Hi Gerald,

Boris and I resolved the problem. This was an incorrect "Certificate
Verify" message sent to the server peer during mutual authentication.
Please try the attached patch and tell us how it works. If it is OK
for you I will attach it to the JIRA report you created (when the
server will work). Please, note – this patch should be applied on the
current JSSE source versions (i.e. without early applied patches).

Actually Harmony supports PKCS12 keystore format. But there is an
issue with using it. We now work on this problem.

Thanks for your collaboration in making Harmony's JSSE Provider more
stable and robust! We really appreciate you support!

Regards,
Alexander Kleymenov
Index: 
modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/DigitalSignature.java
===================================================================
--- 
modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/DigitalSignature.java
     (revision 466004)
+++ 
modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/DigitalSignature.java
     (working copy)
@@ -71,6 +71,7 @@
     public DigitalSignature(int keyExchange) {
         try { 
             if (keyExchange == CipherSuite.KeyExchange_RSA_EXPORT ||
+                    keyExchange == CipherSuite.KeyExchange_RSA ||
                     keyExchange == CipherSuite.KeyExchange_DHE_RSA ||
                     keyExchange == CipherSuite.KeyExchange_DHE_RSA_EXPORT) {
                 // SignatureAlgorithm is rsa
Index: 
modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java
===================================================================
--- 
modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java
  (revision 466004)
+++ 
modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java
  (working copy)
@@ -29,6 +29,7 @@
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
 import java.security.PrivilegedExceptionAction;
 import java.security.PublicKey;
 import java.security.cert.CertificateException;
@@ -366,6 +367,8 @@
      * client messages, computers masterSecret, sends ChangeCipherSpec
      */
     void processServerHelloDone() {
+        PrivateKey clientKey = null;
+
         if (serverCert != null) {
             if (session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DH_anon
                     || session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DH_anon_EXPORT) {
@@ -389,8 +392,10 @@
                     .getTypesAsString(),
                     certificateRequest.certificate_authorities, null);
             if (clientAlias != null) {
-                certs = ((X509ExtendedKeyManager) parameters.getKeyManager())
-                        .getCertificateChain((clientAlias));
+                X509ExtendedKeyManager km = (X509ExtendedKeyManager) parameters
+                        .getKeyManager();
+                certs = km.getCertificateChain((clientAlias));
+                clientKey = km.getPrivateKey(clientAlias);
             }
             session.localCertificates = certs;
             clientCert = new CertificateMessage(certs);
@@ -503,27 +508,29 @@
 
         computerMasterSecret();
 
-        if (clientCert != null) {
-            boolean[] keyUsage = clientCert.certs[0].getKeyUsage();
-            if (keyUsage != null && keyUsage[0]) {
-                // Certificate verify
-                DigitalSignature ds = new DigitalSignature(
-                        session.cipherSuite.keyExchange);
-                if (session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_RSA_EXPORT
-                        || session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DHE_RSA
-                        || session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DHE_RSA_EXPORT) {
-                    ds.setMD5(io_stream.getDigestMD5());
-                    ds.setSHA(io_stream.getDigestSHA());
-                } else if (session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DHE_DSS
-                        || session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DHE_DSS_EXPORT) {
-                    ds.setSHA(io_stream.getDigestSHA());
-                // The Signature should be empty in case of anonimous 
signature algorithm:
-                // } else if (session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DH_anon ||
-                // session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DH_anon_EXPORT) {
-                }
-                certificateVerify = new CertificateVerify(ds.sign());
-                send(certificateVerify);
+        // send certificate verify for all certificates except those containing
+        // fixed DH parameters
+        if (clientCert != null && !clientKeyExchange.isEmpty()) {
+            // Certificate verify
+            DigitalSignature ds = new DigitalSignature(
+                    session.cipherSuite.keyExchange);
+            ds.init(clientKey);
+
+            if (session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_RSA_EXPORT
+                    || session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_RSA
+                    || session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DHE_RSA
+                    || session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DHE_RSA_EXPORT) { 
+                ds.setMD5(io_stream.getDigestMD5());
+                ds.setSHA(io_stream.getDigestSHA());
+            } else if (session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DHE_DSS
+                    || session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DHE_DSS_EXPORT) {
+                ds.setSHA(io_stream.getDigestSHA());
+            // The Signature should be empty in case of anonimous signature 
algorithm:
+            // } else if (session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DH_anon ||
+            //         session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DH_anon_EXPORT) {
             }
+            certificateVerify = new CertificateVerify(ds.sign());
+            send(certificateVerify);
         }
 
         sendChangeCipherSpec();
Index: 
modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/HandshakeIODataStream.java
===================================================================
--- 
modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/HandshakeIODataStream.java
        (revision 466004)
+++ 
modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/HandshakeIODataStream.java
        (working copy)
@@ -425,6 +425,30 @@
     }
 
     /**
+     * Returns the MD5 digest of the data passed throught the stream
+     * except last message
+     * @return MD5 digest
+     */
+    protected byte[] getDigestMD5withoutLast() {
+        synchronized (md5) {
+            md5.update(buffer, 0, marked_pos);
+            return md5.digest();
+        }
+    }
+
+    /**
+     * Returns the SHA-1 digest of the data passed throught the stream
+     * except last message
+     * @return SHA-1 digest
+     */
+    protected byte[] getDigestSHAwithoutLast() {
+        synchronized (sha) {
+            sha.update(buffer, 0, marked_pos);
+            return sha.digest();
+        }
+    }
+
+    /**
      * Returns all the data passed throught the stream
      * @return all the data passed throught the stream at the moment
      */
Index: 
modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java
===================================================================
--- 
modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java
  (revision 466004)
+++ 
modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java
  (working copy)
@@ -184,29 +184,19 @@
                     certificateVerify = new CertificateVerify(io_stream, 
length);
 
                     DigitalSignature ds = new 
DigitalSignature(session.cipherSuite.keyExchange);
+                    ds.init(serverCert.certs[0]);                 
                     byte[] md5_hash = null;
                     byte[] sha_hash = null;
-                    PublicKey pk = serverCert.certs[0].getPublicKey();
-                    if (session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_RSA_EXPORT) {
-                        int l;
-                        try {
-                            l = getRSAKeyLength(pk);
-                        } catch (Exception e) {
-                            fatalAlert(AlertProtocol.INTERNAL_ERROR,
-                                    "INTERNAL ERROR", e);
-                            return;
-                        }
-                        if (l > 512) { // key is longer than 512 bits
-                            md5_hash = io_stream.getDigestMD5();
-                            sha_hash = io_stream.getDigestSHA();
-                        }
-                    } else if (session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DHE_RSA
+
+                    if (session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_RSA_EXPORT
+                            || session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_RSA
+                            || session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DHE_RSA
                             || session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DHE_RSA_EXPORT) {
-                        md5_hash = io_stream.getDigestMD5();
-                        sha_hash = io_stream.getDigestSHA();
+                        md5_hash = io_stream.getDigestMD5withoutLast();
+                        sha_hash = io_stream.getDigestSHAwithoutLast();
                     } else if (session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DHE_DSS
                             || session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DHE_DSS_EXPORT) {
-                        sha_hash = io_stream.getDigestSHA();
+                        sha_hash = io_stream.getDigestSHAwithoutLast();
                     } else if (session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DH_anon
                             || session.cipherSuite.keyExchange == 
CipherSuite.KeyExchange_DH_anon_EXPORT) {
                     }
@@ -712,7 +702,7 @@
         } else {
             if ((parameters.getNeedClientAuth() && clientCert == null)
                     || clientKeyExchange == null
-                    || (clientKeyExchange.isEmpty() && certificateVerify == 
null)) {
+                    || (clientCert != null && !clientKeyExchange.isEmpty() && 
certificateVerify == null)) {
                 unexpectedMessage();
             } else {
                 changeCipherSpecReceived = true;
Index: 
modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/CertificateVerify.java
===================================================================
--- 
modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/CertificateVerify.java
    (revision 466004)
+++ 
modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/CertificateVerify.java
    (working copy)
@@ -63,11 +63,8 @@
             throws IOException {
         if (length == 0) {
             signedHash = new byte[0];
-        } else if (length == 20 || length == 36) {
-            signedHash = in.read(length);
         } else {
-            fatalAlert(AlertProtocol.DECODE_ERROR,
-                    "DECODE ERROR: incorrect CertificateVerify");
+            signedHash = in.read(length);
         }
         this.length = length;
     }

Reply via email to