/* * Copyright (c) 2015, 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. */ /* * @test * @bug 8076221 * @summary Check if weak cipher suites are disabled * @modules jdk.crypto.ec * @run main/othervm DisabledAlgorithms default * @run main/othervm DisabledAlgorithms empty */ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.NoSuchAlgorithmException; import java.security.Security; import java.util.concurrent.TimeUnit; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; public class DisabledAlgorithms { private static final String pathToStores = "../etc"; private static final String keyStoreFile = "keystore"; private static final String trustStoreFile = "truststore"; private static final String passwd = "passphrase"; private static final String keyFilename = System.getProperty("test.src", "./") + "/" + pathToStores + "/" + keyStoreFile; private static final String trustFilename = System.getProperty("test.src", "./") + "/" + pathToStores + "/" + trustStoreFile; // supported RC4 cipher suites // it does not contain KRB5 cipher suites because they need a KDC private static final String[] rc4_ciphersuites = 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" }; public static void main(String[] args) throws Exception { if (args.length < 1) { throw new RuntimeException("No parameters specified"); } System.setProperty("javax.net.ssl.keyStore", keyFilename); System.setProperty("javax.net.ssl.keyStorePassword", passwd); System.setProperty("javax.net.ssl.trustStore", trustFilename); System.setProperty("javax.net.ssl.trustStorePassword", passwd); switch (args[0]) { case "default": // use default jdk.tls.disabledAlgorithms System.out.println("jdk.tls.disabledAlgorithms = " + Security.getProperty("jdk.tls.disabledAlgorithms")); // check if RC4 cipher suites can't be used by default checkFailure(rc4_ciphersuites); break; case "empty": // reset jdk.tls.disabledAlgorithms Security.setProperty("jdk.tls.disabledAlgorithms", ""); System.out.println("jdk.tls.disabledAlgorithms = " + Security.getProperty("jdk.tls.disabledAlgorithms")); // check if RC4 cipher suites can be used // if jdk.tls.disabledAlgorithms is empty checkSuccess(rc4_ciphersuites); break; default: throw new RuntimeException("Wrong parameter: " + args[0]); } System.out.println("Test passed"); } /* * Checks if that specified cipher suites cannot be used. */ private static void checkFailure(String[] ciphersuites) throws Exception { try (SSLServer server = SSLServer.init(ciphersuites)) { startNewThread(server); while (!server.isRunning()) { sleep(); } int port = server.getPort(); for (String ciphersuite : ciphersuites) { try (SSLClient client = SSLClient.init(port, ciphersuite)) { client.connect(); throw new RuntimeException("Expected SSLHandshakeException " + "not thrown"); } catch (SSLHandshakeException e) { System.out.println("Expected exception on client side: " + e); } } while (server.isRunning()) { sleep(); } if (!server.sslError()) { throw new RuntimeException("Expected SSL exception " + "not thrown on server side"); } } } /* * Checks if specified cipher suites can be used. */ private static void checkSuccess(String[] ciphersuites) throws Exception { try (SSLServer server = SSLServer.init(ciphersuites)) { startNewThread(server); while (!server.isRunning()) { sleep(); } int port = server.getPort(); for (String ciphersuite : ciphersuites) { try (SSLClient client = SSLClient.init(port, ciphersuite)) { client.connect(); String negotiated = client.getNegotiatedCipherSuite(); System.out.println("Negotiated cipher suite: " + negotiated); if (!negotiated.equals(ciphersuite)) { throw new RuntimeException("Unexpected cipher suite: " + negotiated); } } } server.stop(); while (server.isRunning()) { sleep(); } if (server.error()) { throw new RuntimeException("Unexpected error on server side"); } } } private static Thread startNewThread(SSLServer server) { Thread serverThread = new Thread(server, "SSL server thread"); serverThread.setDaemon(true); serverThread.start(); return serverThread; } private static void sleep() { try { TimeUnit.MILLISECONDS.sleep(50); } catch (InterruptedException e) { // do nothing } } static class SSLServer implements Runnable, AutoCloseable { private final SSLServerSocket ssocket; private volatile boolean stopped = false; private volatile boolean running = false; private volatile boolean sslError = false; private volatile boolean otherError = false; private SSLServer(SSLServerSocket ssocket) { this.ssocket = ssocket; } @Override public void run() { System.out.println("Server: started"); running = true; while (!stopped) { try (SSLSocket socket = (SSLSocket) ssocket.accept()) { System.out.println("Server: accepted client connection"); InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); int b = in.read(); if (b < 0) { throw new IOException("Unexpected EOF"); } System.out.println("Server: send data: " + b); out.write(b); out.flush(); socket.getSession().invalidate(); } catch (SSLHandshakeException e) { System.out.println("Server: run: " + e); sslError = true; stopped = true; } catch (IOException e) { if (!stopped) { System.out.println("Server: run: unexpected exception: " + e); e.printStackTrace(); otherError = true; stopped = true; } else { System.out.println("Server: run: " + e); System.out.println("The exception above occurred " + "because socket was closed, " + "please ignore it"); } } } System.out.println("Server: finished"); running = false; } int getPort() { return ssocket.getLocalPort(); } String[] getEnabledCiperSuites() { return ssocket.getEnabledCipherSuites(); } boolean isRunning() { return running; } boolean sslError() { return sslError; } boolean error() { return sslError || otherError; } void stop() { stopped = true; if (!ssocket.isClosed()) { try { System.out.println("Server: close socket"); ssocket.close(); } catch (IOException e) { System.out.println("Server: close: " + e); } } } @Override public void close() { stop(); } static SSLServer init(String[] ciphersuites) throws IOException { SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); SSLServerSocket ssocket = (SSLServerSocket) ssf.createServerSocket(0); if (ciphersuites != null) { System.out.println("Server: enable cipher suites: " + java.util.Arrays.toString(ciphersuites)); ssocket.setEnabledCipherSuites(ciphersuites); } return new SSLServer(ssocket); } } static class SSLClient implements AutoCloseable { private final SSLSocket socket; private SSLClient(SSLSocket socket) { this.socket = socket; } void connect() throws IOException { System.out.println("Client: connect to server"); try ( BufferedInputStream bis = new BufferedInputStream( socket.getInputStream()); BufferedOutputStream bos = new BufferedOutputStream( socket.getOutputStream())) { bos.write('x'); bos.flush(); int read = bis.read(); if (read < 0) { throw new IOException("Client: couldn't read a response"); } socket.getSession().invalidate(); } } String[] getEnabledCiperSuites() { return socket.getEnabledCipherSuites(); } String getNegotiatedCipherSuite() { return socket.getSession().getCipherSuite(); } @Override public void close() throws Exception { if (!socket.isClosed()) { try { socket.close(); } catch (IOException e) { System.out.println("Client: close: " + e); } } } static SSLClient init(int port) throws NoSuchAlgorithmException, IOException { return init(port, null); } static SSLClient init(int port, String ciphersuite) throws NoSuchAlgorithmException, IOException { SSLContext context = SSLContext.getDefault(); SSLSocketFactory ssf = (SSLSocketFactory) context.getSocketFactory(); SSLSocket socket = (SSLSocket) ssf.createSocket("localhost", port); if (ciphersuite != null) { System.out.println("Client: enable cipher suite: " + ciphersuite); socket.setEnabledCipherSuites(new String[] { ciphersuite }); } return new SSLClient(socket); } } }