1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.BufferedInputStream; 25 import java.io.BufferedOutputStream; 26 import java.io.IOException; 27 import java.io.InputStream; 28 import java.io.OutputStream; 29 import java.security.NoSuchAlgorithmException; 30 import java.security.Security; 31 import java.util.concurrent.TimeUnit; 32 import javax.net.ssl.SSLContext; 33 import javax.net.ssl.SSLHandshakeException; 34 import javax.net.ssl.SSLServerSocket; 35 import javax.net.ssl.SSLServerSocketFactory; 36 import javax.net.ssl.SSLSocket; 37 import javax.net.ssl.SSLSocketFactory; 38 39 /** 40 * @test 41 * @bug 8076221 42 * @summary Check if weak cipher suites are disabled 43 * @run main/othervm DisabledAlgorithms default 44 * @run main/othervm DisabledAlgorithms empty 45 */ 46 public class DisabledAlgorithms { 47 48 private static final String pathToStores = "../etc"; 49 private static final String keyStoreFile = "keystore"; 50 private static final String trustStoreFile = "truststore"; 51 private static final String passwd = "passphrase"; 52 53 private static final String keyFilename = 54 System.getProperty("test.src", "./") + "/" + pathToStores + 55 "/" + keyStoreFile; 56 57 private static final String trustFilename = 58 System.getProperty("test.src", "./") + "/" + pathToStores + 59 "/" + trustStoreFile; 60 61 // supported RC4 cipher suites 62 // it does not contain KRB5 cipher suites because they need a KDC 63 private static final String[] rc4_ciphersuites = new String[] { 64 "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 65 "TLS_ECDHE_RSA_WITH_RC4_128_SHA", 66 "SSL_RSA_WITH_RC4_128_SHA", 67 "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", 68 "TLS_ECDH_RSA_WITH_RC4_128_SHA", 69 "SSL_RSA_WITH_RC4_128_MD5", 70 "TLS_ECDH_anon_WITH_RC4_128_SHA", 71 "SSL_DH_anon_WITH_RC4_128_MD5" 72 }; 73 74 public static void main(String[] args) throws Exception { 75 if (args.length < 1) { 76 throw new RuntimeException("No parameters specified"); 77 } 78 79 System.setProperty("javax.net.ssl.keyStore", keyFilename); 80 System.setProperty("javax.net.ssl.keyStorePassword", passwd); 81 System.setProperty("javax.net.ssl.trustStore", trustFilename); 82 System.setProperty("javax.net.ssl.trustStorePassword", passwd); 83 84 switch (args[0]) { 85 case "default": 86 // use default jdk.tls.disabledAlgorithms 87 System.out.println("jdk.tls.disabledAlgorithms = " 88 + Security.getProperty("jdk.tls.disabledAlgorithms")); 89 90 // check if RC4 cipher suites can't be used by default 91 checkFailure(rc4_ciphersuites); 92 break; 93 case "empty": 94 // reset jdk.tls.disabledAlgorithms 95 Security.setProperty("jdk.tls.disabledAlgorithms", ""); 96 System.out.println("jdk.tls.disabledAlgorithms = " 97 + Security.getProperty("jdk.tls.disabledAlgorithms")); 98 99 // check if RC4 cipher suites can be used 100 // if jdk.tls.disabledAlgorithms is empty 101 checkSuccess(rc4_ciphersuites); 102 break; 103 default: 104 throw new RuntimeException("Wrong parameter: " + args[0]); 105 } 106 107 System.out.println("Test passed"); 108 } 109 110 /* 111 * Checks if that specified cipher suites cannot be used. 112 */ 113 private static void checkFailure(String[] ciphersuites) throws Exception { 114 try (SSLServer server = SSLServer.init(ciphersuites)) { 115 startNewThread(server); 116 while (!server.isRunning()) { 117 sleep(); 118 } 119 120 int port = server.getPort(); 121 for (String ciphersuite : ciphersuites) { 122 try (SSLClient client = SSLClient.init(port, ciphersuite)) { 123 client.connect(); 124 throw new RuntimeException("Expected SSLHandshakeException " 125 + "not thrown"); 126 } catch (SSLHandshakeException e) { 127 System.out.println("Expected exception on client side: " 128 + e); 129 } 130 } 131 132 while (server.isRunning()) { 133 sleep(); 134 } 135 136 if (!server.sslError()) { 137 throw new RuntimeException("Expected SSL exception " 138 + "not thrown on server side"); 139 } 140 } 141 142 } 143 144 /* 145 * Checks if specified cipher suites can be used. 146 */ 147 private static void checkSuccess(String[] ciphersuites) throws Exception { 148 try (SSLServer server = SSLServer.init(ciphersuites)) { 149 startNewThread(server); 150 while (!server.isRunning()) { 151 sleep(); 152 } 153 154 int port = server.getPort(); 155 for (String ciphersuite : ciphersuites) { 156 try (SSLClient client = SSLClient.init(port, ciphersuite)) { 157 client.connect(); 158 String negotiated = client.getNegotiatedCipherSuite(); 159 System.out.println("Negotiated cipher suite: " 160 + negotiated); 161 if (!negotiated.equals(ciphersuite)) { 162 throw new RuntimeException("Unexpected cipher suite: " 163 + negotiated); 164 } 165 } 166 } 167 168 server.stop(); 169 while (server.isRunning()) { 170 sleep(); 171 } 172 173 if (server.error()) { 174 throw new RuntimeException("Unexpected error on server side"); 175 } 176 } 177 178 } 179 180 private static Thread startNewThread(SSLServer server) { 181 Thread serverThread = new Thread(server, "SSL server thread"); 182 serverThread.setDaemon(true); 183 serverThread.start(); 184 return serverThread; 185 } 186 187 private static void sleep() { 188 try { 189 TimeUnit.MILLISECONDS.sleep(50); 190 } catch (InterruptedException e) { 191 // do nothing 192 } 193 } 194 195 static class SSLServer implements Runnable, AutoCloseable { 196 197 private final SSLServerSocket ssocket; 198 private volatile boolean stopped = false; 199 private volatile boolean running = false; 200 private volatile boolean sslError = false; 201 private volatile boolean otherError = false; 202 203 private SSLServer(SSLServerSocket ssocket) { 204 this.ssocket = ssocket; 205 } 206 207 @Override 208 public void run() { 209 System.out.println("Server: started"); 210 running = true; 211 while (!stopped) { 212 try (SSLSocket socket = (SSLSocket) ssocket.accept()) { 213 System.out.println("Server: accepted client connection"); 214 InputStream in = socket.getInputStream(); 215 OutputStream out = socket.getOutputStream(); 216 int b = in.read(); 217 if (b < 0) { 218 throw new IOException("Unexpected EOF"); 219 } 220 System.out.println("Server: send data: " + b); 221 out.write(b); 222 out.flush(); 223 socket.getSession().invalidate(); 224 } catch (SSLHandshakeException e) { 225 System.out.println("Server: run: " + e); 226 sslError = true; 227 stopped = true; 228 } catch (IOException e) { 229 if (!stopped) { 230 System.out.println("Server: run: unexpected exception: " 231 + e); 232 e.printStackTrace(); 233 otherError = true; 234 stopped = true; 235 } else { 236 System.out.println("Server: run: " + e); 237 System.out.println("The exception above occurred " 238 + "because socket was closed, " 239 + "please ignore it"); 240 } 241 } 242 } 243 244 System.out.println("Server: finished"); 245 running = false; 246 } 247 248 int getPort() { 249 return ssocket.getLocalPort(); 250 } 251 252 String[] getEnabledCiperSuites() { 253 return ssocket.getEnabledCipherSuites(); 254 } 255 256 boolean isRunning() { 257 return running; 258 } 259 260 boolean sslError() { 261 return sslError; 262 } 263 264 boolean error() { 265 return sslError || otherError; 266 } 267 268 void stop() { 269 stopped = true; 270 if (!ssocket.isClosed()) { 271 try { 272 System.out.println("Server: close socket"); 273 ssocket.close(); 274 } catch (IOException e) { 275 System.out.println("Server: close: " + e); 276 } 277 } 278 } 279 280 @Override 281 public void close() { 282 stop(); 283 } 284 285 static SSLServer init(String[] ciphersuites) 286 throws IOException { 287 SSLServerSocketFactory ssf = (SSLServerSocketFactory) 288 SSLServerSocketFactory.getDefault(); 289 SSLServerSocket ssocket = (SSLServerSocket) 290 ssf.createServerSocket(0); 291 292 if (ciphersuites != null) { 293 System.out.println("Server: enable cipher suites: " 294 + java.util.Arrays.toString(ciphersuites)); 295 ssocket.setEnabledCipherSuites(ciphersuites); 296 } 297 298 return new SSLServer(ssocket); 299 } 300 } 301 302 static class SSLClient implements AutoCloseable { 303 304 private final SSLSocket socket; 305 306 private SSLClient(SSLSocket socket) { 307 this.socket = socket; 308 } 309 310 void connect() throws IOException { 311 System.out.println("Client: connect to server"); 312 try ( 313 BufferedInputStream bis = new BufferedInputStream( 314 socket.getInputStream()); 315 BufferedOutputStream bos = new BufferedOutputStream( 316 socket.getOutputStream())) { 317 bos.write('x'); 318 bos.flush(); 319 320 int read = bis.read(); 321 if (read < 0) { 322 throw new IOException("Client: couldn't read a response"); 323 } 324 socket.getSession().invalidate(); 325 } 326 } 327 328 String[] getEnabledCiperSuites() { 329 return socket.getEnabledCipherSuites(); 330 } 331 332 String getNegotiatedCipherSuite() { 333 return socket.getSession().getCipherSuite(); 334 } 335 336 @Override 337 public void close() throws Exception { 338 if (!socket.isClosed()) { 339 try { 340 socket.close(); 341 } catch (IOException e) { 342 System.out.println("Client: close: " + e); 343 } 344 } 345 } 346 347 static SSLClient init(int port) 348 throws NoSuchAlgorithmException, IOException { 349 return init(port, null); 350 } 351 352 static SSLClient init(int port, String ciphersuite) 353 throws NoSuchAlgorithmException, IOException { 354 SSLContext context = SSLContext.getDefault(); 355 SSLSocketFactory ssf = (SSLSocketFactory) 356 context.getSocketFactory(); 357 SSLSocket socket = (SSLSocket) ssf.createSocket("localhost", port); 358 359 if (ciphersuite != null) { 360 System.out.println("Client: enable cipher suite: " 361 + ciphersuite); 362 socket.setEnabledCipherSuites(new String[] { ciphersuite }); 363 } 364 365 return new SSLClient(socket); 366 } 367 368 } 369 370 371 }