1 /* 2 * Copyright (c) 2015, 2017, 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 // SunJSSE does not support dynamic system properties, no way to re-use 25 // system properties in samevm/agentvm mode. 26 27 /* 28 * @test 29 * @bug 8046321 8153829 30 * @summary OCSP Stapling for TLS 31 * @library ../../../../java/security/testlibrary 32 * @build CertificateBuilder SimpleOCSPServer 33 * @run main/othervm SSLSocketWithStapling 34 */ 35 36 import java.io.*; 37 import java.math.BigInteger; 38 import java.security.KeyPair; 39 import java.security.KeyPairGenerator; 40 import javax.net.ssl.*; 41 import java.security.KeyStore; 42 import java.security.PublicKey; 43 import java.security.Security; 44 import java.security.cert.CertPathValidator; 45 import java.security.cert.CertPathValidatorException; 46 import java.security.cert.CertPathValidatorException.BasicReason; 47 import java.security.cert.Certificate; 48 import java.security.cert.PKIXBuilderParameters; 49 import java.security.cert.X509CertSelector; 50 import java.security.cert.X509Certificate; 51 import java.security.cert.PKIXRevocationChecker; 52 import java.security.cert.PKIXRevocationChecker.Option; 53 import java.util.ArrayList; 54 import java.util.Collections; 55 import java.util.Date; 56 import java.util.EnumSet; 57 import java.util.List; 58 import java.util.Map; 59 import java.util.HashMap; 60 import java.util.concurrent.TimeUnit; 61 62 import sun.security.testlibrary.SimpleOCSPServer; 63 import sun.security.testlibrary.CertificateBuilder; 64 65 public class SSLSocketWithStapling { 66 67 /* 68 * ============================================================= 69 * Set the various variables needed for the tests, then 70 * specify what tests to run on each side. 71 */ 72 73 // Turn on TLS debugging 74 static boolean debug = false; 75 76 /* 77 * Should we run the client or server in a separate thread? 78 * Both sides can throw exceptions, but do you have a preference 79 * as to which side should be the main thread. 80 */ 81 static boolean separateServerThread = true; 82 Thread clientThread = null; 83 Thread serverThread = null; 84 85 static String passwd = "passphrase"; 86 static String ROOT_ALIAS = "root"; 87 static String INT_ALIAS = "intermediate"; 88 static String SSL_ALIAS = "ssl"; 89 90 /* 91 * Is the server ready to serve? 92 */ 93 volatile static boolean serverReady = false; 94 volatile int serverPort = 0; 95 96 volatile Exception serverException = null; 97 volatile Exception clientException = null; 98 99 // PKI components we will need for this test 100 static KeyStore rootKeystore; // Root CA Keystore 101 static KeyStore intKeystore; // Intermediate CA Keystore 102 static KeyStore serverKeystore; // SSL Server Keystore 103 static KeyStore trustStore; // SSL Client trust store 104 static SimpleOCSPServer rootOcsp; // Root CA OCSP Responder 105 static int rootOcspPort; // Port number for root OCSP 106 static SimpleOCSPServer intOcsp; // Intermediate CA OCSP Responder 107 static int intOcspPort; // Port number for intermed. OCSP 108 109 /* 110 * If the client or server is doing some kind of object creation 111 * that the other side depends on, and that thread prematurely 112 * exits, you may experience a hang. The test harness will 113 * terminate all hung threads after its timeout has expired, 114 * currently 3 minutes by default, but you might try to be 115 * smart about it.... 116 */ 117 public static void main(String[] args) throws Exception { 118 if (debug) { 119 System.setProperty("javax.net.debug", "ssl"); 120 } 121 122 try { 123 // Create the PKI we will use for the test and start the OCSP servers 124 createPKI(); 125 126 testAllDefault(); 127 testPKIXParametersRevEnabled(); 128 testRevokedCertificate(); 129 testHardFailFallback(); 130 testSoftFailFallback(); 131 testLatencyNoStaple(false); 132 testLatencyNoStaple(true); 133 } finally { 134 // shut down the OCSP responders before finishing the test 135 intOcsp.stop(); 136 rootOcsp.stop(); 137 } 138 } 139 140 /** 141 * Default test using no externally-configured PKIXBuilderParameters 142 */ 143 static void testAllDefault() throws Exception { 144 ClientParameters cliParams = new ClientParameters(); 145 ServerParameters servParams = new ServerParameters(); 146 serverReady = false; 147 Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo = 148 new HashMap<>(); 149 150 // We will prove revocation checking is disabled by marking the SSL 151 // certificate as revoked. The test would only pass if revocation 152 // checking did not happen. 153 X509Certificate sslCert = 154 (X509Certificate)serverKeystore.getCertificate(SSL_ALIAS); 155 Date fiveMinsAgo = new Date(System.currentTimeMillis() - 156 TimeUnit.MINUTES.toMillis(5)); 157 revInfo.put(sslCert.getSerialNumber(), 158 new SimpleOCSPServer.CertStatusInfo( 159 SimpleOCSPServer.CertStatus.CERT_STATUS_REVOKED, 160 fiveMinsAgo)); 161 intOcsp.updateStatusDb(revInfo); 162 163 System.out.println("======================================="); 164 System.out.println("Stapling enabled, default configuration"); 165 System.out.println("======================================="); 166 167 SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams, 168 servParams); 169 TestResult tr = sslTest.getResult(); 170 if (tr.clientExc != null) { 171 throw tr.clientExc; 172 } else if (tr.serverExc != null) { 173 throw tr.serverExc; 174 } 175 176 // Return the ssl certificate to non-revoked status 177 revInfo.put(sslCert.getSerialNumber(), 178 new SimpleOCSPServer.CertStatusInfo( 179 SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); 180 intOcsp.updateStatusDb(revInfo); 181 182 System.out.println(" PASS"); 183 System.out.println("=======================================\n"); 184 } 185 186 /** 187 * Do a basic connection using PKIXParameters with revocation checking 188 * enabled and client-side OCSP disabled. It will only pass if all 189 * stapled responses are present, valid and have a GOOD status. 190 */ 191 static void testPKIXParametersRevEnabled() throws Exception { 192 ClientParameters cliParams = new ClientParameters(); 193 ServerParameters servParams = new ServerParameters(); 194 serverReady = false; 195 196 System.out.println("====================================="); 197 System.out.println("Stapling enabled, PKIXParameters with"); 198 System.out.println("Revocation checking enabled "); 199 System.out.println("====================================="); 200 201 cliParams.pkixParams = new PKIXBuilderParameters(trustStore, 202 new X509CertSelector()); 203 cliParams.pkixParams.setRevocationEnabled(true); 204 Security.setProperty("ocsp.enable", "false"); 205 206 SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams, 207 servParams); 208 TestResult tr = sslTest.getResult(); 209 if (tr.clientExc != null) { 210 throw tr.clientExc; 211 } else if (tr.serverExc != null) { 212 throw tr.serverExc; 213 } 214 215 System.out.println(" PASS"); 216 System.out.println("=====================================\n"); 217 } 218 219 /** 220 * Perform a test where the certificate is revoked and placed in the 221 * TLS handshake. Client-side OCSP is disabled, so this test will only 222 * pass if the OCSP response is found, since we will check the 223 * CertPathValidatorException reason for revoked status. 224 */ 225 static void testRevokedCertificate() throws Exception { 226 ClientParameters cliParams = new ClientParameters(); 227 ServerParameters servParams = new ServerParameters(); 228 serverReady = false; 229 Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo = 230 new HashMap<>(); 231 232 // We will prove revocation checking is disabled by marking the SSL 233 // certificate as revoked. The test would only pass if revocation 234 // checking did not happen. 235 X509Certificate sslCert = 236 (X509Certificate)serverKeystore.getCertificate(SSL_ALIAS); 237 Date fiveMinsAgo = new Date(System.currentTimeMillis() - 238 TimeUnit.MINUTES.toMillis(5)); 239 revInfo.put(sslCert.getSerialNumber(), 240 new SimpleOCSPServer.CertStatusInfo( 241 SimpleOCSPServer.CertStatus.CERT_STATUS_REVOKED, 242 fiveMinsAgo)); 243 intOcsp.updateStatusDb(revInfo); 244 245 System.out.println("======================================="); 246 System.out.println("Stapling enabled, default configuration"); 247 System.out.println("======================================="); 248 249 cliParams.pkixParams = new PKIXBuilderParameters(trustStore, 250 new X509CertSelector()); 251 cliParams.pkixParams.setRevocationEnabled(true); 252 Security.setProperty("ocsp.enable", "false"); 253 254 SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams, 255 servParams); 256 TestResult tr = sslTest.getResult(); 257 if (!checkClientValidationFailure(tr.clientExc, BasicReason.REVOKED)) { 258 if (tr.clientExc != null) { 259 throw tr.clientExc; 260 } else { 261 throw new RuntimeException( 262 "Expected client failure, but the client succeeded"); 263 } 264 } 265 266 // Return the ssl certificate to non-revoked status 267 revInfo.put(sslCert.getSerialNumber(), 268 new SimpleOCSPServer.CertStatusInfo( 269 SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); 270 intOcsp.updateStatusDb(revInfo); 271 272 System.out.println(" PASS"); 273 System.out.println("=======================================\n"); 274 } 275 276 /** 277 * Test a case where client-side stapling is attempted, but does not 278 * occur because OCSP responders are unreachable. This should use a 279 * default hard-fail behavior. 280 */ 281 static void testHardFailFallback() throws Exception { 282 ClientParameters cliParams = new ClientParameters(); 283 ServerParameters servParams = new ServerParameters(); 284 serverReady = false; 285 286 // make OCSP responders reject connections 287 intOcsp.rejectConnections(); 288 rootOcsp.rejectConnections(); 289 290 System.out.println("======================================="); 291 System.out.println("Stapling enbled in client and server,"); 292 System.out.println("but OCSP responders disabled."); 293 System.out.println("PKIXParameters with Revocation checking"); 294 System.out.println("enabled."); 295 System.out.println("======================================="); 296 297 Security.setProperty("ocsp.enable", "true"); 298 cliParams.pkixParams = new PKIXBuilderParameters(trustStore, 299 new X509CertSelector()); 300 cliParams.pkixParams.setRevocationEnabled(true); 301 302 SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams, 303 servParams); 304 TestResult tr = sslTest.getResult(); 305 if (!checkClientValidationFailure(tr.clientExc, 306 BasicReason.UNDETERMINED_REVOCATION_STATUS)) { 307 if (tr.clientExc != null) { 308 throw tr.clientExc; 309 } else { 310 throw new RuntimeException( 311 "Expected client failure, but the client succeeded"); 312 } 313 } 314 315 System.out.println(" PASS"); 316 System.out.println("=======================================\n"); 317 318 // Make OCSP responders accept connections 319 intOcsp.acceptConnections(); 320 rootOcsp.acceptConnections(); 321 322 // Wait 5 seconds for server ready 323 for (int i = 0; (i < 100 && (!intOcsp.isServerReady() || !rootOcsp.isServerReady())); i++) { 324 Thread.sleep(50); 325 } 326 if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) { 327 throw new RuntimeException("Server not ready yet"); 328 } 329 } 330 331 /** 332 * Test a case where client-side stapling is attempted, but does not 333 * occur because OCSP responders are unreachable. Client-side OCSP 334 * checking is enabled for this, with SOFT_FAIL. 335 */ 336 static void testSoftFailFallback() throws Exception { 337 ClientParameters cliParams = new ClientParameters(); 338 ServerParameters servParams = new ServerParameters(); 339 serverReady = false; 340 341 // make OCSP responders reject connections 342 intOcsp.rejectConnections(); 343 rootOcsp.rejectConnections(); 344 345 System.out.println("======================================="); 346 System.out.println("Stapling enbled in client and server,"); 347 System.out.println("but OCSP responders disabled."); 348 System.out.println("PKIXParameters with Revocation checking"); 349 System.out.println("enabled and SOFT_FAIL."); 350 System.out.println("======================================="); 351 352 Security.setProperty("ocsp.enable", "true"); 353 cliParams.pkixParams = new PKIXBuilderParameters(trustStore, 354 new X509CertSelector()); 355 cliParams.pkixParams.setRevocationEnabled(true); 356 CertPathValidator cpv = CertPathValidator.getInstance("PKIX"); 357 cliParams.revChecker = 358 (PKIXRevocationChecker)cpv.getRevocationChecker(); 359 cliParams.revChecker.setOptions(EnumSet.of(Option.SOFT_FAIL)); 360 361 SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams, 362 servParams); 363 TestResult tr = sslTest.getResult(); 364 if (tr.clientExc != null) { 365 throw tr.clientExc; 366 } else if (tr.serverExc != null) { 367 throw tr.serverExc; 368 } 369 370 // make sure getSoftFailExceptions is not empty 371 if (cliParams.revChecker.getSoftFailExceptions().isEmpty()) { 372 throw new Exception("No soft fail exceptions"); 373 } 374 375 System.out.println(" PASS"); 376 System.out.println("=======================================\n"); 377 378 379 // Make OCSP responders accept connections 380 intOcsp.acceptConnections(); 381 rootOcsp.acceptConnections(); 382 383 // Wait 5 seconds for server ready 384 for (int i = 0; (i < 100 && (!intOcsp.isServerReady() || !rootOcsp.isServerReady())); i++) { 385 Thread.sleep(50); 386 } 387 if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) { 388 throw new RuntimeException("Server not ready yet"); 389 } 390 } 391 392 /** 393 * This test initiates stapling from the client, but the server does not 394 * support OCSP stapling for this connection. In this case it happens 395 * because the latency of the OCSP responders is longer than the server 396 * is willing to wait. To keep the test streamlined, we will set the server 397 * latency to a 1 second wait, and set the responder latency to 3 seconds. 398 * 399 * @param fallback if we allow client-side OCSP fallback, which 400 * will change the result from the client failing with CPVE (no fallback) 401 * to a pass (fallback active). 402 */ 403 static void testLatencyNoStaple(Boolean fallback) throws Exception { 404 ClientParameters cliParams = new ClientParameters(); 405 ServerParameters servParams = new ServerParameters(); 406 serverReady = false; 407 408 // Give a 1 second delay before running the test. 409 intOcsp.setDelay(3000); 410 rootOcsp.setDelay(3000); 411 Thread.sleep(1000); 412 413 // Wait 5 seconds for server ready 414 for (int i = 0; (i < 100 && (!intOcsp.isServerReady() || !rootOcsp.isServerReady())); i++) { 415 Thread.sleep(50); 416 } 417 if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) { 418 throw new RuntimeException("Server not ready yet"); 419 } 420 421 System.out.println("========================================"); 422 System.out.println("Stapling enbled in client. Server does"); 423 System.out.println("not support stapling due to OCSP latency."); 424 System.out.println("PKIXParameters with Revocation checking"); 425 System.out.println("enabled, client-side OCSP checking is."); 426 System.out.println(fallback ? "enabled" : "disabled"); 427 System.out.println("========================================"); 428 429 Security.setProperty("ocsp.enable", fallback.toString()); 430 cliParams.pkixParams = new PKIXBuilderParameters(trustStore, 431 new X509CertSelector()); 432 cliParams.pkixParams.setRevocationEnabled(true); 433 servParams.respTimeout = 1000; 434 435 SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams, 436 servParams); 437 TestResult tr = sslTest.getResult(); 438 439 if (fallback) { 440 if (tr.clientExc != null) { 441 throw tr.clientExc; 442 } else if (tr.serverExc != null) { 443 throw tr.serverExc; 444 } 445 } else { 446 if (!checkClientValidationFailure(tr.clientExc, 447 BasicReason.UNDETERMINED_REVOCATION_STATUS)) { 448 if (tr.clientExc != null) { 449 throw tr.clientExc; 450 } else { 451 throw new RuntimeException( 452 "Expected client failure, but the client succeeded"); 453 } 454 } 455 } 456 System.out.println(" PASS"); 457 System.out.println("========================================\n"); 458 459 // Remove the OCSP responder latency 460 intOcsp.setDelay(0); 461 rootOcsp.setDelay(0); 462 Thread.sleep(1000); 463 464 // Wait 5 seconds for server ready 465 for (int i = 0; (i < 100 && (!intOcsp.isServerReady() || !rootOcsp.isServerReady())); i++) { 466 Thread.sleep(50); 467 } 468 if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) { 469 throw new RuntimeException("Server not ready yet"); 470 } 471 } 472 473 /* 474 * Define the server side of the test. 475 * 476 * If the server prematurely exits, serverReady will be set to true 477 * to avoid infinite hangs. 478 */ 479 void doServerSide(ServerParameters servParams) throws Exception { 480 481 // Selectively enable or disable the feature 482 System.setProperty("jdk.tls.server.enableStatusRequestExtension", 483 Boolean.toString(servParams.enabled)); 484 485 // Set all the other operating parameters 486 System.setProperty("jdk.tls.stapling.cacheSize", 487 Integer.toString(servParams.cacheSize)); 488 System.setProperty("jdk.tls.stapling.cacheLifetime", 489 Integer.toString(servParams.cacheLifetime)); 490 System.setProperty("jdk.tls.stapling.responseTimeout", 491 Integer.toString(servParams.respTimeout)); 492 System.setProperty("jdk.tls.stapling.responderURI", servParams.respUri); 493 System.setProperty("jdk.tls.stapling.responderOverride", 494 Boolean.toString(servParams.respOverride)); 495 System.setProperty("jdk.tls.stapling.ignoreExtensions", 496 Boolean.toString(servParams.ignoreExts)); 497 498 // Set keystores and trust stores for the server 499 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 500 kmf.init(serverKeystore, passwd.toCharArray()); 501 TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 502 tmf.init(trustStore); 503 504 SSLContext sslc = SSLContext.getInstance("TLS"); 505 sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 506 507 SSLServerSocketFactory sslssf = sslc.getServerSocketFactory(); 508 509 try (SSLServerSocket sslServerSocket = 510 (SSLServerSocket) sslssf.createServerSocket(serverPort)) { 511 512 serverPort = sslServerSocket.getLocalPort(); 513 514 /* 515 * Signal Client, we're ready for his connect. 516 */ 517 serverReady = true; 518 519 try (SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); 520 InputStream sslIS = sslSocket.getInputStream(); 521 OutputStream sslOS = sslSocket.getOutputStream()) { 522 int numberIn = sslIS.read(); 523 int numberSent = 85; 524 log("Server received number: " + numberIn); 525 sslOS.write(numberSent); 526 sslOS.flush(); 527 log("Server sent number: " + numberSent); 528 } 529 } 530 } 531 532 /* 533 * Define the client side of the test. 534 * 535 * If the server prematurely exits, serverReady will be set to true 536 * to avoid infinite hangs. 537 */ 538 void doClientSide(ClientParameters cliParams) throws Exception { 539 540 // Wait 5 seconds for server ready 541 for (int i = 0; (i < 100 && !serverReady); i++) { 542 Thread.sleep(50); 543 } 544 if (!serverReady) { 545 throw new RuntimeException("Server not ready yet"); 546 } 547 548 // Selectively enable or disable the feature 549 System.setProperty("jdk.tls.client.enableStatusRequestExtension", 550 Boolean.toString(cliParams.enabled)); 551 552 // Create the Trust Manager Factory using the PKIX variant 553 TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); 554 555 // If we have a customized pkixParameters then use it 556 if (cliParams.pkixParams != null) { 557 // LIf we have a customized PKIXRevocationChecker, add 558 // it to the PKIXBuilderParameters. 559 if (cliParams.revChecker != null) { 560 cliParams.pkixParams.addCertPathChecker(cliParams.revChecker); 561 } 562 563 ManagerFactoryParameters trustParams = 564 new CertPathTrustManagerParameters(cliParams.pkixParams); 565 tmf.init(trustParams); 566 } else { 567 tmf.init(trustStore); 568 } 569 570 SSLContext sslc = SSLContext.getInstance("TLS"); 571 sslc.init(null, tmf.getTrustManagers(), null); 572 573 SSLSocketFactory sslsf = sslc.getSocketFactory(); 574 try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket("localhost", 575 serverPort); 576 InputStream sslIS = sslSocket.getInputStream(); 577 OutputStream sslOS = sslSocket.getOutputStream()) { 578 int numberSent = 80; 579 sslOS.write(numberSent); 580 sslOS.flush(); 581 log("Client sent number: " + numberSent); 582 int numberIn = sslIS.read(); 583 log("Client received number:" + numberIn); 584 } 585 } 586 587 /* 588 * Primary constructor, used to drive remainder of the test. 589 * 590 * Fork off the other side, then do your work. 591 */ 592 SSLSocketWithStapling(ClientParameters cliParams, 593 ServerParameters servParams) throws Exception { 594 Exception startException = null; 595 try { 596 if (separateServerThread) { 597 startServer(servParams, true); 598 startClient(cliParams, false); 599 } else { 600 startClient(cliParams, true); 601 startServer(servParams, false); 602 } 603 } catch (Exception e) { 604 startException = e; 605 } 606 607 /* 608 * Wait for other side to close down. 609 */ 610 if (separateServerThread) { 611 if (serverThread != null) { 612 serverThread.join(); 613 } 614 } else { 615 if (clientThread != null) { 616 clientThread.join(); 617 } 618 } 619 } 620 621 /** 622 * Checks a validation failure to see if it failed for the reason we think 623 * it should. This comes in as an SSLException of some sort, but it 624 * encapsulates a ValidatorException which in turn encapsulates the 625 * CertPathValidatorException we are interested in. 626 * 627 * @param e the exception thrown at the top level 628 * @param reason the underlying CertPathValidatorException BasicReason 629 * we are expecting it to have. 630 * 631 * @return true if the reason matches up, false otherwise. 632 */ 633 static boolean checkClientValidationFailure(Exception e, 634 BasicReason reason) { 635 boolean result = false; 636 637 if (e instanceof SSLException) { 638 Throwable valExc = e.getCause(); 639 if (valExc instanceof sun.security.validator.ValidatorException) { 640 Throwable cause = valExc.getCause(); 641 if (cause instanceof CertPathValidatorException) { 642 CertPathValidatorException cpve = 643 (CertPathValidatorException)cause; 644 if (cpve.getReason() == reason) { 645 result = true; 646 } 647 } 648 } 649 } 650 return result; 651 } 652 653 TestResult getResult() { 654 TestResult tr = new TestResult(); 655 tr.clientExc = clientException; 656 tr.serverExc = serverException; 657 return tr; 658 } 659 660 void startServer(ServerParameters servParams, boolean newThread) 661 throws Exception { 662 if (newThread) { 663 serverThread = new Thread() { 664 public void run() { 665 try { 666 doServerSide(servParams); 667 } catch (Exception e) { 668 /* 669 * Our server thread just died. 670 * 671 * Release the client, if not active already... 672 */ 673 System.err.println("Server died..."); 674 e.printStackTrace(System.err); 675 serverReady = true; 676 serverException = e; 677 } 678 } 679 }; 680 serverThread.start(); 681 } else { 682 try { 683 doServerSide(servParams); 684 } catch (Exception e) { 685 serverException = e; 686 } finally { 687 serverReady = true; 688 } 689 } 690 } 691 692 void startClient(ClientParameters cliParams, boolean newThread) 693 throws Exception { 694 if (newThread) { 695 clientThread = new Thread() { 696 public void run() { 697 try { 698 doClientSide(cliParams); 699 } catch (Exception e) { 700 /* 701 * Our client thread just died. 702 */ 703 System.err.println("Client died..."); 704 clientException = e; 705 } 706 } 707 }; 708 clientThread.start(); 709 } else { 710 try { 711 doClientSide(cliParams); 712 } catch (Exception e) { 713 clientException = e; 714 } 715 } 716 } 717 718 /** 719 * Creates the PKI components necessary for this test, including 720 * Root CA, Intermediate CA and SSL server certificates, the keystores 721 * for each entity, a client trust store, and starts the OCSP responders. 722 */ 723 private static void createPKI() throws Exception { 724 CertificateBuilder cbld = new CertificateBuilder(); 725 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); 726 keyGen.initialize(2048); 727 KeyStore.Builder keyStoreBuilder = 728 KeyStore.Builder.newInstance("PKCS12", null, 729 new KeyStore.PasswordProtection(passwd.toCharArray())); 730 731 // Generate Root, IntCA, EE keys 732 KeyPair rootCaKP = keyGen.genKeyPair(); 733 log("Generated Root CA KeyPair"); 734 KeyPair intCaKP = keyGen.genKeyPair(); 735 log("Generated Intermediate CA KeyPair"); 736 KeyPair sslKP = keyGen.genKeyPair(); 737 log("Generated SSL Cert KeyPair"); 738 739 // Set up the Root CA Cert 740 cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany"); 741 cbld.setPublicKey(rootCaKP.getPublic()); 742 cbld.setSerialNumber(new BigInteger("1")); 743 // Make a 3 year validity starting from 60 days ago 744 long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60); 745 long end = start + TimeUnit.DAYS.toMillis(1085); 746 cbld.setValidity(new Date(start), new Date(end)); 747 addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic()); 748 addCommonCAExts(cbld); 749 // Make our Root CA Cert! 750 X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(), 751 "SHA256withRSA"); 752 log("Root CA Created:\n" + certInfo(rootCert)); 753 754 // Now build a keystore and add the keys and cert 755 rootKeystore = keyStoreBuilder.getKeyStore(); 756 Certificate[] rootChain = {rootCert}; 757 rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(), 758 passwd.toCharArray(), rootChain); 759 760 // Now fire up the OCSP responder 761 rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null); 762 rootOcsp.enableLog(debug); 763 rootOcsp.setNextUpdateInterval(3600); 764 rootOcsp.start(); 765 766 // Wait 5 seconds for server ready 767 for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) { 768 Thread.sleep(50); 769 } 770 if (!rootOcsp.isServerReady()) { 771 throw new RuntimeException("Server not ready yet"); 772 } 773 774 rootOcspPort = rootOcsp.getPort(); 775 String rootRespURI = "http://localhost:" + rootOcspPort; 776 log("Root OCSP Responder URI is " + rootRespURI); 777 778 // Now that we have the root keystore and OCSP responder we can 779 // create our intermediate CA. 780 cbld.reset(); 781 cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany"); 782 cbld.setPublicKey(intCaKP.getPublic()); 783 cbld.setSerialNumber(new BigInteger("100")); 784 // Make a 2 year validity starting from 30 days ago 785 start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30); 786 end = start + TimeUnit.DAYS.toMillis(730); 787 cbld.setValidity(new Date(start), new Date(end)); 788 addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic()); 789 addCommonCAExts(cbld); 790 cbld.addAIAExt(Collections.singletonList(rootRespURI)); 791 // Make our Intermediate CA Cert! 792 X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(), 793 "SHA256withRSA"); 794 log("Intermediate CA Created:\n" + certInfo(intCaCert)); 795 796 // Provide intermediate CA cert revocation info to the Root CA 797 // OCSP responder. 798 Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo = 799 new HashMap<>(); 800 revInfo.put(intCaCert.getSerialNumber(), 801 new SimpleOCSPServer.CertStatusInfo( 802 SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); 803 rootOcsp.updateStatusDb(revInfo); 804 805 // Now build a keystore and add the keys, chain and root cert as a TA 806 intKeystore = keyStoreBuilder.getKeyStore(); 807 Certificate[] intChain = {intCaCert, rootCert}; 808 intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(), 809 passwd.toCharArray(), intChain); 810 intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert); 811 812 // Now fire up the Intermediate CA OCSP responder 813 intOcsp = new SimpleOCSPServer(intKeystore, passwd, 814 INT_ALIAS, null); 815 intOcsp.enableLog(debug); 816 intOcsp.setNextUpdateInterval(3600); 817 intOcsp.start(); 818 819 // Wait 5 seconds for server ready 820 for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) { 821 Thread.sleep(50); 822 } 823 if (!intOcsp.isServerReady()) { 824 throw new RuntimeException("Server not ready yet"); 825 } 826 827 intOcspPort = intOcsp.getPort(); 828 String intCaRespURI = "http://localhost:" + intOcspPort; 829 log("Intermediate CA OCSP Responder URI is " + intCaRespURI); 830 831 // Last but not least, let's make our SSLCert and add it to its own 832 // Keystore 833 cbld.reset(); 834 cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany"); 835 cbld.setPublicKey(sslKP.getPublic()); 836 cbld.setSerialNumber(new BigInteger("4096")); 837 // Make a 1 year validity starting from 7 days ago 838 start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7); 839 end = start + TimeUnit.DAYS.toMillis(365); 840 cbld.setValidity(new Date(start), new Date(end)); 841 842 // Add extensions 843 addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic()); 844 boolean[] kuBits = {true, false, true, false, false, false, 845 false, false, false}; 846 cbld.addKeyUsageExt(kuBits); 847 List<String> ekuOids = new ArrayList<>(); 848 ekuOids.add("1.3.6.1.5.5.7.3.1"); 849 ekuOids.add("1.3.6.1.5.5.7.3.2"); 850 cbld.addExtendedKeyUsageExt(ekuOids); 851 cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost")); 852 cbld.addAIAExt(Collections.singletonList(intCaRespURI)); 853 // Make our SSL Server Cert! 854 X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(), 855 "SHA256withRSA"); 856 log("SSL Certificate Created:\n" + certInfo(sslCert)); 857 858 // Provide SSL server cert revocation info to the Intermeidate CA 859 // OCSP responder. 860 revInfo = new HashMap<>(); 861 revInfo.put(sslCert.getSerialNumber(), 862 new SimpleOCSPServer.CertStatusInfo( 863 SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); 864 intOcsp.updateStatusDb(revInfo); 865 866 // Now build a keystore and add the keys, chain and root cert as a TA 867 serverKeystore = keyStoreBuilder.getKeyStore(); 868 Certificate[] sslChain = {sslCert, intCaCert, rootCert}; 869 serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(), 870 passwd.toCharArray(), sslChain); 871 serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert); 872 873 // And finally a Trust Store for the client 874 trustStore = keyStoreBuilder.getKeyStore(); 875 trustStore.setCertificateEntry(ROOT_ALIAS, rootCert); 876 } 877 878 private static void addCommonExts(CertificateBuilder cbld, 879 PublicKey subjKey, PublicKey authKey) throws IOException { 880 cbld.addSubjectKeyIdExt(subjKey); 881 cbld.addAuthorityKeyIdExt(authKey); 882 } 883 884 private static void addCommonCAExts(CertificateBuilder cbld) 885 throws IOException { 886 cbld.addBasicConstraintsExt(true, true, -1); 887 // Set key usage bits for digitalSignature, keyCertSign and cRLSign 888 boolean[] kuBitSettings = {true, false, false, false, false, true, 889 true, false, false}; 890 cbld.addKeyUsageExt(kuBitSettings); 891 } 892 893 /** 894 * Helper routine that dumps only a few cert fields rather than 895 * the whole toString() output. 896 * 897 * @param cert an X509Certificate to be displayed 898 * 899 * @return the String output of the issuer, subject and 900 * serial number 901 */ 902 private static String certInfo(X509Certificate cert) { 903 StringBuilder sb = new StringBuilder(); 904 sb.append("Issuer: ").append(cert.getIssuerX500Principal()). 905 append("\n"); 906 sb.append("Subject: ").append(cert.getSubjectX500Principal()). 907 append("\n"); 908 sb.append("Serial: ").append(cert.getSerialNumber()).append("\n"); 909 return sb.toString(); 910 } 911 912 /** 913 * Log a message on stdout 914 * 915 * @param message The message to log 916 */ 917 private static void log(String message) { 918 if (debug) { 919 System.out.println(message); 920 } 921 } 922 923 // The following two classes are Simple nested class to group a handful 924 // of configuration parameters used before starting a client or server. 925 // We'll just access the data members directly for convenience. 926 static class ClientParameters { 927 boolean enabled = true; 928 PKIXBuilderParameters pkixParams = null; 929 PKIXRevocationChecker revChecker = null; 930 931 ClientParameters() { } 932 } 933 934 static class ServerParameters { 935 boolean enabled = true; 936 int cacheSize = 256; 937 int cacheLifetime = 3600; 938 int respTimeout = 5000; 939 String respUri = ""; 940 boolean respOverride = false; 941 boolean ignoreExts = false; 942 943 ServerParameters() { } 944 } 945 946 static class TestResult { 947 Exception serverExc = null; 948 Exception clientExc = null; 949 } 950 951 }