changeset 3003:93cd7e89adb8

4873188: Support TLS 1.1 Reviewed-by: wetmore, weijun
author xuelei
date Sat, 30 Oct 2010 18:39:17 +0800
parents 7fee717f4707
children d26730767789 5a6c63deacf3
files src/share/classes/javax/net/ssl/SSLSocketFactory.java src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java src/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java src/share/classes/sun/security/ssl/CipherBox.java src/share/classes/sun/security/ssl/CipherSuite.java src/share/classes/sun/security/ssl/ClientHandshaker.java src/share/classes/sun/security/ssl/Debug.java src/share/classes/sun/security/ssl/HandshakeMessage.java src/share/classes/sun/security/ssl/Handshaker.java src/share/classes/sun/security/ssl/KerberosClientKeyExchange.java src/share/classes/sun/security/ssl/MAC.java src/share/classes/sun/security/ssl/ProtocolList.java src/share/classes/sun/security/ssl/ProtocolVersion.java src/share/classes/sun/security/ssl/RSAClientKeyExchange.java src/share/classes/sun/security/ssl/Record.java src/share/classes/sun/security/ssl/SSLEngineImpl.java src/share/classes/sun/security/ssl/SSLServerSocketImpl.java src/share/classes/sun/security/ssl/SSLSocketImpl.java src/share/classes/sun/security/ssl/ServerHandshaker.java src/share/classes/sun/security/ssl/SunJSSE.java src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java test/sun/security/pkcs11/fips/CipherTest.java test/sun/security/pkcs11/sslecc/CipherTest.java test/sun/security/ssl/javax/net/ssl/TLSv11/EmptyCertificateAuthorities.java test/sun/security/ssl/javax/net/ssl/TLSv11/ExportableBlockCipher.java test/sun/security/ssl/javax/net/ssl/TLSv11/ExportableStreamCipher.java test/sun/security/ssl/javax/net/ssl/TLSv11/GenericBlockCipher.java test/sun/security/ssl/javax/net/ssl/TLSv11/GenericStreamCipher.java test/sun/security/ssl/sanity/interop/CipherTest.java
diffstat 30 files changed, 3391 insertions(+), 375 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/javax/net/ssl/SSLSocketFactory.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/javax/net/ssl/SSLSocketFactory.java	Sat Oct 30 18:39:17 2010 +0800
@@ -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
@@ -30,6 +30,7 @@
 import javax.net.SocketFactory;
 import java.io.IOException;
 import java.security.*;
+import java.util.Locale;
 
 import sun.security.action.GetPropertyAction;
 
@@ -50,7 +51,8 @@
 
     static {
         String s = java.security.AccessController.doPrivileged(
-            new GetPropertyAction("javax.net.debug", "")).toLowerCase();
+            new GetPropertyAction("javax.net.debug", "")).toLowerCase(
+                                                            Locale.ENGLISH);
         DEBUG = s.contains("all") || s.contains("ssl");
     }
 
--- a/src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java	Sat Oct 30 18:39:17 2010 +0800
@@ -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
@@ -90,8 +90,10 @@
             throw new NullPointerException();
         }
         this.masterSecret = masterSecret;
-        this.majorVersion = TlsMasterSecretParameterSpec.checkVersion(majorVersion);
-        this.minorVersion = TlsMasterSecretParameterSpec.checkVersion(minorVersion);
+        this.majorVersion =
+            TlsMasterSecretParameterSpec.checkVersion(majorVersion);
+        this.minorVersion =
+            TlsMasterSecretParameterSpec.checkVersion(minorVersion);
         this.clientRandom = clientRandom.clone();
         this.serverRandom = serverRandom.clone();
         this.cipherAlgorithm = cipherAlgorithm;
@@ -172,20 +174,36 @@
     }
 
     /**
-     * Returns the length in bytes of the expanded encryption key to be generated.
+     * Returns the length in bytes of the expanded encryption key to be
+     * generated. Returns zero if the expanded encryption key is not
+     * supposed to be generated.
      *
-     * @return the length in bytes of the expanded encryption key to be generated.
+     * @return the length in bytes of the expanded encryption key to be
+     *     generated.
      */
     public int getExpandedCipherKeyLength() {
+        // TLS v1.1 disables the exportable weak cipher suites.
+        if (majorVersion >= 0x03 && minorVersion >= 0x02) {
+            return 0;
+        }
         return expandedCipherKeyLength;
     }
 
     /**
-     * Returns the length in bytes of the initialization vector to be generated.
+     * Returns the length in bytes of the initialization vector to be
+     * generated. Returns zero if the initialization vector is not
+     * supposed to be generated.
      *
-     * @return the length in bytes of the initialization vector to be generated.
+     * @return the length in bytes of the initialization vector to be
+     *     generated.
      */
     public int getIvLength() {
+        // TLS v1.1 or later uses an explicit IV to protect against
+        // the CBC attacks.
+        if (majorVersion >= 0x03 && minorVersion >= 0x02) {
+            return 0;
+        }
+
         return ivLength;
     }
 
--- a/src/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java	Sat Oct 30 18:39:17 2010 +0800
@@ -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
@@ -67,7 +67,8 @@
      *   negative or larger than 255
      */
     public TlsMasterSecretParameterSpec(SecretKey premasterSecret,
-            int majorVersion, int minorVersion, byte[] clientRandom, byte[] serverRandom) {
+            int majorVersion, int minorVersion,
+            byte[] clientRandom, byte[] serverRandom) {
         if (premasterSecret == null) {
             throw new NullPointerException("premasterSecret must not be null");
         }
@@ -80,7 +81,8 @@
 
     static int checkVersion(int version) {
         if ((version < 0) || (version > 255)) {
-            throw new IllegalArgumentException("Version must be between 0 and 255");
+            throw new IllegalArgumentException(
+                        "Version must be between 0 and 255");
         }
         return version;
     }
--- a/src/share/classes/sun/security/ssl/CipherBox.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/CipherBox.java	Sat Oct 30 18:39:17 2010 +0800
@@ -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
@@ -28,6 +28,7 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.util.Hashtable;
 
 import java.security.*;
 import javax.crypto.*;
@@ -50,6 +51,37 @@
  * Individual instances are obtained by calling the static method
  * newCipherBox(), which should only be invoked by BulkCipher.newCipher().
  *
+ * In RFC 2246, with bock ciphers in CBC mode, the Initialization
+ * Vector (IV) for the first record is generated with the other keys
+ * and secrets when the security parameters are set.  The IV for
+ * subsequent records is the last ciphertext block from the previous
+ * record.
+ *
+ * In RFC 4346, the implicit Initialization Vector (IV) is replaced
+ * with an explicit IV to protect against CBC attacks.  RFC 4346
+ * recommends two algorithms used to generated the per-record IV.
+ * The implementation uses the algorithm (2)(b), as described at
+ * section 6.2.3.2 of RFC 4346.
+ *
+ * The usage of IV in CBC block cipher can be illustrated in
+ * the following diagrams.
+ *
+ *   (random)
+ *        R         P1                    IV        C1
+ *        |          |                     |         |
+ *  SIV---+    |-----+    |-...            |-----    |------
+ *        |    |     |    |                |    |    |     |
+ *     +----+  |  +----+  |             +----+  |  +----+  |
+ *     | Ek |  |  + Ek +  |             | Dk |  |  | Dk |  |
+ *     +----+  |  +----+  |             +----+  |  +----+  |
+ *        |    |     |    |                |    |    |     |
+ *        |----|     |----|           SIV--+    |----|     |-...
+ *        |          |                     |       |
+ *       IV         C1                     R      P1
+ *                                     (discard)
+ *
+ *       CBC Encryption                    CBC Decryption
+ *
  * NOTE that any ciphering involved in key exchange (e.g. with RSA) is
  * handled separately.
  *
@@ -76,6 +108,21 @@
     private int blockSize;
 
     /**
+     * secure random
+     */
+    private SecureRandom random;
+
+    /**
+     * Fixed masks of various block size, as the initial decryption IVs
+     * for TLS 1.1 or later.
+     *
+     * For performance, we do not use random IVs. As the initial decryption
+     * IVs will be discarded by TLS decryption processes, so the fixed masks
+     * do not hurt cryptographic strength.
+     */
+    private static Hashtable<Integer, IvParameterSpec> masks;
+
+    /**
      * NULL cipherbox. Identity operation, no encryption.
      */
     private CipherBox() {
@@ -90,14 +137,37 @@
      * implementation could be found.
      */
     private CipherBox(ProtocolVersion protocolVersion, BulkCipher bulkCipher,
-            SecretKey key,  IvParameterSpec iv, boolean encrypt)
-            throws NoSuchAlgorithmException {
+            SecretKey key, IvParameterSpec iv, SecureRandom random,
+            boolean encrypt) throws NoSuchAlgorithmException {
         try {
             this.protocolVersion = protocolVersion;
             this.cipher = JsseJce.getCipher(bulkCipher.transformation);
             int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
-            cipher.init(mode, key, iv);
-            // do not call getBlockSize until after init()
+
+            if (random == null) {
+                random = JsseJce.getSecureRandom();
+            }
+            this.random = random;
+
+            /*
+             * RFC 4346 recommends two algorithms used to generated the
+             * per-record IV. The implementation uses the algorithm (2)(b),
+             * as described at section 6.2.3.2 of RFC 4346.
+             *
+             * As we don't care about the initial IV value for TLS 1.1 or
+             * later, so if the "iv" parameter is null, we use the default
+             * value generated by Cipher.init() for encryption, and a fixed
+             * mask for decryption.
+             */
+            if (iv == null && bulkCipher.ivSize != 0 &&
+                    mode == Cipher.DECRYPT_MODE &&
+                    protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                iv = getFixedMask(bulkCipher.ivSize);
+            }
+
+            cipher.init(mode, key, iv, random);
+
+            // Do not call getBlockSize until after init()
             // otherwise we would disrupt JCE delayed provider selection
             blockSize = cipher.getBlockSize();
             // some providers implement getBlockSize() incorrectly
@@ -119,19 +189,37 @@
      * Factory method to obtain a new CipherBox object.
      */
     static CipherBox newCipherBox(ProtocolVersion version, BulkCipher cipher,
-            SecretKey key, IvParameterSpec iv, boolean encrypt)
-            throws NoSuchAlgorithmException {
+            SecretKey key, IvParameterSpec iv, SecureRandom random,
+            boolean encrypt) throws NoSuchAlgorithmException {
         if (cipher.allowed == false) {
             throw new NoSuchAlgorithmException("Unsupported cipher " + cipher);
         }
+
         if (cipher == B_NULL) {
             return NULL;
         } else {
-            return new CipherBox(version, cipher, key, iv, encrypt);
+            return new CipherBox(version, cipher, key, iv, random, encrypt);
         }
     }
 
     /*
+     * Get a fixed mask, as the initial decryption IVs for TLS 1.1 or later.
+     */
+    private static IvParameterSpec getFixedMask(int ivSize) {
+        if (masks == null) {
+            masks = new Hashtable<Integer, IvParameterSpec>(5);
+        }
+
+        IvParameterSpec iv = masks.get(ivSize);
+        if (iv == null) {
+            iv = new IvParameterSpec(new byte[ivSize]);
+            masks.put(ivSize, iv);
+        }
+
+        return iv;
+    }
+
+    /*
      * Encrypts a block of data, returning the size of the
      * resulting block.
      */
@@ -139,8 +227,26 @@
         if (cipher == null) {
             return len;
         }
+
         try {
             if (blockSize != 0) {
+                // TLSv1.1 needs a IV block
+                if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                    // generate a random number
+                    byte[] prefix = new byte[blockSize];
+                    random.nextBytes(prefix);
+
+                    // move forward the plaintext
+                    System.arraycopy(buf, offset,
+                                     buf, offset + prefix.length, len);
+
+                    // prefix the plaintext
+                    System.arraycopy(prefix, 0,
+                                     buf, offset, prefix.length);
+
+                    len += prefix.length;
+                }
+
                 len = addPadding(buf, offset, len, blockSize);
             }
             if (debug != null && Debug.isOn("plaintext")) {
@@ -189,6 +295,34 @@
             int pos = bb.position();
 
             if (blockSize != 0) {
+                // TLSv1.1 needs a IV block
+                if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                    // generate a random number
+                    byte[] prefix = new byte[blockSize];
+                    random.nextBytes(prefix);
+
+                    // move forward the plaintext
+                    byte[] buf = null;
+                    int limit = bb.limit();
+                    if (bb.hasArray()) {
+                        buf = bb.array();
+                        System.arraycopy(buf, pos,
+                                buf, pos + prefix.length, limit - pos);
+                        bb.limit(limit + prefix.length);
+                    } else {
+                        buf = new byte[limit - pos];
+                        bb.get(buf, 0, limit - pos);
+                        bb.position(pos + prefix.length);
+                        bb.limit(limit + prefix.length);
+                        bb.put(buf);
+                    }
+                    bb.position(pos);
+
+                    // prefix the plaintext
+                    bb.put(prefix);
+                    bb.position(pos);
+                }
+
                 // addPadding adjusts pos/limit
                 len = addPadding(bb, blockSize);
                 bb.position(pos);
@@ -236,11 +370,25 @@
     /*
      * Decrypts a block of data, returning the size of the
      * resulting block if padding was required.
+     *
+     * For SSLv3 and TLSv1.0, with block ciphers in CBC mode the
+     * Initialization Vector (IV) for the first record is generated by
+     * the handshake protocol, the IV for subsequent records is the
+     * last ciphertext block from the previous record.
+     *
+     * From TLSv1.1, the implicit IV is replaced with an explicit IV to
+     * protect against CBC attacks.
+     *
+     * Differentiating between bad_record_mac and decryption_failed alerts
+     * may permit certain attacks against CBC mode. It is preferable to
+     * uniformly use the bad_record_mac alert to hide the specific type of
+     * the error.
      */
     int decrypt(byte[] buf, int offset, int len) throws BadPaddingException {
         if (cipher == null) {
             return len;
         }
+
         try {
             int newLen = cipher.update(buf, offset, len, buf, offset);
             if (newLen != len) {
@@ -263,6 +411,18 @@
             if (blockSize != 0) {
                 newLen = removePadding(buf, offset, newLen,
                              blockSize, protocolVersion);
+
+                if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                    if (newLen < blockSize) {
+                        throw new BadPaddingException("invalid explicit IV");
+                    }
+
+                    // discards the first cipher block, the IV component.
+                    System.arraycopy(buf, offset + blockSize,
+                                     buf, offset, newLen - blockSize);
+
+                    newLen -= blockSize;
+                }
             }
             return newLen;
         } catch (ShortBufferException e) {
@@ -277,6 +437,8 @@
      * point to the end of the decrypted/depadded data.  The initial
      * limit and new limit may be different, given we may
      * have stripped off some padding bytes.
+     *
+     *  @see decrypt(byte[], int, int)
      */
     int decrypt(ByteBuffer bb) throws BadPaddingException {
 
@@ -292,7 +454,6 @@
              * Decrypt "in-place".
              */
             int pos = bb.position();
-
             ByteBuffer dup = bb.duplicate();
             int newLen = cipher.update(dup, bb);
             if (newLen != len) {
@@ -320,6 +481,33 @@
             if (blockSize != 0) {
                 bb.position(pos);
                 newLen = removePadding(bb, blockSize, protocolVersion);
+
+                if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                    if (newLen < blockSize) {
+                        throw new BadPaddingException("invalid explicit IV");
+                    }
+
+                    // discards the first cipher block, the IV component.
+                    byte[] buf = null;
+                    int limit = bb.limit();
+                    if (bb.hasArray()) {
+                        buf = bb.array();
+                        System.arraycopy(buf, pos + blockSize,
+                                         buf, pos, limit - pos - blockSize);
+                        bb.limit(limit - blockSize);
+                    } else {
+                        buf = new byte[limit - pos - blockSize];
+                        bb.position(pos + blockSize);
+                        bb.get(buf);
+                        bb.position(pos);
+                        bb.put(buf);
+                        bb.limit(limit - blockSize);
+                    }
+
+                    // reset the position to the end of the decrypted data
+                    limit = bb.limit();
+                    bb.position(limit);
+                }
             }
             return newLen;
         } catch (ShortBufferException e) {
--- a/src/share/classes/sun/security/ssl/CipherSuite.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/CipherSuite.java	Sat Oct 30 18:39:17 2010 +0800
@@ -30,6 +30,7 @@
 
 import java.security.NoSuchAlgorithmException;
 import java.security.InvalidKeyException;
+import java.security.SecureRandom;
 
 import javax.crypto.SecretKey;
 import javax.crypto.spec.IvParameterSpec;
@@ -112,8 +113,12 @@
     // true iff implemented and enabled at compile time
     final boolean allowed;
 
+    // obsoleted since protocol version
+    final int obsoleted;
+
     private CipherSuite(String name, int id, int priority,
-            KeyExchange keyExchange, BulkCipher cipher, boolean allowed) {
+            KeyExchange keyExchange, BulkCipher cipher,
+            boolean allowed, int obsoleted) {
         this.name = name;
         this.id = id;
         this.priority = priority;
@@ -136,6 +141,7 @@
         allowed &= keyExchange.allowed;
         allowed &= cipher.allowed;
         this.allowed = allowed;
+        this.obsoleted = obsoleted;
     }
 
     private CipherSuite(String name, int id) {
@@ -148,6 +154,7 @@
         this.cipher = null;
         this.macAlg = null;
         this.exportable = false;
+        this.obsoleted = ProtocolVersion.LIMIT_MAX_VALUE;
     }
 
     /**
@@ -197,10 +204,12 @@
         if (s == null) {
             throw new IllegalArgumentException("Name must not be null");
         }
+
         CipherSuite c = nameMap.get(s);
         if ((c == null) || (c.allowed == false)) {
             throw new IllegalArgumentException("Unsupported ciphersuite " + s);
         }
+
         return c;
     }
 
@@ -228,9 +237,11 @@
     }
 
     private static void add(String name, int id, int priority,
-            KeyExchange keyExchange, BulkCipher cipher, boolean allowed) {
+            KeyExchange keyExchange, BulkCipher cipher,
+            boolean allowed, int obsoleted) {
+
         CipherSuite c = new CipherSuite(name, id, priority, keyExchange,
-                                        cipher, allowed);
+                                        cipher, allowed, obsoleted);
         if (idMap.put(id, c) != null) {
             throw new RuntimeException("Duplicate ciphersuite definition: "
                                         + id + ", " + name);
@@ -243,6 +254,12 @@
         }
     }
 
+    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);
+    }
+
     private static void add(String name, int id) {
         CipherSuite c = new CipherSuite(name, id);
         if (idMap.put(id, c) != null) {
@@ -380,10 +397,11 @@
          *
          * @exception NoSuchAlgorithmException if anything goes wrong
          */
-        CipherBox newCipher(ProtocolVersion version,
-                SecretKey key, IvParameterSpec iv,
+        CipherBox newCipher(ProtocolVersion version, SecretKey key,
+                IvParameterSpec iv, SecureRandom random,
                 boolean encrypt) throws NoSuchAlgorithmException {
-            return CipherBox.newCipherBox(version, this, key, iv, encrypt);
+            return CipherBox.newCipherBox(version, this,
+                                            key, iv, random, encrypt);
         }
 
         /**
@@ -402,6 +420,7 @@
             if (this == B_AES_256) {
                 return isAvailable(this);
             }
+
             // always available
             return true;
         }
@@ -421,7 +440,8 @@
                         (new byte[cipher.expandedKeySize], cipher.algorithm);
                     IvParameterSpec iv =
                         new IvParameterSpec(new byte[cipher.ivSize]);
-                    cipher.newCipher(ProtocolVersion.DEFAULT, key, iv, true);
+                    cipher.newCipher(ProtocolVersion.DEFAULT,
+                                                key, iv, null, true);
                     b = Boolean.TRUE;
                 } catch (NoSuchAlgorithmException e) {
                     b = Boolean.FALSE;
@@ -509,6 +529,239 @@
         // N: ciphersuites only allowed if we are not in FIPS mode
         final boolean N = (SunJSSE.isFIPS() == false);
 
+        /*
+         * TLS Cipher Suite Registry, as of August 2010.
+         *
+         * http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
+         *
+         * Range      Registration Procedures   Notes
+         * 000-191    Standards Action          Refers to value of first byte
+         * 192-254    Specification Required    Refers to value of first byte
+         * 255        Reserved for Private Use  Refers to value of first byte
+         *
+         * Value      Description                               Reference
+         * 0x00,0x00  TLS_NULL_WITH_NULL_NULL                   [RFC5246]
+         * 0x00,0x01  TLS_RSA_WITH_NULL_MD5                     [RFC5246]
+         * 0x00,0x02  TLS_RSA_WITH_NULL_SHA                     [RFC5246]
+         * 0x00,0x03  TLS_RSA_EXPORT_WITH_RC4_40_MD5            [RFC4346]
+         * 0x00,0x04  TLS_RSA_WITH_RC4_128_MD5                  [RFC5246]
+         * 0x00,0x05  TLS_RSA_WITH_RC4_128_SHA                  [RFC5246]
+         * 0x00,0x06  TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5        [RFC4346]
+         * 0x00,0x07  TLS_RSA_WITH_IDEA_CBC_SHA                 [RFC5469]
+         * 0x00,0x08  TLS_RSA_EXPORT_WITH_DES40_CBC_SHA         [RFC4346]
+         * 0x00,0x09  TLS_RSA_WITH_DES_CBC_SHA                  [RFC5469]
+         * 0x00,0x0A  TLS_RSA_WITH_3DES_EDE_CBC_SHA             [RFC5246]
+         * 0x00,0x0B  TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA      [RFC4346]
+         * 0x00,0x0C  TLS_DH_DSS_WITH_DES_CBC_SHA               [RFC5469]
+         * 0x00,0x0D  TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA          [RFC5246]
+         * 0x00,0x0E  TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA      [RFC4346]
+         * 0x00,0x0F  TLS_DH_RSA_WITH_DES_CBC_SHA               [RFC5469]
+         * 0x00,0x10  TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA          [RFC5246]
+         * 0x00,0x11  TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA     [RFC4346]
+         * 0x00,0x12  TLS_DHE_DSS_WITH_DES_CBC_SHA              [RFC5469]
+         * 0x00,0x13  TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA         [RFC5246]
+         * 0x00,0x14  TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA     [RFC4346]
+         * 0x00,0x15  TLS_DHE_RSA_WITH_DES_CBC_SHA              [RFC5469]
+         * 0x00,0x16  TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA         [RFC5246]
+         * 0x00,0x17  TLS_DH_anon_EXPORT_WITH_RC4_40_MD5        [RFC4346]
+         * 0x00,0x18  TLS_DH_anon_WITH_RC4_128_MD5              [RFC5246]
+         * 0x00,0x19  TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA     [RFC4346]
+         * 0x00,0x1A  TLS_DH_anon_WITH_DES_CBC_SHA              [RFC5469]
+         * 0x00,0x1B  TLS_DH_anon_WITH_3DES_EDE_CBC_SHA         [RFC5246]
+         * 0x00,0x1C-1D Reserved to avoid conflicts with SSLv3  [RFC5246]
+         * 0x00,0x1E  TLS_KRB5_WITH_DES_CBC_SHA                 [RFC2712]
+         * 0x00,0x1F  TLS_KRB5_WITH_3DES_EDE_CBC_SHA            [RFC2712]
+         * 0x00,0x20  TLS_KRB5_WITH_RC4_128_SHA                 [RFC2712]
+         * 0x00,0x21  TLS_KRB5_WITH_IDEA_CBC_SHA                [RFC2712]
+         * 0x00,0x22  TLS_KRB5_WITH_DES_CBC_MD5                 [RFC2712]
+         * 0x00,0x23  TLS_KRB5_WITH_3DES_EDE_CBC_MD5            [RFC2712]
+         * 0x00,0x24  TLS_KRB5_WITH_RC4_128_MD5                 [RFC2712]
+         * 0x00,0x25  TLS_KRB5_WITH_IDEA_CBC_MD5                [RFC2712]
+         * 0x00,0x26  TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA       [RFC2712]
+         * 0x00,0x27  TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA       [RFC2712]
+         * 0x00,0x28  TLS_KRB5_EXPORT_WITH_RC4_40_SHA           [RFC2712]
+         * 0x00,0x29  TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5       [RFC2712]
+         * 0x00,0x2A  TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5       [RFC2712]
+         * 0x00,0x2B  TLS_KRB5_EXPORT_WITH_RC4_40_MD5           [RFC2712]
+         * 0x00,0x2C  TLS_PSK_WITH_NULL_SHA                     [RFC4785]
+         * 0x00,0x2D  TLS_DHE_PSK_WITH_NULL_SHA                 [RFC4785]
+         * 0x00,0x2E  TLS_RSA_PSK_WITH_NULL_SHA                 [RFC4785]
+         * 0x00,0x2F  TLS_RSA_WITH_AES_128_CBC_SHA              [RFC5246]
+         * 0x00,0x30  TLS_DH_DSS_WITH_AES_128_CBC_SHA           [RFC5246]
+         * 0x00,0x31  TLS_DH_RSA_WITH_AES_128_CBC_SHA           [RFC5246]
+         * 0x00,0x32  TLS_DHE_DSS_WITH_AES_128_CBC_SHA          [RFC5246]
+         * 0x00,0x33  TLS_DHE_RSA_WITH_AES_128_CBC_SHA          [RFC5246]
+         * 0x00,0x34  TLS_DH_anon_WITH_AES_128_CBC_SHA          [RFC5246]
+         * 0x00,0x35  TLS_RSA_WITH_AES_256_CBC_SHA              [RFC5246]
+         * 0x00,0x36  TLS_DH_DSS_WITH_AES_256_CBC_SHA           [RFC5246]
+         * 0x00,0x37  TLS_DH_RSA_WITH_AES_256_CBC_SHA           [RFC5246]
+         * 0x00,0x38  TLS_DHE_DSS_WITH_AES_256_CBC_SHA          [RFC5246]
+         * 0x00,0x39  TLS_DHE_RSA_WITH_AES_256_CBC_SHA          [RFC5246]
+         * 0x00,0x3A  TLS_DH_anon_WITH_AES_256_CBC_SHA          [RFC5246]
+         * 0x00,0x3B  TLS_RSA_WITH_NULL_SHA256                  [RFC5246]
+         * 0x00,0x3C  TLS_RSA_WITH_AES_128_CBC_SHA256           [RFC5246]
+         * 0x00,0x3D  TLS_RSA_WITH_AES_256_CBC_SHA256           [RFC5246]
+         * 0x00,0x3E  TLS_DH_DSS_WITH_AES_128_CBC_SHA256        [RFC5246]
+         * 0x00,0x3F  TLS_DH_RSA_WITH_AES_128_CBC_SHA256        [RFC5246]
+         * 0x00,0x40  TLS_DHE_DSS_WITH_AES_128_CBC_SHA256       [RFC5246]
+         * 0x00,0x41  TLS_RSA_WITH_CAMELLIA_128_CBC_SHA         [RFC5932]
+         * 0x00,0x42  TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA      [RFC5932]
+         * 0x00,0x43  TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA      [RFC5932]
+         * 0x00,0x44  TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA     [RFC5932]
+         * 0x00,0x45  TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA     [RFC5932]
+         * 0x00,0x46  TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA     [RFC5932]
+         * 0x00,0x47-4F Reserved to avoid conflicts with
+         *            deployed implementations                  [Pasi_Eronen]
+         * 0x00,0x50-58 Reserved to avoid conflicts             [Pasi Eronen]
+         * 0x00,0x59-5C Reserved to avoid conflicts with
+         *            deployed implementations                  [Pasi_Eronen]
+         * 0x00,0x5D-5F Unassigned
+         * 0x00,0x60-66 Reserved to avoid conflicts with widely
+         *            deployed implementations                  [Pasi_Eronen]
+         * 0x00,0x67  TLS_DHE_RSA_WITH_AES_128_CBC_SHA256       [RFC5246]
+         * 0x00,0x68  TLS_DH_DSS_WITH_AES_256_CBC_SHA256        [RFC5246]
+         * 0x00,0x69  TLS_DH_RSA_WITH_AES_256_CBC_SHA256        [RFC5246]
+         * 0x00,0x6A  TLS_DHE_DSS_WITH_AES_256_CBC_SHA256       [RFC5246]
+         * 0x00,0x6B  TLS_DHE_RSA_WITH_AES_256_CBC_SHA256       [RFC5246]
+         * 0x00,0x6C  TLS_DH_anon_WITH_AES_128_CBC_SHA256       [RFC5246]
+         * 0x00,0x6D  TLS_DH_anon_WITH_AES_256_CBC_SHA256       [RFC5246]
+         * 0x00,0x6E-83 Unassigned
+         * 0x00,0x84  TLS_RSA_WITH_CAMELLIA_256_CBC_SHA         [RFC5932]
+         * 0x00,0x85  TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA      [RFC5932]
+         * 0x00,0x86  TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA      [RFC5932]
+         * 0x00,0x87  TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA     [RFC5932]
+         * 0x00,0x88  TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA     [RFC5932]
+         * 0x00,0x89  TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA     [RFC5932]
+         * 0x00,0x8A  TLS_PSK_WITH_RC4_128_SHA                  [RFC4279]
+         * 0x00,0x8B  TLS_PSK_WITH_3DES_EDE_CBC_SHA             [RFC4279]
+         * 0x00,0x8C  TLS_PSK_WITH_AES_128_CBC_SHA              [RFC4279]
+         * 0x00,0x8D  TLS_PSK_WITH_AES_256_CBC_SHA              [RFC4279]
+         * 0x00,0x8E  TLS_DHE_PSK_WITH_RC4_128_SHA              [RFC4279]
+         * 0x00,0x8F  TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA         [RFC4279]
+         * 0x00,0x90  TLS_DHE_PSK_WITH_AES_128_CBC_SHA          [RFC4279]
+         * 0x00,0x91  TLS_DHE_PSK_WITH_AES_256_CBC_SHA          [RFC4279]
+         * 0x00,0x92  TLS_RSA_PSK_WITH_RC4_128_SHA              [RFC4279]
+         * 0x00,0x93  TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA         [RFC4279]
+         * 0x00,0x94  TLS_RSA_PSK_WITH_AES_128_CBC_SHA          [RFC4279]
+         * 0x00,0x95  TLS_RSA_PSK_WITH_AES_256_CBC_SHA          [RFC4279]
+         * 0x00,0x96  TLS_RSA_WITH_SEED_CBC_SHA                 [RFC4162]
+         * 0x00,0x97  TLS_DH_DSS_WITH_SEED_CBC_SHA              [RFC4162]
+         * 0x00,0x98  TLS_DH_RSA_WITH_SEED_CBC_SHA              [RFC4162]
+         * 0x00,0x99  TLS_DHE_DSS_WITH_SEED_CBC_SHA             [RFC4162]
+         * 0x00,0x9A  TLS_DHE_RSA_WITH_SEED_CBC_SHA             [RFC4162]
+         * 0x00,0x9B  TLS_DH_anon_WITH_SEED_CBC_SHA             [RFC4162]
+         * 0x00,0x9C  TLS_RSA_WITH_AES_128_GCM_SHA256           [RFC5288]
+         * 0x00,0x9D  TLS_RSA_WITH_AES_256_GCM_SHA384           [RFC5288]
+         * 0x00,0x9E  TLS_DHE_RSA_WITH_AES_128_GCM_SHA256       [RFC5288]
+         * 0x00,0x9F  TLS_DHE_RSA_WITH_AES_256_GCM_SHA384       [RFC5288]
+         * 0x00,0xA0  TLS_DH_RSA_WITH_AES_128_GCM_SHA256        [RFC5288]
+         * 0x00,0xA1  TLS_DH_RSA_WITH_AES_256_GCM_SHA384        [RFC5288]
+         * 0x00,0xA2  TLS_DHE_DSS_WITH_AES_128_GCM_SHA256       [RFC5288]
+         * 0x00,0xA3  TLS_DHE_DSS_WITH_AES_256_GCM_SHA384       [RFC5288]
+         * 0x00,0xA4  TLS_DH_DSS_WITH_AES_128_GCM_SHA256        [RFC5288]
+         * 0x00,0xA5  TLS_DH_DSS_WITH_AES_256_GCM_SHA384        [RFC5288]
+         * 0x00,0xA6  TLS_DH_anon_WITH_AES_128_GCM_SHA256       [RFC5288]
+         * 0x00,0xA7  TLS_DH_anon_WITH_AES_256_GCM_SHA384       [RFC5288]
+         * 0x00,0xA8  TLS_PSK_WITH_AES_128_GCM_SHA256           [RFC5487]
+         * 0x00,0xA9  TLS_PSK_WITH_AES_256_GCM_SHA384           [RFC5487]
+         * 0x00,0xAA  TLS_DHE_PSK_WITH_AES_128_GCM_SHA256       [RFC5487]
+         * 0x00,0xAB  TLS_DHE_PSK_WITH_AES_256_GCM_SHA384       [RFC5487]
+         * 0x00,0xAC  TLS_RSA_PSK_WITH_AES_128_GCM_SHA256       [RFC5487]
+         * 0x00,0xAD  TLS_RSA_PSK_WITH_AES_256_GCM_SHA384       [RFC5487]
+         * 0x00,0xAE  TLS_PSK_WITH_AES_128_CBC_SHA256           [RFC5487]
+         * 0x00,0xAF  TLS_PSK_WITH_AES_256_CBC_SHA384           [RFC5487]
+         * 0x00,0xB0  TLS_PSK_WITH_NULL_SHA256                  [RFC5487]
+         * 0x00,0xB1  TLS_PSK_WITH_NULL_SHA384                  [RFC5487]
+         * 0x00,0xB2  TLS_DHE_PSK_WITH_AES_128_CBC_SHA256       [RFC5487]
+         * 0x00,0xB3  TLS_DHE_PSK_WITH_AES_256_CBC_SHA384       [RFC5487]
+         * 0x00,0xB4  TLS_DHE_PSK_WITH_NULL_SHA256              [RFC5487]
+         * 0x00,0xB5  TLS_DHE_PSK_WITH_NULL_SHA384              [RFC5487]
+         * 0x00,0xB6  TLS_RSA_PSK_WITH_AES_128_CBC_SHA256       [RFC5487]
+         * 0x00,0xB7  TLS_RSA_PSK_WITH_AES_256_CBC_SHA384       [RFC5487]
+         * 0x00,0xB8  TLS_RSA_PSK_WITH_NULL_SHA256              [RFC5487]
+         * 0x00,0xB9  TLS_RSA_PSK_WITH_NULL_SHA384              [RFC5487]
+         * 0x00,0xBA  TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256      [RFC5932]
+         * 0x00,0xBB  TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256   [RFC5932]
+         * 0x00,0xBC  TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256   [RFC5932]
+         * 0x00,0xBD  TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256  [RFC5932]
+         * 0x00,0xBE  TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256  [RFC5932]
+         * 0x00,0xBF  TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256  [RFC5932]
+         * 0x00,0xC0  TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256      [RFC5932]
+         * 0x00,0xC1  TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256   [RFC5932]
+         * 0x00,0xC2  TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256   [RFC5932]
+         * 0x00,0xC3  TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256  [RFC5932]
+         * 0x00,0xC4  TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256  [RFC5932]
+         * 0x00,0xC5  TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256  [RFC5932]
+         * 0x00,0xC6-FE         Unassigned
+         * 0x00,0xFF  TLS_EMPTY_RENEGOTIATION_INFO_SCSV         [RFC5746]
+         * 0x01-BF,*  Unassigned
+         * 0xC0,0x01  TLS_ECDH_ECDSA_WITH_NULL_SHA              [RFC4492]
+         * 0xC0,0x02  TLS_ECDH_ECDSA_WITH_RC4_128_SHA           [RFC4492]
+         * 0xC0,0x03  TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA      [RFC4492]
+         * 0xC0,0x04  TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA       [RFC4492]
+         * 0xC0,0x05  TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA       [RFC4492]
+         * 0xC0,0x06  TLS_ECDHE_ECDSA_WITH_NULL_SHA             [RFC4492]
+         * 0xC0,0x07  TLS_ECDHE_ECDSA_WITH_RC4_128_SHA          [RFC4492]
+         * 0xC0,0x08  TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA     [RFC4492]
+         * 0xC0,0x09  TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA      [RFC4492]
+         * 0xC0,0x0A  TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA      [RFC4492]
+         * 0xC0,0x0B  TLS_ECDH_RSA_WITH_NULL_SHA                [RFC4492]
+         * 0xC0,0x0C  TLS_ECDH_RSA_WITH_RC4_128_SHA             [RFC4492]
+         * 0xC0,0x0D  TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA        [RFC4492]
+         * 0xC0,0x0E  TLS_ECDH_RSA_WITH_AES_128_CBC_SHA         [RFC4492]
+         * 0xC0,0x0F  TLS_ECDH_RSA_WITH_AES_256_CBC_SHA         [RFC4492]
+         * 0xC0,0x10  TLS_ECDHE_RSA_WITH_NULL_SHA               [RFC4492]
+         * 0xC0,0x11  TLS_ECDHE_RSA_WITH_RC4_128_SHA            [RFC4492]
+         * 0xC0,0x12  TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA       [RFC4492]
+         * 0xC0,0x13  TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA        [RFC4492]
+         * 0xC0,0x14  TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA        [RFC4492]
+         * 0xC0,0x15  TLS_ECDH_anon_WITH_NULL_SHA               [RFC4492]
+         * 0xC0,0x16  TLS_ECDH_anon_WITH_RC4_128_SHA            [RFC4492]
+         * 0xC0,0x17  TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA       [RFC4492]
+         * 0xC0,0x18  TLS_ECDH_anon_WITH_AES_128_CBC_SHA        [RFC4492]
+         * 0xC0,0x19  TLS_ECDH_anon_WITH_AES_256_CBC_SHA        [RFC4492]
+         * 0xC0,0x1A  TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA         [RFC5054]
+         * 0xC0,0x1B  TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA     [RFC5054]
+         * 0xC0,0x1C  TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA     [RFC5054]
+         * 0xC0,0x1D  TLS_SRP_SHA_WITH_AES_128_CBC_SHA          [RFC5054]
+         * 0xC0,0x1E  TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA      [RFC5054]
+         * 0xC0,0x1F  TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA      [RFC5054]
+         * 0xC0,0x20  TLS_SRP_SHA_WITH_AES_256_CBC_SHA          [RFC5054]
+         * 0xC0,0x21  TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA      [RFC5054]
+         * 0xC0,0x22  TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA      [RFC5054]
+         * 0xC0,0x23  TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256   [RFC5289]
+         * 0xC0,0x24  TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384   [RFC5289]
+         * 0xC0,0x25  TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256    [RFC5289]
+         * 0xC0,0x26  TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384    [RFC5289]
+         * 0xC0,0x27  TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256     [RFC5289]
+         * 0xC0,0x28  TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384     [RFC5289]
+         * 0xC0,0x29  TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256      [RFC5289]
+         * 0xC0,0x2A  TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384      [RFC5289]
+         * 0xC0,0x2B  TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256   [RFC5289]
+         * 0xC0,0x2C  TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384   [RFC5289]
+         * 0xC0,0x2D  TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256    [RFC5289]
+         * 0xC0,0x2E  TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384    [RFC5289]
+         * 0xC0,0x2F  TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256     [RFC5289]
+         * 0xC0,0x30  TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384     [RFC5289]
+         * 0xC0,0x31  TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256      [RFC5289]
+         * 0xC0,0x32  TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384      [RFC5289]
+         * 0xC0,0x33  TLS_ECDHE_PSK_WITH_RC4_128_SHA            [RFC5489]
+         * 0xC0,0x34  TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA       [RFC5489]
+         * 0xC0,0x35  TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA        [RFC5489]
+         * 0xC0,0x36  TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA        [RFC5489]
+         * 0xC0,0x37  TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256     [RFC5489]
+         * 0xC0,0x38  TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384     [RFC5489]
+         * 0xC0,0x39  TLS_ECDHE_PSK_WITH_NULL_SHA               [RFC5489]
+         * 0xC0,0x3A  TLS_ECDHE_PSK_WITH_NULL_SHA256            [RFC5489]
+         * 0xC0,0x3B  TLS_ECDHE_PSK_WITH_NULL_SHA384            [RFC5489]
+         * 0xC0,0x3C-FF Unassigned
+         * 0xC1-FD,*  Unassigned
+         * 0xFE,0x00-FD Unassigned
+         * 0xFE,0xFE-FF Reserved to avoid conflicts with widely
+         *            deployed implementations                  [Pasi_Eronen]
+         * 0xFF,0x00-FF Reserved for Private Use                [RFC5246]
+         */
+
         add("SSL_NULL_WITH_NULL_NULL",
                               0x0000,   1, K_NULL,       B_NULL,    F);
 
@@ -574,7 +827,6 @@
                               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",
@@ -582,13 +834,17 @@
         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);
+                              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);
+                              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);
+                              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);
+                              0x0011, --p, K_DHE_DSS,    B_DES_40,  N,
+                              ProtocolVersion.TLS11.v);
 
         // Renegotiation protection request Signalling Cipher Suite Value (SCSV)
         add("TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
@@ -634,9 +890,11 @@
                               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);
+                              0x0017, --p, K_DH_ANON,    B_RC4_40,  N,
+                              ProtocolVersion.TLS11.v);
         add("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
-                              0x0019, --p, K_DH_ANON,    B_DES_40,  N);
+                              0x0019, --p, K_DH_ANON,    B_DES_40,  N,
+                              ProtocolVersion.TLS11.v);
 
         add("TLS_ECDH_anon_WITH_NULL_SHA",
                               0xC015, --p, K_ECDH_ANON,  B_NULL,    N);
@@ -655,52 +913,212 @@
         add("TLS_KRB5_WITH_DES_CBC_MD5",
                               0x0022, --p, K_KRB5,        B_DES,     N);
         add("TLS_KRB5_EXPORT_WITH_RC4_40_SHA",
-                              0x0028, --p, K_KRB5_EXPORT, B_RC4_40,  N);
+                              0x0028, --p, K_KRB5_EXPORT, B_RC4_40,  N,
+                              ProtocolVersion.TLS11.v);
         add("TLS_KRB5_EXPORT_WITH_RC4_40_MD5",
-                              0x002b, --p, K_KRB5_EXPORT, B_RC4_40,  N);
+                              0x002b, --p, K_KRB5_EXPORT, B_RC4_40,  N,
+                              ProtocolVersion.TLS11.v);
         add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA",
-                              0x0026, --p, K_KRB5_EXPORT, B_DES_40,  N);
+                              0x0026, --p, K_KRB5_EXPORT, B_DES_40,  N,
+                              ProtocolVersion.TLS11.v);
         add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5",
-                              0x0029, --p, K_KRB5_EXPORT, B_DES_40,  N);
+                              0x0029, --p, K_KRB5_EXPORT, B_DES_40,  N,
+                              ProtocolVersion.TLS11.v);
+
+        /*
+         * Other values from the TLS Cipher Suite Registry, as of August 2010.
+         *
+         * http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
+         *
+         * Range      Registration Procedures   Notes
+         * 000-191    Standards Action          Refers to value of first byte
+         * 192-254    Specification Required    Refers to value of first byte
+         * 255        Reserved for Private Use  Refers to value of first byte
+         */
 
         // Register the names of a few additional CipherSuites.
         // Makes them show up as names instead of numbers in
         // the debug output.
 
         // remaining unsupported ciphersuites defined in RFC2246.
-        add("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5",      0x0006);
-        add("SSL_RSA_WITH_IDEA_CBC_SHA",               0x0007);
-        add("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",    0x000b);
-        add("SSL_DH_DSS_WITH_DES_CBC_SHA",             0x000c);
-        add("SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA",        0x000d);
-        add("SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",    0x000e);
-        add("SSL_DH_RSA_WITH_DES_CBC_SHA",             0x000f);
-        add("SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA",        0x0010);
+        add("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5",          0x0006);
+        add("SSL_RSA_WITH_IDEA_CBC_SHA",                   0x0007);
+        add("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",        0x000b);
+        add("SSL_DH_DSS_WITH_DES_CBC_SHA",                 0x000c);
+        add("SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA",            0x000d);
+        add("SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",        0x000e);
+        add("SSL_DH_RSA_WITH_DES_CBC_SHA",                 0x000f);
+        add("SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA",            0x0010);
 
         // SSL 3.0 Fortezza ciphersuites
-        add("SSL_FORTEZZA_DMS_WITH_NULL_SHA",          0x001c);
-        add("SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA",  0x001d);
+        add("SSL_FORTEZZA_DMS_WITH_NULL_SHA",              0x001c);
+        add("SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA",      0x001d);
 
         // 1024/56 bit exportable ciphersuites from expired internet draft
-        add("SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA",     0x0062);
-        add("SSL_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA", 0x0063);
-        add("SSL_RSA_EXPORT1024_WITH_RC4_56_SHA",      0x0064);
-        add("SSL_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA",  0x0065);
-        add("SSL_DHE_DSS_WITH_RC4_128_SHA",            0x0066);
+        add("SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA",         0x0062);
+        add("SSL_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA",     0x0063);
+        add("SSL_RSA_EXPORT1024_WITH_RC4_56_SHA",          0x0064);
+        add("SSL_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA",      0x0065);
+        add("SSL_DHE_DSS_WITH_RC4_128_SHA",                0x0066);
 
         // Netscape old and new SSL 3.0 FIPS ciphersuites
         // see http://www.mozilla.org/projects/security/pki/nss/ssl/fips-ssl-ciphersuites.html
-        add("NETSCAPE_RSA_FIPS_WITH_3DES_EDE_CBC_SHA", 0xffe0);
-        add("NETSCAPE_RSA_FIPS_WITH_DES_CBC_SHA",      0xffe1);
-        add("SSL_RSA_FIPS_WITH_DES_CBC_SHA",           0xfefe);
-        add("SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA",      0xfeff);
+        add("NETSCAPE_RSA_FIPS_WITH_3DES_EDE_CBC_SHA",     0xffe0);
+        add("NETSCAPE_RSA_FIPS_WITH_DES_CBC_SHA",          0xffe1);
+        add("SSL_RSA_FIPS_WITH_DES_CBC_SHA",               0xfefe);
+        add("SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA",          0xfeff);
 
         // Unsupported Kerberos cipher suites from RFC 2712
-        add("TLS_KRB5_WITH_IDEA_CBC_SHA",              0x0021);
-        add("TLS_KRB5_WITH_IDEA_CBC_MD5",              0x0025);
-        add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA",     0x0027);
-        add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5",     0x002a);
+        add("TLS_KRB5_WITH_IDEA_CBC_SHA",                  0x0021);
+        add("TLS_KRB5_WITH_IDEA_CBC_MD5",                  0x0025);
+        add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA",         0x0027);
+        add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5",         0x002a);
 
+        // Unsupported cipher suites from RFC 4162
+        add("TLS_RSA_WITH_SEED_CBC_SHA",                   0x0096);
+        add("TLS_DH_DSS_WITH_SEED_CBC_SHA",                0x0097);
+        add("TLS_DH_RSA_WITH_SEED_CBC_SHA",                0x0098);
+        add("TLS_DHE_DSS_WITH_SEED_CBC_SHA",               0x0099);
+        add("TLS_DHE_RSA_WITH_SEED_CBC_SHA",               0x009a);
+        add("TLS_DH_anon_WITH_SEED_CBC_SHA",               0x009b);
+
+        // Unsupported cipher suites from RFC 4279
+        add("TLS_PSK_WITH_RC4_128_SHA",                    0x008a);
+        add("TLS_PSK_WITH_3DES_EDE_CBC_SHA",               0x008b);
+        add("TLS_PSK_WITH_AES_128_CBC_SHA",                0x008c);
+        add("TLS_PSK_WITH_AES_256_CBC_SHA",                0x008d);
+        add("TLS_DHE_PSK_WITH_RC4_128_SHA",                0x008e);
+        add("TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA",           0x008f);
+        add("TLS_DHE_PSK_WITH_AES_128_CBC_SHA",            0x0090);
+        add("TLS_DHE_PSK_WITH_AES_256_CBC_SHA",            0x0091);
+        add("TLS_RSA_PSK_WITH_RC4_128_SHA",                0x0092);
+        add("TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA",           0x0093);
+        add("TLS_RSA_PSK_WITH_AES_128_CBC_SHA",            0x0094);
+        add("TLS_RSA_PSK_WITH_AES_256_CBC_SHA",            0x0095);
+
+        // Unsupported cipher suites from RFC 4785
+        add("TLS_PSK_WITH_NULL_SHA",                       0x002c);
+        add("TLS_DHE_PSK_WITH_NULL_SHA",                   0x002d);
+        add("TLS_RSA_PSK_WITH_NULL_SHA",                   0x002e);
+
+        // Unsupported cipher suites from RFC 5246
+        add("TLS_DH_DSS_WITH_AES_128_CBC_SHA",             0x0030);
+        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);
+        add("TLS_RSA_WITH_AES_256_GCM_SHA384",             0x009d);
+        add("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",         0x009e);
+        add("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",         0x009f);
+        add("TLS_DH_RSA_WITH_AES_128_GCM_SHA256",          0x00a0);
+        add("TLS_DH_RSA_WITH_AES_256_GCM_SHA384",          0x00a1);
+        add("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",         0x00a2);
+        add("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",         0x00a3);
+        add("TLS_DH_DSS_WITH_AES_128_GCM_SHA256",          0x00a4);
+        add("TLS_DH_DSS_WITH_AES_256_GCM_SHA384",          0x00a5);
+        add("TLS_DH_anon_WITH_AES_128_GCM_SHA256",         0x00a6);
+        add("TLS_DH_anon_WITH_AES_256_GCM_SHA384",         0x00a7);
+
+        // Unsupported cipher suites from RFC 5487
+        add("TLS_PSK_WITH_AES_128_GCM_SHA256",             0x00a8);
+        add("TLS_PSK_WITH_AES_256_GCM_SHA384",             0x00a9);
+        add("TLS_DHE_PSK_WITH_AES_128_GCM_SHA256",         0x00aa);
+        add("TLS_DHE_PSK_WITH_AES_256_GCM_SHA384",         0x00ab);
+        add("TLS_RSA_PSK_WITH_AES_128_GCM_SHA256",         0x00ac);
+        add("TLS_RSA_PSK_WITH_AES_256_GCM_SHA384",         0x00ad);
+        add("TLS_PSK_WITH_AES_128_CBC_SHA256",             0x00ae);
+        add("TLS_PSK_WITH_AES_256_CBC_SHA384",             0x00af);
+        add("TLS_PSK_WITH_NULL_SHA256",                    0x00b0);
+        add("TLS_PSK_WITH_NULL_SHA384",                    0x00b1);
+        add("TLS_DHE_PSK_WITH_AES_128_CBC_SHA256",         0x00b2);
+        add("TLS_DHE_PSK_WITH_AES_256_CBC_SHA384",         0x00b3);
+        add("TLS_DHE_PSK_WITH_NULL_SHA256",                0x00b4);
+        add("TLS_DHE_PSK_WITH_NULL_SHA384",                0x00b5);
+        add("TLS_RSA_PSK_WITH_AES_128_CBC_SHA256",         0x00b6);
+        add("TLS_RSA_PSK_WITH_AES_256_CBC_SHA384",         0x00b7);
+        add("TLS_RSA_PSK_WITH_NULL_SHA256",                0x00b8);
+        add("TLS_RSA_PSK_WITH_NULL_SHA384",                0x00b9);
+
+        // Unsupported cipher suites from RFC 5932
+        add("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",           0x0041);
+        add("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA",        0x0042);
+        add("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA",        0x0043);
+        add("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA",       0x0044);
+        add("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",       0x0045);
+        add("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA",       0x0046);
+        add("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",           0x0084);
+        add("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA",        0x0085);
+        add("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA",        0x0086);
+        add("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA",       0x0087);
+        add("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",       0x0088);
+        add("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA",       0x0089);
+        add("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256",        0x00ba);
+        add("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256",     0x00bb);
+        add("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256",     0x00bc);
+        add("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256",    0x00bd);
+        add("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",    0x00be);
+        add("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256",    0x00bf);
+        add("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256",        0x00c0);
+        add("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256",     0x00c1);
+        add("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256",     0x00c2);
+        add("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256",    0x00c3);
+        add("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256",    0x00c4);
+        add("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256",    0x00c5);
+
+        // Unsupported cipher suites from RFC 5054
+        add("TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA",           0xc01a);
+        add("TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA",       0xc01b);
+        add("TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA",       0xc01c);
+        add("TLS_SRP_SHA_WITH_AES_128_CBC_SHA",            0xc01d);
+        add("TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA",        0xc01e);
+        add("TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA",        0xc01f);
+        add("TLS_SRP_SHA_WITH_AES_256_CBC_SHA",            0xc020);
+        add("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA",        0xc021);
+        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);
+        add("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",      0xc02e);
+        add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",       0xc02f);
+        add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",       0xc030);
+        add("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",        0xc031);
+        add("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",        0xc032);
+
+        // Unsupported cipher suites from RFC 5489
+        add("TLS_ECDHE_PSK_WITH_RC4_128_SHA",              0xc033);
+        add("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA",         0xc034);
+        add("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",          0xc035);
+        add("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",          0xc036);
+        add("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256",       0xc037);
+        add("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384",       0xc038);
+        add("TLS_ECDHE_PSK_WITH_NULL_SHA",                 0xc039);
+        add("TLS_ECDHE_PSK_WITH_NULL_SHA256",              0xc03a);
+        add("TLS_ECDHE_PSK_WITH_NULL_SHA384",              0xc03b);
     }
 
     // ciphersuite SSL_NULL_WITH_NULL_NULL
--- a/src/share/classes/sun/security/ssl/ClientHandshaker.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/ClientHandshaker.java	Sat Oct 30 18:39:17 2010 +0800
@@ -345,9 +345,10 @@
 
         // check if the server selected protocol version is OK for us
         ProtocolVersion mesgVersion = mesg.protocolVersion;
-        if (enabledProtocols.contains(mesgVersion) == false) {
-            throw new SSLHandshakeException
-            ("Server chose unsupported or disabled protocol: " + mesgVersion);
+        if (!isNegotiable(mesgVersion)) {
+            throw new SSLHandshakeException(
+                    "Server chose unsupported or disabled protocol: " +
+                    mesgVersion);
         }
 
         // Set protocolVersion and propagate to SSLSocket and the
@@ -1022,7 +1023,7 @@
         SessionId sessionId = SSLSessionImpl.nullSession.getSessionId();
 
         // a list of cipher suites sent by the client
-        CipherSuiteList cipherSuites = enabledCipherSuites;
+        CipherSuiteList cipherSuites = getActiveCipherSuites();
 
         // set the max protocol version this client is supporting.
         maxProtocolVersion = protocolVersion;
@@ -1057,8 +1058,7 @@
                 session = null;
             }
 
-            if ((session != null) &&
-                        (enabledProtocols.contains(sessionVersion) == false)) {
+            if ((session != null) && !isNegotiable(sessionVersion)) {
                 if (debug != null && Debug.isOn("session")) {
                     System.out.println("%% can't resume, protocol disabled");
                 }
@@ -1088,7 +1088,7 @@
              */
             if (!enableNewSession) {
                 if (session == null) {
-                    throw new SSLException(
+                    throw new SSLHandshakeException(
                         "Can't reuse existing SSL client session");
                 }
 
@@ -1105,7 +1105,7 @@
         }
 
         if (session == null && !enableNewSession) {
-            throw new SSLException("No existing session to resume");
+            throw new SSLHandshakeException("No existing session to resume");
         }
 
         // exclude SCSV for secure renegotiation
@@ -1131,7 +1131,7 @@
         }
 
         if (!negotiable) {
-            throw new SSLException("No negotiable cipher suite");
+            throw new SSLHandshakeException("No negotiable cipher suite");
         }
 
         // create the ClientHello message
--- a/src/share/classes/sun/security/ssl/Debug.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/Debug.java	Sat Oct 30 18:39:17 2010 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2009, 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,6 +27,7 @@
 
 import java.io.PrintStream;
 import java.security.AccessController;
+import java.util.Locale;
 
 import sun.security.action.GetPropertyAction;
 
@@ -44,7 +45,7 @@
     static {
         args = java.security.AccessController.doPrivileged(
             new GetPropertyAction("javax.net.debug", ""));
-        args = args.toLowerCase();
+        args = args.toLowerCase(Locale.ENGLISH);
         if (args.equals("help")) {
             Help();
         }
@@ -114,7 +115,7 @@
             return false;
         } else {
             int n = 0;
-            option = option.toLowerCase();
+            option = option.toLowerCase(Locale.ENGLISH);
 
             if (args.indexOf("all") != -1) {
                 return true;
--- a/src/share/classes/sun/security/ssl/HandshakeMessage.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/HandshakeMessage.java	Sat Oct 30 18:39:17 2010 +0800
@@ -1167,8 +1167,13 @@
             s.println();
 
             s.println("Cert Authorities:");
-            for (int i = 0; i < authorities.length; i++)
-                authorities[i].print(s);
+            if (authorities.length == 0) {
+                s.println("<Empty>");
+            } else {
+                for (int i = 0; i < authorities.length; i++) {
+                    authorities[i].print(s);
+                }
+            }
         }
     }
 }
--- a/src/share/classes/sun/security/ssl/Handshaker.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/Handshaker.java	Sat Oct 30 18:39:17 2010 +0800
@@ -71,11 +71,31 @@
     byte[]              clientVerifyData;
     byte[]              serverVerifyData;
 
-    // is it an initial negotiation  or a renegotiation?
+    // Is it an initial negotiation  or a renegotiation?
     boolean                     isInitialHandshake;
 
-    // list of enabled protocols
-    ProtocolList enabledProtocols;
+    // List of enabled protocols
+    private ProtocolList        enabledProtocols;
+
+    // List of enabled CipherSuites
+    private CipherSuiteList     enabledCipherSuites;
+
+    /*
+     * List of active protocols
+     *
+     * Active protocols is a subset of enabled protocols, and will
+     * contain only those protocols that have vaild cipher suites
+     * enabled.
+     */
+    private ProtocolList       activeProtocols;
+
+    /*
+     * List of active cipher suites
+     *
+     * Active cipher suites is a subset of enabled cipher suites, and will
+     * contain only those cipher suites available for the active protocols.
+     */
+    private CipherSuiteList    activeCipherSuites;
 
     private boolean             isClient;
 
@@ -94,9 +114,6 @@
     // in reset state after use.
     private MessageDigest md5Tmp, shaTmp;
 
-    // list of enabled CipherSuites
-    CipherSuiteList     enabledCipherSuites;
-
     // current CipherSuite. Never null, initially SSL_NULL_WITH_NULL_NULL
     CipherSuite         cipherSuite;
 
@@ -233,7 +250,7 @@
         // client's cert verify, those constants are in a convenient
         // order to drastically simplify state machine checking.
         //
-        state = -1;
+        state = -2;  // initialized but not activated
     }
 
     /*
@@ -345,26 +362,69 @@
     void setVersion(ProtocolVersion protocolVersion) {
         this.protocolVersion = protocolVersion;
         setVersionSE(protocolVersion);
+
         output.r.setVersion(protocolVersion);
     }
 
 
     /**
      * Set the enabled protocols. Called from the constructor or
-     * SSLSocketImpl.setEnabledProtocols() (if the handshake is not yet
-     * in progress).
+     * SSLSocketImpl/SSLEngineImpl.setEnabledProtocols() (if the
+     * handshake is not yet in progress).
      */
     void setEnabledProtocols(ProtocolList enabledProtocols) {
+        activeCipherSuites = null;
+        activeProtocols = null;
+
         this.enabledProtocols = enabledProtocols;
+    }
+
+    /**
+     * Set the enabled cipher suites. Called from
+     * SSLSocketImpl/SSLEngineImpl.setEnabledCipherSuites() (if the
+     * handshake is not yet in progress).
+     */
+    void setEnabledCipherSuites(CipherSuiteList enabledCipherSuites) {
+        activeCipherSuites = null;
+        activeProtocols = null;
+        this.enabledCipherSuites = enabledCipherSuites;
+    }
+
+
+    /**
+     * Prior to handshaking, activate the handshake and initialize the version,
+     * input stream and output stream.
+     */
+    void activate(ProtocolVersion helloVersion) throws IOException {
+        if (activeProtocols == null) {
+            activeProtocols = getActiveProtocols();
+        }
+
+        if (activeProtocols.collection().isEmpty() ||
+                activeProtocols.max.v == ProtocolVersion.NONE.v) {
+            throw new SSLHandshakeException("No appropriate protocol");
+        }
+
+        if (activeCipherSuites == null) {
+            activeCipherSuites = getActiveCipherSuites();
+        }
+
+        if (activeCipherSuites.collection().isEmpty()) {
+            throw new SSLHandshakeException("No appropriate cipher suite");
+        }
 
         // temporary protocol version until the actual protocol version
         // is negotiated in the Hello exchange. This affects the record
-        // version we sent with the ClientHello. Using max() as the record
-        // version is not really correct but some implementations fail to
-        // correctly negotiate TLS otherwise.
-        protocolVersion = enabledProtocols.max;
+        // version we sent with the ClientHello.
+        if (!isInitialHandshake) {
+            protocolVersion = activeProtocolVersion;
+        } else {
+            protocolVersion = activeProtocols.max;
+        }
 
-        ProtocolVersion helloVersion = enabledProtocols.helloVersion;
+        if (helloVersion == null || helloVersion.v == ProtocolVersion.NONE.v) {
+            helloVersion = activeProtocols.helloVersion;
+        }
 
         input = new HandshakeInStream(handshakeHash);
 
@@ -372,12 +432,16 @@
             output = new HandshakeOutStream(protocolVersion, helloVersion,
                                         handshakeHash, conn);
             conn.getAppInputStream().r.setHelloVersion(helloVersion);
+            conn.getAppOutputStream().r.setHelloVersion(helloVersion);
         } else {
             output = new HandshakeOutStream(protocolVersion, helloVersion,
                                         handshakeHash, engine);
+            engine.inputRecord.setHelloVersion(helloVersion);
             engine.outputRecord.setHelloVersion(helloVersion);
         }
 
+        // move state to activated
+        state = -1;
     }
 
     /**
@@ -392,20 +456,127 @@
 
     /**
      * Check if the given ciphersuite is enabled and available.
-     * (Enabled ciphersuites are always available unless the status has
-     * changed due to change in JCE providers since it was enabled).
      * Does not check if the required server certificates are available.
      */
     boolean isNegotiable(CipherSuite s) {
-        return enabledCipherSuites.contains(s) && s.isNegotiable();
+        if (activeCipherSuites == null) {
+            activeCipherSuites = getActiveCipherSuites();
+        }
+
+        return activeCipherSuites.contains(s) && s.isNegotiable();
     }
 
     /**
-     * As long as handshaking has not started, we can
+     * Check if the given protocol version is enabled and available.
+     */
+    boolean isNegotiable(ProtocolVersion protocolVersion) {
+        if (activeProtocols == null) {
+            activeProtocols = getActiveProtocols();
+        }
+
+        return activeProtocols.contains(protocolVersion);
+    }
+
+    /**
+     * Select a protocol version from the list. Called from
+     * ServerHandshaker to negotiate protocol version.
+     *
+     * Return the lower of the protocol version suggested in the
+     * clien hello and the highest supported by the server.
+     */
+    ProtocolVersion selectProtocolVersion(ProtocolVersion protocolVersion) {
+        if (activeProtocols == null) {
+            activeProtocols = getActiveProtocols();
+        }
+
+        return activeProtocols.selectProtocolVersion(protocolVersion);
+    }
+
+    /**
+     * Get the active cipher suites.
+     *
+     * In TLS 1.1, many weak or vulnerable cipher suites were obsoleted,
+     * such as TLS_RSA_EXPORT_WITH_RC4_40_MD5. The implementation MUST NOT
+     * negotiate these cipher suites in TLS 1.1 or later mode.
+     *
+     * 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
+     * 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.
+     *
+     * Return empty list instead of null if no active cipher suites.
+     */
+    CipherSuiteList getActiveCipherSuites() {
+        if (activeCipherSuites == null) {
+            if (activeProtocols == null) {
+                activeProtocols = getActiveProtocols();
+            }
+
+            ArrayList<CipherSuite> suites = new ArrayList<CipherSuite>();
+            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);
+                    }
+                }
+            }
+            activeCipherSuites = new CipherSuiteList(suites);
+        }
+
+        return activeCipherSuites;
+    }
+
+    /*
+     * Get the active protocol versions.
+     *
+     * In TLS 1.1, many weak or vulnerable cipher suites were obsoleted,
+     * such as TLS_RSA_EXPORT_WITH_RC4_40_MD5. The implementation MUST NOT
+     * negotiate these cipher suites in TLS 1.1 or later mode.
+     *
+     * For example, if "TLS_RSA_EXPORT_WITH_RC4_40_MD5" is the
+     * only enabled cipher suite, the client cannot request TLS 1.1 or
+     * later, even though TLS 1.1 or later is enabled.  We need to create a
+     * subset of the enabled protocols, called the active protocols, which
+     * contains protocols appropriate to the list of enabled Ciphersuites.
+     *
+     * Return empty list instead of null if no active protocol versions.
+     */
+    ProtocolList getActiveProtocols() {
+        if (activeProtocols == null) {
+            ArrayList<ProtocolVersion> protocols =
+                                            new ArrayList<ProtocolVersion>(3);
+            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 (!found && (debug != null) && Debug.isOn("handshake")) {
+                    System.out.println(
+                        "No available cipher suite for " + protocol);
+                }
+            }
+            activeProtocols = new ProtocolList(protocols);
+        }
+
+        return activeProtocols;
+    }
+
+    /**
+     * As long as handshaking has not activated, we can
      * change whether session creations are allowed.
      *
      * Callers should do their own checking if handshaking
-     * has started.
+     * has activated.
      */
     void setEnableSessionCreation(boolean newSessions) {
         enableNewSession = newSessions;
@@ -419,12 +590,12 @@
         CipherBox box;
         if (isClient) {
             box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV,
-                                   false);
+                                   sslContext.getSecureRandom(), false);
             svrWriteKey = null;
             svrWriteIV = null;
         } else {
             box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV,
-                                   false);
+                                   sslContext.getSecureRandom(), false);
             clntWriteKey = null;
             clntWriteIV = null;
         }
@@ -439,12 +610,12 @@
         CipherBox box;
         if (isClient) {
             box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV,
-                                   true);
+                                   sslContext.getSecureRandom(), true);
             clntWriteKey = null;
             clntWriteIV = null;
         } else {
             box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV,
-                                   true);
+                                   sslContext.getSecureRandom(), true);
             svrWriteKey = null;
             svrWriteIV = null;
         }
@@ -614,13 +785,20 @@
 
 
     /**
+     * Returns true iff the handshaker has been activated.
+     *
+     * In activated state, the handshaker may not send any messages out.
+     */
+    boolean activated() {
+        return state >= -1;
+    }
+
+    /**
      * Returns true iff the handshaker has sent any messages.
-     * Server kickstarting is not as neat as it should be; we
-     * need to create a new handshaker, this method lets us
-     * know if we should.
      */
     boolean started() {
-        return state >= 0;
+        return state >= 0;  // 0: HandshakeMessage.ht_hello_request
+                            // 1: HandshakeMessage.ht_hello_request
     }
 
 
@@ -633,6 +811,7 @@
         if (state >= 0) {
             return;
         }
+
         HandshakeMessage m = getKickstartMessage();
 
         if (debug != null && Debug.isOn("handshake")) {
@@ -746,6 +925,7 @@
      */
     private SecretKey calculateMasterSecret(SecretKey preMasterSecret,
             ProtocolVersion requestedVersion) {
+
         TlsMasterSecretParameterSpec spec = new TlsMasterSecretParameterSpec
                 (preMasterSecret, protocolVersion.major, protocolVersion.minor,
                 clnt_random.random_bytes, svr_random.random_bytes);
@@ -773,22 +953,37 @@
             if (!preMasterSecret.getAlgorithm().equals("TlsRsaPremasterSecret")) {
                 throw new ProviderException(e);
             }
+
             if (debug != null && Debug.isOn("handshake")) {
                 System.out.println("RSA master secret generation error:");
                 e.printStackTrace(System.out);
                 System.out.println("Generating new random premaster secret");
             }
-            preMasterSecret = RSAClientKeyExchange.generateDummySecret(protocolVersion);
+
+            if (requestedVersion != null) {
+                preMasterSecret =
+                    RSAClientKeyExchange.generateDummySecret(requestedVersion);
+            } else {
+                preMasterSecret =
+                    RSAClientKeyExchange.generateDummySecret(protocolVersion);
+            }
+
             // recursive call with new premaster secret
             return calculateMasterSecret(preMasterSecret, null);
         }
 
-        // if no version check requested (client side handshake),
-        // or version information is not available (not an RSA premaster secret),
+        // if no version check requested (client side handshake), or version
+        // information is not available (not an RSA premaster secret),
         // return master secret immediately.
-        if ((requestedVersion == null) || !(masterSecret instanceof TlsMasterSecret)) {
+        if ((requestedVersion == null) ||
+                !(masterSecret instanceof TlsMasterSecret)) {
             return masterSecret;
         }
+
+        // we have checked the ClientKeyExchange message when reading TLS
+        // record, the following check is necessary to ensure that
+        // JCE provider does not ignore the checking, or the previous
+        // checking process bypassed the premaster secret version checking.
         TlsMasterSecret tlsKey = (TlsMasterSecret)masterSecret;
         int major = tlsKey.getMajorVersion();
         int minor = tlsKey.getMinorVersion();
@@ -800,13 +995,21 @@
         // the specification says that it must be the maximum version supported
         // by the client from its ClientHello message. However, many
         // implementations send the negotiated version, so accept both
-        // NOTE that we may be comparing two unsupported version numbers in
-        // the second case, which is why we cannot use object reference
-        // equality in this special case
-        ProtocolVersion premasterVersion = ProtocolVersion.valueOf(major, minor);
-        boolean versionMismatch = (premasterVersion != protocolVersion) &&
-                                  (premasterVersion.v != requestedVersion.v);
+        // for SSL v3.0 and TLS v1.0.
+        // NOTE that we may be comparing two unsupported version numbers, which
+        // is why we cannot use object reference equality in this special case.
+        ProtocolVersion premasterVersion =
+                                    ProtocolVersion.valueOf(major, minor);
+        boolean versionMismatch = (premasterVersion.v != requestedVersion.v);
 
+        /*
+         * we never checked the client_version in server side
+         * for TLS v1.0 and SSL v3.0. For compatibility, we
+         * maintain this behavior.
+         */
+        if (versionMismatch && requestedVersion.v <= ProtocolVersion.TLS10.v) {
+            versionMismatch = (premasterVersion.v != protocolVersion.v);
+        }
 
         if (versionMismatch == false) {
             // check passed, return key
@@ -823,7 +1026,9 @@
                 + premasterVersion);
             System.out.println("Generating new random premaster secret");
         }
-        preMasterSecret = RSAClientKeyExchange.generateDummySecret(protocolVersion);
+        preMasterSecret =
+            RSAClientKeyExchange.generateDummySecret(requestedVersion);
+
         // recursive call with new premaster secret
         return calculateMasterSecret(preMasterSecret, null);
     }
@@ -849,8 +1054,6 @@
         int hashSize = cipherSuite.macAlg.size;
         boolean is_exportable = cipherSuite.exportable;
         BulkCipher cipher = cipherSuite.cipher;
-        int keySize = cipher.keySize;
-        int ivSize = cipher.ivSize;
         int expandedKeySize = is_exportable ? cipher.expandedKeySize : 0;
 
         TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec
@@ -867,6 +1070,8 @@
             clntWriteKey = keySpec.getClientCipherKey();
             svrWriteKey = keySpec.getServerCipherKey();
 
+            // Return null if IVs are not supposed to be generated.
+            // e.g. TLS 1.1+.
             clntWriteIV = keySpec.getClientIv();
             svrWriteIV = keySpec.getServerIv();
 
@@ -914,7 +1119,12 @@
                     System.out.println("Server write IV:");
                     printHex(dump, svrWriteIV.getIV());
                 } else {
-                    System.out.println("... no IV used for this cipher");
+                    if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                        System.out.println(
+                                "... no IV derived for this protocol");
+                    } else {
+                        System.out.println("... no IV used for this cipher");
+                    }
                 }
                 System.out.flush();
             }
--- a/src/share/classes/sun/security/ssl/KerberosClientKeyExchange.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/KerberosClientKeyExchange.java	Sat Oct 30 18:39:17 2010 +0800
@@ -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
@@ -69,6 +69,7 @@
     }
 
     public KerberosClientKeyExchange() {
+        // empty
     }
 
     public KerberosClientKeyExchange(String serverName, boolean isLoopback,
@@ -93,14 +94,17 @@
         }
     }
 
+    @Override
     int messageType() {
         return ht_client_key_exchange;
     }
 
+    @Override
     public int  messageLength() {
         return impl.messageLength();
     }
 
+    @Override
     public void send(HandshakeOutStream s) throws IOException {
         impl.send(s);
     }
--- a/src/share/classes/sun/security/ssl/MAC.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/MAC.java	Sat Oct 30 18:39:17 2010 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2007, 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
@@ -155,6 +155,42 @@
         return compute(type, bb, null, 0, bb.remaining());
     }
 
+    /**
+     * Check whether the sequence number is close to wrap
+     *
+     * Sequence numbers are of type uint64 and may not exceed 2^64-1.
+     * Sequence numbers do not wrap. When the sequence number is near
+     * to wrap, we need to close the connection immediately.
+     */
+    final boolean seqNumOverflow() {
+        /*
+         * Conservatively, we don't allow more records to be generated
+         * when there are only 2^8 sequence numbers left.
+         */
+        return (block != null && mac != null &&
+                block[0] == 0xFF && block[1] == 0xFF &&
+                block[2] == 0xFF && block[3] == 0xFF &&
+                block[4] == 0xFF && block[5] == 0xFF &&
+                block[6] == 0xFF);
+    }
+
+    /*
+     * Check whether to renew the sequence number
+     *
+     * Sequence numbers are of type uint64 and may not exceed 2^64-1.
+     * Sequence numbers do not wrap.  If a TLS
+     * implementation would need to wrap a sequence number, it must
+     * renegotiate instead.
+     */
+    final boolean seqNumIsHuge() {
+        /*
+         * Conservatively, we should ask for renegotiation when there are
+         * only 2^48 sequence numbers left.
+         */
+        return (block != null && mac != null &&
+                block[0] == 0xFF && block[1] == 0xFF);
+    }
+
     // increment the sequence number in the block array
     // it is a 64-bit number stored in big-endian format
     private void incrementSequenceNumber() {
--- a/src/share/classes/sun/security/ssl/ProtocolList.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/ProtocolList.java	Sat Oct 30 18:39:17 2010 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2008, 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
@@ -38,8 +38,12 @@
 final class ProtocolList {
 
     private static final ProtocolList SUPPORTED;
+    private static final ProtocolList CLIENT_DEFAULT;
+    private static final ProtocolList SERVER_DEFAULT;
 
-    private final Collection<ProtocolVersion> protocols;
+    // the sorted protocol version list
+    private final ArrayList<ProtocolVersion> protocols;
+
     private String[] protocolNames;
 
     // the minimum and maximum ProtocolVersions in this list
@@ -49,30 +53,45 @@
     final ProtocolVersion helloVersion;
 
     ProtocolList(String[] names) {
+        this(convert(names));
+    }
+
+    ProtocolList(ArrayList<ProtocolVersion> versions) {
+        this.protocols = versions;
+
+        if ((protocols.size() == 1) &&
+                protocols.contains(ProtocolVersion.SSL20Hello)) {
+            throw new IllegalArgumentException("SSLv2Hello cannot be " +
+                "enabled unless at least one other supported version " +
+                "is also enabled.");
+        }
+
+        if (protocols.size() != 0) {
+            Collections.sort(protocols);
+            min = protocols.get(0);
+            max = protocols.get(protocols.size() - 1);
+            helloVersion = protocols.get(0);
+        } else {
+            min = ProtocolVersion.NONE;
+            max = ProtocolVersion.NONE;
+            helloVersion = ProtocolVersion.NONE;
+        }
+    }
+
+    private static ArrayList<ProtocolVersion> convert(String[] names) {
         if (names == null) {
             throw new IllegalArgumentException("Protocols may not be null");
         }
-        protocols = new ArrayList<ProtocolVersion>(3);
+
+        ArrayList<ProtocolVersion> versions = new ArrayList<ProtocolVersion>(3);
         for (int i = 0; i < names.length; i++ ) {
             ProtocolVersion version = ProtocolVersion.valueOf(names[i]);
-            if (protocols.contains(version) == false) {
-                protocols.add(version);
+            if (versions.contains(version) == false) {
+                versions.add(version);
             }
         }
-        if ((protocols.size() == 1)
-                && protocols.contains(ProtocolVersion.SSL20Hello)) {
-            throw new IllegalArgumentException("SSLv2Hello" +
-                  "cannot be enabled unless TLSv1 or SSLv3 is also enabled");
-        }
-        min = contains(ProtocolVersion.SSL30) ? ProtocolVersion.SSL30
-                                              : ProtocolVersion.TLS10;
-        max = contains(ProtocolVersion.TLS10) ? ProtocolVersion.TLS10
-                                              : ProtocolVersion.SSL30;
-        if (protocols.contains(ProtocolVersion.SSL20Hello)) {
-            helloVersion = ProtocolVersion.SSL20Hello;
-        } else {
-            helloVersion = min;
-        }
+
+        return versions;
     }
 
     /**
@@ -88,6 +107,37 @@
     }
 
     /**
+     * Return a reference to the internal Collection of CipherSuites.
+     * The Collection MUST NOT be modified.
+     */
+    Collection<ProtocolVersion> collection() {
+        return protocols;
+    }
+
+    /**
+     * Select a protocol version from the list.
+     *
+     * Return the lower of the protocol version of that suggested by
+     * the <code>protocolVersion</code> and the highest version of this
+     * protocol list, or null if no protocol version is available.
+     *
+     * The method is used by TLS server to negotiated the protocol
+     * version between client suggested protocol version in the
+     * client hello and protocol versions supported by the server.
+     */
+    ProtocolVersion selectProtocolVersion(ProtocolVersion protocolVersion) {
+        ProtocolVersion selectedVersion = null;
+        for (ProtocolVersion pv : protocols) {
+            if (pv.v > protocolVersion.v) {
+                break;  // Safe to break here as this.protocols is sorted
+            }
+            selectedVersion = pv;
+        }
+
+        return selectedVersion;
+    }
+
+    /**
      * Return an array with the names of the ProtocolVersions in this list.
      */
     synchronized String[] toStringArray() {
@@ -106,11 +156,18 @@
     }
 
     /**
-     * Return the list of default enabled protocols. Currently, this
-     * is identical to the supported protocols.
+     * Return the list of default enabled protocols.
      */
-    static ProtocolList getDefault() {
-        return SUPPORTED;
+    static ProtocolList getDefault(boolean isServer) {
+        return isServer ? SERVER_DEFAULT : CLIENT_DEFAULT;
+    }
+
+    /**
+     * Return whether a protocol list is the original default enabled
+     * protocols.  See: SSLSocket/SSLEngine.setEnabledProtocols()
+     */
+    static boolean isDefaultProtocolList(ProtocolList protocols) {
+        return protocols == CLIENT_DEFAULT || protocols == SERVER_DEFAULT;
     }
 
     /**
@@ -123,6 +180,12 @@
     static {
         if (SunJSSE.isFIPS()) {
             SUPPORTED = new ProtocolList(new String[] {
+                ProtocolVersion.TLS10.name,
+                ProtocolVersion.TLS11.name
+            });
+
+            SERVER_DEFAULT = SUPPORTED;
+            CLIENT_DEFAULT = new ProtocolList(new String[] {
                 ProtocolVersion.TLS10.name
             });
         } else {
@@ -130,6 +193,13 @@
                 ProtocolVersion.SSL20Hello.name,
                 ProtocolVersion.SSL30.name,
                 ProtocolVersion.TLS10.name,
+                ProtocolVersion.TLS11.name
+            });
+
+            SERVER_DEFAULT = SUPPORTED;
+            CLIENT_DEFAULT = new ProtocolList(new String[] {
+                ProtocolVersion.SSL30.name,
+                ProtocolVersion.TLS10.name
             });
         }
     }
--- a/src/share/classes/sun/security/ssl/ProtocolVersion.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/ProtocolVersion.java	Sat Oct 30 18:39:17 2010 +0800
@@ -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
@@ -45,9 +45,12 @@
  * @author  Andreas Sterbenz
  * @since   1.4.1
  */
-public final class ProtocolVersion {
+public final class ProtocolVersion implements Comparable<ProtocolVersion> {
 
-    // dummy protocol version value for invalid SSLSession
+    // The limit of maximum protocol version
+    final static int LIMIT_MAX_VALUE = 0xFFFF;
+
+    // Dummy protocol version value for invalid SSLSession
     final static ProtocolVersion NONE = new ProtocolVersion(-1, "NONE");
 
     // If enabled, send/ accept SSLv2 hello messages
@@ -61,22 +64,24 @@
     final static ProtocolVersion TLS10 = new ProtocolVersion(0x0301, "TLSv1");
 
     // TLS 1.1
-    // not supported yet, but added for better readability of the debug trace
     final static ProtocolVersion TLS11 = new ProtocolVersion(0x0302, "TLSv1.1");
 
+    // TLS 1.2
+    final static ProtocolVersion TLS12 = new ProtocolVersion(0x0303, "TLSv1.2");
+
     private static final boolean FIPS = SunJSSE.isFIPS();
 
     // minimum version we implement (SSL 3.0)
     final static ProtocolVersion MIN = FIPS ? TLS10 : SSL30;
 
-    // maximum version we implement (TLS 1.0)
-    final static ProtocolVersion MAX = TLS10;
+    // maximum version we implement (TLS 1.1)
+    final static ProtocolVersion MAX = TLS11;
 
     // ProtocolVersion to use by default (TLS 1.0)
     final static ProtocolVersion DEFAULT = TLS10;
 
     // Default version for hello messages (SSLv2Hello)
-    final static ProtocolVersion DEFAULT_HELLO = FIPS ? TLS10 : SSL20Hello;
+    final static ProtocolVersion DEFAULT_HELLO = FIPS ? TLS10 : SSL30;
 
     // version in 16 bit MSB format as it appears in records and
     // messages, i.e. 0x0301 for TLS 1.0
@@ -104,6 +109,8 @@
             return TLS10;
         } else if (v == TLS11.v) {
             return TLS11;
+        } else if (v == TLS12.v) {
+            return TLS12;
         } else if (v == SSL20Hello.v) {
             return SSL20Hello;
         } else {
@@ -134,18 +141,20 @@
         if (name == null) {
             throw new IllegalArgumentException("Protocol cannot be null");
         }
-        if (FIPS) {
-            if (name.equals(TLS10.name)) {
-                return TLS10;
-            } else {
-                throw new IllegalArgumentException
-                    ("Only TLS 1.0 allowed in FIPS mode");
-            }
+
+        if (FIPS && (name.equals(SSL30.name) || name.equals(SSL20Hello.name))) {
+            throw new IllegalArgumentException
+                ("Only TLS 1.0 or later allowed in FIPS mode");
         }
+
         if (name.equals(SSL30.name)) {
             return SSL30;
         } else if (name.equals(TLS10.name)) {
             return TLS10;
+        } else if (name.equals(TLS11.name)) {
+            return TLS11;
+        } else if (name.equals(TLS12.name)) {
+            return TLS12;
         } else if (name.equals(SSL20Hello.name)) {
             return SSL20Hello;
         } else {
@@ -157,4 +166,10 @@
         return name;
     }
 
+    /**
+     * Compares this object with the specified object for order.
+     */
+    public int compareTo(ProtocolVersion protocolVersion) {
+        return this.v - protocolVersion.v;
+    }
 }
--- a/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java	Sat Oct 30 18:39:17 2010 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2007, 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
@@ -55,20 +55,17 @@
      * requested in its client hello version). However, we (and other
      * implementations) used to send the active negotiated version. The
      * system property below allows to toggle the behavior.
-     *
-     * Default is "false" (old behavior) for compatibility reasons. This
-     * will be changed in the future.
      */
     private final static String PROP_NAME =
                                 "com.sun.net.ssl.rsaPreMasterSecretFix";
 
+    /*
+     * Default is "false" (old behavior) for compatibility reasons in
+     * SSLv3/TLSv1.  Later protocols (TLSv1.1+) do not use this property.
+     */
     private final static boolean rsaPreMasterSecretFix =
                                 Debug.getBooleanProperty(PROP_NAME, false);
 
-    int messageType() {
-        return ht_client_key_exchange;
-    }
-
     /*
      * The following field values were encrypted with the server's public
      * key (or temp key from server key exchange msg) and are presented
@@ -78,14 +75,14 @@
     SecretKey preMaster;
     private byte[] encrypted;           // same size as public modulus
 
-
     /*
      * Client randomly creates a pre-master secret and encrypts it
      * using the server's RSA public key; only the server can decrypt
      * it, using its RSA private key.  Result is the same size as the
      * server's public key, and uses PKCS #1 block format 02.
      */
-    RSAClientKeyExchange(ProtocolVersion protocolVersion, ProtocolVersion maxVersion,
+    RSAClientKeyExchange(ProtocolVersion protocolVersion,
+            ProtocolVersion maxVersion,
             SecureRandom generator, PublicKey publicKey) throws IOException {
         if (publicKey.getAlgorithm().equals("RSA") == false) {
             throw new SSLKeyException("Public key not of type RSA");
@@ -94,7 +91,7 @@
 
         int major, minor;
 
-        if (rsaPreMasterSecretFix) {
+        if (rsaPreMasterSecretFix || maxVersion.v >= ProtocolVersion.TLS11.v) {
             major = maxVersion.major;
             minor = maxVersion.minor;
         } else {
@@ -103,7 +100,8 @@
         }
 
         try {
-            KeyGenerator kg = JsseJce.getKeyGenerator("SunTlsRsaPremasterSecret");
+            KeyGenerator kg =
+                        JsseJce.getKeyGenerator("SunTlsRsaPremasterSecret");
             kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor));
             preMaster = kg.generateKey();
 
@@ -120,14 +118,15 @@
      * Server gets the PKCS #1 (block format 02) data, decrypts
      * it with its private key.
      */
-    RSAClientKeyExchange(ProtocolVersion currentVersion, HandshakeInStream input,
+    RSAClientKeyExchange(ProtocolVersion currentVersion,
+            ProtocolVersion maxVersion,
+            SecureRandom generator, HandshakeInStream input,
             int messageSize, PrivateKey privateKey) throws IOException {
 
         if (privateKey.getAlgorithm().equals("RSA") == false) {
             throw new SSLKeyException("Private key not of type RSA");
         }
 
-        this.protocolVersion = currentVersion;
         if (currentVersion.v >= ProtocolVersion.TLS10.v) {
             encrypted = input.getBytes16();
         } else {
@@ -143,24 +142,101 @@
             cipher.init(Cipher.UNWRAP_MODE, privateKey);
             preMaster = (SecretKey)cipher.unwrap(encrypted,
                                 "TlsRsaPremasterSecret", Cipher.SECRET_KEY);
+
+            // polish the premaster secret
+            preMaster = polishPreMasterSecretKey(currentVersion, maxVersion,
+                                                generator, preMaster, null);
         } catch (Exception e) {
-            /*
-             * Bogus decrypted ClientKeyExchange? If so, conjure a
-             * a random preMaster secret that will fail later during
-             * Finished message processing. This is a countermeasure against
-             * the "interactive RSA PKCS#1 encryption envelop attack" reported
-             * in June 1998. Preserving the executation path will
-             * mitigate timing attacks and force consistent error handling
-             * that will prevent an attacking client from differentiating
-             * different kinds of decrypted ClientKeyExchange bogosities.
-             */
-            if (debug != null && Debug.isOn("handshake")) {
+            // polish the premaster secret
+            preMaster =
+                    polishPreMasterSecretKey(currentVersion, maxVersion,
+                                                generator, null, e);
+        }
+    }
+
+    /**
+     * To avoid vulnerabilities described by section 7.4.7.1, RFC 5246,
+     * treating incorrectly formatted message blocks and/or mismatched
+     * version numbers in a manner indistinguishable from correctly
+     * formatted RSA blocks.
+     *
+     * RFC 5246 describes the approach as :
+     *
+     *  1. Generate a string R of 46 random bytes
+     *
+     *  2. Decrypt the message to recover the plaintext M
+     *
+     *  3. If the PKCS#1 padding is not correct, or the length of message
+     *     M is not exactly 48 bytes:
+     *        pre_master_secret = ClientHello.client_version || R
+     *     else If ClientHello.client_version <= TLS 1.0, and version
+     *     number check is explicitly disabled:
+     *        pre_master_secret = M
+     *     else:
+     *        pre_master_secret = ClientHello.client_version || M[2..47]
+     */
+    private SecretKey polishPreMasterSecretKey(ProtocolVersion currentVersion,
+            ProtocolVersion clientHelloVersion, SecureRandom generator,
+            SecretKey secretKey, Exception failoverException) {
+
+        this.protocolVersion = clientHelloVersion;
+
+        if (failoverException == null && secretKey != null) {
+            // check the length
+            byte[] encoded = secretKey.getEncoded();
+            if (encoded == null) {      // unable to get the encoded key
+                if (debug != null && Debug.isOn("handshake")) {
+                    System.out.println(
+                        "unable to get the plaintext of the premaster secret");
+                }
+
+                // We are not always able to get the encoded key of the
+                // premaster secret. Pass the cheking to master secret
+                // calculation.
+                return secretKey;
+            } else if (encoded.length == 48) {
+                // check the version
+                if (clientHelloVersion.major == encoded[0] &&
+                    clientHelloVersion.minor == encoded[1]) {
+                    return secretKey;
+                } else if (clientHelloVersion.v <= ProtocolVersion.TLS10.v) {
+                    /*
+                     * we never checked the client_version in server side
+                     * for TLS v1.0 and SSL v3.0. For compatibility, we
+                     * maintain this behavior.
+                     */
+                    if (currentVersion.major == encoded[0] &&
+                        currentVersion.minor == encoded[1]) {
+                        this.protocolVersion = currentVersion;
+                        return secretKey;
+                    }
+                }
+
+                if (debug != null && Debug.isOn("handshake")) {
+                    System.out.println("Mismatching Protocol Versions, " +
+                        "ClientHello.client_version is " + clientHelloVersion +
+                        ", while PreMasterSecret.client_version is " +
+                        ProtocolVersion.valueOf(encoded[0], encoded[1]));
+                }
+            } else {
+                if (debug != null && Debug.isOn("handshake")) {
+                    System.out.println(
+                        "incorrect length of premaster secret: " +
+                        encoded.length);
+                }
+            }
+        }
+
+        if (debug != null && Debug.isOn("handshake")) {
+            if (failoverException != null) {
                 System.out.println("Error decrypting premaster secret:");
-                e.printStackTrace(System.out);
-                System.out.println("Generating random secret");
+                failoverException.printStackTrace(System.out);
             }
-            preMaster = generateDummySecret(currentVersion);
+
+            System.out.println("Generating random secret");
         }
+
+        return generateDummySecret(clientHelloVersion);
     }
 
     // generate a premaster secret with the specified version number
@@ -176,6 +252,12 @@
         }
     }
 
+    @Override
+    int messageType() {
+        return ht_client_key_exchange;
+    }
+
+    @Override
     int messageLength() {
         if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
             return encrypted.length + 2;
@@ -184,6 +266,7 @@
         }
     }
 
+    @Override
     void send(HandshakeOutStream s) throws IOException {
         if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
             s.putBytes16(encrypted);
@@ -192,7 +275,9 @@
         }
     }
 
+    @Override
     void print(PrintStream s) throws IOException {
-        s.println("*** ClientKeyExchange, RSA PreMasterSecret, " + protocolVersion);
+        s.println("*** ClientKeyExchange, RSA PreMasterSecret, " +
+                                                        protocolVersion);
     }
 }
--- a/src/share/classes/sun/security/ssl/Record.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/Record.java	Sat Oct 30 18:39:17 2010 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2007, 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
@@ -47,11 +47,12 @@
     static final byte   ct_handshake = 22;
     static final byte   ct_application_data = 23;
 
-    static final int            headerSize = 5;         // SSLv3 record header
-    static final int            maxExpansion = 1024;    // for bad compression
-    static final int            trailerSize = 20;       // SHA1 hash size
-    static final int            maxDataSize = 16384;    // 2^14 bytes of data
-    static final int            maxPadding = 256;       // block cipher padding
+    static final int    headerSize = 5;         // SSLv3 record header
+    static final int    maxExpansion = 1024;    // for bad compression
+    static final int    trailerSize = 20;       // SHA1 hash size
+    static final int    maxDataSize = 16384;    // 2^14 bytes of data
+    static final int    maxPadding = 256;       // block cipher padding
+    static final int    maxIVLength = 256;      // block length
 
     /*
      * SSL has a maximum record size.  It's header, (compressed) data,
@@ -59,8 +60,9 @@
      * Some compression algorithms have rare cases where they expand the data.
      * As we don't support compression at this time, leave that out.
      */
-    static final int            maxRecordSize =
+    static final int    maxRecordSize =
                                       headerSize        // header
+                                    + maxIVLength       // iv
                                     + maxDataSize       // data
                                     + maxPadding        // padding
                                     + trailerSize;      // MAC
@@ -74,7 +76,7 @@
      * The maximum large record size is defined as maxRecordSize plus 2^14,
      * this is the amount OpenSSL is using.
      */
-    static final int            maxLargeRecordSize =
+    static final int    maxLargeRecordSize =
                 maxRecordSize   // Max size with a conforming implemenation
               + maxDataSize;    // extra 2^14 bytes for large data packets.
 
@@ -84,7 +86,11 @@
      * They only contain 2 and 1 bytes of data, respectively.
      * Allocate a smaller array.
      */
-    static final int maxAlertRecordSize =
-                        headerSize + 2 + maxPadding + trailerSize;
+    static final int    maxAlertRecordSize =
+                                      headerSize        // header
+                                    + maxIVLength       // iv
+                                    + 2                 // alert
+                                    + maxPadding        // padding
+                                    + trailerSize;      // MAC
 
 }
--- a/src/share/classes/sun/security/ssl/SSLEngineImpl.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/SSLEngineImpl.java	Sat Oct 30 18:39:17 2010 +0800
@@ -240,12 +240,14 @@
      * session is changed.
      */
     private byte                        doClientAuth;
-    private CipherSuiteList             enabledCipherSuites;
     private boolean                     enableSessionCreation = true;
     EngineInputRecord                   inputRecord;
     EngineOutputRecord                  outputRecord;
     private AccessControlContext        acc;
 
+    // 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;
@@ -255,11 +257,11 @@
     private boolean                     roleIsServer;
 
     /*
-     * The protocols we support are SSL Version 3.0) and
-     * TLS (version 3.1).
-     * In addition we support a pseudo protocol called
-     * SSLv2Hello which when set will result in an SSL v2 Hello
-     * being sent with SSLv3 or TLSv1 version info.
+     * The protocol versions enabled for use on this connection.
+     *
+     * Note: we support a pseudo protocol called SSLv2Hello which when
+     * set will result in an SSL v2 Hello being sent with SSL (version 3.0)
+     * or TLS (version 3.1, 3.2, etc.) version info.
      */
     private ProtocolList        enabledProtocols;
 
@@ -368,7 +370,7 @@
         serverVerifyData = new byte[0];
 
         enabledCipherSuites = CipherSuiteList.getDefault();
-        enabledProtocols = ProtocolList.getDefault();
+        enabledProtocols = ProtocolList.getDefault(roleIsServer);
 
         wrapLock = new Object();
         unwrapLock = new Object();
@@ -405,8 +407,8 @@
      *  . if the engine is already closed, throw an Exception (internal error)
      *
      *  . otherwise (cs_START or cs_DATA), create the appropriate handshaker
-     *    object, initialize it, and advance the connection state (to
-     *    cs_HANDSHAKE or cs_RENEGOTIATE, respectively).
+     *    object and advance the connection state (to cs_HANDSHAKE or
+     *    cs_RENEGOTIATE, respectively).
      *
      * This method is called right after a new engine is created, when
      * starting renegotiation, or when changing client/server mode of the
@@ -454,12 +456,8 @@
                     protocolVersion, connectionState == cs_HANDSHAKE,
                     secureRenegotiation, clientVerifyData, serverVerifyData);
         }
-        handshaker.enabledCipherSuites = enabledCipherSuites;
+        handshaker.setEnabledCipherSuites(enabledCipherSuites);
         handshaker.setEnableSessionCreation(enableSessionCreation);
-        if (connectionState == cs_RENEGOTIATE) {
-            // don't use SSLv2Hello when renegotiating
-            handshaker.output.r.setHelloVersion(protocolVersion);
-        }
     }
 
     /*
@@ -686,7 +684,15 @@
         // to its HandshakeOutStream, which calls back into
         // SSLSocketImpl.writeRecord() to send it.
         //
-        if (!handshaker.started()) {
+        if (!handshaker.activated()) {
+             // prior to handshaking, activate the handshake
+            if (connectionState == cs_RENEGOTIATE) {
+                // don't use SSLv2Hello when renegotiating
+                handshaker.activate(protocolVersion);
+            } else {
+                handshaker.activate(null);
+            }
+
             if (handshaker instanceof ClientHandshaker) {
                 // send client hello
                 handshaker.kickstart();
@@ -696,6 +702,7 @@
                 } else {
                     // we want to renegotiate, send hello request
                     handshaker.kickstart();
+
                     // hello request is not included in the handshake
                     // hashes, reset them
                     handshaker.handshakeHash.reset();
@@ -982,6 +989,15 @@
                      * in it.
                      */
                     initHandshaker();
+                    if (!handshaker.activated()) {
+                        // prior to handshaking, activate the handshake
+                        if (connectionState == cs_RENEGOTIATE) {
+                            // don't use SSLv2Hello when renegotiating
+                            handshaker.activate(protocolVersion);
+                        } else {
+                            handshaker.activate(null);
+                        }
+                    }
 
                     /*
                      * process the handshake record ... may contain just
@@ -1081,6 +1097,26 @@
                     }
                     break;
                 } // switch
+
+                /*
+                 * We only need to check the sequence number state for
+                 * non-handshaking record.
+                 *
+                 * Note that in order to maintain the handshake status
+                 * properly, we check the sequence number after the last
+                 * record reading process. As we request renegotiation
+                 * or close the connection for wrapped sequence number
+                 * when there is enough sequence number space left to
+                 * handle a few more records, so the sequence number
+                 * of the last record cannot be wrapped.
+                 */
+                if (connectionState < cs_ERROR && !isInboundDone() &&
+                        (hsStatus == HandshakeStatus.NOT_HANDSHAKING)) {
+                    if (checkSequenceNumber(readMAC,
+                            inputRecord.contentType())) {
+                        hsStatus = getHSStatus(null);
+                    }
+                }
             } // synchronized (this)
         }
 
@@ -1229,7 +1265,29 @@
             EngineArgs ea) throws IOException {
 
         // eventually compress as well.
-        return writer.writeRecord(eor, ea, writeMAC, writeCipher);
+        HandshakeStatus hsStatus =
+                writer.writeRecord(eor, ea, writeMAC, writeCipher);
+
+        /*
+         * We only need to check the sequence number state for
+         * non-handshaking record.
+         *
+         * Note that in order to maintain the handshake status
+         * properly, we check the sequence number after the last
+         * record writing process. As we request renegotiation
+         * or close the connection for wrapped sequence number
+         * when there is enough sequence number space left to
+         * handle a few more records, so the sequence number
+         * of the last record cannot be wrapped.
+         */
+        if (connectionState < cs_ERROR && !isOutboundDone() &&
+                (hsStatus == HandshakeStatus.NOT_HANDSHAKING)) {
+            if (checkSequenceNumber(writeMAC, eor.contentType())) {
+                hsStatus = getHSStatus(null);
+            }
+        }
+
+        return hsStatus;
     }
 
     /*
@@ -1238,6 +1296,21 @@
     void writeRecord(EngineOutputRecord eor) throws IOException {
         // eventually compress as well.
         writer.writeRecord(eor, writeMAC, writeCipher);
+
+        /*
+         * Check the sequence number state
+         *
+         * Note that in order to maintain the connection I/O
+         * properly, we check the sequence number after the last
+         * record writing process. As we request renegotiation
+         * or close the connection for wrapped sequence number
+         * when there is enough sequence number space left to
+         * handle a few more records, so the sequence number
+         * of the last record cannot be wrapped.
+         */
+        if ((connectionState < cs_ERROR) && !isOutboundDone()) {
+            checkSequenceNumber(writeMAC, eor.contentType());
+        }
     }
 
     //
@@ -1245,6 +1318,67 @@
     //
 
     /**
+     * Check the sequence number state
+     *
+     * RFC 4346 states that, "Sequence numbers are of type uint64 and
+     * may not exceed 2^64-1.  Sequence numbers do not wrap. If a TLS
+     * implementation would need to wrap a sequence number, it must
+     * renegotiate instead."
+     *
+     * Return true if the handshake status may be changed.
+     */
+    private boolean checkSequenceNumber(MAC mac, byte type)
+            throws IOException {
+
+        /*
+         * Don't bother to check the sequence number for error or
+         * closed connections, or NULL MAC
+         */
+        if (connectionState >= cs_ERROR || mac == MAC.NULL) {
+            return false;
+        }
+
+        /*
+         * Conservatively, close the connection immediately when the
+         * sequence number is close to overflow
+         */
+        if (mac.seqNumOverflow()) {
+            /*
+             * TLS protocols do not define a error alert for sequence
+             * number overflow. We use handshake_failure error alert
+             * for handshaking and bad_record_mac for other records.
+             */
+            if (debug != null && Debug.isOn("ssl")) {
+                System.out.println(threadName() +
+                    ", sequence number extremely close to overflow " +
+                    "(2^64-1 packets). Closing connection.");
+            }
+
+            fatal(Alerts.alert_handshake_failure, "sequence number overflow");
+
+            return true; // make the compiler happy
+        }
+
+        /*
+         * Ask for renegotiation when need to renew sequence number.
+         *
+         * Don't bother to kickstart the renegotiation when the local is
+         * asking for it.
+         */
+        if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) {
+            if (debug != null && Debug.isOn("ssl")) {
+                System.out.println(threadName() + ", request renegotiation " +
+                        "to avoid sequence number overflow");
+            }
+
+            beginHandshake();
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
      * Signals that no more outbound application data will be sent
      * on this <code>SSLEngine</code>.
      */
@@ -1594,10 +1728,18 @@
      * Emit alerts.  Caller must have synchronized with "this".
      */
     private void sendAlert(byte level, byte description) {
+        // the connectionState cannot be cs_START
         if (connectionState >= cs_CLOSED) {
             return;
         }
 
+        // For initial handshaking, don't send alert message to peer if
+        // handshaker has not started.
+        if (connectionState == cs_HANDSHAKE &&
+            (handshaker == null || !handshaker.started())) {
+            return;
+        }
+
         EngineOutputRecord r = new EngineOutputRecord(Record.ct_alert, this);
         r.setVersion(protocolVersion);
 
@@ -1647,7 +1789,7 @@
     synchronized public void setEnableSessionCreation(boolean flag) {
         enableSessionCreation = flag;
 
-        if ((handshaker != null) && !handshaker.started()) {
+        if ((handshaker != null) && !handshaker.activated()) {
             handshaker.setEnableSessionCreation(enableSessionCreation);
         }
     }
@@ -1675,7 +1817,7 @@
 
         if ((handshaker != null) &&
                 (handshaker instanceof ServerHandshaker) &&
-                !handshaker.started()) {
+                !handshaker.activated()) {
             ((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
         }
     }
@@ -1698,7 +1840,7 @@
 
         if ((handshaker != null) &&
                 (handshaker instanceof ServerHandshaker) &&
-                !handshaker.started()) {
+                !handshaker.activated()) {
             ((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
         }
     }
@@ -1717,6 +1859,16 @@
         switch (connectionState) {
 
         case cs_START:
+            /*
+             * If we need to change the engine mode and the enabled
+             * protocols haven't specifically been set by the user,
+             * change them to the corresponding default ones.
+             */
+            if (roleIsServer != (!flag) &&
+                    ProtocolList.isDefaultProtocolList(enabledProtocols)) {
+                enabledProtocols = ProtocolList.getDefault(!flag);
+            }
+
             roleIsServer = !flag;
             serverModeSet = true;
             break;
@@ -1730,7 +1882,17 @@
              * have the streams.
              */
             assert(handshaker != null);
-            if (!handshaker.started()) {
+            if (!handshaker.activated()) {
+                /*
+                 * If we need to change the engine mode and the enabled
+                 * protocols haven't specifically been set by the user,
+                 * change them to the corresponding default ones.
+                 */
+                if (roleIsServer != (!flag) &&
+                        ProtocolList.isDefaultProtocolList(enabledProtocols)) {
+                    enabledProtocols = ProtocolList.getDefault(!flag);
+                }
+
                 roleIsServer = !flag;
                 connectionState = cs_START;
                 initHandshaker();
@@ -1786,8 +1948,8 @@
      */
     synchronized public void setEnabledCipherSuites(String[] suites) {
         enabledCipherSuites = new CipherSuiteList(suites);
-        if ((handshaker != null) && !handshaker.started()) {
-            handshaker.enabledCipherSuites = enabledCipherSuites;
+        if ((handshaker != null) && !handshaker.activated()) {
+            handshaker.setEnabledCipherSuites(enabledCipherSuites);
         }
     }
 
@@ -1826,7 +1988,7 @@
      */
     synchronized public void setEnabledProtocols(String[] protocols) {
         enabledProtocols = new ProtocolList(protocols);
-        if ((handshaker != null) && !handshaker.started()) {
+        if ((handshaker != null) && !handshaker.activated()) {
             handshaker.setEnabledProtocols(enabledProtocols);
         }
     }
--- a/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java	Sat Oct 30 18:39:17 2010 +0800
@@ -145,7 +145,7 @@
         }
         sslContext = context;
         enabledCipherSuites = CipherSuiteList.getDefault();
-        enabledProtocols = ProtocolList.getDefault();
+        enabledProtocols = ProtocolList.getDefault(true);
     }
 
     /**
@@ -238,6 +238,16 @@
      * rejoining the already-negotiated SSL connection.
      */
     public void setUseClientMode(boolean flag) {
+        /*
+         * If we need to change the socket mode and the enabled
+         * protocols haven't specifically been set by the user,
+         * change them to the corresponding default ones.
+         */
+        if (useServerMode != (!flag) &&
+                ProtocolList.isDefaultProtocolList(enabledProtocols)) {
+            enabledProtocols = ProtocolList.getDefault(!flag);
+        }
+
         useServerMode = !flag;
     }
 
@@ -262,15 +272,12 @@
         return enableSessionCreation;
     }
 
-
     /**
      * Accept a new SSL connection.  This server identifies itself with
      * information provided in the authentication context which was
      * presented during construction.
      */
     public Socket accept() throws IOException {
-        checkEnabledSuites();
-
         SSLSocketImpl s = new SSLSocketImpl(sslContext, useServerMode,
             enabledCipherSuites, doClientAuth, enableSessionCreation,
             enabledProtocols);
@@ -280,56 +287,6 @@
         return s;
     }
 
-
-    /*
-     * This is a sometimes helpful diagnostic check that is performed
-     * once for each ServerSocket to verify that the initial set of
-     * enabled suites are capable of supporting a successful handshake.
-     */
-    private void checkEnabledSuites() throws IOException {
-        //
-        // We want to report an error if no cipher suites were actually
-        // enabled, since this is an error users are known to make.  Then
-        // they get vastly confused by having clients report an error!
-        //
-        synchronized (this) {
-            if (checkedEnabled) {
-                return;
-            }
-            if (useServerMode == false) {
-                return;
-            }
-
-            SSLSocketImpl tmp = new SSLSocketImpl(sslContext, useServerMode,
-                         enabledCipherSuites, doClientAuth,
-                         enableSessionCreation, enabledProtocols);
-
-            try {
-                ServerHandshaker handshaker = tmp.getServerHandshaker();
-
-                for (Iterator<CipherSuite> t = enabledCipherSuites.iterator();
-                        t.hasNext();) {
-                    CipherSuite suite = t.next();
-                    if (handshaker.trySetCipherSuite(suite)) {
-                        checkedEnabled = true;
-                        return;
-                    }
-                }
-            } finally {
-                tmp.closeSocket();
-            }
-
-            //
-            // diagnostic text here is currently appropriate
-            // since it's only certificate unavailability that can
-            // cause such problems ... but that might change someday.
-            //
-            throw new SSLException("No available certificate or key corresponds"
-                + " to the SSL cipher suites which are enabled.");
-        }
-    }
-
-
     /**
      * Provides a brief description of this SSL socket.
      */
--- a/src/share/classes/sun/security/ssl/SSLSocketImpl.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/SSLSocketImpl.java	Sat Oct 30 18:39:17 2010 +0800
@@ -194,12 +194,14 @@
      */
     private byte                doClientAuth;
     private boolean             roleIsServer;
-    private CipherSuiteList     enabledCipherSuites;
     private boolean             enableSessionCreation = true;
     private String              host;
     private boolean             autoClose = true;
     private AccessControlContext acc;
 
+    // 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;
@@ -341,11 +343,11 @@
     private AppOutputStream     output;
 
     /*
-     * The protocols we support are SSL Version 3.0) and
-     * TLS (version 3.1).
-     * In addition we support a pseudo protocol called
-     * SSLv2Hello which when set will result in an SSL v2 Hello
-     * being sent with SSLv3 or TLSv1 version info.
+     * The protocol versions enabled for use on this connection.
+     *
+     * Note: we support a pseudo protocol called SSLv2Hello which when
+     * set will result in an SSL v2 Hello being sent with SSL (version 3.0)
+     * or TLS (version 3.1, 3.2, etc.) version info.
      */
     private ProtocolList enabledProtocols;
 
@@ -541,7 +543,7 @@
         serverVerifyData = new byte[0];
 
         enabledCipherSuites = CipherSuiteList.getDefault();
-        enabledProtocols = ProtocolList.getDefault();
+        enabledProtocols = ProtocolList.getDefault(roleIsServer);
         inrec = null;
 
         // save the acc
@@ -764,6 +766,21 @@
         r.addMAC(writeMAC);
         r.encrypt(writeCipher);
         r.write(sockOutput);
+
+        /*
+         * Check the sequence number state
+         *
+         * Note that in order to maintain the connection I/O
+         * properly, we check the sequence number after the last
+         * record writing process. As we request renegotiation
+         * or close the connection for wrapped sequence number
+         * when there is enough sequence number space left to
+         * handle a few more records, so the sequence number
+         * of the last record cannot be wrapped.
+         */
+        if (connectionState < cs_ERROR) {
+            checkSequenceNumber(writeMAC, r.contentType());
+        }
     }
 
 
@@ -883,6 +900,7 @@
                 }
             }
 
+
             // if (!r.decompress(c))
             //     fatal(Alerts.alert_decompression_failure,
             //         "decompression failure");
@@ -905,6 +923,15 @@
                      * in it.
                      */
                     initHandshaker();
+                    if (!handshaker.activated()) {
+                        // prior to handshaking, activate the handshake
+                        if (connectionState == cs_RENEGOTIATE) {
+                            // don't use SSLv2Hello when renegotiating
+                            handshaker.activate(protocolVersion);
+                        } else {
+                            handshaker.activate(null);
+                        }
+                    }
 
                     /*
                      * process the handshake record ... may contain just
@@ -949,9 +976,8 @@
 
                     if (needAppData || connectionState != cs_DATA) {
                         continue;
-                    } else {
-                        return;
                     }
+                    break;
 
                 case Record.ct_application_data:
                     // Pass this right back up to the application.
@@ -971,7 +997,7 @@
                     }
 
                     r.setAppDataValid(true);
-                    return;
+                    break;
 
                 case Record.ct_alert:
                     recvAlert(r);
@@ -1010,6 +1036,23 @@
                     }
                     continue;
               } // switch
+
+              /*
+               * Check the sequence number state
+               *
+               * Note that in order to maintain the connection I/O
+               * properly, we check the sequence number after the last
+               * record reading process. As we request renegotiation
+               * or close the connection for wrapped sequence number
+               * when there is enough sequence number space left to
+               * handle a few more records, so the sequence number
+               * of the last record cannot be wrapped.
+               */
+              if (connectionState < cs_ERROR) {
+                  checkSequenceNumber(readMAC, r.contentType());
+              }
+
+              return;
             } // synchronized (this)
         }
 
@@ -1021,6 +1064,61 @@
       }  // synchronized (readLock)
     }
 
+    /**
+     * Check the sequence number state
+     *
+     * RFC 4346 states that, "Sequence numbers are of type uint64 and
+     * may not exceed 2^64-1.  Sequence numbers do not wrap. If a TLS
+     * implementation would need to wrap a sequence number, it must
+     * renegotiate instead."
+     */
+    private void checkSequenceNumber(MAC mac, byte type)
+            throws IOException {
+
+        /*
+         * Don't bother to check the sequence number for error or
+         * closed connections, or NULL MAC.
+         */
+        if (connectionState >= cs_ERROR || mac == MAC.NULL) {
+            return;
+        }
+
+        /*
+         * Conservatively, close the connection immediately when the
+         * sequence number is close to overflow
+         */
+        if (mac.seqNumOverflow()) {
+            /*
+             * TLS protocols do not define a error alert for sequence
+             * number overflow. We use handshake_failure error alert
+             * for handshaking and bad_record_mac for other records.
+             */
+            if (debug != null && Debug.isOn("ssl")) {
+                System.out.println(threadName() +
+                    ", sequence number extremely close to overflow " +
+                    "(2^64-1 packets). Closing connection.");
+
+            }
+
+            fatal(Alerts.alert_handshake_failure, "sequence number overflow");
+        }
+
+        /*
+         * Ask for renegotiation when need to renew sequence number.
+         *
+         * Don't bother to kickstart the renegotiation when the local is
+         * asking for it.
+         */
+        if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) {
+            if (debug != null && Debug.isOn("ssl")) {
+                System.out.println(threadName() + ", request renegotiation " +
+                        "to avoid sequence number overflow");
+            }
+
+            startHandshake();
+        }
+    }
+
     //
     // HANDSHAKE RELATED CODE
     //
@@ -1033,28 +1131,10 @@
     }
 
     /**
-     * Initialize and get the server handshaker. Used by SSLServerSocketImpl
-     * for the ciphersuite availability test *only*.
+     * Return the AppOutputStream. For use by Handshaker only.
      */
-    ServerHandshaker getServerHandshaker() throws SSLException {
-        initHandshaker();
-
-         // The connection state would have been set to cs_HANDSHAKE during the
-         // handshaking initializing, however the caller may not have the
-         // the low level connection's established, which is not consistent with
-         // the HANDSHAKE state. As if it is unconnected, we need to reset the
-         // connection state to cs_START.
-         if (!isConnected()) {
-             connectionState = cs_START;
-         }
-
-         // Make sure that we get a ServerHandshaker.
-         // This should never happen.
-         if (!(handshaker instanceof ServerHandshaker)) {
-             throw new SSLProtocolException("unexpected handshaker instance");
-         }
-
-        return (ServerHandshaker)handshaker;
+    AppOutputStream getAppOutputStream() {
+        return output;
     }
 
     /**
@@ -1066,8 +1146,8 @@
      *  . if the socket is already closed, throw an Exception (internal error)
      *
      *  . otherwise (cs_START or cs_DATA), create the appropriate handshaker
-     *    object, initialize it, and advance the connection state (to
-     *    cs_HANDSHAKE or cs_RENEGOTIATE, respectively).
+     *    object, and advance the connection state (to cs_HANDSHAKE or
+     *    cs_RENEGOTIATE, respectively).
      *
      * This method is called right after a new socket is created, when
      * starting renegotiation, or when changing client/ server mode of the
@@ -1115,12 +1195,8 @@
                     protocolVersion, connectionState == cs_HANDSHAKE,
                     secureRenegotiation, clientVerifyData, serverVerifyData);
         }
-        handshaker.enabledCipherSuites = enabledCipherSuites;
+        handshaker.setEnabledCipherSuites(enabledCipherSuites);
         handshaker.setEnableSessionCreation(enableSessionCreation);
-        if (connectionState == cs_RENEGOTIATE) {
-            // don't use SSLv2Hello when renegotiating
-            handshaker.output.r.setHelloVersion(protocolVersion);
-        }
     }
 
     /**
@@ -1135,6 +1211,8 @@
         // one thread performs the handshake
         synchronized (handshakeLock) {
             if (getConnectionState() == cs_HANDSHAKE) {
+                kickstartHandshake();
+
                 /*
                  * All initial handshaking goes through this
                  * InputRecord until we have a valid SSL connection.
@@ -1157,7 +1235,6 @@
                     inrec.enableFormatChecks();
                 }
 
-                kickstartHandshake();
                 readRecord(inrec, false);
                 inrec = null;
             }
@@ -1211,6 +1288,7 @@
      *    on servers when renegotiating).
      */
     private synchronized void kickstartHandshake() throws IOException {
+
         switch (connectionState) {
 
         case cs_HANDSHAKE:
@@ -1257,7 +1335,15 @@
         // to its HandshakeOutStream, which calls back into
         // SSLSocketImpl.writeRecord() to send it.
         //
-        if (!handshaker.started()) {
+        if (!handshaker.activated()) {
+             // prior to handshaking, activate the handshake
+            if (connectionState == cs_RENEGOTIATE) {
+                // don't use SSLv2Hello when renegotiating
+                handshaker.activate(protocolVersion);
+            } else {
+                handshaker.activate(null);
+            }
+
             if (handshaker instanceof ClientHandshaker) {
                 // send client hello
                 handshaker.kickstart();
@@ -1752,10 +1838,18 @@
      * Emit alerts.  Caller must have synchronized with "this".
      */
     private void sendAlert(byte level, byte description) {
+        // the connectionState cannot be cs_START
         if (connectionState >= cs_SENT_CLOSE) {
             return;
         }
 
+        // For initial handshaking, don't send alert message to peer if
+        // handshaker has not started.
+        if (connectionState == cs_HANDSHAKE &&
+            (handshaker == null || !handshaker.started())) {
+            return;
+        }
+
         OutputRecord r = new OutputRecord(Record.ct_alert);
         r.setVersion(protocolVersion);
 
@@ -1962,7 +2056,7 @@
     synchronized public void setEnableSessionCreation(boolean flag) {
         enableSessionCreation = flag;
 
-        if ((handshaker != null) && !handshaker.started()) {
+        if ((handshaker != null) && !handshaker.activated()) {
             handshaker.setEnableSessionCreation(enableSessionCreation);
         }
     }
@@ -1990,7 +2084,7 @@
 
         if ((handshaker != null) &&
                 (handshaker instanceof ServerHandshaker) &&
-                !handshaker.started()) {
+                !handshaker.activated()) {
             ((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
         }
     }
@@ -2013,7 +2107,7 @@
 
         if ((handshaker != null) &&
                 (handshaker instanceof ServerHandshaker) &&
-                !handshaker.started()) {
+                !handshaker.activated()) {
             ((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
         }
     }
@@ -2032,6 +2126,15 @@
         switch (connectionState) {
 
         case cs_START:
+            /*
+             * If we need to change the socket mode and the enabled
+             * protocols haven't specifically been set by the user,
+             * change them to the corresponding default ones.
+             */
+            if (roleIsServer != (!flag) &&
+                    ProtocolList.isDefaultProtocolList(enabledProtocols)) {
+                enabledProtocols = ProtocolList.getDefault(!flag);
+            }
             roleIsServer = !flag;
             break;
 
@@ -2044,7 +2147,16 @@
              * have the streams.
              */
             assert(handshaker != null);
-            if (!handshaker.started()) {
+            if (!handshaker.activated()) {
+                /*
+                 * If we need to change the socket mode and the enabled
+                 * protocols haven't specifically been set by the user,
+                 * change them to the corresponding default ones.
+                 */
+                if (roleIsServer != (!flag) &&
+                        ProtocolList.isDefaultProtocolList(enabledProtocols)) {
+                    enabledProtocols = ProtocolList.getDefault(!flag);
+                }
                 roleIsServer = !flag;
                 connectionState = cs_START;
                 initHandshaker();
@@ -2095,8 +2207,8 @@
      */
     synchronized public void setEnabledCipherSuites(String[] suites) {
         enabledCipherSuites = new CipherSuiteList(suites);
-        if ((handshaker != null) && !handshaker.started()) {
-            handshaker.enabledCipherSuites = enabledCipherSuites;
+        if ((handshaker != null) && !handshaker.activated()) {
+            handshaker.setEnabledCipherSuites(enabledCipherSuites);
         }
     }
 
@@ -2135,7 +2247,7 @@
      */
     synchronized public void setEnabledProtocols(String[] protocols) {
         enabledProtocols = new ProtocolList(protocols);
-        if ((handshaker != null) && !handshaker.started()) {
+        if ((handshaker != null) && !handshaker.activated()) {
             handshaker.setEnabledProtocols(enabledProtocols);
         }
     }
--- a/src/share/classes/sun/security/ssl/ServerHandshaker.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/ServerHandshaker.java	Sat Oct 30 18:39:17 2010 +0800
@@ -185,8 +185,10 @@
                      * temporary one used for non-export or signing-only
                      * certificates/keys.
                      */
-                    RSAClientKeyExchange pms = new RSAClientKeyExchange
-                        (protocolVersion, input, message_len, privateKey);
+                    RSAClientKeyExchange pms = new RSAClientKeyExchange(
+                            protocolVersion, clientRequestedVersion,
+                            sslContext.getSecureRandom(), input,
+                            message_len, privateKey);
                     preMasterSecret = this.clientKeyExchange(pms);
                     break;
                 case K_KRB5:
@@ -408,20 +410,14 @@
 
         clientRequestedVersion = mesg.protocolVersion;
 
-        // check if clientVersion is recent enough for us
-        if (clientRequestedVersion.v < enabledProtocols.min.v) {
+        // select a proper protocol version.
+        ProtocolVersion selectedVersion =
+               selectProtocolVersion(clientRequestedVersion);
+        if (selectedVersion == null ||
+                selectedVersion.v == ProtocolVersion.SSL20Hello.v) {
             fatalSE(Alerts.alert_handshake_failure,
                 "Client requested protocol " + clientRequestedVersion +
-                 " not enabled or not supported");
-        }
-
-        // now we know we have an acceptable version
-        // use the lower of our max and the client requested version
-        ProtocolVersion selectedVersion;
-        if (clientRequestedVersion.v <= enabledProtocols.max.v) {
-            selectedVersion = clientRequestedVersion;
-        } else {
-            selectedVersion = enabledProtocols.max;
+                " not enabled or not supported");
         }
         setVersion(selectedVersion);
 
@@ -813,8 +809,7 @@
      * method should only be called if you really want to use the
      * CipherSuite.
      *
-     * This method is called from chooseCipherSuite() in this class
-     * and SSLServerSocketImpl.checkEnabledSuites() (as a sanity check).
+     * This method is called from chooseCipherSuite() in this class.
      */
     boolean trySetCipherSuite(CipherSuite suite) {
         /*
@@ -831,6 +826,11 @@
             return false;
         }
 
+        // TLSv1.1 must not negotiate the exportable weak cipher suites.
+        if (protocolVersion.v >= suite.obsoleted) {
+            return false;
+        }
+
         KeyExchange keyExchange = suite.keyExchange;
 
         // null out any existing references
--- a/src/share/classes/sun/security/ssl/SunJSSE.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/SunJSSE.java	Sat Oct 30 18:39:17 2010 +0800
@@ -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
@@ -38,7 +38,7 @@
  *
  * SunJSSE now supports an experimental FIPS compliant mode when used with an
  * appropriate FIPS certified crypto provider. In FIPS mode, we:
- *  . allow only TLS 1.0
+ *  . allow only TLS 1.0 or later
  *  . allow only FIPS approved ciphersuites
  *  . perform all crypto in the FIPS crypto provider
  *
@@ -211,6 +211,8 @@
             "sun.security.ssl.SSLContextImpl");
         put("SSLContext.TLSv1",
             "sun.security.ssl.SSLContextImpl");
+        put("SSLContext.TLSv1.1",
+            "sun.security.ssl.SSLContextImpl");
         put("SSLContext.Default",
             "sun.security.ssl.DefaultSSLContextImpl");
 
--- a/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java	Sat Oct 30 18:39:17 2010 +0800
@@ -244,7 +244,7 @@
                 clientVersion, rand, input, sessionKey);
         } else {
             // Generate bogus premaster secret
-            preMaster = new KerberosPreMasterSecret(protocolVersion, rand);
+            preMaster = new KerberosPreMasterSecret(clientVersion, rand);
         }
     }
 
--- a/src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java	Sat Oct 30 18:39:17 2010 +0800
@@ -176,13 +176,21 @@
         // check if the premaster secret version is ok
         // the specification says that it must be the maximum version supported
         // by the client from its ClientHello message. However, many
-        // implementations send the negotiated version, so accept both
+        // old implementations send the negotiated version, so accept both
+        // for SSL v3.0 and TLS v1.0.
         // NOTE that we may be comparing two unsupported version numbers in
         // the second case, which is why we cannot use object references
         // equality in this special case
-        boolean versionMismatch = (protocolVersion != currentVersion) &&
-                                  (protocolVersion.v != clientVersion.v);
+        boolean versionMismatch = (protocolVersion.v != clientVersion.v);
 
+        /*
+         * we never checked the client_version in server side
+         * for TLS v1.0 and SSL v3.0. For compatibility, we
+         * maintain this behavior.
+         */
+        if (versionMismatch && (clientVersion.v <= 0x0301)) {
+            versionMismatch = (protocolVersion.v != currentVersion.v);
+        }
 
         /*
          * Bogus decrypted ClientKeyExchange? If so, conjure a
@@ -203,8 +211,14 @@
                     Debug.println(System.out, "Invalid secret", preMaster);
                 }
             }
-            preMaster = generatePreMaster(generator, currentVersion);
-            protocolVersion = currentVersion;
+
+            /*
+             * Randomize the preMaster secret with the
+             * ClientHello.client_version, as will produce invalid master
+             * secret to prevent the attacks.
+             */
+            preMaster = generatePreMaster(generator, clientVersion);
+            protocolVersion = clientVersion;
         }
     }
 
--- a/test/sun/security/pkcs11/fips/CipherTest.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/test/sun/security/pkcs11/fips/CipherTest.java	Sat Oct 30 18:39:17 2010 +0800
@@ -119,6 +119,13 @@
                 return false;
             }
 
+            // ignore exportable cipher suite for TLSv1.1
+            if (protocol.equals("TLSv1.1")) {
+                if(cipherSuite.indexOf("_EXPORT_") != -1) {
+                    return false;
+                }
+            }
+
             return true;
         }
 
@@ -149,18 +156,14 @@
             cipherSuites.length * protocols.length * clientAuths.length);
         for (int i = 0; i < cipherSuites.length; i++) {
             String cipherSuite = cipherSuites[i];
-            if (peerFactory.isSupported(cipherSuite) == false) {
-                continue;
-            }
-            // skip kerberos cipher suites
-            if (cipherSuite.startsWith("TLS_KRB5")) {
-                continue;
-            }
+
             for (int j = 0; j < protocols.length; j++) {
                 String protocol = protocols[j];
-                if (protocol.equals("SSLv2Hello")) {
+
+                if (!peerFactory.isSupported(cipherSuite, protocol)) {
                     continue;
                 }
+
                 for (int k = 0; k < clientAuths.length; k++) {
                     String clientAuth = clientAuths[k];
                     if ((clientAuth != null) &&
@@ -293,11 +296,12 @@
         return ks;
     }
 
-    public static void main(PeerFactory peerFactory, KeyStore keyStore, String[] args)
-            throws Exception {
+    public static void main(PeerFactory peerFactory, KeyStore keyStore,
+            String[] args) throws Exception {
+
         long time = System.currentTimeMillis();
         String relPath;
-        if ((args.length > 0) && args[0].equals("sh")) {
+        if ((args != null) && (args.length > 0) && args[0].equals("sh")) {
             relPath = pathToStoresSH;
         } else {
             relPath = pathToStores;
@@ -345,7 +349,30 @@
 
         abstract Server newServer(CipherTest cipherTest) throws Exception;
 
-        boolean isSupported(String cipherSuite) {
+        boolean isSupported(String cipherSuite, String protocol) {
+            // skip kerberos cipher suites
+            if (cipherSuite.startsWith("TLS_KRB5")) {
+                System.out.println("Skipping unsupported test for " +
+                                    cipherSuite + " of " + protocol);
+                return false;
+            }
+
+            // skip SSLv2Hello protocol
+            if (protocol.equals("SSLv2Hello")) {
+                System.out.println("Skipping unsupported test for " +
+                                    cipherSuite + " of " + protocol);
+                return false;
+            }
+
+            // ignore exportable cipher suite for TLSv1.1
+            if (protocol.equals("TLSv1.1")) {
+                if (cipherSuite.indexOf("_EXPORT_WITH") != -1) {
+                    System.out.println("Skipping obsoleted test for " +
+                                        cipherSuite + " of " + protocol);
+                    return false;
+                }
+            }
+
             return true;
         }
     }
--- a/test/sun/security/pkcs11/sslecc/CipherTest.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/test/sun/security/pkcs11/sslecc/CipherTest.java	Sat Oct 30 18:39:17 2010 +0800
@@ -119,6 +119,13 @@
                 return false;
             }
 
+            // ignore exportable cipher suite for TLSv1.1
+            if (protocol.equals("TLSv1.1")) {
+                if(cipherSuite.indexOf("_EXPORT_") != -1) {
+                    return false;
+                }
+            }
+
             return true;
         }
 
@@ -148,18 +155,14 @@
             cipherSuites.length * protocols.length * clientAuths.length);
         for (int i = 0; i < cipherSuites.length; i++) {
             String cipherSuite = cipherSuites[i];
-            if (peerFactory.isSupported(cipherSuite) == false) {
-                continue;
-            }
-            // skip kerberos cipher suites
-            if (cipherSuite.startsWith("TLS_KRB5")) {
-                continue;
-            }
+
             for (int j = 0; j < protocols.length; j++) {
                 String protocol = protocols[j];
-                if (protocol.equals("SSLv2Hello")) {
+
+                if (!peerFactory.isSupported(cipherSuite, protocol)) {
                     continue;
                 }
+
                 for (int k = 0; k < clientAuths.length; k++) {
                     String clientAuth = clientAuths[k];
                     if ((clientAuth != null) &&
@@ -275,7 +278,6 @@
 
     // for some reason, ${test.src} has a different value when the
     // test is called from the script and when it is called directly...
-//    static String pathToStores = "../../etc";
     static String pathToStores = ".";
     static String pathToStoresSH = ".";
     static String keyStoreFile = "keystore";
@@ -336,7 +338,30 @@
 
         abstract Server newServer(CipherTest cipherTest) throws Exception;
 
-        boolean isSupported(String cipherSuite) {
+        boolean isSupported(String cipherSuite, String protocol) {
+            // skip kerberos cipher suites
+            if (cipherSuite.startsWith("TLS_KRB5")) {
+                System.out.println("Skipping unsupported test for " +
+                                    cipherSuite + " of " + protocol);
+                return false;
+            }
+
+            // skip SSLv2Hello protocol
+            if (protocol.equals("SSLv2Hello")) {
+                System.out.println("Skipping unsupported test for " +
+                                    cipherSuite + " of " + protocol);
+                return false;
+            }
+
+            // ignore exportable cipher suite for TLSv1.1
+            if (protocol.equals("TLSv1.1")) {
+                if (cipherSuite.indexOf("_EXPORT_WITH") != -1) {
+                    System.out.println("Skipping obsoleted test for " +
+                                        cipherSuite + " of " + protocol);
+                    return false;
+                }
+            }
+
             return true;
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/javax/net/ssl/TLSv11/EmptyCertificateAuthorities.java	Sat Oct 30 18:39:17 2010 +0800
@@ -0,0 +1,371 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4873188
+ * @summary Support TLS 1.1
+ * @run main/othervm -Djavax.net.debug=all EmptyCertificateAuthorities
+ *
+ * @author Xuelei Fan
+ */
+
+import java.io.*;
+import java.net.*;
+import java.security.*;
+import java.security.cert.*;
+import javax.net.ssl.*;
+
+public class EmptyCertificateAuthorities {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "/../../../../etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf = getSSLServerSF();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        // require client authentication.
+        sslServerSocket.setNeedClientAuth(true);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write('A');
+        sslOS.flush();
+
+        sslSocket.close();
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+
+        // enable TLSv1.1 only
+        sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"});
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslOS.write('B');
+        sslOS.flush();
+        sslIS.read();
+
+        sslSocket.close();
+    }
+
+    private SSLServerSocketFactory getSSLServerSF() throws Exception {
+
+        char [] password =
+            System.getProperty("javax.net.ssl.keyStorePassword").toCharArray();
+        String keyFilename = System.getProperty("javax.net.ssl.keyStore");
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(new FileInputStream(keyFilename), password);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+        kmf.init(ks, password);
+
+        KeyManager[] kms = kmf.getKeyManagers();
+        TrustManager[] tms = new MyX509TM[] {new MyX509TM()};
+
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        ctx.init(kms, tms, null);
+
+        return ctx.getServerSocketFactory();
+    }
+
+
+    static class MyX509TM implements X509TrustManager {
+        X509TrustManager tm;
+
+        public void checkClientTrusted(X509Certificate[] chain,
+            String authType) throws CertificateException {
+            if (tm == null) {
+                initialize();
+            }
+            tm.checkClientTrusted(chain, authType);
+        }
+
+        public void checkServerTrusted(X509Certificate[] chain,
+            String authType) throws CertificateException {
+            if (tm == null) {
+                initialize();
+            }
+            tm.checkServerTrusted(chain, authType);
+        }
+
+        public X509Certificate[] getAcceptedIssuers() {
+            // always return empty array
+            return new X509Certificate[0];
+        }
+
+        private void initialize() throws CertificateException {
+            String passwd =
+                System.getProperty("javax.net.ssl.trustStorePassword");
+            char [] password = passwd.toCharArray();
+            String trustFilename =
+                System.getProperty("javax.net.ssl.trustStore");
+
+            try {
+                KeyStore ks = KeyStore.getInstance("JKS");
+                ks.load(new FileInputStream(trustFilename), password);
+
+                TrustManagerFactory tmf =
+                        TrustManagerFactory.getInstance("PKIX");
+                tmf.init(ks);
+                tm = (X509TrustManager)tmf.getTrustManagers()[0];
+            } catch (Exception e) {
+                throw new CertificateException("Unable to initialize TM");
+            }
+
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new EmptyCertificateAuthorities();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    EmptyCertificateAuthorities() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/javax/net/ssl/TLSv11/ExportableBlockCipher.java	Sat Oct 30 18:39:17 2010 +0800
@@ -0,0 +1,327 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4873188
+ * @summary Support TLS 1.1
+ * @run main/othervm -Djavax.net.debug=all ExportableBlockCipher
+ *
+ * @author Xuelei Fan
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+
+public class ExportableBlockCipher {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "/../../../../etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        boolean interrupted = false;
+        try {
+            sslIS.read();
+            sslOS.write('A');
+            sslOS.flush();
+        } catch (SSLException ssle) {
+            // get the expected exception
+            interrupted = true;
+        } finally {
+            sslSocket.close();
+        }
+
+        if (!interrupted) {
+            throw new SSLHandshakeException(
+                "A weak cipher suite is negotiated, " +
+                "TLSv1.1 must not negotiate the exportable cipher suites.");
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+
+        // enable TLSv1.1 only
+        sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"});
+
+        // enable a exportable block cipher
+        sslSocket.setEnabledCipherSuites(
+            new String[] {"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"});
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        boolean interrupted = false;
+        try {
+            sslOS.write('B');
+            sslOS.flush();
+            sslIS.read();
+        } catch (SSLException ssle) {
+            // get the expected exception
+            interrupted = true;
+        } finally {
+            sslSocket.close();
+        }
+
+        if (!interrupted) {
+            throw new SSLHandshakeException(
+                "A weak cipher suite is negotiated, " +
+                "TLSv1.1 must not negotiate the exportable cipher suites.");
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new ExportableBlockCipher();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ExportableBlockCipher() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/javax/net/ssl/TLSv11/ExportableStreamCipher.java	Sat Oct 30 18:39:17 2010 +0800
@@ -0,0 +1,327 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4873188
+ * @summary Support TLS 1.1
+ * @run main/othervm -Djavax.net.debug=all ExportableStreamCipher
+ *
+ * @author Xuelei Fan
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+
+public class ExportableStreamCipher {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "/../../../../etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        boolean interrupted = false;
+        try {
+            sslIS.read();
+            sslOS.write('A');
+            sslOS.flush();
+        } catch (SSLException ssle) {
+            // get the expected exception
+            interrupted = true;
+        } finally {
+            sslSocket.close();
+        }
+
+        if (!interrupted) {
+            throw new SSLHandshakeException(
+                "A weak cipher suite is negotiated, " +
+                "TLSv1.1 must not negotiate the exportable cipher suites.");
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+
+        // enable TLSv1.1 only
+        sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"});
+
+        // enable a exportable stream cipher
+        sslSocket.setEnabledCipherSuites(
+            new String[] {"SSL_RSA_EXPORT_WITH_RC4_40_MD5"});
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        boolean interrupted = false;
+        try {
+            sslOS.write('B');
+            sslOS.flush();
+            sslIS.read();
+        } catch (SSLException ssle) {
+            // get the expected exception
+            interrupted = true;
+        } finally {
+            sslSocket.close();
+        }
+
+        if (!interrupted) {
+            throw new SSLHandshakeException(
+                "A weak cipher suite is negotiated, " +
+                "TLSv1.1 must not negotiate the exportable cipher suites.");
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new ExportableStreamCipher();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ExportableStreamCipher() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/javax/net/ssl/TLSv11/GenericBlockCipher.java	Sat Oct 30 18:39:17 2010 +0800
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4873188
+ * @summary Support TLS 1.1
+ * @run main/othervm -Djavax.net.debug=all GenericBlockCipher
+ *
+ * @author Xuelei Fan
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+
+public class GenericBlockCipher {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "/../../../../etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write('A');
+        sslOS.flush();
+
+        sslSocket.close();
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+
+        // enable TLSv1.1 only
+        sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"});
+
+        // enable a block cipher
+        sslSocket.setEnabledCipherSuites(
+            new String[] {"TLS_RSA_WITH_AES_128_CBC_SHA"});
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslOS.write('B');
+        sslOS.flush();
+        sslIS.read();
+
+        sslSocket.close();
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new GenericBlockCipher();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    GenericBlockCipher() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/javax/net/ssl/TLSv11/GenericStreamCipher.java	Sat Oct 30 18:39:17 2010 +0800
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4873188
+ * @summary Support TLS 1.1
+ * @run main/othervm -Djavax.net.debug=all GenericStreamCipher
+ *
+ * @author Xuelei Fan
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+
+public class GenericStreamCipher {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "/../../../../etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write('A');
+        sslOS.flush();
+
+        sslSocket.close();
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+
+        // enable TLSv1.1 only
+        sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"});
+
+        // enable a stream cipher
+        sslSocket.setEnabledCipherSuites(
+            new String[] {"SSL_RSA_WITH_RC4_128_MD5"});
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslOS.write('B');
+        sslOS.flush();
+        sslIS.read();
+
+        sslSocket.close();
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new GenericStreamCipher();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    GenericStreamCipher() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- a/test/sun/security/ssl/sanity/interop/CipherTest.java	Fri Oct 29 12:35:07 2010 +0200
+++ b/test/sun/security/ssl/sanity/interop/CipherTest.java	Sat Oct 30 18:39:17 2010 +0800
@@ -120,6 +120,13 @@
                 return false;
             }
 
+            // ignore exportable cipher suite for TLSv1.1
+            if (protocol.equals("TLSv1.1")) {
+                if(cipherSuite.indexOf("_EXPORT_") != -1) {
+                    return false;
+                }
+            }
+
             return true;
         }
 
@@ -149,18 +156,14 @@
             cipherSuites.length * protocols.length * clientAuths.length);
         for (int i = 0; i < cipherSuites.length; i++) {
             String cipherSuite = cipherSuites[i];
-            if (peerFactory.isSupported(cipherSuite) == false) {
-                continue;
-            }
-            // skip kerberos cipher suites
-            if (cipherSuite.startsWith("TLS_KRB5")) {
-                continue;
-            }
+
             for (int j = 0; j < protocols.length; j++) {
                 String protocol = protocols[j];
-                if (protocol.equals("SSLv2Hello")) {
+
+                if (!peerFactory.isSupported(cipherSuite, protocol)) {
                     continue;
                 }
+
                 for (int k = 0; k < clientAuths.length; k++) {
                     String clientAuth = clientAuths[k];
                     if ((clientAuth != null) &&
@@ -297,7 +300,7 @@
             throws Exception {
         long time = System.currentTimeMillis();
         String relPath;
-        if ((args.length > 0) && args[0].equals("sh")) {
+        if ((args != null) && (args.length > 0) && args[0].equals("sh")) {
             relPath = pathToStoresSH;
         } else {
             relPath = pathToStores;
@@ -336,7 +339,30 @@
 
         abstract Server newServer(CipherTest cipherTest) throws Exception;
 
-        boolean isSupported(String cipherSuite) {
+        boolean isSupported(String cipherSuite, String protocol) {
+            // skip kerberos cipher suites
+            if (cipherSuite.startsWith("TLS_KRB5")) {
+                System.out.println("Skipping unsupported test for " +
+                                    cipherSuite + " of " + protocol);
+                return false;
+            }
+
+            // skip SSLv2Hello protocol
+            if (protocol.equals("SSLv2Hello")) {
+                System.out.println("Skipping unsupported test for " +
+                                    cipherSuite + " of " + protocol);
+                return false;
+            }
+
+            // ignore exportable cipher suite for TLSv1.1
+            if (protocol.equals("TLSv1.1")) {
+                if (cipherSuite.indexOf("_EXPORT_WITH") != -1) {
+                    System.out.println("Skipping obsoleted test for " +
+                                        cipherSuite + " of " + protocol);
+                    return false;
+                }
+            }
+
             return true;
         }
     }