changeset 3005:fdcb0f667b7d

Merge
author alanb
date Tue, 02 Nov 2010 10:15:06 +0000
parents 88462abbf774 9d6a9f65d2bf
children e127cb5c2fbd
files
diffstat 99 files changed, 8823 insertions(+), 1062 deletions(-) [+]
line wrap: on
line diff
--- a/make/java/jli/Makefile	Tue Nov 02 10:07:21 2010 +0000
+++ b/make/java/jli/Makefile	Tue Nov 02 10:15:06 2010 +0000
@@ -148,14 +148,9 @@
 #
 ifeq ($(PLATFORM), windows)
 
-STATIC_LIBRARY_DIR = $(OBJDIR)/static
-STATIC_LIBRARY_NAME = $(LIBPREFIX)$(LIBRARY).lib
-STATIC_LIBRARY = $(STATIC_LIBRARY_DIR)/$(STATIC_LIBRARY_NAME)
+STATIC_LIBRARY = $(OBJDIR)/static/$(LIBPREFIX)$(LIBRARY).lib
 
-$(STATIC_LIBRARY_DIR): $(OBJDIR)
-	@$(MKDIR) $(STATIC_LIBRARY_DIR)
-
-$(STATIC_LIBRARY): $(STATIC_LIBRARY_DIR)
+$(STATIC_LIBRARY): $(FILES_o)
 	@$(prep-target)
 	$(LIBEXE) -nologo -out:$@ $(FILES_o)
 
--- a/src/share/classes/com/sun/crypto/provider/AESCrypt.java	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/com/sun/crypto/provider/AESCrypt.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/com/sun/crypto/provider/DESedeCipher.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/com/sun/crypto/provider/DHPrivateKey.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/com/sun/crypto/provider/DHPublicKey.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/com/sun/crypto/provider/JceKeyStore.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/com/sun/crypto/provider/OAEPParameters.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/com/sun/crypto/provider/SunJCE.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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/java/security/AlgorithmConstraints.java	Tue Nov 02 10:15:06 2010 +0000
@@ -0,0 +1,108 @@
+/*
+ * 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 java.security;
+
+import java.util.Set;
+
+/**
+ * This interface specifies constraints for cryptographic algorithms,
+ * keys (key sizes), and other algorithm parameters.
+ * <p>
+ * {@code AlgorithmConstraints} objects are immutable.  An implementation
+ * of this interface should not provide methods that can change the state
+ * of an instance once it has been created.
+ * <p>
+ * Note that {@code AlgorithmConstraints} can be used to represent the
+ * restrictions described by the security properties
+ * {@code jdk.certpath.disabledAlgorithms} and
+ * {@code jdk.tls.disabledAlgorithms}, or could be used by a
+ * concrete {@code PKIXCertPathChecker} to check whether a specified
+ * certificate in the certification path contains the required algorithm
+ * constraints.
+ *
+ * @see javax.net.ssl.SSLParameters#getAlgorithmConstraints
+ * @see javax.net.ssl.SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+ *
+ * @since 1.7
+ */
+
+public interface AlgorithmConstraints {
+
+    /**
+     * Determines whether an algorithm is granted permission for the
+     * specified cryptographic primitives.
+     *
+     * @param primitives a set of cryptographic primitives
+     * @param algorithm the algorithm name
+     * @param parameters the algorithm parameters, or null if no additional
+     *     parameters
+     *
+     * @return true if the algorithm is permitted and can be used for all
+     *     of the specified cryptographic primitives
+     *
+     * @throws IllegalArgumentException if primitives or algorithm is null
+     *     or empty
+     */
+    public boolean permits(Set<CryptoPrimitive> primitives,
+            String algorithm, AlgorithmParameters parameters);
+
+    /**
+     * Determines whether a key is granted permission for the specified
+     * cryptographic primitives.
+     * <p>
+     * This method is usually used to check key size and key usage.
+     *
+     * @param primitives a set of cryptographic primitives
+     * @param key the key
+     *
+     * @return true if the key can be used for all of the specified
+     *     cryptographic primitives
+     *
+     * @throws IllegalArgumentException if primitives is null or empty,
+     *     or the key is null
+     */
+    public boolean permits(Set<CryptoPrimitive> primitives, Key key);
+
+    /**
+     * Determines whether an algorithm and the corresponding key are granted
+     * permission for the specified cryptographic primitives.
+     *
+     * @param primitives a set of cryptographic primitives
+     * @param algorithm the algorithm name
+     * @param key the key
+     * @param parameters the algorithm parameters, or null if no additional
+     *     parameters
+     *
+     * @return true if the key and the algorithm can be used for all of the
+     *     specified cryptographic primitives
+     *
+     * @throws IllegalArgumentException if primitives or algorithm is null
+     *     or empty, or the key is null
+     */
+    public boolean permits(Set<CryptoPrimitive> primitives,
+                String algorithm, Key key, AlgorithmParameters parameters);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/security/CryptoPrimitive.java	Tue Nov 02 10:15:06 2010 +0000
@@ -0,0 +1,83 @@
+/*
+ * 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 java.security;
+
+/**
+ * An enumeration of cryptographic primitives.
+ *
+ * @since 1.7
+ */
+public enum CryptoPrimitive {
+    /**
+     * Hash function
+     */
+    MESSAGE_DIGEST,
+
+    /**
+     * Cryptographic random number generator
+     */
+    SECURE_RANDOM,
+
+    /**
+     * Symmetric primitive: block cipher
+     */
+    BLOCK_CIPHER,
+
+    /**
+     * Symmetric primitive: stream cipher
+     */
+    STREAM_CIPHER,
+
+    /**
+     * Symmetric primitive: message authentication code
+     */
+    MAC,
+
+    /**
+     * Symmetric primitive: key wrap
+     */
+    KEY_WRAP,
+
+    /**
+     * Asymmetric primitive: public key encryption
+     */
+    PUBLIC_KEY_ENCRYPTION,
+
+    /**
+     * Asymmetric primitive: signature scheme
+     */
+    SIGNATURE,
+
+    /**
+     * Asymmetric primitive: key encapsulation mechanism
+     */
+    KEY_ENCAPSULATION,
+
+    /**
+     * Asymmetric primitive: key agreement and key distribution
+     */
+    KEY_AGREEMENT
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/javax/net/ssl/ExtendedSSLSession.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/javax/net/ssl/HttpsURLConnection.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/javax/net/ssl/SSLEngine.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/javax/net/ssl/SSLParameters.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/javax/net/ssl/SSLServerSocket.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/javax/net/ssl/SSLSocket.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/net/www/protocol/https/HttpsClient.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/internal/interfaces/TlsMasterSecret.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/internal/spec/TlsKeyMaterialSpec.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/internal/spec/TlsPrfParameterSpec.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/pkcs11/SunPKCS11.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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/provider/certpath/AlgorithmChecker.java	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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,95 +25,336 @@
 
 package sun.security.provider.certpath;
 
+import java.security.AlgorithmConstraints;
+import java.security.CryptoPrimitive;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Set;
-import java.util.Collection;
-import java.util.Locale;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.security.KeyFactory;
+import java.security.AlgorithmParameters;
+import java.security.NoSuchAlgorithmException;
+import java.security.GeneralSecurityException;
 import java.security.cert.Certificate;
+import java.security.cert.X509CRL;
 import java.security.cert.X509Certificate;
-import java.security.cert.X509CRL;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.TrustAnchor;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateException;
 import java.security.cert.CertPathValidatorException;
-import java.security.cert.PKIXCertPathChecker;
+import java.io.IOException;
+import java.security.interfaces.*;
+import java.security.spec.*;
 
+import sun.security.util.DisabledAlgorithmConstraints;
+import sun.security.x509.X509CertImpl;
+import sun.security.x509.X509CRLImpl;
 import sun.security.x509.AlgorithmId;
 
 /**
- * AlgorithmChecker is a <code>PKIXCertPathChecker</code> that checks that
- * the signature algorithm of the specified certificate is not disabled.
+ * A <code>PKIXCertPathChecker</code> implementation to check whether a
+ * specified certificate contains the required algorithm constraints.
+ * <p>
+ * Certificate fields such as the subject public key, the signature
+ * algorithm, key usage, extended key usage, etc. need to conform to
+ * the specified algorithm constraints.
  *
- * @author      Xuelei Fan
+ * @see PKIXCertPathChecker
+ * @see PKIXParameters
  */
 final public class AlgorithmChecker extends PKIXCertPathChecker {
 
-    // the disabled algorithms
-    private static final String[] disabledAlgorithms = new String[] {"md2"};
+    private final AlgorithmConstraints constraints;
+    private final PublicKey trustedPubKey;
+    private PublicKey prevPubKey;
 
-    // singleton instance
-    static final AlgorithmChecker INSTANCE = new AlgorithmChecker();
+    private final static Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET =
+                                    EnumSet.of(CryptoPrimitive.SIGNATURE);
+
+    private final static DisabledAlgorithmConstraints
+        certPathDefaultConstraints = new DisabledAlgorithmConstraints(
+            DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
 
     /**
-     * Default Constructor
+     * Create a new <code>AlgorithmChecker</code> with the algorithm
+     * constraints specified in security property
+     * "jdk.certpath.disabledAlgorithms".
+     *
+     * @param anchor the trust anchor selected to validate the target
+     *     certificate
      */
-    private AlgorithmChecker() {
-        // do nothing
+    public AlgorithmChecker(TrustAnchor anchor) {
+        this(anchor, certPathDefaultConstraints);
     }
 
     /**
-     * Return a AlgorithmChecker instance.
+     * Create a new <code>AlgorithmChecker</code> with the
+     * given {@code AlgorithmConstraints}.
+     * <p>
+     * Note that this constructor will be used to check a certification
+     * path where the trust anchor is unknown, or a certificate list which may
+     * contain the trust anchor. This constructor is used by SunJSSE.
+     *
+     * @param constraints the algorithm constraints (or null)
      */
-    static AlgorithmChecker getInstance() {
-        return INSTANCE;
+    public AlgorithmChecker(AlgorithmConstraints constraints) {
+        this.prevPubKey = null;
+        this.trustedPubKey = null;
+        this.constraints = constraints;
     }
 
     /**
-     * Initializes the internal state of the checker from parameters
-     * specified in the constructor.
+     * Create a new <code>AlgorithmChecker</code> with the
+     * given <code>TrustAnchor</code> and <code>AlgorithmConstraints</code>.
+     *
+     * @param anchor the trust anchor selected to validate the target
+     *     certificate
+     * @param constraints the algorithm constraints (or null)
+     *
+     * @throws IllegalArgumentException if the <code>anchor</code> is null
      */
-    public void init(boolean forward) throws CertPathValidatorException {
-        // do nothing
+    public AlgorithmChecker(TrustAnchor anchor,
+            AlgorithmConstraints constraints) {
+
+        if (anchor == null) {
+            throw new IllegalArgumentException(
+                        "The trust anchor cannot be null");
+        }
+
+        if (anchor.getTrustedCert() != null) {
+            this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
+        } else {
+            this.trustedPubKey = anchor.getCAPublicKey();
+        }
+
+        this.prevPubKey = trustedPubKey;
+        this.constraints = constraints;
     }
 
+    @Override
+    public void init(boolean forward) throws CertPathValidatorException {
+        //  Note that this class does not support forward mode.
+        if (!forward) {
+            if (trustedPubKey != null) {
+                prevPubKey = trustedPubKey;
+            } else {
+                prevPubKey = null;
+            }
+        } else {
+            throw new
+                CertPathValidatorException("forward checking not supported");
+        }
+    }
+
+    @Override
     public boolean isForwardCheckingSupported() {
+        //  Note that as this class does not support forward mode, the method
+        //  will always returns false.
         return false;
     }
 
+    @Override
     public Set<String> getSupportedExtensions() {
         return null;
     }
 
-    /**
-     * Checks the signature algorithm of the specified certificate.
-     */
-    public void check(Certificate cert, Collection<String> unresolvedCritExts)
+    @Override
+    public void check(Certificate cert,
+            Collection<String> unresolvedCritExts)
             throws CertPathValidatorException {
-        check(cert);
+
+        if (!(cert instanceof X509Certificate) || constraints == null) {
+            // ignore the check for non-x.509 certificate or null constraints
+            return;
+        }
+
+        X509CertImpl x509Cert = null;
+        try {
+            x509Cert = X509CertImpl.toImpl((X509Certificate)cert);
+        } catch (CertificateException ce) {
+            throw new CertPathValidatorException(ce);
+        }
+
+        PublicKey currPubKey = x509Cert.getPublicKey();
+        String currSigAlg = x509Cert.getSigAlgName();
+
+        AlgorithmId algorithmId = null;
+        try {
+            algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG);
+        } catch (CertificateException ce) {
+            throw new CertPathValidatorException(ce);
+        }
+
+        AlgorithmParameters currSigAlgParams = algorithmId.getParameters();
+
+        // Check the current signature algorithm
+        if (!constraints.permits(
+                SIGNATURE_PRIMITIVE_SET,
+                currSigAlg, currSigAlgParams)) {
+            throw new CertPathValidatorException(
+                "Algorithm constraints check failed: " + currSigAlg);
+        }
+
+        // check the key usage and key size
+        boolean[] keyUsage = x509Cert.getKeyUsage();
+        if (keyUsage != null && keyUsage.length < 9) {
+            throw new CertPathValidatorException(
+                        "incorrect KeyUsage extension");
+        }
+
+        if (keyUsage != null) {
+            Set<CryptoPrimitive> primitives =
+                        EnumSet.noneOf(CryptoPrimitive.class);
+
+            if (keyUsage[0] || keyUsage[1] || keyUsage[5] || keyUsage[6]) {
+                // keyUsage[0]: KeyUsage.digitalSignature
+                // keyUsage[1]: KeyUsage.nonRepudiation
+                // keyUsage[5]: KeyUsage.keyCertSign
+                // keyUsage[6]: KeyUsage.cRLSign
+                primitives.add(CryptoPrimitive.SIGNATURE);
+            }
+
+            if (keyUsage[2]) {      // KeyUsage.keyEncipherment
+                primitives.add(CryptoPrimitive.KEY_ENCAPSULATION);
+            }
+
+            if (keyUsage[3]) {      // KeyUsage.dataEncipherment
+                primitives.add(CryptoPrimitive.PUBLIC_KEY_ENCRYPTION);
+            }
+
+            if (keyUsage[4]) {      // KeyUsage.keyAgreement
+                primitives.add(CryptoPrimitive.KEY_AGREEMENT);
+            }
+
+            // KeyUsage.encipherOnly and KeyUsage.decipherOnly are
+            // undefined in the absence of the keyAgreement bit.
+
+            if (!primitives.isEmpty()) {
+                if (!constraints.permits(primitives, currPubKey)) {
+                    throw new CertPathValidatorException(
+                        "algorithm constraints check failed");
+                }
+            }
+        }
+
+        // Check with previous cert for signature algorithm and public key
+        if (prevPubKey != null) {
+            if (currSigAlg != null) {
+                if (!constraints.permits(
+                        SIGNATURE_PRIMITIVE_SET,
+                        currSigAlg, prevPubKey, currSigAlgParams)) {
+                    throw new CertPathValidatorException(
+                        "Algorithm constraints check failed: " + currSigAlg);
+                }
+            }
+
+            // Inherit key parameters from previous key
+            if (currPubKey instanceof DSAPublicKey &&
+                ((DSAPublicKey)currPubKey).getParams() == null) {
+                // Inherit DSA parameters from previous key
+                if (!(prevPubKey instanceof DSAPublicKey)) {
+                    throw new CertPathValidatorException("Input key is not " +
+                         "of a appropriate type for inheriting parameters");
+                }
+
+                DSAParams params = ((DSAPublicKey)prevPubKey).getParams();
+                if (params == null) {
+                    throw new CertPathValidatorException(
+                                    "Key parameters missing");
+                }
+
+                try {
+                    BigInteger y = ((DSAPublicKey)currPubKey).getY();
+                    KeyFactory kf = KeyFactory.getInstance("DSA");
+                    DSAPublicKeySpec ks = new DSAPublicKeySpec(y,
+                                                       params.getP(),
+                                                       params.getQ(),
+                                                       params.getG());
+                    currPubKey = kf.generatePublic(ks);
+                } catch (GeneralSecurityException e) {
+                    throw new CertPathValidatorException("Unable to generate " +
+                        "key with inherited parameters: " + e.getMessage(), e);
+                }
+            }
+        }
+
+        // reset the previous public key
+        prevPubKey = currPubKey;
+
+        // check the extended key usage, ignore the check now
+        // List<String> extendedKeyUsages = x509Cert.getExtendedKeyUsage();
+
+        // DO NOT remove any unresolved critical extensions
     }
 
-    public static void check(Certificate cert)
-            throws CertPathValidatorException {
-        X509Certificate xcert = (X509Certificate)cert;
-        check(xcert.getSigAlgName());
-    }
+    /**
+     * Try to set the trust anchor of the checker.
+     * <p>
+     * If there is no trust anchor specified and the checker has not started,
+     * set the trust anchor.
+     *
+     * @param anchor the trust anchor selected to validate the target
+     *     certificate
+     */
+    void trySetTrustAnchor(TrustAnchor anchor) {
+        // Don't bother if the check has started or trust anchor has already
+        // specified.
+        if (prevPubKey == null) {
+            if (anchor == null) {
+                throw new IllegalArgumentException(
+                        "The trust anchor cannot be null");
+            }
 
-    static void check(AlgorithmId aid) throws CertPathValidatorException {
-        check(aid.getName());
-    }
-
-    static void check(X509CRL crl) throws CertPathValidatorException {
-        check(crl.getSigAlgName());
-    }
-
-    private static void check(String algName)
-            throws CertPathValidatorException {
-
-        String lowerCaseAlgName = algName.toLowerCase(Locale.ENGLISH);
-
-        for (String disabled : disabledAlgorithms) {
-            // checking the signature algorithm name
-            if (lowerCaseAlgName.indexOf(disabled) != -1) {
-                throw new CertPathValidatorException(
-                    "algorithm check failed: " + algName + " is disabled");
+            // Don't bother to change the trustedPubKey.
+            if (anchor.getTrustedCert() != null) {
+                prevPubKey = anchor.getTrustedCert().getPublicKey();
+            } else {
+                prevPubKey = anchor.getCAPublicKey();
             }
         }
     }
 
+    /**
+     * Check the signature algorithm with the specified public key.
+     *
+     * @param key the public key to verify the CRL signature
+     * @param crl the target CRL
+     */
+    static void check(PublicKey key, X509CRL crl)
+                        throws CertPathValidatorException {
+
+        X509CRLImpl x509CRLImpl = null;
+        try {
+            x509CRLImpl = X509CRLImpl.toImpl(crl);
+        } catch (CRLException ce) {
+            throw new CertPathValidatorException(ce);
+        }
+
+        AlgorithmId algorithmId = x509CRLImpl.getSigAlgId();
+        check(key, algorithmId);
+    }
+
+    /**
+     * Check the signature algorithm with the specified public key.
+     *
+     * @param key the public key to verify the CRL signature
+     * @param crl the target CRL
+     */
+    static void check(PublicKey key, AlgorithmId algorithmId)
+                        throws CertPathValidatorException {
+        String sigAlgName = algorithmId.getName();
+        AlgorithmParameters sigAlgParams = algorithmId.getParameters();
+
+        if (!certPathDefaultConstraints.permits(
+                SIGNATURE_PRIMITIVE_SET, sigAlgName, key, sigAlgParams)) {
+            throw new CertPathValidatorException(
+                "algorithm check failed: " + sigAlgName + " is disabled");
+        }
+    }
+
 }
+
--- a/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java	Tue Nov 02 10:15:06 2010 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2009, 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
@@ -289,16 +289,6 @@
         X500Name certIssuer = (X500Name) certImpl.getIssuerDN();
         X500Name crlIssuer = (X500Name) crlImpl.getIssuerDN();
 
-        // check the crl signature algorithm
-        try {
-            AlgorithmChecker.check(crl);
-        } catch (CertPathValidatorException cpve) {
-            if (debug != null) {
-                debug.println("CRL signature algorithm check failed: " + cpve);
-            }
-            return false;
-        }
-
         // if crlIssuer is set, verify that it matches the issuer of the
         // CRL and the CRL contains an IDP extension with the indirectCRL
         // boolean asserted. Otherwise, verify that the CRL issuer matches the
@@ -637,6 +627,16 @@
             }
         }
 
+        // check the crl signature algorithm
+        try {
+            AlgorithmChecker.check(prevKey, crl);
+        } catch (CertPathValidatorException cpve) {
+            if (debug != null) {
+                debug.println("CRL signature algorithm check failed: " + cpve);
+            }
+            return false;
+        }
+
         // validate the signature on the CRL
         try {
             crl.verify(prevKey, provider);
--- a/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java	Tue Nov 02 10:15:06 2010 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -719,11 +719,6 @@
         /* we don't perform any validation of the trusted cert */
         if (!isTrustedCert) {
             /*
-             * check that the signature algorithm is not disabled.
-             */
-            AlgorithmChecker.check(cert);
-
-            /*
              * Check CRITICAL private extensions for user checkers that
              * support forward checking (forwardCheckers) and remove
              * ones we know how to check.
--- a/src/share/classes/sun/security/provider/certpath/OCSPChecker.java	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/provider/certpath/OCSPChecker.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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
@@ -327,6 +327,10 @@
                 "(set using the OCSP security properties).");
         }
 
+        // The algorithm constraints of the OCSP trusted responder certificate
+        // does not need to be checked in this code. The constraints will be
+        // checked when the responder's certificate is validated.
+
         CertId certId = null;
         OCSPResponse response = null;
         try {
--- a/src/share/classes/sun/security/provider/certpath/OCSPResponse.java	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/provider/certpath/OCSPResponse.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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
@@ -32,6 +32,7 @@
 import java.security.cert.CertificateParsingException;
 import java.security.cert.CertPathValidatorException;
 import java.security.cert.CRLReason;
+import java.security.cert.TrustAnchor;
 import java.security.cert.X509Certificate;
 import java.util.Collections;
 import java.util.Date;
@@ -371,6 +372,13 @@
                         "OCSP responses", cpe);
                 }
 
+                // Check algorithm constraints specified in security property
+                // "jdk.certpath.disabledAlgorithms".
+                AlgorithmChecker algChecker = new AlgorithmChecker(
+                                    new TrustAnchor(responderCert, null));
+                algChecker.init(false);
+                algChecker.check(cert, Collections.<String>emptySet());
+
                 // check the validity
                 try {
                     if (dateCheckedAgainst == null) {
@@ -422,6 +430,10 @@
         // Confirm that the signed response was generated using the public
         // key from the trusted responder cert
         if (responderCert != null) {
+            // Check algorithm constraints specified in security property
+            // "jdk.certpath.disabledAlgorithms".
+            AlgorithmChecker.check(responderCert.getPublicKey(), sigAlgId);
+
             if (!verifyResponse(responseDataDer, responderCert,
                 sigAlgId, signature)) {
                 throw new CertPathValidatorException(
--- a/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java	Tue Nov 02 10:15:06 2010 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -275,7 +275,7 @@
         int certPathLen = certList.size();
 
         basicChecker = new BasicChecker(anchor, testDate, sigProvider, false);
-        AlgorithmChecker algorithmChecker= AlgorithmChecker.getInstance();
+        AlgorithmChecker algorithmChecker = new AlgorithmChecker(anchor);
         KeyChecker keyChecker = new KeyChecker(certPathLen,
             pkixParam.getTargetCertConstraints());
         ConstraintsChecker constraintsChecker =
--- a/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java	Tue Nov 02 10:15:06 2010 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -347,9 +347,6 @@
             return;
         }
 
-        /* check that the signature algorithm is not disabled. */
-        AlgorithmChecker.check(cert);
-
         /*
          * check for looping - abort a loop if
          * ((we encounter the same certificate twice) AND
@@ -470,9 +467,16 @@
         if (unresolvedCritExts == null) {
             unresolvedCritExts = Collections.<String>emptySet();
         }
+
+        /*
+         * Check that the signature algorithm is not disabled.
+         */
+        currentState.algorithmChecker.check(cert, unresolvedCritExts);
+
         for (PKIXCertPathChecker checker : currentState.userCheckers) {
             checker.check(cert, unresolvedCritExts);
         }
+
         /*
          * Look at the remaining extensions and remove any ones we have
          * already checked. If there are any left, throw an exception!
--- a/src/share/classes/sun/security/provider/certpath/ReverseState.java	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/provider/certpath/ReverseState.java	Tue Nov 02 10:15:06 2010 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -96,6 +96,9 @@
     /* the checker used for revocation status */
     public CrlRevocationChecker crlChecker;
 
+    /* the algorithm checker */
+    AlgorithmChecker algorithmChecker;
+
     /* the trust anchor used to validate the path */
     TrustAnchor trustAnchor;
 
@@ -241,6 +244,14 @@
             updateState(anchor.getCAPublicKey(), caName);
         }
 
+        // The user specified AlgorithmChecker may not be
+        // able to set the trust anchor until now.
+        for (PKIXCertPathChecker checker : userCheckers) {
+            if (checker instanceof AlgorithmChecker) {
+                ((AlgorithmChecker)checker).trySetTrustAnchor(anchor);
+            }
+        }
+
         init = false;
     }
 
--- a/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java	Tue Nov 02 10:15:06 2010 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -302,6 +302,7 @@
             // init the crl checker
             currentState.crlChecker =
                 new CrlRevocationChecker(null, buildParams, null, onlyEECert);
+            currentState.algorithmChecker = new AlgorithmChecker(anchor);
             try {
                 depthFirstSearchReverse(null, currentState,
                 new ReverseBuilder(buildParams, targetSubjectDN), adjacencyList,
@@ -475,29 +476,41 @@
                 userCheckers.add(mustCheck, policyChecker);
                 mustCheck++;
 
+                // add the algorithm checker
+                userCheckers.add(mustCheck,
+                        new AlgorithmChecker(builder.trustAnchor));
+                mustCheck++;
+
                 if (nextState.keyParamsNeeded()) {
                     PublicKey rootKey = cert.getPublicKey();
                     if (builder.trustAnchor.getTrustedCert() == null) {
                         rootKey = builder.trustAnchor.getCAPublicKey();
                         if (debug != null)
-                            debug.println("SunCertPathBuilder.depthFirstSearchForward" +
-                                          " using buildParams public key: " +
-                                          rootKey.toString());
+                            debug.println(
+                                "SunCertPathBuilder.depthFirstSearchForward " +
+                                "using buildParams public key: " +
+                                rootKey.toString());
                     }
                     TrustAnchor anchor = new TrustAnchor
                         (cert.getSubjectX500Principal(), rootKey, null);
+
+                    // add the basic checker
                     basicChecker = new BasicChecker(anchor,
                                            builder.date,
                                            buildParams.getSigProvider(),
                                            true);
                     userCheckers.add(mustCheck, basicChecker);
                     mustCheck++;
+
+                    // add the crl revocation checker
                     if (buildParams.isRevocationEnabled()) {
                         userCheckers.add(mustCheck, new CrlRevocationChecker
                             (anchor, buildParams, null, onlyEECert));
                         mustCheck++;
                     }
                 }
+                // Why we don't need BasicChecker and CrlRevocationChecker
+                // if nextState.keyParamsNeeded() is false?
 
                 for (int i=0; i<appendedCerts.size(); i++) {
                     X509Certificate currCert = appendedCerts.get(i);
@@ -513,10 +526,18 @@
                     for (int j=0; j<userCheckers.size(); j++) {
                         PKIXCertPathChecker currChecker = userCheckers.get(j);
                         if (j < mustCheck ||
-                            !currChecker.isForwardCheckingSupported())
-                        {
+                            !currChecker.isForwardCheckingSupported()) {
                             if (i == 0) {
                                 currChecker.init(false);
+
+                                // The user specified
+                                // AlgorithmChecker may not be
+                                // able to set the trust anchor until now.
+                                if (j >= mustCheck &&
+                                    currChecker instanceof AlgorithmChecker) {
+                                    ((AlgorithmChecker)currChecker).
+                                        trySetTrustAnchor(builder.trustAnchor);
+                                }
                             }
 
                             try {
--- a/src/share/classes/sun/security/rsa/RSASignature.java	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/rsa/RSASignature.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/CipherSuite.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/ClientHandshaker.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/HandshakeHash.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/HandshakeMessage.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/Handshaker.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/HelloExtensions.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/MAC.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/ProtocolList.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/ProtocolVersion.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/SSLContextImpl.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/SSLEngineImpl.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/SSLSessionImpl.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/SSLSocketImpl.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/ServerHandshaker.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/SunJSSE.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/TrustManagerFactoryImpl.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/X509KeyManagerImpl.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/ssl/X509TrustManagerImpl.java	Tue Nov 02 10:15:06 2010 +0000
@@ -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 {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java	Tue Nov 02 10:15:06 2010 +0000
@@ -0,0 +1,486 @@
+/*
+ * 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.util;
+
+import java.security.AlgorithmConstraints;
+import java.security.CryptoPrimitive;
+import java.security.AlgorithmParameters;
+
+import java.security.Key;
+import java.security.Security;
+import java.security.PrivilegedAction;
+import java.security.AccessController;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.RSAKey;
+import java.security.interfaces.DSAKey;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.DHKey;
+
+import java.util.Locale;
+import java.util.Set;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+/**
+ * Algorithm constraints for disabled algorithms property
+ *
+ * See the "jdk.certpath.disabledAlgorithms" specification in java.security
+ * for the syntax of the disabled algorithm string.
+ */
+public class DisabledAlgorithmConstraints implements AlgorithmConstraints {
+
+    // the known security property, jdk.certpath.disabledAlgorithms
+    public final static String PROPERTY_CERTPATH_DISABLED_ALGS =
+            "jdk.certpath.disabledAlgorithms";
+
+    // the known security property, jdk.tls.disabledAlgorithms
+    public final static String PROPERTY_TLS_DISABLED_ALGS =
+            "jdk.tls.disabledAlgorithms";
+
+    private static Map<String, String[]> disabledAlgorithmsMap =
+            Collections.synchronizedMap(new HashMap<String, String[]>());
+    private static Map<String, KeySizeConstraints> keySizeConstraintsMap =
+        Collections.synchronizedMap(new HashMap<String, KeySizeConstraints>());
+
+    private String[] disabledAlgorithms;
+    private KeySizeConstraints keySizeConstraints;
+
+    /**
+     * Initialize algorithm constraints with the specified security property.
+     *
+     * @param propertyName the security property name that define the disabled
+     *        algorithm constraints
+     */
+    public DisabledAlgorithmConstraints(String propertyName) {
+        synchronized (disabledAlgorithmsMap) {
+            if(!disabledAlgorithmsMap.containsKey(propertyName)) {
+                loadDisabledAlgorithmsMap(propertyName);
+            }
+
+            disabledAlgorithms = disabledAlgorithmsMap.get(propertyName);
+            keySizeConstraints = keySizeConstraintsMap.get(propertyName);
+        }
+    }
+
+    @Override
+    final 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");
+        }
+
+        Set<String> elements = null;
+        for (String disabled : disabledAlgorithms) {
+            if (disabled == null || disabled.isEmpty()) {
+                continue;
+            }
+
+            // check the full name
+            if (disabled.equalsIgnoreCase(algorithm)) {
+                return false;
+            }
+
+            // decompose the algorithm into sub-elements
+            if (elements == null) {
+                elements = decomposes(algorithm);
+            }
+
+            // check the items of the algorithm
+            for (String element : elements) {
+                if (disabled.equalsIgnoreCase(element)) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    @Override
+    final public boolean permits(Set<CryptoPrimitive> primitives, Key key) {
+        return checkConstraints(primitives, "", key, null);
+    }
+
+    @Override
+    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 checkConstraints(primitives, algorithm, key, parameters);
+    }
+
+    /**
+     * Decompose the standard algorithm name into sub-elements.
+     * <p>
+     * For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA"
+     * so that we can check the "SHA1" and "RSA" algorithm constraints
+     * separately.
+     * <p>
+     * Please override the method if need to support more name pattern.
+     */
+    protected Set<String> decomposes(String algorithm) {
+        if (algorithm == null || algorithm.length() == 0) {
+            return new HashSet<String>();
+        }
+
+        // algorithm/mode/padding
+        Pattern transPattern = Pattern.compile("/");
+        String[] transTockens = transPattern.split(algorithm);
+
+        Set<String> elements = new HashSet<String>();
+        for (String transTocken : transTockens) {
+            if (transTocken == null || transTocken.length() == 0) {
+                continue;
+            }
+
+            // PBEWith<digest>And<encryption>
+            // PBEWith<prf>And<encryption>
+            // OAEPWith<digest>And<mgf>Padding
+            // <digest>with<encryption>
+            // <digest>with<encryption>and<mgf>
+            Pattern pattern =
+                    Pattern.compile("with|and", Pattern.CASE_INSENSITIVE);
+            String[] tokens = pattern.split(transTocken);
+
+            for (String token : tokens) {
+                if (token == null || token.length() == 0) {
+                    continue;
+                }
+
+                elements.add(token);
+            }
+        }
+
+        // In Java standard algorithm name specification, for different
+        // purpose, the SHA-1 and SHA-2 algorithm names are different. For
+        // example, for MessageDigest, the standard name is "SHA-256", while
+        // for Signature, the digest algorithm component is "SHA256" for
+        // signature algorithm "SHA256withRSA". So we need to check both
+        // "SHA-256" and "SHA256" to make the right constraint checking.
+
+        // handle special name: SHA-1 and SHA1
+        if (elements.contains("SHA1") && !elements.contains("SHA-1")) {
+            elements.add("SHA-1");
+        }
+        if (elements.contains("SHA-1") && !elements.contains("SHA1")) {
+            elements.add("SHA1");
+        }
+
+        // handle special name: SHA-224 and SHA224
+        if (elements.contains("SHA224") && !elements.contains("SHA-224")) {
+            elements.add("SHA-224");
+        }
+        if (elements.contains("SHA-224") && !elements.contains("SHA224")) {
+            elements.add("SHA224");
+        }
+
+        // handle special name: SHA-256 and SHA256
+        if (elements.contains("SHA256") && !elements.contains("SHA-256")) {
+            elements.add("SHA-256");
+        }
+        if (elements.contains("SHA-256") && !elements.contains("SHA256")) {
+            elements.add("SHA256");
+        }
+
+        // handle special name: SHA-384 and SHA384
+        if (elements.contains("SHA384") && !elements.contains("SHA-384")) {
+            elements.add("SHA-384");
+        }
+        if (elements.contains("SHA-384") && !elements.contains("SHA384")) {
+            elements.add("SHA384");
+        }
+
+        // handle special name: SHA-512 and SHA512
+        if (elements.contains("SHA512") && !elements.contains("SHA-512")) {
+            elements.add("SHA-512");
+        }
+        if (elements.contains("SHA-512") && !elements.contains("SHA512")) {
+            elements.add("SHA512");
+        }
+
+        return elements;
+    }
+
+    // Check algorithm constraints
+    private boolean checkConstraints(Set<CryptoPrimitive> primitives,
+            String algorithm, Key key, AlgorithmParameters parameters) {
+
+        // check the key parameter, it cannot be null.
+        if (key == null) {
+            throw new IllegalArgumentException("The key cannot be null");
+        }
+
+        // check the target algorithm
+        if (algorithm != null && algorithm.length() != 0) {
+            if (!permits(primitives, algorithm, parameters)) {
+                return false;
+            }
+        }
+
+        // check the key algorithm
+        if (!permits(primitives, key.getAlgorithm(), null)) {
+            return false;
+        }
+
+        // check the key constraints
+        if (keySizeConstraints.disables(key)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    // Get disabled algorithm constraints from the specified security property.
+    private static void loadDisabledAlgorithmsMap(
+            final String propertyName) {
+
+        String property = AccessController.doPrivileged(
+            new PrivilegedAction<String>() {
+                public String run() {
+                    return Security.getProperty(propertyName);
+                }
+            });
+
+        String[] algorithmsInProperty = null;
+
+        if (property != null && !property.isEmpty()) {
+
+            // remove double quote marks from beginning/end of the property
+            if (property.charAt(0) == '"' &&
+                    property.charAt(property.length() - 1) == '"') {
+                property = property.substring(1, property.length() - 1);
+            }
+
+            algorithmsInProperty = property.split(",");
+            for (int i = 0; i < algorithmsInProperty.length; i++) {
+                algorithmsInProperty[i] = algorithmsInProperty[i].trim();
+            }
+        }
+
+        // map the disabled algorithms
+        if (algorithmsInProperty == null) {
+            algorithmsInProperty = new String[0];
+        }
+        disabledAlgorithmsMap.put(propertyName, algorithmsInProperty);
+
+        // map the key constraints
+        KeySizeConstraints keySizeConstraints =
+            new KeySizeConstraints(algorithmsInProperty);
+        keySizeConstraintsMap.put(propertyName, keySizeConstraints);
+    }
+
+    /**
+     * key constraints
+     */
+    private static class KeySizeConstraints {
+        private static final Pattern pattern = Pattern.compile(
+                "(\\S+)\\s+keySize\\s*(<=|<|==|!=|>|>=)\\s*(\\d+)");
+
+        private Map<String, Set<KeySizeConstraint>> constraintsMap =
+            Collections.synchronizedMap(
+                        new HashMap<String, Set<KeySizeConstraint>>());
+
+        public KeySizeConstraints(String[] restrictions) {
+            for (String restriction : restrictions) {
+                if (restriction == null || restriction.isEmpty()) {
+                    continue;
+                }
+
+                Matcher matcher = pattern.matcher(restriction);
+                if (matcher.matches()) {
+                    String algorithm = matcher.group(1);
+
+                    KeySizeConstraint.Operator operator =
+                             KeySizeConstraint.Operator.of(matcher.group(2));
+                    int length = Integer.parseInt(matcher.group(3));
+
+                    algorithm = algorithm.toLowerCase(Locale.ENGLISH);
+
+                    synchronized (constraintsMap) {
+                        if (!constraintsMap.containsKey(algorithm)) {
+                            constraintsMap.put(algorithm,
+                                new HashSet<KeySizeConstraint>());
+                        }
+
+                        Set<KeySizeConstraint> constraintSet =
+                            constraintsMap.get(algorithm);
+                        KeySizeConstraint constraint =
+                            new KeySizeConstraint(operator, length);
+                        constraintSet.add(constraint);
+                    }
+                }
+            }
+        }
+
+        // Does this KeySizeConstraints disable the specified key?
+        public boolean disables(Key key) {
+            String algorithm = key.getAlgorithm().toLowerCase(Locale.ENGLISH);
+            synchronized (constraintsMap) {
+                if (constraintsMap.containsKey(algorithm)) {
+                    Set<KeySizeConstraint> constraintSet =
+                                        constraintsMap.get(algorithm);
+                    for (KeySizeConstraint constraint : constraintSet) {
+                        if (constraint.disables(key)) {
+                            return true;
+                        }
+                    }
+                }
+            }
+
+            return false;
+        }
+    }
+
+    /**
+     * Key size constraint.
+     *
+     * e.g.  "keysize <= 1024"
+     */
+    private static class KeySizeConstraint {
+        // operator
+        static enum Operator {
+            EQ,         // "=="
+            NE,         // "!="
+            LT,         // "<"
+            LE,         // "<="
+            GT,         // ">"
+            GE;         // ">="
+
+            static Operator of(String s) {
+                switch (s) {
+                    case "==":
+                        return EQ;
+                    case "!=":
+                        return NE;
+                    case "<":
+                        return LT;
+                    case "<=":
+                        return LE;
+                    case ">":
+                        return GT;
+                    case ">=":
+                        return GE;
+                }
+
+                throw new IllegalArgumentException(
+                        s + " is not a legal Operator");
+            }
+        }
+
+        private int minSize;            // the minimal available key size
+        private int maxSize;            // the maximal available key size
+        private int prohibitedSize = -1;    // unavailable key sizes
+
+        public KeySizeConstraint(Operator operator, int length) {
+            switch (operator) {
+                case EQ:      // an unavailable key size
+                    this.minSize = 0;
+                    this.maxSize = Integer.MAX_VALUE;
+                    prohibitedSize = length;
+                    break;
+                case NE:
+                    this.minSize = length;
+                    this.maxSize = length;
+                    break;
+                case LT:
+                    this.minSize = length;
+                    this.maxSize = Integer.MAX_VALUE;
+                    break;
+                case LE:
+                    this.minSize = length + 1;
+                    this.maxSize = Integer.MAX_VALUE;
+                    break;
+                case GT:
+                    this.minSize = 0;
+                    this.maxSize = length;
+                    break;
+                case GE:
+                    this.minSize = 0;
+                    this.maxSize = length > 1 ? (length - 1) : 0;
+                    break;
+                default:
+                    // unlikely to happen
+                    this.minSize = Integer.MAX_VALUE;
+                    this.maxSize = -1;
+            }
+        }
+
+        // Does this key constraint disable the specified key?
+        public boolean disables(Key key) {
+            int size = -1;
+
+            // it is a SecretKey
+            if (key instanceof SecretKey) {
+                SecretKey sk = (SecretKey)key;
+                if (sk.getFormat().equals("RAW") && sk.getEncoded() != null) {
+                    size = sk.getEncoded().length * 8;
+
+                }
+            }
+
+            // it is an asymmetric key
+            if (key instanceof RSAKey) {
+                RSAKey pubk = (RSAKey)key;
+                size = pubk.getModulus().bitLength();
+            } else if (key instanceof ECKey) {
+                ECKey pubk = (ECKey)key;
+                size = pubk.getParams().getOrder().bitLength();
+            } else if (key instanceof DSAKey) {
+                DSAKey pubk = (DSAKey)key;
+                size = pubk.getParams().getP().bitLength();
+            } else if (key instanceof DHKey) {
+                DHKey pubk = (DHKey)key;
+                size = pubk.getParams().getP().bitLength();
+            } // else, it is not a key we know.
+
+            if (size == 0) {
+                return true;    // we don't allow any key of size 0.
+            }
+
+            if (size >= 0) {
+                return ((size < minSize) || (size > maxSize) ||
+                    (prohibitedSize == size));
+            }
+
+            return false;
+        }
+    }
+
+}
+
--- a/src/share/classes/sun/security/validator/PKIXValidator.java	Tue Nov 02 10:07:21 2010 +0000
+++ b/src/share/classes/sun/security/validator/PKIXValidator.java	Tue Nov 02 10:15:06 2010 +0000
@@ -31,20 +31,35 @@
 import java.security.cert.*;
 
 import javax.security.auth.x500.X500Principal;
+import sun.security.action.GetBooleanAction;
+import sun.security.provider.certpath.AlgorithmChecker;
 
 /**
  * Validator implementation built on the PKIX CertPath API. This
  * implementation will be emphasized going forward.<p>
- *
+ * <p>
  * Note that the validate() implementation tries to use a PKIX validator
  * if that appears possible and a PKIX builder otherwise. This increases
  * performance and currently also leads to better exception messages
  * in case of failures.
+ * <p>
+ * {@code PKIXValidator} objects are immutable once they have been created.
+ * Please DO NOT add methods that can change the state of an instance once
+ * it has been created.
  *
  * @author Andreas Sterbenz
  */
 public final class PKIXValidator extends Validator {
 
+    /**
+     * 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 checkTLSRevocation =
+        AccessController.doPrivileged
+            (new GetBooleanAction("com.sun.net.ssl.checkRevocation"));
+
     // enable use of the validator if possible
     private final static boolean TRY_VALIDATOR = true;
 
@@ -53,10 +68,10 @@
     private int certPathLength = -1;
 
     // needed only for the validator
-    private Map<X500Principal, List<PublicKey>> trustedSubjects;
-    private CertificateFactory factory;
+    private final Map<X500Principal, List<PublicKey>> trustedSubjects;
+    private final CertificateFactory factory;
 
-    private boolean plugin = false;
+    private final boolean plugin;
 
     PKIXValidator(String variant, Collection<X509Certificate> trustedCerts) {
         super(TYPE_PKIX, variant);
@@ -75,7 +90,33 @@
             throw new RuntimeException("Unexpected error: " + e.toString(), e);
         }
         setDefaultParameters(variant);
-        initCommon();
+
+        // initCommon();
+        if (TRY_VALIDATOR) {
+            if (TRY_VALIDATOR == false) {
+                return;
+            }
+            trustedSubjects = new HashMap<X500Principal, List<PublicKey>>();
+            for (X509Certificate cert : trustedCerts) {
+                X500Principal dn = cert.getSubjectX500Principal();
+                List<PublicKey> keys;
+                if (trustedSubjects.containsKey(dn)) {
+                    keys = trustedSubjects.get(dn);
+                } else {
+                    keys = new ArrayList<PublicKey>();
+                    trustedSubjects.put(dn, keys);
+                }
+                keys.add(cert.getPublicKey());
+            }
+            try {
+                factory = CertificateFactory.getInstance("X.509");
+            } catch (CertificateException e) {
+                throw new RuntimeException("Internal error", e);
+            }
+            plugin = variant.equals(VAR_PLUGIN_CODE_SIGNING);
+        } else {
+            plugin = false;
+        }
     }
 
     PKIXValidator(String variant, PKIXBuilderParameters params) {
@@ -88,31 +129,33 @@
             }
         }
         parameterTemplate = params;
-        initCommon();
-    }
 
-    private void initCommon() {
-        if (TRY_VALIDATOR == false) {
-            return;
+        // initCommon();
+        if (TRY_VALIDATOR) {
+            if (TRY_VALIDATOR == false) {
+                return;
+            }
+            trustedSubjects = new HashMap<X500Principal, List<PublicKey>>();
+            for (X509Certificate cert : trustedCerts) {
+                X500Principal dn = cert.getSubjectX500Principal();
+                List<PublicKey> keys;
+                if (trustedSubjects.containsKey(dn)) {
+                    keys = trustedSubjects.get(dn);
+                } else {
+                    keys = new ArrayList<PublicKey>();
+                    trustedSubjects.put(dn, keys);
+                }
+                keys.add(cert.getPublicKey());
+            }
+            try {
+                factory = CertificateFactory.getInstance("X.509");
+            } catch (CertificateException e) {
+                throw new RuntimeException("Internal error", e);
+            }
+            plugin = variant.equals(VAR_PLUGIN_CODE_SIGNING);
+        } else {
+            plugin = false;
         }
-        trustedSubjects = new HashMap<X500Principal, List<PublicKey>>();
-        for (X509Certificate cert : trustedCerts) {
-            X500Principal dn = cert.getSubjectX500Principal();
-            List<PublicKey> keys;
-            if (trustedSubjects.containsKey(dn)) {
-                keys = trustedSubjects.get(dn);
-            } else {
-                keys = new ArrayList<PublicKey>();
-                trustedSubjects.put(dn, keys);
-            }