Path: blob/master/test/jdk/sun/security/ssl/CipherSuite/NoDesRC4CiphSuite.java
41152 views
/*1* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 820835026* @summary Disable all DES cipher suites27* @run main/othervm NoDesRC4CiphSuite28*/2930/*31* SunJSSE does not support dynamic system properties, no way to re-use32* system properties in samevm/agentvm mode.33*/3435import java.security.Security;36import javax.net.ssl.*;37import javax.net.ssl.SSLEngineResult.HandshakeStatus;38import java.io.IOException;39import java.nio.ByteBuffer;40import java.security.GeneralSecurityException;41import java.util.List;42import java.util.ArrayList;43import java.util.Arrays;4445public class NoDesRC4CiphSuite {4647private static final boolean DEBUG = false;4849private static final byte RECTYPE_HS = 0x16;50private static final byte HSMSG_CLIHELLO = 0x01;5152// These are some groups of Cipher Suites by names and IDs53private static final List<Integer> DES_CS_LIST = Arrays.asList(540x0009, 0x0015, 0x0012, 0x001A, 0x0008, 0x0014, 0x0011, 0x001955);56private static final String[] DES_CS_LIST_NAMES = new String[] {57"SSL_RSA_WITH_DES_CBC_SHA",58"SSL_DHE_RSA_WITH_DES_CBC_SHA",59"SSL_DHE_DSS_WITH_DES_CBC_SHA",60"SSL_DH_anon_WITH_DES_CBC_SHA",61"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",62"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",63"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",64"SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"65};66private static final List<Integer> RC4_CS_LIST = Arrays.asList(670xC007, 0xC011, 0x0005, 0xC002, 0xC00C, 0x0004, 0xC016, 0x0018,680x0003, 0x001769);70private static final String[] RC4_CS_LIST_NAMES = new String[] {71"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",72"TLS_ECDHE_RSA_WITH_RC4_128_SHA",73"SSL_RSA_WITH_RC4_128_SHA",74"TLS_ECDH_ECDSA_WITH_RC4_128_SHA",75"TLS_ECDH_RSA_WITH_RC4_128_SHA",76"SSL_RSA_WITH_RC4_128_MD5",77"TLS_ECDH_anon_WITH_RC4_128_SHA",78"SSL_DH_anon_WITH_RC4_128_MD5",79"SSL_RSA_EXPORT_WITH_RC4_40_MD5",80"SSL_DH_anon_EXPORT_WITH_RC4_40_MD5"81};8283private static final ByteBuffer CLIOUTBUF =84ByteBuffer.wrap("Client Side".getBytes());8586public static void main(String[] args) throws Exception {87boolean allGood = true;88String disAlg = Security.getProperty("jdk.tls.disabledAlgorithms");89System.err.println("Disabled Algs: " + disAlg);9091// Disabled DES tests92allGood &= testDefaultCase(DES_CS_LIST);93allGood &= testEngAddDisabled(DES_CS_LIST_NAMES, DES_CS_LIST);94allGood &= testEngOnlyDisabled(DES_CS_LIST_NAMES);9596// Disabled RC4 tests97allGood &= testDefaultCase(RC4_CS_LIST);98allGood &= testEngAddDisabled(RC4_CS_LIST_NAMES, RC4_CS_LIST);99allGood &= testEngOnlyDisabled(RC4_CS_LIST_NAMES);100101if (allGood) {102System.err.println("All tests passed");103} else {104throw new RuntimeException("One or more tests failed");105}106}107108/**109* Create an engine with the default set of cipher suites enabled and make110* sure none of the disabled suites are present in the client hello.111*112* @param disabledSuiteIds the {@code List} of disabled cipher suite IDs113* to be checked for.114*115* @return true if the test passed (No disabled suites), false otherwise116*/117private static boolean testDefaultCase(List<Integer> disabledSuiteIds)118throws Exception {119System.err.println("\nTest: Default SSLEngine suite set");120SSLEngine ssle = makeEngine();121if (DEBUG) {122listCiphers("Suite set upon creation", ssle);123}124SSLEngineResult clientResult;125ByteBuffer cTOs = makeClientBuf(ssle);126clientResult = ssle.wrap(CLIOUTBUF, cTOs);127if (DEBUG) {128dumpResult("ClientHello: ", clientResult);129}130cTOs.flip();131boolean foundSuite = areSuitesPresentCH(cTOs, disabledSuiteIds);132if (foundSuite) {133System.err.println("FAIL: Found disabled suites!");134return false;135} else {136System.err.println("PASS: No disabled suites found.");137return true;138}139}140141/**142* Create an engine and set only disabled cipher suites.143* The engine should not create the client hello message since the only144* available suites to assert in the client hello are disabled ones.145*146* @param disabledSuiteNames an array of cipher suite names that147* should be disabled cipher suites.148*149* @return true if the engine throws SSLHandshakeException during client150* hello creation, false otherwise.151*/152private static boolean testEngOnlyDisabled(String[] disabledSuiteNames)153throws Exception {154System.err.println(155"\nTest: SSLEngine configured with only disabled suites");156try {157SSLEngine ssle = makeEngine();158ssle.setEnabledCipherSuites(disabledSuiteNames);159if (DEBUG) {160listCiphers("Suite set upon creation", ssle);161}162SSLEngineResult clientResult;163ByteBuffer cTOs = makeClientBuf(ssle);164clientResult = ssle.wrap(CLIOUTBUF, cTOs);165if (DEBUG) {166dumpResult("ClientHello: ", clientResult);167}168cTOs.flip();169} catch (SSLHandshakeException shse) {170System.err.println("PASS: Caught expected exception: " + shse);171return true;172}173System.err.println("FAIL: Expected SSLHandshakeException not thrown");174return false;175}176177/**178* Create an engine and add some disabled suites to the default179* set of cipher suites. Make sure none of the disabled suites show up180* in the client hello even though they were explicitly added.181*182* @param disabledSuiteNames an array of cipher suite names that183* should be disabled cipher suites.184* @param disabledIds the {@code List} of disabled cipher suite IDs185* to be checked for.186*187* @return true if the test passed (No disabled suites), false otherwise188*/189private static boolean testEngAddDisabled(String[] disabledNames,190List<Integer> disabledIds) throws Exception {191System.err.println("\nTest: SSLEngine with disabled suites added");192SSLEngine ssle = makeEngine();193194// Add disabled suites to the existing engine's set of enabled suites195String[] initialSuites = ssle.getEnabledCipherSuites();196String[] plusDisSuites = Arrays.copyOf(initialSuites,197initialSuites.length + disabledNames.length);198System.arraycopy(disabledNames, 0, plusDisSuites,199initialSuites.length, disabledNames.length);200ssle.setEnabledCipherSuites(plusDisSuites);201202if (DEBUG) {203listCiphers("Suite set upon creation", ssle);204}205SSLEngineResult clientResult;206ByteBuffer cTOs = makeClientBuf(ssle);207clientResult = ssle.wrap(CLIOUTBUF, cTOs);208if (DEBUG) {209dumpResult("ClientHello: ", clientResult);210}211cTOs.flip();212boolean foundDisabled = areSuitesPresentCH(cTOs, disabledIds);213if (foundDisabled) {214System.err.println("FAIL: Found disabled suites!");215return false;216} else {217System.err.println("PASS: No disabled suites found.");218return true;219}220}221222private static SSLEngine makeEngine() throws GeneralSecurityException {223SSLContext ctx = SSLContext.getInstance("TLSv1.2");224ctx.init(null, null, null);225return ctx.createSSLEngine();226}227228private static ByteBuffer makeClientBuf(SSLEngine ssle) {229ssle.setUseClientMode(true);230ssle.setNeedClientAuth(false);231SSLSession sess = ssle.getSession();232ByteBuffer cTOs = ByteBuffer.allocateDirect(sess.getPacketBufferSize());233return cTOs;234}235236private static void listCiphers(String prefix, SSLEngine ssle) {237System.err.println(prefix + "\n---------------");238String[] suites = ssle.getEnabledCipherSuites();239for (String suite : suites) {240System.err.println(suite);241}242System.err.println("---------------");243}244245/**246* Walk a TLS 1.2 or earlier ClientHello looking for any of the suites247* in the suiteIdList.248*249* @param clientHello a ByteBuffer containing the ClientHello message as250* a complete TLS record. The position of the buffer should be251* at the first byte of the TLS record header.252* @param suiteIdList a List of integer values corresponding to253* TLS cipher suite identifiers.254*255* @return true if at least one of the suites in {@code suiteIdList}256* is found in the ClientHello's cipher suite list257*258* @throws IOException if the data in the {@code clientHello}259* buffer is not a TLS handshake message or is not a client hello.260*/261private static boolean areSuitesPresentCH(ByteBuffer clientHello,262List<Integer> suiteIdList) throws IOException {263byte val;264265// Process the TLS Record266val = clientHello.get();267if (val != RECTYPE_HS) {268throw new IOException(269"Not a handshake record, type = " + val);270}271272// Just skip over the version and length273clientHello.position(clientHello.position() + 4);274275// Check the handshake message type276val = clientHello.get();277if (val != HSMSG_CLIHELLO) {278throw new IOException(279"Not a ClientHello handshake message, type = " + val);280}281282// Skip over the length283clientHello.position(clientHello.position() + 3);284285// Skip over the protocol version (2) and random (32);286clientHello.position(clientHello.position() + 34);287288// Skip past the session ID (variable length <= 32)289int len = Byte.toUnsignedInt(clientHello.get());290if (len > 32) {291throw new IOException("Session ID is too large, len = " + len);292}293clientHello.position(clientHello.position() + len);294295// Finally, we are at the cipher suites. Walk the list and place them296// into a List.297int csLen = Short.toUnsignedInt(clientHello.getShort());298if (csLen % 2 != 0) {299throw new IOException("CipherSuite length is invalid, len = " +300csLen);301}302int csCount = csLen / 2;303List<Integer> csSuiteList = new ArrayList<>(csCount);304log("Found following suite IDs in hello:");305for (int i = 0; i < csCount; i++) {306int curSuite = Short.toUnsignedInt(clientHello.getShort());307log(String.format("Suite ID: 0x%04x", curSuite));308csSuiteList.add(curSuite);309}310311// Now check to see if any of the suites passed in match what is in312// the suite list.313boolean foundMatch = false;314for (Integer cs : suiteIdList) {315if (csSuiteList.contains(cs)) {316System.err.format("Found match for suite ID 0x%04x\n", cs);317foundMatch = true;318break;319}320}321322// We don't care about the rest of the ClientHello message.323// Rewind and return whether we found a match or not.324clientHello.rewind();325return foundMatch;326}327328private static void dumpResult(String str, SSLEngineResult result) {329System.err.println("The format of the SSLEngineResult is: \n" +330"\t\"getStatus() / getHandshakeStatus()\" +\n" +331"\t\"bytesConsumed() / bytesProduced()\"\n");332HandshakeStatus hsStatus = result.getHandshakeStatus();333System.err.println(str + result.getStatus() + "/" + hsStatus + ", " +334result.bytesConsumed() + "/" + result.bytesProduced() + " bytes");335if (hsStatus == HandshakeStatus.FINISHED) {336System.err.println("\t...ready for application data");337}338}339340private static void log(String str) {341if (DEBUG) {342System.err.println(str);343}344}345}346347348