Mercurial > hg > release > icedtea7-forest-2.6 > jdk
changeset 9712:1f10820808c5
8162362: Introduce system property to control enabled ciphersuites
Reviewed-by: xuelei
author | coffeys |
---|---|
date | Tue, 27 Mar 2018 16:54:03 +0100 |
parents | bbb49ffe60a3 |
children | ba99d2bbbda5 |
files | src/share/classes/sun/security/ssl/SSLContextImpl.java src/share/classes/sun/security/ssl/SSLEngineImpl.java src/share/classes/sun/security/ssl/SSLSocketImpl.java test/sun/security/ssl/SSLContextImpl/CustomizedCipherSuites.java |
diffstat | 4 files changed, 420 insertions(+), 34 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/sun/security/ssl/SSLContextImpl.java Wed Feb 13 06:50:44 2019 +0000 +++ b/src/share/classes/sun/security/ssl/SSLContextImpl.java Tue Mar 27 16:54:03 2018 +0100 @@ -53,6 +53,11 @@ private X509TrustManager trustManager; private SecureRandom secureRandom; + private final static Collection<CipherSuite> clientCustomizedCipherSuites = + getCustomizedCipherSuites("jdk.tls.client.cipherSuites"); + private final static Collection<CipherSuite> serverCustomizedCipherSuites = + getCustomizedCipherSuites("jdk.tls.server.cipherSuites"); + SSLContextImpl() { ephemeralKeyManager = new EphemeralKeyManager(); clientCache = new SSLSessionContextImpl(); @@ -272,19 +277,50 @@ } /* - * Return the list of all available CipherSuites with a priority of - * minPriority or above. + * Return the list of all available CipherSuites that are supported + * using currently installed providers. + */ + private static CipherSuiteList getApplicableSupportedCipherSuiteList( + ProtocolList protocols) { + + return getApplicableCipherSuiteList( + CipherSuite.allowedCipherSuites(), + protocols, CipherSuite.SUPPORTED_SUITES_PRIORITY); + } + + /* + * Return the list of all available CipherSuites that are default enabled + * in client or server side. + */ + private static CipherSuiteList getApplicableEnabledCipherSuiteList( + ProtocolList protocols, boolean isClient) { + + if (isClient) { + if (!clientCustomizedCipherSuites.isEmpty()) { + return getApplicableCipherSuiteList( + clientCustomizedCipherSuites, + protocols, CipherSuite.SUPPORTED_SUITES_PRIORITY); + } + } else { + if (!serverCustomizedCipherSuites.isEmpty()) { + return getApplicableCipherSuiteList( + serverCustomizedCipherSuites, + protocols, CipherSuite.SUPPORTED_SUITES_PRIORITY); + } + } + + return getApplicableCipherSuiteList( + CipherSuite.allowedCipherSuites(), + protocols, CipherSuite.DEFAULT_SUITES_PRIORITY); + } + + /* + * Return the list of available CipherSuites which are applicable to + * the specified protocols. */ private static CipherSuiteList getApplicableCipherSuiteList( - ProtocolList protocols, boolean onlyEnabled) { - - int minPriority = CipherSuite.SUPPORTED_SUITES_PRIORITY; - if (onlyEnabled) { - minPriority = CipherSuite.DEFAULT_SUITES_PRIORITY; - } - - Collection<CipherSuite> allowedCipherSuites = - CipherSuite.allowedCipherSuites(); + Collection<CipherSuite> allowedCipherSuites, + ProtocolList protocols, int minPriority) { TreeSet<CipherSuite> suites = new TreeSet<>(); if (!(protocols.collection().isEmpty()) && @@ -328,6 +364,67 @@ return new CipherSuiteList(suites); } + /* + * Get the customized cipher suites specified by the given system property. + */ + private static Collection<CipherSuite> getCustomizedCipherSuites( + String propertyName) { + + String property = AccessController.doPrivileged( + new GetPropertyAction(propertyName)); + if (debug != null && Debug.isOn("sslctx")) { + System.out.println( + "System property " + propertyName + " is set to '" + + property + "'"); + } + 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[] cipherSuiteNames = property.split(","); + Collection<CipherSuite> cipherSuites = + new ArrayList<>(cipherSuiteNames.length); + for (int i = 0; i < cipherSuiteNames.length; i++) { + cipherSuiteNames[i] = cipherSuiteNames[i].trim(); + if (cipherSuiteNames[i].isEmpty()) { + continue; + } + + CipherSuite suite; + try { + suite = CipherSuite.valueOf(cipherSuiteNames[i]); + } catch (IllegalArgumentException iae) { + if (debug != null && Debug.isOn("sslctx")) { + System.out.println( + "Unknown or unsupported cipher suite name: " + + cipherSuiteNames[i]); + } + + continue; + } + + if (suite.isAvailable()) { + cipherSuites.add(suite); + } else { + if (debug != null && Debug.isOn("sslctx")) { + System.out.println( + "The current installed providers do not " + + "support cipher suite: " + cipherSuiteNames[i]); + } + } + } + + return cipherSuites; + } + + return Collections.emptyList(); + } + private static String[] getAvailableProtocols( ProtocolVersion[] protocolCandidates) { @@ -422,10 +519,10 @@ })); } - supportedCipherSuiteList = getApplicableCipherSuiteList( - supportedProtocolList, false); // all supported - serverDefaultCipherSuiteList = getApplicableCipherSuiteList( - serverDefaultProtocolList, true); // enabled only + supportedCipherSuiteList = getApplicableSupportedCipherSuiteList( + supportedProtocolList); + serverDefaultCipherSuiteList = getApplicableEnabledCipherSuiteList( + serverDefaultProtocolList, false); } @Override @@ -482,8 +579,8 @@ })); } - clientDefaultCipherSuiteList = getApplicableCipherSuiteList( - clientDefaultProtocolList, true); // enabled only + clientDefaultCipherSuiteList = getApplicableEnabledCipherSuiteList( + clientDefaultProtocolList, true); } @Override @@ -522,8 +619,9 @@ })); } - clientDefaultCipherSuiteList = getApplicableCipherSuiteList( - clientDefaultProtocolList, true); // enabled only + clientDefaultCipherSuiteList = getApplicableEnabledCipherSuiteList( + clientDefaultProtocolList, true); + } @Override @@ -564,8 +662,8 @@ })); } - clientDefaultCipherSuiteList = getApplicableCipherSuiteList( - clientDefaultProtocolList, true); // enabled only + clientDefaultCipherSuiteList = getApplicableEnabledCipherSuiteList( + clientDefaultProtocolList, true); } @Override @@ -696,8 +794,9 @@ clientDefaultProtocolList = new ProtocolList( getAvailableProtocols(candidates)); - clientDefaultCipherSuiteList = getApplicableCipherSuiteList( - clientDefaultProtocolList, true); // enabled only + clientDefaultCipherSuiteList = + getApplicableEnabledCipherSuiteList( + clientDefaultProtocolList, true); } else { clientDefaultProtocolList = null; // unlikely to be used clientDefaultCipherSuiteList = null; // unlikely to be used
--- a/src/share/classes/sun/security/ssl/SSLEngineImpl.java Wed Feb 13 06:50:44 2019 +0000 +++ b/src/share/classes/sun/security/ssl/SSLEngineImpl.java Tue Mar 27 16:54:03 2018 +0100 @@ -1884,13 +1884,21 @@ 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 we need to change the socket mode and the enabled + * protocols and cipher suites haven't specifically been + * set by the user, change them to the corresponding + * default ones. */ - if (roleIsServer != (!flag) && - sslContext.isDefaultProtocolList(enabledProtocols)) { - enabledProtocols = sslContext.getDefaultProtocolList(!flag); + if (roleIsServer != (!flag)) { + if (sslContext.isDefaultProtocolList(enabledProtocols)) { + enabledProtocols = + sslContext.getDefaultProtocolList(!flag); + } + + if (sslContext.isDefaultCipherSuiteList(enabledCipherSuites)) { + enabledCipherSuites = + sslContext.getDefaultCipherSuiteList(!flag); + } } roleIsServer = !flag;
--- a/src/share/classes/sun/security/ssl/SSLSocketImpl.java Wed Feb 13 06:50:44 2019 +0000 +++ b/src/share/classes/sun/security/ssl/SSLSocketImpl.java Tue Mar 27 16:54:03 2018 +0100 @@ -2315,13 +2315,22 @@ 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. + * protocols and cipher suites haven't specifically been + * set by the user, change them to the corresponding + * default ones. */ - if (roleIsServer != (!flag) && - sslContext.isDefaultProtocolList(enabledProtocols)) { - enabledProtocols = sslContext.getDefaultProtocolList(!flag); + if (roleIsServer != (!flag)) { + if (sslContext.isDefaultProtocolList(enabledProtocols)) { + enabledProtocols = + sslContext.getDefaultProtocolList(!flag); + } + + if (sslContext.isDefaultCipherSuiteList(enabledCipherSuites)) { + enabledCipherSuites = + sslContext.getDefaultCipherSuiteList(!flag); + } } + roleIsServer = !flag; break;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/ssl/SSLContextImpl/CustomizedCipherSuites.java Tue Mar 27 16:54:03 2018 +0100 @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. + +/* + * @test + * @bug 8162362 + * @summary Cannot enable previously default enabled cipher suites + * @run main/othervm + * CustomizedCipherSuites Default true + * TLS_RSA_WITH_AES_128_CBC_SHA + * SSL_RSA_WITH_DES_CBC_SHA + * @run main/othervm + * -Djdk.tls.client.cipherSuites="unknown" + * CustomizedCipherSuites Default true + * TLS_RSA_WITH_AES_128_CBC_SHA + * SSL_RSA_WITH_DES_CBC_SHA + * @run main/othervm + * -Djdk.tls.client.cipherSuites="" + * CustomizedCipherSuites Default true + * TLS_RSA_WITH_AES_128_CBC_SHA + * SSL_RSA_WITH_DES_CBC_SHA + * @run main/othervm + * -Djdk.tls.client.cipherSuites="SSL_RSA_WITH_DES_CBC_SHA" + * CustomizedCipherSuites Default true + * SSL_RSA_WITH_DES_CBC_SHA + * TLS_RSA_WITH_AES_128_CBC_SHA + * @run main/othervm + * -Djdk.tls.server.cipherSuites="SSL_RSA_WITH_DES_CBC_SHA" + * CustomizedCipherSuites Default false + * SSL_RSA_WITH_DES_CBC_SHA + * TLS_RSA_WITH_AES_128_CBC_SHA + * @run main/othervm + * -Djdk.tls.client.cipherSuites="TLS_RSA_WITH_AES_128_CBC_SHA,unknown,SSL_RSA_WITH_DES_CBC_SHA" + * CustomizedCipherSuites Default true + * SSL_RSA_WITH_DES_CBC_SHA + * "" + * @run main/othervm + * -Djdk.tls.server.cipherSuites="TLS_RSA_WITH_AES_128_CBC_SHA,unknown,SSL_RSA_WITH_DES_CBC_SHA" + * CustomizedCipherSuites Default false + * TLS_RSA_WITH_AES_128_CBC_SHA + * "" + * @run main/othervm + * -Djdk.tls.server.cipherSuites="SSL_RSA_WITH_DES_CBC_SHA" + * CustomizedCipherSuites Default true + * TLS_RSA_WITH_AES_128_CBC_SHA + * SSL_RSA_WITH_DES_CBC_SHA + * @run main/othervm + * -Djdk.tls.client.cipherSuites="SSL_RSA_WITH_DES_CBC_SHA" + * CustomizedCipherSuites Default false + * TLS_RSA_WITH_AES_128_CBC_SHA + * SSL_RSA_WITH_DES_CBC_SHA + */ + +import javax.net.ssl.*; + +/** + * Test the customized default cipher suites. + * + * This test is based on the behavior that SSL_RSA_WITH_DES_CBC_SHA is + * disabled by default, and TLS_RSA_WITH_AES_128_CBC_SHA is enabled by + * default in JDK. If the behavior is changed in the future, please + * update the test cases above accordingly. + */ +public class CustomizedCipherSuites { + + private static String contextProtocol; + private static boolean isClientMode; + + private static String enabledCipherSuite; + private static String disabledCipherSuite; + + public static void main(String[] args) throws Exception { + + contextProtocol = trimQuotes(args[0]); + isClientMode = Boolean.parseBoolean(args[1]); + enabledCipherSuite = trimQuotes(args[2]); + disabledCipherSuite = trimQuotes(args[3]); + + // + // Create instance of SSLContext with the specified protocol. + // + SSLContext context = SSLContext.getInstance(contextProtocol); + + // Default SSLContext is initialized automatically. + if (!contextProtocol.equals("Default")) { + // Use default TK, KM and random. + context.init((KeyManager[])null, (TrustManager[])null, null); + } + + // SSLContext default parameters is client mode in JDK. + if (isClientMode) { + // + // Check default parameters of the specified SSLContext protocol + // + SSLParameters parameters = context.getDefaultSSLParameters(); + System.out.println("Checking SSLContext default parameters ..."); + checkEnabledCiphers(parameters.getCipherSuites()); + } + + // + // Check supported parameters of the specified SSLContext protocol + // + SSLParameters parameters = context.getSupportedSSLParameters(); + System.out.println("Checking SSLContext suppport parameters ..."); + checkSupportedCiphers(parameters.getCipherSuites()); + + + // + // Check the default cipher suites of SSLEngine. + // + SSLEngine engine = context.createSSLEngine(); + engine.setUseClientMode(isClientMode); + + System.out.println("Checking SSLEngine default cipher suites ..."); + checkEnabledCiphers(engine.getEnabledCipherSuites()); + + // + // Check the supported cipher suites of SSLEngine. + // + System.out.println("Checking SSLEngine supported cipher suites ..."); + checkSupportedCiphers(engine.getSupportedCipherSuites()); + + if (isClientMode) { + SSLSocketFactory factory = context.getSocketFactory(); + // Use an unconnected socket. + try (SSLSocket socket = (SSLSocket)factory.createSocket()) { + // + // Check the default cipher suites of SSLSocket. + // + System.out.println( + "Checking SSLSocket default cipher suites ..."); + checkEnabledCiphers(socket.getEnabledCipherSuites()); + + // + // Check the supported cipher suites of SSLSocket. + // + System.out.println( + "Checking SSLSocket supported cipher suites ..."); + checkSupportedCiphers(socket.getSupportedCipherSuites()); + } + } else { + SSLServerSocketFactory factory = context.getServerSocketFactory(); + // Use an unbound server socket. + try (SSLServerSocket socket = + (SSLServerSocket)factory.createServerSocket()) { + // + // Check the default cipher suites of SSLServerSocket. + // + System.out.println( + "Checking SSLServerSocket default cipher suites ..."); + checkEnabledCiphers(socket.getEnabledCipherSuites()); + + // + // Check the supported cipher suites of SSLServerSocket. + // + System.out.println( + "Checking SSLServerSocket supported cipher suites ..."); + checkSupportedCiphers(socket.getSupportedCipherSuites()); + } + } + + System.out.println("\t... Success"); + } + + private static void checkEnabledCiphers( + String[] ciphers) throws Exception { + + if (ciphers.length == 0) { + throw new Exception("No default cipher suites"); + } + + boolean isMatch = false; + if (enabledCipherSuite.isEmpty()) { + // Don't check if not specify the expected cipher suite. + isMatch = true; + } + + boolean isBroken = false; + for (String cipher : ciphers) { + System.out.println("\tdefault cipher suite " + cipher); + if (!enabledCipherSuite.isEmpty() && + cipher.equals(enabledCipherSuite)) { + isMatch = true; + } + + if (!disabledCipherSuite.isEmpty() && + cipher.equals(disabledCipherSuite)) { + isBroken = true; + } + } + + if (!isMatch) { + throw new Exception( + "Cipher suite " + enabledCipherSuite + " should be enabled"); + } + + if (isBroken) { + throw new Exception( + "Cipher suite " + disabledCipherSuite + " should be disabled"); + } + } + + private static void checkSupportedCiphers( + String[] ciphers) throws Exception { + + if (ciphers.length == 0) { + throw new Exception("No supported cipher suites"); + } + + boolean hasEnabledCipherSuite = enabledCipherSuite.isEmpty(); + boolean hasDisabledCipherSuite = disabledCipherSuite.isEmpty(); + for (String cipher : ciphers) { + System.out.println("\tsupported cipher suite " + cipher); + if (!enabledCipherSuite.isEmpty() && + cipher.equals(enabledCipherSuite)) { + hasEnabledCipherSuite = true; + } + + if (!disabledCipherSuite.isEmpty() && + cipher.equals(disabledCipherSuite)) { + hasDisabledCipherSuite = true; + } + } + + if (!hasEnabledCipherSuite) { + throw new Exception( + "Cipher suite " + enabledCipherSuite + " should be supported"); + } + + if (!hasDisabledCipherSuite) { + throw new Exception( + "Cipher suite " + disabledCipherSuite + " should be supported"); + } + } + + private static String trimQuotes(String candidate) { + if (candidate != null && candidate.length() != 0) { + // Remove double quote marks from beginning/end of the string. + if (candidate.length() > 1 && candidate.charAt(0) == '"' && + candidate.charAt(candidate.length() - 1) == '"') { + return candidate.substring(1, candidate.length() - 1); + } + } + + return candidate; + } +}