am 74e97557: am db219623: am a7a96f2e: SSLEngine: verify DHE signature

* commit '74e97557020b9b2c4452d65a371c284e69a757bb':
  SSLEngine: verify DHE signature
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java
index c855c0c..839237b 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java
@@ -438,59 +438,61 @@
                         "Unexpected exception", e);
                 return;
             }
-        } else {
+        } else if (session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_DSS
+                || session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_DSS_EXPORT
+                || session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_RSA
+                || session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_RSA_EXPORT
+                || session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_DH_anon
+                || session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_DH_anon_EXPORT) {
+            /*
+             * All other key exchanges should have had a DH key communicated via
+             * ServerKeyExchange beforehand.
+             */
+            if (serverKeyExchange == null) {
+                fatalAlert(AlertProtocol.UNEXPECTED_MESSAGE, "Expected ServerKeyExchange");
+                return;
+            }
+            if (session.cipherSuite.isAnonymous() != serverKeyExchange.isAnonymous()) {
+                fatalAlert(AlertProtocol.DECRYPT_ERROR, "Wrong type in ServerKeyExchange");
+                return;
+            }
             try {
+                if (!session.cipherSuite.isAnonymous()) {
+                    DigitalSignature ds = new DigitalSignature(serverCert.getAuthType());
+                    ds.init(serverCert.certs[0]);
+                    ds.update(clientHello.getRandom());
+                    ds.update(serverHello.getRandom());
+                    if (!serverKeyExchange.verifySignature(ds)) {
+                        fatalAlert(AlertProtocol.DECRYPT_ERROR, "Cannot verify DH params");
+                        return;
+                    }
+                }
                 KeyFactory kf = KeyFactory.getInstance("DH");
                 KeyAgreement agreement = KeyAgreement.getInstance("DH");
                 KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH");
-                PublicKey serverPublic;
-                DHParameterSpec spec;
-                if (serverKeyExchange != null) {
-                    serverPublic = kf.generatePublic(new DHPublicKeySpec(
-                            serverKeyExchange.par3, serverKeyExchange.par1,
-                            serverKeyExchange.par2));
-                    spec = new DHParameterSpec(serverKeyExchange.par1,
-                            serverKeyExchange.par2);
-                } else {
-                    serverPublic = serverCert.certs[0].getPublicKey();
-                    spec = ((DHPublicKey) serverPublic).getParams();
-                }
+                PublicKey serverDhPublic = kf.generatePublic(new DHPublicKeySpec(
+                        serverKeyExchange.par3, serverKeyExchange.par1,
+                        serverKeyExchange.par2));
+                DHParameterSpec spec = new DHParameterSpec(serverKeyExchange.par1,
+                        serverKeyExchange.par2);
                 kpg.initialize(spec);
-
                 KeyPair kp = kpg.generateKeyPair();
-                Key key = kp.getPublic();
-                if (clientCert != null
-                        && serverCert != null
-                        && (session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_RSA
-                                || session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_DSS)) {
-                    PublicKey client_pk = clientCert.certs[0].getPublicKey();
-                    PublicKey server_pk = serverCert.certs[0].getPublicKey();
-                    if (client_pk instanceof DHKey
-                            && server_pk instanceof DHKey) {
-                        if (((DHKey) client_pk).getParams().getG().equals(
-                                ((DHKey) server_pk).getParams().getG())
-                                && ((DHKey) client_pk).getParams().getP()
-                                    .equals(((DHKey) server_pk).getParams().getG())) {
-                            // client cert message DH public key parameters
-                            // matched those specified by the
-                            //   server in its certificate,
-                            clientKeyExchange = new ClientKeyExchange(); // empty
-                        }
-                    }
-                } else {
-                    clientKeyExchange = new ClientKeyExchange(
-                            ((DHPublicKey) key).getY());
-                }
-                key = kp.getPrivate();
-                agreement.init(key);
-                agreement.doPhase(serverPublic, true);
+                DHPublicKey pubDhKey = (DHPublicKey) kp.getPublic();
+                clientKeyExchange = new ClientKeyExchange(pubDhKey.getY());
+                PrivateKey privDhKey = kp.getPrivate();
+                agreement.init(privDhKey);
+                agreement.doPhase(serverDhPublic, true);
                 preMasterSecret = agreement.generateSecret();
             } catch (Exception e) {
                 fatalAlert(AlertProtocol.INTERNAL_ERROR,
                         "Unexpected exception", e);
                 return;
             }
+        } else {
+            fatalAlert(AlertProtocol.DECRYPT_ERROR, "Unsupported handshake type");
+            return;
         }
+
         if (clientKeyExchange != null) {
             send(clientKeyExchange);
         }
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/DigitalSignature.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/DigitalSignature.java
index af12bb3..ade2c7a 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/DigitalSignature.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/DigitalSignature.java
@@ -211,6 +211,9 @@
     public boolean verifySignature(byte[] data) {
         if (signature != null) {
             try {
+                if (sha_hash == null) {
+                    sha_hash = sha.digest();
+                }
                 signature.update(sha_hash);
                 return signature.verify(data);
             } catch (SignatureException e) {
@@ -229,6 +232,12 @@
             }
 
             final byte[] md5_sha;
+            if (sha != null && sha_hash == null) {
+                sha_hash = sha.digest();
+            }
+            if (md5 != null && md5_hash == null) {
+                md5_hash = md5.digest();
+            }
             if (md5_hash != null && sha_hash != null) {
                 md5_sha = new byte[md5_hash.length + sha_hash.length];
                 System.arraycopy(md5_hash, 0, md5_sha, 0, md5_hash.length);
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java
index fa8d291..29cb9cd 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java
@@ -522,36 +522,13 @@
                     ds.update(clientHello.getRandom());
                     ds.update(serverHello.getRandom());
 
-                    byte[] tmp;
-                    byte[] tmpLength = new byte[2];
 //FIXME 1_byte==0x00
                     if (cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_RSA_EXPORT) {
-                        tmp = ServerKeyExchange.toUnsignedByteArray(rsakey.getModulus());
-                        tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
-                        tmpLength[1] = (byte) (tmp.length & 0xFF);
-                        ds.update(tmpLength);
-                        ds.update(tmp);
-                        tmp = ServerKeyExchange.toUnsignedByteArray(rsakey.getPublicExponent());
-                        tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
-                        tmpLength[1] = (byte) (tmp.length & 0xFF);
-                        ds.update(tmpLength);
-                        ds.update(tmp);
+                        ServerKeyExchange.updateSignatureRsa(ds, rsakey.getModulus(),
+                                rsakey.getPublicExponent());
                     } else {
-                        tmp = ServerKeyExchange.toUnsignedByteArray(dhkeySpec.getP());
-                        tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
-                        tmpLength[1] = (byte) (tmp.length & 0xFF);
-                        ds.update(tmpLength);
-                        ds.update(tmp);
-                        tmp = ServerKeyExchange.toUnsignedByteArray(dhkeySpec.getG());
-                        tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
-                        tmpLength[1] = (byte) (tmp.length & 0xFF);
-                        ds.update(tmpLength);
-                        ds.update(tmp);
-                        tmp = ServerKeyExchange.toUnsignedByteArray(dhkeySpec.getY());
-                        tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
-                        tmpLength[1] = (byte) (tmp.length & 0xFF);
-                        ds.update(tmpLength);
-                        ds.update(tmp);
+                        ServerKeyExchange.updateSignatureDh(ds, dhkeySpec.getP(), dhkeySpec.getG(),
+                                dhkeySpec.getY());
                     }
                     hash = ds.sign();
                 } else {
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerKeyExchange.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerKeyExchange.java
index fea8076..7ccaf7cd3 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerKeyExchange.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerKeyExchange.java
@@ -98,6 +98,60 @@
         }
     }
 
+    public static void updateSignatureRsa(DigitalSignature ds, BigInteger modulus,
+            BigInteger publicExponent) {
+        byte[] tmp;
+        byte[] tmpLength = new byte[2];
+        tmp = ServerKeyExchange.toUnsignedByteArray(modulus);
+        tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
+        tmpLength[1] = (byte) (tmp.length & 0xFF);
+        ds.update(tmpLength);
+        ds.update(tmp);
+        tmp = ServerKeyExchange.toUnsignedByteArray(publicExponent);
+        tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
+        tmpLength[1] = (byte) (tmp.length & 0xFF);
+        ds.update(tmpLength);
+        ds.update(tmp);
+    }
+
+    public static void updateSignatureDh(DigitalSignature ds, BigInteger p, BigInteger g,
+            BigInteger y) {
+        byte[] tmp;
+        byte[] tmpLength = new byte[2];
+        tmp = ServerKeyExchange.toUnsignedByteArray(p);
+        tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
+        tmpLength[1] = (byte) (tmp.length & 0xFF);
+        ds.update(tmpLength);
+        ds.update(tmp);
+        tmp = ServerKeyExchange.toUnsignedByteArray(g);
+        tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
+        tmpLength[1] = (byte) (tmp.length & 0xFF);
+        ds.update(tmpLength);
+        ds.update(tmp);
+        tmp = ServerKeyExchange.toUnsignedByteArray(y);
+        tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
+        tmpLength[1] = (byte) (tmp.length & 0xFF);
+        ds.update(tmpLength);
+        ds.update(tmp);
+    }
+
+    public boolean verifySignature(DigitalSignature ds) {
+        if (par3 != null) {
+            updateSignatureDh(ds, par1, par2, par3);
+        } else {
+            updateSignatureRsa(ds, par1, par2);
+        }
+        return ds.verifySignature(hash);
+    }
+
+    /**
+     * Will return {@code true} if the signature is {@code null} since this is
+     * considered anonymous.
+     */
+    public boolean isAnonymous() {
+        return hash == null;
+    }
+
     /**
      * Creates inbound message
      * @param in