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 467301) +++ 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 467301) +++ 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 467301) +++ 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/CertificateRequest.java =================================================================== --- modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/CertificateRequest.java (revision 467301) +++ modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/CertificateRequest.java (working copy) @@ -29,6 +29,7 @@ import java.io.IOException; import java.security.cert.X509Certificate; +import java.util.Vector; import javax.security.auth.x500.X500Principal; @@ -57,7 +58,7 @@ /** * Certificate authorities */ - final X500Principal[] certificate_authorities; + X500Principal[] certificate_authorities; //Requested certificate types as Strings // ("RSA", "DSA", "DH_RSA" or "DH_DSA") @@ -109,12 +110,17 @@ certificate_authorities = new X500Principal[size]; int totalPrincipalsLength = 0; int principalLength = 0; - for (int i = 0; i < size; i++) { + Vector principals = new Vector(); + while (totalPrincipalsLength < size) { principalLength = in.readUint16(); // encoded X500Principal size - certificate_authorities[i] = new X500Principal(in); + principals.add(new X500Principal(in)); totalPrincipalsLength += 2; totalPrincipalsLength += principalLength; } + certificate_authorities = new X500Principal[principals.size()]; + for (int i = 0; i < certificate_authorities.length; i++) { + certificate_authorities[i] = (X500Principal) principals.elementAt(i); + } this.length = 3 + certificate_types.length + totalPrincipalsLength; if (this.length != length) { fatalAlert(AlertProtocol.DECODE_ERROR, @@ -134,8 +140,12 @@ for (int i = 0; i < certificate_types.length; i++) { out.write(certificate_types[i]); } - out.writeUint16(certificate_authorities.length); + int authoritiesLength = 0; for (int i = 0; i < certificate_authorities.length; i++) { + authoritiesLength += encoded_principals[i].length +2; + } + out.writeUint16(authoritiesLength); + for (int i = 0; i < certificate_authorities.length; i++) { out.writeUint16(encoded_principals[i].length); out.write(encoded_principals[i]); } 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 467301) +++ 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 467301) +++ modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/CertificateVerify.java (working copy) @@ -49,7 +49,7 @@ */ public CertificateVerify(byte[] hash) { this.signedHash = hash; - length = hash.length; + length = hash.length + 2; } /** @@ -61,13 +61,14 @@ */ public CertificateVerify(HandshakeIODataStream in, int length) throws IOException { - if (length == 0) { + if (length == 2) { signedHash = new byte[0]; - } else if (length == 20 || length == 36) { - signedHash = in.read(length); } else { - fatalAlert(AlertProtocol.DECODE_ERROR, - "DECODE ERROR: incorrect CertificateVerify"); + if (in.readUint16() != length - 2) { + fatalAlert(AlertProtocol.DECODE_ERROR, + "DECODE ERROR: incorrect CertificateVerify"); + } + signedHash = in.read(length -2); } this.length = length; } @@ -79,6 +80,7 @@ */ public void send(HandshakeIODataStream out) { if (signedHash.length != 0) { + out.writeUint16(signedHash.length); out.write(signedHash); } } @@ -91,4 +93,4 @@ public int getType() { return Handshake.CERTIFICATE_VERIFY; } -} \ No newline at end of file +}