changeset 3148:9d6a9f65d2bf

6916074: Add support for TLS 1.2 6985179: To support Server Name Indication extension for JSSE client Summary: Introduces the algorithm constraints to support signature and hash algorithm selection. Includes contributions from wetmore and weijung. Reviewed-by: wetmore, weijun
author xuelei
date Mon, 01 Nov 2010 22:02:35 -0700
parents e95c7f8979ee
children fdcb0f667b7d
files src/share/classes/com/sun/crypto/provider/AESCrypt.java src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java src/share/classes/com/sun/crypto/provider/DESedeCipher.java src/share/classes/com/sun/crypto/provider/DHPrivateKey.java src/share/classes/com/sun/crypto/provider/DHPublicKey.java src/share/classes/com/sun/crypto/provider/JceKeyStore.java src/share/classes/com/sun/crypto/provider/OAEPParameters.java src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java src/share/classes/com/sun/crypto/provider/SunJCE.java src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java src/share/classes/javax/net/ssl/ExtendedSSLSession.java src/share/classes/javax/net/ssl/HttpsURLConnection.java src/share/classes/javax/net/ssl/SSLEngine.java src/share/classes/javax/net/ssl/SSLParameters.java src/share/classes/javax/net/ssl/SSLServerSocket.java src/share/classes/javax/net/ssl/SSLSocket.java src/share/classes/javax/net/ssl/X509ExtendedTrustManager.java src/share/classes/sun/net/www/protocol/https/HttpsClient.java src/share/classes/sun/security/internal/interfaces/TlsMasterSecret.java src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java src/share/classes/sun/security/internal/spec/TlsKeyMaterialSpec.java src/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java src/share/classes/sun/security/internal/spec/TlsPrfParameterSpec.java src/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java src/share/classes/sun/security/pkcs11/SunPKCS11.java src/share/classes/sun/security/rsa/RSASignature.java src/share/classes/sun/security/ssl/CipherSuite.java src/share/classes/sun/security/ssl/ClientHandshaker.java src/share/classes/sun/security/ssl/HandshakeHash.java src/share/classes/sun/security/ssl/HandshakeMessage.java src/share/classes/sun/security/ssl/Handshaker.java src/share/classes/sun/security/ssl/HelloExtensions.java src/share/classes/sun/security/ssl/MAC.java src/share/classes/sun/security/ssl/ProtocolList.java src/share/classes/sun/security/ssl/ProtocolVersion.java src/share/classes/sun/security/ssl/RSAClientKeyExchange.java src/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java src/share/classes/sun/security/ssl/SSLContextImpl.java src/share/classes/sun/security/ssl/SSLEngineImpl.java src/share/classes/sun/security/ssl/SSLServerSocketImpl.java src/share/classes/sun/security/ssl/SSLSessionImpl.java src/share/classes/sun/security/ssl/SSLSocketImpl.java src/share/classes/sun/security/ssl/ServerHandshaker.java src/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java src/share/classes/sun/security/ssl/SunJSSE.java src/share/classes/sun/security/ssl/TrustManagerFactoryImpl.java src/share/classes/sun/security/ssl/X509KeyManagerImpl.java src/share/classes/sun/security/ssl/X509TrustManagerImpl.java test/com/sun/crypto/provider/TLS/TestKeyMaterial.java test/com/sun/crypto/provider/TLS/TestMasterSecret.java test/com/sun/crypto/provider/TLS/TestPRF.java test/com/sun/crypto/provider/TLS/TestPRF12.java test/com/sun/crypto/provider/TLS/TestPremaster.java test/com/sun/crypto/provider/TLS/Utils.java test/com/sun/crypto/provider/TLS/prf12data.txt test/sun/security/ec/TestEC.java test/sun/security/pkcs11/fips/ClientJSSEServerJSSE.java test/sun/security/pkcs11/tls/TestKeyMaterial.java test/sun/security/pkcs11/tls/TestMasterSecret.java test/sun/security/pkcs11/tls/TestPRF.java test/sun/security/pkcs11/tls/TestPremaster.java test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/ClientModeClientAuth.java test/sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/ClientServer.java test/sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/PKIXExtendedTM.java test/sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/SunX509ExtendedTM.java test/sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/X509ExtendedTMEnabled.java test/sun/security/ssl/javax/net/ssl/NewAPIs/CheckMyTrustedKeystore.java test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/Basics.java test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/TestAllSuites.java test/sun/security/ssl/sanity/ciphersuites/CheckCipherSuites.java test/sun/security/ssl/sanity/interop/CipherTest.java test/sun/security/ssl/sanity/interop/ClientJSSEServerJSSE.java test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/IPAddressDNSIdentities.java
diffstat 77 files changed, 7104 insertions(+), 864 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/crypto/provider/AESCrypt.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/com/sun/crypto/provider/AESCrypt.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -253,7 +253,8 @@
             for (j = 0; j < 8; j++) {
                 if (AA[i][j] != 0) {
                     AA[i][j] = (byte)
-                        alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255];
+                        alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF])
+                        % 255];
                 }
             }
             for (t = 0; t < 4; t++) {
--- a/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -92,7 +92,8 @@
     }
 
     // core crypt code. OFB style, so works for both encryption and decryption
-    private void crypt(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) {
+    private void crypt(byte[] in, int inOfs, int inLen, byte[] out,
+            int outOfs) {
         if (is < 0) {
             // doFinal() was called, need to reset the cipher to initial state
             init(lastKey);
--- a/src/share/classes/com/sun/crypto/provider/DESedeCipher.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/com/sun/crypto/provider/DESedeCipher.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,8 +31,8 @@
 import javax.crypto.spec.*;
 
 /**
- * This class implements the DESede algorithm (DES-EDE, tripleDES) in its various
- * modes (<code>ECB</code>, <code>CFB</code>, <code>OFB</code>,
+ * This class implements the DESede algorithm (DES-EDE, tripleDES) in
+ * its various modes (<code>ECB</code>, <code>CFB</code>, <code>OFB</code>,
  * <code>CBC</code>, <code>PCBC</code>) and padding schemes
  * (<code>PKCS5Padding</code>, <code>NoPadding</code>,
  * <code>ISO10126Padding</code>).
--- a/src/share/classes/com/sun/crypto/provider/DHPrivateKey.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/com/sun/crypto/provider/DHPrivateKey.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -190,7 +190,8 @@
             ike.initCause(e);
             throw ike;
         } catch (IOException e) {
-            InvalidKeyException ike = new InvalidKeyException("Error parsing key encoding: " + e.getMessage());
+            InvalidKeyException ike = new InvalidKeyException(
+                "Error parsing key encoding: " + e.getMessage());
             ike.initCause(e);
             throw ike;
         }
@@ -300,7 +301,8 @@
             DerInputStream in = new DerInputStream(this.key);
             this.x = in.getBigInteger();
         } catch (IOException e) {
-            InvalidKeyException ike = new InvalidKeyException("Error parsing key encoding: " + e.getMessage());
+            InvalidKeyException ike = new InvalidKeyException(
+                "Error parsing key encoding: " + e.getMessage());
             ike.initCause(e);
             throw ike;
         }
--- a/src/share/classes/com/sun/crypto/provider/DHPublicKey.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/com/sun/crypto/provider/DHPublicKey.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -180,7 +180,8 @@
             throw new InvalidKeyException("Private-value length too big");
 
         } catch (IOException e) {
-            throw new InvalidKeyException("Error parsing key encoding: " + e.toString());
+            throw new InvalidKeyException(
+                "Error parsing key encoding: " + e.toString());
         }
     }
 
@@ -281,7 +282,8 @@
             DerInputStream in = new DerInputStream(this.key);
             this.y = in.getBigInteger();
         } catch (IOException e) {
-            throw new InvalidKeyException("Error parsing key encoding: " + e.toString());
+            throw new InvalidKeyException(
+                "Error parsing key encoding: " + e.toString());
         }
     }
 
--- a/src/share/classes/com/sun/crypto/provider/JceKeyStore.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/com/sun/crypto/provider/JceKeyStore.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -764,7 +764,8 @@
                                     cf = (CertificateFactory)cfs.get(certType);
                                 } else {
                                 // create new certificate factory
-                                    cf = CertificateFactory.getInstance(certType);
+                                    cf = CertificateFactory.getInstance(
+                                        certType);
                                 // store the certificate factory so we can
                                 // reuse it later
                                     cfs.put(certType, cf);
@@ -863,8 +864,9 @@
                     dis.readFully(actual);
                     for (int i = 0; i < computed.length; i++) {
                         if (computed[i] != actual[i]) {
-                            throw new IOException("Keystore was tampered with, or "
-                                                  + "password was incorrect");
+                            throw new IOException(
+                                "Keystore was tampered with, or "
+                                + "password was incorrect");
                         }
                     }
                 }
--- a/src/share/classes/com/sun/crypto/provider/OAEPParameters.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/com/sun/crypto/provider/OAEPParameters.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -139,7 +139,8 @@
                 if (!val.getOID().equals((Object) OID_MGF1)) {
                     throw new IOException("Only MGF1 mgf is supported");
                 }
-                AlgorithmId params = AlgorithmId.parse(new DerValue(val.getEncodedParams()));
+                AlgorithmId params = AlgorithmId.parse(
+                    new DerValue(val.getEncodedParams()));
                 String mgfDigestName = convertToStandardName(params.getName());
                 if (mgfDigestName.equals("SHA-1")) {
                     mgfSpec = MGF1ParameterSpec.SHA1;
@@ -150,7 +151,8 @@
                 } else if (mgfDigestName.equals("SHA-512")) {
                     mgfSpec = MGF1ParameterSpec.SHA512;
                 } else {
-                    throw new IOException("Unrecognized message digest algorithm");
+                    throw new IOException(
+                        "Unrecognized message digest algorithm");
                 }
             } else if (data.isContextSpecific((byte) 0x02)) {
                 // pSource algid
--- a/src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -121,8 +121,8 @@
         this.key = deriveKey(prf, passwdBytes, salt, iterCount, keyLength);
     }
 
-    private static byte[] deriveKey(final Mac prf, final byte[] password, byte[] salt,
-                                    int iterCount, int keyLengthInBit) {
+    private static byte[] deriveKey(final Mac prf, final byte[] password,
+            byte[] salt, int iterCount, int keyLengthInBit) {
         int keyLength = keyLengthInBit/8;
         byte[] key = new byte[keyLength];
         try {
@@ -155,8 +155,9 @@
                     if (this == obj) return true;
                     if (this.getClass() != obj.getClass()) return false;
                     SecretKey sk = (SecretKey)obj;
-                    return prf.getAlgorithm().equalsIgnoreCase(sk.getAlgorithm()) &&
-                            Arrays.equals(password, sk.getEncoded());
+                    return prf.getAlgorithm().equalsIgnoreCase(
+                        sk.getAlgorithm()) &&
+                        Arrays.equals(password, sk.getEncoded());
                 }
             };
             prf.init(macKey);
--- a/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -206,7 +206,8 @@
                 (algo.equalsIgnoreCase("RC2")?"RC2_40":algo), "SunJCE");
         } catch (GeneralSecurityException gse) {
             // should never happen
-            throw new RuntimeException("SunJCE provider is not configured properly");
+            throw new RuntimeException(
+                "SunJCE provider is not configured properly");
         }
         try {
             params.init(pbeSpec);
@@ -316,7 +317,8 @@
             try {
                 paramSpec = params.getParameterSpec(PBEParameterSpec.class);
             } catch (InvalidParameterSpecException ipse) {
-                throw new InvalidAlgorithmParameterException("requires PBE parameters");
+                throw new InvalidAlgorithmParameterException(
+                    "requires PBE parameters");
             }
         }
         implInit(opmode, key, paramSpec, random);
--- a/src/share/classes/com/sun/crypto/provider/SunJCE.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/com/sun/crypto/provider/SunJCE.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -423,15 +423,31 @@
 
                 /*
                  * SSL/TLS mechanisms
+                 *
+                 * These are strictly internal implementations and may
+                 * be changed at any time.  These names were chosen
+                 * because PKCS11/SunPKCS11 does not yet have TLS1.2
+                 * mechanisms, and it will cause calls to come here.
                  */
                 put("KeyGenerator.SunTlsPrf",
-                        "com.sun.crypto.provider.TlsPrfGenerator");
+                        "com.sun.crypto.provider.TlsPrfGenerator$V10");
+                put("KeyGenerator.SunTls12Prf",
+                        "com.sun.crypto.provider.TlsPrfGenerator$V12");
+
+                put("KeyGenerator.SunTlsMasterSecret",
+                    "com.sun.crypto.provider.TlsMasterSecretGenerator");
+                put("Alg.Alias.KeyGenerator.SunTls12MasterSecret",
+                    "SunTlsMasterSecret");
+
+                put("KeyGenerator.SunTlsKeyMaterial",
+                    "com.sun.crypto.provider.TlsKeyMaterialGenerator");
+                put("Alg.Alias.KeyGenerator.SunTls12KeyMaterial",
+                    "SunTlsKeyMaterial");
+
                 put("KeyGenerator.SunTlsRsaPremasterSecret",
-                        "com.sun.crypto.provider.TlsRsaPremasterSecretGenerator");
-                put("KeyGenerator.SunTlsMasterSecret",
-                        "com.sun.crypto.provider.TlsMasterSecretGenerator");
-                put("KeyGenerator.SunTlsKeyMaterial",
-                        "com.sun.crypto.provider.TlsKeyMaterialGenerator");
+                    "com.sun.crypto.provider.TlsRsaPremasterSecretGenerator");
+                put("Alg.Alias.KeyGenerator.SunTls12RsaPremasterSecret",
+                    "SunTlsRsaPremasterSecret");
 
                 return null;
             }
--- a/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -65,12 +65,14 @@
         }
         this.spec = (TlsKeyMaterialParameterSpec)params;
         if ("RAW".equals(spec.getMasterSecret().getFormat()) == false) {
-            throw new InvalidAlgorithmParameterException("Key format must be RAW");
+            throw new InvalidAlgorithmParameterException(
+                "Key format must be RAW");
         }
-        protocolVersion = (spec.getMajorVersion() << 8) | spec.getMinorVersion();
-        if ((protocolVersion < 0x0300) || (protocolVersion > 0x0302)) {
-            throw new InvalidAlgorithmParameterException
-                ("Only SSL 3.0, TLS 1.0, and TLS 1.1 supported");
+        protocolVersion = (spec.getMajorVersion() << 8)
+            | spec.getMinorVersion();
+        if ((protocolVersion < 0x0300) || (protocolVersion > 0x0303)) {
+            throw new InvalidAlgorithmParameterException(
+                "Only SSL 3.0, TLS 1.0/1.1/1.2 supported");
         }
     }
 
@@ -80,8 +82,8 @@
 
     protected SecretKey engineGenerateKey() {
         if (spec == null) {
-            throw new IllegalStateException
-                ("TlsKeyMaterialGenerator must be initialized");
+            throw new IllegalStateException(
+                "TlsKeyMaterialGenerator must be initialized");
         }
         try {
             return engineGenerateKey0();
@@ -99,8 +101,8 @@
         SecretKey clientMacKey = null;
         SecretKey serverMacKey = null;
         SecretKey clientCipherKey = null;
+        SecretKey serverCipherKey = null;
         IvParameterSpec clientIv = null;
-        SecretKey serverCipherKey = null;
         IvParameterSpec serverIv = null;
 
         int macLength = spec.getMacKeyLength();
@@ -109,21 +111,33 @@
         int keyLength = spec.getCipherKeyLength();
         int ivLength = spec.getIvLength();
 
-        int keyBlockLen = macLength + keyLength + (isExportable ? 0 : ivLength);
+        int keyBlockLen = macLength + keyLength
+            + (isExportable ? 0 : ivLength);
         keyBlockLen <<= 1;
         byte[] keyBlock = new byte[keyBlockLen];
 
-        MessageDigest md5 = MessageDigest.getInstance("MD5");
-        MessageDigest sha = MessageDigest.getInstance("SHA1");
+        // These may be used again later for exportable suite calculations.
+        MessageDigest md5 = null;
+        MessageDigest sha = null;
 
         // generate key block
-        if (protocolVersion >= 0x0301) {
-            // TLS
+        if (protocolVersion >= 0x0303) {
+            // TLS 1.2
             byte[] seed = concat(serverRandom, clientRandom);
-            keyBlock = doPRF(masterSecret, LABEL_KEY_EXPANSION, seed,
+            keyBlock = doTLS12PRF(masterSecret, LABEL_KEY_EXPANSION, seed,
+                        keyBlockLen, spec.getPRFHashAlg(),
+                        spec.getPRFHashLength(), spec.getPRFBlockSize());
+        } else if (protocolVersion >= 0x0301) {
+            // TLS 1.0/1.1
+            md5 = MessageDigest.getInstance("MD5");
+            sha = MessageDigest.getInstance("SHA1");
+            byte[] seed = concat(serverRandom, clientRandom);
+            keyBlock = doTLS10PRF(masterSecret, LABEL_KEY_EXPANSION, seed,
                         keyBlockLen, md5, sha);
         } else {
             // SSL
+            md5 = MessageDigest.getInstance("MD5");
+            sha = MessageDigest.getInstance("SHA1");
             keyBlock = new byte[keyBlockLen];
 
             byte[] tmp = new byte[20];
@@ -169,6 +183,7 @@
 
         String alg = spec.getCipherAlgorithm();
 
+        // cipher keys
         byte[] clientKeyBytes = new byte[keyLength];
         System.arraycopy(keyBlock, ofs, clientKeyBytes, 0, keyLength);
         ofs += keyLength;
@@ -182,6 +197,7 @@
             clientCipherKey = new SecretKeySpec(clientKeyBytes, alg);
             serverCipherKey = new SecretKeySpec(serverKeyBytes, alg);
 
+            // IV keys if needed.
             if (ivLength != 0) {
                 tmp = new byte[ivLength];
 
@@ -194,21 +210,28 @@
                 serverIv = new IvParameterSpec(tmp);
             }
         } else {
+            // if exportable suites, calculate the alternate
             // cipher key expansion and IV generation
-            if (protocolVersion >= 0x0301) {
+            if (protocolVersion >= 0x0302) {
+                // TLS 1.1+
+                throw new RuntimeException(
+                    "Internal Error:  TLS 1.1+ should not be negotiating" +
+                    "exportable ciphersuites");
+            } else if (protocolVersion == 0x0301) {
+                // TLS 1.0
                 byte[] seed = concat(clientRandom, serverRandom);
 
-                tmp = doPRF(clientKeyBytes, LABEL_CLIENT_WRITE_KEY, seed,
+                tmp = doTLS10PRF(clientKeyBytes, LABEL_CLIENT_WRITE_KEY, seed,
                             expandedKeyLength, md5, sha);
                 clientCipherKey = new SecretKeySpec(tmp, alg);
 
-                tmp = doPRF(serverKeyBytes, LABEL_SERVER_WRITE_KEY, seed,
+                tmp = doTLS10PRF(serverKeyBytes, LABEL_SERVER_WRITE_KEY, seed,
                             expandedKeyLength, md5, sha);
                 serverCipherKey = new SecretKeySpec(tmp, alg);
 
                 if (ivLength != 0) {
                     tmp = new byte[ivLength];
-                    byte[] block = doPRF(null, LABEL_IV_BLOCK, seed,
+                    byte[] block = doTLS10PRF(null, LABEL_IV_BLOCK, seed,
                                 ivLength << 1, md5, sha);
                     System.arraycopy(block, 0, tmp, 0, ivLength);
                     clientIv = new IvParameterSpec(tmp);
@@ -216,6 +239,7 @@
                     serverIv = new IvParameterSpec(tmp);
                 }
             } else {
+                // SSLv3
                 tmp = new byte[expandedKeyLength];
 
                 md5.update(clientKeyBytes);
--- a/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -64,12 +64,14 @@
         }
         this.spec = (TlsMasterSecretParameterSpec)params;
         if ("RAW".equals(spec.getPremasterSecret().getFormat()) == false) {
-            throw new InvalidAlgorithmParameterException("Key format must be RAW");
+            throw new InvalidAlgorithmParameterException(
+                "Key format must be RAW");
         }
-        protocolVersion = (spec.getMajorVersion() << 8) | spec.getMinorVersion();
-        if ((protocolVersion < 0x0300) || (protocolVersion > 0x0302)) {
-            throw new InvalidAlgorithmParameterException
-                ("Only SSL 3.0, TLS 1.0, and TLS 1.1 supported");
+        protocolVersion = (spec.getMajorVersion() << 8)
+            | spec.getMinorVersion();
+        if ((protocolVersion < 0x0300) || (protocolVersion > 0x0303)) {
+            throw new InvalidAlgorithmParameterException(
+                "Only SSL 3.0, TLS 1.0/1.1/1.2 supported");
         }
     }
 
@@ -79,8 +81,8 @@
 
     protected SecretKey engineGenerateKey() {
         if (spec == null) {
-            throw new IllegalStateException
-                ("TlsMasterSecretGenerator must be initialized");
+            throw new IllegalStateException(
+                "TlsMasterSecretGenerator must be initialized");
         }
         SecretKey premasterKey = spec.getPremasterSecret();
         byte[] premaster = premasterKey.getEncoded();
@@ -103,7 +105,11 @@
 
             if (protocolVersion >= 0x0301) {
                 byte[] seed = concat(clientRandom, serverRandom);
-                master = doPRF(premaster, LABEL_MASTER_SECRET, seed, 48);
+                master = ((protocolVersion >= 0x0303) ?
+                    doTLS12PRF(premaster, LABEL_MASTER_SECRET, seed, 48,
+                        spec.getPRFHashAlg(), spec.getPRFHashLength(),
+                        spec.getPRFBlockSize()) :
+                    doTLS10PRF(premaster, LABEL_MASTER_SECRET, seed, 48));
             } else {
                 master = new byte[48];
                 MessageDigest md5 = MessageDigest.getInstance("MD5");
@@ -124,7 +130,8 @@
 
             }
 
-            return new TlsMasterSecretKey(master, premasterMajor, premasterMinor);
+            return new TlsMasterSecretKey(master, premasterMajor,
+                premasterMinor);
         } catch (NoSuchAlgorithmException e) {
             throw new ProviderException(e);
         } catch (DigestException e) {
--- a/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,11 +37,15 @@
 
 /**
  * KeyGenerator implementation for the TLS PRF function.
+ * <p>
+ * This class duplicates the HMAC functionality (RFC 2104) with
+ * performance optimizations (e.g. XOR'ing keys with padding doesn't
+ * need to be redone for each HMAC operation).
  *
  * @author  Andreas Sterbenz
  * @since   1.6
  */
-public final class TlsPrfGenerator extends KeyGeneratorSpi {
+abstract class TlsPrfGenerator extends KeyGeneratorSpi {
 
     // magic constants and utility functions, also used by other files
     // in this package
@@ -69,8 +73,10 @@
      * TLS HMAC "inner" and "outer" padding.  This isn't a function
      * of the digest algorithm.
      */
-    private static final byte[] HMAC_ipad = genPad((byte)0x36, 64);
-    private static final byte[] HMAC_opad = genPad((byte)0x5c, 64);
+    private static final byte[] HMAC_ipad64  = genPad((byte)0x36, 64);
+    private static final byte[] HMAC_ipad128 = genPad((byte)0x36, 128);
+    private static final byte[] HMAC_opad64  = genPad((byte)0x5c, 64);
+    private static final byte[] HMAC_opad128 = genPad((byte)0x5c, 128);
 
     // SSL3 magic mix constants ("A", "BB", "CCC", ...)
     final static byte[][] SSL3_CONST = genConst();
@@ -123,8 +129,8 @@
         this.spec = (TlsPrfParameterSpec)params;
         SecretKey key = spec.getSecret();
         if ((key != null) && ("RAW".equals(key.getFormat()) == false)) {
-            throw new InvalidAlgorithmParameterException
-                ("Key encoding format must be RAW");
+            throw new InvalidAlgorithmParameterException(
+                "Key encoding format must be RAW");
         }
     }
 
@@ -132,17 +138,21 @@
         throw new InvalidParameterException(MSG);
     }
 
-    protected SecretKey engineGenerateKey() {
+    SecretKey engineGenerateKey0(boolean tls12) {
         if (spec == null) {
-            throw new IllegalStateException
-                ("TlsPrfGenerator must be initialized");
+            throw new IllegalStateException(
+                "TlsPrfGenerator must be initialized");
         }
         SecretKey key = spec.getSecret();
         byte[] secret = (key == null) ? null : key.getEncoded();
         try {
             byte[] labelBytes = spec.getLabel().getBytes("UTF8");
             int n = spec.getOutputLength();
-            byte[] prfBytes = doPRF(secret, labelBytes, spec.getSeed(), n);
+            byte[] prfBytes = (tls12 ?
+                doTLS12PRF(secret, labelBytes, spec.getSeed(), n,
+                    spec.getPRFHashAlg(), spec.getPRFHashLength(),
+                    spec.getPRFBlockSize()) :
+                doTLS10PRF(secret, labelBytes, spec.getSeed(), n));
             return new SecretKeySpec(prfBytes, "TlsPrf");
         } catch (GeneralSecurityException e) {
             throw new ProviderException("Could not generate PRF", e);
@@ -151,16 +161,67 @@
         }
     }
 
-    static final byte[] doPRF(byte[] secret, byte[] labelBytes, byte[] seed,
-            int outputLength) throws NoSuchAlgorithmException, DigestException {
+    static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes,
+            byte[] seed, int outputLength,
+            String prfHash, int prfHashLength, int prfBlockSize)
+            throws NoSuchAlgorithmException, DigestException {
+        if (prfHash == null) {
+            throw new NoSuchAlgorithmException("Unspecified PRF algorithm");
+        }
+        MessageDigest prfMD = MessageDigest.getInstance(prfHash);
+        return doTLS12PRF(secret, labelBytes, seed, outputLength,
+            prfMD, prfHashLength, prfBlockSize);
+    }
+
+    static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes,
+            byte[] seed, int outputLength,
+            MessageDigest mdPRF, int mdPRFLen, int mdPRFBlockSize)
+            throws DigestException {
+
+        if (secret == null) {
+            secret = B0;
+        }
+
+        // If we have a long secret, digest it first.
+        if (secret.length > mdPRFBlockSize) {
+            secret = mdPRF.digest(secret);
+        }
+
+        byte[] output = new byte[outputLength];
+        byte [] ipad;
+        byte [] opad;
+
+        switch (mdPRFBlockSize) {
+        case 64:
+            ipad = HMAC_ipad64.clone();
+            opad = HMAC_opad64.clone();
+            break;
+        case 128:
+            ipad = HMAC_ipad128.clone();
+            opad = HMAC_opad128.clone();
+            break;
+        default:
+            throw new DigestException("Unexpected block size.");
+        }
+
+        // P_HASH(Secret, label + seed)
+        expand(mdPRF, mdPRFLen, secret, 0, secret.length, labelBytes,
+            seed, output, ipad, opad);
+
+        return output;
+    }
+
+    static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes,
+            byte[] seed, int outputLength) throws NoSuchAlgorithmException,
+            DigestException {
         MessageDigest md5 = MessageDigest.getInstance("MD5");
         MessageDigest sha = MessageDigest.getInstance("SHA1");
-        return doPRF(secret, labelBytes, seed, outputLength, md5, sha);
+        return doTLS10PRF(secret, labelBytes, seed, outputLength, md5, sha);
     }
 
-    static final byte[] doPRF(byte[] secret, byte[] labelBytes, byte[] seed,
-            int outputLength, MessageDigest md5, MessageDigest sha)
-            throws DigestException {
+    static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes,
+            byte[] seed, int outputLength, MessageDigest md5,
+            MessageDigest sha) throws DigestException {
         /*
          * Split the secret into two halves S1 and S2 of same length.
          * S1 is taken from the first half of the secret, S2 from the
@@ -183,10 +244,12 @@
         byte[] output = new byte[outputLength];
 
         // P_MD5(S1, label + seed)
-        expand(md5, 16, secret, 0, seclen, labelBytes, seed, output);
+        expand(md5, 16, secret, 0, seclen, labelBytes, seed, output,
+            HMAC_ipad64.clone(), HMAC_opad64.clone());
 
         // P_SHA-1(S2, label + seed)
-        expand(sha, 20, secret, off, seclen, labelBytes, seed, output);
+        expand(sha, 20, secret, off, seclen, labelBytes, seed, output,
+            HMAC_ipad64.clone(), HMAC_opad64.clone());
 
         return output;
     }
@@ -201,16 +264,13 @@
      * @param seed the seed
      * @param output the output array
      */
-    private static final void expand(MessageDigest digest, int hmacSize,
+    private static void expand(MessageDigest digest, int hmacSize,
             byte[] secret, int secOff, int secLen, byte[] label, byte[] seed,
-            byte[] output) throws DigestException {
+            byte[] output, byte[] pad1, byte[] pad2) throws DigestException {
         /*
          * modify the padding used, by XORing the key into our copy of that
          * padding.  That's to avoid doing that for each HMAC computation.
          */
-        byte[] pad1 = HMAC_ipad.clone();
-        byte[] pad2 = HMAC_opad.clone();
-
         for (int i = 0; i < secLen; i++) {
             pad1[i] ^= secret[i + secOff];
             pad2[i] ^= secret[i + secOff];
@@ -275,7 +335,34 @@
             }
             remaining -= k;
         }
-
     }
 
+    /**
+     * A KeyGenerator implementation that supports TLS 1.2.
+     * <p>
+     * TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the PRF
+     * calculations.  As of 2010, there is no PKCS11-level support for TLS
+     * 1.2 PRF calculations, and no known OS's have an internal variant
+     * we could use.  Therefore for TLS 1.2, we are updating JSSE to request
+     * a different provider algorithm:  "SunTls12Prf".  If we reused the
+     * name "SunTlsPrf", the PKCS11 provider would need be updated to
+     * fail correctly when presented with the wrong version number
+     * (via Provider.Service.supportsParameters()), and add the
+     * appropriate supportsParamters() checks into KeyGenerators (not
+     * currently there).
+     */
+    static public class V12 extends TlsPrfGenerator {
+        protected SecretKey engineGenerateKey() {
+            return engineGenerateKey0(true);
+        }
+    }
+
+    /**
+     * A KeyGenerator implementation that supports TLS 1.0/1.1.
+     */
+    static public class V10 extends TlsPrfGenerator {
+        protected SecretKey engineGenerateKey() {
+            return engineGenerateKey0(false);
+        }
+    }
 }
--- a/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -69,8 +69,8 @@
 
     protected SecretKey engineGenerateKey() {
         if (spec == null) {
-            throw new IllegalStateException
-                    ("TlsRsaPremasterSecretGenerator must be initialized");
+            throw new IllegalStateException(
+                "TlsRsaPremasterSecretGenerator must be initialized");
         }
         if (random == null) {
             random = new SecureRandom();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/javax/net/ssl/ExtendedSSLSession.java	Mon Nov 01 22:02:35 2010 -0700
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.net.ssl;
+
+/**
+ * Extends the <code>SSLSession</code> interface to support additional
+ * session attributes.
+ *
+ * @since 1.7
+ */
+public abstract class ExtendedSSLSession implements SSLSession {
+    /**
+     * Obtains an array of supported signature algorithms that the local side
+     * is willing to use.
+     * <p>
+     * Note: this method is used to indicate to the peer which signature
+     * algorithms may be used for digital signatures in TLS 1.2. It is
+     * not meaningful for TLS versions prior to 1.2.
+     * <p>
+     * The signature algorithm name must be a standard Java Security
+     * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
+     * See Appendix A in the <a href=
+     * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture API Specification &amp; Reference </a>
+     * for information about standard algorithm names.
+     * <p>
+     * Note: the local supported signature algorithms should conform to
+     * the algorithm constraints specified by
+     * {@link SSLParameters#getAlgorithmConstraints getAlgorithmConstraints()}
+     * method in <code>SSLParameters</code>.
+     *
+     * @return An array of supported signature algorithms, in descending
+     *     order of preference.  The return value is an empty array if
+     *     no signature algorithm is supported.
+     *
+     * @see SSLParameters#getAlgorithmConstraints
+     */
+    public abstract String[] getLocalSupportedSignatureAlgorithms();
+
+    /**
+     * Obtains an array of supported signature algorithms that the peer is
+     * able to use.
+     * <p>
+     * Note: this method is used to indicate to the local side which signature
+     * algorithms may be used for digital signatures in TLS 1.2. It is
+     * not meaningful for TLS versions prior to 1.2.
+     * <p>
+     * The signature algorithm name must be a standard Java Security
+     * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
+     * See Appendix A in the <a href=
+     * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture API Specification &amp; Reference </a>
+     * for information about standard algorithm names.
+     *
+     * @return An array of supported signature algorithms, in descending
+     *     order of preference.  The return value is an empty array if
+     *     the peer has not sent the supported signature algorithms.
+     *
+     * @see X509KeyManager
+     * @see X509ExtendedKeyManager
+     */
+    public abstract String[] getPeerSupportedSignatureAlgorithms();
+}
--- a/src/share/classes/javax/net/ssl/HttpsURLConnection.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/javax/net/ssl/HttpsURLConnection.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -188,19 +188,8 @@
      * <p>
      * The default implementation will deny such connections.
      */
-    private static HostnameVerifier defaultHostnameVerifier;
-
-    /**
-     * Initialize the default <code>HostnameVerifier</code>.
-     */
-    static {
-        try {
-            defaultHostnameVerifier =
-                new sun.net.www.protocol.https.DefaultHostnameVerifier();
-        } catch (NoClassDefFoundError e) {
-            defaultHostnameVerifier = new DefaultHostnameVerifier();
-        }
-    }
+    private static HostnameVerifier defaultHostnameVerifier =
+                                        new DefaultHostnameVerifier();
 
     /*
      * The initial default <code>HostnameVerifier</code>.  Should be
--- a/src/share/classes/javax/net/ssl/SSLEngine.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/javax/net/ssl/SSLEngine.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -968,6 +968,47 @@
 
 
     /**
+     * Returns the {@code SSLSession} being constructed during a SSL/TLS
+     * handshake.
+     * <p>
+     * TLS protocols may negotiate parameters that are needed when using
+     * an instance of this class, but before the {@code SSLSession} has
+     * been completely initialized and made available via {@code getSession}.
+     * For example, the list of valid signature algorithms may restrict
+     * the type of certificates that can used during TrustManager
+     * decisions, or the maximum TLS fragment packet sizes can be
+     * resized to better support the network environment.
+     * <p>
+     * This method provides early access to the {@code SSLSession} being
+     * constructed.  Depending on how far the handshake has progressed,
+     * some data may not yet be available for use.  For example, if a
+     * remote server will be sending a Certificate chain, but that chain
+     * has yet not been processed, the {@code getPeerCertificates}
+     * method of {@code SSLSession} will throw a
+     * SSLPeerUnverifiedException.  Once that chain has been processed,
+     * {@code getPeerCertificates} will return the proper value.
+     *
+     * @see SSLSocket
+     * @see SSLSession
+     * @see ExtendedSSLSession
+     * @see X509ExtendedKeyManager
+     * @see X509ExtendedTrustManager
+     *
+     * @return null if this instance is not currently handshaking, or
+     *         if the current handshake has not progressed far enough to
+     *         create a basic SSLSession.  Otherwise, this method returns the
+     *         {@code SSLSession} currently being negotiated.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     *
+     * @since 1.7
+     */
+    public SSLSession getHandshakeSession() {
+        throw new UnsupportedOperationException();
+    }
+
+
+    /**
      * Initiates handshaking (initial or renegotiation) on this SSLEngine.
      * <P>
      * This method is not needed for the initial handshake, as the
--- a/src/share/classes/javax/net/ssl/SSLParameters.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/javax/net/ssl/SSLParameters.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,24 +25,29 @@
 
 package javax.net.ssl;
 
+import java.security.AlgorithmConstraints;
+
 /**
  * Encapsulates parameters for an SSL/TLS connection. The parameters
  * are the list of ciphersuites to be accepted in an SSL/TLS handshake,
- * the list of protocols to be allowed, and whether SSL/TLS servers should
- * request or require client authentication.
- *
- * <p>SSLParameters can be created via the constructors in this class.
+ * the list of protocols to be allowed, the endpoint identification
+ * algorithm during SSL/TLS handshaking, the algorithm constraints and
+ * whether SSL/TLS servers should request or require client authentication.
+ * <p>
+ * SSLParameters can be created via the constructors in this class.
  * Objects can also be obtained using the <code>getSSLParameters()</code>
  * methods in
  * {@link SSLSocket#getSSLParameters SSLSocket} and
+ * {@link SSLServerSocket#getSSLParameters SSLServerSocket} and
  * {@link SSLEngine#getSSLParameters SSLEngine} or the
  * {@link SSLContext#getDefaultSSLParameters getDefaultSSLParameters()} and
  * {@link SSLContext#getSupportedSSLParameters getSupportedSSLParameters()}
  * methods in <code>SSLContext</code>.
- *
- * <P>SSLParameters can be applied to a connection via the methods
+ * <p>
+ * SSLParameters can be applied to a connection via the methods
  * {@link SSLSocket#setSSLParameters SSLSocket.setSSLParameters()} and
- * {@link SSLEngine#setSSLParameters SSLEngine.getSSLParameters()}.
+ * {@link SSLServerSocket#setSSLParameters SSLServerSocket.setSSLParameters()}
+ * and {@link SSLEngine#setSSLParameters SSLEngine.getSSLParameters()}.
  *
  * @see SSLSocket
  * @see SSLEngine
@@ -56,11 +61,13 @@
     private String[] protocols;
     private boolean wantClientAuth;
     private boolean needClientAuth;
+    private String identificationAlgorithm;
+    private AlgorithmConstraints algorithmConstraints;
 
     /**
      * Constructs SSLParameters.
-     *
-     * <p>The cipherSuites and protocols values are set to <code>null</code>,
+     * <p>
+     * The cipherSuites and protocols values are set to <code>null</code>,
      * wantClientAuth and needClientAuth are set to <code>false</code>.
      */
     public SSLParameters() {
@@ -69,6 +76,7 @@
 
     /**
      * Constructs SSLParameters from the specified array of ciphersuites.
+     * <p>
      * Calling this constructor is equivalent to calling the no-args
      * constructor followed by
      * <code>setCipherSuites(cipherSuites);</code>.
@@ -82,6 +90,7 @@
     /**
      * Constructs SSLParameters from the specified array of ciphersuites
      * and protocols.
+     * <p>
      * Calling this constructor is equivalent to calling the no-args
      * constructor followed by
      * <code>setCipherSuites(cipherSuites); setProtocols(protocols);</code>.
@@ -178,4 +187,71 @@
         this.needClientAuth = needClientAuth;
     }
 
+    /**
+     * Returns the cryptographic algorithm constraints.
+     *
+     * @return the cryptographic algorithm constraints, or null if the
+     *     constraints have not been set
+     *
+     * @see #setAlgorithmConstraints(AlgorithmConstraints)
+     *
+     * @since 1.7
+     */
+    public AlgorithmConstraints getAlgorithmConstraints() {
+        return algorithmConstraints;
+    }
+
+    /**
+     * Sets the cryptographic algorithm constraints, which will be used
+     * in addition to any configured by the runtime environment.
+     * <p>
+     * If the <code>constraints</code> parameter is non-null, every
+     * cryptographic algorithm, key and algorithm parameters used in the
+     * SSL/TLS handshake must be permitted by the constraints.
+     *
+     * @param constraints the algorithm constraints (or null)
+     *
+     * @since 1.7
+     */
+    public void setAlgorithmConstraints(AlgorithmConstraints constraints) {
+        // the constraints object is immutable
+        this.algorithmConstraints = constraints;
+    }
+
+    /**
+     * Gets the endpoint identification algorithm.
+     *
+     * @return the endpoint identification algorithm, or null if none
+     * has been set.
+     *
+     * @see X509ExtendedTrustManager
+     * @see #setEndpointIdentificationAlgorithm(String)
+     *
+     * @since 1.7
+     */
+    public String getEndpointIdentificationAlgorithm() {
+        return identificationAlgorithm;
+    }
+
+    /**
+     * Sets the endpoint identification algorithm.
+     * <p>
+     * If the <code>algorithm</code> parameter is non-null or non-empty, the
+     * endpoint identification/verification procedures must be handled during
+     * SSL/TLS handshaking.  This is to prevent man-in-the-middle attacks.
+     *
+     * @param algorithm The standard string name of the endpoint
+     *     identification algorithm (or null).  See Appendix A in the <a href=
+     *     "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     *     Java Cryptography Architecture API Specification &amp; Reference </a>
+     *     for information about standard algorithm names.
+     *
+     * @see X509ExtendedTrustManager
+     *
+     * @since 1.7
+     */
+    public void setEndpointIdentificationAlgorithm(String algorithm) {
+        this.identificationAlgorithm = algorithm;
+    }
+
 }
--- a/src/share/classes/javax/net/ssl/SSLServerSocket.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/javax/net/ssl/SSLServerSocket.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -56,8 +56,8 @@
  * @since 1.4
  * @author David Brownell
  */
-public abstract class SSLServerSocket extends ServerSocket
-{
+public abstract class SSLServerSocket extends ServerSocket {
+
     /**
      * Used only by subclasses.
      * <P>
@@ -449,8 +449,79 @@
      *
      * @return true indicates that sessions may be created; this
      *          is the default.  false indicates that an existing
-     *          session must be resumed.
+     *          session must be resumed
      * @see #setEnableSessionCreation(boolean)
      */
     public abstract boolean getEnableSessionCreation();
+
+    /**
+     * Returns the SSLParameters in effect for newly accepted connections.
+     * The ciphersuites and protocols of the returned SSLParameters
+     * are always non-null.
+     *
+     * @return the SSLParameters in effect for newly accepted connections
+     *
+     * @see #setSSLParameters(SSLParameters)
+     *
+     * @since 1.7
+     */
+    public SSLParameters getSSLParameters() {
+        SSLParameters parameters = new SSLParameters();
+
+        parameters.setCipherSuites(getEnabledCipherSuites());
+        parameters.setProtocols(getEnabledProtocols());
+        if (getNeedClientAuth()) {
+            parameters.setNeedClientAuth(true);
+        } else if (getWantClientAuth()) {
+            parameters.setWantClientAuth(true);
+        }
+
+        return parameters;
+    }
+
+    /**
+     * Applies SSLParameters to newly accepted connections.
+     *
+     * <p>This means:
+     * <ul>
+     * <li>if <code>params.getCipherSuites()</code> is non-null,
+     *   <code>setEnabledCipherSuites()</code> is called with that value
+     * <li>if <code>params.getProtocols()</code> is non-null,
+     *   <code>setEnabledProtocols()</code> is called with that value
+     * <li>if <code>params.getNeedClientAuth()</code> or
+     *   <code>params.getWantClientAuth()</code> return <code>true</code>,
+     *   <code>setNeedClientAuth(true)</code> and
+     *   <code>setWantClientAuth(true)</code> are called, respectively;
+     *   otherwise <code>setWantClientAuth(false)</code> is called.
+     * </ul>
+     *
+     * @param params the parameters
+     * @throws IllegalArgumentException if the setEnabledCipherSuites() or
+     *    the setEnabledProtocols() call fails
+     *
+     * @see #getSSLParameters()
+     *
+     * @since 1.7
+     */
+    public void setSSLParameters(SSLParameters params) {
+        String[] s;
+        s = params.getCipherSuites();
+        if (s != null) {
+            setEnabledCipherSuites(s);
+        }
+
+        s = params.getProtocols();
+        if (s != null) {
+            setEnabledProtocols(s);
+        }
+
+        if (params.getNeedClientAuth()) {
+            setNeedClientAuth(true);
+        } else if (params.getWantClientAuth()) {
+            setWantClientAuth(true);
+        } else {
+            setWantClientAuth(false);
+        }
+    }
+
 }
--- a/src/share/classes/javax/net/ssl/SSLSocket.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/javax/net/ssl/SSLSocket.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -371,6 +371,51 @@
 
 
     /**
+     * Returns the {@code SSLSession} being constructed during a SSL/TLS
+     * handshake.
+     * <p>
+     * TLS protocols may negotiate parameters that are needed when using
+     * an instance of this class, but before the {@code SSLSession} has
+     * been completely initialized and made available via {@code getSession}.
+     * For example, the list of valid signature algorithms may restrict
+     * the type of certificates that can used during TrustManager
+     * decisions, or the maximum TLS fragment packet sizes can be
+     * resized to better support the network environment.
+     * <p>
+     * This method provides early access to the {@code SSLSession} being
+     * constructed.  Depending on how far the handshake has progressed,
+     * some data may not yet be available for use.  For example, if a
+     * remote server will be sending a Certificate chain, but that chain
+     * has yet not been processed, the {@code getPeerCertificates}
+     * method of {@code SSLSession} will throw a
+     * SSLPeerUnverifiedException.  Once that chain has been processed,
+     * {@code getPeerCertificates} will return the proper value.
+     * <p>
+     * Unlike {@link #getSession()}, this method does not initiate the
+     * initial handshake and does not block until handshaking is
+     * complete.
+     *
+     * @see SSLEngine
+     * @see SSLSession
+     * @see ExtendedSSLSession
+     * @see X509ExtendedKeyManager
+     * @see X509ExtendedTrustManager
+     *
+     * @return null if this instance is not currently handshaking, or
+     *         if the current handshake has not progressed far enough to
+     *         create a basic SSLSession.  Otherwise, this method returns the
+     *         {@code SSLSession} currently being negotiated.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     *
+     * @since 1.7
+     */
+    public SSLSession getHandshakeSession() {
+        throw new UnsupportedOperationException();
+    }
+
+
+    /**
      * Registers an event listener to receive notifications that an
      * SSL handshake has completed on this connection.
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/javax/net/ssl/X509ExtendedTrustManager.java	Mon Nov 01 22:02:35 2010 -0700
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.net.ssl;
+
+import java.net.Socket;
+import javax.net.ssl.X509TrustManager;
+
+import java.security.cert.X509Certificate;
+import java.security.cert.CertificateException;
+
+/**
+ * Extensions to the <code>X509TrustManager</code> interface to support
+ * SSL/TLS connection sensitive trust management.
+ * <p>
+ * To prevent man-in-the-middle attacks, hostname checks can be done
+ * to verify that the hostname in an end-entity certificate matches the
+ * targeted hostname.  TLS does not require such checks, but some protocols
+ * over TLS (such as HTTPS) do.  In earlier versions of the JDK, the
+ * certificate chain checks were done at the SSL/TLS layer, and the hostname
+ * verification checks were done at the layer over TLS.  This class allows
+ * for the checking to be done during a single call to this class.
+ * <p>
+ * RFC 2830 defines the server identification specification for the "LDAPS"
+ * algorithm. RFC 2818 defines both the server identification and the
+ * client identification specification for the "HTTPS" algorithm.
+ *
+ * @see X509TrustManager
+ * @see HostnameVerifier
+ *
+ * @since 1.7
+ */
+public abstract class X509ExtendedTrustManager implements X509TrustManager {
+    /**
+     * Given the partial or complete certificate chain provided by the
+     * peer, build and validate the certificate path based on the
+     * authentication type and ssl parameters.
+     * <p>
+     * The authentication type is determined by the actual certificate
+     * used. For instance, if RSAPublicKey is used, the authType
+     * should be "RSA". Checking is case-sensitive.
+     * <p>
+     * If the <code>socket</code> parameter is an instance of
+     * {@link javax.net.SSLSocket}, and the endpoint identification
+     * algorithm of the <code>SSLParameters</code> is non-empty, to prevent
+     * man-in-the-middle attacks, the address that the <code>socket</code>
+     * connected to should be checked against the peer's identity presented
+     * in the end-entity X509 certificate, as specified in the endpoint
+     * identification algorithm.
+     * <p>
+     * If the <code>socket</code> parameter is an instance of
+     * {@link javax.net.SSLSocket}, and the algorithm constraints of the
+     * <code>SSLParameters</code> is non-null, for every certificate in the
+     * certification path, fields such as subject public key, the signature
+     * algorithm, key usage, extended key usage, etc. need to conform to the
+     * algorithm constraints in place on this socket.
+     *
+     * @param chain the peer certificate chain
+     * @param authType the key exchange algorithm used
+     * @param socket the socket used for this connection. This parameter
+     *        can be null, which indicates that implementations need not check
+     *        the ssl parameters
+     * @throws IllegalArgumentException if null or zero-length array is passed
+     *        in for the <code>chain</code> parameter or if null or zero-length
+     *        string is passed in for the <code>authType</code> parameter
+     * @throws CertificateException if the certificate chain is not trusted
+     *        by this TrustManager
+     *
+     * @see SSLParameters#getEndpointIdentificationProtocol
+     * @see SSLParameters#setEndpointIdentificationProtocol(String)
+     * @see SSLParameters#getAlgorithmConstraints
+     * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+     */
+    public abstract void checkClientTrusted(X509Certificate[] chain,
+            String authType, Socket socket) throws CertificateException;
+
+    /**
+     * Given the partial or complete certificate chain provided by the
+     * peer, build and validate the certificate path based on the
+     * authentication type and ssl parameters.
+     * <p>
+     * The authentication type is the key exchange algorithm portion
+     * of the cipher suites represented as a String, such as "RSA",
+     * "DHE_DSS". Note: for some exportable cipher suites, the key
+     * exchange algorithm is determined at run time during the
+     * handshake. For instance, for TLS_RSA_EXPORT_WITH_RC4_40_MD5,
+     * the authType should be RSA_EXPORT when an ephemeral RSA key is
+     * used for the key exchange, and RSA when the key from the server
+     * certificate is used. Checking is case-sensitive.
+     * <p>
+     * If the <code>socket</code> parameter is an instance of
+     * {@link javax.net.SSLSocket}, and the endpoint identification
+     * algorithm of the <code>SSLParameters</code> is non-empty, to prevent
+     * man-in-the-middle attacks, the address that the <code>socket</code>
+     * connected to should be checked against the peer's identity presented
+     * in the end-entity X509 certificate, as specified in the endpoint
+     * identification algorithm.
+     * <p>
+     * If the <code>socket</code> parameter is an instance of
+     * {@link javax.net.SSLSocket}, and the algorithm constraints of the
+     *  <code>SSLParameters</code> is non-null, for every certificate in the
+     * certification path, fields such as subject public key, the signature
+     * algorithm, key usage, extended key usage, etc. need to conform to the
+     * algorithm constraints in place on this socket.
+     *
+     * @param chain the peer certificate chain
+     * @param authType the key exchange algorithm used
+     * @param socket the socket used for this connection. This parameter
+     *        can be null, which indicates that implementations need not check
+     *        the ssl parameters
+     * @throws IllegalArgumentException if null or zero-length array is passed
+     *        in for the <code>chain</code> parameter or if null or zero-length
+     *        string is passed in for the <code>authType</code> parameter
+     * @throws CertificateException if the certificate chain is not trusted
+     *        by this TrustManager
+     *
+     * @see SSLParameters#getEndpointIdentificationProtocol
+     * @see SSLParameters#setEndpointIdentificationProtocol(String)
+     * @see SSLParameters#getAlgorithmConstraints
+     * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+     */
+    public abstract void checkServerTrusted(X509Certificate[] chain,
+        String authType, Socket socket) throws CertificateException;
+
+    /**
+     * Given the partial or complete certificate chain provided by the
+     * peer, build and validate the certificate path based on the
+     * authentication type and ssl parameters.
+     * <p>
+     * The authentication type is determined by the actual certificate
+     * used. For instance, if RSAPublicKey is used, the authType
+     * should be "RSA". Checking is case-sensitive.
+     * <p>
+     * If the <code>engine</code> parameter is available, and the endpoint
+     * identification algorithm of the <code>SSLParameters</code> is
+     * non-empty, to prevent man-in-the-middle attacks, the address that
+     * the <code>engine</code> connected to should be checked against
+     * the peer's identity presented in the end-entity X509 certificate,
+     * as specified in the endpoint identification algorithm.
+     * <p>
+     * If the <code>engine</code> parameter is available, and the algorithm
+     * constraints of the <code>SSLParameters</code> is non-null, for every
+     * certificate in the certification path, fields such as subject public
+     * key, the signature algorithm, key usage, extended key usage, etc.
+     * need to conform to the algorithm constraints in place on this engine.
+     *
+     * @param chain the peer certificate chain
+     * @param authType the key exchange algorithm used
+     * @param engine the engine used for this connection. This parameter
+     *        can be null, which indicates that implementations need not check
+     *        the ssl parameters
+     * @throws IllegalArgumentException if null or zero-length array is passed
+     *        in for the <code>chain</code> parameter or if null or zero-length
+     *        string is passed in for the <code>authType</code> parameter
+     * @throws CertificateException if the certificate chain is not trusted
+     *        by this TrustManager
+     *
+     * @see SSLParameters#getEndpointIdentificationProtocol
+     * @see SSLParameters#setEndpointIdentificationProtocol(String)
+     * @see SSLParameters#getAlgorithmConstraints
+     * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+     */
+    public abstract void checkClientTrusted(X509Certificate[] chain,
+        String authType, SSLEngine engine) throws CertificateException;
+
+    /**
+     * Given the partial or complete certificate chain provided by the
+     * peer, build and validate the certificate path based on the
+     * authentication type and ssl parameters.
+     * <p>
+     * The authentication type is the key exchange algorithm portion
+     * of the cipher suites represented as a String, such as "RSA",
+     * "DHE_DSS". Note: for some exportable cipher suites, the key
+     * exchange algorithm is determined at run time during the
+     * handshake. For instance, for TLS_RSA_EXPORT_WITH_RC4_40_MD5,
+     * the authType should be RSA_EXPORT when an ephemeral RSA key is
+     * used for the key exchange, and RSA when the key from the server
+     * certificate is used. Checking is case-sensitive.
+     * <p>
+     * If the <code>engine</code> parameter is available, and the endpoint
+     * identification algorithm of the <code>SSLParameters</code> is
+     * non-empty, to prevent man-in-the-middle attacks, the address that
+     * the <code>engine</code> connected to should be checked against
+     * the peer's identity presented in the end-entity X509 certificate,
+     * as specified in the endpoint identification algorithm.
+     * <p>
+     * If the <code>engine</code> parameter is available, and the algorithm
+     * constraints of the <code>SSLParameters</code> is non-null, for every
+     * certificate in the certification path, fields such as subject public
+     * key, the signature algorithm, key usage, extended key usage, etc.
+     * need to conform to the algorithm constraints in place on this engine.
+     *
+     * @param chain the peer certificate chain
+     * @param authType the key exchange algorithm used
+     * @param engine the engine used for this connection. This parameter
+     *        can be null, which indicates that implementations need not check
+     *        the ssl parameters
+     * @throws IllegalArgumentException if null or zero-length array is passed
+     *        in for the <code>chain</code> parameter or if null or zero-length
+     *        string is passed in for the <code>authType</code> parameter
+     * @throws CertificateException if the certificate chain is not trusted
+     *        by this TrustManager
+     *
+     * @see SSLParameters#getEndpointIdentificationProtocol
+     * @see SSLParameters#setEndpointIdentificationProtocol(String)
+     * @see SSLParameters#getAlgorithmConstraints
+     * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+     */
+    public abstract void checkServerTrusted(X509Certificate[] chain,
+        String authType, SSLEngine engine) throws CertificateException;
+
+}
--- a/src/share/classes/sun/net/www/protocol/https/HttpsClient.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/net/www/protocol/https/HttpsClient.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -109,6 +109,10 @@
     // HTTPS uses a different default port number than HTTP.
     private static final int    httpsPortNumber = 443;
 
+    // default HostnameVerifier class canonical name
+    private static final String defaultHVCanonicalName =
+            "javax.net.ssl.HttpsURLConnection.DefaultHostnameVerifier";
+
     /** Returns the default HTTPS port (443) */
     @Override
     protected int getDefaultPort() { return httpsPortNumber; }
@@ -427,13 +431,93 @@
             }
             s.addHandshakeCompletedListener(this);
 
-            // if the HostnameVerifier is not set, try to enable endpoint
-            // identification during handshaking
-            boolean enabledIdentification = false;
-            if (hv instanceof DefaultHostnameVerifier &&
-                (s instanceof SSLSocketImpl) &&
-                ((SSLSocketImpl)s).trySetHostnameVerification("HTTPS")) {
-                enabledIdentification = true;
+            // We have two hostname verification approaches. One is in
+            // SSL/TLS socket layer, where the algorithm is configured with
+            // SSLParameters.setEndpointIdentificationAlgorithm(), and the
+            // hostname verification is done by X509ExtendedTrustManager when
+            // the algorithm is "HTTPS". The other one is in HTTPS layer,
+            // where the algorithm is customized by
+            // HttpsURLConnection.setHostnameVerifier(), and the hostname
+            // verification is done by HostnameVerifier when the default
+            // rules for hostname verification fail.
+            //
+            // The relationship between two hostname verification approaches
+            // likes the following:
+            //
+            //               |             EIA algorithm
+            //               +----------------------------------------------
+            //               |     null      |   HTTPS    |   LDAP/other   |
+            // -------------------------------------------------------------
+            //     |         |1              |2           |3               |
+            // HNV | default | Set HTTPS EIA | use EIA    | HTTPS          |
+            //     |--------------------------------------------------------
+            //     | non -   |4              |5           |6               |
+            //     | default | HTTPS/HNV     | use EIA    | HTTPS/HNV      |
+            // -------------------------------------------------------------
+            //
+            // Abbreviation:
+            //     EIA: the endpoint identification algorithm in SSL/TLS
+            //           socket layer
+            //     HNV: the hostname verification object in HTTPS layer
+            // Notes:
+            //     case 1. default HNV and EIA is null
+            //           Set EIA as HTTPS, hostname check done in SSL/TLS
+            //           layer.
+            //     case 2. default HNV and EIA is HTTPS
+            //           Use existing EIA, hostname check done in SSL/TLS
+            //           layer.
+            //     case 3. default HNV and EIA is other than HTTPS
+            //           Use existing EIA, EIA check done in SSL/TLS
+            //           layer, then do HTTPS check in HTTPS layer.
+            //     case 4. non-default HNV and EIA is null
+            //           No EIA, no EIA check done in SSL/TLS layer, then do
+            //           HTTPS check in HTTPS layer using HNV as override.
+            //     case 5. non-default HNV and EIA is HTTPS
+            //           Use existing EIA, hostname check done in SSL/TLS
+            //           layer. No HNV override possible. We will review this
+            //           decision and may update the architecture for JDK 7.
+            //     case 6. non-default HNV and EIA is other than HTTPS
+            //           Use existing EIA, EIA check done in SSL/TLS layer,
+            //           then do HTTPS check in HTTPS layer as override.
+            boolean needToCheckSpoofing = true;
+            String identification =
+                s.getSSLParameters().getEndpointIdentificationAlgorithm();
+            if (identification != null && identification.length() != 0) {
+                if (identification.equalsIgnoreCase("HTTPS")) {
+                    // Do not check server identity again out of SSLSocket,
+                    // the endpoint will be identified during TLS handshaking
+                    // in SSLSocket.
+                    needToCheckSpoofing = false;
+                }   // else, we don't understand the identification algorithm,
+                    // need to check URL spoofing here.
+            } else {
+                boolean isDefaultHostnameVerifier = false;
+
+                // We prefer to let the SSLSocket do the spoof checks, but if
+                // the application has specified a HostnameVerifier (HNV),
+                // we will always use that.
+                if (hv != null) {
+                    String canonicalName = hv.getClass().getCanonicalName();
+                    if (canonicalName != null &&
+                    canonicalName.equalsIgnoreCase(defaultHVCanonicalName)) {
+                        isDefaultHostnameVerifier = true;
+                    }
+                } else {
+                    // Unlikely to happen! As the behavior is the same as the
+                    // default hostname verifier, so we prefer to let the
+                    // SSLSocket do the spoof checks.
+                    isDefaultHostnameVerifier = true;
+                }
+
+                if (isDefaultHostnameVerifier) {
+                    // If the HNV is the default from HttpsURLConnection, we
+                    // will do the spoof checks in SSLSocket.
+                    SSLParameters paramaters = s.getSSLParameters();
+                    paramaters.setEndpointIdentificationAlgorithm("HTTPS");
+                    s.setSSLParameters(paramaters);
+
+                    needToCheckSpoofing = false;
+                }
             }
 
             s.startHandshake();
@@ -449,7 +533,7 @@
             }
 
             // check URL spoofing if it has not been checked under handshaking
-            if (!enabledIdentification) {
+            if (needToCheckSpoofing) {
                 checkURLSpoofing(hv);
             }
         } else {
@@ -463,8 +547,7 @@
     // Server identity checking is done according to RFC 2818: HTTP over TLS
     // Section 3.1 Server Identity
     private void checkURLSpoofing(HostnameVerifier hostnameVerifier)
-            throws IOException
-    {
+            throws IOException {
         //
         // Get authenticated server name, if any
         //
--- a/src/share/classes/sun/security/internal/interfaces/TlsMasterSecret.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/internal/interfaces/TlsMasterSecret.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,8 @@
  *
  * @since   1.6
  * @author  Andreas Sterbenz
- * @deprecated Sun JDK internal use only --- WILL BE REMOVED in Dolphin (JDK 7)
+ * @deprecated Sun JDK internal use only --- WILL BE REMOVED in a future
+ * release.
  */
 @Deprecated
 public interface TlsMasterSecret extends SecretKey {
--- a/src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java	Mon Nov 01 22:02:35 2010 -0700
@@ -39,7 +39,8 @@
  *
  * @since   1.6
  * @author  Andreas Sterbenz
- * @deprecated Sun JDK internal use only --- WILL BE REMOVED in Dolphin (JDK 7)
+ * @deprecated Sun JDK internal use only --- WILL BE REMOVED in a future
+ * release.
  */
 @Deprecated
 public class TlsKeyMaterialParameterSpec implements AlgorithmParameterSpec {
@@ -50,6 +51,9 @@
     private final String cipherAlgorithm;
     private final int cipherKeyLength, ivLength, macKeyLength;
     private final int expandedCipherKeyLength; // == 0 for domestic ciphersuites
+    private final String prfHashAlg;
+    private final int prfHashLength;
+    private final int prfBlockSize;
 
     /**
      * Constructs a new TlsKeyMaterialParameterSpec.
@@ -71,6 +75,12 @@
      * @param ivLength the length in bytes of the initialization vector
      *    to be generated, or 0 if no initialization vector is required
      * @param macKeyLength the length in bytes of the MAC key to be generated
+     * @param prfHashAlg the name of the TLS PRF hash algorithm to use.
+     *        Used only for TLS 1.2+.  TLS1.1 and earlier use a fixed PRF.
+     * @param prfHashLength the output length of the TLS PRF hash algorithm.
+     *        Used only for TLS 1.2+.
+     * @param prfBlockSize the input block size of the TLS PRF hash algorithm.
+     *        Used only for TLS 1.2+.
      *
      * @throws NullPointerException if masterSecret, clientRandom,
      *   serverRandom, or cipherAlgorithm are null
@@ -82,7 +92,8 @@
     public TlsKeyMaterialParameterSpec(SecretKey masterSecret,
             int majorVersion, int minorVersion, byte[] clientRandom,
             byte[] serverRandom, String cipherAlgorithm, int cipherKeyLength,
-            int expandedCipherKeyLength, int ivLength, int macKeyLength) {
+            int expandedCipherKeyLength, int ivLength, int macKeyLength,
+            String prfHashAlg, int prfHashLength, int prfBlockSize) {
         if (masterSecret.getAlgorithm().equals("TlsMasterSecret") == false) {
             throw new IllegalArgumentException("Not a TLS master secret");
         }
@@ -101,6 +112,9 @@
         this.expandedCipherKeyLength = checkSign(expandedCipherKeyLength);
         this.ivLength = checkSign(ivLength);
         this.macKeyLength = checkSign(macKeyLength);
+        this.prfHashAlg = prfHashAlg;
+        this.prfHashLength = prfHashLength;
+        this.prfBlockSize = prfBlockSize;
     }
 
     private static int checkSign(int k) {
@@ -216,4 +230,30 @@
         return macKeyLength;
     }
 
+    /**
+     * Obtains the PRF hash algorithm to use in the PRF calculation.
+     *
+     * @return the hash algorithm.
+     */
+    public String getPRFHashAlg() {
+        return prfHashAlg;
+    }
+
+    /**
+     * Obtains the length of the PRF hash algorithm.
+     *
+     * @return the hash algorithm length.
+     */
+    public int getPRFHashLength() {
+        return prfHashLength;
+    }
+
+    /**
+     * Obtains the block size of the PRF hash algorithm.
+     *
+     * @return the hash algorithm block size
+     */
+    public int getPRFBlockSize() {
+        return prfBlockSize;
+    }
 }
--- a/src/share/classes/sun/security/internal/spec/TlsKeyMaterialSpec.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/internal/spec/TlsKeyMaterialSpec.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,7 +39,8 @@
  *
  * @since   1.6
  * @author  Andreas Sterbenz
- * @deprecated Sun JDK internal use only --- WILL BE REMOVED in Dolphin (JDK 7)
+ * @deprecated Sun JDK internal use only --- WILL BE REMOVED in a future
+ * release.
  */
 @Deprecated
 public class TlsKeyMaterialSpec implements KeySpec, SecretKey {
@@ -80,7 +81,8 @@
      */
     public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey,
             SecretKey clientCipherKey, SecretKey serverCipherKey) {
-        this(clientMacKey, serverMacKey, clientCipherKey, null, serverCipherKey, null);
+        this(clientMacKey, serverMacKey, clientCipherKey, null,
+            serverCipherKey, null);
     }
 
     /**
--- a/src/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java	Mon Nov 01 22:02:35 2010 -0700
@@ -39,7 +39,8 @@
  *
  * @since   1.6
  * @author  Andreas Sterbenz
- * @deprecated Sun JDK internal use only --- WILL BE REMOVED in Dolphin (JDK 7)
+ * @deprecated Sun JDK internal use only --- WILL BE REMOVED in a future
+ * release.
  */
 @Deprecated
 public class TlsMasterSecretParameterSpec implements AlgorithmParameterSpec {
@@ -47,6 +48,9 @@
     private final SecretKey premasterSecret;
     private final int majorVersion, minorVersion;
     private final byte[] clientRandom, serverRandom;
+    private final String prfHashAlg;
+    private final int prfHashLength;
+    private final int prfBlockSize;
 
     /**
      * Constructs a new TlsMasterSecretParameterSpec.
@@ -60,6 +64,12 @@
      * @param minorVersion the minor number of the protocol version
      * @param clientRandom the client's random value
      * @param serverRandom the server's random value
+     * @param prfHashAlg the name of the TLS PRF hash algorithm to use.
+     *        Used only for TLS 1.2+.  TLS1.1 and earlier use a fixed PRF.
+     * @param prfHashLength the output length of the TLS PRF hash algorithm.
+     *        Used only for TLS 1.2+.
+     * @param prfBlockSize the input block size of the TLS PRF hash algorithm.
+     *        Used only for TLS 1.2+.
      *
      * @throws NullPointerException if premasterSecret, clientRandom,
      *   or serverRandom are null
@@ -68,7 +78,8 @@
      */
     public TlsMasterSecretParameterSpec(SecretKey premasterSecret,
             int majorVersion, int minorVersion,
-            byte[] clientRandom, byte[] serverRandom) {
+            byte[] clientRandom, byte[] serverRandom,
+            String prfHashAlg, int prfHashLength, int prfBlockSize) {
         if (premasterSecret == null) {
             throw new NullPointerException("premasterSecret must not be null");
         }
@@ -77,6 +88,9 @@
         this.minorVersion = checkVersion(minorVersion);
         this.clientRandom = clientRandom.clone();
         this.serverRandom = serverRandom.clone();
+        this.prfHashAlg = prfHashAlg;
+        this.prfHashLength = prfHashLength;
+        this.prfBlockSize = prfBlockSize;
     }
 
     static int checkVersion(int version) {
@@ -132,4 +146,30 @@
         return serverRandom.clone();
     }
 
+    /**
+     * Obtains the PRF hash algorithm to use in the PRF calculation.
+     *
+     * @return the hash algorithm.
+     */
+    public String getPRFHashAlg() {
+        return prfHashAlg;
+    }
+
+    /**
+     * Obtains the length of the PRF hash algorithm.
+     *
+     * @return the hash algorithm length.
+     */
+    public int getPRFHashLength() {
+        return prfHashLength;
+    }
+
+    /**
+     * Obtains the block size of the PRF hash algorithm.
+     *
+     * @return the hash algorithm block size.
+     */
+    public int getPRFBlockSize() {
+        return prfBlockSize;
+    }
 }
--- a/src/share/classes/sun/security/internal/spec/TlsPrfParameterSpec.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/internal/spec/TlsPrfParameterSpec.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,8 @@
  *
  * @since   1.6
  * @author  Andreas Sterbenz
- * @deprecated Sun JDK internal use only --- WILL BE REMOVED in Dolphin (JDK 7)
+ * @deprecated Sun JDK internal use only --- WILL BE REMOVED in a future
+ * release.
  */
 @Deprecated
 public class TlsPrfParameterSpec implements AlgorithmParameterSpec {
@@ -47,6 +48,9 @@
     private final String label;
     private final byte[] seed;
     private final int outputLength;
+    private final String prfHashAlg;
+    private final int prfHashLength;
+    private final int prfBlockSize;
 
     /**
      * Constructs a new TlsPrfParameterSpec.
@@ -55,11 +59,19 @@
      * @param label the label to use in the calculation
      * @param seed the random seed to use in the calculation
      * @param outputLength the length in bytes of the output key to be produced
+     * @param prfHashAlg the name of the TLS PRF hash algorithm to use.
+     *        Used only for TLS 1.2+.  TLS1.1 and earlier use a fixed PRF.
+     * @param prfHashLength the output length of the TLS PRF hash algorithm.
+     *        Used only for TLS 1.2+.
+     * @param prfBlockSize the input block size of the TLS PRF hash algorithm.
+     *        Used only for TLS 1.2+.
      *
      * @throws NullPointerException if label or seed is null
      * @throws IllegalArgumentException if outputLength is negative
      */
-    public TlsPrfParameterSpec(SecretKey secret, String label, byte[] seed, int outputLength) {
+    public TlsPrfParameterSpec(SecretKey secret, String label,
+            byte[] seed, int outputLength,
+            String prfHashAlg, int prfHashLength, int prfBlockSize) {
         if ((label == null) || (seed == null)) {
             throw new NullPointerException("label and seed must not be null");
         }
@@ -70,6 +82,9 @@
         this.label = label;
         this.seed = seed.clone();
         this.outputLength = outputLength;
+        this.prfHashAlg = prfHashAlg;
+        this.prfHashLength = prfHashLength;
+        this.prfBlockSize = prfBlockSize;
     }
 
     /**
@@ -110,4 +125,33 @@
         return outputLength;
     }
 
+    /**
+     * Obtains the PRF hash algorithm to use in the PRF calculation.
+     *
+     * @return the hash algorithm, or null if no algorithm was specified.
+     */
+    public String getPRFHashAlg() {
+        return prfHashAlg;
+    }
+
+    /**
+     * Obtains the length of PRF hash algorithm.
+     *
+     * It would have been preferred to use MessageDigest.getDigestLength(),
+     * but the API does not require implementations to support the method.
+     *
+     * @return the hash algorithm length.
+     */
+    public int getPRFHashLength() {
+        return prfHashLength;
+    }
+
+    /**
+     * Obtains the length of PRF hash algorithm.
+     *
+     * @return the hash algorithm length.
+     */
+    public int getPRFBlockSize() {
+        return prfBlockSize;
+    }
 }
--- a/src/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,10 +36,12 @@
  *
  * @since   1.6
  * @author  Andreas Sterbenz
- * @deprecated Sun JDK internal use only --- WILL BE REMOVED in Dolphin (JDK 7)
+ * @deprecated Sun JDK internal use only --- WILL BE REMOVED in a future
+ * release.
  */
 @Deprecated
-public class TlsRsaPremasterSecretParameterSpec implements AlgorithmParameterSpec {
+public class TlsRsaPremasterSecretParameterSpec
+        implements AlgorithmParameterSpec {
 
     private final int majorVersion;
     private final int minorVersion;
@@ -58,10 +60,12 @@
      * @throws IllegalArgumentException if minorVersion or majorVersion are
      *   negative or larger than 255
      */
-    public TlsRsaPremasterSecretParameterSpec(int majorVersion, int minorVersion) {
-        this.majorVersion = TlsMasterSecretParameterSpec.checkVersion(majorVersion);
-        this.minorVersion = TlsMasterSecretParameterSpec.checkVersion(minorVersion);
-    }
+    public TlsRsaPremasterSecretParameterSpec(int majorVersion,
+            int minorVersion) {
+        this.majorVersion =
+            TlsMasterSecretParameterSpec.checkVersion(majorVersion);
+        this.minorVersion =
+            TlsMasterSecretParameterSpec.checkVersion(minorVersion); }
 
     /**
      * Returns the major version.
--- a/src/share/classes/sun/security/pkcs11/SunPKCS11.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/pkcs11/SunPKCS11.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -655,6 +655,25 @@
         d(SIG, "SHA512withRSA", P11Signature,
                 m(CKM_SHA512_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
 
+        /*
+         * TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the
+         * PRF calculations.  As of 2010, there is no PKCS11-level
+         * support for TLS 1.2 PRF calculations, and no known OS's have
+         * an internal variant we could use.  Therefore for TLS 1.2, we
+         * are updating JSSE to request different provider algorithms
+         * (e.g. "SunTls12Prf"), and currently only SunJCE has these
+         * TLS 1.2 algorithms.
+         *
+         * If we reused the names such as "SunTlsPrf", the PKCS11
+         * providers would need be updated to fail correctly when
+         * presented with the wrong version number (via
+         * Provider.Service.supportsParameters()), and we would also
+         * need to add the appropriate supportsParamters() checks into
+         * KeyGenerators (not currently there).
+         *
+         * In the future, if PKCS11 support is added, we will restructure
+         * this.
+         */
         d(KG, "SunTlsRsaPremasterSecret",
                     "sun.security.pkcs11.P11TlsRsaPremasterSecretGenerator",
                 m(CKM_SSL3_PRE_MASTER_KEY_GEN, CKM_TLS_PRE_MASTER_KEY_GEN));
@@ -887,7 +906,8 @@
             return (aliases == null) ? null : Arrays.asList(aliases);
         }
 
-        public Object newInstance(Object param) throws NoSuchAlgorithmException {
+        public Object newInstance(Object param)
+                throws NoSuchAlgorithmException {
             if (token.isValid() == false) {
                 throw new NoSuchAlgorithmException("Token has been removed");
             }
--- a/src/share/classes/sun/security/rsa/RSASignature.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/rsa/RSASignature.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -49,7 +49,7 @@
 public abstract class RSASignature extends SignatureSpi {
 
     // we sign an ASN.1 SEQUENCE of AlgorithmId and digest
-    // it has the form 30:xx:30:0c:[digestOID]:05:00:04:xx:[digest]
+    // it has the form 30:xx:30:xx:[digestOID]:05:00:04:xx:[digest]
     // this means the encoded length is (8 + digestOID.length + digest.length)
     private static final int baseLength = 8;
 
@@ -104,7 +104,8 @@
     // initialize for signing. See JCA doc
     protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
             throws InvalidKeyException {
-        RSAPrivateKey rsaKey = (RSAPrivateKey)RSAKeyFactory.toRSAKey(privateKey);
+        RSAPrivateKey rsaKey =
+            (RSAPrivateKey)RSAKeyFactory.toRSAKey(privateKey);
         this.privateKey = rsaKey;
         this.publicKey = null;
         initCommon(rsaKey, random);
@@ -212,7 +213,8 @@
         DerOutputStream out = new DerOutputStream();
         new AlgorithmId(oid).encode(out);
         out.putOctetString(digest);
-        DerValue result = new DerValue(DerValue.tag_Sequence, out.toByteArray());
+        DerValue result =
+            new DerValue(DerValue.tag_Sequence, out.toByteArray());
         return result.toByteArray();
     }
 
@@ -229,7 +231,8 @@
         }
         AlgorithmId algId = AlgorithmId.parse(values[0]);
         if (algId.getOID().equals(oid) == false) {
-            throw new IOException("ObjectIdentifier mismatch: " + algId.getOID());
+            throw new IOException("ObjectIdentifier mismatch: "
+                + algId.getOID());
         }
         if (algId.getEncodedParams() != null) {
             throw new IOException("Unexpected AlgorithmId parameters");
--- a/src/share/classes/sun/security/ssl/CipherSuite.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/CipherSuite.java	Mon Nov 01 22:02:35 2010 -0700
@@ -38,6 +38,7 @@
 
 import sun.security.ssl.CipherSuite.*;
 import static sun.security.ssl.CipherSuite.KeyExchange.*;
+import static sun.security.ssl.CipherSuite.PRF.*;
 import static sun.security.ssl.JsseJce.*;
 
 /**
@@ -102,12 +103,15 @@
     // by default
     final int priority;
 
-    // key exchange, bulk cipher, and mac algorithms. See those classes below.
+    // key exchange, bulk cipher, mac and prf algorithms. See those
+    // classes below.
     final KeyExchange keyExchange;
     final BulkCipher cipher;
     final MacAlg macAlg;
+    final PRF prfAlg;
 
     // whether a CipherSuite qualifies as exportable under 512/40 bit rules.
+    // TLS 1.1+ (RFC 4346) must not negotiate to these suites.
     final boolean exportable;
 
     // true iff implemented and enabled at compile time
@@ -116,9 +120,15 @@
     // obsoleted since protocol version
     final int obsoleted;
 
+    // supported since protocol version
+    final int supported;
+
+    /**
+     * Constructor for implemented CipherSuites.
+     */
     private CipherSuite(String name, int id, int priority,
             KeyExchange keyExchange, BulkCipher cipher,
-            boolean allowed, int obsoleted) {
+            boolean allowed, int obsoleted, int supported, PRF prfAlg) {
         this.name = name;
         this.id = id;
         this.priority = priority;
@@ -129,6 +139,10 @@
             macAlg = M_MD5;
         } else if (name.endsWith("_SHA")) {
             macAlg = M_SHA;
+        } else if (name.endsWith("_SHA256")) {
+            macAlg = M_SHA256;
+        } else if (name.endsWith("_SHA384")) {
+            macAlg = M_SHA384;
         } else if (name.endsWith("_NULL")) {
             macAlg = M_NULL;
         } else if (name.endsWith("_SCSV")) {
@@ -142,8 +156,13 @@
         allowed &= cipher.allowed;
         this.allowed = allowed;
         this.obsoleted = obsoleted;
+        this.supported = supported;
+        this.prfAlg = prfAlg;
     }
 
+    /**
+     * Constructor for unimplemented CipherSuites.
+     */
     private CipherSuite(String name, int id) {
         this.name = name;
         this.id = id;
@@ -155,6 +174,8 @@
         this.macAlg = null;
         this.exportable = false;
         this.obsoleted = ProtocolVersion.LIMIT_MAX_VALUE;
+        this.supported = ProtocolVersion.LIMIT_MIN_VALUE;
+        this.prfAlg = P_NONE;
     }
 
     /**
@@ -236,12 +257,17 @@
         return nameMap.values();
     }
 
+    /*
+     * Use this method when all of the values need to be specified.
+     * This is primarily used when defining a new ciphersuite for
+     * TLS 1.2+ that doesn't use the "default" PRF.
+     */
     private static void add(String name, int id, int priority,
             KeyExchange keyExchange, BulkCipher cipher,
-            boolean allowed, int obsoleted) {
+            boolean allowed, int obsoleted, int supported, PRF prf) {
 
         CipherSuite c = new CipherSuite(name, id, priority, keyExchange,
-                                        cipher, allowed, obsoleted);
+            cipher, allowed, obsoleted, supported, prf);
         if (idMap.put(id, c) != null) {
             throw new RuntimeException("Duplicate ciphersuite definition: "
                                         + id + ", " + name);
@@ -254,12 +280,41 @@
         }
     }
 
+    /*
+     * Use this method when there is no lower protocol limit where this
+     * suite can be used, and the PRF is P_SHA256.  That is, the
+     * existing ciphersuites.  From RFC 5246:
+     *
+     *     All cipher suites in this document use P_SHA256.
+     */
+    private static void add(String name, int id, int priority,
+            KeyExchange keyExchange, BulkCipher cipher,
+            boolean allowed, int obsoleted) {
+        // If this is an obsoleted suite, then don't let the TLS 1.2
+        // protocol have a valid PRF value.
+        PRF prf = P_SHA256;
+        if (obsoleted < ProtocolVersion.TLS12.v) {
+            prf = P_NONE;
+        }
+
+        add(name, id, priority, keyExchange, cipher, allowed, obsoleted,
+            ProtocolVersion.LIMIT_MIN_VALUE, prf);
+    }
+
+    /*
+     * Use this method when there is no upper protocol limit.  That is,
+     * suites which have not been obsoleted.
+     */
     private static void add(String name, int id, int priority,
             KeyExchange keyExchange, BulkCipher cipher, boolean allowed) {
         add(name, id, priority, keyExchange,
             cipher, allowed, ProtocolVersion.LIMIT_MAX_VALUE);
     }
 
+    /*
+     * Use this method to define an unimplemented suite.  This provides
+     * a number<->name mapping that can be used for debugging.
+     */
     private static void add(String name, int id) {
         CipherSuite c = new CipherSuite(name, id);
         if (idMap.put(id, c) != null) {
@@ -459,7 +514,7 @@
     /**
      * An SSL/TLS key MAC algorithm.
      *
-     * Also contains a factory method to obtain in initialized MAC
+     * Also contains a factory method to obtain an initialized MAC
      * for this algorithm.
      */
     final static class MacAlg {
@@ -519,6 +574,48 @@
     final static MacAlg M_NULL = new MacAlg("NULL", 0);
     final static MacAlg M_MD5  = new MacAlg("MD5", 16);
     final static MacAlg M_SHA  = new MacAlg("SHA", 20);
+    final static MacAlg M_SHA256  = new MacAlg("SHA256", 32);
+    final static MacAlg M_SHA384  = new MacAlg("SHA384", 48);
+
+    // PRFs (PseudoRandom Function) from TLS specifications.
+    //
+    // TLS 1.1- uses a single MD5/SHA1-based PRF algorithm for generating
+    // the necessary material.
+    //
+    // In TLS 1.2+, all existing/known CipherSuites use SHA256, however
+    // new Ciphersuites (e.g. RFC 5288) can define specific PRF hash
+    // algorithms.
+    static enum PRF {
+
+        // PRF algorithms
+        P_NONE(     "NONE",  0,   0),
+        P_SHA256("SHA-256", 32,  64),
+        P_SHA384("SHA-384", 48, 128),
+        P_SHA512("SHA-512", 64, 128);  // not currently used.
+
+        // PRF characteristics
+        private final String prfHashAlg;
+        private final int prfHashLength;
+        private final int prfBlockSize;
+
+        PRF(String prfHashAlg, int prfHashLength, int prfBlockSize) {
+            this.prfHashAlg = prfHashAlg;
+            this.prfHashLength = prfHashLength;
+            this.prfBlockSize = prfBlockSize;
+        }
+
+        String getPRFHashAlg() {
+            return prfHashAlg;
+        }
+
+        int getPRFHashLength() {
+            return prfHashLength;
+        }
+
+        int getPRFBlockSize() {
+            return prfBlockSize;
+        }
+    }
 
     static {
         idMap = new HashMap<Integer,CipherSuite>();
@@ -769,161 +866,199 @@
         // They are listed in preference order, most preferred first.
         int p = DEFAULT_SUITES_PRIORITY * 2;
 
+        // shorten names to fit the following table cleanly.
+        int max = ProtocolVersion.LIMIT_MAX_VALUE;
+        int tls11 = ProtocolVersion.TLS11.v;
+        int tls12 = ProtocolVersion.TLS12.v;
+
+        //  ID           Key Exchange   Cipher     A  obs  suprt  PRF
+        //  ======       ============   =========  =  ===  =====  ========
+        add("TLS_RSA_WITH_AES_128_CBC_SHA256",
+            0x003c, --p, K_RSA,         B_AES_128, T, max, tls12, P_SHA256);
+        add("TLS_RSA_WITH_AES_256_CBC_SHA256",
+            0x003d, --p, K_RSA,         B_AES_256, T, max, tls12, P_SHA256);
+        add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
+            0x0040, --p, K_DHE_DSS,     B_AES_128, T, max, tls12, P_SHA256);
+        add("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
+            0x0067, --p, K_DHE_RSA,     B_AES_128, T, max, tls12, P_SHA256);
+        add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
+            0x006a, --p, K_DHE_DSS,     B_AES_256, T, max, tls12, P_SHA256);
+        add("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
+            0x006b, --p, K_DHE_RSA,     B_AES_256, T, max, tls12, P_SHA256);
+
+        add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+            0xc023, --p, K_ECDHE_ECDSA, B_AES_128, T, max, tls12, P_SHA256);
+        add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
+            0xc024, --p, K_ECDHE_ECDSA, B_AES_256, T, max, tls12, P_SHA384);
+        add("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
+            0xc025, --p, K_ECDH_ECDSA,  B_AES_128, T, max, tls12, P_SHA256);
+        add("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
+            0xc026, --p, K_ECDH_ECDSA,  B_AES_256, T, max, tls12, P_SHA384);
+        add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+            0xc027, --p, K_ECDHE_RSA,   B_AES_128, T, max, tls12, P_SHA256);
+        add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
+            0xc028, --p, K_ECDHE_RSA,   B_AES_256, T, max, tls12, P_SHA384);
+        add("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
+            0xc029, --p, K_ECDH_RSA,    B_AES_128, T, max, tls12, P_SHA256);
+        add("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
+            0xc02a, --p, K_ECDH_RSA,    B_AES_256, T, max, tls12, P_SHA384);
+
         add("SSL_RSA_WITH_RC4_128_MD5",
-                              0x0004, --p, K_RSA,        B_RC4_128, N);
+            0x0004, --p, K_RSA,         B_RC4_128, N);
         add("SSL_RSA_WITH_RC4_128_SHA",
-                              0x0005, --p, K_RSA,        B_RC4_128, N);
+            0x0005, --p, K_RSA,         B_RC4_128, N);
         add("TLS_RSA_WITH_AES_128_CBC_SHA",
-                              0x002f, --p, K_RSA,        B_AES_128, T);
+            0x002f, --p, K_RSA,         B_AES_128, T);
         add("TLS_RSA_WITH_AES_256_CBC_SHA",
-                              0x0035, --p, K_RSA,        B_AES_256, T);
+            0x0035, --p, K_RSA,         B_AES_256, T);
 
         add("TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
-                              0xC002, --p, K_ECDH_ECDSA, B_RC4_128, N);
+            0xC002, --p, K_ECDH_ECDSA,  B_RC4_128, N);
         add("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
-                              0xC004, --p, K_ECDH_ECDSA, B_AES_128, T);
+            0xC004, --p, K_ECDH_ECDSA,  B_AES_128, T);
         add("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
-                              0xC005, --p, K_ECDH_ECDSA, B_AES_256, T);
+            0xC005, --p, K_ECDH_ECDSA,  B_AES_256, T);
         add("TLS_ECDH_RSA_WITH_RC4_128_SHA",
-                              0xC00C, --p, K_ECDH_RSA,   B_RC4_128, N);
+            0xC00C, --p, K_ECDH_RSA,    B_RC4_128, N);
         add("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
-                              0xC00E, --p, K_ECDH_RSA,   B_AES_128, T);
+            0xC00E, --p, K_ECDH_RSA,    B_AES_128, T);
         add("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
-                              0xC00F, --p, K_ECDH_RSA,   B_AES_256, T);
+            0xC00F, --p, K_ECDH_RSA,    B_AES_256, T);
 
         add("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
-                              0xC007, --p, K_ECDHE_ECDSA,B_RC4_128, N);
+            0xC007, --p, K_ECDHE_ECDSA, B_RC4_128, N);
         add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
-                              0xC009, --p, K_ECDHE_ECDSA,B_AES_128, T);
+            0xC009, --p, K_ECDHE_ECDSA, B_AES_128, T);
         add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
-                              0xC00A, --p, K_ECDHE_ECDSA,B_AES_256, T);
+            0xC00A, --p, K_ECDHE_ECDSA, B_AES_256, T);
         add("TLS_ECDHE_RSA_WITH_RC4_128_SHA",
-                              0xC011, --p, K_ECDHE_RSA,  B_RC4_128, N);
+            0xC011, --p, K_ECDHE_RSA,   B_RC4_128, N);
         add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
-                              0xC013, --p, K_ECDHE_RSA,  B_AES_128, T);
+            0xC013, --p, K_ECDHE_RSA,   B_AES_128, T);
         add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
-                              0xC014, --p, K_ECDHE_RSA,  B_AES_256, T);
+            0xC014, --p, K_ECDHE_RSA,   B_AES_256, T);
 
         add("TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
-                              0x0033, --p, K_DHE_RSA,    B_AES_128, T);
+            0x0033, --p, K_DHE_RSA,     B_AES_128, T);
         add("TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
-                              0x0039, --p, K_DHE_RSA,    B_AES_256, T);
+            0x0039, --p, K_DHE_RSA,     B_AES_256, T);
         add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
-                              0x0032, --p, K_DHE_DSS,    B_AES_128, T);
+            0x0032, --p, K_DHE_DSS,     B_AES_128, T);
         add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
-                              0x0038, --p, K_DHE_DSS,    B_AES_256, T);
+            0x0038, --p, K_DHE_DSS,     B_AES_256, T);
 
         add("SSL_RSA_WITH_3DES_EDE_CBC_SHA",
-                              0x000a, --p, K_RSA,        B_3DES,    T);
+            0x000a, --p, K_RSA,         B_3DES,    T);
         add("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
-                              0xC003, --p, K_ECDH_ECDSA, B_3DES,    T);
+            0xC003, --p, K_ECDH_ECDSA,  B_3DES,    T);
         add("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
-                              0xC00D, --p, K_ECDH_RSA,   B_3DES,    T);
+            0xC00D, --p, K_ECDH_RSA,    B_3DES,    T);
         add("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
-                              0xC008, --p, K_ECDHE_ECDSA,B_3DES,    T);
+            0xC008, --p, K_ECDHE_ECDSA, B_3DES,    T);
         add("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
-                              0xC012, --p, K_ECDHE_RSA,  B_3DES,    T);
+            0xC012, --p, K_ECDHE_RSA,   B_3DES,    T);
         add("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
-                              0x0016, --p, K_DHE_RSA,    B_3DES,    T);
+            0x0016, --p, K_DHE_RSA,     B_3DES,    T);
         add("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
-                              0x0013, --p, K_DHE_DSS,    B_3DES,    N);
-        add("SSL_RSA_WITH_DES_CBC_SHA",
-                              0x0009, --p, K_RSA,        B_DES,     N);
-        add("SSL_DHE_RSA_WITH_DES_CBC_SHA",
-                              0x0015, --p, K_DHE_RSA,    B_DES,     N);
-        add("SSL_DHE_DSS_WITH_DES_CBC_SHA",
-                              0x0012, --p, K_DHE_DSS,    B_DES,     N);
-        add("SSL_RSA_EXPORT_WITH_RC4_40_MD5",
-                              0x0003, --p, K_RSA_EXPORT, B_RC4_40,  N,
-                              ProtocolVersion.TLS11.v);
-        add("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
-                              0x0008, --p, K_RSA_EXPORT, B_DES_40,  N,
-                              ProtocolVersion.TLS11.v);
-        add("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
-                              0x0014, --p, K_DHE_RSA,    B_DES_40,  N,
-                              ProtocolVersion.TLS11.v);
-        add("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
-                              0x0011, --p, K_DHE_DSS,    B_DES_40,  N,
-                              ProtocolVersion.TLS11.v);
+            0x0013, --p, K_DHE_DSS,     B_3DES,    N);
 
         // Renegotiation protection request Signalling Cipher Suite Value (SCSV)
         add("TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
-                              0x00ff, --p, K_SCSV,       B_NULL,    T);
+            0x00ff, --p, K_SCSV,        B_NULL,    T);
 
         // Definition of the CipherSuites that are supported but not enabled
         // by default.
         // They are listed in preference order, preferred first.
         p = DEFAULT_SUITES_PRIORITY;
 
+        // weak single-DES cipher suites
+        add("SSL_RSA_WITH_DES_CBC_SHA",
+            0x0009, --p, K_RSA,         B_DES,     N, tls12);
+        add("SSL_DHE_RSA_WITH_DES_CBC_SHA",
+            0x0015, --p, K_DHE_RSA,     B_DES,     N, tls12);
+        add("SSL_DHE_DSS_WITH_DES_CBC_SHA",
+            0x0012, --p, K_DHE_DSS,     B_DES,     N, tls12);
+
         // Anonymous key exchange and the NULL ciphers
         add("SSL_RSA_WITH_NULL_MD5",
-                              0x0001, --p, K_RSA,        B_NULL,    N);
+            0x0001, --p, K_RSA,         B_NULL,    N);
         add("SSL_RSA_WITH_NULL_SHA",
-                              0x0002, --p, K_RSA,        B_NULL,    N);
+            0x0002, --p, K_RSA,         B_NULL,    N);
+        add("TLS_RSA_WITH_NULL_SHA256",
+            0x003b, --p, K_RSA,         B_NULL,    N, max, tls12, P_SHA256);
+
         add("TLS_ECDH_ECDSA_WITH_NULL_SHA",
-                              0xC001, --p, K_ECDH_ECDSA, B_NULL,    N);
+            0xC001, --p, K_ECDH_ECDSA,  B_NULL,    N);
         add("TLS_ECDH_RSA_WITH_NULL_SHA",
-                              0xC00B, --p, K_ECDH_RSA,   B_NULL,    N);
+            0xC00B, --p, K_ECDH_RSA,    B_NULL,    N);
         add("TLS_ECDHE_ECDSA_WITH_NULL_SHA",
-                              0xC006, --p, K_ECDHE_ECDSA,B_NULL,    N);
+            0xC006, --p, K_ECDHE_ECDSA, B_NULL,    N);
         add("TLS_ECDHE_RSA_WITH_NULL_SHA",
-                              0xC010, --p, K_ECDHE_RSA,  B_NULL,    N);
+            0xC010, --p, K_ECDHE_RSA,   B_NULL,    N);
 
         add("SSL_DH_anon_WITH_RC4_128_MD5",
-                              0x0018, --p, K_DH_ANON,    B_RC4_128, N);
+            0x0018, --p, K_DH_ANON,     B_RC4_128, N);
         add("TLS_DH_anon_WITH_AES_128_CBC_SHA",
-                              0x0034, --p, K_DH_ANON,    B_AES_128, N);
+            0x0034, --p, K_DH_ANON,     B_AES_128, N);
         add("TLS_DH_anon_WITH_AES_256_CBC_SHA",
-                              0x003a, --p, K_DH_ANON,    B_AES_256, N);
+            0x003a, --p, K_DH_ANON,     B_AES_256, N);
         add("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
-                              0x001b, --p, K_DH_ANON,    B_3DES,    N);
+            0x001b, --p, K_DH_ANON,     B_3DES,    N);
         add("SSL_DH_anon_WITH_DES_CBC_SHA",
-                              0x001a, --p, K_DH_ANON,    B_DES,     N);
+            0x001a, --p, K_DH_ANON,     B_DES,     N, tls12);
+
+        add("TLS_DH_anon_WITH_AES_128_CBC_SHA256",
+            0x006c, --p, K_DH_ANON,     B_AES_128, N, max, tls12, P_SHA256);
+        add("TLS_DH_anon_WITH_AES_256_CBC_SHA256",
+            0x006d, --p, K_DH_ANON,     B_AES_256, N, max, tls12, P_SHA256);
 
         add("TLS_ECDH_anon_WITH_RC4_128_SHA",
-                              0xC016, --p, K_ECDH_ANON,  B_RC4_128, N);
+            0xC016, --p, K_ECDH_ANON,   B_RC4_128, N);
         add("TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
-                              0xC018, --p, K_ECDH_ANON,  B_AES_128, T);
+            0xC018, --p, K_ECDH_ANON,   B_AES_128, T);
         add("TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
-                              0xC019, --p, K_ECDH_ANON,  B_AES_256, T);
+            0xC019, --p, K_ECDH_ANON,   B_AES_256, T);
         add("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
-                              0xC017, --p, K_ECDH_ANON,  B_3DES,    T);
+            0xC017, --p, K_ECDH_ANON,   B_3DES,    T);
 
         add("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
-                              0x0017, --p, K_DH_ANON,    B_RC4_40,  N,
-                              ProtocolVersion.TLS11.v);
+            0x0017, --p, K_DH_ANON,     B_RC4_40,  N, tls11);
         add("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
-                              0x0019, --p, K_DH_ANON,    B_DES_40,  N,
-                              ProtocolVersion.TLS11.v);
+            0x0019, --p, K_DH_ANON,     B_DES_40,  N, tls11);
 
         add("TLS_ECDH_anon_WITH_NULL_SHA",
-                              0xC015, --p, K_ECDH_ANON,  B_NULL,    N);
+            0xC015, --p, K_ECDH_ANON,   B_NULL,    N);
+
+        add("SSL_RSA_EXPORT_WITH_RC4_40_MD5",
+            0x0003, --p, K_RSA_EXPORT,  B_RC4_40,  N, tls11);
+        add("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
+            0x0008, --p, K_RSA_EXPORT,  B_DES_40,  N, tls11);
+        add("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
+            0x0014, --p, K_DHE_RSA,     B_DES_40,  N, tls11);
+        add("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
+            0x0011, --p, K_DHE_DSS,     B_DES_40,  N, tls11);
 
         // Supported Kerberos ciphersuites from RFC2712
         add("TLS_KRB5_WITH_RC4_128_SHA",
-                              0x0020, --p, K_KRB5,        B_RC4_128, N);
+            0x0020, --p, K_KRB5,        B_RC4_128, N);
         add("TLS_KRB5_WITH_RC4_128_MD5",
-                              0x0024, --p, K_KRB5,        B_RC4_128, N);
+            0x0024, --p, K_KRB5,        B_RC4_128, N);
         add("TLS_KRB5_WITH_3DES_EDE_CBC_SHA",
-                              0x001f, --p, K_KRB5,        B_3DES,    N);
+            0x001f, --p, K_KRB5,        B_3DES,    N);
         add("TLS_KRB5_WITH_3DES_EDE_CBC_MD5",
-                              0x0023, --p, K_KRB5,        B_3DES,    N);
+            0x0023, --p, K_KRB5,        B_3DES,    N);
         add("TLS_KRB5_WITH_DES_CBC_SHA",
-                              0x001e, --p, K_KRB5,        B_DES,     N);
+            0x001e, --p, K_KRB5,        B_DES,     N, tls12);
         add("TLS_KRB5_WITH_DES_CBC_MD5",
-                              0x0022, --p, K_KRB5,        B_DES,     N);
+            0x0022, --p, K_KRB5,        B_DES,     N, tls12);
         add("TLS_KRB5_EXPORT_WITH_RC4_40_SHA",
-                              0x0028, --p, K_KRB5_EXPORT, B_RC4_40,  N,
-                              ProtocolVersion.TLS11.v);
+            0x0028, --p, K_KRB5_EXPORT, B_RC4_40,  N, tls11);
         add("TLS_KRB5_EXPORT_WITH_RC4_40_MD5",
-                              0x002b, --p, K_KRB5_EXPORT, B_RC4_40,  N,
-                              ProtocolVersion.TLS11.v);
+            0x002b, --p, K_KRB5_EXPORT, B_RC4_40,  N, tls11);
         add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA",
-                              0x0026, --p, K_KRB5_EXPORT, B_DES_40,  N,
-                              ProtocolVersion.TLS11.v);
+            0x0026, --p, K_KRB5_EXPORT, B_DES_40,  N, tls11);
         add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5",
-                              0x0029, --p, K_KRB5_EXPORT, B_DES_40,  N,
-                              ProtocolVersion.TLS11.v);
+            0x0029, --p, K_KRB5_EXPORT, B_DES_40,  N, tls11);
 
         /*
          * Other values from the TLS Cipher Suite Registry, as of August 2010.
@@ -1006,19 +1141,10 @@
         add("TLS_DH_RSA_WITH_AES_128_CBC_SHA",             0x0031);
         add("TLS_DH_DSS_WITH_AES_256_CBC_SHA",             0x0036);
         add("TLS_DH_RSA_WITH_AES_256_CBC_SHA",             0x0037);
-        add("TLS_RSA_WITH_NULL_SHA256",                    0x003b);
-        add("TLS_RSA_WITH_AES_128_CBC_SHA256",             0x003c);
-        add("TLS_RSA_WITH_AES_256_CBC_SHA256",             0x003d);
         add("TLS_DH_DSS_WITH_AES_128_CBC_SHA256",          0x003e);
         add("TLS_DH_RSA_WITH_AES_128_CBC_SHA256",          0x003f);
-        add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",         0x0040);
-        add("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",         0x0067);
         add("TLS_DH_DSS_WITH_AES_256_CBC_SHA256",          0x0068);
         add("TLS_DH_RSA_WITH_AES_256_CBC_SHA256",          0x0069);
-        add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",         0x006a);
-        add("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",         0x006b);
-        add("TLS_DH_anon_WITH_AES_128_CBC_SHA256",         0x006c);
-        add("TLS_DH_anon_WITH_AES_256_CBC_SHA256",         0x006d);
 
         // Unsupported cipher suites from RFC 5288
         add("TLS_RSA_WITH_AES_128_GCM_SHA256",             0x009c);
@@ -1092,14 +1218,6 @@
         add("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA",        0xc022);
 
         // Unsupported cipher suites from RFC 5289
-        add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",     0xc023);
-        add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",     0xc024);
-        add("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",      0xc025);
-        add("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",      0xc026);
-        add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",       0xc027);
-        add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",       0xc028);
-        add("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",        0xc029);
-        add("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",        0xc02a);
         add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",     0xc02b);
         add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",     0xc02c);
         add("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",      0xc02d);
--- a/src/share/classes/sun/security/ssl/ClientHandshaker.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/ClientHandshaker.java	Mon Nov 01 22:02:35 2010 -0700
@@ -23,7 +23,6 @@
  * questions.
  */
 
-
 package sun.security.ssl;
 
 import java.io.*;
@@ -45,12 +44,12 @@
 
 import javax.security.auth.Subject;
 
-import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager;
-
 import sun.security.ssl.HandshakeMessage.*;
 import sun.security.ssl.CipherSuite.*;
 import static sun.security.ssl.CipherSuite.KeyExchange.*;
 
+import sun.net.util.IPAddressUtil;
+
 /**
  * ClientHandshaker does the protocol handshaking from the point
  * of view of a client.  It is driven asychronously by handshake messages
@@ -89,6 +88,10 @@
      */
     private ProtocolVersion maxProtocolVersion;
 
+    // To switch off the SNI extension.
+    private final static boolean enableSNIExtension =
+            Debug.getBooleanProperty("jsse.enableSNIExtension", true);
+
     /*
      * Constructors
      */
@@ -190,7 +193,8 @@
                 }
                 break;
             case K_DH_ANON:
-                this.serverKeyExchange(new DH_ServerKeyExchange(input));
+                this.serverKeyExchange(new DH_ServerKeyExchange(
+                                                input, protocolVersion));
                 break;
             case K_DHE_DSS:
             case K_DHE_RSA:
@@ -198,7 +202,8 @@
                     this.serverKeyExchange(new DH_ServerKeyExchange(
                         input, serverKey,
                         clnt_random.random_bytes, svr_random.random_bytes,
-                        messageLen));
+                        messageLen,
+                        localSupportedSignAlgs, protocolVersion));
                 } catch (GeneralSecurityException e) {
                     throwSSLException("Server key", e);
                 }
@@ -209,7 +214,8 @@
                 try {
                     this.serverKeyExchange(new ECDH_ServerKeyExchange
                         (input, serverKey, clnt_random.random_bytes,
-                        svr_random.random_bytes));
+                        svr_random.random_bytes,
+                        localSupportedSignAlgs, protocolVersion));
                 } catch (GeneralSecurityException e) {
                     throwSSLException("Server key", e);
                 }
@@ -219,8 +225,9 @@
             case K_DH_DSS:
             case K_ECDH_ECDSA:
             case K_ECDH_RSA:
-                throw new SSLProtocolException("Protocol violation: server sent"
-                    + " a server key exchange message for key exchange " + keyExchange);
+                throw new SSLProtocolException(
+                    "Protocol violation: server sent a server key exchange"
+                    + "message for key exchange " + keyExchange);
             case K_KRB5:
             case K_KRB5_EXPORT:
                 throw new SSLProtocolException(
@@ -243,10 +250,32 @@
                     "Client certificate requested for "+
                     "kerberos cipher suite.");
             }
-            certRequest = new CertificateRequest(input);
+            certRequest = new CertificateRequest(input, protocolVersion);
             if (debug != null && Debug.isOn("handshake")) {
                 certRequest.print(System.out);
             }
+
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                Collection<SignatureAndHashAlgorithm> peerSignAlgs =
+                                        certRequest.getSignAlgorithms();
+                if (peerSignAlgs == null || peerSignAlgs.isEmpty()) {
+                    throw new SSLHandshakeException(
+                        "No peer supported signature algorithms");
+                }
+
+                Collection<SignatureAndHashAlgorithm> supportedPeerSignAlgs =
+                    SignatureAndHashAlgorithm.getSupportedAlgorithms(
+                                                            peerSignAlgs);
+                if (supportedPeerSignAlgs.isEmpty()) {
+                    throw new SSLHandshakeException(
+                        "No supported signature and hash algorithm in common");
+                }
+
+                setPeerSupportedSignAlgs(supportedPeerSignAlgs);
+                session.setPeerSupportedSignatureAlgorithms(
+                                                supportedPeerSignAlgs);
+            }
+
             break;
 
         case HandshakeMessage.ht_server_hello_done:
@@ -254,7 +283,8 @@
             break;
 
         case HandshakeMessage.ht_finished:
-            this.serverFinished(new Finished(protocolVersion, input));
+            this.serverFinished(
+                new Finished(protocolVersion, input, cipherSuite));
             break;
 
         default:
@@ -351,6 +381,9 @@
                     mesgVersion);
         }
 
+        handshakeHash.protocolDetermined(
+            mesgVersion.v >= ProtocolVersion.TLS12.v);
+
         // Set protocolVersion and propagate to SSLSocket and the
         // Handshake streams
         setVersion(mesgVersion);
@@ -426,10 +459,13 @@
 
         if (isNegotiable(mesg.cipherSuite) == false) {
             fatalSE(Alerts.alert_illegal_parameter,
-                "Server selected improper ciphersuite " + cipherSuite);
+                "Server selected improper ciphersuite " + mesg.cipherSuite);
         }
 
         setCipherSuite(mesg.cipherSuite);
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            handshakeHash.setFinishedAlg(cipherSuite.prfAlg.getPRFHashAlg());
+        }
 
         if (mesg.compression_method != 0) {
             fatalSE(Alerts.alert_illegal_parameter,
@@ -508,7 +544,6 @@
                 if (debug != null && Debug.isOn("session")) {
                     System.out.println("%% Server resumed " + session);
                 }
-                return;
             } else {
                 // we wanted to resume, but the server refused
                 session = null;
@@ -519,11 +554,21 @@
             }
         }
 
+        if (resumingSession && session != null) {
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                handshakeHash.setCertificateVerifyAlg(null);
+            }
+
+            setHandshakeSessionSE(session);
+            return;
+        }
+
         // check extensions
         for (HelloExtension ext : mesg.extensions.list()) {
             ExtensionType type = ext.type;
             if ((type != ExtensionType.EXT_ELLIPTIC_CURVES)
                     && (type != ExtensionType.EXT_EC_POINT_FORMATS)
+                    && (type != ExtensionType.EXT_SERVER_NAME)
                     && (type != ExtensionType.EXT_RENEGOTIATION_INFO)) {
                 fatalSE(Alerts.alert_unsupported_extension,
                     "Server sent an unsupported extension: " + type);
@@ -532,7 +577,9 @@
 
         // Create a new session, we need to do the full handshake
         session = new SSLSessionImpl(protocolVersion, cipherSuite,
+                            getLocalSupportedSignAlgs(),
                             mesg.sessionId, getHostSE(), getPortSE());
+        setHandshakeSessionSE(session);
         if (debug != null && Debug.isOn("handshake")) {
             System.out.println("** " + cipherSuite);
         }
@@ -568,11 +615,13 @@
         if (debug != null && Debug.isOn("handshake")) {
             mesg.print(System.out);
         }
-        dh = new DHCrypt(mesg.getModulus(), mesg.getBase(), sslContext.getSecureRandom());
+        dh = new DHCrypt(mesg.getModulus(), mesg.getBase(),
+                                            sslContext.getSecureRandom());
         serverDH = mesg.getServerPublicKey();
     }
 
-    private void serverKeyExchange(ECDH_ServerKeyExchange mesg) throws IOException {
+    private void serverKeyExchange(ECDH_ServerKeyExchange mesg)
+            throws IOException {
         if (debug != null && Debug.isOn("handshake")) {
             mesg.print(System.out);
         }
@@ -666,9 +715,13 @@
                     PublicKey publicKey = certs[0].getPublicKey();
                     // for EC, make sure we use a supported named curve
                     if (publicKey instanceof ECPublicKey) {
-                        ECParameterSpec params = ((ECPublicKey)publicKey).getParams();
-                        int index = SupportedEllipticCurvesExtension.getCurveIndex(params);
-                        if (!SupportedEllipticCurvesExtension.isSupported(index)) {
+                        ECParameterSpec params =
+                            ((ECPublicKey)publicKey).getParams();
+                        int index =
+                            SupportedEllipticCurvesExtension.getCurveIndex(
+                                params);
+                        if (!SupportedEllipticCurvesExtension.isSupported(
+                                index)) {
                             publicKey = null;
                         }
                     }
@@ -814,8 +867,9 @@
                 throw new IOException("Hostname is required" +
                                 " to use Kerberos cipher suites");
             }
-            KerberosClientKeyExchange kerberosMsg = new KerberosClientKeyExchange
-                (hostname, isLoopbackSE(), getAccSE(), protocolVersion,
+            KerberosClientKeyExchange kerberosMsg =
+                new KerberosClientKeyExchange(
+                    hostname, isLoopbackSE(), getAccSE(), protocolVersion,
                 sslContext.getSecureRandom());
             // Record the principals involved in exchange
             session.setPeerPrincipal(kerberosMsg.getPeerPrincipal());
@@ -862,7 +916,8 @@
         case K_KRB5_EXPORT:
             byte[] secretBytes =
                 ((KerberosClientKeyExchange)m2).getUnencryptedPreMasterSecret();
-            preMasterSecret = new SecretKeySpec(secretBytes, "TlsPremasterSecret");
+            preMasterSecret = new SecretKeySpec(secretBytes,
+                "TlsPremasterSecret");
             break;
         case K_DHE_RSA:
         case K_DHE_DSS:
@@ -879,7 +934,8 @@
             preMasterSecret = ecdh.getAgreedSecret(serverKey);
             break;
         default:
-            throw new IOException("Internal error: unknown key exchange " + keyExchange);
+            throw new IOException("Internal error: unknown key exchange "
+                + keyExchange);
         }
 
         calculateKeys(preMasterSecret, null);
@@ -897,9 +953,32 @@
         if (signingKey != null) {
             CertificateVerify m3;
             try {
+                SignatureAndHashAlgorithm preferableSignatureAlgorithm = null;
+                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                    preferableSignatureAlgorithm =
+                        SignatureAndHashAlgorithm.getPreferableAlgorithm(
+                            peerSupportedSignAlgs, signingKey.getAlgorithm());
+
+                    if (preferableSignatureAlgorithm == null) {
+                        throw new SSLHandshakeException(
+                            "No supported signature algorithm");
+                    }
+
+                    String hashAlg =
+                        SignatureAndHashAlgorithm.getHashAlgorithmName(
+                                preferableSignatureAlgorithm);
+                    if (hashAlg == null || hashAlg.length() == 0) {
+                        throw new SSLHandshakeException(
+                                "No supported hash algorithm");
+                    }
+
+                    handshakeHash.setCertificateVerifyAlg(hashAlg);
+                }
+
                 m3 = new CertificateVerify(protocolVersion, handshakeHash,
                     signingKey, session.getMasterSecret(),
-                    sslContext.getSecureRandom());
+                    sslContext.getSecureRandom(),
+                    preferableSignatureAlgorithm);
             } catch (GeneralSecurityException e) {
                 fatalSE(Alerts.alert_handshake_failure,
                     "Error signing certificate verify", e);
@@ -911,6 +990,10 @@
             }
             m3.write(output);
             output.doHashes();
+        } else {
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                handshakeHash.setCertificateVerifyAlg(null);
+            }
         }
 
         /*
@@ -931,8 +1014,8 @@
             mesg.print(System.out);
         }
 
-        boolean verified = mesg.verify(protocolVersion, handshakeHash,
-                                Finished.SERVER, session.getMasterSecret());
+        boolean verified = mesg.verify(handshakeHash, Finished.SERVER,
+            session.getMasterSecret());
 
         if (!verified) {
             fatalSE(Alerts.alert_illegal_parameter,
@@ -989,7 +1072,7 @@
     private void sendChangeCipherAndFinish(boolean finishedTag)
             throws IOException {
         Finished mesg = new Finished(protocolVersion, handshakeHash,
-                                Finished.CLIENT, session.getMasterSecret());
+            Finished.CLIENT, session.getMasterSecret(), cipherSuite);
 
         /*
          * Send the change_cipher_spec message, then the Finished message
@@ -1134,11 +1217,49 @@
             throw new SSLHandshakeException("No negotiable cipher suite");
         }
 
+        // Not a TLS1.2+ handshake
+        // For SSLv2Hello, HandshakeHash.reset() will be called, so we
+        // cannot call HandshakeHash.protocolDetermined() here. As it does
+        // not follow the spec that HandshakeHash.reset() can be only be
+        // called before protocolDetermined.
+        // if (maxProtocolVersion.v < ProtocolVersion.TLS12.v) {
+        //     handshakeHash.protocolDetermined(false);
+        // }
+
         // create the ClientHello message
         ClientHello clientHelloMessage = new ClientHello(
                 sslContext.getSecureRandom(), maxProtocolVersion,
                 sessionId, cipherSuites);
 
+        // add signature_algorithm extension
+        if (maxProtocolVersion.v >= ProtocolVersion.TLS12.v) {
+            // we will always send the signature_algorithm extension
+            Collection<SignatureAndHashAlgorithm> localSignAlgs =
+                                                getLocalSupportedSignAlgs();
+            if (localSignAlgs.isEmpty()) {
+                throw new SSLHandshakeException(
+                            "No supported signature algorithm");
+            }
+
+            clientHelloMessage.addSignatureAlgorithmsExtension(localSignAlgs);
+        }
+
+        // add server_name extension
+        if (enableSNIExtension) {
+            // We cannot use the hostname resolved from name services.  For
+            // virtual hosting, multiple hostnames may be bound to the same IP
+            // address, so the hostname resolved from name services is not
+            // reliable.
+            String hostname = getRawHostnameSE();
+
+            // we only allow FQDN
+            if (hostname != null && hostname.indexOf('.') > 0 &&
+                    !IPAddressUtil.isIPv4LiteralAddress(hostname) &&
+                    !IPAddressUtil.isIPv6LiteralAddress(hostname)) {
+                clientHelloMessage.addServerNameIndicationExtension(hostname);
+            }
+        }
+
         // reset the client random cookie
         clnt_random = clientHelloMessage.clnt_random;
 
@@ -1194,26 +1315,23 @@
                 keyExchangeString = keyExchange.name;
             }
 
-            String identificator = getHostnameVerificationSE();
             if (tm instanceof X509ExtendedTrustManager) {
-                ((X509ExtendedTrustManager)tm).checkServerTrusted(
-                        (peerCerts != null ?
-                            peerCerts.clone() :
-                            null),
+                if (conn != null) {
+                    ((X509ExtendedTrustManager)tm).checkServerTrusted(
+                        peerCerts.clone(),
                         keyExchangeString,
-                        getHostSE(),
-                        identificator);
+                        conn);
+                } else {
+                    ((X509ExtendedTrustManager)tm).checkServerTrusted(
+                        peerCerts.clone(),
+                        keyExchangeString,
+                        engine);
+                }
             } else {
-                if (identificator != null) {
-                    throw new RuntimeException(
-                        "trust manager does not support peer identification");
-                }
-
-                tm.checkServerTrusted(
-                    (peerCerts != null ?
-                        peerCerts.clone() :
-                        peerCerts),
-                    keyExchangeString);
+                // Unlikely to happen, because we have wrapped the old
+                // X509TrustManager with the new X509ExtendedTrustManager.
+                throw new CertificateException(
+                    "Improper X509TrustManager implementation");
             }
         } catch (CertificateException e) {
             // This will throw an exception, so include the original error.
--- a/src/share/classes/sun/security/ssl/HandshakeHash.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/HandshakeHash.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,13 @@
 
 package sun.security.ssl;
 
+import java.io.ByteArrayOutputStream;
 import java.security.*;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
 
 /**
  * Abstraction for the SSL/TLS hash of all handshake messages that is
@@ -36,51 +42,161 @@
  *
  * This class transparently deals with cloneable and non-cloneable digests.
  *
+ * This class now supports TLS 1.2 also. The key difference for TLS 1.2
+ * is that you cannot determine the hash algorithms for CertificateVerify
+ * at a early stage. On the other hand, it's simpler than TLS 1.1 (and earlier)
+ * that there is no messy MD5+SHA1 digests.
+ *
+ * You need to obey these conventions when using this class:
+ *
+ * 1. protocolDetermined(boolean isTLS12) should be called when the negotiated
+ * protocol version is determined.
+ *
+ * 2. Before protocolDetermined() is called, only update(), reset(),
+ * restrictCertificateVerifyAlgs(), setFinishedAlg(), and
+ * setCertificateVerifyAlg() can be called.
+ *
+ * 3. After protocolDetermined(*) is called. reset() cannot be called.
+ *
+ * 4. After protocolDetermined(false) is called, getFinishedHash() and
+ * getCertificateVerifyHash() cannot be called. After protocolDetermined(true)
+ * is called, getMD5Clone() and getSHAClone() cannot be called.
+ *
+ * 5. getMD5Clone() and getSHAClone() can only be called after
+ * protocolDetermined(false) is called.
+ *
+ * 6. getFinishedHash() and getCertificateVerifyHash() can only be called after
+ * all protocolDetermined(true), setCertificateVerifyAlg() and setFinishedAlg()
+ * have been called. If a CertificateVerify message is to be used, call
+ * setCertificateVerifyAlg() with the hash algorithm as the argument.
+ * Otherwise, you still must call setCertificateVerifyAlg(null) before
+ * calculating any hash value.
+ *
+ * Suggestions: Call protocolDetermined(), restrictCertificateVerifyAlgs(),
+ * setFinishedAlg(), and setCertificateVerifyAlg() as early as possible.
+ *
+ * Example:
+ * <pre>
+ * HandshakeHash hh = new HandshakeHash(...)
+ * hh.update(clientHelloBytes);
+ * hh.setFinishedAlg("SHA-256");
+ * hh.update(serverHelloBytes);
+ * ...
+ * hh.setCertificateVerifyAlg("SHA-384");
+ * hh.update(CertificateVerifyBytes);
+ * byte[] cvDigest = hh.getCertificateVerifyHash();
+ * ...
+ * hh.update(finished1);
+ * byte[] finDigest1 = hh.getFinishedHash();
+ * hh.update(finished2);
+ * byte[] finDigest2 = hh.getFinishedHash();
+ * </pre>
+ * If no CertificateVerify message is to be used, call
+ * <pre>
+ * hh.setCertificateVerifyAlg(null);
+ * </pre>
+ * This call can be made once you are certain that this message
+ * will never be used.
  */
 final class HandshakeHash {
 
-    private final MessageDigest md5, sha;
+    // Common
+
+    // -1:  unknown
+    //  1:  <=TLS 1.1
+    //  2:  TLS 1.2
+    private int version = -1;
+    private ByteArrayOutputStream data = new ByteArrayOutputStream();
+    private final boolean isServer;
+
+    // For TLS 1.1
+    private MessageDigest md5, sha;
+    private final int clonesNeeded;    // needs to be saved for later use
+
+    // For TLS 1.2
+    // cvAlgDetermined == true means setCertificateVerifyAlg() is called
+    private boolean cvAlgDetermined = false;
+    private String cvAlg;
+    private MessageDigest finMD;
 
     /**
      * Create a new HandshakeHash. needCertificateVerify indicates whether
-     * a hash for the certificate verify message is required.
+     * a hash for the certificate verify message is required. The argument
+     * algs is a set of all possible hash algorithms that might be used in
+     * TLS 1.2. If the caller is sure that TLS 1.2 won't be used or no
+     * CertificateVerify message will be used, leave it null or empty.
      */
-    HandshakeHash(boolean needCertificateVerify) {
-        int n = needCertificateVerify ? 3 : 2;
-        try {
-            md5 = CloneableDigest.getDigest("MD5", n);
-            sha = CloneableDigest.getDigest("SHA", n);
-        } catch (NoSuchAlgorithmException e) {
-            throw new RuntimeException
-                        ("Algorithm MD5 or SHA not available", e);
+    HandshakeHash(boolean isServer, boolean needCertificateVerify,
+            Set<String> algs) {
+        this.isServer = isServer;
+        clonesNeeded = needCertificateVerify ? 3 : 2;
+    }
 
+    void update(byte[] b, int offset, int len) {
+        switch (version) {
+            case 1:
+                md5.update(b, offset, len);
+                sha.update(b, offset, len);
+                break;
+            default:
+                if (finMD != null) {
+                    finMD.update(b, offset, len);
+                }
+                data.write(b, offset, len);
+                break;
         }
     }
 
-    void update(byte b) {
-        md5.update(b);
-        sha.update(b);
-    }
-
-    void update(byte[] b, int offset, int len) {
-        md5.update(b, offset, len);
-        sha.update(b, offset, len);
-    }
-
     /**
-     * Reset the remaining digests. Note this does *not* reset the numbe of
+     * Reset the remaining digests. Note this does *not* reset the number of
      * digest clones that can be obtained. Digests that have already been
      * cloned and are gone remain gone.
      */
     void reset() {
-        md5.reset();
-        sha.reset();
+        if (version != -1) {
+            throw new RuntimeException(
+                    "reset() can be only be called before protocolDetermined");
+        }
+        data.reset();
     }
 
+
+    void protocolDetermined(boolean isTLS12) {
+
+        // Do not set again, will ignore
+        if (version != -1) return;
+
+        version = isTLS12 ? 2 : 1;
+        switch (version) {
+            case 1:
+                // initiate md5, sha and call update on saved array
+                try {
+                    md5 = CloneableDigest.getDigest("MD5", clonesNeeded);
+                    sha = CloneableDigest.getDigest("SHA", clonesNeeded);
+                } catch (NoSuchAlgorithmException e) {
+                    throw new RuntimeException
+                                ("Algorithm MD5 or SHA not available", e);
+                }
+                byte[] bytes = data.toByteArray();
+                update(bytes, 0, bytes.length);
+                break;
+            case 2:
+                break;
+        }
+    }
+
+    /////////////////////////////////////////////////////////////
+    // Below are old methods for pre-TLS 1.1
+    /////////////////////////////////////////////////////////////
+
     /**
      * Return a new MD5 digest updated with all data hashed so far.
      */
     MessageDigest getMD5Clone() {
+        if (version != 1) {
+            throw new RuntimeException(
+                    "getMD5Clone() can be only be called for TLS 1.1");
+        }
         return cloneDigest(md5);
     }
 
@@ -88,6 +204,10 @@
      * Return a new SHA digest updated with all data hashed so far.
      */
     MessageDigest getSHAClone() {
+        if (version != 1) {
+            throw new RuntimeException(
+                    "getSHAClone() can be only be called for TLS 1.1");
+        }
         return cloneDigest(sha);
     }
 
@@ -100,6 +220,181 @@
         }
     }
 
+    /////////////////////////////////////////////////////////////
+    // Below are new methods for TLS 1.2
+    /////////////////////////////////////////////////////////////
+
+    private static String normalizeAlgName(String alg) {
+        alg = alg.toUpperCase(Locale.US);
+        if (alg.startsWith("SHA")) {
+            if (alg.length() == 3) {
+                return "SHA-1";
+            }
+            if (alg.charAt(3) != '-') {
+                return "SHA-" + alg.substring(3);
+            }
+        }
+        return alg;
+    }
+    /**
+     * Specifies the hash algorithm used in Finished. This should be called
+     * based in info in ServerHello.
+     * Can be called multiple times.
+     */
+    void setFinishedAlg(String s) {
+        if (s == null) {
+            throw new RuntimeException(
+                    "setFinishedAlg's argument cannot be null");
+        }
+
+        // Can be called multiple times, but only set once
+        if (finMD != null) return;
+
+        try {
+            finMD = CloneableDigest.getDigest(normalizeAlgName(s), 2);
+        } catch (NoSuchAlgorithmException e) {
+            throw new Error(e);
+        }
+        finMD.update(data.toByteArray());
+    }
+
+    /**
+     * Restricts the possible algorithms for the CertificateVerify. Called by
+     * the server based on info in CertRequest. The argument must be a subset
+     * of the argument with the same name in the constructor. The method can be
+     * called multiple times. If the caller is sure that no CertificateVerify
+     * message will be used, leave this argument null or empty.
+     */
+    void restrictCertificateVerifyAlgs(Set<String> algs) {
+        if (version == 1) {
+            throw new RuntimeException(
+                    "setCertificateVerifyAlg() cannot be called for TLS 1.1");
+        }
+        // Not used yet
+    }
+
+    /**
+     * Specifies the hash algorithm used in CertificateVerify.
+     * Can be called multiple times.
+     */
+    void setCertificateVerifyAlg(String s) {
+
+        // Can be called multiple times, but only set once
+        if (cvAlgDetermined) return;
+
+        cvAlg = s == null ? null : normalizeAlgName(s);
+        cvAlgDetermined = true;
+    }
+
+    byte[] getAllHandshakeMessages() {
+        return data.toByteArray();
+    }
+
+    /**
+     * Calculates the hash in the CertificateVerify. Must be called right
+     * after setCertificateVerifyAlg()
+     */
+    /*byte[] getCertificateVerifyHash() {
+        throw new Error("Do not call getCertificateVerifyHash()");
+    }*/
+
+    /**
+     * Calculates the hash in Finished. Must be called after setFinishedAlg().
+     * This method can be called twice, for Finished messages of the server
+     * side and client side respectively.
+     */
+    byte[] getFinishedHash() {
+        try {
+            return cloneDigest(finMD).digest();
+        } catch (Exception e) {
+            throw new Error("BAD");
+        }
+    }
+
+    ////////////////////////////////////////////////////////////////
+    // TEST
+    ////////////////////////////////////////////////////////////////
+
+    public static void main(String[] args) throws Exception {
+        Test t = new Test();
+        t.test(null, "SHA-256");
+        t.test("", "SHA-256");
+        t.test("SHA-1", "SHA-256");
+        t.test("SHA-256", "SHA-256");
+        t.test("SHA-384", "SHA-256");
+        t.test("SHA-512", "SHA-256");
+        t.testSame("sha", "SHA-1");
+        t.testSame("SHA", "SHA-1");
+        t.testSame("SHA1", "SHA-1");
+        t.testSame("SHA-1", "SHA-1");
+        t.testSame("SHA256", "SHA-256");
+        t.testSame("SHA-256", "SHA-256");
+    }
+
+    static class Test {
+        void update(HandshakeHash hh, String s) {
+            hh.update(s.getBytes(), 0, s.length());
+        }
+        static byte[] digest(String alg, String data) throws Exception {
+            return MessageDigest.getInstance(alg).digest(data.getBytes());
+        }
+        static void equals(byte[] b1, byte[] b2) {
+            if (!Arrays.equals(b1, b2)) {
+                throw new RuntimeException("Bad");
+            }
+        }
+        void testSame(String a, String a2) {
+            System.out.println("testSame: " + a + " " + a2);
+            if (!HandshakeHash.normalizeAlgName(a).equals(a2)) {
+                throw new RuntimeException("Bad");
+            }
+        }
+        /**
+         * Special convention: when it's certain that CV will not be used at the
+         * very beginning, use null as cvAlg. If known at a late stage, use "".
+         */
+        void test(String cvAlg, String finAlg) throws Exception {
+            System.out.println("test: " + cvAlg + " " + finAlg);
+            byte[] cv = null, f1, f2;
+            HandshakeHash hh = new HandshakeHash(true, true, null);
+            if (cvAlg == null) {
+                hh.setCertificateVerifyAlg(cvAlg);
+            }
+
+            update(hh, "ClientHello,");
+            hh.reset();
+            update(hh, "ClientHellov2,");
+            hh.setFinishedAlg(finAlg);
+
+            // Useless calls
+            hh.setFinishedAlg("SHA-1");
+            hh.setFinishedAlg("SHA-512");
+
+            update(hh, "More,");
+            if (cvAlg != null) {
+                if (cvAlg.isEmpty()) cvAlg = null;
+                hh.setCertificateVerifyAlg(cvAlg);
+            }
+
+            // Useless calls
+            hh.setCertificateVerifyAlg("SHA-1");
+            hh.setCertificateVerifyAlg(null);
+
+            hh.protocolDetermined(true);
+
+            if (cvAlg != null) {
+                cv = hh.getAllHandshakeMessages();
+                equals(cv, "ClientHellov2,More,".getBytes());
+            }
+
+            update(hh, "FIN1,");
+            f1 = hh.getFinishedHash();
+            equals(f1, digest(finAlg, "ClientHellov2,More,FIN1,"));
+            update(hh, "FIN2,");
+            f2 = hh.getFinishedHash();
+            equals(f2, digest(finAlg, "ClientHellov2,More,FIN1,FIN2,"));
+        }
+    }
 }
 
 /**
--- a/src/share/classes/sun/security/ssl/HandshakeMessage.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/HandshakeMessage.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,15 +41,12 @@
 
 import javax.crypto.KeyGenerator;
 import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
 
 import javax.net.ssl.*;
 
-import sun.security.action.GetPropertyAction;
-
 import sun.security.internal.spec.TlsPrfParameterSpec;
-
 import sun.security.ssl.CipherSuite.*;
+import static sun.security.ssl.CipherSuite.PRF.*;
 
 /**
  * Many data structures are involved in the handshake messages.  These
@@ -258,6 +255,27 @@
         extensions.add(renegotiationInfo);
     }
 
+    // add server_name extension
+    void addServerNameIndicationExtension(String hostname) {
+        // We would have checked that the hostname ia a FQDN.
+        ArrayList<String> hostnames = new ArrayList<String>(1);
+        hostnames.add(hostname);
+
+        try {
+            extensions.add(new ServerNameExtension(hostnames));
+        } catch (IOException ioe) {
+            // ignore the exception and return
+        }
+    }
+
+    // add signature_algorithm extension
+    void addSignatureAlgorithmsExtension(
+            Collection<SignatureAndHashAlgorithm> algorithms) {
+        HelloExtension signatureAlgorithm =
+                new SignatureAlgorithmsExtension(algorithms);
+        extensions.add(signatureAlgorithm);
+    }
+
     @Override
     int messageType() { return ht_client_hello; }
 
@@ -290,7 +308,8 @@
         s.println("*** ClientHello, " + protocolVersion);
 
         if (debug != null && Debug.isOn("verbose")) {
-            s.print   ("RandomCookie:  "); clnt_random.print(s);
+            s.print("RandomCookie:  ");
+            clnt_random.print(s);
 
             s.print("Session ID:  ");
             s.println(sessionId);
@@ -327,7 +346,8 @@
         // empty
     }
 
-    ServerHello(HandshakeInStream input, int messageLength) throws IOException {
+    ServerHello(HandshakeInStream input, int messageLength)
+            throws IOException {
         protocolVersion = ProtocolVersion.valueOf(input.getInt8(),
                                                   input.getInt8());
         svr_random = new RandomCookie(input);
@@ -367,7 +387,8 @@
         s.println("*** ServerHello, " + protocolVersion);
 
         if (debug != null && Debug.isOn("verbose")) {
-            s.print   ("RandomCookie:  "); svr_random.print(s);
+            s.print("RandomCookie:  ");
+            svr_random.print(s);
 
             int i;
 
@@ -425,8 +446,8 @@
                 }
                 v.add(cf.generateCertificate(new ByteArrayInputStream(cert)));
             } catch (CertificateException e) {
-                throw (SSLProtocolException)new SSLProtocolException
-                        (e.getMessage()).initCause(e);
+                throw (SSLProtocolException)new SSLProtocolException(
+                    e.getMessage()).initCause(e);
             }
         }
 
@@ -469,7 +490,7 @@
     }
 
     X509Certificate[] getCertificateChain() {
-        return chain;
+        return chain.clone();
     }
 }
 
@@ -597,9 +618,9 @@
         try {
             KeyFactory kfac = JsseJce.getKeyFactory("RSA");
             // modulus and exponent are always positive
-            RSAPublicKeySpec kspec = new RSAPublicKeySpec
-                                         (new BigInteger(1, rsa_modulus),
-                                          new BigInteger(1, rsa_exponent));
+            RSAPublicKeySpec kspec = new RSAPublicKeySpec(
+                new BigInteger(1, rsa_modulus),
+                new BigInteger(1, rsa_exponent));
             return kfac.generatePublic(kspec);
         } catch (Exception e) {
             throw new RuntimeException(e);
@@ -667,6 +688,12 @@
 
     private byte                signature [];
 
+    // protocol version being established using this ServerKeyExchange message
+    ProtocolVersion protocolVersion;
+
+    // the preferable signature algorithm used by this ServerKeyExchange message
+    private SignatureAndHashAlgorithm preferableSignatureAlgorithm;
+
     /* Return the Diffie-Hellman modulus */
     BigInteger getModulus() {
         return new BigInteger(1, dh_p);
@@ -712,8 +739,11 @@
      * Construct from initialized DH key object, for DH_anon
      * key exchange.
      */
-    DH_ServerKeyExchange(DHCrypt obj) {
-        getValues(obj);
+    DH_ServerKeyExchange(DHCrypt obj, ProtocolVersion protocolVersion) {
+        this.protocolVersion = protocolVersion;
+        this.preferableSignatureAlgorithm = null;
+
+        setValues(obj);
         signature = null;
     }
 
@@ -723,22 +753,33 @@
      * key exchange.  (Constructor called by server.)
      */
     DH_ServerKeyExchange(DHCrypt obj, PrivateKey key, byte clntNonce[],
-            byte svrNonce[], SecureRandom sr) throws GeneralSecurityException {
+            byte svrNonce[], SecureRandom sr,
+            SignatureAndHashAlgorithm signAlgorithm,
+            ProtocolVersion protocolVersion) throws GeneralSecurityException {
 
-        getValues(obj);
+        this.protocolVersion = protocolVersion;
+
+        setValues(obj);
 
         Signature sig;
-        if (key.getAlgorithm().equals("DSA")) {
-            sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA);
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            this.preferableSignatureAlgorithm = signAlgorithm;
+            sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName());
         } else {
-            sig = RSASignature.getInstance();
+            this.preferableSignatureAlgorithm = null;
+            if (key.getAlgorithm().equals("DSA")) {
+                sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA);
+            } else {
+                sig = RSASignature.getInstance();
+            }
         }
+
         sig.initSign(key, sr);
         updateSignature(sig, clntNonce, svrNonce);
         signature = sig.sign();
     }
 
-    private void getValues(DHCrypt obj) {
+    private void setValues(DHCrypt obj) {
         dh_p = toByteArray(obj.getModulus());
         dh_g = toByteArray(obj.getBase());
         dh_Ys = toByteArray(obj.getPublicKey());
@@ -749,7 +790,12 @@
      * stream, as if sent from server to client for use with
      * DH_anon key exchange
      */
-    DH_ServerKeyExchange(HandshakeInStream input) throws IOException {
+    DH_ServerKeyExchange(HandshakeInStream input,
+            ProtocolVersion protocolVersion) throws IOException {
+
+        this.protocolVersion = protocolVersion;
+        this.preferableSignatureAlgorithm = null;
+
         dh_p = input.getBytes16();
         dh_g = input.getBytes16();
         dh_Ys = input.getBytes16();
@@ -762,13 +808,38 @@
      * DHE_DSS or DHE_RSA key exchange.  (Called by client.)
      */
     DH_ServerKeyExchange(HandshakeInStream input, PublicKey publicKey,
-            byte clntNonce[], byte svrNonce[], int messageSize)
+            byte clntNonce[], byte svrNonce[], int messageSize,
+            Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs,
+            ProtocolVersion protocolVersion)
             throws IOException, GeneralSecurityException {
 
+        this.protocolVersion = protocolVersion;
+
+        // read params: ServerDHParams
         dh_p = input.getBytes16();
         dh_g = input.getBytes16();
         dh_Ys = input.getBytes16();
 
+        // read the signature and hash algorithm
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            int hash = input.getInt8();         // hash algorithm
+            int signature = input.getInt8();    // signature algorithm
+
+            preferableSignatureAlgorithm =
+                SignatureAndHashAlgorithm.valueOf(hash, signature, 0);
+
+            // Is it a local supported signature algorithm?
+            if (!localSupportedSignAlgs.contains(
+                    preferableSignatureAlgorithm)) {
+                throw new SSLHandshakeException(
+                        "Unsupported SignatureAndHashAlgorithm in " +
+                        "ServerKeyExchange message");
+            }
+        } else {
+            this.preferableSignatureAlgorithm = null;
+        }
+
+        // read the signature
         byte signature[];
         if (dhKeyExchangeFix) {
             signature = input.getBytes16();
@@ -783,12 +854,17 @@
 
         Signature sig;
         String algorithm = publicKey.getAlgorithm();
-        if (algorithm.equals("DSA")) {
-            sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA);
-        } else if (algorithm.equals("RSA")) {
-            sig = RSASignature.getInstance();
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            sig = JsseJce.getSignature(
+                        preferableSignatureAlgorithm.getAlgorithmName());
         } else {
-            throw new SSLKeyException("neither an RSA or a DSA key");
+            if (algorithm.equals("DSA")) {
+                sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA);
+            } else if (algorithm.equals("RSA")) {
+                sig = RSASignature.getInstance();
+            } else {
+                throw new SSLKeyException("neither an RSA or a DSA key");
+            }
         }
 
         sig.initVerify(publicKey);
@@ -805,12 +881,18 @@
         temp += dh_p.length;
         temp += dh_g.length;
         temp += dh_Ys.length;
+
         if (signature != null) {
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                temp += SignatureAndHashAlgorithm.sizeInRecord();
+            }
+
             temp += signature.length;
             if (dhKeyExchangeFix) {
                 temp += 2;
             }
         }
+
         return temp;
     }
 
@@ -818,7 +900,13 @@
         s.putBytes16(dh_p);
         s.putBytes16(dh_g);
         s.putBytes16(dh_Ys);
+
         if (signature != null) {
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                s.putInt8(preferableSignatureAlgorithm.getHashValue());
+                s.putInt8(preferableSignatureAlgorithm.getSignatureValue());
+            }
+
             if (dhKeyExchangeFix) {
                 s.putBytes16(signature);
             } else {
@@ -838,6 +926,11 @@
             if (signature == null) {
                 s.println("Anonymous");
             } else {
+                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                    s.println("Signature Algorithm " +
+                        preferableSignatureAlgorithm.getAlgorithmName());
+                }
+
                 s.println("Signed with a DSA or RSA public key");
             }
         }
@@ -871,9 +964,19 @@
     // public key object encapsulated in this message
     private ECPublicKey publicKey;
 
+    // protocol version being established using this ServerKeyExchange message
+    ProtocolVersion protocolVersion;
+
+    // the preferable signature algorithm used by this ServerKeyExchange message
+    private SignatureAndHashAlgorithm preferableSignatureAlgorithm;
+
     ECDH_ServerKeyExchange(ECDHCrypt obj, PrivateKey privateKey,
-            byte[] clntNonce, byte[] svrNonce, SecureRandom sr)
-            throws GeneralSecurityException {
+            byte[] clntNonce, byte[] svrNonce, SecureRandom sr,
+            SignatureAndHashAlgorithm signAlgorithm,
+            ProtocolVersion protocolVersion) throws GeneralSecurityException {
+
+        this.protocolVersion = protocolVersion;
+
         publicKey = (ECPublicKey)obj.getPublicKey();
         ECParameterSpec params = publicKey.getParams();
         ECPoint point = publicKey.getW();
@@ -885,8 +988,14 @@
             return;
         }
 
-        Signature sig = getSignature(privateKey.getAlgorithm());
-        sig.initSign(privateKey);
+        Signature sig;
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            this.preferableSignatureAlgorithm = signAlgorithm;
+            sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName());
+        } else {
+            sig = getSignature(privateKey.getAlgorithm());
+        }
+        sig.initSign(privateKey);  // where is the SecureRandom?
 
         updateSignature(sig, clntNonce, svrNonce);
         signatureBytes = sig.sign();
@@ -896,49 +1005,87 @@
      * Parse an ECDH server key exchange message.
      */
     ECDH_ServerKeyExchange(HandshakeInStream input, PublicKey signingKey,
-            byte[] clntNonce, byte[] svrNonce)
+            byte[] clntNonce, byte[] svrNonce,
+            Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs,
+            ProtocolVersion protocolVersion)
             throws IOException, GeneralSecurityException {
+
+        this.protocolVersion = protocolVersion;
+
+        // read params: ServerECDHParams
         int curveType = input.getInt8();
         ECParameterSpec parameters;
         // These parsing errors should never occur as we negotiated
         // the supported curves during the exchange of the Hello messages.
         if (curveType == CURVE_NAMED_CURVE) {
             curveId = input.getInt16();
-            if (SupportedEllipticCurvesExtension.isSupported(curveId) == false) {
-                throw new SSLHandshakeException("Unsupported curveId: " + curveId);
+            if (SupportedEllipticCurvesExtension.isSupported(curveId)
+                    == false) {
+                throw new SSLHandshakeException(
+                    "Unsupported curveId: " + curveId);
             }
-            String curveOid = SupportedEllipticCurvesExtension.getCurveOid(curveId);
+            String curveOid =
+                SupportedEllipticCurvesExtension.getCurveOid(curveId);
             if (curveOid == null) {
-                throw new SSLHandshakeException("Unknown named curve: " + curveId);
+                throw new SSLHandshakeException(
+                    "Unknown named curve: " + curveId);
             }
             parameters = JsseJce.getECParameterSpec(curveOid);
             if (parameters == null) {
-                throw new SSLHandshakeException("Unsupported curve: " + curveOid);
+                throw new SSLHandshakeException(
+                    "Unsupported curve: " + curveOid);
             }
         } else {
-            throw new SSLHandshakeException("Unsupported ECCurveType: " + curveType);
+            throw new SSLHandshakeException(
+                "Unsupported ECCurveType: " + curveType);
         }
         pointBytes = input.getBytes8();
 
         ECPoint point = JsseJce.decodePoint(pointBytes, parameters.getCurve());
         KeyFactory factory = JsseJce.getKeyFactory("EC");
-        publicKey = (ECPublicKey)factory.generatePublic(new ECPublicKeySpec(point, parameters));
+        publicKey = (ECPublicKey)factory.generatePublic(
+            new ECPublicKeySpec(point, parameters));
 
         if (signingKey == null) {
             // ECDH_anon
             return;
         }
 
+        // read the signature and hash algorithm
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            int hash = input.getInt8();         // hash algorithm
+            int signature = input.getInt8();    // signature algorithm
+
+            preferableSignatureAlgorithm =
+                SignatureAndHashAlgorithm.valueOf(hash, signature, 0);
+
+            // Is it a local supported signature algorithm?
+            if (!localSupportedSignAlgs.contains(
+                    preferableSignatureAlgorithm)) {
+                throw new SSLHandshakeException(
+                        "Unsupported SignatureAndHashAlgorithm in " +
+                        "ServerKeyExchange message");
+            }
+        }
+
+        // read the signature
+        signatureBytes = input.getBytes16();
+
         // verify the signature
-        signatureBytes = input.getBytes16();
-        Signature sig = getSignature(signingKey.getAlgorithm());
+        Signature sig;
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            sig = JsseJce.getSignature(
+                        preferableSignatureAlgorithm.getAlgorithmName());
+        } else {
+            sig = getSignature(signingKey.getAlgorithm());
+        }
         sig.initVerify(signingKey);
 
         updateSignature(sig, clntNonce, svrNonce);
 
         if (sig.verify(signatureBytes) == false ) {
-            throw new SSLKeyException
-                ("Invalid signature on ECDH server key exchange message");
+            throw new SSLKeyException(
+                "Invalid signature on ECDH server key exchange message");
         }
     }
 
@@ -949,7 +1096,8 @@
         return publicKey;
     }
 
-    private static Signature getSignature(String keyAlgorithm) throws NoSuchAlgorithmException {
+    private static Signature getSignature(String keyAlgorithm)
+            throws NoSuchAlgorithmException {
         if (keyAlgorithm.equals("EC")) {
             return JsseJce.getSignature(JsseJce.SIGNATURE_ECDSA);
         } else if (keyAlgorithm.equals("RSA")) {
@@ -973,6 +1121,11 @@
 
     int messageLength() {
         int sigLen = (signatureBytes == null) ? 0 : 2 + signatureBytes.length;
+
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            sigLen += SignatureAndHashAlgorithm.sizeInRecord();
+        }
+
         return 4 + pointBytes.length + sigLen;
     }
 
@@ -980,6 +1133,11 @@
         s.putInt8(CURVE_NAMED_CURVE);
         s.putInt16(curveId);
         s.putBytes8(pointBytes);
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            s.putInt8(preferableSignatureAlgorithm.getHashValue());
+            s.putInt8(preferableSignatureAlgorithm.getSignatureValue());
+        }
+
         if (signatureBytes != null) {
             s.putBytes16(signatureBytes);
         }
@@ -989,6 +1147,11 @@
         s.println("*** ECDH ServerKeyExchange");
 
         if (debug != null && Debug.isOn("verbose")) {
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                s.println("Signature Algorithm " +
+                        preferableSignatureAlgorithm.getAlgorithmName());
+            }
+
             s.println("Server key: " + publicKey);
         }
     }
@@ -1014,8 +1177,8 @@
         try {
             return new X500Principal(name);
         } catch (IllegalArgumentException e) {
-            throw (SSLProtocolException)new SSLProtocolException
-                    (e.getMessage()).initCause(e);
+            throw (SSLProtocolException)new SSLProtocolException(
+                e.getMessage()).initCause(e);
         }
     }
 
@@ -1038,12 +1201,25 @@
  *
  * Authenticated servers may ask clients to authenticate themselves
  * in turn, using this message.
+ *
+ * Prior to TLS 1.2, the structure of the message is defined as:
+ *     struct {
+ *         ClientCertificateType certificate_types<1..2^8-1>;
+ *         DistinguishedName certificate_authorities<0..2^16-1>;
+ *     } CertificateRequest;
+ *
+ * In TLS 1.2, the structure is changed to:
+ *     struct {
+ *         ClientCertificateType certificate_types<1..2^8-1>;
+ *         SignatureAndHashAlgorithm
+ *           supported_signature_algorithms<2^16-1>;
+ *         DistinguishedName certificate_authorities<0..2^16-1>;
+ *     } CertificateRequest;
+ *
  */
 static final
 class CertificateRequest extends HandshakeMessage
 {
-    int messageType() { return ht_certificate_request; }
-
     // enum ClientCertificateType
     static final int   cct_rsa_sign = 1;
     static final int   cct_dss_sign = 2;
@@ -1068,8 +1244,21 @@
     DistinguishedName   authorities [];         // 3 to 2^16 - 1
         // ... "3" because that's the smallest DER-encoded X500 DN
 
-    CertificateRequest(X509Certificate ca[], KeyExchange keyExchange)
-            throws IOException {
+    // protocol version being established using this CertificateRequest message
+    ProtocolVersion protocolVersion;
+
+    // supported_signature_algorithms for TLS 1.2 or later
+    private Collection<SignatureAndHashAlgorithm> algorithms;
+
+    // length of supported_signature_algorithms
+    private int algorithmsLen;
+
+    CertificateRequest(X509Certificate ca[], KeyExchange keyExchange,
+            Collection<SignatureAndHashAlgorithm> signAlgs,
+            ProtocolVersion protocolVersion) throws IOException {
+
+        this.protocolVersion = protocolVersion;
+
         // always use X500Principal
         authorities = new DistinguishedName[ca.length];
         for (int i = 0; i < ca.length; i++) {
@@ -1081,10 +1270,63 @@
         // needs to be adapted to take keyExchange into account.
         // We only request ECDSA client auth if we have ECC crypto available.
         this.types = JsseJce.isEcAvailable() ? TYPES_ECC : TYPES_NO_ECC;
+
+        // Use supported_signature_algorithms for TLS 1.2 or later.
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (signAlgs == null || signAlgs.isEmpty()) {
+                throw new SSLProtocolException(
+                        "No supported signature algorithms");
+            }
+
+            algorithms = new ArrayList<SignatureAndHashAlgorithm>(signAlgs);
+            algorithmsLen =
+                SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size();
+        } else {
+            algorithms = new ArrayList<SignatureAndHashAlgorithm>();
+            algorithmsLen = 0;
+        }
     }
 
-    CertificateRequest(HandshakeInStream input) throws IOException {
+    CertificateRequest(HandshakeInStream input,
+            ProtocolVersion protocolVersion) throws IOException {
+
+        this.protocolVersion = protocolVersion;
+
+        // Read the certificate_types.
         types = input.getBytes8();
+
+        // Read the supported_signature_algorithms for TLS 1.2 or later.
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            algorithmsLen = input.getInt16();
+            if (algorithmsLen < 2) {
+                throw new SSLProtocolException(
+                        "Invalid supported_signature_algorithms field");
+            }
+
+            algorithms = new ArrayList<SignatureAndHashAlgorithm>();
+            int remains = algorithmsLen;
+            int sequence = 0;
+            while (remains > 1) {    // needs at least two bytes
+                int hash = input.getInt8();         // hash algorithm
+                int signature = input.getInt8();    // signature algorithm
+
+                SignatureAndHashAlgorithm algorithm =
+                    SignatureAndHashAlgorithm.valueOf(hash, signature,
+                                                                ++sequence);
+                algorithms.add(algorithm);
+                remains -= 2;  // one byte for hash, one byte for signature
+            }
+
+            if (remains != 0) {
+                throw new SSLProtocolException(
+                        "Invalid supported_signature_algorithms field");
+            }
+        } else {
+            algorithms = new ArrayList<SignatureAndHashAlgorithm>();
+            algorithmsLen = 0;
+        }
+
+        // read the certificate_authorities
         int len = input.getInt16();
         ArrayList<DistinguishedName> v = new ArrayList<DistinguishedName>();
         while (len >= 3) {
@@ -1108,31 +1350,58 @@
         return ret;
     }
 
-    int messageLength()
-    {
-        int len;
+    Collection<SignatureAndHashAlgorithm> getSignAlgorithms() {
+        return algorithms;
+    }
 
-        len = 1 + types.length + 2;
-        for (int i = 0; i < authorities.length; i++)
+    @Override
+    int messageType() {
+        return ht_certificate_request;
+    }
+
+    @Override
+    int messageLength() {
+        int len = 1 + types.length + 2;
+
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            len += algorithmsLen + 2;
+        }
+
+        for (int i = 0; i < authorities.length; i++) {
             len += authorities[i].length();
+        }
+
         return len;
     }
 
-    void send(HandshakeOutStream output) throws IOException
-    {
-        int     len = 0;
+    @Override
+    void send(HandshakeOutStream output) throws IOException {
+        // put certificate_types
+        output.putBytes8(types);
 
-        for (int i = 0; i < authorities.length; i++)
+        // put supported_signature_algorithms
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            output.putInt16(algorithmsLen);
+            for (SignatureAndHashAlgorithm algorithm : algorithms) {
+                output.putInt8(algorithm.getHashValue());      // hash
+                output.putInt8(algorithm.getSignatureValue()); // signature
+            }
+        }
+
+        // put certificate_authorities
+        int len = 0;
+        for (int i = 0; i < authorities.length; i++) {
             len += authorities[i].length();
+        }
 
-        output.putBytes8(types);
         output.putInt16(len);
-        for (int i = 0; i < authorities.length; i++)
+        for (int i = 0; i < authorities.length; i++) {
             authorities[i].send(output);
+        }
     }
 
-    void print(PrintStream s) throws IOException
-    {
+    @Override
+    void print(PrintStream s) throws IOException {
         s.println("*** CertificateRequest");
 
         if (debug != null && Debug.isOn("verbose")) {
@@ -1166,6 +1435,20 @@
             }
             s.println();
 
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                StringBuffer buffer = new StringBuffer();
+                boolean opened = false;
+                for (SignatureAndHashAlgorithm signAlg : algorithms) {
+                    if (opened) {
+                        buffer.append(", " + signAlg.getAlgorithmName());
+                    } else {
+                        buffer.append(signAlg.getAlgorithmName());
+                        opened = true;
+                    }
+                }
+                s.println("Supported Signature Algorithms: " + buffer);
+            }
+
             s.println("Cert Authorities:");
             if (authorities.length == 0) {
                 s.println("<Empty>");
@@ -1224,18 +1507,34 @@
  */
 static final class CertificateVerify extends HandshakeMessage {
 
-    int messageType() { return ht_certificate_verify; }
+    // the signature bytes
+    private byte[] signature;
 
-    private byte[] signature;
+    // protocol version being established using this ServerKeyExchange message
+    ProtocolVersion protocolVersion;
+
+    // the preferable signature algorithm used by this CertificateVerify message
+    private SignatureAndHashAlgorithm preferableSignatureAlgorithm = null;
 
     /*
      * Create an RSA or DSA signed certificate verify message.
      */
-    CertificateVerify(ProtocolVersion protocolVersion, HandshakeHash
-            handshakeHash, PrivateKey privateKey, SecretKey masterSecret,
-            SecureRandom sr) throws GeneralSecurityException {
+    CertificateVerify(ProtocolVersion protocolVersion,
+            HandshakeHash handshakeHash, PrivateKey privateKey,
+            SecretKey masterSecret, SecureRandom sr,
+            SignatureAndHashAlgorithm signAlgorithm)
+            throws GeneralSecurityException {
+
+        this.protocolVersion = protocolVersion;
+
         String algorithm = privateKey.getAlgorithm();
-        Signature sig = getSignature(protocolVersion, algorithm);
+        Signature sig = null;
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            this.preferableSignatureAlgorithm = signAlgorithm;
+            sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName());
+        } else {
+            sig = getSignature(protocolVersion, algorithm);
+        }
         sig.initSign(privateKey, sr);
         updateSignature(sig, protocolVersion, handshakeHash, algorithm,
                         masterSecret);
@@ -1245,11 +1544,41 @@
     //
     // Unmarshal the signed data from the input stream.
     //
-    CertificateVerify(HandshakeInStream input) throws IOException  {
+    CertificateVerify(HandshakeInStream input,
+            Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs,
+            ProtocolVersion protocolVersion) throws IOException  {
+
+        this.protocolVersion = protocolVersion;
+
+        // read the signature and hash algorithm
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            int hashAlg = input.getInt8();         // hash algorithm
+            int signAlg = input.getInt8();         // signature algorithm
+
+            preferableSignatureAlgorithm =
+                SignatureAndHashAlgorithm.valueOf(hashAlg, signAlg, 0);
+
+            // Is it a local supported signature algorithm?
+            if (!localSupportedSignAlgs.contains(
+                    preferableSignatureAlgorithm)) {
+                throw new SSLHandshakeException(
+                        "Unsupported SignatureAndHashAlgorithm in " +
+                        "ServerKeyExchange message");
+            }
+        }
+
+        // read the signature
         signature = input.getBytes16();
     }
 
     /*
+     * Get the preferable signature algorithm used by this message
+     */
+    SignatureAndHashAlgorithm getPreferableSignatureAlgorithm() {
+        return preferableSignatureAlgorithm;
+    }
+
+    /*
      * Verify a certificate verify message. Return the result of verification,
      * if there is a problem throw a GeneralSecurityException.
      */
@@ -1257,7 +1586,13 @@
             HandshakeHash handshakeHash, PublicKey publicKey,
             SecretKey masterSecret) throws GeneralSecurityException {
         String algorithm = publicKey.getAlgorithm();
-        Signature sig = getSignature(protocolVersion, algorithm);
+        Signature sig = null;
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            sig = JsseJce.getSignature(
+                        preferableSignatureAlgorithm.getAlgorithmName());
+        } else {
+            sig = getSignature(protocolVersion, algorithm);
+        }
         sig.initVerify(publicKey);
         updateSignature(sig, protocolVersion, handshakeHash, algorithm,
                         masterSecret);
@@ -1291,25 +1626,35 @@
             ProtocolVersion protocolVersion,
             HandshakeHash handshakeHash, String algorithm, SecretKey masterKey)
             throws SignatureException {
-        MessageDigest md5Clone = handshakeHash.getMD5Clone();
-        MessageDigest shaClone = handshakeHash.getSHAClone();
-        boolean tls = protocolVersion.v >= ProtocolVersion.TLS10.v;
+
         if (algorithm.equals("RSA")) {
-            if (tls) {
-                // nothing to do
-            } else { // SSLv3
-                updateDigest(md5Clone, MD5_pad1, MD5_pad2, masterKey);
-                updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey);
+            if (protocolVersion.v < ProtocolVersion.TLS12.v) { // TLS1.1-
+                MessageDigest md5Clone = handshakeHash.getMD5Clone();
+                MessageDigest shaClone = handshakeHash.getSHAClone();
+
+                if (protocolVersion.v < ProtocolVersion.TLS10.v) { // SSLv3
+                    updateDigest(md5Clone, MD5_pad1, MD5_pad2, masterKey);
+                    updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey);
+                }
+
+                // The signature must be an instance of RSASignature, need
+                // to use these hashes directly.
+                RSASignature.setHashes(sig, md5Clone, shaClone);
+            } else {  // TLS1.2+
+                sig.update(handshakeHash.getAllHandshakeMessages());
             }
-            // need to use these hashes directly
-            RSASignature.setHashes(sig, md5Clone, shaClone);
         } else { // DSA, ECDSA
-            if (tls) {
-                // nothing to do
-            } else { // SSLv3
-                updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey);
+            if (protocolVersion.v < ProtocolVersion.TLS12.v) { // TLS1.1-
+                MessageDigest shaClone = handshakeHash.getSHAClone();
+
+                if (protocolVersion.v < ProtocolVersion.TLS10.v) { // SSLv3
+                    updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey);
+                }
+
+                sig.update(shaClone.digest());
+            } else {  // TLS1.2+
+                sig.update(handshakeHash.getAllHandshakeMessages());
             }
-            sig.update(shaClone.digest());
         }
     }
 
@@ -1319,7 +1664,8 @@
      * all preceding handshake messages.
      * Used by the Finished class as well.
      */
-    static void updateDigest(MessageDigest md, byte[] pad1, byte[] pad2,
+    private static void updateDigest(MessageDigest md,
+            byte[] pad1, byte[] pad2,
             SecretKey masterSecret) {
         // Digest the key bytes if available.
         // Otherwise (sensitive key), try digesting the key directly.
@@ -1395,26 +1741,54 @@
                 methodCache.put(clazz, r);
             }
             if (r == NULL_OBJECT) {
-                throw new Exception("Digest does not support implUpdate(SecretKey)");
+                throw new Exception(
+                    "Digest does not support implUpdate(SecretKey)");
             }
             Method update = (Method)r;
             update.invoke(spi, key);
         } catch (Exception e) {
-            throw new RuntimeException
-            ("Could not obtain encoded key and MessageDigest cannot digest key", e);
+            throw new RuntimeException(
+                "Could not obtain encoded key and "
+                + "MessageDigest cannot digest key", e);
         }
     }
 
-    int messageLength() {
-        return 2 + signature.length;
+    @Override
+    int messageType() {
+        return ht_certificate_verify;
     }
 
+    @Override
+    int messageLength() {
+        int temp = 2;
+
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            temp += SignatureAndHashAlgorithm.sizeInRecord();
+        }
+
+        return temp + signature.length;
+    }
+
+    @Override
     void send(HandshakeOutStream s) throws IOException {
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            s.putInt8(preferableSignatureAlgorithm.getHashValue());
+            s.putInt8(preferableSignatureAlgorithm.getSignatureValue());
+        }
+
         s.putBytes16(signature);
     }
 
+    @Override
     void print(PrintStream s) throws IOException {
         s.println("*** CertificateVerify");
+
+        if (debug != null && Debug.isOn("verbose")) {
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                s.println("Signature Algorithm " +
+                        preferableSignatureAlgorithm.getAlgorithmName());
+            }
+        }
     }
 }
 
@@ -1453,19 +1827,29 @@
     private byte[] verifyData;
 
     /*
+     * Current cipher suite we are negotiating.  TLS 1.2 has
+     * ciphersuite-defined PRF algorithms.
+     */
+    private ProtocolVersion protocolVersion;
+    private CipherSuite cipherSuite;
+
+    /*
      * Create a finished message to send to the remote peer.
      */
     Finished(ProtocolVersion protocolVersion, HandshakeHash handshakeHash,
-            int sender, SecretKey master) {
-        verifyData = getFinished(protocolVersion, handshakeHash, sender,
-                                 master);
+            int sender, SecretKey master, CipherSuite cipherSuite) {
+        this.protocolVersion = protocolVersion;
+        this.cipherSuite = cipherSuite;
+        verifyData = getFinished(handshakeHash, sender, master);
     }
 
     /*
      * Constructor that reads FINISHED message from stream.
      */
-    Finished(ProtocolVersion protocolVersion, HandshakeInStream input)
-            throws IOException {
+    Finished(ProtocolVersion protocolVersion, HandshakeInStream input,
+            CipherSuite cipherSuite) throws IOException {
+        this.protocolVersion = protocolVersion;
+        this.cipherSuite = cipherSuite;
         int msgLen = (protocolVersion.v >= ProtocolVersion.TLS10.v) ? 12 : 36;
         verifyData = new byte[msgLen];
         input.read(verifyData);
@@ -1477,18 +1861,16 @@
      * both client and server are fully in sync, and that the handshake
      * computations have been successful.
      */
-    boolean verify(ProtocolVersion protocolVersion,
-             HandshakeHash handshakeHash, int sender, SecretKey master) {
-        byte[] myFinished = getFinished(protocolVersion, handshakeHash,
-                                        sender, master);
+    boolean verify(HandshakeHash handshakeHash, int sender, SecretKey master) {
+        byte[] myFinished = getFinished(handshakeHash, sender, master);
         return Arrays.equals(myFinished, verifyData);
     }
 
     /*
      * Perform the actual finished message calculation.
      */
-    private static byte[] getFinished(ProtocolVersion protocolVersion,
-            HandshakeHash handshakeHash, int sender, SecretKey masterKey) {
+    private byte[] getFinished(HandshakeHash handshakeHash,
+            int sender, SecretKey masterKey) {
         byte[] sslLabel;
         String tlsLabel;
         if (sender == CLIENT) {
@@ -1500,23 +1882,53 @@
         } else {
             throw new RuntimeException("Invalid sender: " + sender);
         }
-        MessageDigest md5Clone = handshakeHash.getMD5Clone();
-        MessageDigest shaClone = handshakeHash.getSHAClone();
+
         if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
-            // TLS
+            // TLS 1.0+
             try {
-                byte[] seed = new byte[36];
-                md5Clone.digest(seed, 0, 16);
-                shaClone.digest(seed, 16, 20);
+                byte [] seed;
+                String prfAlg;
+                PRF prf;
 
-                TlsPrfParameterSpec spec = new TlsPrfParameterSpec
-                                                (masterKey, tlsLabel, seed, 12);
-                KeyGenerator prf = JsseJce.getKeyGenerator("SunTlsPrf");
-                prf.init(spec);
-                SecretKey prfKey = prf.generateKey();
+                // Get the KeyGenerator alg and calculate the seed.
+                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                    // TLS 1.2
+                    seed = handshakeHash.getFinishedHash();
+
+                    prfAlg = "SunTls12Prf";
+                    prf = cipherSuite.prfAlg;
+                } else {
+                    // TLS 1.0/1.1
+                    MessageDigest md5Clone = handshakeHash.getMD5Clone();
+                    MessageDigest shaClone = handshakeHash.getSHAClone();
+                    seed = new byte[36];
+                    md5Clone.digest(seed, 0, 16);
+                    shaClone.digest(seed, 16, 20);
+
+                    prfAlg = "SunTlsPrf";
+                    prf = P_NONE;
+                }
+
+                String prfHashAlg = prf.getPRFHashAlg();
+                int prfHashLength = prf.getPRFHashLength();
+                int prfBlockSize = prf.getPRFBlockSize();
+
+                /*
+                 * RFC 5246/7.4.9 says that finished messages can
+                 * be ciphersuite-specific in both length/PRF hash
+                 * algorithm.  If we ever run across a different
+                 * length, this call will need to be updated.
+                 */
+                TlsPrfParameterSpec spec = new TlsPrfParameterSpec(
+                    masterKey, tlsLabel, seed, 12,
+                    prfHashAlg, prfHashLength, prfBlockSize);
+
+                KeyGenerator kg = JsseJce.getKeyGenerator(prfAlg);
+                kg.init(spec);
+                SecretKey prfKey = kg.generateKey();
                 if ("RAW".equals(prfKey.getFormat()) == false) {
-                    throw new ProviderException
-                        ("Invalid PRF output, format must be RAW");
+                    throw new ProviderException(
+                        "Invalid PRF output, format must be RAW");
                 }
                 byte[] finished = prfKey.getEncoded();
                 return finished;
@@ -1525,6 +1937,8 @@
             }
         } else {
             // SSLv3
+            MessageDigest md5Clone = handshakeHash.getMD5Clone();
+            MessageDigest shaClone = handshakeHash.getSHAClone();
             updateDigest(md5Clone, sslLabel, MD5_pad1, MD5_pad2, masterKey);
             updateDigest(shaClone, sslLabel, SHA_pad1, SHA_pad2, masterKey);
             byte[] finished = new byte[36];
--- a/src/share/classes/sun/security/ssl/Handshaker.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/Handshaker.java	Mon Nov 01 22:02:35 2010 -0700
@@ -29,13 +29,12 @@
 import java.io.*;
 import java.util.*;
 import java.security.*;
-import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.AccessController;
+import java.security.AlgorithmConstraints;
 import java.security.AccessControlContext;
 import java.security.PrivilegedExceptionAction;
 import java.security.PrivilegedActionException;
-import java.security.cert.X509Certificate;
 
 import javax.crypto.*;
 import javax.crypto.spec.*;
@@ -49,6 +48,8 @@
 import sun.security.ssl.HandshakeMessage.*;
 import sun.security.ssl.CipherSuite.*;
 
+import static sun.security.ssl.CipherSuite.PRF.*;
+
 /**
  * Handshaker ... processes handshake records from an SSL V3.0
  * data stream, handling all the details of the handshake protocol.
@@ -80,6 +81,20 @@
     // List of enabled CipherSuites
     private CipherSuiteList     enabledCipherSuites;
 
+    // The endpoint identification protocol
+    String              identificationProtocol;
+
+    // The cryptographic algorithm constraints
+    private AlgorithmConstraints    algorithmConstraints = null;
+
+    // Local supported signature and algorithms
+    Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs;
+
+    // Peer supported signature and algorithms
+    Collection<SignatureAndHashAlgorithm> peerSupportedSignAlgs;
+
+    /*
+
     /*
      * List of active protocols
      *
@@ -98,6 +113,7 @@
     private CipherSuiteList    activeCipherSuites;
 
     private boolean             isClient;
+    private boolean             needCertVerify;
 
     SSLSocketImpl               conn = null;
     SSLEngineImpl               engine = null;
@@ -110,10 +126,6 @@
     RandomCookie                clnt_random, svr_random;
     SSLSessionImpl              session;
 
-    // Temporary MD5 and SHA message digests. Must always be left
-    // in reset state after use.
-    private MessageDigest md5Tmp, shaTmp;
-
     // current CipherSuite. Never null, initially SSL_NULL_WITH_NULL_NULL
     CipherSuite         cipherSuite;
 
@@ -208,6 +220,7 @@
 
         this.sslContext = context;
         this.isClient = isClient;
+        this.needCertVerify = needCertVerify;
         this.activeProtocolVersion = activeProtocolVersion;
         this.isInitialHandshake = isInitialHandshake;
         this.secureRenegotiation = secureRenegotiation;
@@ -217,23 +230,12 @@
         invalidated = false;
 
         setCipherSuite(CipherSuite.C_NULL);
-
-        md5Tmp = JsseJce.getMD5();
-        shaTmp = JsseJce.getSHA();
-
-        //
-        // We accumulate digests of the handshake messages so that
-        // we can read/write CertificateVerify and Finished messages,
-        // getting assurance against some particular active attacks.
-        //
-        handshakeHash = new HandshakeHash(needCertVerify);
-
         setEnabledProtocols(enabledProtocols);
 
         if (conn != null) {
-            conn.getAppInputStream().r.setHandshakeHash(handshakeHash);
+            algorithmConstraints = new SSLAlgorithmConstraints(conn, true);
         } else {        // engine != null
-            engine.inputRecord.setHandshakeHash(handshakeHash);
+            algorithmConstraints = new SSLAlgorithmConstraints(engine, true);
         }
 
 
@@ -285,6 +287,14 @@
         }
     }
 
+    String getRawHostnameSE() {
+        if (conn != null) {
+            return conn.getRawHostname();
+        } else {
+            return engine.getPeerHost();
+        }
+    }
+
     String getHostSE() {
         if (conn != null) {
             return conn.getHost();
@@ -330,14 +340,6 @@
         }
     }
 
-    String getHostnameVerificationSE() {
-        if (conn != null) {
-            return conn.getHostnameVerification();
-        } else {
-            return engine.getHostnameVerification();
-        }
-    }
-
     AccessControlContext getAccSE() {
         if (conn != null) {
             return conn.getAcc();
@@ -366,7 +368,6 @@
         output.r.setVersion(protocolVersion);
     }
 
-
     /**
      * Set the enabled protocols. Called from the constructor or
      * SSLSocketImpl/SSLEngineImpl.setEnabledProtocols() (if the
@@ -390,6 +391,49 @@
         this.enabledCipherSuites = enabledCipherSuites;
     }
 
+    /**
+     * Set the algorithm constraints. Called from the constructor or
+     * SSLSocketImpl/SSLEngineImpl.setAlgorithmConstraints() (if the
+     * handshake is not yet in progress).
+     */
+    void setAlgorithmConstraints(AlgorithmConstraints algorithmConstraints) {
+        activeCipherSuites = null;
+        activeProtocols = null;
+
+        this.algorithmConstraints =
+            new SSLAlgorithmConstraints(algorithmConstraints);
+        this.localSupportedSignAlgs = null;
+    }
+
+    Collection<SignatureAndHashAlgorithm> getLocalSupportedSignAlgs() {
+        if (localSupportedSignAlgs == null) {
+            localSupportedSignAlgs =
+                SignatureAndHashAlgorithm.getSupportedAlgorithms(
+                                                    algorithmConstraints);
+        }
+
+        return localSupportedSignAlgs;
+    }
+
+    void setPeerSupportedSignAlgs(
+            Collection<SignatureAndHashAlgorithm> algorithms) {
+        peerSupportedSignAlgs =
+            new ArrayList<SignatureAndHashAlgorithm>(algorithms);
+    }
+
+    Collection<SignatureAndHashAlgorithm> getPeerSupportedSignAlgs() {
+        return peerSupportedSignAlgs;
+    }
+
+
+    /**
+     * Set the identification protocol. Called from the constructor or
+     * SSLSocketImpl/SSLEngineImpl.setIdentificationProtocol() (if the
+     * handshake is not yet in progress).
+     */
+    void setIdentificationProtocol(String protocol) {
+        this.identificationProtocol = protocol;
+    }
 
     /**
      * Prior to handshaking, activate the handshake and initialize the version,
@@ -426,16 +470,27 @@
             helloVersion = activeProtocols.helloVersion;
         }
 
+        // We accumulate digests of the handshake messages so that
+        // we can read/write CertificateVerify and Finished messages,
+        // getting assurance against some particular active attacks.
+        Set<String> localSupportedHashAlgorithms =
+            SignatureAndHashAlgorithm.getHashAlgorithmNames(
+                getLocalSupportedSignAlgs());
+        handshakeHash = new HandshakeHash(!isClient, needCertVerify,
+            localSupportedHashAlgorithms);
+
+        // Generate handshake input/output stream.
         input = new HandshakeInStream(handshakeHash);
-
         if (conn != null) {
             output = new HandshakeOutStream(protocolVersion, helloVersion,
                                         handshakeHash, conn);
+            conn.getAppInputStream().r.setHandshakeHash(handshakeHash);
             conn.getAppInputStream().r.setHelloVersion(helloVersion);
             conn.getAppOutputStream().r.setHelloVersion(helloVersion);
         } else {
             output = new HandshakeOutStream(protocolVersion, helloVersion,
                                         handshakeHash, engine);
+            engine.inputRecord.setHandshakeHash(handshakeHash);
             engine.inputRecord.setHelloVersion(helloVersion);
             engine.outputRecord.setHelloVersion(helloVersion);
         }
@@ -501,7 +556,7 @@
      *
      * Therefore, when the active protocols only include TLS 1.1 or later,
      * the client cannot request to negotiate those obsoleted cipher
-     * suites, that's, the obsoleted suites should not be included in the
+     * suites.  That is, the obsoleted suites should not be included in the
      * client hello. So we need to create a subset of the enabled cipher
      * suites, the active cipher suites, which does not contain obsoleted
      * cipher suites of the minimum active protocol.
@@ -518,11 +573,21 @@
             if (!(activeProtocols.collection().isEmpty()) &&
                     activeProtocols.min.v != ProtocolVersion.NONE.v) {
                 for (CipherSuite suite : enabledCipherSuites.collection()) {
-                    if (suite.obsoleted > activeProtocols.min.v) {
-                        suites.add(suite);
-                    } else if (debug != null && Debug.isOn("handshake")) {
-                        System.out.println(
-                            "Ignoring obsoleted cipher suite: " + suite);
+                    if (suite.obsoleted > activeProtocols.min.v &&
+                            suite.supported <= activeProtocols.max.v) {
+                        if (algorithmConstraints.permits(
+                                EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
+                                suite.name, null)) {
+                            suites.add(suite);
+                        }
+                    } else if (debug != null && Debug.isOn("verbose")) {
+                        if (suite.obsoleted <= activeProtocols.min.v) {
+                            System.out.println(
+                                "Ignoring obsoleted cipher suite: " + suite);
+                        } else {
+                            System.out.println(
+                                "Ignoring unsupported cipher suite: " + suite);
+                        }
                     }
                 }
             }
@@ -550,14 +615,27 @@
     ProtocolList getActiveProtocols() {
         if (activeProtocols == null) {
             ArrayList<ProtocolVersion> protocols =
-                                            new ArrayList<ProtocolVersion>(3);
+                                            new ArrayList<ProtocolVersion>(4);
             for (ProtocolVersion protocol : enabledProtocols.collection()) {
                 boolean found = false;
                 for (CipherSuite suite : enabledCipherSuites.collection()) {
-                    if (suite.isAvailable() && suite.obsoleted > protocol.v) {
-                        protocols.add(protocol);
-                        found = true;
-                        break;
+                    if (suite.isAvailable() && suite.obsoleted > protocol.v &&
+                                               suite.supported <= protocol.v) {
+                        if (algorithmConstraints.permits(
+                                EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
+                                suite.name, null)) {
+                            protocols.add(protocol);
+                            found = true;
+                            break;
+                        } else if (debug != null && Debug.isOn("verbose")) {
+                            System.out.println(
+                                "Ignoring disabled cipher suite: " + suite +
+                                 " for " + protocol);
+                        }
+                    } else if (debug != null && Debug.isOn("verbose")) {
+                        System.out.println(
+                            "Ignoring unsupported cipher suite: " + suite +
+                                 " for " + protocol);
                     }
                 }
                 if (!found && (debug != null) && Debug.isOn("handshake")) {
@@ -673,6 +751,17 @@
     }
 
     /*
+     * Set the handshake session
+     */
+    void setHandshakeSessionSE(SSLSessionImpl handshakeSession) {
+        if (conn != null) {
+            conn.setHandshakeSession(handshakeSession);
+        } else {
+            engine.setHandshakeSession(handshakeSession);
+        }
+    }
+
+    /*
      * Returns true if renegotiation is in use for this connection.
      */
     boolean isSecureRenegotiation() {
@@ -798,7 +887,7 @@
      */
     boolean started() {
         return state >= 0;  // 0: HandshakeMessage.ht_hello_request
-                            // 1: HandshakeMessage.ht_hello_request
+                            // 1: HandshakeMessage.ht_client_hello
     }
 
 
@@ -926,10 +1015,6 @@
     private SecretKey calculateMasterSecret(SecretKey preMasterSecret,
             ProtocolVersion requestedVersion) {
 
-        TlsMasterSecretParameterSpec spec = new TlsMasterSecretParameterSpec
-                (preMasterSecret, protocolVersion.major, protocolVersion.minor,
-                clnt_random.random_bytes, svr_random.random_bytes);
-
         if (debug != null && Debug.isOn("keygen")) {
             HexDumpEncoder      dump = new HexDumpEncoder();
 
@@ -942,15 +1027,37 @@
             // benefit to doing it twice
         }
 
+        // What algs/params do we need to use?
+        String masterAlg;
+        PRF prf;
+
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            masterAlg = "SunTls12MasterSecret";
+            prf = cipherSuite.prfAlg;
+        } else {
+            masterAlg = "SunTlsMasterSecret";
+            prf = P_NONE;
+        }
+
+        String prfHashAlg = prf.getPRFHashAlg();
+        int prfHashLength = prf.getPRFHashLength();
+        int prfBlockSize = prf.getPRFBlockSize();
+
+        TlsMasterSecretParameterSpec spec = new TlsMasterSecretParameterSpec(
+                preMasterSecret, protocolVersion.major, protocolVersion.minor,
+                clnt_random.random_bytes, svr_random.random_bytes,
+                prfHashAlg, prfHashLength, prfBlockSize);
+
         SecretKey masterSecret;
         try {
-            KeyGenerator kg = JsseJce.getKeyGenerator("SunTlsMasterSecret");
+            KeyGenerator kg = JsseJce.getKeyGenerator(masterAlg);
             kg.init(spec);
             masterSecret = kg.generateKey();
         } catch (GeneralSecurityException e) {
             // For RSA premaster secrets, do not signal a protocol error
             // due to the Bleichenbacher attack. See comments further down.
-            if (!preMasterSecret.getAlgorithm().equals("TlsRsaPremasterSecret")) {
+            if (!preMasterSecret.getAlgorithm().equals(
+                    "TlsRsaPremasterSecret")) {
                 throw new ProviderException(e);
             }
 
@@ -1056,14 +1163,31 @@
         BulkCipher cipher = cipherSuite.cipher;
         int expandedKeySize = is_exportable ? cipher.expandedKeySize : 0;
 
-        TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec
-            (masterKey, protocolVersion.major, protocolVersion.minor,
+        // Which algs/params do we need to use?
+        String keyMaterialAlg;
+        PRF prf;
+
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            keyMaterialAlg = "SunTls12KeyMaterial";
+            prf = cipherSuite.prfAlg;
+        } else {
+            keyMaterialAlg = "SunTlsKeyMaterial";
+            prf = P_NONE;
+        }
+
+        String prfHashAlg = prf.getPRFHashAlg();
+        int prfHashLength = prf.getPRFHashLength();
+        int prfBlockSize = prf.getPRFBlockSize();
+
+        TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec(
+            masterKey, protocolVersion.major, protocolVersion.minor,
             clnt_random.random_bytes, svr_random.random_bytes,
             cipher.algorithm, cipher.keySize, expandedKeySize,
-            cipher.ivSize, hashSize);
+            cipher.ivSize, hashSize,
+            prfHashAlg, prfHashLength, prfBlockSize);
 
         try {
-            KeyGenerator kg = JsseJce.getKeyGenerator("SunTlsKeyMaterial");
+            KeyGenerator kg = JsseJce.getKeyGenerator(keyMaterialAlg);
             kg.init(spec);
             TlsKeyMaterialSpec keySpec = (TlsKeyMaterialSpec)kg.generateKey();
 
--- a/src/share/classes/sun/security/ssl/HelloExtensions.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/HelloExtensions.java	Mon Nov 01 22:02:35 2010 -0700
@@ -50,7 +50,8 @@
  *
  *  . UnknownExtension: used to represent all parsed extensions that we do not
  *      explicitly support.
- *  . ServerNameExtension: partially implemented server_name extension.
+ *  . ServerNameExtension: the server_name extension.
+ *  . SignatureAlgorithmsExtension: the signature_algorithms extension.
  *  . SupportedEllipticCurvesExtension: the ECC supported curves extension.
  *  . SupportedEllipticPointFormatsExtension: the ECC supported point formats
  *      (compressed/uncompressed) extension.
@@ -78,6 +79,8 @@
             HelloExtension extension;
             if (extType == ExtensionType.EXT_SERVER_NAME) {
                 extension = new ServerNameExtension(s, extlen);
+            } else if (extType == ExtensionType.EXT_SIGNATURE_ALGORITHMS) {
+                extension = new SignatureAlgorithmsExtension(s, extlen);
             } else if (extType == ExtensionType.EXT_ELLIPTIC_CURVES) {
                 extension = new SupportedEllipticCurvesExtension(s, extlen);
             } else if (extType == ExtensionType.EXT_EC_POINT_FORMATS) {
@@ -266,31 +269,102 @@
     }
 
     public String toString() {
-        return "Unsupported extension " + type + ", data: " + Debug.toString(data);
+        return "Unsupported extension " + type + ", data: " +
+            Debug.toString(data);
     }
 }
 
 /*
- * Support for the server_name extension is incomplete. Parsing is implemented
- * so that we get nicer debug output, but we neither send it nor do we do
- * act on it if we receive it.
+ * [RFC4366] To facilitate secure connections to servers that host multiple
+ * 'virtual' servers at a single underlying network address, clients MAY
+ * include an extension of type "server_name" in the (extended) client hello.
+ * The "extension_data" field of this extension SHALL contain "ServerNameList"
+ * where:
+ *
+ *     struct {
+ *         NameType name_type;
+ *         select (name_type) {
+ *             case host_name: HostName;
+ *         } name;
+ *     } ServerName;
+ *
+ *     enum {
+ *         host_name(0), (255)
+ *     } NameType;
+ *
+ *     opaque HostName<1..2^16-1>;
+ *
+ *     struct {
+ *         ServerName server_name_list<1..2^16-1>
+ *     } ServerNameList;
  */
 final class ServerNameExtension extends HelloExtension {
 
     final static int NAME_HOST_NAME = 0;
 
     private List<ServerName> names;
+    private int listLength;     // ServerNameList length
+
+    ServerNameExtension(List<String> hostnames) throws IOException {
+        super(ExtensionType.EXT_SERVER_NAME);
+
+        listLength = 0;
+        names = new ArrayList<ServerName>(hostnames.size());
+        for (String hostname : hostnames) {
+            if (hostname != null && hostname.length() != 0) {
+                // we only support DNS hostname now.
+                ServerName serverName =
+                        new ServerName(NAME_HOST_NAME, hostname);
+                names.add(serverName);
+                listLength += serverName.length;
+            }
+        }
+
+        // As we only support DNS hostname now, the hostname list must
+        // not contain more than one hostname
+        if (names.size() > 1) {
+            throw new SSLProtocolException(
+                    "The ServerNameList MUST NOT contain more than " +
+                    "one name of the same name_type");
+        }
+
+        // We only need to add "server_name" extension in ClientHello unless
+        // we support SNI in server side in the future. It is possible that
+        // the SNI is empty in ServerHello. As we don't support SNI in
+        // ServerHello now, we will throw exception for empty list for now.
+        if (listLength == 0) {
+            throw new SSLProtocolException(
+                    "The ServerNameList cannot be empty");
+        }
+    }
 
     ServerNameExtension(HandshakeInStream s, int len)
             throws IOException {
         super(ExtensionType.EXT_SERVER_NAME);
-        names = new ArrayList<ServerName>();
-        while (len > 0) {
-            ServerName name = new ServerName(s);
-            names.add(name);
-            len -= name.length + 2;
+
+        int remains = len;
+        if (len >= 2) {    // "server_name" extension in ClientHello
+            listLength = s.getInt16();     // ServerNameList length
+            if (listLength == 0 || listLength + 2 != len) {
+                throw new SSLProtocolException(
+                        "Invalid " + type + " extension");
+            }
+
+            remains -= 2;
+            names = new ArrayList<ServerName>();
+            while (remains > 0) {
+                ServerName name = new ServerName(s);
+                names.add(name);
+                remains -= name.length;
+
+                // we may need to check the duplicated ServerName type
+            }
+        } else if (len == 0) {     // "server_name" extension in ServerHello
+            listLength = 0;
+            names = Collections.<ServerName>emptyList();
         }
-        if (len != 0) {
+
+        if (remains != 0) {
             throw new SSLProtocolException("Invalid server_name extension");
         }
     }
@@ -301,10 +375,19 @@
         final byte[] data;
         final String hostname;
 
+        ServerName(int type, String hostname) throws IOException {
+            this.type = type;                       // NameType
+            this.hostname = hostname;
+            this.data = hostname.getBytes("UTF8");  // HostName
+            this.length = data.length + 3;          // NameType: 1 byte
+                                                    // HostName length: 2 bytes
+        }
+
         ServerName(HandshakeInStream s) throws IOException {
-            length = s.getInt16();      // ServerNameList length
             type = s.getInt8();         // NameType
             data = s.getBytes16();      // HostName (length read in getBytes16)
+            length = data.length + 3;   // NameType: 1 byte
+                                        // HostName length: 2 bytes
             if (type == NAME_HOST_NAME) {
                 hostname = new String(data, "UTF8");
             } else {
@@ -322,15 +405,29 @@
     }
 
     int length() {
-        throw new RuntimeException("not yet supported");
+        return listLength == 0 ? 4 : 6 + listLength;
     }
 
     void send(HandshakeOutStream s) throws IOException {
-        throw new RuntimeException("not yet supported");
+        s.putInt16(type.id);
+        s.putInt16(listLength + 2);
+        if (listLength != 0) {
+            s.putInt16(listLength);
+
+            for (ServerName name : names) {
+                s.putInt8(name.type);           // NameType
+                s.putBytes16(name.data);        // HostName
+            }
+        }
     }
 
     public String toString() {
-        return "Unsupported extension " + type + ", " + names.toString();
+        StringBuffer buffer = new StringBuffer();
+        for (ServerName name : names) {
+            buffer.append("[" + name + "]");
+        }
+
+        return "Extension " + type + ", server_name: " + buffer;
     }
 }
 
@@ -523,7 +620,8 @@
     final static int FMT_ANSIX962_COMPRESSED_CHAR2 = 2;
 
     static final HelloExtension DEFAULT =
-        new SupportedEllipticPointFormatsExtension(new byte[] {FMT_UNCOMPRESSED});
+        new SupportedEllipticPointFormatsExtension(
+            new byte[] {FMT_UNCOMPRESSED});
 
     private final byte[] formats;
 
@@ -665,3 +763,105 @@
     }
 
 }
+
+/*
+ * [RFC5246] The client uses the "signature_algorithms" extension to
+ * indicate to the server which signature/hash algorithm pairs may be
+ * used in digital signatures.  The "extension_data" field of this
+ * extension contains a "supported_signature_algorithms" value.
+ *
+ *     enum {
+ *         none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
+ *         sha512(6), (255)
+ *     } HashAlgorithm;
+ *
+ *     enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) }
+ *       SignatureAlgorithm;
+ *
+ *     struct {
+ *           HashAlgorithm hash;
+ *           SignatureAlgorithm signature;
+ *     } SignatureAndHashAlgorithm;
+ *
+ *     SignatureAndHashAlgorithm
+ *       supported_signature_algorithms<2..2^16-2>;
+ */
+final class SignatureAlgorithmsExtension extends HelloExtension {
+
+    private Collection<SignatureAndHashAlgorithm> algorithms;
+    private int algorithmsLen;  // length of supported_signature_algorithms
+
+    SignatureAlgorithmsExtension(
+            Collection<SignatureAndHashAlgorithm> signAlgs) {
+
+        super(ExtensionType.EXT_SIGNATURE_ALGORITHMS);
+
+        algorithms = new ArrayList<SignatureAndHashAlgorithm>(signAlgs);
+        algorithmsLen =
+            SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size();
+    }
+
+    SignatureAlgorithmsExtension(HandshakeInStream s, int len)
+                throws IOException {
+        super(ExtensionType.EXT_SIGNATURE_ALGORITHMS);
+
+        algorithmsLen = s.getInt16();
+        if (algorithmsLen == 0 || algorithmsLen + 2 != len) {
+            throw new SSLProtocolException("Invalid " + type + " extension");
+        }
+
+        algorithms = new ArrayList<SignatureAndHashAlgorithm>();
+        int remains = algorithmsLen;
+        int sequence = 0;
+        while (remains > 1) {   // needs at least two bytes
+            int hash = s.getInt8();         // hash algorithm
+            int signature = s.getInt8();    // signature algorithm
+
+            SignatureAndHashAlgorithm algorithm =
+                SignatureAndHashAlgorithm.valueOf(hash, signature, ++sequence);
+            algorithms.add(algorithm);
+            remains -= 2;  // one byte for hash, one byte for signature
+        }
+
+        if (remains != 0) {
+            throw new SSLProtocolException("Invalid server_name extension");
+        }
+    }
+
+    Collection<SignatureAndHashAlgorithm> getSignAlgorithms() {
+        return algorithms;
+    }
+
+    @Override
+    int length() {
+        return 6 + algorithmsLen;
+    }
+
+    @Override
+    void send(HandshakeOutStream s) throws IOException {
+        s.putInt16(type.id);
+        s.putInt16(algorithmsLen + 2);
+        s.putInt16(algorithmsLen);
+
+        for (SignatureAndHashAlgorithm algorithm : algorithms) {
+            s.putInt8(algorithm.getHashValue());      // HashAlgorithm
+            s.putInt8(algorithm.getSignatureValue()); // SignatureAlgorithm
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+        boolean opened = false;
+        for (SignatureAndHashAlgorithm signAlg : algorithms) {
+            if (opened) {
+                buffer.append(", " + signAlg.getAlgorithmName());
+            } else {
+                buffer.append(signAlg.getAlgorithmName());
+                opened = true;
+            }
+        }
+
+        return "Extension " + type + ", signature_algorithms: " + buffer;
+    }
+}
--- a/src/share/classes/sun/security/ssl/MAC.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/MAC.java	Mon Nov 01 22:02:35 2010 -0700
@@ -105,6 +105,10 @@
             algorithm = tls ? "HmacMD5" : "SslMacMD5";
         } else if (macAlg == M_SHA) {
             algorithm = tls ? "HmacSHA1" : "SslMacSHA1";
+        } else if (macAlg == M_SHA256) {
+            algorithm = "HmacSHA256";    // TLS 1.2+
+        } else if (macAlg == M_SHA384) {
+            algorithm = "HmacSHA384";    // TLS 1.2+
         } else {
             throw new RuntimeException("Unknown Mac " + macAlg);
         }
@@ -204,7 +208,8 @@
      * Compute based on either buffer type, either bb.position/limit
      * or buf/offset/len.
      */
-    private byte[] compute(byte type, ByteBuffer bb, byte[] buf, int offset, int len) {
+    private byte[] compute(byte type, ByteBuffer bb, byte[] buf,
+            int offset, int len) {
 
         if (macSize == 0) {
             return nullMAC;
--- a/src/share/classes/sun/security/ssl/ProtocolList.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/ProtocolList.java	Mon Nov 01 22:02:35 2010 -0700
@@ -181,7 +181,8 @@
         if (SunJSSE.isFIPS()) {
             SUPPORTED = new ProtocolList(new String[] {
                 ProtocolVersion.TLS10.name,
-                ProtocolVersion.TLS11.name
+                ProtocolVersion.TLS11.name,
+                ProtocolVersion.TLS12.name
             });
 
             SERVER_DEFAULT = SUPPORTED;
@@ -193,10 +194,21 @@
                 ProtocolVersion.SSL20Hello.name,
                 ProtocolVersion.SSL30.name,
                 ProtocolVersion.TLS10.name,
-                ProtocolVersion.TLS11.name
+                ProtocolVersion.TLS11.name,
+                ProtocolVersion.TLS12.name
             });
 
             SERVER_DEFAULT = SUPPORTED;
+
+            /*
+             * RFC 5246 says that sending SSLv2 backward-compatible
+             * hello SHOULD NOT be done any longer.
+             *
+             * We are not enabling TLS 1.1/1.2 by default yet on clients
+             * out of concern for interop with existing
+             * SSLv3/TLS1.0-only servers.  When these versions of TLS
+             * gain more traction, we'll enable them.
+             */
             CLIENT_DEFAULT = new ProtocolList(new String[] {
                 ProtocolVersion.SSL30.name,
                 ProtocolVersion.TLS10.name
--- a/src/share/classes/sun/security/ssl/ProtocolVersion.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/ProtocolVersion.java	Mon Nov 01 22:02:35 2010 -0700
@@ -50,6 +50,9 @@
     // The limit of maximum protocol version
     final static int LIMIT_MAX_VALUE = 0xFFFF;
 
+    // The limit of minimum protocol version
+    final static int LIMIT_MIN_VALUE = 0x0000;
+
     // Dummy protocol version value for invalid SSLSession
     final static ProtocolVersion NONE = new ProtocolVersion(-1, "NONE");
 
@@ -74,8 +77,8 @@
     // minimum version we implement (SSL 3.0)
     final static ProtocolVersion MIN = FIPS ? TLS10 : SSL30;
 
-    // maximum version we implement (TLS 1.1)
-    final static ProtocolVersion MAX = TLS11;
+    // maximum version we implement (TLS 1.2)
+    final static ProtocolVersion MAX = TLS12;
 
     // ProtocolVersion to use by default (TLS 1.0)
     final static ProtocolVersion DEFAULT = TLS10;
--- a/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java	Mon Nov 01 22:02:35 2010 -0700
@@ -100,8 +100,9 @@
         }
 
         try {
-            KeyGenerator kg =
-                        JsseJce.getKeyGenerator("SunTlsRsaPremasterSecret");
+            String s = ((protocolVersion.v >= ProtocolVersion.TLS12.v) ?
+                "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret");
+            KeyGenerator kg = JsseJce.getKeyGenerator(s);
             kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor));
             preMaster = kg.generateKey();
 
@@ -242,8 +243,9 @@
     // generate a premaster secret with the specified version number
     static SecretKey generateDummySecret(ProtocolVersion version) {
         try {
-            KeyGenerator kg =
-                    JsseJce.getKeyGenerator("SunTlsRsaPremasterSecret");
+            String s = ((version.v >= ProtocolVersion.TLS12.v) ?
+                "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret");
+            KeyGenerator kg = JsseJce.getKeyGenerator(s);
             kg.init(new TlsRsaPremasterSecretParameterSpec
                     (version.major, version.minor));
             return kg.generateKey();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java	Mon Nov 01 22:02:35 2010 -0700
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.security.AlgorithmConstraints;
+import java.security.CryptoPrimitive;
+import java.security.AlgorithmParameters;
+
+import javax.net.ssl.*;
+
+import java.security.Key;
+
+import java.util.Set;
+import java.util.HashSet;
+
+import sun.security.util.DisabledAlgorithmConstraints;
+import sun.security.ssl.CipherSuite.*;
+
+/**
+ * Algorithm constraints for disabled algorithms property
+ *
+ * See the "jdk.certpath.disabledAlgorithms" specification in java.security
+ * for the syntax of the disabled algorithm string.
+ */
+final class SSLAlgorithmConstraints implements AlgorithmConstraints {
+    private final static AlgorithmConstraints tlsDisabledAlgConstraints =
+            new TLSDisabledAlgConstraints();
+    private final static AlgorithmConstraints x509DisabledAlgConstraints =
+            new X509DisabledAlgConstraints();
+    private AlgorithmConstraints userAlgConstraints = null;
+    private AlgorithmConstraints peerAlgConstraints = null;
+
+    private boolean enabledX509DisabledAlgConstraints = true;
+
+    SSLAlgorithmConstraints(AlgorithmConstraints algorithmConstraints) {
+        userAlgConstraints = algorithmConstraints;
+    }
+
+    SSLAlgorithmConstraints(SSLSocket socket,
+            boolean withDefaultCertPathConstraints) {
+        if (socket != null) {
+            userAlgConstraints =
+                socket.getSSLParameters().getAlgorithmConstraints();
+        }
+
+        if (!withDefaultCertPathConstraints) {
+            enabledX509DisabledAlgConstraints = false;
+        }
+    }
+
+    SSLAlgorithmConstraints(SSLEngine engine,
+            boolean withDefaultCertPathConstraints) {
+        if (engine != null) {
+            userAlgConstraints =
+                engine.getSSLParameters().getAlgorithmConstraints();
+        }
+
+        if (!withDefaultCertPathConstraints) {
+            enabledX509DisabledAlgConstraints = false;
+        }
+    }
+
+    SSLAlgorithmConstraints(SSLSocket socket, String[] supportedAlgorithms,
+            boolean withDefaultCertPathConstraints) {
+        if (socket != null) {
+            userAlgConstraints =
+                socket.getSSLParameters().getAlgorithmConstraints();
+            peerAlgConstraints =
+                new SupportedSignatureAlgorithmConstraints(supportedAlgorithms);
+        }
+
+        if (!withDefaultCertPathConstraints) {
+            enabledX509DisabledAlgConstraints = false;
+        }
+    }
+
+    SSLAlgorithmConstraints(SSLEngine engine, String[] supportedAlgorithms,
+            boolean withDefaultCertPathConstraints) {
+        if (engine != null) {
+            userAlgConstraints =
+                engine.getSSLParameters().getAlgorithmConstraints();
+            peerAlgConstraints =
+                new SupportedSignatureAlgorithmConstraints(supportedAlgorithms);
+        }
+
+        if (!withDefaultCertPathConstraints) {
+            enabledX509DisabledAlgConstraints = false;
+        }
+    }
+
+    public boolean permits(Set<CryptoPrimitive> primitives,
+            String algorithm, AlgorithmParameters parameters) {
+
+        boolean permitted = true;
+
+        if (peerAlgConstraints != null) {
+            permitted = peerAlgConstraints.permits(
+                                    primitives, algorithm, parameters);
+        }
+
+        if (permitted && userAlgConstraints != null) {
+            permitted = userAlgConstraints.permits(
+                                    primitives, algorithm, parameters);
+        }
+
+        if (permitted) {
+            permitted = tlsDisabledAlgConstraints.permits(
+                                    primitives, algorithm, parameters);
+        }
+
+        if (permitted && enabledX509DisabledAlgConstraints) {
+            permitted = x509DisabledAlgConstraints.permits(
+                                    primitives, algorithm, parameters);
+        }
+
+        return permitted;
+    }
+
+    public boolean permits(Set<CryptoPrimitive> primitives, Key key) {
+
+        boolean permitted = true;
+
+        if (peerAlgConstraints != null) {
+            permitted = peerAlgConstraints.permits(primitives, key);
+        }
+
+        if (permitted && userAlgConstraints != null) {
+            permitted = userAlgConstraints.permits(primitives, key);
+        }
+
+        if (permitted) {
+            permitted = tlsDisabledAlgConstraints.permits(primitives, key);
+        }
+
+        if (permitted && enabledX509DisabledAlgConstraints) {
+            permitted = x509DisabledAlgConstraints.permits(primitives, key);
+        }
+
+        return permitted;
+    }
+
+    public boolean permits(Set<CryptoPrimitive> primitives,
+            String algorithm, Key key, AlgorithmParameters parameters) {
+
+        boolean permitted = true;
+
+        if (peerAlgConstraints != null) {
+            permitted = peerAlgConstraints.permits(
+                                    primitives, algorithm, key, parameters);
+        }
+
+        if (permitted && userAlgConstraints != null) {
+            permitted = userAlgConstraints.permits(
+                                    primitives, algorithm, key, parameters);
+        }
+
+        if (permitted) {
+            permitted = tlsDisabledAlgConstraints.permits(
+                                    primitives, algorithm, key, parameters);
+        }
+
+        if (permitted && enabledX509DisabledAlgConstraints) {
+            permitted = x509DisabledAlgConstraints.permits(
+                                    primitives, algorithm, key, parameters);
+        }
+
+        return permitted;
+    }
+
+
+    static private class SupportedSignatureAlgorithmConstraints
+                                    implements AlgorithmConstraints {
+        // supported signature algorithms
+        private String[] supportedAlgorithms;
+
+        SupportedSignatureAlgorithmConstraints(String[] supportedAlgorithms) {
+            if (supportedAlgorithms != null) {
+                this.supportedAlgorithms = supportedAlgorithms.clone();
+            } else {
+                this.supportedAlgorithms = null;
+            }
+        }
+
+        public boolean permits(Set<CryptoPrimitive> primitives,
+                String algorithm, AlgorithmParameters parameters) {
+
+            if (algorithm == null || algorithm.length() == 0) {
+                throw new IllegalArgumentException(
+                        "No algorithm name specified");
+            }
+
+            if (primitives == null || primitives.isEmpty()) {
+                throw new IllegalArgumentException(
+                        "No cryptographic primitive specified");
+            }
+
+            if (supportedAlgorithms == null ||
+                        supportedAlgorithms.length == 0) {
+                return false;
+            }
+
+            // trim the MGF part: <digest>with<encryption>and<mgf>
+            int position = algorithm.indexOf("and");
+            if (position > 0) {
+                algorithm = algorithm.substring(0, position);
+            }
+
+            for (String supportedAlgorithm : supportedAlgorithms) {
+                if (algorithm.equalsIgnoreCase(supportedAlgorithm)) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        final public boolean permits(Set<CryptoPrimitive> primitives, Key key) {
+            return true;
+        }
+
+        final public boolean permits(Set<CryptoPrimitive> primitives,
+                String algorithm, Key key, AlgorithmParameters parameters) {
+
+            if (algorithm == null || algorithm.length() == 0) {
+                throw new IllegalArgumentException(
+                        "No algorithm name specified");
+            }
+
+            return permits(primitives, algorithm, parameters);
+        }
+    }
+
+    static private class BasicDisabledAlgConstraints
+            extends DisabledAlgorithmConstraints {
+        BasicDisabledAlgConstraints(String propertyName) {
+            super(propertyName);
+        }
+
+        protected Set<String> decomposes(KeyExchange keyExchange,
+                        boolean forCertPathOnly) {
+            Set<String> components = new HashSet<String>();
+            switch (keyExchange) {
+                case K_NULL:
+                    if (!forCertPathOnly) {
+                        components.add("NULL");
+                    }
+                    break;
+                case K_RSA:
+                    components.add("RSA");
+                    break;
+                case K_RSA_EXPORT:
+                    components.add("RSA");
+                    components.add("RSA_EXPORT");
+                    break;
+                case K_DH_RSA:
+                    components.add("RSA");
+                    components.add("DH");
+                    components.add("DiffieHellman");
+                    components.add("DH_RSA");
+                    break;
+                case K_DH_DSS:
+                    components.add("DSA");
+                    components.add("DSS");
+                    components.add("DH");
+                    components.add("DiffieHellman");
+                    components.add("DH_DSS");
+                    break;
+                case K_DHE_DSS:
+                    components.add("DSA");
+                    components.add("DSS");
+                    components.add("DH");
+                    components.add("DHE");
+                    components.add("DiffieHellman");
+                    components.add("DHE_DSS");
+                    break;
+                case K_DHE_RSA:
+                    components.add("RSA");
+                    components.add("DH");
+                    components.add("DHE");
+                    components.add("DiffieHellman");
+                    components.add("DHE_RSA");
+                    break;
+                case K_DH_ANON:
+                    if (!forCertPathOnly) {
+                        components.add("ANON");
+                        components.add("DH");
+                        components.add("DiffieHellman");
+                        components.add("DH_ANON");
+                    }
+                    break;
+                case K_ECDH_ECDSA:
+                    components.add("ECDH");
+                    components.add("ECDSA");
+                    components.add("ECDH_ECDSA");
+                    break;
+                case K_ECDH_RSA:
+                    components.add("ECDH");
+                    components.add("RSA");
+                    components.add("ECDH_RSA");
+                    break;
+                case K_ECDHE_ECDSA:
+                    components.add("ECDHE");
+                    components.add("ECDSA");
+                    components.add("ECDHE_ECDSA");
+                    break;
+                case K_ECDHE_RSA:
+                    components.add("ECDHE");
+                    components.add("RSA");
+                    components.add("ECDHE_RSA");
+                    break;
+                case K_ECDH_ANON:
+                    if (!forCertPathOnly) {
+                        components.add("ECDH");
+                        components.add("ANON");
+                        components.add("ECDH_ANON");
+                    }
+                    break;
+                case K_KRB5:
+                    if (!forCertPathOnly) {
+                        components.add("KRB5");
+                    }
+                    break;
+                case K_KRB5_EXPORT:
+                    if (!forCertPathOnly) {
+                        components.add("KRB5_EXPORT");
+                    }
+                    break;
+                default:
+                    // ignore
+            }
+
+            return components;
+        }
+
+        protected Set<String> decomposes(BulkCipher bulkCipher) {
+            Set<String> components = new HashSet<String>();
+
+            if (bulkCipher.transformation != null) {
+                components.addAll(super.decomposes(bulkCipher.transformation));
+            }
+
+            return components;
+        }
+
+        protected Set<String> decomposes(MacAlg macAlg) {
+            Set<String> components = new HashSet<String>();
+
+            if (macAlg == CipherSuite.M_MD5) {
+                components.add("MD5");
+                components.add("HmacMD5");
+            } else if (macAlg == CipherSuite.M_SHA) {
+                components.add("SHA1");
+                components.add("SHA-1");
+                components.add("HmacSHA1");
+            } else if (macAlg == CipherSuite.M_SHA256) {
+                components.add("SHA256");
+                components.add("SHA-256");
+                components.add("HmacSHA256");
+            } else if (macAlg == CipherSuite.M_SHA384) {
+                components.add("SHA384");
+                components.add("SHA-384");
+                components.add("HmacSHA384");
+            }
+
+            return components;
+        }
+    }
+
+    static private class TLSDisabledAlgConstraints
+            extends BasicDisabledAlgConstraints {
+
+        TLSDisabledAlgConstraints() {
+            super(DisabledAlgorithmConstraints.PROPERTY_TLS_DISABLED_ALGS);
+        }
+
+        @Override
+        protected Set<String> decomposes(String algorithm) {
+            if (algorithm.startsWith("SSL_") || algorithm.startsWith("TLS_")) {
+                CipherSuite cipherSuite = null;
+                try {
+                    cipherSuite = CipherSuite.valueOf(algorithm);
+                } catch (IllegalArgumentException iae) {
+                    // ignore: unknown or unsupported ciphersuite
+                }
+
+                if (cipherSuite != null) {
+                    Set<String> components = new HashSet<String>();
+
+                    if(cipherSuite.keyExchange != null) {
+                        components.addAll(
+                            decomposes(cipherSuite.keyExchange, false));
+                    }
+
+                    if (cipherSuite.cipher != null) {
+                        components.addAll(decomposes(cipherSuite.cipher));
+                    }
+
+                    if (cipherSuite.macAlg != null) {
+                        components.addAll(decomposes(cipherSuite.macAlg));
+                    }
+
+                    return components;
+                }
+            }
+
+            return super.decomposes(algorithm);
+        }
+    }
+
+    static private class X509DisabledAlgConstraints
+            extends BasicDisabledAlgConstraints {
+
+        X509DisabledAlgConstraints() {
+            super(DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
+        }
+
+        @Override
+        protected Set<String> decomposes(String algorithm) {
+            if (algorithm.startsWith("SSL_") || algorithm.startsWith("TLS_")) {
+                CipherSuite cipherSuite = null;
+                try {
+                    cipherSuite = CipherSuite.valueOf(algorithm);
+                } catch (IllegalArgumentException iae) {
+                    // ignore: unknown or unsupported ciphersuite
+                }
+
+                if (cipherSuite != null) {
+                    Set<String> components = new HashSet<String>();
+
+                    if(cipherSuite.keyExchange != null) {
+                        components.addAll(
+                            decomposes(cipherSuite.keyExchange, true));
+                    }
+
+                    // Certification path algorithm constraints do not apply
+                    // to cipherSuite.cipher and cipherSuite.macAlg.
+
+                    return components;
+                }
+            }
+
+            return super.decomposes(algorithm);
+        }
+    }
+}
+
--- a/src/share/classes/sun/security/ssl/SSLContextImpl.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/SSLContextImpl.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,11 +27,15 @@
 
 import java.net.Socket;
 
+import java.util.*;
 import java.security.*;
 import java.security.cert.*;
+import java.security.cert.Certificate;
 
 import javax.net.ssl.*;
 
+import sun.security.provider.certpath.AlgorithmChecker;
+
 public class SSLContextImpl extends SSLContextSpi {
 
     private static final Debug debug = Debug.getInstance("ssl");
@@ -82,7 +86,8 @@
         if (sr == null) {
             secureRandom = JsseJce.getSecureRandom();
         } else {
-            if (SunJSSE.isFIPS() && (sr.getProvider() != SunJSSE.cryptoProvider)) {
+            if (SunJSSE.isFIPS() &&
+                        (sr.getProvider() != SunJSSE.cryptoProvider)) {
                 throw new KeyManagementException
                     ("FIPS mode: SecureRandom must be from provider "
                     + SunJSSE.cryptoProvider.getName());
@@ -111,11 +116,18 @@
         // We only use the first instance of X509TrustManager passed to us.
         for (int i = 0; tm != null && i < tm.length; i++) {
             if (tm[i] instanceof X509TrustManager) {
-                if (SunJSSE.isFIPS() && !(tm[i] instanceof X509TrustManagerImpl)) {
+                if (SunJSSE.isFIPS() &&
+                        !(tm[i] instanceof X509TrustManagerImpl)) {
                     throw new KeyManagementException
                         ("FIPS mode: only SunJSSE TrustManagers may be used");
                 }
-                return (X509TrustManager)tm[i];
+
+                if (tm[i] instanceof X509ExtendedTrustManager) {
+                    return (X509TrustManager)tm[i];
+                } else {
+                    return new AbstractTrustManagerWrapper(
+                                        (X509TrustManager)tm[i]);
+                }
             }
         }
 
@@ -153,7 +165,7 @@
                     "SSLContext.init():  need an " +
                     "X509ExtendedKeyManager for SSLEngine use");
             }
-            return new AbstractWrapper((X509KeyManager)km);
+            return new AbstractKeyManagerWrapper((X509KeyManager)km);
         }
 
         // nothing found, return a dummy X509ExtendedKeyManager
@@ -217,9 +229,179 @@
 
 }
 
+
+final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager
+            implements X509TrustManager {
+
+    private final X509TrustManager tm;
+
+    AbstractTrustManagerWrapper(X509TrustManager tm) {
+        this.tm = tm;
+    }
+
+    @Override
+    public void checkClientTrusted(X509Certificate[] chain, String authType)
+        throws CertificateException {
+        tm.checkClientTrusted(chain, authType);
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] chain, String authType)
+        throws CertificateException {
+        tm.checkServerTrusted(chain, authType);
+    }
+
+    @Override
+    public X509Certificate[] getAcceptedIssuers() {
+        return tm.getAcceptedIssuers();
+    }
+
+    @Override
+    public void checkClientTrusted(X509Certificate[] chain, String authType,
+                Socket socket) throws CertificateException {
+        tm.checkClientTrusted(chain, authType);
+        checkAdditionalTrust(chain, authType, socket, true);
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] chain, String authType,
+            Socket socket) throws CertificateException {
+        tm.checkServerTrusted(chain, authType);
+        checkAdditionalTrust(chain, authType, socket, false);
+    }
+
+    @Override
+    public void checkClientTrusted(X509Certificate[] chain, String authType,
+            SSLEngine engine) throws CertificateException {
+        tm.checkClientTrusted(chain, authType);
+        checkAdditionalTrust(chain, authType, engine, true);
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] chain, String authType,
+            SSLEngine engine) throws CertificateException {
+        tm.checkServerTrusted(chain, authType);
+        checkAdditionalTrust(chain, authType, engine, false);
+    }
+
+    private void checkAdditionalTrust(X509Certificate[] chain, String authType,
+                Socket socket, boolean isClient) throws CertificateException {
+        if (socket != null && socket.isConnected() &&
+                                    socket instanceof SSLSocket) {
+
+            SSLSocket sslSocket = (SSLSocket)socket;
+            SSLSession session = sslSocket.getHandshakeSession();
+            if (session == null) {
+                throw new CertificateException("No handshake session");
+            }
+
+            // check endpoint identity
+            String identityAlg = sslSocket.getSSLParameters().
+                                        getEndpointIdentificationAlgorithm();
+            if (identityAlg != null && identityAlg.length() != 0) {
+                String hostname = session.getPeerHost();
+                X509TrustManagerImpl.checkIdentity(
+                                    hostname, chain[0], identityAlg);
+            }
+
+            // try the best to check the algorithm constraints
+            ProtocolVersion protocolVersion =
+                ProtocolVersion.valueOf(session.getProtocol());
+            AlgorithmConstraints constraints = null;
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                if (session instanceof ExtendedSSLSession) {
+                    ExtendedSSLSession extSession =
+                                    (ExtendedSSLSession)session;
+                    String[] peerSupportedSignAlgs =
+                            extSession.getLocalSupportedSignatureAlgorithms();
+
+                    constraints = new SSLAlgorithmConstraints(
+                                    sslSocket, peerSupportedSignAlgs, true);
+                } else {
+                    constraints =
+                            new SSLAlgorithmConstraints(sslSocket, true);
+                }
+            } else {
+                constraints = new SSLAlgorithmConstraints(sslSocket, true);
+            }
+
+            AlgorithmChecker checker = new AlgorithmChecker(constraints);
+            try {
+                checker.init(false);
+
+                // a forward checker, need to check from trust to target
+                for (int i = chain.length - 1; i >= 0; i--) {
+                    Certificate cert = chain[i];
+                    // We don't care about the unresolved critical extensions.
+                    checker.check(cert, Collections.<String>emptySet());
+                }
+            } catch (CertPathValidatorException cpve) {
+                throw new CertificateException(
+                    "Certificates does not conform to algorithm constraints");
+            }
+        }
+    }
+
+    private void checkAdditionalTrust(X509Certificate[] chain, String authType,
+            SSLEngine engine, boolean isClient) throws CertificateException {
+        if (engine != null) {
+            SSLSession session = engine.getHandshakeSession();
+            if (session == null) {
+                throw new CertificateException("No handshake session");
+            }
+
+            // check endpoint identity
+            String identityAlg = engine.getSSLParameters().
+                                        getEndpointIdentificationAlgorithm();
+            if (identityAlg != null && identityAlg.length() != 0) {
+                String hostname = session.getPeerHost();
+                X509TrustManagerImpl.checkIdentity(
+                                    hostname, chain[0], identityAlg);
+            }
+
+            // try the best to check the algorithm constraints
+            ProtocolVersion protocolVersion =
+                ProtocolVersion.valueOf(session.getProtocol());
+            AlgorithmConstraints constraints = null;
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                if (session instanceof ExtendedSSLSession) {
+                    ExtendedSSLSession extSession =
+                                    (ExtendedSSLSession)session;
+                    String[] peerSupportedSignAlgs =
+                            extSession.getLocalSupportedSignatureAlgorithms();
+
+                    constraints = new SSLAlgorithmConstraints(
+                                    engine, peerSupportedSignAlgs, true);
+                } else {
+                    constraints =
+                            new SSLAlgorithmConstraints(engine, true);
+                }
+            } else {
+                constraints = new SSLAlgorithmConstraints(engine, true);
+            }
+
+            AlgorithmChecker checker = new AlgorithmChecker(constraints);
+            try {
+                checker.init(false);
+
+                // A forward checker, need to check from trust to target
+                for (int i = chain.length - 1; i >= 0; i--) {
+                    Certificate cert = chain[i];
+                    // We don't care about the unresolved critical extensions.
+                    checker.check(cert, Collections.<String>emptySet());
+                }
+            } catch (CertPathValidatorException cpve) {
+                throw new CertificateException(
+                    "Certificates does not conform to algorithm constraints");
+            }
+        }
+    }
+}
+
 // Dummy X509TrustManager implementation, rejects all peer certificates.
 // Used if the application did not specify a proper X509TrustManager.
-final class DummyX509TrustManager implements X509TrustManager {
+final class DummyX509TrustManager extends X509ExtendedTrustManager
+            implements X509TrustManager {
 
     static final X509TrustManager INSTANCE = new DummyX509TrustManager();
 
@@ -234,6 +416,7 @@
      * validated and is trusted for client SSL authentication.
      * If not, it throws an exception.
      */
+    @Override
     public void checkClientTrusted(X509Certificate[] chain, String authType)
         throws CertificateException {
         throw new CertificateException(
@@ -247,6 +430,7 @@
      * validated and is trusted for server SSL authentication.
      * If not, it throws an exception.
      */
+    @Override
     public void checkServerTrusted(X509Certificate[] chain, String authType)
         throws CertificateException {
         throw new CertificateException(
@@ -257,19 +441,48 @@
      * Return an array of issuer certificates which are trusted
      * for authenticating peers.
      */
+    @Override
     public X509Certificate[] getAcceptedIssuers() {
         return new X509Certificate[0];
     }
+
+    @Override
+    public void checkClientTrusted(X509Certificate[] chain, String authType,
+                Socket socket) throws CertificateException {
+        throw new CertificateException(
+            "No X509TrustManager implementation available");
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] chain, String authType,
+            Socket socket) throws CertificateException {
+        throw new CertificateException(
+            "No X509TrustManager implementation available");
+    }
+
+    @Override
+    public void checkClientTrusted(X509Certificate[] chain, String authType,
+            SSLEngine engine) throws CertificateException {
+        throw new CertificateException(
+            "No X509TrustManager implementation available");
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] chain, String authType,
+            SSLEngine engine) throws CertificateException {
+        throw new CertificateException(
+            "No X509TrustManager implementation available");
+    }
 }
 
 /*
  * A wrapper class to turn a X509KeyManager into an X509ExtendedKeyManager
  */
-final class AbstractWrapper extends X509ExtendedKeyManager {
+final class AbstractKeyManagerWrapper extends X509ExtendedKeyManager {
 
     private final X509KeyManager km;
 
-    AbstractWrapper(X509KeyManager km) {
+    AbstractKeyManagerWrapper(X509KeyManager km) {
         this.km = km;
     }
 
--- a/src/share/classes/sun/security/ssl/SSLEngineImpl.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/SSLEngineImpl.java	Mon Nov 01 22:02:35 2010 -0700
@@ -200,8 +200,10 @@
      * is associated with a session at the same time.  (TLS/IETF may
      * change that to add client authentication w/o new key exchg.)
      */
-    private SSLSessionImpl      sess;
-    private Handshaker          handshaker;
+    private Handshaker                  handshaker;
+    private SSLSessionImpl              sess;
+    private volatile SSLSessionImpl     handshakeSession;
+
 
     /*
      * Client authentication be off, requested, or required.
@@ -248,9 +250,11 @@
     // The cipher suites enabled for use on this connection.
     private CipherSuiteList             enabledCipherSuites;
 
-    // hostname identification algorithm, the hostname identification is
-    // disabled by default.
-    private String                      identificationAlg = null;
+    // the endpoint identification protocol
+    private String                      identificationProtocol = null;
+
+    // The cryptographic algorithm constraints
+    private AlgorithmConstraints        algorithmConstraints = null;
 
     // Have we been told whether we're client or server?
     private boolean                     serverModeSet = false;
@@ -344,6 +348,7 @@
 
         sslContext = ctx;
         sess = SSLSessionImpl.nullSession;
+        handshakeSession = null;
 
         /*
          * State is cs_START until we initialize the handshaker.
@@ -1023,6 +1028,7 @@
                         serverVerifyData = handshaker.getServerVerifyData();
 
                         sess = handshaker.getSession();
+                        handshakeSession = null;
                         if (!writer.hasOutboundData()) {
                             hsStatus = HandshakeStatus.FINISHED;
                         }
@@ -1528,6 +1534,15 @@
         return sess;
     }
 
+    @Override
+    synchronized public SSLSession getHandshakeSession() {
+        return handshakeSession;
+    }
+
+    synchronized void setHandshakeSession(SSLSessionImpl session) {
+        handshakeSession = session;
+    }
+
     /**
      * Returns a delegated <code>Runnable</code> task for
      * this <code>SSLEngine</code>.
@@ -1629,6 +1644,9 @@
         inboundDone = true;
 
         sess.invalidate();
+        if (handshakeSession != null) {
+            handshakeSession.invalidate();
+        }
 
         /*
          * If we haven't even started handshaking yet, no need
@@ -1971,7 +1989,7 @@
     /**
      * Returns the protocols that are supported by this implementation.
      * A subset of the supported protocols may be enabled for this connection
-     * @ returns an array of protocol names.
+     * @return an array of protocol names.
      */
     public String[] getSupportedProtocols() {
         return ProtocolList.getSupported().toStringArray();
@@ -1998,28 +2016,31 @@
     }
 
     /**
-     * Try to configure the endpoint identification algorithm of the engine.
-     *
-     * @param identificationAlgorithm the algorithm used to check the
-     *          endpoint identity.
-     * @return true if the identification algorithm configuration success.
+     * Returns the SSLParameters in effect for this SSLEngine.
      */
-    synchronized public boolean trySetHostnameVerification(
-        String identificationAlgorithm) {
-        if (sslContext.getX509TrustManager() instanceof
-                X509ExtendedTrustManager) {
-            this.identificationAlg = identificationAlgorithm;
-            return true;
-        } else {
-            return false;
-        }
+    synchronized public SSLParameters getSSLParameters() {
+        SSLParameters params = super.getSSLParameters();
+
+        // the super implementation does not handle the following parameters
+        params.setEndpointIdentificationAlgorithm(identificationProtocol);
+        params.setAlgorithmConstraints(algorithmConstraints);
+
+        return params;
     }
 
     /**
-     * Returns the endpoint identification algorithm of the engine.
+     * Applies SSLParameters to this engine.
      */
-    synchronized public String getHostnameVerification() {
-        return identificationAlg;
+    synchronized public void setSSLParameters(SSLParameters params) {
+        super.setSSLParameters(params);
+
+        // the super implementation does not handle the following parameters
+        identificationProtocol = params.getEndpointIdentificationAlgorithm();
+        algorithmConstraints = params.getAlgorithmConstraints();
+        if ((handshaker != null) && !handshaker.started()) {
+            handshaker.setIdentificationProtocol(identificationProtocol);
+            handshaker.setAlgorithmConstraints(algorithmConstraints);
+        }
     }
 
     /**
--- a/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java	Mon Nov 01 22:02:35 2010 -0700
@@ -31,11 +31,14 @@
 import java.net.Socket;
 import java.net.ServerSocket;
 
+import java.security.AlgorithmConstraints;
+
 import java.util.*;
 
 import javax.net.ServerSocketFactory;
 import javax.net.ssl.SSLException;
 import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLParameters;
 
 
 /**
@@ -83,6 +86,12 @@
     /* could enabledCipherSuites ever complete handshaking? */
     private boolean             checkedEnabled = false;
 
+    // the endpoint identification protocol to use by default
+    private String              identificationProtocol = null;
+
+    // The cryptographic algorithm constraints
+    private AlgorithmConstraints    algorithmConstraints = null;
+
     /**
      * Create an SSL server socket on a port, using a non-default
      * authentication context and a specified connection backlog.
@@ -273,6 +282,30 @@
     }
 
     /**
+     * Returns the SSLParameters in effect for newly accepted connections.
+     */
+    synchronized public SSLParameters getSSLParameters() {
+        SSLParameters params = super.getSSLParameters();
+
+        // the super implementation does not handle the following parameters
+        params.setEndpointIdentificationAlgorithm(identificationProtocol);
+        params.setAlgorithmConstraints(algorithmConstraints);
+
+        return params;
+    }
+
+    /**
+     * Applies SSLParameters to newly accepted connections.
+     */
+    synchronized public void setSSLParameters(SSLParameters params) {
+        super.setSSLParameters(params);
+
+        // the super implementation does not handle the following parameters
+        identificationProtocol = params.getEndpointIdentificationAlgorithm();
+        algorithmConstraints = params.getAlgorithmConstraints();
+    }
+
+    /**
      * Accept a new SSL connection.  This server identifies itself with
      * information provided in the authentication context which was
      * presented during construction.
@@ -280,7 +313,7 @@
     public Socket accept() throws IOException {
         SSLSocketImpl s = new SSLSocketImpl(sslContext, useServerMode,
             enabledCipherSuites, doClientAuth, enableSessionCreation,
-            enabledProtocols);
+            enabledProtocols, identificationProtocol, algorithmConstraints);
 
         implAccept(s);
         s.doneConnect();
--- a/src/share/classes/sun/security/ssl/SSLSessionImpl.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/SSLSessionImpl.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,8 @@
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.Vector;
+import java.util.Arrays;
+import java.util.Collection;
 
 import java.security.Principal;
 import java.security.PrivateKey;
@@ -47,6 +49,8 @@
 import javax.net.ssl.SSLPeerUnverifiedException;
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLPermission;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.ExtendedSSLSession;
 
 import javax.security.auth.x500.X500Principal;
 
@@ -71,7 +75,7 @@
  *
  * @author David Brownell
  */
-final class SSLSessionImpl implements SSLSession {
+final class SSLSessionImpl extends ExtendedSSLSession {
 
     /*
      * we only really need a single null session
@@ -89,7 +93,7 @@
     private final SessionId             sessionId;
     private X509Certificate[]   peerCerts;
     private byte                compressionMethod;
-    private final CipherSuite   cipherSuite;
+    private CipherSuite         cipherSuite;
     private SecretKey           masterSecret;
 
     /*
@@ -105,6 +109,8 @@
     private boolean             invalidated;
     private X509Certificate[]   localCerts;
     private PrivateKey          localPrivateKey;
+    private String[]            localSupportedSignAlgs;
+    private String[]            peerSupportedSignAlgs;
 
     // Principals for non-certificate based cipher suites
     private Principal peerPrincipal;
@@ -132,8 +138,8 @@
      * first opened and before handshaking begins.
      */
     private SSLSessionImpl() {
-        this(ProtocolVersion.NONE, CipherSuite.C_NULL,
-             new SessionId(false, null), null, -1);
+        this(ProtocolVersion.NONE, CipherSuite.C_NULL, null,
+            new SessionId(false, null), null, -1);
     }
 
     /*
@@ -142,8 +148,9 @@
      * is intended mostly for use by serves.
      */
     SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite,
+            Collection<SignatureAndHashAlgorithm> algorithms,
             SecureRandom generator, String host, int port) {
-        this(protocolVersion, cipherSuite,
+        this(protocolVersion, cipherSuite, algorithms,
              new SessionId(defaultRejoinable, generator), host, port);
     }
 
@@ -151,6 +158,7 @@
      * Record a new session, using a given cipher spec and session ID.
      */
     SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite,
+            Collection<SignatureAndHashAlgorithm> algorithms,
             SessionId id, String host, int port) {
         this.protocolVersion = protocolVersion;
         sessionId = id;
@@ -161,9 +169,11 @@
         this.host = host;
         this.port = port;
         sessionCount = ++counter;
+        localSupportedSignAlgs =
+            SignatureAndHashAlgorithm.getAlgorithmNames(algorithms);
 
         if (debug != null && Debug.isOn("session")) {
-            System.out.println("%% Created:  " + this);
+            System.out.println("%% Initialized:  " + this);
         }
     }
 
@@ -196,6 +206,12 @@
         localPrivateKey = privateKey;
     }
 
+    void setPeerSupportedSignatureAlgorithms(
+            Collection<SignatureAndHashAlgorithm> algorithms) {
+        peerSupportedSignAlgs =
+            SignatureAndHashAlgorithm.getAlgorithmNames(algorithms);
+    }
+
     /**
      * Set the peer principal.
      */
@@ -293,6 +309,17 @@
     }
 
     /**
+     * Resets the cipher spec in use on this session
+     */
+    void setSuite(CipherSuite suite) {
+       cipherSuite = suite;
+
+       if (debug != null && Debug.isOn("session")) {
+           System.out.println("%% Negotiating:  " + this);
+       }
+    }
+
+    /**
      * Returns the name of the cipher suite in use on this session
      */
     public String getCipherSuite() {
@@ -718,6 +745,30 @@
         return getPacketBufferSize() - Record.headerSize;
     }
 
+    /**
+     * Gets an array of supported signature algorithms that the local side is
+     * willing to verify.
+     */
+    public String[] getLocalSupportedSignatureAlgorithms() {
+        if (localSupportedSignAlgs != null) {
+            return localSupportedSignAlgs.clone();
+        }
+
+        return new String[0];
+    }
+
+    /**
+     * Gets an array of supported signature algorithms that the peer is
+     * able to verify.
+     */
+    public String[] getPeerSupportedSignatureAlgorithms() {
+        if (peerSupportedSignAlgs != null) {
+            return peerSupportedSignAlgs.clone();
+        }
+
+        return new String[0];
+    }
+
     /** Returns a string representation of this SSL session */
     public String toString() {
         return "[Session-" + sessionCount
--- a/src/share/classes/sun/security/ssl/SSLSocketImpl.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/SSLSocketImpl.java	Mon Nov 01 22:02:35 2010 -0700
@@ -32,6 +32,7 @@
 import java.security.AccessController;
 import java.security.AccessControlContext;
 import java.security.PrivilegedAction;
+import java.security.AlgorithmConstraints;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.ReentrantLock;
@@ -199,12 +200,22 @@
     private boolean             autoClose = true;
     private AccessControlContext acc;
 
+    /*
+     * We cannot use the hostname resolved from name services.  For
+     * virtual hosting, multiple hostnames may be bound to the same IP
+     * address, so the hostname resolved from name services is not
+     * reliable.
+     */
+    private String              rawHostname;
+
     // The cipher suites enabled for use on this connection.
     private CipherSuiteList     enabledCipherSuites;
 
-    // hostname identification algorithm, the hostname identification is
-    // disabled by default.
-    private String              identificationAlg = null;
+    // The endpoint identification protocol
+    private String              identificationProtocol = null;
+
+    // The cryptographic algorithm constraints
+    private AlgorithmConstraints    algorithmConstraints = null;
 
     /*
      * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME *
@@ -314,8 +325,9 @@
      * is associated with a session at the same time.  (TLS/IETF may
      * change that to add client authentication w/o new key exchg.)
      */
-    private SSLSessionImpl      sess;
-    private Handshaker          handshaker;
+    private Handshaker                  handshaker;
+    private SSLSessionImpl              sess;
+    private volatile SSLSessionImpl     handshakeSession;
 
 
     /*
@@ -376,6 +388,7 @@
             throws IOException, UnknownHostException {
         super();
         this.host = host;
+        this.rawHostname = host;
         init(context, false);
         SocketAddress socketAddress =
                host != null ? new InetSocketAddress(host, port) :
@@ -418,6 +431,7 @@
             throws IOException, UnknownHostException {
         super();
         this.host = host;
+        this.rawHostname = host;
         init(context, false);
         bind(new InetSocketAddress(localAddr, localPort));
         SocketAddress socketAddress =
@@ -457,11 +471,15 @@
      */
     SSLSocketImpl(SSLContextImpl context, boolean serverMode,
             CipherSuiteList suites, byte clientAuth,
-            boolean sessionCreation, ProtocolList protocols)
-            throws IOException {
+            boolean sessionCreation, ProtocolList protocols,
+            String identificationProtocol,
+            AlgorithmConstraints algorithmConstraints) throws IOException {
+
         super();
         doClientAuth = clientAuth;
         enableSessionCreation = sessionCreation;
+        this.identificationProtocol = identificationProtocol;
+        this.algorithmConstraints = algorithmConstraints;
         init(context, serverMode);
 
         /*
@@ -508,6 +526,7 @@
             throw new SocketException("Underlying socket is not connected");
         }
         this.host = host;
+        this.rawHostname = host;
         init(context, false);
         this.autoClose = autoClose;
         doneConnect();
@@ -519,6 +538,7 @@
     private void init(SSLContextImpl context, boolean isServer) {
         sslContext = context;
         sess = SSLSessionImpl.nullSession;
+        handshakeSession = null;
 
         /*
          * role is as specified, state is START until after
@@ -957,6 +977,7 @@
                         serverVerifyData = handshaker.getServerVerifyData();
 
                         sess = handshaker.getSession();
+                        handshakeSession = null;
                         handshaker = null;
                         connectionState = cs_DATA;
 
@@ -1732,6 +1753,9 @@
             input.r.close();
         }
         sess.invalidate();
+        if (handshakeSession != null) {
+            handshakeSession.invalidate();
+        }
 
         int oldState = connectionState;
         connectionState = cs_ERROR;
@@ -1972,9 +1996,14 @@
         return host;
     }
 
+    synchronized String getRawHostname() {
+        return rawHostname;
+    }
+
     // ONLY used by HttpsClient to setup the URI specified hostname
     synchronized public void setHost(String host) {
         this.host = host;
+        this.rawHostname = host;
     }
 
     /**
@@ -2045,6 +2074,15 @@
         }
     }
 
+    @Override
+    synchronized public SSLSession getHandshakeSession() {
+        return handshakeSession;
+    }
+
+    synchronized void setHandshakeSession(SSLSessionImpl session) {
+        handshakeSession = session;
+    }
+
     /**
      * Controls whether new connections may cause creation of new SSL
      * sessions.
@@ -2230,7 +2268,7 @@
     /**
      * Returns the protocols that are supported by this implementation.
      * A subset of the supported protocols may be enabled for this connection
-     * @ returns an array of protocol names.
+     * @return an array of protocol names.
      */
     public String[] getSupportedProtocols() {
         return ProtocolList.getSupported().toStringArray();
@@ -2306,28 +2344,31 @@
     }
 
     /**
-     * Try to configure the endpoint identification algorithm of the socket.
-     *
-     * @param identificationAlgorithm the algorithm used to check the
-     *        endpoint identity.
-     * @return true if the identification algorithm configuration success.
+     * Returns the SSLParameters in effect for this SSLSocket.
      */
-    synchronized public boolean trySetHostnameVerification(
-        String identificationAlgorithm) {
-        if (sslContext.getX509TrustManager() instanceof
-                X509ExtendedTrustManager) {
-            this.identificationAlg = identificationAlgorithm;
-            return true;
-        } else {
-            return false;
-        }
+    synchronized public SSLParameters getSSLParameters() {
+        SSLParameters params = super.getSSLParameters();
+
+        // the super implementation does not handle the following parameters
+        params.setEndpointIdentificationAlgorithm(identificationProtocol);
+        params.setAlgorithmConstraints(algorithmConstraints);
+
+        return params;
     }
 
     /**
-     * Returns the endpoint identification algorithm of the socket.
+     * Applies SSLParameters to this socket.
      */
-    synchronized public String getHostnameVerification() {
-        return identificationAlg;
+    synchronized public void setSSLParameters(SSLParameters params) {
+        super.setSSLParameters(params);
+
+        // the super implementation does not handle the following parameters
+        identificationProtocol = params.getEndpointIdentificationAlgorithm();
+        algorithmConstraints = params.getAlgorithmConstraints();
+        if ((handshaker != null) && !handshaker.started()) {
+            handshaker.setIdentificationProtocol(identificationProtocol);
+            handshaker.setAlgorithmConstraints(algorithmConstraints);
+        }
     }
 
     //
--- a/src/share/classes/sun/security/ssl/ServerHandshaker.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/ServerHandshaker.java	Mon Nov 01 22:02:35 2010 -0700
@@ -40,10 +40,9 @@
 
 import javax.security.auth.Subject;
 
-import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager;
-
 import sun.security.ssl.HandshakeMessage.*;
 import sun.security.ssl.CipherSuite.*;
+import sun.security.ssl.SignatureAndHashAlgorithm.*;
 import static sun.security.ssl.CipherSuite.*;
 import static sun.security.ssl.CipherSuite.KeyExchange.*;
 
@@ -92,6 +91,9 @@
 
     private SupportedEllipticCurvesExtension supportedCurves;
 
+    // the preferable signature algorithm used by ServerKeyExchange message
+    SignatureAndHashAlgorithm preferableSignatureAlgorithm;
+
     /*
      * Constructor ... use the keys found in the auth context.
      */
@@ -233,11 +235,13 @@
                 break;
 
             case HandshakeMessage.ht_certificate_verify:
-                this.clientCertificateVerify(new CertificateVerify(input));
+                this.clientCertificateVerify(new CertificateVerify(input,
+                            localSupportedSignAlgs, protocolVersion));
                 break;
 
             case HandshakeMessage.ht_finished:
-                this.clientFinished(new Finished(protocolVersion, input));
+                this.clientFinished(
+                    new Finished(protocolVersion, input, cipherSuite));
                 break;
 
             default:
@@ -419,6 +423,9 @@
                 "Client requested protocol " + clientRequestedVersion +
                 " not enabled or not supported");
         }
+
+        handshakeHash.protocolDetermined(
+            selectedVersion.v >= ProtocolVersion.TLS12.v);
         setVersion(selectedVersion);
 
         m1.protocolVersion = protocolVersion;
@@ -562,14 +569,71 @@
             if (!enableNewSession) {
                 throw new SSLException("Client did not resume a session");
             }
+
             supportedCurves = (SupportedEllipticCurvesExtension)
                         mesg.extensions.get(ExtensionType.EXT_ELLIPTIC_CURVES);
+
+            // We only need to handle the "signature_algorithm" extension
+            // for full handshakes and TLS 1.2 or later.
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                SignatureAlgorithmsExtension signAlgs =
+                    (SignatureAlgorithmsExtension)mesg.extensions.get(
+                                    ExtensionType.EXT_SIGNATURE_ALGORITHMS);
+                if (signAlgs != null) {
+                    Collection<SignatureAndHashAlgorithm> peerSignAlgs =
+                                            signAlgs.getSignAlgorithms();
+                    if (peerSignAlgs == null || peerSignAlgs.isEmpty()) {
+                        throw new SSLHandshakeException(
+                            "No peer supported signature algorithms");
+                    }
+
+                    Collection<SignatureAndHashAlgorithm>
+                        supportedPeerSignAlgs =
+                            SignatureAndHashAlgorithm.getSupportedAlgorithms(
+                                                            peerSignAlgs);
+                    if (supportedPeerSignAlgs.isEmpty()) {
+                        throw new SSLHandshakeException(
+                            "No supported signature and hash algorithm " +
+                            "in common");
+                    }
+
+                    setPeerSupportedSignAlgs(supportedPeerSignAlgs);
+                } // else, need to use peer implicit supported signature algs
+            }
+
+            session = new SSLSessionImpl(protocolVersion, CipherSuite.C_NULL,
+                        getLocalSupportedSignAlgs(),
+                        sslContext.getSecureRandom(),
+                        getHostAddressSE(), getPortSE());
+
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                if (peerSupportedSignAlgs != null) {
+                    session.setPeerSupportedSignatureAlgorithms(
+                            peerSupportedSignAlgs);
+                }   // else, we will set the implicit peer supported signature
+                    // algorithms in chooseCipherSuite()
+            }
+
+            // set the handshake session
+            setHandshakeSessionSE(session);
+
+            // choose cipher suite and corresponding private key
             chooseCipherSuite(mesg);
-            session = new SSLSessionImpl(protocolVersion, cipherSuite,
-                sslContext.getSecureRandom(),
-                getHostAddressSE(), getPortSE());
+
+            session.setSuite(cipherSuite);
             session.setLocalPrivateKey(privateKey);
+
             // chooseCompression(mesg);
+        } else {
+            // set the handshake session
+            setHandshakeSessionSE(session);
+        }
+
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (resumingSession) {
+                handshakeHash.setCertificateVerifyAlg(null);
+            }
+            handshakeHash.setFinishedAlg(cipherSuite.prfAlg.getPRFHashAlg());
         }
 
         m1.cipherSuite = cipherSuite;
@@ -689,14 +753,16 @@
                     privateKey,
                     clnt_random.random_bytes,
                     svr_random.random_bytes,
-                    sslContext.getSecureRandom());
+                    sslContext.getSecureRandom(),
+                    preferableSignatureAlgorithm,
+                    protocolVersion);
             } catch (GeneralSecurityException e) {
                 throwSSLException("Error generating DH server key exchange", e);
                 m3 = null; // make compiler happy
             }
             break;
         case K_DH_ANON:
-            m3 = new DH_ServerKeyExchange(dh);
+            m3 = new DH_ServerKeyExchange(dh, protocolVersion);
             break;
         case K_ECDHE_RSA:
         case K_ECDHE_ECDSA:
@@ -706,9 +772,12 @@
                     privateKey,
                     clnt_random.random_bytes,
                     svr_random.random_bytes,
-                    sslContext.getSecureRandom());
+                    sslContext.getSecureRandom(),
+                    preferableSignatureAlgorithm,
+                    protocolVersion);
             } catch (GeneralSecurityException e) {
-                throwSSLException("Error generating ECDH server key exchange", e);
+                throwSSLException(
+                    "Error generating ECDH server key exchange", e);
                 m3 = null; // make compiler happy
             }
             break;
@@ -737,21 +806,48 @@
         // Needed only if server requires client to authenticate self.
         // Illegal for anonymous flavors, so we need to check that.
         //
-        if (keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) {
-            // CertificateRequest is omitted for Kerberos ciphers
+        // CertificateRequest is omitted for Kerberos ciphers
+        if (doClientAuth != SSLEngineImpl.clauth_none &&
+                keyExchange != K_DH_ANON && keyExchange != K_ECDH_ANON &&
+                keyExchange != K_KRB5 && keyExchange != K_KRB5_EXPORT) {
 
-        } else if (doClientAuth != SSLEngineImpl.clauth_none &&
-                keyExchange != K_DH_ANON && keyExchange != K_ECDH_ANON) {
             CertificateRequest m4;
             X509Certificate caCerts[];
 
+            Collection<SignatureAndHashAlgorithm> localSignAlgs = null;
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                // We currently use all local upported signature and hash
+                // algorithms. However, to minimize the computation cost
+                // of requested hash algorithms, we may use a restricted
+                // set of signature algorithms in the future.
+                localSignAlgs = getLocalSupportedSignAlgs();
+                if (localSignAlgs.isEmpty()) {
+                    throw new SSLHandshakeException(
+                            "No supported signature algorithm");
+                }
+
+                Set<String> localHashAlgs =
+                    SignatureAndHashAlgorithm.getHashAlgorithmNames(
+                        localSignAlgs);
+                if (localHashAlgs.isEmpty()) {
+                    throw new SSLHandshakeException(
+                            "No supported signature algorithm");
+                }
+                handshakeHash.restrictCertificateVerifyAlgs(localHashAlgs);
+            }
+
             caCerts = sslContext.getX509TrustManager().getAcceptedIssuers();
-            m4 = new CertificateRequest(caCerts, keyExchange);
+            m4 = new CertificateRequest(caCerts, keyExchange,
+                                            localSignAlgs, protocolVersion);
 
             if (debug != null && Debug.isOn("handshake")) {
                 m4.print(System.out);
             }
             m4.write(output);
+        } else {
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                handshakeHash.setCertificateVerifyAlg(null);
+            }
         }
 
         /*
@@ -826,11 +922,16 @@
             return false;
         }
 
-        // TLSv1.1 must not negotiate the exportable weak cipher suites.
+        // must not negotiate the obsoleted weak cipher suites.
         if (protocolVersion.v >= suite.obsoleted) {
             return false;
         }
 
+        // must not negotiate unsupported cipher suites.
+        if (protocolVersion.v < suite.supported) {
+            return false;
+        }
+
         KeyExchange keyExchange = suite.keyExchange;
 
         // null out any existing references
@@ -840,36 +941,136 @@
         tempPrivateKey = null;
         tempPublicKey = null;
 
+        Collection<SignatureAndHashAlgorithm> supportedSignAlgs = null;
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (peerSupportedSignAlgs != null) {
+                supportedSignAlgs = peerSupportedSignAlgs;
+            } else {
+                SignatureAndHashAlgorithm algorithm = null;
+
+                // we may optimize the performance
+                switch (keyExchange) {
+                    // If the negotiated key exchange algorithm is one of
+                    // (RSA, DHE_RSA, DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA),
+                    // behave as if client had sent the value {sha1,rsa}.
+                    case K_RSA:
+                    case K_DHE_RSA:
+                    case K_DH_RSA:
+                    // case K_RSA_PSK:
+                    case K_ECDH_RSA:
+                    case K_ECDHE_RSA:
+                        algorithm = SignatureAndHashAlgorithm.valueOf(
+                                HashAlgorithm.SHA1.value,
+                                SignatureAlgorithm.RSA.value, 0);
+                        break;
+                    // If the negotiated key exchange algorithm is one of
+                    // (DHE_DSS, DH_DSS), behave as if the client had
+                    // sent the value {sha1,dsa}.
+                    case K_DHE_DSS:
+                    case K_DH_DSS:
+                        algorithm = SignatureAndHashAlgorithm.valueOf(
+                                HashAlgorithm.SHA1.value,
+                                SignatureAlgorithm.DSA.value, 0);
+                        break;
+                    // If the negotiated key exchange algorithm is one of
+                    // (ECDH_ECDSA, ECDHE_ECDSA), behave as if the client
+                    // had sent value {sha1,ecdsa}.
+                    case K_ECDH_ECDSA:
+                    case K_ECDHE_ECDSA:
+                        algorithm = SignatureAndHashAlgorithm.valueOf(
+                                HashAlgorithm.SHA1.value,
+                                SignatureAlgorithm.ECDSA.value, 0);
+                        break;
+                    default:
+                        // no peer supported signature algorithms
+                }
+
+                if (algorithm == null) {
+                    supportedSignAlgs =
+                        Collections.<SignatureAndHashAlgorithm>emptySet();
+                } else {
+                    supportedSignAlgs =
+                        new ArrayList<SignatureAndHashAlgorithm>(1);
+                    supportedSignAlgs.add(algorithm);
+                }
+
+                // Sets the peer supported signature algorithm to use in KM
+                // temporarily.
+                session.setPeerSupportedSignatureAlgorithms(supportedSignAlgs);
+            }
+        }
+
         switch (keyExchange) {
         case K_RSA:
+            // need RSA certs for authentication
+            if (setupPrivateKeyAndChain("RSA") == false) {
+                return false;
+            }
+            break;
         case K_RSA_EXPORT:
-        case K_DHE_RSA:
-        case K_ECDHE_RSA:
             // need RSA certs for authentication
             if (setupPrivateKeyAndChain("RSA") == false) {
                 return false;
             }
 
-            if (keyExchange == K_RSA_EXPORT) {
-                try {
-                   if (JsseJce.getRSAKeyLength(certs[0].getPublicKey()) > 512) {
-                        if (!setupEphemeralRSAKeys(suite.exportable)) {
-                            return false;
-                        }
-                   }
-                } catch (RuntimeException e) {
-                    // could not determine keylength, ignore key
+            try {
+               if (JsseJce.getRSAKeyLength(certs[0].getPublicKey()) > 512) {
+                    if (!setupEphemeralRSAKeys(suite.exportable)) {
+                        return false;
+                    }
+               }
+            } catch (RuntimeException e) {
+                // could not determine keylength, ignore key
+                return false;
+            }
+            break;
+        case K_DHE_RSA:
+            // get preferable peer signature algorithm for server key exchange
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                preferableSignatureAlgorithm =
+                    SignatureAndHashAlgorithm.getPreferableAlgorithm(
+                                                supportedSignAlgs, "RSA");
+                if (preferableSignatureAlgorithm == null) {
                     return false;
                 }
-            } else if (keyExchange == K_DHE_RSA) {
-                setupEphemeralDHKeys(suite.exportable);
-            } else if (keyExchange == K_ECDHE_RSA) {
-                if (setupEphemeralECDHKeys() == false) {
+            }
+
+            // need RSA certs for authentication
+            if (setupPrivateKeyAndChain("RSA") == false) {
+                return false;
+            }
+            setupEphemeralDHKeys(suite.exportable);
+            break;
+        case K_ECDHE_RSA:
+            // get preferable peer signature algorithm for server key exchange
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                preferableSignatureAlgorithm =
+                    SignatureAndHashAlgorithm.getPreferableAlgorithm(
+                                                supportedSignAlgs, "RSA");
+                if (preferableSignatureAlgorithm == null) {
                     return false;
                 }
-            } // else nothing more to do for K_RSA
+            }
+
+            // need RSA certs for authentication
+            if (setupPrivateKeyAndChain("RSA") == false) {
+                return false;
+            }
+            if (setupEphemeralECDHKeys() == false) {
+                return false;
+            }
             break;
         case K_DHE_DSS:
+            // get preferable peer signature algorithm for server key exchange
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                preferableSignatureAlgorithm =
+                    SignatureAndHashAlgorithm.getPreferableAlgorithm(
+                                                supportedSignAlgs, "DSA");
+                if (preferableSignatureAlgorithm == null) {
+                    return false;
+                }
+            }
+
             // need DSS certs for authentication
             if (setupPrivateKeyAndChain("DSA") == false) {
                 return false;
@@ -877,6 +1078,16 @@
             setupEphemeralDHKeys(suite.exportable);
             break;
         case K_ECDHE_ECDSA:
+            // get preferable peer signature algorithm for server key exchange
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                preferableSignatureAlgorithm =
+                    SignatureAndHashAlgorithm.getPreferableAlgorithm(
+                                            supportedSignAlgs, "ECDSA");
+                if (preferableSignatureAlgorithm == null) {
+                    return false;
+                }
+            }
+
             // need EC cert signed using EC
             if (setupPrivateKeyAndChain("EC_EC") == false) {
                 return false;
@@ -921,6 +1132,14 @@
             throw new RuntimeException("Unrecognized cipherSuite: " + suite);
         }
         setCipherSuite(suite);
+
+        // set the peer implicit supported signature algorithms
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (peerSupportedSignAlgs == null) {
+                setPeerSupportedSignAlgs(supportedSignAlgs);
+                // we had alreay update the session
+            }
+        }
         return true;
     }
 
@@ -1170,6 +1389,24 @@
             mesg.print(System.out);
         }
 
+        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            SignatureAndHashAlgorithm signAlg =
+                mesg.getPreferableSignatureAlgorithm();
+            if (signAlg == null) {
+                throw new SSLHandshakeException(
+                        "Illegal CertificateVerify message");
+            }
+
+            String hashAlg =
+                SignatureAndHashAlgorithm.getHashAlgorithmName(signAlg);
+            if (hashAlg == null || hashAlg.length() == 0) {
+                throw new SSLHandshakeException(
+                        "No supported hash algorithm");
+            }
+
+            handshakeHash.setCertificateVerifyAlg(hashAlg);
+        }
+
         try {
             PublicKey publicKey =
                 session.getPeerCertificates()[0].getPublicKey();
@@ -1225,8 +1462,8 @@
          * Verify the client's message with the "before" digest of messages,
          * and forget about continuing to use that digest.
          */
-        boolean verified = mesg.verify(protocolVersion, handshakeHash,
-                                Finished.CLIENT, session.getMasterSecret());
+        boolean verified = mesg.verify(handshakeHash, Finished.CLIENT,
+            session.getMasterSecret());
 
         if (!verified) {
             fatalSE(Alerts.alert_handshake_failure,
@@ -1281,7 +1518,7 @@
         output.flush();
 
         Finished mesg = new Finished(protocolVersion, handshakeHash,
-                                Finished.SERVER, session.getMasterSecret());
+            Finished.SERVER, session.getMasterSecret(), cipherSuite);
 
         /*
          * Send the change_cipher_spec record; then our Finished handshake
@@ -1351,7 +1588,8 @@
      * ServerKeyExchange) message that was sent to it by the server.  That's
      * decrypted using the private key before we get here.
      */
-    private SecretKey clientKeyExchange(RSAClientKeyExchange mesg) throws IOException {
+    private SecretKey clientKeyExchange(RSAClientKeyExchange mesg)
+            throws IOException {
 
         if (debug != null && Debug.isOn("handshake")) {
             mesg.print(System.out);
@@ -1379,6 +1617,11 @@
              * not *REQUIRED*, this is an acceptable condition.)
              */
             if (doClientAuth == SSLEngineImpl.clauth_requested) {
+                // Smart (aka stupid) to forecast that no CertificateVerify
+                // message will be received.
+                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                    handshakeHash.setCertificateVerifyAlg(null);
+                }
                 return;
             } else {
                 fatalSE(Alerts.alert_bad_certificate,
@@ -1405,26 +1648,23 @@
                 authType = "UNKNOWN";
             }
 
-            String identificator = getHostnameVerificationSE();
             if (tm instanceof X509ExtendedTrustManager) {
-                ((X509ExtendedTrustManager)tm).checkClientTrusted(
-                        (peerCerts != null ?
-                            peerCerts.clone() :
-                            null),
+                if (conn != null) {
+                    ((X509ExtendedTrustManager)tm).checkClientTrusted(
+                        peerCerts.clone(),
                         authType,
-                        getHostSE(),
-                        identificator);
+                        conn);
+                } else {
+                    ((X509ExtendedTrustManager)tm).checkClientTrusted(
+                        peerCerts.clone(),
+                        authType,
+                        engine);
+                }
             } else {
-                if (identificator != null) {
-                    throw new RuntimeException(
-                        "trust manager does not support peer identification");
-                }
-
-                tm.checkClientTrusted(
-                    (peerCerts != null ?
-                        peerCerts.clone() :
-                        peerCerts),
-                    authType);
+                // Unlikely to happen, because we have wrapped the old
+                // X509TrustManager with the new X509ExtendedTrustManager.
+                throw new CertificateException(
+                    "Improper X509TrustManager implementation");
             }
         } catch (CertificateException e) {
             // This will throw an exception, so include the original error.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java	Mon Nov 01 22:02:35 2010 -0700
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.security.AlgorithmConstraints;
+import java.security.CryptoPrimitive;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.EnumSet;
+import java.util.TreeMap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.ArrayList;
+
+/**
+ * Signature and hash algorithm.
+ *
+ * [RFC5246] The client uses the "signature_algorithms" extension to
+ * indicate to the server which signature/hash algorithm pairs may be
+ * used in digital signatures.  The "extension_data" field of this
+ * extension contains a "supported_signature_algorithms" value.
+ *
+ *     enum {
+ *         none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
+ *         sha512(6), (255)
+ *     } HashAlgorithm;
+ *
+ *     enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) }
+ *       SignatureAlgorithm;
+ *
+ *     struct {
+ *           HashAlgorithm hash;
+ *           SignatureAlgorithm signature;
+ *     } SignatureAndHashAlgorithm;
+ */
+final class SignatureAndHashAlgorithm {
+
+    // minimum priority for default enabled algorithms
+    final static int SUPPORTED_ALG_PRIORITY_MAX_NUM = 0x00F0;
+
+    // performance optimization
+    private final static Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET =
+                                    EnumSet.of(CryptoPrimitive.SIGNATURE);
+
+    // supported pairs of signature and hash algorithm
+    private final static Map<Integer, SignatureAndHashAlgorithm> supportedMap;
+    private final static Map<Integer, SignatureAndHashAlgorithm> priorityMap;
+
+    // the hash algorithm
+    private HashAlgorithm hash;
+
+    // the signature algorithm
+    private SignatureAlgorithm signature;
+
+    // id in 16 bit MSB format, i.e. 0x0603 for SHA512withECDSA
+    private int id;
+
+    // the standard algorithm name, for example "SHA512withECDSA"
+    private String algorithm;
+
+    // Priority for the preference order. The lower the better.
+    //
+    // If the algorithm is unsupported, its priority should be bigger
+    // than SUPPORTED_ALG_PRIORITY_MAX_NUM.
+    private int priority;
+
+    // constructor for supported algorithm
+    private SignatureAndHashAlgorithm(HashAlgorithm hash,
+            SignatureAlgorithm signature, String algorithm, int priority) {
+        this.hash = hash;
+        this.signature = signature;
+        this.algorithm = algorithm;
+        this.id = ((hash.value & 0xFF) << 8) | (signature.value & 0xFF);
+        this.priority = priority;
+    }
+
+    // constructor for unsupported algorithm
+    private SignatureAndHashAlgorithm(String algorithm, int id, int sequence) {
+        this.hash = HashAlgorithm.valueOf((id >> 8) & 0xFF);
+        this.signature = SignatureAlgorithm.valueOf(id & 0xFF);
+        this.algorithm = algorithm;
+        this.id = id;
+
+        // add one more to the sequece number, in case that the number is zero
+        this.priority = SUPPORTED_ALG_PRIORITY_MAX_NUM + sequence + 1;
+    }
+
+    // Note that we do not use the sequence argument for supported algorithms,
+    // so please don't sort by comparing the objects read from handshake
+    // messages.
+    static SignatureAndHashAlgorithm valueOf(int hash,
+            int signature, int sequence) {
+        hash &= 0xFF;
+        signature &= 0xFF;
+
+        int id = (hash << 8) | signature;
+        SignatureAndHashAlgorithm signAlg = supportedMap.get(id);
+        if (signAlg == null) {
+            // unsupported algorithm
+            signAlg = new SignatureAndHashAlgorithm(
+                "Unknown (hash:0x" + Integer.toString(hash, 16) +
+                ", signature:0x" + Integer.toString(signature, 16) + ")",
+                id, sequence);
+        }
+
+        return signAlg;
+    }
+
+    int getHashValue() {
+        return (id >> 8) & 0xFF;
+    }
+
+    int getSignatureValue() {
+        return id & 0xFF;
+    }
+
+    String getAlgorithmName() {
+        return algorithm;
+    }
+
+    // return the size of a SignatureAndHashAlgorithm structure in TLS record
+    static int sizeInRecord() {
+        return 2;
+    }
+
+    // Get local supported algorithm collection complying to
+    // algorithm constraints
+    static Collection<SignatureAndHashAlgorithm>
+            getSupportedAlgorithms(AlgorithmConstraints constraints) {
+
+        Collection<SignatureAndHashAlgorithm> supported =
+                        new ArrayList<SignatureAndHashAlgorithm>();
+        synchronized (priorityMap) {
+            for (SignatureAndHashAlgorithm sigAlg : priorityMap.values()) {
+                if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM &&
+                        constraints.permits(SIGNATURE_PRIMITIVE_SET,
+                                sigAlg.algorithm, null)) {
+                    supported.add(sigAlg);
+                }
+            }
+        }
+
+        return supported;
+    }
+
+    // Get supported algorithm collection from an untrusted collection
+    static Collection<SignatureAndHashAlgorithm> getSupportedAlgorithms(
+            Collection<SignatureAndHashAlgorithm> algorithms ) {
+        Collection<SignatureAndHashAlgorithm> supported =
+                        new ArrayList<SignatureAndHashAlgorithm>();
+        for (SignatureAndHashAlgorithm sigAlg : algorithms) {
+            if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM) {
+                supported.add(sigAlg);
+            }
+        }
+
+        return supported;
+    }
+
+    static String[] getAlgorithmNames(
+            Collection<SignatureAndHashAlgorithm> algorithms) {
+        ArrayList<String> algorithmNames = new ArrayList<String>();
+        if (algorithms != null) {
+            for (SignatureAndHashAlgorithm sigAlg : algorithms) {
+                algorithmNames.add(sigAlg.algorithm);
+            }
+        }
+
+        String[] array = new String[algorithmNames.size()];
+        return algorithmNames.toArray(array);
+    }
+
+    static Set<String> getHashAlgorithmNames(
+            Collection<SignatureAndHashAlgorithm> algorithms) {
+        Set<String> algorithmNames = new HashSet<String>();
+        if (algorithms != null) {
+            for (SignatureAndHashAlgorithm sigAlg : algorithms) {
+                if (sigAlg.hash.value > 0) {
+                    algorithmNames.add(sigAlg.hash.standardName);
+                }
+            }
+        }
+
+        return algorithmNames;
+    }
+
+    static String getHashAlgorithmName(SignatureAndHashAlgorithm algorithm) {
+        return algorithm.hash.standardName;
+    }
+
+    private static void supports(HashAlgorithm hash,
+            SignatureAlgorithm signature, String algorithm, int priority) {
+
+        SignatureAndHashAlgorithm pair =
+            new SignatureAndHashAlgorithm(hash, signature, algorithm, priority);
+        if (supportedMap.put(pair.id, pair) != null) {
+            throw new RuntimeException(
+                "Duplicate SignatureAndHashAlgorithm definition, id: " +
+                pair.id);
+        }
+        if (priorityMap.put(pair.priority, pair) != null) {
+            throw new RuntimeException(
+                "Duplicate SignatureAndHashAlgorithm definition, priority: " +
+                pair.priority);
+        }
+    }
+
+    static SignatureAndHashAlgorithm getPreferableAlgorithm(
+        Collection<SignatureAndHashAlgorithm> algorithms, String expected) {
+
+        if (expected == null && !algorithms.isEmpty()) {
+            for (SignatureAndHashAlgorithm sigAlg : algorithms) {
+                if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM) {
+                    return sigAlg;
+                }
+            }
+
+            return null;  // no supported algorithm
+        }
+
+
+        for (SignatureAndHashAlgorithm algorithm : algorithms) {
+            int signValue = algorithm.id & 0xFF;
+            if ((expected.equalsIgnoreCase("dsa") &&
+                    signValue == SignatureAlgorithm.DSA.value) ||
+                (expected.equalsIgnoreCase("rsa") &&
+                    signValue == SignatureAlgorithm.RSA.value) ||
+                (expected.equalsIgnoreCase("ecdsa") &&
+                    signValue == SignatureAlgorithm.ECDSA.value) ||
+                (expected.equalsIgnoreCase("ec") &&
+                    signValue == SignatureAlgorithm.ECDSA.value)) {
+                return algorithm;
+            }
+        }
+
+        return null;
+    }
+
+    static enum HashAlgorithm {
+        UNDEFINED("undefined",        "", -1),
+        NONE(          "none",    "NONE",  0),
+        MD5(            "md5",     "MD5",  1),
+        SHA1(          "sha1",   "SHA-1",  2),
+        SHA224(      "sha224", "SHA-224",  3),
+        SHA256(      "sha256", "SHA-256",  4),
+        SHA384(      "sha384", "SHA-384",  5),
+        SHA512(      "sha512", "SHA-512",  6);
+
+        final String name;  // not the standard signature algorithm name
+                            // except the UNDEFINED, other names are defined
+                            // by TLS 1.2 protocol
+        final String standardName; // the standard MessageDigest algorithm name
+        final int value;
+
+        private HashAlgorithm(String name, String standardName, int value) {
+            this.name = name;
+            this.standardName = standardName;
+            this.value = value;
+        }
+
+        static HashAlgorithm valueOf(int value) {
+            HashAlgorithm algorithm = UNDEFINED;
+            switch (value) {
+                case 0:
+                    algorithm = NONE;
+                    break;
+                case 1:
+                    algorithm = MD5;
+                    break;
+                case 2:
+                    algorithm = SHA1;
+                    break;
+                case 3:
+                    algorithm = SHA224;
+                    break;
+                case 4:
+                    algorithm = SHA256;
+                    break;
+                case 5:
+                    algorithm = SHA384;
+                    break;
+                case 6:
+                    algorithm = SHA512;
+                    break;
+            }
+
+            return algorithm;
+        }
+    }
+
+    static enum SignatureAlgorithm {
+        UNDEFINED("undefined", -1),
+        ANONYMOUS("anonymous",  0),
+        RSA(            "rsa",  1),
+        DSA(            "dsa",  2),
+        ECDSA(        "ecdsa",  3);
+
+        final String name;  // not the standard signature algorithm name
+                            // except the UNDEFINED, other names are defined
+                            // by TLS 1.2 protocol
+        final int value;
+
+        private SignatureAlgorithm(String name, int value) {
+            this.name = name;
+            this.value = value;
+        }
+
+        static SignatureAlgorithm valueOf(int value) {
+            SignatureAlgorithm algorithm = UNDEFINED;
+            switch (value) {
+                case 0:
+                    algorithm = ANONYMOUS;
+                    break;
+                case 1:
+                    algorithm = RSA;
+                    break;
+                case 2:
+                    algorithm = DSA;
+                    break;
+                case 3:
+                    algorithm = ECDSA;
+                    break;
+            }
+
+            return algorithm;
+        }
+    }
+
+    static {
+        supportedMap = Collections.synchronizedSortedMap(
+            new TreeMap<Integer, SignatureAndHashAlgorithm>());
+        priorityMap = Collections.synchronizedSortedMap(
+            new TreeMap<Integer, SignatureAndHashAlgorithm>());
+
+        synchronized (supportedMap) {
+            int p = SUPPORTED_ALG_PRIORITY_MAX_NUM;
+            supports(HashAlgorithm.MD5,         SignatureAlgorithm.RSA,
+                    "MD5withRSA",           --p);
+            supports(HashAlgorithm.SHA1,        SignatureAlgorithm.DSA,
+                    "SHA1withDSA",          --p);
+            supports(HashAlgorithm.SHA1,        SignatureAlgorithm.RSA,
+                    "SHA1withRSA",          --p);
+            supports(HashAlgorithm.SHA1,        SignatureAlgorithm.ECDSA,
+                    "SHA1withECDSA",        --p);
+            supports(HashAlgorithm.SHA224,      SignatureAlgorithm.RSA,
+                    "SHA224withRSA",        --p);
+            supports(HashAlgorithm.SHA224,      SignatureAlgorithm.ECDSA,
+                    "SHA224withECDSA",      --p);
+            supports(HashAlgorithm.SHA256,      SignatureAlgorithm.RSA,
+                    "SHA256withRSA",        --p);
+            supports(HashAlgorithm.SHA256,      SignatureAlgorithm.ECDSA,
+                    "SHA256withECDSA",      --p);
+            supports(HashAlgorithm.SHA384,      SignatureAlgorithm.RSA,
+                    "SHA384withRSA",        --p);
+            supports(HashAlgorithm.SHA384,      SignatureAlgorithm.ECDSA,
+                    "SHA384withECDSA",      --p);
+            supports(HashAlgorithm.SHA512,      SignatureAlgorithm.RSA,
+                    "SHA512withRSA",        --p);
+            supports(HashAlgorithm.SHA512,      SignatureAlgorithm.ECDSA,
+                    "SHA512withECDSA",      --p);
+        }
+    }
+}
+
--- a/src/share/classes/sun/security/ssl/SunJSSE.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/SunJSSE.java	Mon Nov 01 22:02:35 2010 -0700
@@ -129,7 +129,8 @@
         return t;
     }
 
-    private SunJSSE(java.security.Provider cryptoProvider, String providerName) {
+    private SunJSSE(java.security.Provider cryptoProvider,
+            String providerName) {
         super("SunJSSE", 1.6d, fipsInfo + providerName + ")");
         subclassCheck();
         if (cryptoProvider == null) {
@@ -213,6 +214,8 @@
             "sun.security.ssl.SSLContextImpl");
         put("SSLContext.TLSv1.1",
             "sun.security.ssl.SSLContextImpl");
+        put("SSLContext.TLSv1.2",
+            "sun.security.ssl.SSLContextImpl");
         put("SSLContext.Default",
             "sun.security.ssl.DefaultSSLContextImpl");
 
--- a/src/share/classes/sun/security/ssl/TrustManagerFactoryImpl.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/TrustManagerFactoryImpl.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
--- a/src/share/classes/sun/security/ssl/X509KeyManagerImpl.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/X509KeyManagerImpl.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,6 +38,8 @@
 
 import javax.net.ssl.*;
 
+import sun.security.provider.certpath.AlgorithmChecker;
+
 /**
  * The new X509 key manager implementation. The main differences to the
  * old SunX509 key manager are:
@@ -111,36 +113,98 @@
 
     public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
             Socket socket) {
-        return chooseAlias(getKeyTypes(keyTypes), issuers, CheckType.CLIENT);
+        return chooseAlias(getKeyTypes(keyTypes), issuers, CheckType.CLIENT,
+                        getAlgorithmConstraints(socket));
     }
 
     public String chooseEngineClientAlias(String[] keyTypes,
             Principal[] issuers, SSLEngine engine) {
-        return chooseAlias(getKeyTypes(keyTypes), issuers, CheckType.CLIENT);
+        return chooseAlias(getKeyTypes(keyTypes), issuers, CheckType.CLIENT,
+                        getAlgorithmConstraints(engine));
     }
 
     public String chooseServerAlias(String keyType,
             Principal[] issuers, Socket socket) {
-        return chooseAlias(getKeyTypes(keyType), issuers, CheckType.SERVER);
+        return chooseAlias(getKeyTypes(keyType), issuers, CheckType.SERVER,
+                        getAlgorithmConstraints(socket));
     }
 
     public String chooseEngineServerAlias(String keyType,
             Principal[] issuers, SSLEngine engine) {
-        return chooseAlias(getKeyTypes(keyType), issuers, CheckType.SERVER);
+        return chooseAlias(getKeyTypes(keyType), issuers, CheckType.SERVER,
+                        getAlgorithmConstraints(engine));
     }
 
     public String[] getClientAliases(String keyType, Principal[] issuers) {
-        return getAliases(keyType, issuers, CheckType.CLIENT);
+        return getAliases(keyType, issuers, CheckType.CLIENT, null);
     }
 
     public String[] getServerAliases(String keyType, Principal[] issuers) {
-        return getAliases(keyType, issuers, CheckType.SERVER);
+        return getAliases(keyType, issuers, CheckType.SERVER, null);
     }
 
     //
     // implementation private methods
     //
 
+    // Gets algorithm constraints of the socket.
+    private AlgorithmConstraints getAlgorithmConstraints(Socket socket) {
+        if (socket != null && socket.isConnected() &&
+                                        socket instanceof SSLSocket) {
+
+            SSLSocket sslSocket = (SSLSocket)socket;
+            SSLSession session = sslSocket.getHandshakeSession();
+
+            if (session != null) {
+                ProtocolVersion protocolVersion =
+                    ProtocolVersion.valueOf(session.getProtocol());
+                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                    String[] peerSupportedSignAlgs = null;
+
+                    if (session instanceof ExtendedSSLSession) {
+                        ExtendedSSLSession extSession =
+                            (ExtendedSSLSession)session;
+                        peerSupportedSignAlgs =
+                            extSession.getPeerSupportedSignatureAlgorithms();
+                    }
+
+                    return new SSLAlgorithmConstraints(
+                        sslSocket, peerSupportedSignAlgs, true);
+                }
+            }
+
+            return new SSLAlgorithmConstraints(sslSocket, true);
+        }
+
+        return new SSLAlgorithmConstraints((SSLSocket)null, true);
+    }
+
+    // Gets algorithm constraints of the engine.
+    private AlgorithmConstraints getAlgorithmConstraints(SSLEngine engine) {
+        if (engine != null) {
+            SSLSession session = engine.getHandshakeSession();
+            if (session != null) {
+                ProtocolVersion protocolVersion =
+                    ProtocolVersion.valueOf(session.getProtocol());
+                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                    String[] peerSupportedSignAlgs = null;
+
+                    if (session instanceof ExtendedSSLSession) {
+                        ExtendedSSLSession extSession =
+                            (ExtendedSSLSession)session;
+                        peerSupportedSignAlgs =
+                            extSession.getPeerSupportedSignatureAlgorithms();
+                    }
+
+                    return new SSLAlgorithmConstraints(
+                        engine, peerSupportedSignAlgs, true);
+                }
+            }
+        }
+
+        return new SSLAlgorithmConstraints(engine, true);
+    }
+
     // we construct the alias we return to JSSE as seen in the code below
     // a unique id is included to allow us to reliably cache entries
     // between the calls to getCertificateChain() and getPrivateKey()
@@ -196,6 +260,13 @@
     private static class KeyType {
 
         final String keyAlgorithm;
+
+        // In TLS 1.2, the signature algorithm  has been obsoleted by the
+        // supported_signature_algorithms, and the certificate type no longer
+        // restricts the algorithm used to sign the certificate.
+        // However, because we don't support certificate type checking other
+        // than rsa_sign, dss_sign and ecdsa_sign, we don't have to check the
+        // protocol version here.
         final String sigKeyAlgorithm;
 
         KeyType(String algorithm) {
@@ -218,7 +289,8 @@
             }
             if (chain.length > 1) {
                 // if possible, check the public key in the issuer cert
-                return sigKeyAlgorithm.equals(chain[1].getPublicKey().getAlgorithm());
+                return sigKeyAlgorithm.equals(
+                        chain[1].getPublicKey().getAlgorithm());
             } else {
                 // Check the signature algorithm of the certificate itself.
                 // Look for the "withRSA" in "SHA1withRSA", etc.
@@ -231,7 +303,8 @@
     }
 
     private static List<KeyType> getKeyTypes(String ... keyTypes) {
-        if ((keyTypes == null) || (keyTypes.length == 0) || (keyTypes[0] == null)) {
+        if ((keyTypes == null) ||
+                (keyTypes.length == 0) || (keyTypes[0] == null)) {
             return null;
         }
         List<KeyType> list = new ArrayList<KeyType>(keyTypes.length);
@@ -254,8 +327,8 @@
      *     with appropriate key usage to certs with the wrong key usage.
      *     return the first one of them.
      */
-    private String chooseAlias(List<KeyType> keyTypeList,
-            Principal[] issuers, CheckType checkType) {
+    private String chooseAlias(List<KeyType> keyTypeList, Principal[] issuers,
+            CheckType checkType, AlgorithmConstraints constraints) {
         if (keyTypeList == null || keyTypeList.size() == 0) {
             return null;
         }
@@ -264,8 +337,8 @@
         List<EntryStatus> allResults = null;
         for (int i = 0, n = builders.size(); i < n; i++) {
             try {
-                List<EntryStatus> results =
-                    getAliases(i, keyTypeList, issuerSet, false, checkType);
+                List<EntryStatus> results = getAliases(i, keyTypeList,
+                                    issuerSet, false, checkType, constraints);
                 if (results != null) {
                     // the results will either be a single perfect match
                     // or 1 or more imperfect matches
@@ -308,7 +381,7 @@
      * The perfect matches will be first in the array.
      */
     public String[] getAliases(String keyType, Principal[] issuers,
-            CheckType checkType) {
+            CheckType checkType, AlgorithmConstraints constraints) {
         if (keyType == null) {
             return null;
         }
@@ -318,8 +391,8 @@
         List<EntryStatus> allResults = null;
         for (int i = 0, n = builders.size(); i < n; i++) {
             try {
-                List<EntryStatus> results =
-                        getAliases(i, keyTypeList, issuerSet, true, checkType);
+                List<EntryStatus> results = getAliases(i, keyTypeList,
+                                    issuerSet, true, checkType, constraints);
                 if (results != null) {
                     if (allResults == null) {
                         allResults = new ArrayList<EntryStatus>();
@@ -438,7 +511,8 @@
             try {
                 // check extended key usage
                 List<String> certEku = cert.getExtendedKeyUsage();
-                if ((certEku != null) && Collections.disjoint(validEku, certEku)) {
+                if ((certEku != null) &&
+                        Collections.disjoint(validEku, certEku)) {
                     // if extension present and it does not contain any of
                     // the valid EKU OIDs, return extension_mismatch
                     return CheckResult.EXTENSION_MISMATCH;
@@ -534,7 +608,8 @@
      */
     private List<EntryStatus> getAliases(int builderIndex,
             List<KeyType> keyTypes, Set<Principal> issuerSet,
-            boolean findAll, CheckType checkType) throws Exception {
+            boolean findAll, CheckType checkType,
+            AlgorithmConstraints constraints) throws Exception {
         Builder builder = builders.get(builderIndex);
         KeyStore ks = builder.getKeyStore();
         List<EntryStatus> results = null;
@@ -552,6 +627,19 @@
                 // must be secret key entry, ignore
                 continue;
             }
+
+            boolean incompatible = false;
+            for (Certificate cert : chain) {
+                if (cert instanceof X509Certificate == false) {
+                    // not an X509Certificate, ignore this alias
+                    incompatible = true;
+                    break;
+                }
+            }
+            if (incompatible) {
+                continue;
+            }
+
             // check keytype
             int keyIndex = -1;
             int j = 0;
@@ -573,10 +661,6 @@
             if (issuerSet != null) {
                 boolean found = false;
                 for (Certificate cert : chain) {
-                    if (cert instanceof X509Certificate == false) {
-                        // not an X509Certificate, ignore this entry
-                        break;
-                    }
                     X509Certificate xcert = (X509Certificate)cert;
                     if (issuerSet.contains(xcert.getIssuerX500Principal())) {
                         found = true;
@@ -591,6 +675,19 @@
                     continue;
                 }
             }
+
+            // check the algorithm constraints
+            if (constraints != null &&
+                    !conformsToAlgorithmConstraints(constraints, chain)) {
+
+                if (useDebug) {
+                    debug.println("Ignoring alias " + alias +
+                            ": certificate list does not conform to " +
+                            "algorithm constraints");
+                }
+                continue;
+            }
+
             if (date == null) {
                 date = new Date();
             }
@@ -616,4 +713,29 @@
         return results;
     }
 
+    private static boolean conformsToAlgorithmConstraints(
+            AlgorithmConstraints constraints, Certificate[] chain) {
+
+        AlgorithmChecker checker = new AlgorithmChecker(constraints);
+        try {
+            checker.init(false);
+        } catch (CertPathValidatorException cpve) {
+            // unlikely to happen
+            return false;
+        }
+
+        // It is a forward checker, so we need to check from trust to target.
+        for (int i = chain.length - 1; i >= 0; i--) {
+            Certificate cert = chain[i];
+            try {
+                // We don't care about the unresolved critical extensions.
+                checker.check(cert, Collections.<String>emptySet());
+            } catch (CertPathValidatorException cpve) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
 }
--- a/src/share/classes/sun/security/ssl/X509TrustManagerImpl.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/src/share/classes/sun/security/ssl/X509TrustManagerImpl.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,14 +26,15 @@
 
 package sun.security.ssl;
 
+import java.net.Socket;
+import javax.net.ssl.SSLSession;
+
 import java.util.*;
 import java.security.*;
 import java.security.cert.*;
 
 import javax.net.ssl.*;
 
-import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager;
-
 import sun.security.validator.*;
 
 import sun.security.util.HostnameChecker;
@@ -41,7 +42,7 @@
 /**
  * This class implements the SunJSSE X.509 trust manager using the internal
  * validator API in J2SE core. The logic in this class is minimal.<p>
- *
+ * <p>
  * This class supports both the Simple validation algorithm from previous
  * JSSE versions and PKIX validation. Currently, it is not possible for the
  * application to specify PKIX parameters other than trust anchors. This will
@@ -50,19 +51,10 @@
  * classes.
  *
  * @author Andreas Sterbenz
- * @author Xuelei Fan
  */
 final class X509TrustManagerImpl extends X509ExtendedTrustManager
         implements X509TrustManager {
 
-    /**
-     * Flag indicating whether to enable revocation check for the PKIX trust
-     * manager. Typically, this will only work if the PKIX implementation
-     * supports CRL distribution points as we do not manually setup CertStores.
-     */
-    private final static boolean checkRevocation =
-        Debug.getBooleanProperty("com.sun.net.ssl.checkRevocation", false);
-
     private final String validatorType;
 
     /**
@@ -103,6 +95,199 @@
         showTrustedCerts();
     }
 
+    @Override
+    public void checkClientTrusted(X509Certificate chain[], String authType)
+            throws CertificateException {
+        checkTrusted(chain, authType, (Socket)null, true);
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate chain[], String authType)
+            throws CertificateException {
+        checkTrusted(chain, authType, (Socket)null, false);
+    }
+
+    @Override
+    public X509Certificate[] getAcceptedIssuers() {
+        X509Certificate[] certsArray = new X509Certificate[trustedCerts.size()];
+        trustedCerts.toArray(certsArray);
+        return certsArray;
+    }
+
+    @Override
+    public void checkClientTrusted(X509Certificate[] chain, String authType,
+                Socket socket) throws CertificateException {
+        checkTrusted(chain, authType, socket, true);
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] chain, String authType,
+            Socket socket) throws CertificateException {
+        checkTrusted(chain, authType, socket, false);
+    }
+
+    @Override
+    public void checkClientTrusted(X509Certificate[] chain, String authType,
+            SSLEngine engine) throws CertificateException {
+        checkTrusted(chain, authType, engine, true);
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] chain, String authType,
+            SSLEngine engine) throws CertificateException {
+        checkTrusted(chain, authType, engine, false);
+    }
+
+    private Validator checkTrustedInit(X509Certificate[] chain,
+                                        String authType, boolean isClient) {
+        if (chain == null || chain.length == 0) {
+            throw new IllegalArgumentException(
+                "null or zero-length certificate chain");
+        }
+
+        if (authType == null || authType.length() == 0) {
+            throw new IllegalArgumentException(
+                "null or zero-length authentication type");
+        }
+
+        Validator v = null;
+        if (isClient) {
+            v = clientValidator;
+            if (v == null) {
+                synchronized (this) {
+                    v = clientValidator;
+                    if (v == null) {
+                        v = getValidator(Validator.VAR_TLS_CLIENT);
+                        clientValidator = v;
+                    }
+                }
+            }
+        } else {
+            // assume double checked locking with a volatile flag works
+            // (guaranteed under the new Tiger memory model)
+            v = serverValidator;
+            if (v == null) {
+                synchronized (this) {
+                    v = serverValidator;
+                    if (v == null) {
+                        v = getValidator(Validator.VAR_TLS_SERVER);
+                        serverValidator = v;
+                    }
+                }
+            }
+        }
+
+        return v;
+    }
+
+
+    private void checkTrusted(X509Certificate[] chain, String authType,
+                Socket socket, boolean isClient) throws CertificateException {
+        Validator v = checkTrustedInit(chain, authType, isClient);
+
+        AlgorithmConstraints constraints = null;
+        if ((socket != null) && socket.isConnected() &&
+                                        (socket instanceof SSLSocket)) {
+
+            SSLSocket sslSocket = (SSLSocket)socket;
+            SSLSession session = sslSocket.getHandshakeSession();
+            if (session == null) {
+                throw new CertificateException("No handshake session");
+            }
+
+            // check endpoint identity
+            String identityAlg = sslSocket.getSSLParameters().
+                                        getEndpointIdentificationAlgorithm();
+            if (identityAlg != null && identityAlg.length() != 0) {
+                String hostname = session.getPeerHost();
+                checkIdentity(hostname, chain[0], identityAlg);
+            }
+
+            // create the algorithm constraints
+            ProtocolVersion protocolVersion =
+                ProtocolVersion.valueOf(session.getProtocol());
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                if (session instanceof ExtendedSSLSession) {
+                    ExtendedSSLSession extSession =
+                                    (ExtendedSSLSession)session;
+                    String[] localSupportedSignAlgs =
+                            extSession.getLocalSupportedSignatureAlgorithms();
+
+                    constraints = new SSLAlgorithmConstraints(
+                                    sslSocket, localSupportedSignAlgs, false);
+                } else {
+                    constraints =
+                            new SSLAlgorithmConstraints(sslSocket, false);
+                }
+            } else {
+                constraints = new SSLAlgorithmConstraints(sslSocket, false);
+            }
+        }
+
+        X509Certificate[] trustedChain = null;
+        if (isClient) {
+            trustedChain = validate(v, chain, constraints, null);
+        } else {
+            trustedChain = validate(v, chain, constraints, authType);
+        }
+        if (debug != null && Debug.isOn("trustmanager")) {
+            System.out.println("Found trusted certificate:");
+            System.out.println(trustedChain[trustedChain.length - 1]);
+        }
+    }
+
+    private void checkTrusted(X509Certificate[] chain, String authType,
+            SSLEngine engine, boolean isClient) throws CertificateException {
+        Validator v = checkTrustedInit(chain, authType, isClient);
+
+        AlgorithmConstraints constraints = null;
+        if (engine != null) {
+            SSLSession session = engine.getHandshakeSession();
+            if (session == null) {
+                throw new CertificateException("No handshake session");
+            }
+
+            // check endpoint identity
+            String identityAlg = engine.getSSLParameters().
+                                        getEndpointIdentificationAlgorithm();
+            if (identityAlg != null && identityAlg.length() != 0) {
+                String hostname = session.getPeerHost();
+                checkIdentity(hostname, chain[0], identityAlg);
+            }
+
+            // create the algorithm constraints
+            ProtocolVersion protocolVersion =
+                ProtocolVersion.valueOf(session.getProtocol());
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                if (session instanceof ExtendedSSLSession) {
+                    ExtendedSSLSession extSession =
+                                    (ExtendedSSLSession)session;
+                    String[] localSupportedSignAlgs =
+                            extSession.getLocalSupportedSignatureAlgorithms();
+
+                    constraints = new SSLAlgorithmConstraints(
+                                    engine, localSupportedSignAlgs, false);
+                } else {
+                    constraints =
+                            new SSLAlgorithmConstraints(engine, false);
+                }
+            } else {
+                constraints = new SSLAlgorithmConstraints(engine, false);
+            }
+        }
+
+        X509Certificate[] trustedChain = null;
+        if (isClient) {
+            trustedChain = validate(v, chain, constraints, null);
+        } else {
+            trustedChain = validate(v, chain, constraints, authType);
+        }
+        if (debug != null && Debug.isOn("trustmanager")) {
+            System.out.println("Found trusted certificate:");
+            System.out.println(trustedChain[trustedChain.length - 1]);
+        }
+    }
+
     private void showTrustedCerts() {
         if (debug != null && Debug.isOn("trustmanager")) {
             for (X509Certificate cert : trustedCerts) {
@@ -127,13 +312,6 @@
         Validator v;
         if (pkixParams == null) {
             v = Validator.getInstance(validatorType, variant, trustedCerts);
-            // if the PKIX validator is created from a KeyStore,
-            // disable revocation checking
-            if (v instanceof PKIXValidator) {
-                PKIXValidator pkixValidator = (PKIXValidator)v;
-                pkixValidator.getParameters().setRevocationEnabled
-                                                            (checkRevocation);
-            }
         } else {
             v = Validator.getInstance(validatorType, variant, pkixParams);
         }
@@ -141,150 +319,35 @@
     }
 
     private static X509Certificate[] validate(Validator v,
-            X509Certificate[] chain, String authType) throws CertificateException {
+            X509Certificate[] chain, AlgorithmConstraints constraints,
+            String authType) throws CertificateException {
         Object o = JsseJce.beginFipsProvider();
         try {
-            return v.validate(chain, null, authType);
+            return v.validate(chain, null, constraints, authType);
         } finally {
             JsseJce.endFipsProvider(o);
         }
     }
 
-    /**
-     * Returns true if the client certificate can be trusted.
+    /*
+     * Identify the peer by its certificate and hostname.
      *
-     * @param chain certificates which establish an identity for the client.
-     *      Chains of arbitrary length are supported, and certificates
-     *      marked internally as trusted will short-circuit signature checks.
-     * @throws IllegalArgumentException if null or zero-length chain
-     *         is passed in for the chain parameter or if null or zero-length
-     *         string is passed in for the authType parameter.
-     * @throws CertificateException if the certificate chain is not trusted
-     *      by this TrustManager.
+     * Lifted from sun.net.www.protocol.https.HttpsClient.
      */
-    public void checkClientTrusted(X509Certificate chain[], String authType)
-            throws CertificateException {
-        if (chain == null || chain.length == 0) {
-            throw new IllegalArgumentException(
-                "null or zero-length certificate chain");
-        }
-        if (authType == null || authType.length() == 0) {
-            throw new IllegalArgumentException(
-                "null or zero-length authentication type");
-        }
-
-        // assume double checked locking with a volatile flag works
-        // (guaranteed under the new Tiger memory model)
-        Validator v = clientValidator;
-        if (v == null) {
-            synchronized (this) {
-                v = clientValidator;
-                if (v == null) {
-                    v = getValidator(Validator.VAR_TLS_CLIENT);
-                    clientValidator = v;
-                }
-            }
-        }
-        X509Certificate[] trustedChain = validate(v, chain, null);
-        if (debug != null && Debug.isOn("trustmanager")) {
-            System.out.println("Found trusted certificate:");
-            System.out.println(trustedChain[trustedChain.length - 1]);
-        }
-    }
-
-    /**
-     * Returns true if the server certifcate can be trusted.
-     *
-     * @param chain certificates which establish an identity for the server.
-     *      Chains of arbitrary length are supported, and certificates
-     *      marked internally as trusted will short-circuit signature checks.
-     * @throws IllegalArgumentException if null or zero-length chain
-     *         is passed in for the chain parameter or if null or zero-length
-     *         string is passed in for the authType parameter.
-     * @throws CertificateException if the certificate chain is not trusted
-     *      by this TrustManager.
-     */
-    public void checkServerTrusted(X509Certificate chain[], String authType)
-            throws CertificateException {
-        if (chain == null || chain.length == 0) {
-            throw new IllegalArgumentException(
-                "null or zero-length certificate chain");
-        }
-        if (authType == null || authType.length() == 0) {
-            throw new IllegalArgumentException(
-                "null or zero-length authentication type");
-        }
-
-        // assume double checked locking with a volatile flag works
-        // (guaranteed under the new Tiger memory model)
-        Validator v = serverValidator;
-        if (v == null) {
-            synchronized (this) {
-                v = serverValidator;
-                if (v == null) {
-                    v = getValidator(Validator.VAR_TLS_SERVER);
-                    serverValidator = v;
-                }
-            }
-        }
-        X509Certificate[] trustedChain = validate(v, chain, authType);
-        if (debug != null && Debug.isOn("trustmanager")) {
-            System.out.println("Found trusted certificate:");
-            System.out.println(trustedChain[trustedChain.length - 1]);
-        }
-    }
-
-    /**
-     * Returns a list of CAs accepted to authenticate entities for the
-     * specified purpose.
-     *
-     * @param purpose activity for which CAs should be trusted
-     * @return list of CAs accepted for authenticating such tasks
-     */
-    public X509Certificate[] getAcceptedIssuers() {
-        X509Certificate[] certsArray = new X509Certificate[trustedCerts.size()];
-        trustedCerts.toArray(certsArray);
-        return certsArray;
-    }
-
-    /**
-     * Given the partial or complete certificate chain provided by the
-     * peer, check its identity and build a certificate path to a trusted
-     * root, return if it can be validated and is trusted for client SSL
-     * authentication based on the authentication type.
-     */
-    public void checkClientTrusted(X509Certificate[] chain, String authType,
-        String hostname, String algorithm) throws CertificateException {
-        checkClientTrusted(chain, authType);
-        checkIdentity(hostname, chain[0], algorithm);
-    }
-
-    /**
-     * Given the partial or complete certificate chain provided by the
-     * peer, check its identity and build a certificate path to a trusted
-     * root, return if it can be validated and is trusted for server SSL
-     * authentication based on the authentication type.
-     */
-    public void checkServerTrusted(X509Certificate[] chain, String authType,
-        String hostname, String algorithm) throws CertificateException {
-        checkServerTrusted(chain, authType);
-        checkIdentity(hostname, chain[0], algorithm);
-    }
-
-    // Identify the peer by its certificate and hostname.
-    private void checkIdentity(String hostname, X509Certificate cert,
-        String algorithm) throws CertificateException {
+    static void checkIdentity(String hostname, X509Certificate cert,
+            String algorithm) throws CertificateException {
         if (algorithm != null && algorithm.length() != 0) {
             // if IPv6 strip off the "[]"
-            if (hostname != null && hostname.startsWith("[") &&
-                hostname.endsWith("]")) {
-                hostname = hostname.substring(1, hostname.length()-1);
+            if ((hostname != null) && hostname.startsWith("[") &&
+                    hostname.endsWith("]")) {
+                hostname = hostname.substring(1, hostname.length() - 1);
             }
 
             if (algorithm.equalsIgnoreCase("HTTPS")) {
                 HostnameChecker.getInstance(HostnameChecker.TYPE_TLS).match(
                         hostname, cert);
-            } else if (algorithm.equalsIgnoreCase("LDAP")) {
+            } else if (algorithm.equalsIgnoreCase("LDAP") ||
+                    algorithm.equalsIgnoreCase("LDAPS")) {
                 HostnameChecker.getInstance(HostnameChecker.TYPE_LDAP).match(
                         hostname, cert);
             } else {
--- a/test/com/sun/crypto/provider/TLS/TestKeyMaterial.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/test/com/sun/crypto/provider/TLS/TestKeyMaterial.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -117,16 +117,23 @@
                 System.out.print(".");
                 n++;
 
-                KeyGenerator kg = KeyGenerator.getInstance("SunTlsKeyMaterial", provider);
-                SecretKey masterKey = new SecretKeySpec(master, "TlsMasterSecret");
-                TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec
-                (masterKey, major, minor, clientRandom, serverRandom, cipherAlgorithm,
-                keyLength, expandedKeyLength, ivLength, macLength);
+                KeyGenerator kg =
+                    KeyGenerator.getInstance("SunTlsKeyMaterial", provider);
+                SecretKey masterKey =
+                    new SecretKeySpec(master, "TlsMasterSecret");
+                TlsKeyMaterialParameterSpec spec =
+                    new TlsKeyMaterialParameterSpec(masterKey, major, minor,
+                        clientRandom, serverRandom, cipherAlgorithm,
+                        keyLength, expandedKeyLength, ivLength, macLength,
+                        null, -1, -1);
 
                 kg.init(spec);
-                TlsKeyMaterialSpec result = (TlsKeyMaterialSpec)kg.generateKey();
-                match(lineNumber, clientCipherBytes, result.getClientCipherKey());
-                match(lineNumber, serverCipherBytes, result.getServerCipherKey());
+                TlsKeyMaterialSpec result =
+                    (TlsKeyMaterialSpec)kg.generateKey();
+                match(lineNumber, clientCipherBytes,
+                    result.getClientCipherKey());
+                match(lineNumber, serverCipherBytes,
+                    result.getServerCipherKey());
                 match(lineNumber, clientIv, result.getClientIv());
                 match(lineNumber, serverIv, result.getServerIv());
                 match(lineNumber, clientMacBytes, result.getClientMacKey());
@@ -144,7 +151,8 @@
         System.out.println("OK: " + n + " tests");
     }
 
-    private static void match(int lineNumber, byte[] out, Object res) throws Exception {
+    private static void match(int lineNumber, byte[] out, Object res)
+            throws Exception {
         if ((out == null) || (res == null)) {
             if (out != res) {
                 throw new Exception("null mismatch line " + lineNumber);
--- a/test/com/sun/crypto/provider/TLS/TestMasterSecret.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/test/com/sun/crypto/provider/TLS/TestMasterSecret.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -97,17 +97,22 @@
                 System.out.print(".");
                 n++;
 
-                KeyGenerator kg = KeyGenerator.getInstance("SunTlsMasterSecret", provider);
-                SecretKey premasterKey = new SecretKeySpec(premaster, algorithm);
-                TlsMasterSecretParameterSpec spec = new TlsMasterSecretParameterSpec
-                    (premasterKey, protoMajor, protoMinor, clientRandom, serverRandom);
+                KeyGenerator kg =
+                    KeyGenerator.getInstance("SunTlsMasterSecret", provider);
+                SecretKey premasterKey =
+                    new SecretKeySpec(premaster, algorithm);
+                TlsMasterSecretParameterSpec spec =
+                    new TlsMasterSecretParameterSpec(premasterKey, protoMajor,
+                        protoMinor, clientRandom, serverRandom,
+                        null, -1, -1);
                 kg.init(spec);
                 TlsMasterSecret key = (TlsMasterSecret)kg.generateKey();
                 byte[] enc = key.getEncoded();
                 if (Arrays.equals(master, enc) == false) {
                     throw new Exception("mismatch line: " + lineNumber);
                 }
-                if ((preMajor != key.getMajorVersion()) || (preMinor != key.getMinorVersion())) {
+                if ((preMajor != key.getMajorVersion()) ||
+                        (preMinor != key.getMinorVersion())) {
                     throw new Exception("version mismatch line: " + lineNumber);
                 }
             } else {
--- a/test/com/sun/crypto/provider/TLS/TestPRF.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/test/com/sun/crypto/provider/TLS/TestPRF.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -85,14 +85,17 @@
                 System.out.print(".");
                 n++;
 
-                KeyGenerator kg = KeyGenerator.getInstance("SunTlsPrf", provider);
+                KeyGenerator kg =
+                    KeyGenerator.getInstance("SunTlsPrf", provider);
                 SecretKey inKey;
                 if (secret == null) {
                     inKey = null;
                 } else {
                     inKey = new SecretKeySpec(secret, "Generic");
                 }
-                TlsPrfParameterSpec spec = new TlsPrfParameterSpec(inKey, label, seed, length);
+                TlsPrfParameterSpec spec =
+                    new TlsPrfParameterSpec(inKey, label, seed, length,
+                        null, -1, -1);
                 kg.init(spec);
                 SecretKey key = kg.generateKey();
                 byte[] enc = key.getEncoded();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/crypto/provider/TLS/TestPRF12.java	Mon Nov 01 22:02:35 2010 -0700
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 6313661
+ * @summary Basic known-answer-test for TlsPrf 12
+ *
+ * Vector obtained from the IETF TLS working group mailing list:
+ *
+ *     http://www.ietf.org/mail-archive/web/tls/current/msg03416.html
+ */
+
+import java.io.*;
+import java.util.*;
+
+import java.security.Security;
+import java.security.Provider;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import javax.crypto.spec.*;
+
+import sun.security.internal.spec.*;
+
+public class TestPRF12 extends Utils {
+
+    private static int PREFIX_LENGTH = "prf-output: ".length();
+
+    public static void main(String[] args) throws Exception {
+        Provider provider = Security.getProvider("SunJCE");
+
+        InputStream in = new FileInputStream(new File(BASE, "prf12data.txt"));
+        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+
+        int n = 0;
+        int lineNumber = 0;
+
+        byte[] secret = null;
+        String label = null;
+        byte[] seed = null;
+        int length = 0;
+        String prfAlg = null;
+        int prfHashLength = 0;
+        int prfBlockSize = 0;
+        byte[] output = null;
+
+        while (true) {
+            String line = reader.readLine();
+            lineNumber++;
+            if (line == null) {
+                break;
+            }
+            if (line.startsWith("prf-") == false) {
+                continue;
+            }
+
+            String data = line.substring(PREFIX_LENGTH);
+            if (line.startsWith("prf-secret:")) {
+                secret = parse(data);
+            } else if (line.startsWith("prf-label:")) {
+                label = data;
+            } else if (line.startsWith("prf-seed:")) {
+                seed = parse(data);
+            } else if (line.startsWith("prf-length:")) {
+                length = Integer.parseInt(data);
+            } else if (line.startsWith("prf-alg:")) {
+                prfAlg = data;
+                switch (prfAlg) {
+                case "SHA-224":
+                    prfHashLength = 28;
+                    prfBlockSize =  64;
+                    break;
+                case "SHA-256":
+                    prfHashLength = 32;
+                    prfBlockSize =  64;
+                    break;
+                case "SHA-384":
+                    prfHashLength = 48;
+                    prfBlockSize = 128;
+                    break;
+                case "SHA-512":
+                    prfHashLength = 64;
+                    prfBlockSize = 128;
+                    break;
+                default:
+                    throw new Exception("Unknown Alg in the data.");
+                }
+            } else if (line.startsWith("prf-output:")) {
+                output = parse(data);
+
+                System.out.print(".");
+                n++;
+
+                KeyGenerator kg =
+                    KeyGenerator.getInstance("SunTls12Prf", provider);
+                SecretKey inKey;
+                if (secret == null) {
+                    inKey = null;
+                } else {
+                    inKey = new SecretKeySpec(secret, "Generic");
+                }
+                TlsPrfParameterSpec spec =
+                    new TlsPrfParameterSpec(inKey, label, seed, length,
+                        prfAlg, prfHashLength, prfBlockSize);
+                kg.init(spec);
+                SecretKey key = kg.generateKey();
+                byte[] enc = key.getEncoded();
+                if (Arrays.equals(output, enc) == false) {
+                    throw new Exception("mismatch line: " + lineNumber);
+                }
+            } else {
+                throw new Exception("Unknown line: " + line);
+            }
+        }
+        if (n == 0) {
+            throw new Exception("no tests");
+        }
+        in.close();
+        System.out.println();
+        System.out.println("OK: " + n + " tests");
+    }
+
+}
--- a/test/com/sun/crypto/provider/TLS/TestPremaster.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/test/com/sun/crypto/provider/TLS/TestPremaster.java	Mon Nov 01 22:02:35 2010 -0700
@@ -60,7 +60,8 @@
         System.out.println("Done.");
     }
 
-    private static void test(KeyGenerator kg, int major, int minor) throws Exception {
+    private static void test(KeyGenerator kg, int major, int minor)
+            throws Exception {
 
         kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor));
         SecretKey key = kg.generateKey();
@@ -69,7 +70,8 @@
             throw new Exception("length: " + encoded.length);
         }
         if ((encoded[0] != major) || (encoded[1] != minor)) {
-            throw new Exception("version mismatch: "  + encoded[0] + "." + encoded[1]);
+            throw new Exception("version mismatch: "  + encoded[0] +
+                "." + encoded[1]);
         }
         System.out.println("OK: " + major + "." + minor);
     }
--- a/test/com/sun/crypto/provider/TLS/Utils.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/test/com/sun/crypto/provider/TLS/Utils.java	Mon Nov 01 22:02:35 2010 -0700
@@ -22,7 +22,6 @@
  */
 
 import java.io.*;
-import java.util.*;
 
 class Utils {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/crypto/provider/TLS/prf12data.txt	Mon Nov 01 22:02:35 2010 -0700
@@ -0,0 +1,19 @@
+prf-secret: 9b:be:43:6b:a9:40:f0:17:b1:76:52:84:9a:71:db:35
+prf-seed:   a0:ba:9f:93:6c:da:31:18:27:a6:f7:96:ff:d5:19:8c
+prf-label:  test label
+prf-length: 100
+prf-alg:    SHA-256
+prf-output: e3:f2:29:ba:72:7b:e1:7b:8d:12:26:20:55:7c:d4:53:c2:aa:b2:1d:07:c3:d4:95:32:9b:52:d4:e6:1e:db:5a:6b:30:17:91:e9:0d:35:c9:c9:a4:6b:4e:14:ba:f9:af:0f:a0:22:f7:07:7d:ef:17:ab:fd:37:97:c0:56:4b:ab:4f:bc:91:66:6e:9d:ef:9b:97:fc:e3:4f:79:67:89:ba:a4:80:82:d1:22:ee:42:c5:a7:2e:5a:51:10:ff:f7:01:87:34:7b:66
+prf-secret: b8:0b:73:3d:6c:ee:fc:dc:71:56:6e:a4:8e:55:67:df
+prf-seed:   cd:66:5c:f6:a8:44:7d:d6:ff:8b:27:55:5e:db:74:65
+prf-label:  test label
+prf-length: 148
+prf-alg:    SHA-384
+prf-output: 7b:0c:18:e9:ce:d4:10:ed:18:04:f2:cf:a3:4a:33:6a:1c:14:df:fb:49:00:bb:5f:d7:94:21:07:e8:1c:83:cd:e9:ca:0f:aa:60:be:9f:e3:4f:82:b1:23:3c:91:46:a0:e5:34:cb:40:0f:ed:27:00:88:4f:9d:c2:36:f8:0e:dd:8b:fa:96:11:44:c9:e8:d7:92:ec:a7:22:a7:b3:2f:c3:d4:16:d4:73:eb:c2:c5:fd:4a:bf:da:d0:5d:91:84:25:9b:5b:f8:cd:4d:90:fa:0d:31:e2:de:c4:79:e4:f1:a2:60:66:f2:ee:a9:a6:92:36:a3:e5:26:55:c9:e9:ae:e6:91:c8:f3:a2:68:54:30:8d:5e:aa:3b:e8:5e:09:90:70:3d:73:e5:6f
+prf-secret: b0:32:35:23:c1:85:35:99:58:4d:88:56:8b:bb:05:eb
+prf-seed:   d4:64:0e:12:e4:bc:db:fb:43:7f:03:e6:ae:41:8e:e5
+prf-label:  test label
+prf-length: 196
+prf-alg:    SHA-512
+prf-output: 12:61:f5:88:c7:98:c5:c2:01:ff:03:6e:7a:9c:b5:ed:cd:7f:e3:f9:4c:66:9a:12:2a:46:38:d7:d5:08:b2:83:04:2d:f6:78:98:75:c7:14:7e:90:6d:86:8b:c7:5c:45:e2:0e:b4:0c:1c:f4:a1:71:3b:27:37:1f:68:43:25:92:f7:dc:8e:a8:ef:22:3e:12:ea:85:07:84:13:11:bf:68:65:3d:0c:fc:40:56:d8:11:f0:25:c4:5d:df:a6:e6:fe:c7:02:f0:54:b4:09:d6:f2:8d:d0:a3:23:3e:49:8d:a4:1a:3e:75:c5:63:0e:ed:be:22:fe:25:4e:33:a1:b0:e9:f6:b9:82:66:75:be:c7:d0:1a:84:56:58:dc:9c:39:75:45:40:1d:40:b9:f4:6c:7a:40:0e:e1:b8:f8:1c:a0:a6:0d:1a:39:7a:10:28:bf:f5:d2:ef:50:66:12:68:42:fb:8d:a4:19:76:32:bd:b5:4f:f6:63:3f:86:bb:c8:36:e6:40:d4:d8:98
+
--- a/test/sun/security/ec/TestEC.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/test/sun/security/ec/TestEC.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
  * @test
  * @bug 6840752
  * @summary  Provide out-of-the-box support for ECC algorithms
+ * @ignore JSSE supported cipher suites are changed with CR 6916074,
+ *     need to update this test case in JDK 7 soon
  * @library ../pkcs11
  * @library ../pkcs11/ec
  * @library ../pkcs11/sslecc
--- a/test/sun/security/pkcs11/fips/ClientJSSEServerJSSE.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/test/sun/security/pkcs11/fips/ClientJSSEServerJSSE.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
  * @test
  * @bug 6313675 6323647
  * @summary Verify that all ciphersuites work in FIPS mode
+ * @ignore JSSE supported cipher suites are changed with CR 6916074,
+ *     need to update this test case in JDK 7 soon
  * @author Andreas Sterbenz
  * @library ..
  */
--- a/test/sun/security/pkcs11/tls/TestKeyMaterial.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/test/sun/security/pkcs11/tls/TestKeyMaterial.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -125,16 +125,23 @@
                 System.out.print(".");
                 n++;
 
-                KeyGenerator kg = KeyGenerator.getInstance("SunTlsKeyMaterial", provider);
-                SecretKey masterKey = new SecretKeySpec(master, "TlsMasterSecret");
-                TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec
-                (masterKey, major, minor, clientRandom, serverRandom, cipherAlgorithm,
-                keyLength, expandedKeyLength, ivLength, macLength);
+                KeyGenerator kg =
+                    KeyGenerator.getInstance("SunTlsKeyMaterial", provider);
+                SecretKey masterKey =
+                    new SecretKeySpec(master, "TlsMasterSecret");
+                TlsKeyMaterialParameterSpec spec =
+                    new TlsKeyMaterialParameterSpec(masterKey, major, minor,
+                    clientRandom, serverRandom, cipherAlgorithm,
+                    keyLength, expandedKeyLength, ivLength, macLength,
+                    null, -1, -1);
 
                 kg.init(spec);
-                TlsKeyMaterialSpec result = (TlsKeyMaterialSpec)kg.generateKey();
-                match(lineNumber, clientCipherBytes, result.getClientCipherKey(), cipherAlgorithm);
-                match(lineNumber, serverCipherBytes, result.getServerCipherKey(), cipherAlgorithm);
+                TlsKeyMaterialSpec result =
+                    (TlsKeyMaterialSpec)kg.generateKey();
+                match(lineNumber, clientCipherBytes,
+                    result.getClientCipherKey(), cipherAlgorithm);
+                match(lineNumber, serverCipherBytes,
+                    result.getServerCipherKey(), cipherAlgorithm);
                 match(lineNumber, clientIv, result.getClientIv(), "");
                 match(lineNumber, serverIv, result.getServerIv(), "");
                 match(lineNumber, clientMacBytes, result.getClientMacKey(), "");
@@ -158,7 +165,8 @@
         }
     }
 
-    private static void match(int lineNumber, byte[] out, Object res, String cipherAlgorithm) throws Exception {
+    private static void match(int lineNumber, byte[] out, Object res,
+            String cipherAlgorithm) throws Exception {
         if ((out == null) || (res == null)) {
             if (out != res) {
                 throw new Exception("null mismatch line " + lineNumber);
@@ -169,7 +177,8 @@
         byte[] b;
         if (res instanceof SecretKey) {
             b = ((SecretKey)res).getEncoded();
-            if (cipherAlgorithm.equalsIgnoreCase("DES") || cipherAlgorithm.equalsIgnoreCase("DESede")) {
+            if (cipherAlgorithm.equalsIgnoreCase("DES") ||
+                    cipherAlgorithm.equalsIgnoreCase("DESede")) {
                 // strip DES parity bits before comparision
                 stripParity(out);
                 stripParity(b);
--- a/test/sun/security/pkcs11/tls/TestMasterSecret.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/test/sun/security/pkcs11/tls/TestMasterSecret.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -104,17 +104,22 @@
                 System.out.print(".");
                 n++;
 
-                KeyGenerator kg = KeyGenerator.getInstance("SunTlsMasterSecret", provider);
-                SecretKey premasterKey = new SecretKeySpec(premaster, algorithm);
-                TlsMasterSecretParameterSpec spec = new TlsMasterSecretParameterSpec
-                    (premasterKey, protoMajor, protoMinor, clientRandom, serverRandom);
+                KeyGenerator kg =
+                    KeyGenerator.getInstance("SunTlsMasterSecret", provider);
+                SecretKey premasterKey =
+                    new SecretKeySpec(premaster, algorithm);
+                TlsMasterSecretParameterSpec spec =
+                    new TlsMasterSecretParameterSpec(premasterKey,
+                        protoMajor, protoMinor, clientRandom, serverRandom,
+                        null, -1, -1);
                 kg.init(spec);
                 TlsMasterSecret key = (TlsMasterSecret)kg.generateKey();
                 byte[] enc = key.getEncoded();
                 if (Arrays.equals(master, enc) == false) {
                     throw new Exception("mismatch line: " + lineNumber);
                 }
-                if ((preMajor != key.getMajorVersion()) || (preMinor != key.getMinorVersion())) {
+                if ((preMajor != key.getMajorVersion()) ||
+                        (preMinor != key.getMinorVersion())) {
                     throw new Exception("version mismatch line: " + lineNumber);
                 }
             } else {
--- a/test/sun/security/pkcs11/tls/TestPRF.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/test/sun/security/pkcs11/tls/TestPRF.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -93,14 +93,17 @@
                 System.out.print(".");
                 n++;
 
-                KeyGenerator kg = KeyGenerator.getInstance("SunTlsPrf", provider);
+                KeyGenerator kg =
+                    KeyGenerator.getInstance("SunTlsPrf", provider);
                 SecretKey inKey;
                 if (secret == null) {
                     inKey = null;
                 } else {
                     inKey = new SecretKeySpec(secret, "Generic");
                 }
-                TlsPrfParameterSpec spec = new TlsPrfParameterSpec(inKey, label, seed, length);
+                TlsPrfParameterSpec spec =
+                    new TlsPrfParameterSpec(inKey, label, seed, length,
+                        null, -1, -1);
                 SecretKey key;
                 try {
                     kg.init(spec);
@@ -109,7 +112,8 @@
                     if (secret == null) {
                         // This fails on Solaris, but since we never call this
                         // API for this case in JSSE, ignore the failure.
-                        // (SunJSSE uses the CKM_TLS_KEY_AND_MAC_DERIVE mechanism)
+                        // (SunJSSE uses the CKM_TLS_KEY_AND_MAC_DERIVE
+                        // mechanism)
                         System.out.print("X");
                         continue;
                     }
--- a/test/sun/security/pkcs11/tls/TestPremaster.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/test/sun/security/pkcs11/tls/TestPremaster.java	Mon Nov 01 22:02:35 2010 -0700
@@ -44,7 +44,8 @@
     }
 
     public void main(Provider provider) throws Exception {
-        if (provider.getService("KeyGenerator", "SunTlsRsaPremasterSecret") == null) {
+        if (provider.getService(
+                "KeyGenerator", "SunTlsRsaPremasterSecret") == null) {
             System.out.println("Not supported by provider, skipping");
             return;
         }
@@ -66,7 +67,8 @@
         System.out.println("Done.");
     }
 
-    private static void test(KeyGenerator kg, int major, int minor) throws Exception {
+    private static void test(KeyGenerator kg, int major, int minor)
+            throws Exception {
 
         kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor));
         SecretKey key = kg.generateKey();
@@ -75,7 +77,8 @@
             throw new Exception("length: " + encoded.length);
         }
         if ((encoded[0] != major) || (encoded[1] != minor)) {
-            throw new Exception("version mismatch: "  + encoded[0] + "." + encoded[1]);
+            throw new Exception("version mismatch: "  + encoded[0] +
+                "." + encoded[1]);
         }
         System.out.println("OK: " + major + "." + minor);
     }
--- a/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/ClientModeClientAuth.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/ClientModeClientAuth.java	Mon Nov 01 22:02:35 2010 -0700
@@ -24,6 +24,7 @@
 /*
  * @test
  * @bug 4390659
+ * @run main/othervm -Djavax.net.debug=all ClientModeClientAuth
  * @summary setNeedClientAuth() isn't working after a handshaker is established
  * @author Brad Wetmore
  */
--- a/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/ClientServer.java	Mon Nov 01 10:59:03 2010 -0700
+++ b/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/ClientServer.java	Mon Nov 01 22:02:35 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
  * @test
  * @bug 4717766
  * @summary 1.0.3 JsseX509TrustManager erroneously calls isClientTrusted()
+ * @ignore JSSE supports algorithm constraints with CR 6916074,
+ *     need to update this test case in JDK 7 soon
  * @author Brad Wetmore
  *
  * This problem didn't exist in JSSE 1.4, only JSSE 1.0.3.  However,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/PKIXExtendedTM.java	Mon Nov 01 22:02:35 2010 -0700
@@ -0,0 +1,882 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * @test
+ * @bug 6916074
+ * @summary Add support for TLS 1.2
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import java.math.BigInteger;
+
+
+/*
+ * Certificates and key used in the test.
+ *
+ * TLS server certificate:
+ * server private key:
+ * -----BEGIN RSA PRIVATE KEY-----
+ * Proc-Type: 4,ENCRYPTED
+ * DEK-Info: DES-EDE3-CBC,D9AE407F6D0E389A
+ *
+ * WPrA7TFol/cQCcp9oHnXWNpYlvRbbIcQj0m+RKT2Iuzfus+DHt3Zadf8nJpKfX2e
+ * h2rnhlzCN9M7djRDooZKDOPCsdBn51Au7HlZF3S3Opgo7D8XFM1a8t1Je4ke14oI
+ * nw6QKYsBblRziPnP2PZ0zvX24nOv7bbY8beynlJHGs00VWSFdoH2DS0aE1p6D+3n
+ * ptJuJ75dVfZFK4X7162APlNXevX8D6PEQpSiRw1rjjGGcnvQ4HdWk3BxDVDcCNJb
+ * Y1aGNRxsjTDvPi3R9Qx2M+W03QzEPx4SR3ZHVskeSJHaetM0TM/w/45Paq4GokXP
+ * ZeTnbEx1xmjkA7h+t4doLL4watx5F6yLsJzu8xB3lt/1EtmkYtLz1t7X4BetPAXz
+ * zS69X/VwhKfsOI3qXBWuL2oHPyhDmT1gcaUQwEPSV6ogHEEQEDXdiUS8heNK13KF
+ * TCQYFkETvV2BLxUhV1hypPzRQ6tUpJiAbD5KmoK2lD9slshG2QtvKQq0/bgkDY5J
+ * LhDHV2dtcZ3kDPkkZXpbcJQvoeH3d09C5sIsuTFo2zgNR6oETHUc5TzP6FY2YYRa
+ * QcK5HcmtsRRiXFm01ac+aMejJUIujjFt84SiKWT/73vC8AmY4tYcJBLjCg4XIxSH
+ * fdDFLL1YZENNO5ivlp8mdiHqcawx+36L7DrEZQ8RZt6cqST5t/+XTdM74s6k81GT
+ * pNsa82P2K2zmIUZ/DL2mKjW1vfRByw1NQFEBkN3vdyZxYfM/JyUzX4hbjXBEkh9Q
+ * QYrcwLKLjis2QzSvK04B3bvRzRb+4ocWiso8ZPAXAIxZFBWDpTMM2A==
+ * -----END RSA PRIVATE KEY-----
+ *
+ * -----BEGIN RSA PRIVATE KEY-----
+ * MIICXAIBAAKBgQClrFscN6LdmYktsnm4j9VIpecchBeNaZzGrG358h0fORna03Ie
+ * buxEzHCk3LoAMPagTz1UemFqzFfQCn+VKBg/mtmU8hvIJIh+/p0PPftXUwizIDPU
+ * PxdHFNHN6gjYDnVOr77M0uyvqXpJ38LZrLgkQJCmA1Yq0DAFQCxPq9l0iQIDAQAB
+ * AoGAbqcbg1E1mkR99uOJoNeQYKFOJyGiiXTMnXV1TseC4+PDfQBU7Dax35GcesBi
+ * CtapIpFKKS5D+ozY6b7ZT8ojxuQ/uHLPAvz0WDR3ds4iRF8tyu71Q1ZHcQsJa17y
+ * yO7UbkSSKn/Mp9Rb+/dKqftUGNXVFLqgHBOzN2s3We3bbbECQQDYBPKOg3hkaGHo
+ * OhpHKqtQ6EVkldihG/3i4WejRonelXN+HRh1KrB2HBx0M8D/qAzP1i3rNSlSHer4
+ * 59YRTJnHAkEAxFX/sVYSn07BHv9Zhn6XXct/Cj43z/tKNbzlNbcxqQwQerw3IH51
+ * 8UH2YOA+GD3lXbKp+MytoFLWv8zg4YT/LwJAfqan75Z1R6lLffRS49bIiq8jwE16
+ * rTrUJ+kv8jKxMqc9B3vXkxpsS1M/+4E8bqgAmvpgAb8xcsvHsBd9ErdukQJBAKs2
+ * j67W75BrPjBI34pQ1LEfp56IGWXOrq1kF8IbCjxv3+MYRT6Z6UJFkpRymNPNDjsC
+ * dgUYgITiGJHUGXuw3lMCQHEHqo9ZtXz92yFT+VhsNc29B8m/sqUJdtCcMd/jGpAF
+ * u6GHufjqIZBpQsk63wbwESAPZZ+kk1O1kS5GIRLX608=
+ * -----END RSA PRIVATE KEY-----
+ *
+ * Private-Key: (1024 bit)
+ * modulus:
+ *     00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f:
+ *     d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2:
+ *     1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc:
+ *     ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a:
+ *     7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe:
+ *     9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14:
+ *     d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9:
+ *     7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0:
+ *     30:05:40:2c:4f:ab:d9:74:89
+ * publicExponent: 65537 (0x10001)
+ * privateExponent:
+ *     6e:a7:1b:83:51:35:9a:44:7d:f6:e3:89:a0:d7:90:
+ *     60:a1:4e:27:21:a2:89:74:cc:9d:75:75:4e:c7:82:
+ *     e3:e3:c3:7d:00:54:ec:36:b1:df:91:9c:7a:c0:62:
+ *     0a:d6:a9:22:91:4a:29:2e:43:fa:8c:d8:e9:be:d9:
+ *     4f:ca:23:c6:e4:3f:b8:72:cf:02:fc:f4:58:34:77:
+ *     76:ce:22:44:5f:2d:ca:ee:f5:43:56:47:71:0b:09:
+ *     6b:5e:f2:c8:ee:d4:6e:44:92:2a:7f:cc:a7:d4:5b:
+ *     fb:f7:4a:a9:fb:54:18:d5:d5:14:ba:a0:1c:13:b3:
+ *     37:6b:37:59:ed:db:6d:b1
+ * prime1:
+ *     00:d8:04:f2:8e:83:78:64:68:61:e8:3a:1a:47:2a:
+ *     ab:50:e8:45:64:95:d8:a1:1b:fd:e2:e1:67:a3:46:
+ *     89:de:95:73:7e:1d:18:75:2a:b0:76:1c:1c:74:33:
+ *     c0:ff:a8:0c:cf:d6:2d:eb:35:29:52:1d:ea:f8:e7:
+ *     d6:11:4c:99:c7
+ * prime2:
+ *     00:c4:55:ff:b1:56:12:9f:4e:c1:1e:ff:59:86:7e:
+ *     97:5d:cb:7f:0a:3e:37:cf:fb:4a:35:bc:e5:35:b7:
+ *     31:a9:0c:10:7a:bc:37:20:7e:75:f1:41:f6:60:e0:
+ *     3e:18:3d:e5:5d:b2:a9:f8:cc:ad:a0:52:d6:bf:cc:
+ *     e0:e1:84:ff:2f
+ * exponent1:
+ *     7e:a6:a7:ef:96:75:47:a9:4b:7d:f4:52:e3:d6:c8:
+ *     8a:af:23:c0:4d:7a:ad:3a:d4:27:e9:2f:f2:32:b1:
+ *     32:a7:3d:07:7b:d7:93:1a:6c:4b:53:3f:fb:81:3c:
+ *     6e:a8:00:9a:fa:60:01:bf:31:72:cb:c7:b0:17:7d:
+ *     12:b7:6e:91
+ * exponent2:
+ *     00:ab:36:8f:ae:d6:ef:90:6b:3e:30:48:df:8a:50:
+ *     d4:b1:1f:a7:9e:88:19:65:ce:ae:ad:64:17:c2:1b:
+ *     0a:3c:6f:df:e3:18:45:3e:99:e9:42:45:92:94:72:
+ *     98:d3:cd:0e:3b:02:76:05:18:80:84:e2:18:91:d4:
+ *     19:7b:b0:de:53
+ * coefficient:
+ *     71:07:aa:8f:59:b5:7c:fd:db:21:53:f9:58:6c:35:
+ *     cd:bd:07:c9:bf:b2:a5:09:76:d0:9c:31:df:e3:1a:
+ *     90:05:bb:a1:87:b9:f8:ea:21:90:69:42:c9:3a:df:
+ *     06:f0:11:20:0f:65:9f:a4:93:53:b5:91:2e:46:21:
+ *     12:d7:eb:4f
+ *
+ *
+ * server certificate:
+ * Data:
+ *     Version: 3 (0x2)
+ *     Serial Number: 8 (0x8)
+ *     Signature Algorithm: md5WithRSAEncryption
+ *     Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org
+ *     Validity
+ *         Not Before: Dec  8 03:43:04 2008 GMT
+ *         Not After : Aug 25 03:43:04 2028 GMT
+ *     Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Server, CN=localhost
+ *     Subject Public Key Info:
+ *         Public Key Algorithm: rsaEncryption
+ *         RSA Public Key: (1024 bit)
+ *             Modulus (1024 bit):
+ *                 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f:
+ *                 d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2:
+ *                 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc:
+ *                 ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a:
+ *                 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe:
+ *                 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14:
+ *                 d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9:
+ *                 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0:
+ *                 30:05:40:2c:4f:ab:d9:74:89
+ *             Exponent: 65537 (0x10001)
+ *     X509v3 extensions:
+ *         X509v3 Basic Constraints:
+ *             CA:FALSE
+ *         X509v3 Key Usage:
+ *             Digital Signature, Non Repudiation, Key Encipherment
+ *         X509v3 Subject Key Identifier:
+ *             ED:6E:DB:F4:B5:56:C8:FB:1A:06:61:3F:0F:08:BB:A6:04:D8:16:54
+ *         X509v3 Authority Key Identifier:
+ *             keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14
+ *
+ *         X509v3 Subject Alternative Name: critical
+ *             DNS:localhost
+ * Signature Algorithm: md5WithRSAEncryption0
+ *
+ * -----BEGIN CERTIFICATE-----
+ * MIICpDCCAg2gAwIBAgIBCDANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET
+ * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK
+ * EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMDRaFw0yODA4MjUwMzQzMDRaMHIxCzAJ
+ * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp
+ * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD
+ * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3
+ * ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6
+ * YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS
+ * 7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjczBxMAkGA1UdEwQCMAAw
+ * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV
+ * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh
+ * bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAoqVTciHtcvsUj+YaTct8tUh3aTCsKsac
+ * PHhfQ+ObjiXSgxsKYTX7ym/wk/wvlbUcbqLKxsu7qrcJitH+H9heV1hEHEu65Uoi
+ * nRugFruyOrwvAylV8Cm2af7ddilmYJ+sdJA6N2M3xJRxR0G2LFHEXDNEjYReyexn
+ * JqCpf5uZGOo=
+ * -----END CERTIFICATE-----
+ *
+ *
+ * TLS client certificate:
+ * client private key:
+ * ----BEGIN RSA PRIVATE KEY-----
+ * Proc-Type: 4,ENCRYPTED
+ * DEK-Info: DES-EDE3-CBC,FA2A435CD35A9390
+ *
+ * Z+Y2uaETbsUWIyJUyVu1UV2G4rgFYJyACZT6Tp1KjRtxflSh2kXkJ9MpuXMXA0V4
+ * Yy3fDzPqCL9NJmQAYRlAx/W/+j4F5EyMWDIx8fUxzONRZyoiwF7jLm+KscAfv6Pf
+ * q7ItWOdj3z7IYrwlB8YIGd3F2cDKT3S+lYRk7rKb/qT7itbuHnY4Ardh3yl+MZak
+ * jBp+ELUlRsUqSr1V0LoM+0rCCykarpyfhpxEcqsrl0v9Cyi5uhU50/oKv5zql3SH
+ * l2ImgDjp3batAs8+Bd4NF2aqi0a7Hy44JUHxRm4caZryU/i/D9N1MbuM6882HLat
+ * 5N0G+NaIUfywa8mjwq2D5aiit18HqKA6XeRRYeJ5Dvu9DCO4GeFSwcUFIBMI0L46
+ * 7s114+oDodg57pMgITi+04vmUxvqlN9aiyd7f5Fgd7PeHGeOdbMz1NaJLJaPI9++
+ * NakK8eK9iwT/Gdq0Uap5/CHW7vCT5PO+h3HY0STH0lWStXhdWnFO04zTdywsbSp+
+ * DLpHeFT66shfeUlxR0PsCbG9vPRt/QmGLeYQZITppWo/ylSq4j+pRIuXvuWHdBRN
+ * rTZ8QF4Y7AxQUXVz1j1++s6ZMHTzaK2i9HrhmDs1MbJl+QwWre3Xpv3LvTVz3k5U
+ * wX8kuY1m3STt71QCaRWENq5sRaMImLxZbxc/ivFl9RAzUqo4NCxLod/QgA4iLqtO
+ * ztnlpzwlC/F8HbQ1oqYWwnZAPhzU/cULtstl+Yrws2c2atO323LbPXZqbASySgig
+ * sNpFXQMObdfP6LN23bY+1SvtK7V4NUTNhpdIc6INQAQ=
+ * -----END RSA PRIVATE KEY-----
+ *
+ * -----BEGIN RSA PRIVATE KEY-----
+ * MIICWwIBAAKBgQC78EA2rCZUTvSjWgAvaSFvuXo6k+yi9uGOx2PYLxIwmS6w8o/4
+ * Jy0keCiE9wG/jUR53TvSVfPOPLJbIX3v/TNKsaP/xsibuQ98QTWX+ds6BWAFFa9Z
+ * F5KjEK0WHOQHU6+odqJWKpLT+SjgeM9eH0irXBnd4WdDunWN9YKsQ5JEGwIDAQAB
+ * AoGAEbdqNj0wN85hnWyEi/ObJU8UyKTdL9eaF72QGfcF/fLSxfd3vurihIeXOkGW
+ * tpn4lIxYcVGM9CognhqgJpl11jFTQzn1KqZ+NEJRKkCHA4hDabKJbSC9fXHvRwrf
+ * BsFpZqgiNxp3HseUTiwnaUVeyPgMt/jAj5nB5Sib+UyUxrECQQDnNQBiF2aifEg6
+ * zbJOOC7he5CHAdkFxSxWVFVHL6EfXfqdLVkUohMbgZv+XxyIeU2biOExSg49Kds3
+ * FOKgTau1AkEA0Bd1haj6QuCo8I0AXm2WO+MMTZMTvtHD/bGjKNM+fT4I8rKYnQRX
+ * 1acHdqS9Xx2rNJqZgkMmpESIdPR2fc4yjwJALFeM6EMmqvj8/VIf5UJ/Mz14fXwM
+ * PEARfckUxd9LnnFutCBTWlKvKXJVEZb6KO5ixPaegc57Jp3Vbh3yTN44lQJADD/1
+ * SSMDaIB1MYP7a5Oj7m6VQNPRq8AJe5vDcRnOae0G9dKRrVyeFxO4GsHj6/+BHp2j
+ * P8nYMn9eURQ7DXjf/QJAAQzMlWnKGSO8pyTDtnQx3hRMoUkOEhmNq4bQhLkYqtnY
+ * FcqpUQ2qMjW+NiNWk5HnTrMS3L9EdJobMUzaNZLy4w==
+ * -----END RSA PRIVATE KEY-----
+ *
+ * Private-Key: (1024 bit)
+ * modulus:
+ *     00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69:
+ *     21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f:
+ *     12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7:
+ *     01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21:
+ *     7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41:
+ *     35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10:
+ *     ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9:
+ *     28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba:
+ *     75:8d:f5:82:ac:43:92:44:1b
+ * publicExponent: 65537 (0x10001)
+ * privateExponent:
+ *     11:b7:6a:36:3d:30:37:ce:61:9d:6c:84:8b:f3:9b:
+ *     25:4f:14:c8:a4:dd:2f:d7:9a:17:bd:90:19:f7:05:
+ *     fd:f2:d2:c5:f7:77:be:ea:e2:84:87:97:3a:41:96:
+ *     b6:99:f8:94:8c:58:71:51:8c:f4:2a:20:9e:1a:a0:
+ *     26:99:75:d6:31:53:43:39:f5:2a:a6:7e:34:42:51:
+ *     2a:40:87:03:88:43:69:b2:89:6d:20:bd:7d:71:ef:
+ *     47:0a:df:06:c1:69:66:a8:22:37:1a:77:1e:c7:94:
+ *     4e:2c:27:69:45:5e:c8:f8:0c:b7:f8:c0:8f:99:c1:
+ *     e5:28:9b:f9:4c:94:c6:b1
+ * prime1:
+ *     00:e7:35:00:62:17:66:a2:7c:48:3a:cd:b2:4e:38:
+ *     2e:e1:7b:90:87:01:d9:05:c5:2c:56:54:55:47:2f:
+ *     a1:1f:5d:fa:9d:2d:59:14:a2:13:1b:81:9b:fe:5f:
+ *     1c:88:79:4d:9b:88:e1:31:4a:0e:3d:29:db:37:14:
+ *     e2:a0:4d:ab:b5
+ * prime2:
+ *     00:d0:17:75:85:a8:fa:42:e0:a8:f0:8d:00:5e:6d:
+ *     96:3b:e3:0c:4d:93:13:be:d1:c3:fd:b1:a3:28:d3:
+ *     3e:7d:3e:08:f2:b2:98:9d:04:57:d5:a7:07:76:a4:
+ *     bd:5f:1d:ab:34:9a:99:82:43:26:a4:44:88:74:f4:
+ *     76:7d:ce:32:8f
+ * exponent1:
+ *     2c:57:8c:e8:43:26:aa:f8:fc:fd:52:1f:e5:42:7f:
+ *     33:3d:78:7d:7c:0c:3c:40:11:7d:c9:14:c5:df:4b:
+ *     9e:71:6e:b4:20:53:5a:52:af:29:72:55:11:96:fa:
+ *     28:ee:62:c4:f6:9e:81:ce:7b:26:9d:d5:6e:1d:f2:
+ *     4c:de:38:95
+ * exponent2:
+ *     0c:3f:f5:49:23:03:68:80:75:31:83:fb:6b:93:a3:
+ *     ee:6e:95:40:d3:d1:ab:c0:09:7b:9b:c3:71:19:ce:
+ *     69:ed:06:f5:d2:91:ad:5c:9e:17:13:b8:1a:c1:e3:
+ *     eb:ff:81:1e:9d:a3:3f:c9:d8:32:7f:5e:51:14:3b:
+ *     0d:78:df:fd
+ * coefficient:
+ *     01:0c:cc:95:69:ca:19:23:bc:a7:24:c3:b6:74:31:
+ *     de:14:4c:a1:49:0e:12:19:8d:ab:86:d0:84:b9:18:
+ *     aa:d9:d8:15:ca:a9:51:0d:aa:32:35:be:36:23:56:
+ *     93:91:e7:4e:b3:12:dc:bf:44:74:9a:1b:31:4c:da:
+ *     35:92:f2:e3
+ *
+ * client certificate:
+ * Data:
+ *     Version: 3 (0x2)
+ *     Serial Number: 9 (0x9)
+ *     Signature Algorithm: md5WithRSAEncryption
+ *     Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org
+ *     Validity
+ *         Not Before: Dec  8 03:43:24 2008 GMT
+ *         Not After : Aug 25 03:43:24 2028 GMT
+ *     Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Client, CN=localhost
+ *     Subject Public Key Info:
+ *         Public Key Algorithm: rsaEncryption
+ *         RSA Public Key: (1024 bit)
+ *             Modulus (1024 bit):
+ *                 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69:
+ *                 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f:
+ *                 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7:
+ *                 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21:
+ *                 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41:
+ *                 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10:
+ *                 ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9:
+ *                 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba:
+ *                 75:8d:f5:82:ac:43:92:44:1b
+ *             Exponent: 65537 (0x10001)
+ *     X509v3 extensions:
+ *         X509v3 Basic Constraints:
+ *             CA:FALSE
+ *         X509v3 Key Usage:
+ *             Digital Signature, Non Repudiation, Key Encipherment
+ *         X509v3 Subject Key Identifier:
+ *             CD:BB:C8:85:AA:91:BD:FD:1D:BE:CD:67:7C:FF:B3:E9:4C:A8:22:E6
+ *         X509v3 Authority Key Identifier:
+ *             keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14
+ *
+ *         X509v3 Subject Alternative Name: critical
+ *             DNS:localhost
+ * Signature Algorithm: md5WithRSAEncryption
+ *
+ * -----BEGIN CERTIFICATE-----
+ * MIICpDCCAg2gAwIBAgIBCTANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET
+ * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK
+ * EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMjRaFw0yODA4MjUwMzQzMjRaMHIxCzAJ
+ * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp
+ * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD
+ * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas
+ * JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV
+ * 8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq
+ * ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjczBxMAkGA1UdEwQCMAAw
+ * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV
+ * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh
+ * bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAm25gJyqW1JznQ1EyOtTGswBVwfgBOf+F
+ * HJuBTcflYQLbTD/AETPQJGvZU9tdhuLtbG3OPhR7vSY8zeAbfM3dbH7QFr3r47Gj
+ * XEH7qM/MX+Z3ifVaC4MeJmrYQkYFSuKeyyKpdRVX4w4nnFHF6OsNASsYrMW6LpxN
+ * cl/epUcHL7E=
+ * -----END CERTIFICATE-----
+ *
+ *
+ *
+ * Trusted CA certificate:
+ * Certificate:
+ *   Data:
+ *     Version: 3 (0x2)
+ *     Serial Number: 0 (0x0)
+ *     Signature Algorithm: md5WithRSAEncryption
+ *     Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org
+ *     Validity
+ *         Not Before: Dec  8 02:43:36 2008 GMT
+ *         Not After : Aug 25 02:43:36 2028 GMT
+ *     Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org
+ *     Subject Public Key Info:
+ *         Public Key Algorithm: rsaEncryption
+ *         RSA Public Key: (1024 bit)
+ *             Modulus (1024 bit):
+ *                 00:cb:c4:38:20:07:be:88:a7:93:b0:a1:43:51:2d:
+ *                 d7:8e:85:af:54:dd:ad:a2:7b:23:5b:cf:99:13:53:
+ *                 99:45:7d:ee:6d:ba:2d:bf:e3:ad:6e:3d:9f:1a:f9:
+ *                 03:97:e0:17:55:ae:11:26:57:de:01:29:8e:05:3f:
+ *                 21:f7:e7:36:e8:2e:37:d7:48:ac:53:d6:60:0e:c7:
+ *                 50:6d:f6:c5:85:f7:8b:a6:c5:91:35:72:3c:94:ee:
+ *                 f1:17:f0:71:e3:ec:1b:ce:ca:4e:40:42:b0:6d:ee:
+ *                 6a:0e:d6:e5:ad:3c:0f:c9:ba:82:4f:78:f8:89:97:
+ *                 89:2a:95:12:4c:d8:09:2a:e9
+ *             Exponent: 65537 (0x10001)
+ *     X509v3 extensions:
+ *         X509v3 Subject Key Identifier:
+ *             FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14
+ *         X509v3 Authority Key Identifier:
+ *             keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14
+ *             DirName:/C=US/ST=Some-State/L=Some-City/O=Some-Org
+ *             serial:00
+ *
+ *         X509v3 Basic Constraints:
+ *             CA:TRUE
+ *  Signature Algorithm: md5WithRSAEncryption
+ *
+ * -----BEGIN CERTIFICATE-----
+ * MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET
+ * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK
+ * EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ
+ * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp
+ * dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
+ * gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX
+ * 4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj
+ * 7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G
+ * A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ
+ * hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt
+ * U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw
+ * DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA
+ * ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ
+ * LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P
+ * 6Mvf0r1PNTY2hwTJLJmKtg==
+ * -----END CERTIFICATE---
+ */
+
+
+public class PKIXExtendedTM {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String trusedCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" +
+        "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" +
+        "EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ\n" +
+        "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" +
+        "dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" +
+        "gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX\n" +
+        "4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj\n" +
+        "7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G\n" +
+        "A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ\n" +
+        "hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt\n" +
+        "U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw\n" +
+        "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA\n" +
+        "ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ\n" +
+        "LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P\n" +
+        "6Mvf0r1PNTY2hwTJLJmKtg==\n" +
+        "-----END CERTIFICATE-----";
+
+    static String serverCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICpDCCAg2gAwIBAgIBCDANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" +
+        "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" +
+        "EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMDRaFw0yODA4MjUwMzQzMDRaMHIxCzAJ\n" +
+        "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" +
+        "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD\n" +
+        "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3\n" +
+        "ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6\n" +
+        "YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS\n" +
+        "7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjczBxMAkGA1UdEwQCMAAw\n" +
+        "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV\n" +
+        "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh\n" +
+        "bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAoqVTciHtcvsUj+YaTct8tUh3aTCsKsac\n" +
+        "PHhfQ+ObjiXSgxsKYTX7ym/wk/wvlbUcbqLKxsu7qrcJitH+H9heV1hEHEu65Uoi\n" +
+        "nRugFruyOrwvAylV8Cm2af7ddilmYJ+sdJA6N2M3xJRxR0G2LFHEXDNEjYReyexn\n" +
+        "JqCpf5uZGOo=\n" +
+        "-----END CERTIFICATE-----";
+
+    static String clientCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICpDCCAg2gAwIBAgIBCTANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" +
+        "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" +
+        "EwhTb21lLU9yZzAeFw0wODEyMDgwMzQzMjRaFw0yODA4MjUwMzQzMjRaMHIxCzAJ\n" +
+        "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" +
+        "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD\n" +
+        "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas\n" +
+        "JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV\n" +
+        "8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq\n" +
+        "ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjczBxMAkGA1UdEwQCMAAw\n" +
+        "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV\n" +
+        "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDAXBgNVHREBAf8EDTALgglsb2Nh\n" +
+        "bGhvc3QwDQYJKoZIhvcNAQEEBQADgYEAm25gJyqW1JznQ1EyOtTGswBVwfgBOf+F\n" +
+        "HJuBTcflYQLbTD/AETPQJGvZU9tdhuLtbG3OPhR7vSY8zeAbfM3dbH7QFr3r47Gj\n" +
+        "XEH7qM/MX+Z3ifVaC4MeJmrYQkYFSuKeyyKpdRVX4w4nnFHF6OsNASsYrMW6LpxN\n" +
+        "cl/epUcHL7E=\n" +
+        "-----END CERTIFICATE-----";
+
+    static byte serverPrivateExponent[] = {
+        (byte)0x6e, (byte)0xa7, (byte)0x1b, (byte)0x83,
+        (byte)0x51, (byte)0x35, (byte)0x9a, (byte)0x44,
+        (byte)0x7d, (byte)0xf6, (byte)0xe3, (byte)0x89,
+        (byte)0xa0, (byte)0xd7, (byte)0x90, (byte)0x60,
+        (byte)0xa1, (byte)0x4e, (byte)0x27, (byte)0x21,
+        (byte)0xa2, (byte)0x89, (byte)0x74, (byte)0xcc,
+        (byte)0x9d, (byte)0x75, (byte)0x75, (byte)0x4e,
+        (byte)0xc7, (byte)0x82, (byte)0xe3, (byte)0xe3,
+        (byte)0xc3, (byte)0x7d, (byte)0x00, (byte)0x54,
+        (byte)0xec, (byte)0x36, (byte)0xb1, (byte)0xdf,
+        (byte)0x91, (byte)0x9c, (byte)0x7a, (byte)0xc0,
+        (byte)0x62, (byte)0x0a, (byte)0xd6, (byte)0xa9,
+        (byte)0x22, (byte)0x91, (byte)0x4a, (byte)0x29,
+        (byte)0x2e, (byte)0x43, (byte)0xfa, (byte)0x8c,
+        (byte)0xd8, (byte)0xe9, (byte)0xbe, (byte)0xd9,
+        (byte)0x4f, (byte)0xca, (byte)0x23, (byte)0xc6,
+        (byte)0xe4, (byte)0x3f, (byte)0xb8, (byte)0x72,
+        (byte)0xcf, (byte)0x02, (byte)0xfc, (byte)0xf4,
+        (byte)0x58, (byte)0x34, (byte)0x77, (byte)0x76,
+        (byte)0xce, (byte)0x22, (byte)0x44, (byte)0x5f,
+        (byte)0x2d, (byte)0xca, (byte)0xee, (byte)0xf5,
+        (byte)0x43, (byte)0x56, (byte)0x47, (byte)0x71,
+        (byte)0x0b, (byte)0x09, (byte)0x6b, (byte)0x5e,
+        (byte)0xf2, (byte)0xc8, (byte)0xee, (byte)0xd4,
+        (byte)0x6e, (byte)0x44, (byte)0x92, (byte)0x2a,
+        (byte)0x7f, (byte)0xcc, (byte)0xa7, (byte)0xd4,
+        (byte)0x5b, (byte)0xfb, (byte)0xf7, (byte)0x4a,
+        (byte)0xa9, (byte)0xfb, (byte)0x54, (byte)0x18,
+        (byte)0xd5, (byte)0xd5, (byte)0x14, (byte)0xba,
+        (byte)0xa0, (byte)0x1c, (byte)0x13, (byte)0xb3,
+        (byte)0x37, (byte)0x6b, (byte)0x37, (byte)0x59,
+        (byte)0xed, (byte)0xdb, (byte)0x6d, (byte)0xb1
+    };
+
+    static byte serverModulus[] = {
+        (byte)0x00,
+        (byte)0xa5, (byte)0xac, (byte)0x5b, (byte)0x1c,
+        (byte)0x37, (byte)0xa2, (byte)0xdd, (byte)0x99,
+        (byte)0x89, (byte)0x2d, (byte)0xb2, (byte)0x79,
+        (byte)0xb8, (byte)0x8f, (byte)0xd5, (byte)0x48,
+        (byte)0xa5, (byte)0xe7, (byte)0x1c, (byte)0x84,
+        (byte)0x17, (byte)0x8d, (byte)0x69, (byte)0x9c,
+        (byte)0xc6, (byte)0xac, (byte)0x6d, (byte)0xf9,
+        (byte)0xf2, (byte)0x1d, (byte)0x1f, (byte)0x39,
+        (byte)0x19, (byte)0xda, (byte)0xd3, (byte)0x72,
+        (byte)0x1e, (byte)0x6e, (byte)0xec, (byte)0x44,
+        (byte)0xcc, (byte)0x70, (byte)0xa4, (byte)0xdc,
+        (byte)0xba, (byte)0x00, (byte)0x30, (byte)0xf6,
+        (byte)0xa0, (byte)0x4f, (byte)0x3d, (byte)0x54,
+        (byte)0x7a, (byte)0x61, (byte)0x6a, (byte)0xcc,
+        (byte)0x57, (byte)0xd0, (byte)0x0a, (byte)0x7f,
+        (byte)0x95, (byte)0x28, (byte)0x18, (byte)0x3f,
+        (byte)0x9a, (byte)0xd9, (byte)0x94, (byte)0xf2,
+        (byte)0x1b, (byte)0xc8, (byte)0x24, (byte)0x88,
+        (byte)0x7e, (byte)0xfe, (byte)0x9d, (byte)0x0f,
+        (byte)0x3d, (byte)0xfb, (byte)0x57, (byte)0x53,
+        (byte)0x08, (byte)0xb3, (byte)0x20, (byte)0x33,
+        (byte)0xd4, (byte)0x3f, (byte)0x17, (byte)0x47,
+        (byte)0x14, (byte)0xd1, (byte)0xcd, (byte)0xea,
+        (byte)0x08, (byte)0xd8, (byte)0x0e, (byte)0x75,
+        (byte)0x4e, (byte)0xaf, (byte)0xbe, (byte)0xcc,
+        (byte)0xd2, (byte)0xec, (byte)0xaf, (byte)0xa9,
+        (byte)0x7a, (byte)0x49, (byte)0xdf, (byte)0xc2,
+        (byte)0xd9, (byte)0xac, (byte)0xb8, (byte)0x24,
+        (byte)0x40, (byte)0x90, (byte)0xa6, (byte)0x03,
+        (byte)0x56, (byte)0x2a, (byte)0xd0, (byte)0x30,
+        (byte)0x05, (byte)0x40, (byte)0x2c, (byte)0x4f,
+        (byte)0xab, (byte)0xd9, (byte)0x74, (byte)0x89
+    };
+
+    static byte clientPrivateExponent[] = {
+        (byte)0x11, (byte)0xb7, (byte)0x6a, (byte)0x36,
+        (byte)0x3d, (byte)0x30, (byte)0x37, (byte)0xce,
+        (byte)0x61, (byte)0x9d, (byte)0x6c, (byte)0x84,
+        (byte)0x8b, (byte)0xf3, (byte)0x9b, (byte)0x25,
+        (byte)0x4f, (byte)0x14, (byte)0xc8, (byte)0xa4,
+        (byte)0xdd, (byte)0x2f, (byte)0xd7, (byte)0x9a,
+        (byte)0x17, (byte)0xbd, (byte)0x90, (byte)0x19,
+        (byte)0xf7, (byte)0x05, (byte)0xfd, (byte)0xf2,
+        (byte)0xd2, (byte)0xc5, (byte)0xf7, (byte)0x77,
+        (byte)0xbe, (byte)0xea, (byte)0xe2, (byte)0x84,
+        (byte)0x87, (byte)0x97, (byte)0x3a, (byte)0x41,
+        (byte)0x96, (byte)0xb6, (byte)0x99, (byte)0xf8,
+        (byte)0x94, (byte)0x8c, (byte)0x58, (byte)0x71,
+        (byte)0x51, (byte)0x8c, (byte)0xf4, (byte)0x2a,
+        (byte)0x20, (byte)0x9e, (byte)0x1a, (byte)0xa0,
+        (byte)0x26, (byte)0x99, (byte)0x75, (byte)0xd6,
+        (byte)0x31, (byte)0x53, (byte)0x43, (byte)0x39,
+        (byte)0xf5, (byte)0x2a, (byte)0xa6, (byte)0x7e,
+        (byte)0x34, (byte)0x42, (byte)0x51, (byte)0x2a,
+        (byte)0x40, (byte)0x87, (byte)0x03, (byte)0x88,
+        (byte)0x43, (byte)0x69, (byte)0xb2, (byte)0x89,
+        (byte)0x6d, (byte)0x20, (byte)0xbd, (byte)0x7d,
+        (byte)0x71, (byte)0xef, (byte)0x47, (byte)0x0a,
+        (byte)0xdf, (byte)0x06, (byte)0xc1, (byte)0x69,
+        (byte)0x66, (byte)0xa8, (byte)0x22, (byte)0x37,
+        (byte)0x1a, (byte)0x77, (byte)0x1e, (byte)0xc7,
+        (byte)0x94, (byte)0x4e, (byte)0x2c, (byte)0x27,
+        (byte)0x69, (byte)0x45, (byte)0x5e, (byte)0xc8,
+        (byte)0xf8, (byte)0x0c, (byte)0xb7, (byte)0xf8,
+        (byte)0xc0, (byte)0x8f, (byte)0x99, (byte)0xc1,
+        (byte)0xe5, (byte)0x28, (byte)0x9b, (byte)0xf9,
+        (byte)0x4c, (byte)0x94, (byte)0xc6, (byte)0xb1
+    };
+
+    static byte clientModulus[] = {
+        (byte)0x00,
+        (byte)0xbb, (byte)0xf0, (byte)0x40, (byte)0x36,
+        (byte)0xac, (byte)0x26, (byte)0x54, (byte)0x4e,
+        (byte)0xf4, (byte)0xa3, (byte)0x5a, (byte)0x00,
+        (byte)0x2f, (byte)0x69, (byte)0x21, (byte)0x6f,
+        (byte)0xb9, (byte)0x7a, (byte)0x3a, (byte)0x93,
+        (byte)0xec, (byte)0xa2, (byte)0xf6, (byte)0xe1,
+        (byte)0x8e, (byte)0xc7, (byte)0x63, (byte)0xd8,
+        (byte)0x2f, (byte)0x12, (byte)0x30, (byte)0x99,
+        (byte)0x2e, (byte)0xb0, (byte)0xf2, (byte)0x8f,
+        (byte)0xf8, (byte)0x27, (byte)0x2d, (byte)0x24,
+        (byte)0x78, (byte)0x28, (byte)0x84, (byte)0xf7,
+        (byte)0x01, (byte)0xbf, (byte)0x8d, (byte)0x44,
+        (byte)0x79, (byte)0xdd, (byte)0x3b, (byte)0xd2,
+        (byte)0x55, (byte)0xf3, (byte)0xce, (byte)0x3c,
+        (byte)0xb2, (byte)0x5b, (byte)0x21, (byte)0x7d,
+        (byte)0xef, (byte)0xfd, (byte)0x33, (byte)0x4a,
+        (byte)0xb1, (byte)0xa3, (byte)0xff, (byte)0xc6,
+        (byte)0xc8, (byte)0x9b, (byte)0xb9, (byte)0x0f,
+        (byte)0x7c, (byte)0x41, (byte)0x35, (byte)0x97,
+        (byte)0xf9, (byte)0xdb, (byte)0x3a, (byte)0x05,
+        (byte)0x60, (byte)0x05, (byte)0x15, (byte)0xaf,
+        (byte)0x59, (byte)0x17, (byte)0x92, (byte)0xa3,
+        (byte)0x10, (byte)0xad, (byte)0x16, (byte)0x1c,
+        (byte)0xe4, (byte)0x07, (byte)0x53, (byte)0xaf,
+        (byte)0xa8, (byte)0x76, (byte)0xa2, (byte)0x56,
+        (byte)0x2a, (byte)0x92, (byte)0xd3, (byte)0xf9,
+        (byte)0x28, (byte)0xe0, (byte)0x78, (byte)0xcf,
+        (byte)0x5e, (byte)0x1f, (byte)0x48, (byte)0xab,
+        (byte)0x5c, (byte)0x19, (byte)0xdd, (byte)0xe1,
+        (byte)0x67, (byte)0x43, (byte)0xba, (byte)0x75,
+        (byte)0x8d, (byte)0xf5, (byte)0x82, (byte)0xac,
+        (byte)0x43, (byte)0x92, (byte)0x44, (byte)0x1b
+    };
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLContext context = getSSLContext(trusedCertStr, serverCertStr,
+            serverModulus, serverPrivateExponent, passphrase);
+        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+
+        // enable endpoint identification
+        // ignore, we may test the feature when known how to parse client
+        // hostname
+        //SSLParameters params = sslServerSocket.getSSLParameters();
+        //params.setEndpointIdentificationAlgorithm("HTTPS");
+        //sslServerSocket.setSSLParameters(params);
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        sslSocket.setNeedClientAuth(true);
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write(85);
+        sslOS.flush();
+
+        sslSocket.close();
+
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLContext context = getSSLContext(trusedCertStr, clientCertStr,
+            clientModulus, clientPrivateExponent, passphrase);
+
+        SSLSocketFactory sslsf = context.getSocketFactory();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+
+        // enable endpoint identification
+        SSLParameters params = sslSocket.getSSLParameters();
+        params.setEndpointIdentificationAlgorithm("HTTPS");
+        sslSocket.setSSLParameters(params);
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslOS.write(280);
+        sslOS.flush();
+        sslIS.read();
+
+        sslSocket.close();
+
+    }
+
+    // get the ssl context
+    private static SSLContext getSSLContext(String trusedCertStr,
+            String keyCertStr, byte[] modulus,
+            byte[] privateExponent, char[] passphrase) throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        ByteArrayInputStream is =
+                    new ByteArrayInputStream(trusedCertStr.getBytes());
+        Certificate trusedCert = cf.generateCertificate(is);
+        is.close();
+
+        // create a key store
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        // import the trused cert
+        ks.setCertificateEntry("RSA Export Signer", trusedCert);
+
+        if (keyCertStr != null) {
+            // generate the private key.
+            RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(
+                                            new BigInteger(modulus),
+                                            new BigInteger(privateExponent));
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            RSAPrivateKey priKey =
+                    (RSAPrivateKey)kf.generatePrivate(priKeySpec);
+
+            // generate certificate chain
+            is = new ByteArrayInputStream(keyCertStr.getBytes());
+            Certificate keyCert = cf.generateCertificate(is);
+            is.close();
+
+            Certificate[] chain = new Certificate[2];
+            chain[0] = keyCert;
+            chain[1] = trusedCert;
+
+            // import the key entry.
+            ks.setKeyEntry("Whatever", priKey, passphrase, chain);
+        }
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
+        tmf.init(ks);
+
+        TrustManager tms[] = tmf.getTrustManagers();
+        if (tms == null || tms.length == 0) {
+            throw new Exception("unexpected trust manager implementation");
+        } else {
+           if (!(tms[0] instanceof X509ExtendedTrustManager)) {
+               throw new Exception("unexpected trust manager implementation: "
+                                + tms[0].getClass().getCanonicalName());
+           }
+        }
+
+
+        SSLContext ctx = SSLContext.getInstance("TLS");
+
+        if (keyCertStr != null) {
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+            kmf.init(ks, passphrase);
+
+            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        } else {
+            ctx.init(null, tmf.getTrustManagers(), null);
+        }
+
+        return ctx;
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String args[]) throws Exception {
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new PKIXExtendedTM();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    PKIXExtendedTM() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+