SSLSocketTemplate.java revision 16082:fefec228bb68
1/* 2 * Copyright (c) 2001, 2016, 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 24import java.io.FileInputStream; 25import java.io.IOException; 26import java.io.InputStream; 27import java.io.OutputStream; 28import java.net.InetSocketAddress; 29import java.net.SocketTimeoutException; 30import java.security.KeyStore; 31import java.security.Security; 32import java.util.concurrent.CountDownLatch; 33import java.util.concurrent.TimeUnit; 34import javax.net.ssl.SSLContext; 35import javax.net.ssl.SSLServerSocket; 36import javax.net.ssl.SSLServerSocketFactory; 37import javax.net.ssl.SSLSocket; 38import javax.net.ssl.SSLSocketFactory; 39 40/** 41 * This class defines a framework for JSSE tests. 42 * 43 * Please run in othervm mode. SunJSSE does not support dynamic system 44 * properties, no way to re-use system properties in samevm/agentvm mode. 45 */ 46 47/* 48 * @test 49 * @bug 1234567 50 * @summary Use this class for JSSE tests 51 * @run main/othervm SSLSocketTemplate 52 * @author Brad Wetmore 53 */ 54 55public class SSLSocketTemplate { 56 57 public static final String TEST_SRC = System.getProperty("test.src", "."); 58 59 /* 60 * Where do we find the keystores? 61 */ 62 public static final String PATH_TO_STORES = "../etc"; 63 public static final String KEY_STORE_FILE = "keystore"; 64 public static final String TRUST_STORE_FILE = "truststore"; 65 public static final String PASSWORD = "passphrase"; 66 67 public static final int FREE_PORT = 0; 68 69 // in seconds 70 public static final long CLIENT_SIGNAL_TIMEOUT = 30L; 71 public static final long SERVER_SIGNAL_TIMEOUT = 90L; 72 73 // in millis 74 public static final int CLIENT_TIMEOUT = 15000; 75 public static final int SERVER_TIMEOUT = 30000; 76 77 /* 78 * Should we run the client or server in a separate thread? 79 * Both sides can throw exceptions, but do you have a preference 80 * as to which side should be the main thread. 81 */ 82 private boolean separateServerThread = false; 83 84 /* 85 * What's the server port? Use any free port by default 86 */ 87 private volatile int serverPort; 88 89 private volatile Exception serverException; 90 private volatile Exception clientException; 91 92 private Thread clientThread; 93 private Thread serverThread; 94 95 private Peer serverPeer; 96 private Peer clientPeer; 97 98 private Application serverApplication; 99 private Application clientApplication; 100 101 private SSLContext context; 102 103 /* 104 * Is the server ready to serve? 105 */ 106 private final CountDownLatch serverReadyCondition = new CountDownLatch(1); 107 108 /* 109 * Is the client ready to handshake? 110 */ 111 private final CountDownLatch clientReadyCondition = new CountDownLatch(1); 112 113 /* 114 * Is the server done? 115 */ 116 private final CountDownLatch serverDoneCondition = new CountDownLatch(1); 117 118 /* 119 * Is the client done? 120 */ 121 private final CountDownLatch clientDoneCondition = new CountDownLatch(1); 122 123 /* 124 * Public API. 125 */ 126 127 public static interface Peer { 128 void run(SSLSocketTemplate test) throws Exception; 129 } 130 131 public static interface Application { 132 void run(SSLSocket socket, SSLSocketTemplate test) throws Exception; 133 } 134 135 public static void debug() { 136 debug("ssl"); 137 } 138 139 public static void debug(String mode) { 140 System.setProperty("javax.net.debug", mode); 141 } 142 143 public static void setup(String keyFilename, String trustFilename, 144 String password) { 145 146 System.setProperty("javax.net.ssl.keyStore", keyFilename); 147 System.setProperty("javax.net.ssl.keyStorePassword", password); 148 System.setProperty("javax.net.ssl.trustStore", trustFilename); 149 System.setProperty("javax.net.ssl.trustStorePassword", password); 150 } 151 152 public static void setup() throws Exception { 153 String keyFilename = TEST_SRC + "/" + PATH_TO_STORES + "/" 154 + KEY_STORE_FILE; 155 String trustFilename = TEST_SRC + "/" + PATH_TO_STORES + "/" 156 + TRUST_STORE_FILE; 157 158 setup(keyFilename, trustFilename, PASSWORD); 159 } 160 161 public static void print(String message, Throwable... errors) { 162 synchronized (System.out) { 163 System.out.println(message); 164 for (Throwable e : errors) { 165 e.printStackTrace(System.out); 166 } 167 } 168 } 169 170 public static KeyStore loadJksKeyStore(String filename, String password) 171 throws Exception { 172 173 return loadKeyStore(filename, password, "JKS"); 174 } 175 176 public static KeyStore loadKeyStore(String filename, String password, 177 String type) throws Exception { 178 179 KeyStore keystore = KeyStore.getInstance(type); 180 FileInputStream fis = new FileInputStream(filename); 181 try { 182 keystore.load(fis, password.toCharArray()); 183 } finally { 184 fis.close(); 185 } 186 return keystore; 187 } 188 189 // Try to accept a connection in 30 seconds. 190 public static SSLSocket accept(SSLServerSocket sslServerSocket) 191 throws IOException { 192 193 return accept(sslServerSocket, SERVER_TIMEOUT); 194 } 195 196 public static SSLSocket accept(SSLServerSocket sslServerSocket, int timeout) 197 throws IOException { 198 199 try { 200 sslServerSocket.setSoTimeout(timeout); 201 return (SSLSocket) sslServerSocket.accept(); 202 } catch (SocketTimeoutException ste) { 203 print("Warning: ", ste); 204 return null; 205 } 206 } 207 208 public SSLSocketTemplate setSeparateServerThread( 209 boolean separateServerThread) { 210 211 this.separateServerThread = separateServerThread; 212 return this; 213 } 214 215 public SSLSocketTemplate setServerPort(int serverPort) { 216 this.serverPort = serverPort; 217 return this; 218 } 219 220 public int getServerPort() { 221 return serverPort; 222 } 223 224 public SSLSocketTemplate setSSLContext(SSLContext context) { 225 this.context = context; 226 return this; 227 } 228 229 public SSLContext getSSLContext() { 230 return context; 231 } 232 233 public SSLServerSocketFactory getSSLServerSocketFactory() { 234 if (context != null) { 235 return context.getServerSocketFactory(); 236 } 237 238 return (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); 239 } 240 241 public SSLSocketFactory getSSLSocketFactory() { 242 if (context != null) { 243 return context.getSocketFactory(); 244 } 245 246 return (SSLSocketFactory) SSLSocketFactory.getDefault(); 247 } 248 249 public void signalServerReady() { 250 serverReadyCondition.countDown(); 251 } 252 253 public void signalServerDone() { 254 serverDoneCondition.countDown(); 255 } 256 257 public boolean waitForClientSignal(long timeout, TimeUnit unit) 258 throws InterruptedException { 259 260 return clientReadyCondition.await(timeout, unit); 261 } 262 263 public boolean waitForClientSignal() throws InterruptedException { 264 return waitForClientSignal(CLIENT_SIGNAL_TIMEOUT, TimeUnit.SECONDS); 265 } 266 267 public boolean waitForClientDone(long timeout, TimeUnit unit) 268 throws InterruptedException { 269 270 return clientDoneCondition.await(timeout, unit); 271 } 272 273 public boolean waitForClientDone() throws InterruptedException { 274 return waitForClientDone(CLIENT_SIGNAL_TIMEOUT, TimeUnit.SECONDS); 275 } 276 277 public void signalClientReady() { 278 clientReadyCondition.countDown(); 279 } 280 281 public void signalClientDone() { 282 clientDoneCondition.countDown(); 283 } 284 285 public boolean waitForServerSignal(long timeout, TimeUnit unit) 286 throws InterruptedException { 287 288 return serverReadyCondition.await(timeout, unit); 289 } 290 291 public boolean waitForServerSignal() throws InterruptedException { 292 return waitForServerSignal(SERVER_SIGNAL_TIMEOUT, TimeUnit.SECONDS); 293 } 294 295 public boolean waitForServerDone(long timeout, TimeUnit unit) 296 throws InterruptedException { 297 298 return serverDoneCondition.await(timeout, unit); 299 } 300 301 public boolean waitForServerDone() throws InterruptedException { 302 return waitForServerDone(SERVER_SIGNAL_TIMEOUT, TimeUnit.SECONDS); 303 } 304 305 public SSLSocketTemplate setServerPeer(Peer serverPeer) { 306 this.serverPeer = serverPeer; 307 return this; 308 } 309 310 public Peer getServerPeer() { 311 return serverPeer; 312 } 313 314 public SSLSocketTemplate setServerApplication( 315 Application serverApplication) { 316 317 this.serverApplication = serverApplication; 318 return this; 319 } 320 321 public Application getServerApplication() { 322 return serverApplication; 323 } 324 325 public SSLSocketTemplate setClientPeer(Peer clientPeer) { 326 this.clientPeer = clientPeer; 327 return this; 328 } 329 330 public Peer getClientPeer() { 331 return clientPeer; 332 } 333 334 public SSLSocketTemplate setClientApplication( 335 Application clientApplication) { 336 337 this.clientApplication = clientApplication; 338 return this; 339 } 340 341 public Application getClientApplication() { 342 return clientApplication; 343 } 344 345 public void runTest() throws Exception { 346 if (separateServerThread) { 347 startServer(true, this); 348 startClient(false, this); 349 serverThread.join(); 350 } else { 351 startClient(true, this); 352 startServer(false, this); 353 clientThread.join(); 354 } 355 356 if (clientException != null || serverException != null) { 357 throw new RuntimeException("Test failed"); 358 } 359 } 360 361 public SSLSocketTemplate() { 362 serverPeer = new Peer() { 363 364 @Override 365 public void run(SSLSocketTemplate test) throws Exception { 366 doServerSide(test); 367 } 368 }; 369 370 clientPeer = new Peer() { 371 372 @Override 373 public void run(SSLSocketTemplate test) throws Exception { 374 doClientSide(test); 375 } 376 }; 377 378 serverApplication = new Application() { 379 380 @Override 381 public void run(SSLSocket socket, SSLSocketTemplate test) 382 throws Exception { 383 384 runServerApplication(socket); 385 } 386 387 }; 388 389 clientApplication = new Application() { 390 391 @Override 392 public void run(SSLSocket socket, SSLSocketTemplate test) 393 throws Exception { 394 395 runClientApplication(socket); 396 } 397 }; 398 } 399 400 public static void main(String args[]) throws Exception { 401 // reset the security property to make sure that the algorithms 402 // and keys used in this test are not disabled. 403 Security.setProperty("jdk.tls.disabledAlgorithms", ""); 404 405 // MD5 is used in this test case, don't disable MD5 algorithm. 406 Security.setProperty( 407 "jdk.certpath.disabledAlgorithms", "MD2, RSA keySize < 1024"); 408 409 setup(); 410 411 new SSLSocketTemplate().runTest(); 412 } 413 414 /* 415 * Private part. 416 */ 417 418 /* 419 * Define the server side of the test. 420 */ 421 private static void doServerSide(SSLSocketTemplate test) throws Exception { 422 SSLServerSocket sslServerSocket; 423 424 // kick start the server side service 425 SSLServerSocketFactory sslssf = test.getSSLServerSocketFactory(); 426 sslServerSocket = (SSLServerSocket)sslssf.createServerSocket(FREE_PORT); 427 428 test.setServerPort(sslServerSocket.getLocalPort()); 429 print("Server is listening on port " + test.getServerPort()); 430 431 // Signal the client, the server is ready to accept connection. 432 test.signalServerReady(); 433 434 // Try to accept a connection in 30 seconds. 435 SSLSocket sslSocket = accept(sslServerSocket); 436 if (sslSocket == null) { 437 // Ignore the test case if no connection within 30 seconds. 438 print("No incoming client connection in 30 seconds. " 439 + "Ignore in server side."); 440 return; 441 } 442 print("Server accepted connection"); 443 444 // handle the connection 445 try { 446 // Is it the expected client connection? 447 // 448 // Naughty test cases or third party routines may try to 449 // connection to this server port unintentionally. In 450 // order to mitigate the impact of unexpected client 451 // connections and avoid intermittent failure, it should 452 // be checked that the accepted connection is really linked 453 // to the expected client. 454 boolean clientIsReady = test.waitForClientSignal(); 455 456 if (clientIsReady) { 457 // Run the application in server side. 458 print("Run server application"); 459 test.getServerApplication().run(sslSocket, test); 460 } else { // Otherwise, ignore 461 // We don't actually care about plain socket connections 462 // for TLS communication testing generally. Just ignore 463 // the test if the accepted connection is not linked to 464 // the expected client or the client connection timeout 465 // in 30 seconds. 466 print("The client is not the expected one or timeout. " 467 + "Ignore in server side."); 468 } 469 } finally { 470 sslSocket.close(); 471 sslServerSocket.close(); 472 } 473 474 test.signalServerDone(); 475 } 476 477 /* 478 * Define the server side application of the test for the specified socket. 479 */ 480 private static void runServerApplication(SSLSocket socket) 481 throws Exception { 482 483 // here comes the test logic 484 InputStream sslIS = socket.getInputStream(); 485 OutputStream sslOS = socket.getOutputStream(); 486 487 sslIS.read(); 488 sslOS.write(85); 489 sslOS.flush(); 490 } 491 492 /* 493 * Define the client side of the test. 494 */ 495 private static void doClientSide(SSLSocketTemplate test) throws Exception { 496 497 // Wait for server to get started. 498 // 499 // The server side takes care of the issue if the server cannot 500 // get started in 90 seconds. The client side would just ignore 501 // the test case if the serer is not ready. 502 boolean serverIsReady = test.waitForServerSignal(); 503 if (!serverIsReady) { 504 print("The server is not ready yet in 90 seconds. " 505 + "Ignore in client side."); 506 return; 507 } 508 509 SSLSocketFactory sslsf = test.getSSLSocketFactory(); 510 SSLSocket sslSocket = (SSLSocket)sslsf.createSocket(); 511 try { 512 try { 513 sslSocket.connect( 514 new InetSocketAddress("localhost", 515 test.getServerPort()), CLIENT_TIMEOUT); 516 print("Client connected to server"); 517 } catch (IOException ioe) { 518 // The server side may be impacted by naughty test cases or 519 // third party routines, and cannot accept connections. 520 // 521 // Just ignore the test if the connection cannot be 522 // established. 523 print("Cannot make a connection in 15 seconds. " 524 + "Ignore in client side.", ioe); 525 return; 526 } 527 528 // OK, here the client and server get connected. 529 530 // Signal the server, the client is ready to communicate. 531 test.signalClientReady(); 532 533 // There is still a chance in theory that the server thread may 534 // wait client-ready timeout and then quit. The chance should 535 // be really rare so we don't consider it until it becomes a 536 // real problem. 537 538 // Run the application in client side. 539 print("Run client application"); 540 test.getClientApplication().run(sslSocket, test); 541 } finally { 542 sslSocket.close(); 543 } 544 545 test.signalClientDone(); 546 } 547 548 /* 549 * Define the client side application of the test for the specified socket. 550 */ 551 private static void runClientApplication(SSLSocket socket) 552 throws Exception { 553 554 InputStream sslIS = socket.getInputStream(); 555 OutputStream sslOS = socket.getOutputStream(); 556 557 sslOS.write(280); 558 sslOS.flush(); 559 sslIS.read(); 560 } 561 562 private void startServer(boolean newThread, SSLSocketTemplate test) 563 throws Exception { 564 565 if (newThread) { 566 serverThread = new Thread() { 567 568 @Override 569 public void run() { 570 try { 571 serverPeer.run(test); 572 } catch (Exception e) { 573 /* 574 * Our server thread just died. 575 * 576 * Release the client, if not active already... 577 */ 578 print("Server died ...", e); 579 serverException = e; 580 } 581 } 582 }; 583 serverThread.start(); 584 } else { 585 try { 586 serverPeer.run(test); 587 } catch (Exception e) { 588 print("Server failed ...", e); 589 serverException = e; 590 } 591 } 592 } 593 594 private void startClient(boolean newThread, SSLSocketTemplate test) 595 throws Exception { 596 597 if (newThread) { 598 clientThread = new Thread() { 599 600 @Override 601 public void run() { 602 try { 603 clientPeer.run(test); 604 } catch (Exception e) { 605 /* 606 * Our client thread just died. 607 */ 608 print("Client died ...", e); 609 clientException = e; 610 } 611 } 612 }; 613 clientThread.start(); 614 } else { 615 try { 616 clientPeer.run(test); 617 } catch (Exception e) { 618 print("Client failed ...", e); 619 clientException = e; 620 } 621 } 622 } 623} 624