You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by rh...@apache.org on 2006/08/09 15:51:33 UTC

svn commit: r430056 [1/4] - in /db/derby/code/trunk/java: client/org/apache/derby/client/am/ client/org/apache/derby/client/net/ client/org/apache/derby/jdbc/ drda/org/apache/derby/impl/drda/ engine/org/apache/derby/iapi/reference/ engine/org/apache/de...

Author: rhillegas
Date: Wed Aug  9 06:51:30 2006
New Revision: 430056

URL: http://svn.apache.org/viewvc?rev=430056&view=rev
Log:
DERBY-528: Commit Francois' 528_diff_v5.txt patch, adding username/password substitution to our authentication options.

Modified:
    db/derby/code/trunk/java/client/org/apache/derby/client/am/EncryptionManager.java
    db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConfiguration.java
    db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnection.java
    db/derby/code/trunk/java/client/org/apache/derby/jdbc/ClientBaseDataSource.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/AppRequester.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/CodePoint.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/Database.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DecryptionManager.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/NetworkServerControlImpl.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/util/StringUtil.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/authentication/AuthenticationServiceBase.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/authentication/BasicAuthenticationServiceImpl.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/ibm14/testSecMec.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/testSecMec.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/ibm14/testSecMec.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk14/testSecMec.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/testSecMec.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/protocol.tests
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/testSecMec.java

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/EncryptionManager.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/EncryptionManager.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/EncryptionManager.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/EncryptionManager.java Wed Aug  9 06:51:30 2006
@@ -24,7 +24,7 @@
 import java.security.Provider;
 import java.security.Security;
 import org.apache.derby.shared.common.reference.SQLState;
-
+import org.apache.derby.shared.common.sanity.SanityManager;
 
 // This class is get used when using encrypted password and/or userid mechanism.
 // The <b>EncryptionManager</b> classs uses Diffie_Hellman algorithm to get the publick key and
@@ -36,6 +36,8 @@
 // obtainPublicKey(), calculateEncryptionToken(int, byte[]) and encryptData(byte[], int, byte[], byte[])
 // The agreed public value for the Diffie-Hellman prime is 256 bits
 // and hence the encrytion will work only if the jce provider supports a 256 bits prime
+//
+// This class also have methods for the SECMEC_USRSSBPWD security mechanism.
 
 public class EncryptionManager {
     transient Agent agent_; // for obtaining an exception log writer only
@@ -87,6 +89,22 @@
     private String providerName; // security provider name
     private Provider provider;
 
+    // Required for SECMEC_USRSSBPWD DRDA security mechanism
+    // NOTE: In a next incarnation, these constants are being moved
+    // to a dedicated/specialized SecMec_USRSSBPWD class implementing
+    // a SecurityMechanism interface.
+    private java.security.MessageDigest messageDigest = null;
+    private java.security.SecureRandom secureRandom = null;
+    private final static int SECMEC_USRSSBPWD_SEED_LEN = 8;  // Seed length
+    // PWSEQs's 8-byte value constant - See DRDA Vol 3
+    private static final byte SECMEC_USRSSBPWD_PWDSEQS[] = {
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01
+    };
+    // Random Number Generator (PRNG) Algorithm
+    private final static String SHA_1_PRNG_ALGORITHM = "SHA1PRNG";
+    public final static String SHA_1_DIGEST_ALGORITHM = "SHA-1";
+
     // EncryptionManager constructor. In this constructor,DHParameterSpec,
     // KeyPairGenerator, KeyPair, and KeyAgreement  are initialized.
     public EncryptionManager(Agent agent) throws SqlException {
@@ -111,6 +129,36 @@
         }
     }
 
+    // Retrieve a particular instance of the Encryption manager for a given
+    // (Messsage Digest) algorithm. This is currently required for the
+    // SECMEC_USRSSBPWD (strong password substitute) security mechanism.
+    // 
+    // NOTE: This is temporary logic as the encryption manager is being
+    // rewritten into a DRDASecurityManager and have some of the
+    // client/engine common logic moved to the Derby 'shared' package.
+    public EncryptionManager(Agent agent, String algorithm) throws SqlException {
+        agent_ = agent;
+        try {
+            // Instantiate the encryption manager for the passed-in security
+            // algorithm and this from the default provider
+            // NOTE: We're only dealing with Message Digest algorithms for now.
+            messageDigest = java.security.MessageDigest.getInstance(algorithm);
+            // We're also verifying that we can instantiate a randon number
+            // generator (PRNG).
+            secureRandom =
+                java.security.SecureRandom.getInstance(SHA_1_PRNG_ALGORITHM);
+        } catch (java.security.NoSuchAlgorithmException nsae) {
+            // The following exception should not be raised for SHA-1 type of
+            // message digest as we've already verified during boot-up that this
+            // algorithm was available as part of the JRE (since BUILT-IN
+            // authentication requires it); but we still raise the exception if
+            // a client were to request a different algorithm.
+            throw new SqlException(agent_.logWriter_, 
+                new ClientMessageId(SQLState.SECURITY_EXCEPTION_ENCOUNTERED),
+                                    nsae); 
+        }
+    }
+
     // This method generates the public key and returns it. This
     // shared public key is the application requester's connection key and will
     // be exchanged with the application server's connection key. This connection
@@ -457,5 +505,187 @@
         secKey_ = null;
     }
 
-}
+    /****************************************************************
+     * Below are methods for the SECMEC_USRSSBPWD security mechanism.
+     ****************************************************************/
+
+	/**
+	 * This method generates an 8-Byte random seed for the client (source).
+	 *
+	 * @return a random 8-Byte seed.
+	 */
+    public byte[] generateSeed() {
+        byte randomSeedBytes[] = new byte[SECMEC_USRSSBPWD_SEED_LEN];
+        secureRandom.setSeed(secureRandom.generateSeed(
+                                        SECMEC_USRSSBPWD_SEED_LEN));
+        secureRandom.nextBytes(randomSeedBytes);
+        return randomSeedBytes;
+    }
 
+    /**
+     * Strong Password Substitution (USRSSBPWD).
+     *
+     * This method generate a password subtitute to send to the target
+     * server.
+     * 
+     * Substitution algorithm works as follow:
+     *
+     * PW_TOKEN = SHA-1(PW, ID)
+     * The password (PW) and user name (ID) can be of any length greater
+     * than or equal to 1 byte.
+     * The client generates a 20-byte password substitute (PW_SUB) as follows:
+     * PW_SUB = SHA-1(PW_TOKEN, RDr, RDs, ID, PWSEQs)
+     * 
+     * w/ (RDs) as the random client seed and (RDr) as the server one.
+     * 
+     * See PWDSSB - Strong Password Substitution Security Mechanism
+     * (DRDA Vol.3 - P.650)
+     *
+     * @param userName The user's name
+     * @param password The user's password
+     * @param sourceSeed_ random client seed (RDs)
+     * @param targetSeed_ random server seed (RDr)
+     *
+     * @return a password substitute.
+     */
+    public byte[] substitutePassword(
+                String userName,
+                String password,
+                byte[] sourceSeed_,
+                byte[] targetSeed_) throws SqlException {
+
+        // Pattern that is prefixed to the BUILTIN encrypted password
+        String ID_PATTERN_NEW_SCHEME = "3b60";
+        
+        // Generated password substitute
+        byte[] passwordSubstitute;
+
+        // Assert we have a SHA-1 Message Digest already instantiated
+        if (SanityManager.DEBUG) {
+            SanityManager.ASSERT((messageDigest != null) &&
+                                 (SHA_1_DIGEST_ALGORITHM.equals(
+                                    messageDigest.getAlgorithm())));
+        }
+
+        // IMPORTANT NOTE: As the password is stored single-hashed in the
+        // database on the target side, it is impossible for the target to
+        // decrypt the password and recompute a substitute to compare with
+        // one generated on the source side - Hence, for now we have to
+        // single-hash and encrypt the password the same way the target is
+        // doing it and we will still generate a substitute obviously - The
+        // password, even pre-hashed will never make it across the wire as
+        // a substitute is generated. In other words, if the target cannot
+        // figure what the original password is (because of not being able
+        // to decrypt it or not being able to retrieve it (i.e. LDAP), then
+        // It may be problematic - so in a way, Strong Password Substitution
+        // (USRSSBPWD) cannot be supported for targets which can't access or
+        // decrypt some password on their side.
+        //
+        // So in short, SECMEC_USRSSBPWD is only supported if the
+        // authentication provider on the target side is NONE or Derby's
+        // BUILTIN one and if using Derby's Client Network driver (for now).
+        //
+        // Encrypt the password as it is done by the derby engine - Note that
+        // this code (logic) is not shared yet - will be in next revision.
+        messageDigest.reset();
+
+		messageDigest.update(this.toHexByte(password, 0, password.length()));
+		byte[] encryptVal = messageDigest.digest();
+		String hexString = ID_PATTERN_NEW_SCHEME +
+                     this.toHexString(encryptVal, 0, encryptVal.length);
+
+        // Generate some 20-byte password token
+        byte[] userBytes = this.toHexByte(userName, 0, userName.length());
+        messageDigest.update(userBytes);
+        messageDigest.update(this.toHexByte(hexString, 0, hexString.length()));
+        byte[] passwordToken = messageDigest.digest();
+        
+        // Now we generate the 20-byte password substitute
+        messageDigest.update(passwordToken);
+        messageDigest.update(targetSeed_);
+        messageDigest.update(sourceSeed_);
+        messageDigest.update(userBytes);
+        messageDigest.update(SECMEC_USRSSBPWD_PWDSEQS);
+
+        passwordSubstitute = messageDigest.digest();
+
+        return passwordSubstitute;
+    }
+
+    /*********************************************************************
+     * RESOLVE:                                                          *
+     * The methods and static vars below should go into some 'shared'    *
+     * package when the capability is put back in (StringUtil.java).     *
+     *********************************************************************/
+
+    private static char[] hex_table = {
+                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
+                'a', 'b', 'c', 'd', 'e', 'f'
+            };
+
+    /**
+        Convert a byte array to a String with a hexidecimal format.
+        The String may be converted back to a byte array using fromHexString.
+        <BR>
+        For each byte (b) two characaters are generated, the first character
+        represents the high nibble (4 bits) in hexidecimal (<code>b & 0xf0</code>),
+        the second character represents the low nibble (<code>b & 0x0f</code>).
+        <BR>
+        The byte at <code>data[offset]</code> is represented by the first two
+        characters in the returned String.
+
+        @param	data	byte array
+        @param	offset	starting byte (zero based) to convert.
+        @param	length	number of bytes to convert.
+
+        @return the String (with hexidecimal format) form of the byte array
+    */
+    private String toHexString(byte[] data, int offset, int length)
+    {
+		StringBuffer s = new StringBuffer(length*2);
+        int end = offset+length;
+
+        for (int i = offset; i < end; i++)
+        {
+            int high_nibble = (data[i] & 0xf0) >>> 4;
+            int low_nibble = (data[i] & 0x0f);
+            s.append(hex_table[high_nibble]);
+            s.append(hex_table[low_nibble]);
+        }
+
+        return s.toString();
+    }
+
+    /**
+  
+        Convert a string into a byte array in hex format.
+        <BR>
+        For each character (b) two bytes are generated, the first byte 
+        represents the high nibble (4 bits) in hexidecimal (<code>b & 0xf0</code>),
+        the second byte represents the low nibble (<code>b & 0x0f</code>).
+        <BR>
+        The character at <code>str.charAt(0)</code> is represented by the first two bytes 
+        in the returned String.
+
+        @param	str string 
+        @param	offset	starting character (zero based) to convert.
+        @param	length	number of characters to convert.
+
+        @return the byte[]  (with hexidecimal format) form of the string (str) 
+    */
+    private byte[] toHexByte(String str, int offset, int length)
+    {
+        byte[] data = new byte[(length - offset) * 2];
+        int end = offset+length;
+
+        for (int i = offset; i < end; i++)
+        {
+            char ch = str.charAt(i);
+            int high_nibble = (ch & 0xf0) >>> 4;
+            int low_nibble = (ch & 0x0f);
+            data[i] = (byte)high_nibble;
+            data[i+1] = (byte)low_nibble;
+        }
+        return data;
+    }
+}

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConfiguration.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConfiguration.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConfiguration.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConfiguration.java Wed Aug  9 06:51:30 2006
@@ -156,20 +156,23 @@
     // Indicates userid/password security mechanism.
     public static final int SECMEC_USRIDPWD = 0x03;
 
-
     //Indicates Encrypted userid and Encrypted Security-sensitive Data security mechanism
     public static final int SECMEC_EUSRIDDTA = 0x0C;
 
     //Indicates Encrypted userid,Encrypted password and Encrypted Security-sensitive Data security mechanism
     public static final int SECMEC_EUSRPWDDTA = 0x0D;
 
+    // Indicates userid with strong password substitute security mechanism.
+    public static final int SECMEC_USRSSBPWD = 0x08;
+
     // list of security mechanisms supported by this driver
     static final int[] SECMGR_SECMECS = {NetConfiguration.SECMEC_EUSRIDPWD,
                                          NetConfiguration.SECMEC_USRENCPWD,
                                          NetConfiguration.SECMEC_USRIDPWD,
                                          NetConfiguration.SECMEC_USRIDONL,
                                          NetConfiguration.SECMEC_EUSRIDDTA,
-                                         NetConfiguration.SECMEC_EUSRPWDDTA};
+                                         NetConfiguration.SECMEC_EUSRPWDDTA,
+                                         NetConfiguration.SECMEC_USRSSBPWD};
 
 
     // IEEE ASCII constant.

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnection.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnection.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnection.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnection.java Wed Aug  9 06:51:30 2006
@@ -120,6 +120,10 @@
     transient byte[] publicKey_;
     transient byte[] targetPublicKey_;
 
+    // Seeds used for strong password substitute generation (USRSSBPWD)
+    transient byte[] sourceSeed_;   // Client seed
+    transient byte[] targetSeed_;   // Server seed
+
     // Product-Specific Data (prddta) sent to the server in the accrdb command.
     // The prddta has a specified format.  It is saved in case it is needed again
     // since it takes a little effort to compute.  Saving this information is
@@ -313,6 +317,8 @@
             targetSrvrlslv_ = null;
             publicKey_ = null;
             targetPublicKey_ = null;
+            sourceSeed_ = null;
+            targetSeed_ = null;
             targetSecmec_ = 0;
             if (ds != null && securityMechanism_ == 0) {
                 securityMechanism_ = ds.getSecurityMechanism(password);
@@ -363,6 +369,8 @@
             targetSrvrlslv_ = null;
             publicKey_ = null;
             targetPublicKey_ = null;
+            sourceSeed_ = null;
+            targetSeed_ = null;
             targetSecmec_ = 0;
             if (ds != null && securityMechanism_ == 0) {
                 securityMechanism_ = ds.getSecurityMechanism();
@@ -446,6 +454,10 @@
                 checkUserPassword(user_, password);
                 flowEUSRPWDDTAconnect(password);
                 break;
+            case NetConfiguration.SECMEC_USRSSBPWD: // Clear text user, strong password substitute
+                checkUserPassword(user_, password);
+                flowUSRSSBPWDconnect(password);
+                break;
 
             default:
                 throw new SqlException(agent_.logWriter_, 
@@ -565,6 +577,11 @@
                 resetConnectionAtFirstSql_ = true;
                 setDeferredResetPassword(password);
                 return true;
+            case NetConfiguration.SECMEC_USRSSBPWD: // Clear text user, strong password substitute
+                checkUserPassword(user_, password);
+                resetConnectionAtFirstSql_ = true;
+                setDeferredResetPassword(password);
+                return true;
             default:
                 throw new SqlException(agent_.logWriter_, 
                     new ClientMessageId(SQLState.SECMECH_NOT_SUPPORTED),
@@ -679,6 +696,39 @@
                 encryptedPasswordForEUSRIDPWD(password));
     }
 
+    /**
+     * The User ID and Strong Password Substitute mechanism (USRSSBPWD)
+     * authenticates the user like the user ID and password mechanism, but
+     * the password does not flow. A password substitute is generated instead
+     * using the SHA-1 algorithm, and is sent to the application server.
+     *
+     * The application server generates a password substitute using the same
+     * algorithm and compares it with the application requesterÂ’s password
+     * substitute. If equal, the user is authenticated.
+     *
+     * The SECTKN parameter is used to flow the client and server encryption
+     * seeds on the ACCSEC and ACCSECRD commands.
+     *
+     * More information in DRDA, V3, Volume 3 standard - PWDSSB (page 650)
+     */
+    private void flowUSRSSBPWDconnect(String password) throws SqlException {
+        flowServerAttributes();
+
+        checkSecmgrForSecmecSupport(NetConfiguration.SECMEC_USRSSBPWD);
+        // Generate a random client seed to send to the target server - in
+        // response we will also get a generated seed from this last one.
+        // Seeds are used on both sides to generate the password substitute.
+        initializeClientSeed();
+
+        flowSeedExchange(NetConfiguration.SECMEC_USRSSBPWD, sourceSeed_);
+
+        flowSecurityCheckAndAccessRdb(targetSecmec_, //securityMechanism
+                user_,
+                null,
+                null,
+                passwordSubstituteForUSRSSBPWD(password)); // PWD Substitute
+    }
+
     private void flowServerAttributes() throws SqlException {
         agent_.beginWriteChainOutsideUOW();
         netAgent_.netConnectionRequest_.writeExchangeServerAttributes(extnam_, //externalName
@@ -706,6 +756,16 @@
         agent_.endReadChain();
     }
 
+    private void flowSeedExchange(int securityMechanism, byte[] sourceSeed) throws SqlException {
+        agent_.beginWriteChainOutsideUOW();
+        netAgent_.netConnectionRequest_.writeAccessSecurity(securityMechanism,
+                databaseName_,
+                sourceSeed);
+        agent_.flowOutsideUOW();
+        netAgent_.netConnectionReply_.readAccessSecurity(this, securityMechanism);
+        agent_.endReadChain();
+    }
+
     private void flowServerAttributesAndKeyExchange(int securityMechanism,
                                                     byte[] publicKey) throws SqlException {
         agent_.beginWriteChainOutsideUOW();
@@ -715,6 +775,15 @@
         agent_.endReadChain();
     }
 
+    private void flowServerAttributesAndSeedExchange(int securityMechanism,
+                                                     byte[] sourceSeed) throws SqlException {
+        agent_.beginWriteChainOutsideUOW();
+        writeServerAttributesAndSeedExchange(sourceSeed);
+        agent_.flowOutsideUOW();
+        readServerAttributesAndSeedExchange();
+        agent_.endReadChain();
+    }
+
     private void flowSecurityCheckAndAccessRdb(int securityMechanism,
                                                String user,
                                                String password,
@@ -765,11 +834,24 @@
                 publicKey);
     }
 
+    private void writeServerAttributesAndSeedExchange(byte[] sourceSeed)
+                                                        throws SqlException {
+        
+        // For now, we're just calling our cousin method to do the job
+        writeServerAttributesAndKeyExchange(NetConfiguration.SECMEC_USRSSBPWD,
+                                            sourceSeed);
+    }
+
     private void readServerAttributesAndKeyExchange(int securityMechanism) throws SqlException {
         netAgent_.netConnectionReply_.readExchangeServerAttributes(this);
         netAgent_.netConnectionReply_.readAccessSecurity(this, securityMechanism);
     }
 
+    private void readServerAttributesAndSeedExchange() throws SqlException {
+        // For now, we're just calling our cousin method to do the job
+        readServerAttributesAndKeyExchange(NetConfiguration.SECMEC_USRSSBPWD);
+    }
+
     private void writeSecurityCheckAndAccessRdb(int securityMechanism,
                                                 String user,
                                                 String password,
@@ -830,21 +912,33 @@
                 endOffset = netAgent_.netConnectionRequest_.offset_;
                 cacheConnectBytes(beginOffset, endOffset);
             }
-            // either NetConfiguration.SECMEC_USRENCPWD or NetConfiguration.SECMEC_EUSRIDPWD
+            // Either NetConfiguration.SECMEC_USRENCPWD,
+            // NetConfiguration.SECMEC_EUSRIDPWD or
+            // NetConfiguration.SECMEC_USRSSBPWD
             else {
-                initializePublicKeyForEncryption();
+                if (securityMechanism_ == NetConfiguration.SECMEC_USRSSBPWD)
+                    initializeClientSeed();
+                else // SECMEC_USRENCPWD, SECMEC_EUSRIDPWD
+                    initializePublicKeyForEncryption();
+
                 // Set the resetConnectionAtFirstSql_ to false to avoid going in an
                 // infinite loop, since all the flow methods call beginWriteChain which then
                 // calls writeDeferredResetConnection where the check for resetConnectionAtFirstSql_
                 // is done. By setting the resetConnectionAtFirstSql_ to false will avoid calling the
                 // writeDeferredReset method again.
                 resetConnectionAtFirstSql_ = false;
-                flowServerAttributesAndKeyExchange(securityMechanism_, publicKey_);
+
+                if (securityMechanism_ == NetConfiguration.SECMEC_USRSSBPWD)
+                    flowSeedExchange(securityMechanism_, sourceSeed_);
+                else // SECMEC_USRENCPWD, SECMEC_EUSRIDPWD
+                    flowServerAttributesAndKeyExchange(securityMechanism_, publicKey_);
+
                 agent_.beginWriteChainOutsideUOW();
 
                 // Reset the resetConnectionAtFirstSql_ to true since we are done
                 // with the flow method.
                 resetConnectionAtFirstSql_ = true;
+
                 // NetConfiguration.SECMEC_USRENCPWD
                 if (securityMechanism_ == NetConfiguration.SECMEC_USRENCPWD) {
                     writeSecurityCheckAndAccessRdb(NetConfiguration.SECMEC_USRENCPWD,
@@ -853,8 +947,15 @@
                             null, //encryptedUserid
                             encryptedPasswordForUSRENCPWD(getDeferredResetPassword()));
                 }
-                // NetConfiguration.SECMEC_EUSRIDPWD
-                else {
+                // NetConfiguration.SECMEC_USRSSBPWD
+                else if (securityMechanism_ == NetConfiguration.SECMEC_USRSSBPWD) {
+                    writeSecurityCheckAndAccessRdb(NetConfiguration.SECMEC_USRSSBPWD,
+                            user_,
+                            null,
+                            null,
+                            passwordSubstituteForUSRSSBPWD(getDeferredResetPassword()));
+                }
+                else {  // NetConfiguration.SECMEC_EUSRIDPWD
                     writeSecurityCheckAndAccessRdb(NetConfiguration.SECMEC_EUSRIDPWD,
                             null, //user
                             null, //password
@@ -924,6 +1025,7 @@
 
                 if ((targetSecmec_ == NetConfiguration.SECMEC_USRENCPWD) ||
                         (targetSecmec_ == NetConfiguration.SECMEC_EUSRIDPWD) ||
+                        (targetSecmec_ == NetConfiguration.SECMEC_USRSSBPWD) ||
                         (targetSecmec_ == NetConfiguration.SECMEC_EUSRIDDTA) ||
                         (targetSecmec_ == NetConfiguration.SECMEC_EUSRPWDDTA)) {
 
@@ -933,7 +1035,10 @@
                             new DisconnectException(agent_, 
                                 new ClientMessageId(SQLState.NET_SECTKN_NOT_RETURNED)));
                     } else {
-                        targetPublicKey_ = sectkn;
+                        if (targetSecmec_ == NetConfiguration.SECMEC_USRSSBPWD)
+                            targetSeed_ = sectkn;
+                        else
+                            targetPublicKey_ = sectkn;
                         if (encryptionManager_ != null) {
                             encryptionManager_.resetSecurityKeys();
                         }
@@ -1309,11 +1414,21 @@
 
     private void initializePublicKeyForEncryption() throws SqlException {
         if (encryptionManager_ == null) {
-            encryptionManager_ = new org.apache.derby.client.am.EncryptionManager(agent_);
+            encryptionManager_ = new EncryptionManager(agent_);
         }
         publicKey_ = encryptionManager_.obtainPublicKey();
     }
 
+    // SECMEC_USRSSBPWD security mechanism - Generate a source (client) seed
+    // to send to the target (application) server.
+    private void initializeClientSeed() throws SqlException {
+        if (encryptionManager_ == null) {
+            encryptionManager_ = new EncryptionManager(
+                                    agent_,
+                                    EncryptionManager.SHA_1_DIGEST_ALGORITHM);
+        }
+        sourceSeed_ = encryptionManager_.generateSeed();
+    }
 
     private byte[] encryptedPasswordForUSRENCPWD(String password) throws SqlException {
         return encryptionManager_.encryptData(netAgent_.sourceCcsidManager_.convertFromUCS2(password, netAgent_),
@@ -1334,6 +1449,35 @@
                 NetConfiguration.SECMEC_EUSRIDPWD,
                 targetPublicKey_,
                 targetPublicKey_);
+    }
+
+    private byte[] passwordSubstituteForUSRSSBPWD(String password) throws SqlException {
+        String userName = user_;
+        
+        // Define which userName takes precedence - If we have a dataSource
+        // available here, it is posible that the userName has been
+        // overriden by some defined as part of the connection attributes
+        // (see ClientBaseDataSource.updateDataSourceValues().
+        // We need to use the right userName as strong password
+        // substitution depends on the userName when the substitute
+        // password is generated; if we were not using the right userName
+        // then authentication would fail when regenerating the substitute
+        // password on the engine server side, where userName as part of the
+        // connection attributes would get used to authenticate the user.
+        if (dataSource_ != null)
+        {
+            String dataSourceUserName = dataSource_.getUser();
+            if (!dataSourceUserName.equals("") &&
+                userName.equalsIgnoreCase(
+                    dataSource_.propertyDefault_user) &&
+                !dataSourceUserName.equalsIgnoreCase(
+                    dataSource_.propertyDefault_user))
+            {
+                userName = dataSourceUserName;
+            }
+        }
+        return encryptionManager_.substitutePassword(
+                userName, password, sourceSeed_, targetSeed_);
     }
 
     // Methods to get the manager levels for Regression harness only.

Modified: db/derby/code/trunk/java/client/org/apache/derby/jdbc/ClientBaseDataSource.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/jdbc/ClientBaseDataSource.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/jdbc/ClientBaseDataSource.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/jdbc/ClientBaseDataSource.java Wed Aug  9 06:51:30 2006
@@ -201,6 +201,7 @@
     // <li> CLEAR_TEXT_PASSWORD_SECURITY
     // <li> ENCRYPTED_PASSWORD_SECURITY
     // <li> ENCRYPTED_USER_AND_PASSWORD_SECURITY - both password and user are encrypted
+    // <li> STRONG_PASSWORD_SUBSTITUTE_SECURITY
     // </ul>
     // The default security mechanism is USER_ONLY_SECURITY.
     // <p>
@@ -209,7 +210,7 @@
     // If the specified security mechanism is not supported by the conversation
     // then an exception will be thrown and there will be no additional retries.
     // <p>
-    // This property is currently only available for the  DNC driver.
+    // This property is currently only available for the DNC driver.
     // <p>
     // Both user and password need to be set for all security mechanism except USER_ONLY_SECURITY
     // When using USER_ONLY_SECURITY, only the user property needs to be specified.
@@ -229,13 +230,12 @@
     // If the security mechanism is not explicitly set as mentioned above, in that case
     // the Client will try to upgrade the security mechanism to a more secure one, if possible.
     // @see #getUpgradedSecurityMechanism
-    // Therefore, need to keep track if the seurityMechanism has been explicitly set 
+    // Therefore, need to keep track if the securityMechanism has been explicitly set 
     protected short securityMechanism = SECMEC_HAS_NOT_EXPLICITLY_SET;
-    // TODO default  should be  USER_ONLY_SECURITY. Change when working on
-    // Network Server
-    //  public final static short propertyDefault_securityMechanism = (short)
-    //  org.apache.derby.client.net.NetConfiguration.SECMEC_USRIDONL;
-    public final static short propertyDefault_securityMechanism = (short) NetConfiguration.SECMEC_USRIDONL;
+
+    //  Default security mechanism is USER_ONLY_SECURITY.
+    public final static short propertyDefault_securityMechanism =
+                                    (short) NetConfiguration.SECMEC_USRIDONL;
 
     
     // We use the NET layer constants to avoid a mapping for the NET driver.
@@ -248,7 +248,9 @@
      */
     public static short getSecurityMechanism(Properties properties) {
         short secmec;
-        String securityMechanismString = properties.getProperty(Attribute.CLIENT_SECURITY_MECHANISM);
+        String securityMechanismString =
+            properties.getProperty(Attribute.CLIENT_SECURITY_MECHANISM);
+
         if ( securityMechanismString != null )
         {
             // security mechanism has been set, do not override, but instead return
@@ -269,16 +271,17 @@
     }
 
     /**
-     * This method has logic to upgrade security mechanism to a better (more secure) one 
-     * if it is possible.   Currently derby server only has support for USRIDPWD,USRIDONL,
-     * EUSRIDPWD and this method only considers these possibilities. 
-     * USRIDPWD, EUSRIDPWD require a password, USRIDONL is the only security mechanism
-     * which does not require password.
+     * This method has logic to upgrade security mechanism to a better (more secure)
+     * one if it is possible. Currently derby server only has support for USRIDPWD,
+     * USRIDONL, EUSRIDPWD and USRSSBPWD (10.2+) - this method only considers these
+     * possibilities. USRIDPWD, EUSRIDPWD and USRSSBPWD require a password, USRIDONL
+     * is the only security mechanism which does not require password.
      * 1. if password is not available, then security mechanism possible is USRIDONL
      * 2. if password is available, if client supports EUSRIDPWD, then EUSRIDPWD is 
      * returned
-     * 3. if password is available, if client does not support EUSRIDPWD, then USRIDPWD
-     * is returned.
+     * 3. if password is available, if client does not support EUSRIDPWD, then
+     * USRIDPWD is returned.
+     *
      * @param password password argument 
      * @return upgraded security mechanism if possible
      */
@@ -288,8 +291,8 @@
         if ( password == null )
             return propertyDefault_securityMechanism;
 
-        // if password is available, then a security mechanism is picked in following
-        // order if support is available
+        // if password is available, then a security mechanism is picked in
+        // following order if support is available.
         // 1. EUSRIDPWD
         // 2. USRIDPWD
         // when we have support for more security mechanisms on server 
@@ -299,7 +302,18 @@
         if (SUPPORTS_EUSRIDPWD)
             return (short)NetConfiguration.SECMEC_EUSRIDPWD;
         else 
+            // IMPORTANT NOTE:
+            // --------------
+            // If DERBY-1517 can be fixed, we should default to
+            // SECMEC_USRSSBPWD (strong password substitute).
+            // Until then, connecting with a 10.2+ client to
+            // a derby server < 10.2, and hence does not support
+            // SECMEC_USRSSBPWD as a SECMEC, will cause a DRDA protocol
+            // exception, as described in DERBY-926).
+            // 
+            // return (short)NetConfiguration.SECMEC_USRSSBPWD;
             return (short)NetConfiguration.SECMEC_USRIDPWD;
+
     }
 
     // ---------------------------- getServerMessageTextOnGetMessage -----------------------------------
@@ -716,8 +730,12 @@
     /**
      * The source security mechanism to use when connecting to this data source.
      * <p/>
-     * Security mechanism options are: <ul> <li> USER_ONLY_SECURITY <li> CLEAR_TEXT_PASSWORD_SECURITY <li>
-     * ENCRYPTED_PASSWORD_SECURITY <li> ENCRYPTED_USER_AND_PASSWORD_SECURITY - both password and user are encrypted
+     * Security mechanism options are: <ul>
+     * <li> USER_ONLY_SECURITY
+     * <li> CLEAR_TEXT_PASSWORD_SECURITY
+     * <li> ENCRYPTED_PASSWORD_SECURITY
+     * <li> ENCRYPTED_USER_AND_PASSWORD_SECURITY - both password and user are encrypted
+     * <li> STRONG_PASSWORD_SUBSTITUTE_SECURITY
      * </ul> The default security mechanism is USER_ONLY SECURITY
      * <p/>
      * If the application specifies a security mechanism then it will be the only one attempted. If the specified
@@ -733,6 +751,7 @@
     public final static short CLEAR_TEXT_PASSWORD_SECURITY = (short) NetConfiguration.SECMEC_USRIDPWD;
     public final static short ENCRYPTED_PASSWORD_SECURITY = (short) NetConfiguration.SECMEC_USRENCPWD;
     public final static short ENCRYPTED_USER_AND_PASSWORD_SECURITY = (short) NetConfiguration.SECMEC_EUSRIDPWD;
+    public final static short STRONG_PASSWORD_SUBSTITUTE_SECURITY = (short) NetConfiguration.SECMEC_USRSSBPWD;
 
     /**
      * sets the security mechanism
@@ -859,8 +878,6 @@
     }
 
 
-
-
     // --- private helper methods
 
 
@@ -888,15 +905,8 @@
         if (prop.containsKey(Attribute.CLIENT_TRACE_APPEND)) {
             setTraceFileAppend(getTraceFileAppend(prop));
         }
-        if (prop.containsKey(Attribute.CLIENT_SECURITY_MECHANISM)) {
-            setSecurityMechanism(getSecurityMechanism(prop));
-        }
         if (prop.containsKey(Attribute.CLIENT_RETIEVE_MESSAGE_TEXT)) {
             setRetrieveMessageText(getRetrieveMessageText(prop));
         }
     }
-
-
 }
-
-

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/AppRequester.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/AppRequester.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/AppRequester.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/AppRequester.java Wed Aug  9 06:51:30 2006
@@ -121,6 +121,19 @@
 	}
 
 	/**
+	 * Returns true if Derby's client driver supports SECMEC_USRSSBPWD 
+	 * DRDA security mechanism.
+	 */
+	protected boolean supportsSecMecUSRSSBPWD()
+	{
+		return
+			(
+			    ( clientType == DNC_CLIENT ) &&
+			    ( greaterThanOrEqualTo( 10, 2, 0 ) )
+			);
+	}
+
+	/**
 	 * Check if the client expects QRYCLSIMP to be supported when the
 	 * protocol is LMTBLKPRC.
 	 *

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/CodePoint.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/CodePoint.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/CodePoint.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/CodePoint.java Wed Aug  9 06:51:30 2006
@@ -719,6 +719,7 @@
 	static final int SECMEC_USRIDNWPWD = 5;  // Userid, Password, and new Password
 	static final int SECMEC_USRSBSPWD = 6;  // Userid with substitute password
 	static final int SECMEC_USRENCPWD = 7;  // Userid with encrypted password
+    static final int SECMEC_USRSSBPWD = 8;  // Userid with Strong password substitute
 	static final int SECMEC_EUSRIDPWD = 9;  // Encrpyted userid and password
 	static final int SECMEC_EUSRIDNWPWD = 10;  // Encrpyted userid and password
 

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java Wed Aug  9 06:51:30 2006
@@ -34,6 +34,7 @@
 import java.math.BigDecimal;
 import java.sql.CallableStatement;
 import java.sql.Connection;
+import java.sql.Driver;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
@@ -51,15 +52,18 @@
 import org.apache.derby.iapi.reference.Attribute;
 import org.apache.derby.iapi.reference.DRDAConstants;
 import org.apache.derby.iapi.reference.JDBC30Translation;
+import org.apache.derby.iapi.reference.Property;
 import org.apache.derby.iapi.reference.SQLState;
 import org.apache.derby.iapi.services.info.JVMInfo;
 import org.apache.derby.iapi.services.monitor.Monitor;
 import org.apache.derby.iapi.services.sanity.SanityManager;
 import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
 import org.apache.derby.iapi.tools.i18n.LocalizedResource;
+import org.apache.derby.iapi.jdbc.AuthenticationService;
 import org.apache.derby.iapi.jdbc.EngineParameterMetaData;
 import org.apache.derby.impl.jdbc.EmbedSQLException;
 import org.apache.derby.impl.jdbc.Util;
+import org.apache.derby.jdbc.InternalDriver;
 
 class DRDAConnThread extends Thread {
 
@@ -161,10 +165,15 @@
 
 	// for decryption
 	private static DecryptionManager decryptionManager;
+
 	// public key generated by Deffie-Hellman algorithm, to be passed to the encrypter,
 	// as well as used to initialize the cipher
 	private byte[] myPublicKey;
 
+    // generated target seed to be used to generate the password substitute
+    // as part of SECMEC_USRSSBPWD security mechanism
+    private byte[] myTargetSeed;
+
     // Some byte[] constants that are frequently written into messages. It is more efficient to 
     // use these constants than to convert from a String each time 
     // (This replaces the qryscraft_ and notQryscraft_ static exception objects.)
@@ -174,6 +183,12 @@
     private static final byte[] errD4_D6 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // 12x0 
     private static final byte[] warn0_warnA = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };  // 11x ' '
 
+    private final static String AUTHENTICATION_PROVIDER_BUILTIN_CLASS =
+    "org.apache.derby.impl.jdbc.authentication.BasicAuthenticationServiceImpl";
+
+    private final static String AUTHENTICATION_PROVIDER_NONE_CLASS =
+    "org.apache.derby.impl.jdbc.authentication.NoneAuthenticationServiceImpl";
+
     // Work around a classloader bug involving interrupt handling during
     // class loading. If the first request to load the
     // DRDAProtocolExceptionInfo class occurs during shutdown, the
@@ -1161,7 +1176,6 @@
 		databaseAccessException = null;
 		int retSecChkCode = 0;
 
-
 		String realName = database.dbName; //first strip off properties
 		int endOfName = realName.indexOf(';');
 		if (endOfName != -1)
@@ -1187,6 +1201,34 @@
 		if (session.drdaID == null)
 			session.drdaID = leftBrace + session.connNum + rightBrace;
 		p.put(Attribute.DRDAID_ATTR, session.drdaID);
+
+        // We pass extra property information for the authentication provider
+        // to successfully re-compute the substitute (hashed) password and
+        // compare it with what we've got from the requester (source).
+        //
+        // If a password attribute appears as part of the connection URL
+        // attributes, we then don't use the substitute hashed password
+        // to authenticate with the engine _as_ the one (if any) as part
+        // of the connection URL attributes, will be used to authenticate
+        // against Derby's BUILT-IN authentication provider - As a reminder,
+        // Derby allows password to be mentioned as part of the connection
+        // URL attributes, as this extra capability could be useful to pass
+        // passwords to external authentication providers for Derby; hence
+        // a password defined as part of the connection URL attributes cannot
+        // be substituted (single-hashed) as it is not recoverable.
+        if ((database.securityMechanism == CodePoint.SECMEC_USRSSBPWD) &&
+            (database.dbName.indexOf(Attribute.PASSWORD_ATTR) == -1))
+        {
+            p.put(Attribute.CLIENT_SECURITY_MECHANISM,
+                  String.valueOf(database.securityMechanism));
+            p.put(Attribute.DRDA_SECTKN_IN,
+                  DecryptionManager.toHexString(database.secTokenIn, 0,
+                                                database.secTokenIn.length));
+            p.put(Attribute.DRDA_SECTKN_OUT,
+                  DecryptionManager.toHexString(database.secTokenOut, 0,
+                                                database.secTokenOut.length));
+        }
+            
 	 	try {
 			database.makeConnection(p);
 	  	} catch (SQLException se) {
@@ -1206,7 +1248,6 @@
 				return CodePoint.SECCHKCD_USERIDINVALID;
 
 			return 0;
-			
 		}
 		catch (Exception e)
 		{
@@ -1576,26 +1617,28 @@
 	 *
 	 *	If the target server supports the SECMEC requested by the application requester
 	 *	then a single value is returned and it is identical to the SECMEC value
-	 *	in the ACCSEC command.  If the target server does not support the SECMEC
+	 *	in the ACCSEC command. If the target server does not support the SECMEC
 	 *	requested, then one or more values are returned and the application requester
 	 *  must choose one of these values for the security mechanism.
 	 *  We currently support
 	 *		- user id and password (default for JCC)
 	 *		- encrypted user id and password
+     *      - strong password substitute (USRSSBPWD w/
+     *                                    Derby network client only)
 	 *
      *  Instance variables
 	 *    SECMGRNM  - security manager name - optional
 	 *	  SECMEC 	- security mechanism - required
 	 *	  RDBNAM	- relational database name - optional
 	 * 	  SECTKN	- security token - optional, (required if sec mech. needs it)
-	 *
+     *
 	 *  @return security check code - 0 if everything O.K.
 	 */
 	private int parseACCSEC() throws  DRDAProtocolException
 	{
 		int securityCheckCode = 0;
 		int securityMechanism = 0;
-		byte [] publicKeyIn = null;
+		byte [] secTokenIn = null;
 
 		reader.markCollection();
 		int codePoint = reader.getCodePoint();
@@ -1614,7 +1657,7 @@
 					checkLength(CodePoint.SECMEC, 2);
 					securityMechanism = reader.readNetworkShort();
 					if (SanityManager.DEBUG)
-						trace("Security mechanism = " + securityMechanism);
+						trace("parseACCSEC - Security mechanism = " + securityMechanism);
                     
                     // if Property.DRDA_PROP_SECURITYMECHANISM has been set, then
                     // network server only accepts connections which use that
@@ -1628,7 +1671,14 @@
                     if ( (server.getSecurityMechanism() != 
                         NetworkServerControlImpl.INVALID_OR_NOTSET_SECURITYMECHANISM)
                             && securityMechanism != server.getSecurityMechanism())
+                    {
                         securityCheckCode = CodePoint.SECCHKCD_NOTSUPPORTED;
+                        if (SanityManager.DEBUG) {
+                            trace("parseACCSEC - SECCHKCD_NOTSUPPORTED [1] - " +
+                                  securityMechanism + " <> " +
+                                  server.getSecurityMechanism() + "\n");
+                        }
+                    }
                     else
                     {
                         // for plain text userid,password USRIDPWD, and USRIDONL
@@ -1636,11 +1686,33 @@
                         if (securityMechanism != CodePoint.SECMEC_USRIDPWD &&
                                 securityMechanism != CodePoint.SECMEC_USRIDONL)
                         {
-                            //this is the only other one we understand
-                            if (securityMechanism != CodePoint.SECMEC_EUSRIDPWD) 
-                                securityCheckCode = CodePoint.SECCHKCD_NOTSUPPORTED;
+                            // These are the only other mechanisms we understand
+                            if ((securityMechanism !=
+                                        CodePoint.SECMEC_EUSRIDPWD) &&
+                                (securityMechanism !=
+                                        CodePoint.SECMEC_USRSSBPWD))
+                                //securityCheckCode = CodePoint.SECCHKCD_NOTSUPPORTED;
+                    {
+                        securityCheckCode = CodePoint.SECCHKCD_NOTSUPPORTED;
+                        if (SanityManager.DEBUG) {
+                            trace("parseACCSEC - SECCHKCD_NOTSUPPORTED [2]\n");
+                        }
+                    }
                             else
                             {
+                                // We delay the initialization and required
+                                // processing for SECMEC_USRSSBPWD as we need
+                                // to ensure the database is booted so that
+                                // we can verify that the current auth scheme
+                                // is set to BUILT-IN or NONE. For this we need
+                                // to have the RDBNAM codepoint available.
+                                //
+                                // See validateSecMecUSRSSBPWD() call below
+                                if (securityMechanism ==
+                                        CodePoint.SECMEC_USRSSBPWD)
+                                    break;
+
+                                // SECMEC_EUSRIDPWD initialization
                                 try {
                                     if (decryptionManager == null)
                                         decryptionManager = new DecryptionManager();
@@ -1654,7 +1726,8 @@
                         }
                     }
 					break;
-				//optional (currently required for Cloudscape - may need to revisit)
+                //optional (currently required for Cloudscape - needed for
+                //          DERBY-528 as well)
 				case CodePoint.RDBNAM:
 					String dbname = parseRDBNAM();
 					Database d = session.getDatabase(dbname);
@@ -1662,7 +1735,6 @@
 						addDatabase(dbname);
 					else
                     {
-                        
                         // reset database for connection re-use 
                         d.reset();
 						database = d;
@@ -1670,13 +1742,14 @@
 					break;
 				//optional - depending on security Mechanism 
 				case CodePoint.SECTKN:
-					publicKeyIn = reader.readBytes();
+					secTokenIn = reader.readBytes();
 					break;
 				default:
 					invalidCodePoint(codePoint);
 			}
 			codePoint = reader.getCodePoint();
 		}
+
 		// check for required CodePoint's
 		if (securityMechanism == 0)
 			missingCodePoint(CodePoint.SECMEC);
@@ -1690,22 +1763,38 @@
 			missingCodePoint(CodePoint.RDBNAM);
 
 		database.securityMechanism = securityMechanism;
-		database.publicKeyIn = publicKeyIn;
+		database.secTokenIn = secTokenIn;
+
+        // If security mechanism is SECMEC_USRSSBPWD, then ensure it can be
+        // used for the database or system based on the client's connection
+        // URL and its identity.
+        if (securityCheckCode == 0  &&
+            (database.securityMechanism == CodePoint.SECMEC_USRSSBPWD))
+        {
+            if (SanityManager.DEBUG)
+		        SanityManager.ASSERT((securityCheckCode == 0),
+						"SECMEC_USRSSBPWD: securityCheckCode should not " +
+                        "already be set, found it initialized with " +
+                        "a value of '" + securityCheckCode + "'.");
+            securityCheckCode = validateSecMecUSRSSBPWD();
+        }
 
 		// need security token
 		if (securityCheckCode == 0  && 
-			database.securityMechanism == CodePoint.SECMEC_EUSRIDPWD &&
-			database.publicKeyIn == null)
+			(database.securityMechanism == CodePoint.SECMEC_EUSRIDPWD ||
+            database.securityMechanism == CodePoint.SECMEC_USRSSBPWD) &&
+			database.secTokenIn == null)
 			securityCheckCode = CodePoint.SECCHKCD_SECTKNMISSING_OR_INVALID;
 
 		// shouldn't have security token
 		if (securityCheckCode == 0 &&
 			(database.securityMechanism == CodePoint.SECMEC_USRIDPWD ||
 			database.securityMechanism == CodePoint.SECMEC_USRIDONL)  &&
-			database.publicKeyIn != null)
+			database.secTokenIn != null)
 			securityCheckCode = CodePoint.SECCHKCD_SECTKNMISSING_OR_INVALID;
+
 		if (SanityManager.DEBUG)
-			trace("** ACCSECRD securityCheckCode is: "+securityCheckCode);
+			trace("** ACCSECRD securityCheckCode is: " + securityCheckCode);
 		
 		// If the security check was successful set the session state to
 		// security accesseed.  Otherwise go back to attributes exchanged so we
@@ -1716,7 +1805,6 @@
 			session.setState(session.ATTEXC);
 
 		return securityCheckCode;
-
 	}
 
 	/**
@@ -2539,6 +2627,7 @@
 			trace("RdbName " + name);
 		return name;
 	}
+
 	/**
 	 * Write ACCSECRD
 	 * If the security mechanism is known, we just send it back along with
@@ -2560,6 +2649,7 @@
 	{
 		writer.createDssReply();
 		writer.startDdm(CodePoint.ACCSECRD);
+
 		if (securityCheckCode != CodePoint.SECCHKCD_NOTSUPPORTED)
 			writer.writeScalar2Bytes(CodePoint.SECMEC, database.securityMechanism);
 		else
@@ -2571,7 +2661,7 @@
             // security mechanism, if so send only the security mechanism  that the 
             // server will accept, to the client
             if ( server.getSecurityMechanism() != NetworkServerControlImpl.INVALID_OR_NOTSET_SECURITYMECHANISM )
-                writer.writeScalar2Bytes(CodePoint.SECMEC,server.getSecurityMechanism());
+                writer.writeScalar2Bytes(CodePoint.SECMEC, server.getSecurityMechanism());
             else
             {
                 // note: per the DDM manual , ACCSECRD response is of 
@@ -2582,8 +2672,10 @@
                 writer.writeScalar2Bytes(CodePoint.SECMEC, CodePoint.SECMEC_USRIDPWD);
                 writer.writeScalar2Bytes(CodePoint.SECMEC, CodePoint.SECMEC_EUSRIDPWD);
                 writer.writeScalar2Bytes(CodePoint.SECMEC, CodePoint.SECMEC_USRIDONL);
+                writer.writeScalar2Bytes(CodePoint.SECMEC, CodePoint.SECMEC_USRSSBPWD);
             }
 		}
+
 		if (securityCheckCode != 0)
 		{
 			writer.writeScalar1Byte(CodePoint.SECCHKCD, securityCheckCode);
@@ -2593,6 +2685,8 @@
 			// we need to send back the key if encryption is being used
 			if (database.securityMechanism == CodePoint.SECMEC_EUSRIDPWD)
 				writer.writeScalarBytes(CodePoint.SECTKN, myPublicKey);
+            else if (database.securityMechanism == CodePoint.SECMEC_USRSSBPWD)
+				writer.writeScalarBytes(CodePoint.SECTKN, myTargetSeed);
 		}
     	writer.endDdmAndDss ();
 
@@ -2603,8 +2697,8 @@
 		}
 
 		finalizeChain();
-
 	}
+
 	/**
 	 * Parse security check
 	 * Instance Variables
@@ -2640,7 +2734,7 @@
 					checkLength(CodePoint.SECMEC, 2);
 					securityMechanism = reader.readNetworkShort();
 					if (SanityManager.DEBUG) 
-						trace("Security mechanism = " + securityMechanism);
+						trace("parseSECCHK - Security mechanism = " + securityMechanism);
 					//RESOLVE - spec is not clear on what should happen
 					//in this case
 					if (securityMechanism != database.securityMechanism)
@@ -2648,37 +2742,76 @@
 					break;
 				//optional - depending on security Mechanism 
 				case CodePoint.SECTKN:
-					if (database.securityMechanism != CodePoint.SECMEC_EUSRIDPWD)
+					if ((database.securityMechanism !=
+                                        CodePoint.SECMEC_EUSRIDPWD) &&
+                        (database.securityMechanism !=
+                                        CodePoint.SECMEC_USRSSBPWD))
 					{
 						securityCheckCode = CodePoint.SECCHKCD_SECTKNMISSING_OR_INVALID;
 						reader.skipBytes();
 					}
-					else if (database.decryptedUserId == null) {
-						try {
-							database.decryptedUserId = reader.readEncryptedString(decryptionManager,
-												database.securityMechanism, myPublicKey, database.publicKeyIn);
-						} catch (SQLException se)
-						{
-							println2Log(database.dbName, session.drdaID, se.getMessage());
-							if (securityCheckCode == 0)
-								securityCheckCode = CodePoint.SECCHKCD_13;	//userid invalid
-						}
-						database.userId = database.decryptedUserId;
-						if (SanityManager.DEBUG) trace("**decrypted userid is: "+database.userId);
-					}
-					else if (database.decryptedPassword == null) {
-						try {
-							database.decryptedPassword = reader.readEncryptedString(decryptionManager,
-												database.securityMechanism, myPublicKey, database.publicKeyIn);
-						} catch (SQLException se)
-						{	
-							println2Log(database.dbName, session.drdaID, se.getMessage());
-							if (securityCheckCode == 0)
-								securityCheckCode = CodePoint.SECCHKCD_0F;	//password invalid
-						}
-						database.password = database.decryptedPassword;
-						if (SanityManager.DEBUG) trace("**decrypted password is: "+database.password);
-					}
+                    else if (database.securityMechanism ==
+                                                CodePoint.SECMEC_EUSRIDPWD)
+                    {
+                        if (database.decryptedUserId == null)
+                        {
+						    try {
+							    database.decryptedUserId =
+                                    reader.readEncryptedString(
+                                                decryptionManager,
+												database.securityMechanism,
+                                                myPublicKey,
+                                                database.secTokenIn);
+						    } catch (SQLException se) {
+							    println2Log(database.dbName, session.drdaID,
+                                            se.getMessage());
+							    if (securityCheckCode == 0)
+                                    //userid invalid
+								    securityCheckCode = CodePoint.SECCHKCD_13;
+						    }
+						    database.userId = database.decryptedUserId;
+						    if (SanityManager.DEBUG)
+                                trace("**decrypted userid is: "+database.userId);
+					    }
+					    else if (database.decryptedPassword == null)
+                        {
+						    try {
+							    database.decryptedPassword =
+                                    reader.readEncryptedString(
+                                            decryptionManager,
+										    database.securityMechanism,
+                                            myPublicKey,
+                                            database.secTokenIn);
+						    } catch (SQLException se) {	
+                                println2Log(database.dbName, session.drdaID,
+                                            se.getMessage());
+                                if (securityCheckCode == 0)
+                                    //password invalid
+                                    securityCheckCode = CodePoint.SECCHKCD_0F;
+                            }
+                            database.password = database.decryptedPassword;
+                            if (SanityManager.DEBUG)
+                                trace("**decrypted password is: " +
+                                      database.password);
+                        }
+                    }
+                    else if (database.securityMechanism ==
+                                                CodePoint.SECMEC_USRSSBPWD)
+                    {
+                        if (database.passwordSubstitute == null)
+                        {
+                            database.passwordSubstitute = reader.readBytes();
+					        if (SanityManager.DEBUG)
+                                trace("** Substitute Password is:" +
+                                      DecryptionManager.toHexString(
+                                        database.passwordSubstitute, 0,
+                                        database.passwordSubstitute.length));
+                            database.password =
+                                DecryptionManager.toHexString(
+                                    database.passwordSubstitute, 0,
+                                    database.passwordSubstitute.length);
+                        }
+                    }
 					else
 					{
 						tooMany(CodePoint.SECTKN);
@@ -2732,7 +2865,7 @@
 		{
 			if (database.userId == null)
 				securityCheckCode = CodePoint.SECCHKCD_USERIDMISSING;
-			else if ( database.securityMechanism == CodePoint.SECMEC_USRIDPWD)
+			else if (database.securityMechanism == CodePoint.SECMEC_USRIDPWD)
 			{
 			    if (database.password == null)
 				securityCheckCode = CodePoint.SECCHKCD_PASSWORDMISSING;
@@ -2740,6 +2873,16 @@
 			//Note, we'll ignore encryptedUserId and encryptedPassword if they
 			//are also set
 		}
+
+		if (securityCheckCode == 0 && 
+				database.securityMechanism == CodePoint.SECMEC_USRSSBPWD)
+		{
+			if (database.userId == null)
+				securityCheckCode = CodePoint.SECCHKCD_USERIDMISSING;
+			else if (database.passwordSubstitute == null)
+				securityCheckCode = CodePoint.SECCHKCD_PASSWORDMISSING;
+		}
+
 		if (securityCheckCode == 0 && 
 				database.securityMechanism == CodePoint.SECMEC_EUSRIDPWD)
 		{
@@ -2747,7 +2890,6 @@
 				securityCheckCode = CodePoint.SECCHKCD_USERIDMISSING;
 			else if (database.decryptedPassword == null)
 				securityCheckCode = CodePoint.SECCHKCD_PASSWORDMISSING;
-
 		}
 		// RESOLVE - when we do security we need to decrypt encrypted userid & password
 		// before proceeding
@@ -7703,6 +7845,135 @@
 
 	}
 
+    /**
+     *  Validate SECMEC_USRSSBPWD (Strong Password Substitute) can be used as
+     *  DRDA security mechanism.
+     *
+     *	Here we check that the target server can support SECMEC_USRSSBPWD
+     *	security mechanism based on the environment, application
+     *	requester's identity (PRDID) and connection URL.
+     *
+     *	IMPORTANT NOTE:
+     *	--------------
+     *	SECMEC_USRSSBPWD is ONLY supported by the target server if:
+     *	    - current authentication provider is Derby BUILTIN or
+     *	      NONE. (database / system level) (Phase I)
+     *		- Application requester is 'DNC' (Derby Network Client)
+     *		  (Phase I)
+     *
+     *  @return security check code - 0 if everything O.K.
+     */
+    private int validateSecMecUSRSSBPWD() throws  DRDAProtocolException
+    {
+        String dbName = null;
+        AuthenticationService authenticationService = null;
+        org.apache.derby.iapi.db.Database databaseObj = null;
+        String srvrlslv = appRequester.srvrlslv;
+
+        // Check if application requester is the Derby Network Client (DNC)
+        //
+        // We use a trick here - as the product ID is not yet available
+        // since ACCRDB message is only coming later, we check the server
+        // release level field sent as part of the initial EXCSAT message;
+        // indeed, the product ID (PRDID) is prefixed to in the field.
+        // Derby always sets it as part of the EXCSAT message so if it is
+        // not available, we stop here and inform the requester that
+        // SECMEC_USRSSBPWD cannot be supported for this connection.
+        if ((srvrlslv == null) || (srvrlslv.length() == 0) ||
+            (srvrlslv.length() < CodePoint.PRDID_MAX) ||
+            (srvrlslv.indexOf(DRDAConstants.DERBY_DRDA_CLIENT_ID)
+                    == -1))
+            return CodePoint.SECCHKCD_NOTSUPPORTED; // Not Supported
+
+
+        // Client product version is extracted from the srvrlslv field.
+        // srvrlslv has the format <PRDID>/<ALTERNATE VERSION FORMAT>
+        // typically, a known Derby client has a four part version number
+        // with a pattern such as DNC10020/10.2.0.3 alpha. If the alternate
+        // version format is not specified, clientProductVersion_ will just
+        // be set to the srvrlslvl. Final fallback will be the product id.
+        //
+        // SECMEC_USRSSBPWD is only supported by the Derby engine and network
+        // server code starting at version major '10' and minor '02'. Hence,
+        // as this is the same for the derby client driver, we need to ensure
+        // our DNC client is at version and release level of 10.2 at least.
+        // We set the client version in the application requester and check
+        // if it is at the level we require at a minimum.
+        appRequester.setClientVersion(
+                srvrlslv.substring(0, (int) CodePoint.PRDID_MAX));
+
+        if (appRequester.supportsSecMecUSRSSBPWD() == false)
+            return CodePoint.SECCHKCD_NOTSUPPORTED; // Not Supported
+
+        dbName = database.shortDbName;
+        // Check if the database is available (booted)
+        // 
+        // First we need to have the database name available and it should
+        // have been set as part of the ACCSEC request (in the case of a Derby
+        // 'DNC' client)
+        if ((dbName == null) || (dbName.length() == 0))
+        {
+            // No database specified in the connection URL attributes
+            //
+            // In this case, we get the authentication service handle from the
+            // local driver, as the requester may simply be trying to shutdown
+            // the engine.
+            authenticationService = ((InternalDriver)
+              NetworkServerControlImpl.getDriver()).getAuthenticationService();
+        }
+        else
+        {
+            // We get the authentication service from the database as this
+            // last one might have specified its own auth provider (at the
+            // database level).
+            // 
+            // if monitor is never setup by any ModuleControl, getMonitor
+            // returns null and no cloudscape database has been booted. 
+            if (Monitor.getMonitor() != null)
+                databaseObj = (org.apache.derby.iapi.db.Database)
+                    Monitor.findService(Property.DATABASE_MODULE, dbName);
+
+            if (databaseObj == null)
+            {
+                // If database is not found, try connecting to it. 
+                database.makeDummyConnection();
+
+                // now try to find it again
+                databaseObj = (org.apache.derby.iapi.db.Database)
+                    Monitor.findService(Property.DATABASE_MODULE, dbName);
+            }
+
+            // If database still could not be found, it means the database
+            // does not exist - we just return security mechanism not
+            // supported down below as we could not verify we can handle
+            // it.
+            if (databaseObj != null)
+                authenticationService =
+                        databaseObj.getAuthenticationService();
+        }
+
+        // Now we check if the authentication provider is NONE or BUILTIN
+        if (authenticationService != null)
+        {
+            String authClassName = authenticationService.getClass().getName();
+                
+            if (!authClassName.equals(AUTHENTICATION_PROVIDER_BUILTIN_CLASS) &&
+                !authClassName.equals(AUTHENTICATION_PROVIDER_NONE_CLASS))
+                return CodePoint.SECCHKCD_NOTSUPPORTED; // Not Supported
+        }
+
+        // SECMEC_USRSSBPWD target initialization
+        try {
+            myTargetSeed = decryptionManager.generateSeed();
+            database.secTokenOut = myTargetSeed;
+        } catch (SQLException se) {
+            println2Log(null, session.drdaID, se.getMessage());
+            // Local security service non-retryable error.
+           return CodePoint.SECCHKCD_0A;
+        }
+                                
+        return 0; // SECMEC_USRSSBPWD is supported
+    }
     
     private static int peekStream(EXTDTAInputStream is) throws IOException{
 	
@@ -7730,6 +8001,4 @@
 	}
 	
     }
-    
-    
 }

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/Database.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/Database.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/Database.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/Database.java Wed Aug  9 06:51:30 2006
@@ -35,6 +35,7 @@
 import org.apache.derby.iapi.reference.Attribute;
 import org.apache.derby.iapi.tools.i18n.LocalizedResource;
 import org.apache.derby.iapi.services.sanity.SanityManager;
+
 /**
 	Database stores information about the current database
 	It is used so that a session may have more than one database
@@ -50,12 +51,13 @@
 	protected String password;			// password
 	protected String decryptedUserId;	// Decrypted User id
 	protected String decryptedPassword;	// Decrypted password
+    protected byte[] passwordSubstitute;// password substitute - SECMEC_USRSSBPWD
 	protected boolean rdbAllowUpdates = true; // Database allows updates -default is true		
 	protected int	accessCount;		// Number of times we have tried to
 										// set up access to this database (only 1 
 										// allowed)
-	protected byte[] publicKeyIn;		// Security token from app requester
-	protected byte[] publicKeyOut;		// Security token sent to app requester
+    protected byte[] secTokenIn;		// Security token from app requester
+    protected byte[] secTokenOut;		// Security token sent to app requester
 	protected byte[] crrtkn;			// Correlation token
 	protected String typDefNam;			// Type definition name
 	protected int byteOrder;			//deduced from typDefNam, save String comparisons
@@ -223,8 +225,8 @@
 	{
 		p.put(Attribute.USERNAME_ATTR, userId);
                 
-                // take care of case of SECMEC_USRIDONL
-                if(password != null) 
+        // take care of case of SECMEC_USRIDONL
+        if (password != null) 
 		    p.put(Attribute.PASSWORD_ATTR, password);
                 
         // Contract between network server and embedded engine
@@ -232,12 +234,37 @@
         EngineConnection conn = (EngineConnection)
             NetworkServerControlImpl.getDriver().connect(Attribute.PROTOCOL
 							 + shortDbName + attrString, p);
-		if(conn != null){
+		if (conn != null) {
 			conn.setAutoCommit(false);
 		}
 		setConnection(conn);
 	}
 
+    /**
+     * This makes a dummy connection to the database in order to 
+     * boot and/or create this last one. If database cannot
+     * be found or authentication does not succeed, this will throw
+     * a SQLException which we catch and do nothing. We don't pass a
+     * userid and password here as we don't need to for the purpose
+     * of this method - main goal is to cause the database to be
+     * booted via a dummy connection.
+     */
+    void makeDummyConnection()
+    {
+        try {
+            // Contract between network server and embedded engine
+            // is that any connection returned implements EngineConnection.
+            EngineConnection conn = (EngineConnection)
+                NetworkServerControlImpl.getDriver().connect(Attribute.PROTOCOL
+                    + shortDbName + attrString, new Properties());
+
+            // If we succeeded in getting a connection, well just close it
+            if (conn != null) {
+                conn.close();
+            }
+        } catch (SQLException se) {} // Simply do nothing
+    }
+    
 	// Create string to pass to DataSource.setConnectionAttributes
 	String appendAttrString(Properties p)
 	{
@@ -248,7 +275,7 @@
 		while (pKeys.hasMoreElements()) 
 		{
 			String key = (String) pKeys.nextElement();
-			attrString +=";" + key  +"=" + p.getProperty(key);
+			attrString +=";" + key  + "=" + p.getProperty(key);
 		}
 
 		return attrString;
@@ -386,28 +413,15 @@
     public void reset()
     {
         // Reset variables for connection re-use. Currently only takes care
-        // of reset the variables that affect EUSRIDPWD security mechanism.  (DERBY-1080)
+        // of reset the variables that affect EUSRIDPWD and USRSSBPWD
+        // security mechanisms.  (DERBY-1080)
         decryptedUserId = null;
         decryptedPassword = null;
-        publicKeyIn = null;
-        publicKeyOut = null;
+        passwordSubstitute = null;
+        secTokenIn = null;
+        secTokenOut = null;
         userId = null;
         password = null;
         securityMechanism = 0;
     }
-        
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
-

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DecryptionManager.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DecryptionManager.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DecryptionManager.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DecryptionManager.java Wed Aug  9 06:51:30 2006
@@ -35,6 +35,7 @@
 import java.security.PublicKey;
 import java.sql.SQLException;
 import java.math.BigInteger;
+import org.apache.derby.shared.common.sanity.SanityManager;
 
 /**
  * This class is used to decrypt password and/or userid.
@@ -89,6 +90,10 @@
   private KeyAgreement keyAgreement_;
   private DHParameterSpec paramSpec_;
 
+  // Random Number Generator (PRNG) Algorithm
+  private final static String SHA_1_PRNG_ALGORITHM = "SHA1PRNG";
+  private final static int SECMEC_USRSSBPWD_SEED_LEN = 8;  // Seed length
+
   /**
    * EncryptionManager constructor. In this constructor,DHParameterSpec,
    * KeyPairGenerator, KeyPair, and KeyAgreement  are initialized.
@@ -381,4 +386,109 @@
     }
     return plainText;
   }
+
+    /**
+     * This method generates an 8-Byte random seed.
+     *
+     * Required for the SECMEC_USRSSBPWD security mechanism
+     *
+     * @return a random 8-Byte seed.
+     */
+    protected static byte[] generateSeed() throws SQLException {
+        java.security.SecureRandom secureRandom = null;
+        try {
+          // We're verifying that we can instantiate a randon number
+          // generator (PRNG).
+          secureRandom =
+              java.security.SecureRandom.getInstance(SHA_1_PRNG_ALGORITHM);
+        } catch (java.security.NoSuchAlgorithmException nsae) {
+            throw new SQLException(
+                    "java.security.NoSuchAlgorithmException is caught" +
+                    " when initializing DecryptionManager '" +
+                    nsae.getMessage() + "'");
+        }
+        byte randomSeedBytes[] = new byte[SECMEC_USRSSBPWD_SEED_LEN];
+        secureRandom.setSeed(secureRandom.generateSeed(
+                                        SECMEC_USRSSBPWD_SEED_LEN));
+        secureRandom.nextBytes(randomSeedBytes);
+        // Return the 8-byte generated random seed
+        return randomSeedBytes;
+    }
+
+    /*********************************************************************
+     * RESOLVE:                                                          *
+     * The methods and static vars below should go into some 'shared'    *
+     * package when the capability is put back in (StringUtil.java).     *
+     *********************************************************************/
+
+    private static char[] hex_table = {
+                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
+                'a', 'b', 'c', 'd', 'e', 'f'
+            };
+    
+    /**
+        Convert a byte array to a String with a hexidecimal format.
+        The String may be converted back to a byte array using fromHexString.
+        <BR>
+        For each byte (b) two characaters are generated, the first character
+        represents the high nibble (4 bits) in hexidecimal (<code>b & 0xf0</code>),
+        the second character represents the low nibble (<code>b & 0x0f</code>).
+		<BR>
+        The byte at <code>data[offset]</code> is represented by the first two characters in the returned String.
+
+        @param	data	byte array
+        @param	offset	starting byte (zero based) to convert.
+        @param	length	number of bytes to convert.
+
+        @return the String (with hexidecimal format) form of the byte array
+    */
+    protected static String toHexString(byte[] data, int offset, int length)
+    {
+        StringBuffer s = new StringBuffer(length*2);
+        int end = offset+length;
+
+        for (int i = offset; i < end; i++)
+        {
+            int high_nibble = (data[i] & 0xf0) >>> 4;
+            int low_nibble = (data[i] & 0x0f);
+            s.append(hex_table[high_nibble]);
+            s.append(hex_table[low_nibble]);
+        }
+
+        return s.toString();
+    }
+
+    /**
+  
+        Convert a string into a byte array in hex format.
+        <BR>
+        For each character (b) two bytes are generated, the first byte 
+        represents the high nibble (4 bits) in hexidecimal (<code>b & 0xf0</code>),
+        the second byte 
+        represents the low nibble (<code>b & 0x0f</code>).
+        <BR>
+        The character at <code>str.charAt(0)</code> is represented by the first two bytes 
+        in the returned String.
+
+        @param	str string 
+        @param	offset	starting character (zero based) to convert.
+        @param	length	number of characters to convert.
+
+        @return the byte[]  (with hexidecimal format) form of the string (str) 
+    */
+    protected static byte[] toHexByte(String str, int offset, int length)
+    {
+  	    byte[] data = new byte[(length - offset) * 2];
+        int end = offset+length;
+
+        for (int i = offset; i < end; i++)
+ 	    {
+            char ch = str.charAt(i);
+            int high_nibble = (ch & 0xf0) >>> 4;
+            int low_nibble = (ch & 0x0f);
+            data[i] = (byte)high_nibble;
+            data[i+1] = (byte)low_nibble;
+        }
+        return data;
+    }
 }

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/NetworkServerControlImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/NetworkServerControlImpl.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/NetworkServerControlImpl.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/NetworkServerControlImpl.java Wed Aug  9 06:51:30 2006
@@ -2534,12 +2534,15 @@
     private int getSecMecValue(String s)
     {
         int secmec = INVALID_OR_NOTSET_SECURITYMECHANISM;
+
         if( StringUtil.SQLEqualsIgnoreCase(s,"USER_ONLY_SECURITY"))
                 secmec = CodePoint.SECMEC_USRIDONL;
         else if( StringUtil.SQLEqualsIgnoreCase(s,"CLEAR_TEXT_PASSWORD_SECURITY"))
                 secmec = CodePoint.SECMEC_USRIDPWD;
         else if( StringUtil.SQLEqualsIgnoreCase(s,"ENCRYPTED_USER_AND_PASSWORD_SECURITY"))
                 secmec = CodePoint.SECMEC_EUSRIDPWD;
+        else if( StringUtil.SQLEqualsIgnoreCase(s,"STRONG_PASSWORD_SUBSTITUTE_SECURITY"))
+                secmec = CodePoint.SECMEC_USRSSBPWD;
         
         return secmec;
     }
@@ -2563,6 +2566,9 @@
             
             case CodePoint.SECMEC_EUSRIDPWD:
                 return "ENCRYPTED_USER_AND_PASSWORD_SECURITY";
+            
+            case CodePoint.SECMEC_USRSSBPWD:
+                return "STRONG_PASSWORD_SUBSTITUTE_SECURITY";
         }
         return null;
     }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java Wed Aug  9 06:51:30 2006
@@ -222,13 +222,25 @@
 	 */
 	String RESTORE_FROM = "restoreFrom";
 
-	
 	/**
 		The attribute that is used to request a roll-forward recovery of the database.
 	*/
 	String ROLL_FORWARD_RECOVERY_FROM = "rollForwardRecoveryFrom";
 
+    /**
+     * securityMechanism sets the DRDA mechanism in-use for the client.
+     * Internal only.
+     */
+    String CLIENT_SECURITY_MECHANISM = "securityMechanism";
 
+    /**
+     * Internal attributes. Mainly used by DRDA and Derby BUILTIN
+     * authentication provider in some security mechanism context
+     * (SECMEC_USRSSBPWD).
+     *
+     * DRDA_SECTKN_IN is the random client seed (RDs)
+     * DRDA_SECTKN_OUT is the random server seed (RDr)
+     */
+    String DRDA_SECTKN_IN = "drdaSecTokenIn";
+    String DRDA_SECTKN_OUT = "drdaSecTokenOut";
 }
-
-

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java Wed Aug  9 06:51:30 2006
@@ -774,6 +774,7 @@
      * USER_ONLY_SECURITY
      * CLEAR_TEXT_PASSWORD_SECURITY
      * ENCRYPTED_USER_AND_PASSWORD_SECURITY
+     * STRONG_PASSWORD_SUBSTITUTE_SECURITY
      * <BR>
      * if derby.drda.securityMechanism is set to a valid mechanism, then
      * the Network Server accepts only connections which use that

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/util/StringUtil.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/util/StringUtil.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/util/StringUtil.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/util/StringUtil.java Wed Aug  9 06:51:30 2006
@@ -191,6 +191,39 @@
 
 		return s.toString();
 	}
+
+    /**
+
+        Convert a string into a byte array in hex format.
+        <BR>
+        For each character (b) two bytes are generated, the first byte 
+        represents the high nibble (4 bits) in hexidecimal (<code>b & 0xf0</code>),
+        the second byte represents the low nibble (<code>b & 0x0f</code>).
+        <BR>
+        The character at <code>str.charAt(0)</code> is represented by the first two bytes 
+        in the returned String.
+
+        @param	str string 
+        @param	offset	starting character (zero based) to convert.
+        @param	length	number of characters to convert.
+
+        @return the byte[]  (with hexidecimal format) form of the string (str) 
+    */
+    public static byte[] toHexByte(String str, int offset, int length)
+    {
+        byte[] data = new byte[(length - offset) * 2];
+        int end = offset+length;
+
+        for (int i = offset; i < end; i++)
+        {
+            char ch = str.charAt(i);
+            int high_nibble = (ch & 0xf0) >>> 4;
+            int low_nibble = (ch & 0x0f);
+            data[i] = (byte)high_nibble;
+            data[i+1] = (byte)low_nibble;
+        }
+        return data;
+    }
 		
 	/**
 		Convert a hexidecimal string generated by toHexString() back