# HG changeset patch # User pkoppula # Date 1535481523 -3600 # Node ID d3e18948020e1778771da4e0084c3e029d8ab585 # Parent ed17b461784df205b8f81387aa04062de054a918 8208350: Disable all DES cipher suites Reviewed-by: mullan, jnimeh, coffeys diff -r ed17b461784d -r d3e18948020e src/share/lib/security/java.security-linux --- a/src/share/lib/security/java.security-linux Wed Aug 08 00:32:07 2018 -0700 +++ b/src/share/lib/security/java.security-linux Tue Aug 28 19:38:43 2018 +0100 @@ -545,8 +545,8 @@ # # Example: # jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048 -jdk.tls.disabledAlgorithms=SSLv3, DH keySize < 1024, \ - EC keySize < 224, DES40_CBC, RC4_40, 3DES_EDE_CBC +jdk.tls.disabledAlgorithms=SSLv3, DES, DH keySize < 1024, \ + EC keySize < 224, RC4_40, 3DES_EDE_CBC # Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS) # processing in JSSE implementation. diff -r ed17b461784d -r d3e18948020e src/share/lib/security/java.security-solaris --- a/src/share/lib/security/java.security-solaris Wed Aug 08 00:32:07 2018 -0700 +++ b/src/share/lib/security/java.security-solaris Tue Aug 28 19:38:43 2018 +0100 @@ -505,8 +505,8 @@ # # Example: # jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048 -jdk.tls.disabledAlgorithms=SSLv3, DH keySize < 1024, \ - EC keySize < 224, DES40_CBC, RC4_40, 3DES_EDE_CBC +jdk.tls.disabledAlgorithms=SSLv3, DES, DH keySize < 1024, \ + EC keySize < 224, RC4_40, 3DES_EDE_CBC # Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS) # processing in JSSE implementation. diff -r ed17b461784d -r d3e18948020e src/share/lib/security/java.security-windows --- a/src/share/lib/security/java.security-windows Wed Aug 08 00:32:07 2018 -0700 +++ b/src/share/lib/security/java.security-windows Tue Aug 28 19:38:43 2018 +0100 @@ -522,8 +522,8 @@ # # Example: # jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048 -jdk.tls.disabledAlgorithms=SSLv3, DH keySize < 1024, \ - EC keySize < 224, DES40_CBC, RC4_40, 3DES_EDE_CBC +jdk.tls.disabledAlgorithms=SSLv3, DES, DH keySize < 1024, \ + EC keySize < 224, RC4_40, 3DES_EDE_CBC # Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS) # processing in JSSE implementation. diff -r ed17b461784d -r d3e18948020e test/sun/security/ssl/CipherSuite/NoDesRC4CiphSuite.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/ssl/CipherSuite/NoDesRC4CiphSuite.java Tue Aug 28 19:38:43 2018 +0100 @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2018, 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. + */ + +/* + * @test + * @bug 8208350 + * @summary Disable all DES cipher suites + * @run main/othervm NoDesRC4CiphSuite + */ + +/* + * SunJSSE does not support dynamic system properties, no way to re-use + * system properties in samevm/agentvm mode. + */ + +import java.security.Security; +import javax.net.ssl.*; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.GeneralSecurityException; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +public class NoDesRC4CiphSuite { + + private static final boolean DEBUG = false; + + private static final byte RECTYPE_HS = 0x16; + private static final byte HSMSG_CLIHELLO = 0x01; + + // These are some groups of Cipher Suites by names and IDs + private static final List DES_CS_LIST = Arrays.asList( + 0x0009, 0x0015, 0x0012, 0x001A, 0x0008, 0x0014, 0x0011, 0x0019 + ); + private static final String[] DES_CS_LIST_NAMES = new String[] { + "SSL_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_DSS_WITH_DES_CBC_SHA", + "SSL_DH_anon_WITH_DES_CBC_SHA", + "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA" + }; + private static final List RC4_CS_LIST = Arrays.asList( + 0xC007, 0xC011, 0x0005, 0xC002, 0xC00C, 0x0004, 0xC016, 0x0018, + 0x0003, 0x0017 + ); + private static final String[] RC4_CS_LIST_NAMES = new String[] { + "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", + "TLS_ECDHE_RSA_WITH_RC4_128_SHA", + "SSL_RSA_WITH_RC4_128_SHA", + "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", + "TLS_ECDH_RSA_WITH_RC4_128_SHA", + "SSL_RSA_WITH_RC4_128_MD5", + "TLS_ECDH_anon_WITH_RC4_128_SHA", + "SSL_DH_anon_WITH_RC4_128_MD5", + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", + "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5" + }; + + private static final ByteBuffer CLIOUTBUF = + ByteBuffer.wrap("Client Side".getBytes()); + + public static void main(String[] args) throws Exception { + boolean allGood = true; + String disAlg = Security.getProperty("jdk.tls.disabledAlgorithms"); + System.err.println("Disabled Algs: " + disAlg); + + // Disabled DES tests + allGood &= testDefaultCase(DES_CS_LIST); + allGood &= testEngAddDisabled(DES_CS_LIST_NAMES, DES_CS_LIST); + allGood &= testEngOnlyDisabled(DES_CS_LIST_NAMES); + + // Disabled RC4 tests + allGood &= testDefaultCase(RC4_CS_LIST); + allGood &= testEngAddDisabled(RC4_CS_LIST_NAMES, RC4_CS_LIST); + allGood &= testEngOnlyDisabled(RC4_CS_LIST_NAMES); + + if (allGood) { + System.err.println("All tests passed"); + } else { + throw new RuntimeException("One or more tests failed"); + } + } + + /** + * Create an engine with the default set of cipher suites enabled and make + * sure none of the disabled suites are present in the client hello. + * + * @param disabledSuiteIds the {@code List} of disabled cipher suite IDs + * to be checked for. + * + * @return true if the test passed (No disabled suites), false otherwise + */ + private static boolean testDefaultCase(List disabledSuiteIds) + throws Exception { + System.err.println("\nTest: Default SSLEngine suite set"); + SSLEngine ssle = makeEngine(); + if (DEBUG) { + listCiphers("Suite set upon creation", ssle); + } + SSLEngineResult clientResult; + ByteBuffer cTOs = makeClientBuf(ssle); + clientResult = ssle.wrap(CLIOUTBUF, cTOs); + if (DEBUG) { + dumpResult("ClientHello: ", clientResult); + } + cTOs.flip(); + boolean foundSuite = areSuitesPresentCH(cTOs, disabledSuiteIds); + if (foundSuite) { + System.err.println("FAIL: Found disabled suites!"); + return false; + } else { + System.err.println("PASS: No disabled suites found."); + return true; + } + } + + /** + * Create an engine and set only disabled cipher suites. + * The engine should not create the client hello message since the only + * available suites to assert in the client hello are disabled ones. + * + * @param disabledSuiteNames an array of cipher suite names that + * should be disabled cipher suites. + * + * @return true if the engine throws SSLHandshakeException during client + * hello creation, false otherwise. + */ + private static boolean testEngOnlyDisabled(String[] disabledSuiteNames) + throws Exception { + System.err.println( + "\nTest: SSLEngine configured with only disabled suites"); + try { + SSLEngine ssle = makeEngine(); + ssle.setEnabledCipherSuites(disabledSuiteNames); + if (DEBUG) { + listCiphers("Suite set upon creation", ssle); + } + SSLEngineResult clientResult; + ByteBuffer cTOs = makeClientBuf(ssle); + clientResult = ssle.wrap(CLIOUTBUF, cTOs); + if (DEBUG) { + dumpResult("ClientHello: ", clientResult); + } + cTOs.flip(); + } catch (SSLHandshakeException shse) { + System.err.println("PASS: Caught expected exception: " + shse); + return true; + } + System.err.println("FAIL: Expected SSLHandshakeException not thrown"); + return false; + } + + /** + * Create an engine and add some disabled suites to the default + * set of cipher suites. Make sure none of the disabled suites show up + * in the client hello even though they were explicitly added. + * + * @param disabledSuiteNames an array of cipher suite names that + * should be disabled cipher suites. + * @param disabledIds the {@code List} of disabled cipher suite IDs + * to be checked for. + * + * @return true if the test passed (No disabled suites), false otherwise + */ + private static boolean testEngAddDisabled(String[] disabledNames, + List disabledIds) throws Exception { + System.err.println("\nTest: SSLEngine with disabled suites added"); + SSLEngine ssle = makeEngine(); + + // Add disabled suites to the existing engine's set of enabled suites + String[] initialSuites = ssle.getEnabledCipherSuites(); + String[] plusDisSuites = Arrays.copyOf(initialSuites, + initialSuites.length + disabledNames.length); + System.arraycopy(disabledNames, 0, plusDisSuites, + initialSuites.length, disabledNames.length); + ssle.setEnabledCipherSuites(plusDisSuites); + + if (DEBUG) { + listCiphers("Suite set upon creation", ssle); + } + SSLEngineResult clientResult; + ByteBuffer cTOs = makeClientBuf(ssle); + clientResult = ssle.wrap(CLIOUTBUF, cTOs); + if (DEBUG) { + dumpResult("ClientHello: ", clientResult); + } + cTOs.flip(); + boolean foundDisabled = areSuitesPresentCH(cTOs, disabledIds); + if (foundDisabled) { + System.err.println("FAIL: Found disabled suites!"); + return false; + } else { + System.err.println("PASS: No disabled suites found."); + return true; + } + } + + private static SSLEngine makeEngine() throws GeneralSecurityException { + SSLContext ctx = SSLContext.getInstance("TLSv1.2"); + ctx.init(null, null, null); + return ctx.createSSLEngine(); + } + + private static ByteBuffer makeClientBuf(SSLEngine ssle) { + ssle.setUseClientMode(true); + ssle.setNeedClientAuth(false); + SSLSession sess = ssle.getSession(); + ByteBuffer cTOs = ByteBuffer.allocateDirect(sess.getPacketBufferSize()); + return cTOs; + } + + private static void listCiphers(String prefix, SSLEngine ssle) { + System.err.println(prefix + "\n---------------"); + String[] suites = ssle.getEnabledCipherSuites(); + for (String suite : suites) { + System.err.println(suite); + } + System.err.println("---------------"); + } + + /** + * Walk a TLS 1.2 or earlier ClientHello looking for any of the suites + * in the suiteIdList. + * + * @param clientHello a ByteBuffer containing the ClientHello message as + * a complete TLS record. The position of the buffer should be + * at the first byte of the TLS record header. + * @param suiteIdList a List of integer values corresponding to + * TLS cipher suite identifiers. + * + * @return true if at least one of the suites in {@code suiteIdList} + * is found in the ClientHello's cipher suite list + * + * @throws IOException if the data in the {@code clientHello} + * buffer is not a TLS handshake message or is not a client hello. + */ + private static boolean areSuitesPresentCH(ByteBuffer clientHello, + List suiteIdList) throws IOException { + byte val; + + // Process the TLS Record + val = clientHello.get(); + if (val != RECTYPE_HS) { + throw new IOException( + "Not a handshake record, type = " + val); + } + + // Just skip over the version and length + clientHello.position(clientHello.position() + 4); + + // Check the handshake message type + val = clientHello.get(); + if (val != HSMSG_CLIHELLO) { + throw new IOException( + "Not a ClientHello handshake message, type = " + val); + } + + // Skip over the length + clientHello.position(clientHello.position() + 3); + + // Skip over the protocol version (2) and random (32); + clientHello.position(clientHello.position() + 34); + + // Skip past the session ID (variable length <= 32) + int len = Byte.toUnsignedInt(clientHello.get()); + if (len > 32) { + throw new IOException("Session ID is too large, len = " + len); + } + clientHello.position(clientHello.position() + len); + + // Finally, we are at the cipher suites. Walk the list and place them + // into a List. + int csLen = Short.toUnsignedInt(clientHello.getShort()); + if (csLen % 2 != 0) { + throw new IOException("CipherSuite length is invalid, len = " + + csLen); + } + int csCount = csLen / 2; + List csSuiteList = new ArrayList<>(csCount); + log("Found following suite IDs in hello:"); + for (int i = 0; i < csCount; i++) { + int curSuite = Short.toUnsignedInt(clientHello.getShort()); + log(String.format("Suite ID: 0x%04x", curSuite)); + csSuiteList.add(curSuite); + } + + // Now check to see if any of the suites passed in match what is in + // the suite list. + boolean foundMatch = false; + for (Integer cs : suiteIdList) { + if (csSuiteList.contains(cs)) { + System.err.format("Found match for suite ID 0x%04x\n", cs); + foundMatch = true; + break; + } + } + + // We don't care about the rest of the ClientHello message. + // Rewind and return whether we found a match or not. + clientHello.rewind(); + return foundMatch; + } + + private static void dumpResult(String str, SSLEngineResult result) { + System.err.println("The format of the SSLEngineResult is: \n" + + "\t\"getStatus() / getHandshakeStatus()\" +\n" + + "\t\"bytesConsumed() / bytesProduced()\"\n"); + HandshakeStatus hsStatus = result.getHandshakeStatus(); + System.err.println(str + result.getStatus() + "/" + hsStatus + ", " + + result.bytesConsumed() + "/" + result.bytesProduced() + " bytes"); + if (hsStatus == HandshakeStatus.FINISHED) { + System.err.println("\t...ready for application data"); + } + } + + private static void log(String str) { + if (DEBUG) { + System.err.println(str); + } + } +}