src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java

Print this page

        

@@ -60,10 +60,13 @@
     // supported and default cipher suites
     private CipherSuiteList defaultServerCipherSuiteList;
     private CipherSuiteList defaultClientCipherSuiteList;
     private CipherSuiteList supportedCipherSuiteList;
 
+    // DTLS cookie exchange manager
+    private HelloCookieManager helloCookieManager;
+
     SSLContextImpl() {
         ephemeralKeyManager = new EphemeralKeyManager();
         clientCache = new SSLSessionContextImpl();
         serverCache = new SSLSessionContextImpl();
     }

@@ -173,43 +176,43 @@
 
         // nothing found, return a dummy X509ExtendedKeyManager
         return DummyX509KeyManager.INSTANCE;
     }
 
+    abstract SSLEngine createSSLEngineImpl();
+    abstract SSLEngine createSSLEngineImpl(String host, int port);
+
     @Override
-    protected SSLSocketFactory engineGetSocketFactory() {
+    protected SSLEngine engineCreateSSLEngine() {
         if (!isInitialized) {
-            throw new IllegalStateException(
-                "SSLContextImpl is not initialized");
+            throw new IllegalStateException("SSLContext is not initialized");
         }
-       return new SSLSocketFactoryImpl(this);
+        return createSSLEngineImpl();
     }
 
     @Override
-    protected SSLServerSocketFactory engineGetServerSocketFactory() {
+    protected SSLEngine engineCreateSSLEngine(String host, int port) {
         if (!isInitialized) {
             throw new IllegalStateException("SSLContext is not initialized");
         }
-        return new SSLServerSocketFactoryImpl(this);
+        return createSSLEngineImpl(host, port);
     }
 
     @Override
-    protected SSLEngine engineCreateSSLEngine() {
+    protected SSLSocketFactory engineGetSocketFactory() {
         if (!isInitialized) {
-            throw new IllegalStateException(
-                "SSLContextImpl is not initialized");
+            throw new IllegalStateException("SSLContext is not initialized");
         }
-        return new SSLEngineImpl(this);
+       return new SSLSocketFactoryImpl(this);
     }
 
     @Override
-    protected SSLEngine engineCreateSSLEngine(String host, int port) {
+    protected SSLServerSocketFactory engineGetServerSocketFactory() {
         if (!isInitialized) {
-            throw new IllegalStateException(
-                "SSLContextImpl is not initialized");
+            throw new IllegalStateException("SSLContext is not initialized");
         }
-        return new SSLEngineImpl(this, host, port);
+        return new SSLServerSocketFactoryImpl(this);
     }
 
     @Override
     protected SSLSessionContext engineGetClientSessionContext() {
         return clientCache;

@@ -234,10 +237,27 @@
 
     EphemeralKeyManager getEphemeralKeyManager() {
         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();
 
     // Get supported ProtocolList.

@@ -317,16 +337,24 @@
     boolean isDefaultProtocolList(ProtocolList protocols) {
         return (protocols == defaultServerProtocolList) ||
                (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;
         if (onlyEnabled) {
             minPriority = CipherSuite.DEFAULT_SUITES_PRIORITY;

@@ -342,23 +370,23 @@
                 if (!suite.allowed || suite.priority < minPriority) {
                     continue;
                 }
 
                 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)) {
                         suites.add(suite);
                     }
                 } 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 {
                         System.out.println(
                             "Ignoring unavailable cipher suite: " + suite);

@@ -386,12 +414,29 @@
             CipherSuite.BulkCipher.clearAvailableCache();
             JsseJce.clearEcAvailable();
         }
     }
 
+    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
      * vendors did not implement these aspects properly, and some current
      * SSL/TLS servers may refuse to talk to a TLS 1.1 or later client.

@@ -416,18 +461,19 @@
      * by default. Applications still can use it by enabling SSLv2Hello with
      * the series of setEnabledProtocols APIs.
      */
 
     /*
-     * 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;
 
         static {

@@ -480,33 +526,27 @@
         @Override
         SSLParameters getSupportedSSLParams() {
             return supportedSSLParams;
         }
 
-        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);
+        @Override
+        SSLEngine createSSLEngineImpl() {
+            return new SSLEngineImpl(this, false);
                     }
-                }
-            }
 
-            return availableProtocols.toArray(new String[0]);
+        @Override
+        SSLEngine createSSLEngineImpl(String host, int port) {
+            return new SSLEngineImpl(this, host, port, false);
         }
     }
 
     /*
      * The SSLContext implementation for SSLv3 and TLS10 algorithm
      *
      * @see SSLContext
      */
-    public static final class TLS10Context extends AbstractSSLContext {
+    public static final class TLS10Context extends AbstractTLSContext {
         private static final SSLParameters defaultClientSSLParams;
 
         static {
             // candidates for available protocols
             ProtocolVersion[] candidates;

@@ -535,11 +575,11 @@
     /*
      * The SSLContext implementation for TLS11 algorithm
      *
      * @see SSLContext
      */
-    public static final class TLS11Context extends AbstractSSLContext {
+    public static final class TLS11Context extends AbstractTLSContext {
         private static final SSLParameters defaultClientSSLParams;
 
         static {
             // candidates for available protocols
             ProtocolVersion[] candidates;

@@ -570,11 +610,11 @@
     /*
      * The SSLContext implementation for TLS12 algorithm
      *
      * @see SSLContext
      */
-    public static final class TLS12Context extends AbstractSSLContext {
+    public static final class TLS12Context extends AbstractTLSContext {
         private static final SSLParameters defaultClientSSLParams;
 
         static {
             // candidates for available protocols
             ProtocolVersion[] candidates;

@@ -603,16 +643,77 @@
             return defaultClientSSLParams;
         }
     }
 
     /*
+     * 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;
 
         // Don't want a java.lang.LinkageError for illegal system property.
         //

@@ -619,17 +720,26 @@
         // 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>
+                        customizedTLSProtocols = new ArrayList<>();
+                for (ProtocolVersion protocol :
+                        CustomizedSSLProtocols.customizedProtocols) {
+                    if (!protocol.isDTLSProtocol()) {
+                        customizedTLSProtocols.add(protocol);
+                    }
+                }
+
             // 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 (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

@@ -641,60 +751,25 @@
                         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);
+                    // Use the customized TLS protocols.
+                    candidates =
+                            new ProtocolVersion[customizedTLSProtocols.size()];
+                    candidates = customizedTLSProtocols.toArray(candidates);
                 }
 
-                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;
-                    }
-                }
-
-                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");
-                        }
-                    }
-                }
-            }
-
             defaultClientSSLParams = new SSLParameters();
-            if (reservedException == null) {
                 defaultClientSSLParams.setProtocols(
                         getAvailableProtocols(candidates));
+            } else {
+                defaultClientSSLParams = null;  // unlikely to be used
             }
         }
 
-        protected CustomizedSSLContext() {
+        protected CustomizedTLSContext() {
             if (reservedException != null) {
                 throw reservedException;
             }
         }
 

@@ -707,20 +782,20 @@
     /*
      * The SSLContext implementation for default "TLS" algorithm
      *
      * @see SSLContext
      */
-    public static final class TLSContext extends CustomizedSSLContext {
+    public static final class TLSContext extends CustomizedTLSContext {
         // use the default constructor and methods
     }
 
     /*
      * The SSLContext implementation for default "Default" algorithm
      *
      * @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";
 
         private static volatile SSLContextImpl defaultImpl;
 

@@ -877,10 +952,197 @@
             defaultKeyManagers = kmf.getKeyManagers();
             return defaultKeyManagers;
         }
     }
 
+    /*
+     * 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
+    }
+
 }
 
 
 final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager
             implements X509TrustManager {

@@ -959,11 +1221,11 @@
 
             // try the best to check the algorithm constraints
             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;
                     String[] peerSupportedSignAlgs =
                             extSession.getLocalSupportedSignatureAlgorithms();

@@ -1001,11 +1263,11 @@
 
             // try the best to check the algorithm constraints
             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;
                     String[] peerSupportedSignAlgs =
                             extSession.getLocalSupportedSignatureAlgorithms();