jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java
changeset 30904 ec0224270f90
parent 28555 c7bf34f7b215
child 32032 22badc53802f
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Tue Jun 02 04:01:04 2015 +0000
@@ -62,6 +62,9 @@
     private CipherSuiteList defaultClientCipherSuiteList;
     private CipherSuiteList supportedCipherSuiteList;
 
+    // DTLS cookie exchange manager
+    private HelloCookieManager helloCookieManager;
+
     SSLContextImpl() {
         ephemeralKeyManager = new EphemeralKeyManager();
         clientCache = new SSLSessionContextImpl();
@@ -175,11 +178,29 @@
         return DummyX509KeyManager.INSTANCE;
     }
 
+    abstract SSLEngine createSSLEngineImpl();
+    abstract SSLEngine createSSLEngineImpl(String host, int port);
+
+    @Override
+    protected SSLEngine engineCreateSSLEngine() {
+        if (!isInitialized) {
+            throw new IllegalStateException("SSLContext is not initialized");
+        }
+        return createSSLEngineImpl();
+    }
+
+    @Override
+    protected SSLEngine engineCreateSSLEngine(String host, int port) {
+        if (!isInitialized) {
+            throw new IllegalStateException("SSLContext is not initialized");
+        }
+        return createSSLEngineImpl(host, port);
+    }
+
     @Override
     protected SSLSocketFactory engineGetSocketFactory() {
         if (!isInitialized) {
-            throw new IllegalStateException(
-                "SSLContextImpl is not initialized");
+            throw new IllegalStateException("SSLContext is not initialized");
         }
        return new SSLSocketFactoryImpl(this);
     }
@@ -193,24 +214,6 @@
     }
 
     @Override
-    protected SSLEngine engineCreateSSLEngine() {
-        if (!isInitialized) {
-            throw new IllegalStateException(
-                "SSLContextImpl is not initialized");
-        }
-        return new SSLEngineImpl(this);
-    }
-
-    @Override
-    protected SSLEngine engineCreateSSLEngine(String host, int port) {
-        if (!isInitialized) {
-            throw new IllegalStateException(
-                "SSLContextImpl is not initialized");
-        }
-        return new SSLEngineImpl(this, host, port);
-    }
-
-    @Override
     protected SSLSessionContext engineGetClientSessionContext() {
         return clientCache;
     }
@@ -236,6 +239,23 @@
         return ephemeralKeyManager;
     }
 
+    HelloCookieManager getHelloCookieManager() {
+        if (!isInitialized) {
+            throw new IllegalStateException("SSLContext is not initialized");
+        }
+
+        if (helloCookieManager == null) {
+            helloCookieManager = getHelloCookieManager(secureRandom);
+        }
+
+        return helloCookieManager;
+    }
+
+    HelloCookieManager getHelloCookieManager(SecureRandom secureRandom) {
+        throw new UnsupportedOperationException(
+                "Cookie exchange applies to DTLS only");
+    }
+
     abstract SSLParameters getDefaultServerSSLParams();
     abstract SSLParameters getDefaultClientSSLParams();
     abstract SSLParameters getSupportedSSLParams();
@@ -319,12 +339,20 @@
                (protocols == defaultClientProtocolList);
     }
 
+    /**
+     * Return whether a protocol list is the original default enabled
+     * protocols.  See: SSLSocket/SSLEngine.setEnabledProtocols()
+     */
+    boolean isDefaultCipherSuiteList(CipherSuiteList cipherSuites) {
+        return (cipherSuites == defaultClientCipherSuiteList) ||
+               (cipherSuites == defaultServerCipherSuiteList);
+    }
 
     /*
      * Return the list of all available CipherSuites with a priority of
      * minPriority or above.
      */
-    private CipherSuiteList getApplicableCipherSuiteList(
+    private static CipherSuiteList getApplicableCipherSuiteList(
             ProtocolList protocols, boolean onlyEnabled) {
 
         int minPriority = CipherSuite.SUPPORTED_SUITES_PRIORITY;
@@ -344,8 +372,8 @@
                 }
 
                 if (suite.isAvailable() &&
-                        suite.obsoleted > protocols.min.v &&
-                        suite.supported <= protocols.max.v) {
+                        !protocols.min.obsoletes(suite) &&
+                        protocols.max.supports(suite)) {
                     if (SSLAlgorithmConstraints.DEFAULT.permits(
                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                             suite.name, null)) {
@@ -353,10 +381,10 @@
                     }
                 } else if (debug != null &&
                         Debug.isOn("sslctx") && Debug.isOn("verbose")) {
-                    if (suite.obsoleted <= protocols.min.v) {
+                    if (protocols.min.obsoletes(suite)) {
                         System.out.println(
                             "Ignoring obsoleted cipher suite: " + suite);
-                    } else if (suite.supported > protocols.max.v) {
+                    } else if (!protocols.max.supports(suite)) {
                         System.out.println(
                             "Ignoring unsupported cipher suite: " + suite);
                     } else {
@@ -388,8 +416,25 @@
         }
     }
 
+    private static String[] getAvailableProtocols(
+            ProtocolVersion[] protocolCandidates) {
+
+        List<String> availableProtocols = Collections.<String>emptyList();
+        if (protocolCandidates !=  null && protocolCandidates.length != 0) {
+            availableProtocols = new ArrayList<>(protocolCandidates.length);
+            for (ProtocolVersion p : protocolCandidates) {
+                if (ProtocolVersion.availableProtocols.contains(p)) {
+                    availableProtocols.add(p.name);
+                }
+            }
+        }
+
+        return availableProtocols.toArray(new String[0]);
+    }
+
+
     /*
-     * The SSLContext implementation for TLS/SSL algorithm
+     * The SSLContext implementation for SSL/(D)TLS algorithm
      *
      * SSL/TLS protocols specify the forward compatibility and version
      * roll-back attack protections, however, a number of SSL/TLS server
@@ -418,14 +463,15 @@
      */
 
     /*
-     * The base abstract SSLContext implementation.
+     * The base abstract SSLContext implementation for the Transport Layer
+     * Security (TLS) protocols.
      *
      * This abstract class encapsulates supported and the default server
-     * SSL parameters.
+     * SSL/TLS parameters.
      *
      * @see SSLContext
      */
-    private abstract static class AbstractSSLContext extends SSLContextImpl {
+    private abstract static class AbstractTLSContext extends SSLContextImpl {
         // parameters
         private static final SSLParameters defaultServerSSLParams;
         private static final SSLParameters supportedSSLParams;
@@ -482,20 +528,14 @@
             return supportedSSLParams;
         }
 
-        static String[] getAvailableProtocols(
-                ProtocolVersion[] protocolCandidates) {
+        @Override
+        SSLEngine createSSLEngineImpl() {
+            return new SSLEngineImpl(this, false);
+        }
 
-            List<String> availableProtocols = Collections.<String>emptyList();
-            if (protocolCandidates !=  null && protocolCandidates.length != 0) {
-                availableProtocols = new ArrayList<>(protocolCandidates.length);
-                for (ProtocolVersion p : protocolCandidates) {
-                    if (ProtocolVersion.availableProtocols.contains(p)) {
-                        availableProtocols.add(p.name);
-                    }
-                }
-            }
-
-            return availableProtocols.toArray(new String[0]);
+        @Override
+        SSLEngine createSSLEngineImpl(String host, int port) {
+            return new SSLEngineImpl(this, host, port, false);
         }
     }
 
@@ -504,7 +544,7 @@
      *
      * @see SSLContext
      */
-    public static final class TLS10Context extends AbstractSSLContext {
+    public static final class TLS10Context extends AbstractTLSContext {
         private static final SSLParameters defaultClientSSLParams;
 
         static {
@@ -537,7 +577,7 @@
      *
      * @see SSLContext
      */
-    public static final class TLS11Context extends AbstractSSLContext {
+    public static final class TLS11Context extends AbstractTLSContext {
         private static final SSLParameters defaultClientSSLParams;
 
         static {
@@ -572,7 +612,7 @@
      *
      * @see SSLContext
      */
-    public static final class TLS12Context extends AbstractSSLContext {
+    public static final class TLS12Context extends AbstractTLSContext {
         private static final SSLParameters defaultClientSSLParams;
 
         static {
@@ -605,12 +645,73 @@
     }
 
     /*
+     * The interface for the customized SSL/(D)TLS SSLContext.
+     *
+     * @see SSLContext
+     */
+    private static class CustomizedSSLProtocols {
+        private final static String PROPERTY_NAME = "jdk.tls.client.protocols";
+        static IllegalArgumentException reservedException = null;
+        static ArrayList<ProtocolVersion>
+                                customizedProtocols = new ArrayList<>();
+
+        // Don't want a java.lang.LinkageError for illegal system property.
+        //
+        // Please don't throw exception in this static block.  Otherwise,
+        // java.lang.LinkageError may be thrown during the instantiation of
+        // the provider service. Instead, please handle the initialization
+        // exception in the caller's constructor.
+        static {
+            String property = AccessController.doPrivileged(
+                    new GetPropertyAction(PROPERTY_NAME));
+            if (property != null && property.length() != 0) {
+                // remove double quote marks from beginning/end of the property
+                if (property.length() > 1 && property.charAt(0) == '"' &&
+                        property.charAt(property.length() - 1) == '"') {
+                    property = property.substring(1, property.length() - 1);
+                }
+            }
+
+            if (property != null && property.length() != 0) {
+                String[] protocols = property.split(",");
+                for (int i = 0; i < protocols.length; i++) {
+                    protocols[i] = protocols[i].trim();
+                    // Is it a supported protocol name?
+                    try {
+                        ProtocolVersion pro =
+                                ProtocolVersion.valueOf(protocols[i]);
+
+                        if (SunJSSE.isFIPS() &&
+                                ((pro.v == ProtocolVersion.SSL30.v) ||
+                                 (pro.v == ProtocolVersion.SSL20Hello.v))) {
+                            reservedException = new IllegalArgumentException(
+                                    PROPERTY_NAME + ": " + pro +
+                                    " is not FIPS compliant");
+
+                            break;
+                        }
+
+                        // ignore duplicated protocols
+                        if (!customizedProtocols.contains(pro)) {
+                            customizedProtocols.add(pro);
+                        }
+                    } catch (IllegalArgumentException iae) {
+                        reservedException = new IllegalArgumentException(
+                                PROPERTY_NAME + ": " + protocols[i] +
+                                " is not a standard SSL protocol name", iae);
+                    }
+                }
+            }
+        }
+    }
+
+    /*
      * The SSLContext implementation for customized TLS protocols
      *
      * @see SSLContext
      */
-    private static class CustomizedSSLContext extends AbstractSSLContext {
-        private static final String PROPERTY_NAME = "jdk.tls.client.protocols";
+    private static class CustomizedTLSContext extends AbstractTLSContext {
+
         private static final SSLParameters defaultClientSSLParams;
         private static IllegalArgumentException reservedException = null;
 
@@ -621,78 +722,52 @@
         // the provider service. Instead, let's handle the initialization
         // exception in constructor.
         static {
-            // candidates for available protocols
-            ProtocolVersion[] candidates;
-
-            String property = AccessController.doPrivileged(
-                    new GetPropertyAction(PROPERTY_NAME));
-            if (property == null || property.length() == 0) {
-                // the default enabled client TLS protocols
-                if (SunJSSE.isFIPS()) {
-                    candidates = new ProtocolVersion[] {
-                        ProtocolVersion.TLS10,
-                        ProtocolVersion.TLS11,
-                        ProtocolVersion.TLS12
-                    };
-                } else {
-                    candidates = new ProtocolVersion[] {
-                        ProtocolVersion.SSL30,
-                        ProtocolVersion.TLS10,
-                        ProtocolVersion.TLS11,
-                        ProtocolVersion.TLS12
-                    };
-                }
-            } else {
-                // remove double quote marks from beginning/end of the property
-                if (property.length() > 1 && property.charAt(0) == '"' &&
-                        property.charAt(property.length() - 1) == '"') {
-                    property = property.substring(1, property.length() - 1);
-                }
-
-                String[] protocols = null;
-                if (property != null && property.length() != 0) {
-                    protocols = property.split(",");
-                } else {
-                    reservedException = new IllegalArgumentException(
-                        "No protocol specified in " +
-                        PROPERTY_NAME + " system property");
-                    protocols = new String[0];
-                }
-
-                candidates = new ProtocolVersion[protocols.length];
-                for (int i = 0; i < protocols.length; i++) {
-                    protocols[i] = protocols[i].trim();
-                    // Is it a supported protocol name?
-                    try {
-                        candidates[i] = ProtocolVersion.valueOf(protocols[i]);
-                    } catch (IllegalArgumentException iae) {
-                        reservedException = new IllegalArgumentException(
-                            PROPERTY_NAME + ": " + protocols[i] +
-                            " is not a standard SSL/TLS protocol name", iae);
-                        break;
+            reservedException = CustomizedSSLProtocols.reservedException;
+            if (reservedException == null) {
+                ArrayList<ProtocolVersion>
+                        customizedTLSProtocols = new ArrayList<>();
+                for (ProtocolVersion protocol :
+                        CustomizedSSLProtocols.customizedProtocols) {
+                    if (!protocol.isDTLSProtocol()) {
+                        customizedTLSProtocols.add(protocol);
                     }
                 }
 
-                if ((reservedException == null) && SunJSSE.isFIPS()) {
-                    for (ProtocolVersion protocolVersion : candidates) {
-                        if (ProtocolVersion.SSL20Hello.v == protocolVersion.v ||
-                                ProtocolVersion.SSL30.v == protocolVersion.v) {
-                            reservedException = new IllegalArgumentException(
-                                    PROPERTY_NAME + ": " + protocolVersion +
-                                    " is not FIPS compliant");
-                        }
+                // candidates for available protocols
+                ProtocolVersion[] candidates;
+                if (customizedTLSProtocols.isEmpty()) {
+                    // Use the default enabled client protocols if no
+                    // customized TLS protocols.
+                    if (SunJSSE.isFIPS()) {
+                        candidates = new ProtocolVersion[] {
+                            ProtocolVersion.TLS10,
+                            ProtocolVersion.TLS11,
+                            ProtocolVersion.TLS12
+                        };
+                    } else {
+                        candidates = new ProtocolVersion[] {
+                            ProtocolVersion.SSL30,
+                            ProtocolVersion.TLS10,
+                            ProtocolVersion.TLS11,
+                            ProtocolVersion.TLS12
+                        };
                     }
+                } else {
+                    // Use the customized TLS protocols.
+                    candidates =
+                            new ProtocolVersion[customizedTLSProtocols.size()];
+                    candidates = customizedTLSProtocols.toArray(candidates);
                 }
-            }
 
-            defaultClientSSLParams = new SSLParameters();
-            if (reservedException == null) {
+                defaultClientSSLParams = new SSLParameters();
                 defaultClientSSLParams.setProtocols(
                         getAvailableProtocols(candidates));
+            } else {
+                defaultClientSSLParams = null;  // unlikely to be used
             }
         }
 
-        protected CustomizedSSLContext() {
+        protected CustomizedTLSContext() {
             if (reservedException != null) {
                 throw reservedException;
             }
@@ -709,7 +784,7 @@
      *
      * @see SSLContext
      */
-    public static final class TLSContext extends CustomizedSSLContext {
+    public static final class TLSContext extends CustomizedTLSContext {
         // use the default constructor and methods
     }
 
@@ -718,7 +793,7 @@
      *
      * @see SSLContext
      */
-    public static final class DefaultSSLContext extends CustomizedSSLContext {
+    public static final class DefaultSSLContext extends CustomizedTLSContext {
         private static final String NONE = "NONE";
         private static final String P11KEYSTORE = "PKCS11";
 
@@ -879,6 +954,193 @@
         }
     }
 
+    /*
+     * The base abstract SSLContext implementation for the Datagram Transport
+     * Layer Security (DTLS) protocols.
+     *
+     * This abstract class encapsulates supported and the default server DTLS
+     * parameters.
+     *
+     * @see SSLContext
+     */
+    private abstract static class AbstractDTLSContext extends SSLContextImpl {
+        // parameters
+        private static final SSLParameters defaultServerSSLParams;
+        private static final SSLParameters supportedSSLParams;
+
+        static {
+            // supported SSL parameters
+            supportedSSLParams = new SSLParameters();
+
+            // Both DTLSv1.0 and DTLSv1.2 can be used in FIPS mode.
+            supportedSSLParams.setProtocols(new String[] {
+                ProtocolVersion.DTLS10.name,
+                ProtocolVersion.DTLS12.name
+            });
+
+            // candidates for available protocols
+            ProtocolVersion[] candidates = new ProtocolVersion[] {
+                ProtocolVersion.DTLS10,
+                ProtocolVersion.DTLS12
+            };
+
+            defaultServerSSLParams = new SSLParameters();
+            defaultServerSSLParams.setProtocols(
+                    getAvailableProtocols(candidates));
+        }
+
+        @Override
+        SSLParameters getDefaultServerSSLParams() {
+            return defaultServerSSLParams;
+        }
+
+        @Override
+        SSLParameters getSupportedSSLParams() {
+            return supportedSSLParams;
+        }
+
+        @Override
+        SSLEngine createSSLEngineImpl() {
+            return new SSLEngineImpl(this, true);
+        }
+
+        @Override
+        SSLEngine createSSLEngineImpl(String host, int port) {
+            return new SSLEngineImpl(this, host, port, true);
+        }
+
+        @Override
+        HelloCookieManager getHelloCookieManager(SecureRandom secureRandom) {
+            return new HelloCookieManager(secureRandom);
+        }
+    }
+
+    /*
+     * The SSLContext implementation for DTLSv1.0 algorithm.
+     *
+     * @see SSLContext
+     */
+    public static final class DTLS10Context extends AbstractDTLSContext {
+        private final static SSLParameters defaultClientSSLParams;
+
+        static {
+            // candidates for available protocols
+            ProtocolVersion[] candidates = new ProtocolVersion[] {
+                ProtocolVersion.DTLS10
+            };
+
+            defaultClientSSLParams = new SSLParameters();
+            defaultClientSSLParams.setProtocols(
+                    getAvailableProtocols(candidates));
+        }
+
+        @Override
+        SSLParameters getDefaultClientSSLParams() {
+            return defaultClientSSLParams;
+        }
+    }
+
+    /*
+     * The SSLContext implementation for DTLSv1.2 algorithm.
+     *
+     * @see SSLContext
+     */
+    public static final class DTLS12Context extends AbstractDTLSContext {
+        private final static SSLParameters defaultClientSSLParams;
+
+        static {
+            // candidates for available protocols
+            ProtocolVersion[] candidates = new ProtocolVersion[] {
+                ProtocolVersion.DTLS10,
+                ProtocolVersion.DTLS12
+            };
+
+            defaultClientSSLParams = new SSLParameters();
+            defaultClientSSLParams.setProtocols(
+                    getAvailableProtocols(candidates));
+        }
+
+        @Override
+        SSLParameters getDefaultClientSSLParams() {
+            return defaultClientSSLParams;
+        }
+    }
+
+    /*
+     * The SSLContext implementation for customized TLS protocols
+     *
+     * @see SSLContext
+     */
+    private static class CustomizedDTLSContext extends AbstractDTLSContext {
+        private final static SSLParameters defaultClientSSLParams;
+        private static IllegalArgumentException reservedException = null;
+
+        // Don't want a java.lang.LinkageError for illegal system property.
+        //
+        // Please don't throw exception in this static block.  Otherwise,
+        // java.lang.LinkageError may be thrown during the instantiation of
+        // the provider service. Instead, let's handle the initialization
+        // exception in constructor.
+        static {
+            reservedException = CustomizedSSLProtocols.reservedException;
+            if (reservedException == null) {
+                ArrayList<ProtocolVersion>
+                        customizedDTLSProtocols = new ArrayList<>();
+                for (ProtocolVersion protocol :
+                        CustomizedSSLProtocols.customizedProtocols) {
+                    if (protocol.isDTLSProtocol()) {
+                        customizedDTLSProtocols.add(protocol);
+                    }
+                }
+
+                // candidates for available protocols
+                ProtocolVersion[] candidates;
+                if (customizedDTLSProtocols.isEmpty()) {
+                    // Use the default enabled client protocols if no
+                    // customized TLS protocols.
+                    //
+                    // Both DTLSv1.0 and DTLSv1.2 can be used in FIPS mode.
+                    candidates = new ProtocolVersion[] {
+                        ProtocolVersion.DTLS10,
+                        ProtocolVersion.DTLS12
+                    };
+
+                } else {
+                    // Use the customized TLS protocols.
+                    candidates =
+                            new ProtocolVersion[customizedDTLSProtocols.size()];
+                    candidates = customizedDTLSProtocols.toArray(candidates);
+                }
+
+                defaultClientSSLParams = new SSLParameters();
+                defaultClientSSLParams.setProtocols(
+                        getAvailableProtocols(candidates));
+            } else {
+                defaultClientSSLParams = null;   // unlikely to be used
+            }
+        }
+
+        protected CustomizedDTLSContext() {
+            if (reservedException != null) {
+                throw reservedException;
+            }
+        }
+
+        @Override
+        SSLParameters getDefaultClientSSLParams() {
+            return defaultClientSSLParams;
+        }
+    }
+
+    /*
+     * The SSLContext implementation for default "DTLS" algorithm
+     *
+     * @see SSLContext
+     */
+    public static final class DTLSContext extends CustomizedDTLSContext {
+        // use the default constructor and methods
+    }
+
 }
 
 
@@ -961,7 +1223,7 @@
             ProtocolVersion protocolVersion =
                 ProtocolVersion.valueOf(session.getProtocol());
             AlgorithmConstraints constraints = null;
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 if (session instanceof ExtendedSSLSession) {
                     ExtendedSSLSession extSession =
                                     (ExtendedSSLSession)session;
@@ -1003,7 +1265,7 @@
             ProtocolVersion protocolVersion =
                 ProtocolVersion.valueOf(session.getProtocol());
             AlgorithmConstraints constraints = null;
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 if (session instanceof ExtendedSSLSession) {
                     ExtendedSSLSession extSession =
                                     (ExtendedSSLSession)session;