1/* 2 * Copyright (c) 2015, 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 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 HttpsUrlConnClient 34 */ 35 36import java.io.*; 37import java.math.BigInteger; 38import java.security.KeyPair; 39import java.security.KeyPairGenerator; 40import java.net.Socket; 41import java.net.URL; 42import java.net.HttpURLConnection; 43import java.net.InetAddress; 44import javax.net.ssl.*; 45import java.security.KeyStore; 46import java.security.PublicKey; 47import java.security.Security; 48import java.security.GeneralSecurityException; 49import java.security.cert.CertPathValidatorException; 50import java.security.cert.CertPathValidatorException.BasicReason; 51import java.security.cert.Certificate; 52import java.security.cert.PKIXBuilderParameters; 53import java.security.cert.X509CertSelector; 54import java.security.cert.X509Certificate; 55import java.security.cert.PKIXRevocationChecker; 56import java.security.spec.PKCS8EncodedKeySpec; 57import java.text.SimpleDateFormat; 58import java.util.*; 59import java.util.concurrent.TimeUnit; 60 61import sun.security.testlibrary.SimpleOCSPServer; 62import sun.security.testlibrary.CertificateBuilder; 63import sun.security.validator.ValidatorException; 64 65public class HttpsUrlConnClient { 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 static final byte[] LINESEP = { 10 }; 74 static final Base64.Encoder B64E = Base64.getMimeEncoder(64, LINESEP); 75 76 // Turn on TLS debugging 77 static boolean debug = true; 78 79 /* 80 * Should we run the client or server in a separate thread? 81 * Both sides can throw exceptions, but do you have a preference 82 * as to which side should be the main thread. 83 */ 84 static boolean separateServerThread = true; 85 Thread clientThread = null; 86 Thread serverThread = null; 87 88 static String passwd = "passphrase"; 89 static String ROOT_ALIAS = "root"; 90 static String INT_ALIAS = "intermediate"; 91 static String SSL_ALIAS = "ssl"; 92 93 /* 94 * Is the server ready to serve? 95 */ 96 volatile static boolean serverReady = false; 97 volatile int serverPort = 0; 98 99 volatile Exception serverException = null; 100 volatile Exception clientException = null; 101 102 // PKI components we will need for this test 103 static KeyStore rootKeystore; // Root CA Keystore 104 static KeyStore intKeystore; // Intermediate CA Keystore 105 static KeyStore serverKeystore; // SSL Server Keystore 106 static KeyStore trustStore; // SSL Client trust store 107 static SimpleOCSPServer rootOcsp; // Root CA OCSP Responder 108 static int rootOcspPort; // Port number for root OCSP 109 static SimpleOCSPServer intOcsp; // Intermediate CA OCSP Responder 110 static int intOcspPort; // Port number for intermed. OCSP 111 112 private static final String SIMPLE_WEB_PAGE = "<HTML>\n" + 113 "<HEAD><Title>Web Page!</Title></HEAD>\n" + 114 "<BODY><H1>Web Page!</H1></BODY>\n</HTML>"; 115 private static final SimpleDateFormat utcDateFmt = 116 new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z"); 117 /* 118 * If the client or server is doing some kind of object creation 119 * that the other side depends on, and that thread prematurely 120 * exits, you may experience a hang. The test harness will 121 * terminate all hung threads after its timeout has expired, 122 * currently 3 minutes by default, but you might try to be 123 * smart about it.... 124 */ 125 public static void main(String[] args) throws Exception { 126 if (debug) { 127 System.setProperty("javax.net.debug", "ssl"); 128 } 129 130 System.setProperty("javax.net.ssl.keyStore", ""); 131 System.setProperty("javax.net.ssl.keyStorePassword", ""); 132 System.setProperty("javax.net.ssl.trustStore", ""); 133 System.setProperty("javax.net.ssl.trustStorePassword", ""); 134 135 // Create the PKI we will use for the test and start the OCSP servers 136 createPKI(); 137 utcDateFmt.setTimeZone(TimeZone.getTimeZone("GMT")); 138 139 testPKIXParametersRevEnabled(); 140 141 // shut down the OCSP responders before finishing the test 142 intOcsp.stop(); 143 rootOcsp.stop(); 144 } 145 146 /** 147 * Do a basic connection using PKIXParameters with revocation checking 148 * enabled and client-side OCSP disabled. It will only pass if all 149 * stapled responses are present, valid and have a GOOD status. 150 */ 151 static void testPKIXParametersRevEnabled() throws Exception { 152 ClientParameters cliParams = new ClientParameters(); 153 ServerParameters servParams = new ServerParameters(); 154 serverReady = false; 155 156 System.out.println("====================================="); 157 System.out.println("Stapling enabled, PKIXParameters with"); 158 System.out.println("Revocation checking enabled "); 159 System.out.println("====================================="); 160 161 // Set the certificate entry in the intermediate OCSP responder 162 // with a revocation date of 8 hours ago. 163 X509Certificate sslCert = 164 (X509Certificate)serverKeystore.getCertificate(SSL_ALIAS); 165 Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo = 166 new HashMap<>(); 167 revInfo.put(sslCert.getSerialNumber(), 168 new SimpleOCSPServer.CertStatusInfo( 169 SimpleOCSPServer.CertStatus.CERT_STATUS_REVOKED, 170 new Date(System.currentTimeMillis() - 171 TimeUnit.HOURS.toMillis(8)))); 172 intOcsp.updateStatusDb(revInfo); 173 174 // Set up revocation checking on the client with no client-side 175 // OCSP fall-back 176 cliParams.pkixParams = new PKIXBuilderParameters(trustStore, 177 new X509CertSelector()); 178 cliParams.pkixParams.setRevocationEnabled(true); 179 Security.setProperty("ocsp.enable", "false"); 180 181 HttpsUrlConnClient sslTest = new HttpsUrlConnClient(cliParams, 182 servParams); 183 TestResult tr = sslTest.getResult(); 184 if (!checkClientValidationFailure(tr.clientExc, BasicReason.REVOKED)) { 185 if (tr.clientExc != null) { 186 throw tr.clientExc; 187 } else { 188 throw new RuntimeException( 189 "Expected client failure, but the client succeeded"); 190 } 191 } 192 193 // In this case the server should also have thrown an exception 194 // because of the client alert 195 if (tr.serverExc instanceof SSLHandshakeException) { 196 if (!tr.serverExc.getMessage().contains( 197 "alert: bad_certificate_status_response")) { 198 throw tr.serverExc; 199 } 200 } 201 202 System.out.println(" PASS"); 203 System.out.println("=====================================\n"); 204 } 205 206 /* 207 * Define the server side of the test. 208 * 209 * If the server prematurely exits, serverReady will be set to true 210 * to avoid infinite hangs. 211 */ 212 void doServerSide(ServerParameters servParams) throws Exception { 213 214 // Selectively enable or disable the feature 215 System.setProperty("jdk.tls.server.enableStatusRequestExtension", 216 Boolean.toString(servParams.enabled)); 217 218 // Set all the other operating parameters 219 System.setProperty("jdk.tls.stapling.cacheSize", 220 Integer.toString(servParams.cacheSize)); 221 System.setProperty("jdk.tls.stapling.cacheLifetime", 222 Integer.toString(servParams.cacheLifetime)); 223 System.setProperty("jdk.tls.stapling.responseTimeout", 224 Integer.toString(servParams.respTimeout)); 225 System.setProperty("jdk.tls.stapling.responderURI", servParams.respUri); 226 System.setProperty("jdk.tls.stapling.responderOverride", 227 Boolean.toString(servParams.respOverride)); 228 System.setProperty("jdk.tls.stapling.ignoreExtensions", 229 Boolean.toString(servParams.ignoreExts)); 230 231 // Set keystores and trust stores for the server 232 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 233 kmf.init(serverKeystore, passwd.toCharArray()); 234 TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 235 tmf.init(trustStore); 236 237 SSLContext sslc = SSLContext.getInstance("TLS"); 238 sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 239 240 SSLServerSocketFactory sslssf = sslc.getServerSocketFactory(); 241 SSLServerSocket sslServerSocket = 242 (SSLServerSocket) sslssf.createServerSocket(serverPort); 243 244 serverPort = sslServerSocket.getLocalPort(); 245 log("Server Port is " + serverPort); 246 247 // Dump the private key in PKCS8 format, not encrypted. This 248 // key dump can be used if the traffic was captured using tcpdump 249 // or wireshark to look into the encrypted packets for debug purposes. 250 if (debug) { 251 byte[] keybytes = serverKeystore.getKey(SSL_ALIAS, 252 passwd.toCharArray()).getEncoded(); 253 PKCS8EncodedKeySpec p8spec = new PKCS8EncodedKeySpec(keybytes); 254 StringBuilder keyPem = new StringBuilder(); 255 keyPem.append("-----BEGIN PRIVATE KEY-----\n"); 256 keyPem.append(B64E.encodeToString(p8spec.getEncoded())).append("\n"); 257 keyPem.append("-----END PRIVATE KEY-----\n"); 258 log("Private key is:\n" + keyPem.toString()); 259 } 260 261 /* 262 * Signal Client, we're ready for his connect. 263 */ 264 serverReady = true; 265 266 try (SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); 267 BufferedReader in = new BufferedReader( 268 new InputStreamReader(sslSocket.getInputStream())); 269 OutputStream out = sslSocket.getOutputStream()) { 270 StringBuilder hdrBldr = new StringBuilder(); 271 String line; 272 while ((line = in.readLine()) != null && !line.isEmpty()) { 273 hdrBldr.append(line).append("\n"); 274 } 275 String headerText = hdrBldr.toString(); 276 log("Header Received: " + headerText.length() + " bytes\n" + 277 headerText); 278 279 StringBuilder sb = new StringBuilder(); 280 sb.append("HTTP/1.0 200 OK\r\n"); 281 sb.append("Date: ").append(utcDateFmt.format(new Date())). 282 append("\r\n"); 283 sb.append("Content-Type: text/html\r\n"); 284 sb.append("Content-Length: ").append(SIMPLE_WEB_PAGE.length()); 285 sb.append("\r\n\r\n"); 286 out.write(sb.toString().getBytes("UTF-8")); 287 out.write(SIMPLE_WEB_PAGE.getBytes("UTF-8")); 288 out.flush(); 289 log("Server replied with:\n" + sb.toString() + SIMPLE_WEB_PAGE); 290 } 291 } 292 293 /* 294 * Define the client side of the test. 295 * 296 * If the server prematurely exits, serverReady will be set to true 297 * to avoid infinite hangs. 298 */ 299 void doClientSide(ClientParameters cliParams) throws Exception { 300 301 // Wait 5 seconds for server ready 302 for (int i = 0; (i < 100 && !serverReady); i++) { 303 Thread.sleep(50); 304 } 305 if (!serverReady) { 306 throw new RuntimeException("Server not ready yet"); 307 } 308 309 // Selectively enable or disable the feature 310 System.setProperty("jdk.tls.client.enableStatusRequestExtension", 311 Boolean.toString(cliParams.enabled)); 312 313 HtucSSLSocketFactory sockFac = new HtucSSLSocketFactory(cliParams); 314 HttpsURLConnection.setDefaultSSLSocketFactory(sockFac); 315 URL location = new URL("https://localhost:" + serverPort); 316 HttpsURLConnection tlsConn = 317 (HttpsURLConnection)location.openConnection(); 318 tlsConn.setConnectTimeout(5000); 319 tlsConn.setReadTimeout(5000); 320 tlsConn.setDoInput(true); 321 322 try (InputStream in = tlsConn.getInputStream()) { 323 // Check the response 324 if (debug && tlsConn.getResponseCode() != 325 HttpURLConnection.HTTP_OK) { 326 log("Received HTTP error: " + tlsConn.getResponseCode() + 327 " - " + tlsConn.getResponseMessage()); 328 throw new IOException("HTTP error: " + 329 tlsConn.getResponseCode()); 330 } 331 332 int contentLength = tlsConn.getContentLength(); 333 if (contentLength == -1) { 334 contentLength = Integer.MAX_VALUE; 335 } 336 byte[] response = new byte[contentLength > 2048 ? 2048 : contentLength]; 337 int total = 0; 338 while (total < contentLength) { 339 int count = in.read(response, total, response.length - total); 340 if (count < 0) 341 break; 342 343 total += count; 344 log("Read " + count + " bytes (" + total + " total)"); 345 if (total >= response.length && total < contentLength) { 346 response = Arrays.copyOf(response, total * 2); 347 } 348 } 349 response = Arrays.copyOf(response, total); 350 String webPage = new String(response, 0, total); 351 if (debug) { 352 log("Web page:\n" + webPage); 353 } 354 } 355 } 356 357 /* 358 * Primary constructor, used to drive remainder of the test. 359 * 360 * Fork off the other side, then do your work. 361 */ 362 HttpsUrlConnClient(ClientParameters cliParams, 363 ServerParameters servParams) throws Exception { 364 Exception startException = null; 365 try { 366 if (separateServerThread) { 367 startServer(servParams, true); 368 startClient(cliParams, false); 369 } else { 370 startClient(cliParams, true); 371 startServer(servParams, false); 372 } 373 } catch (Exception e) { 374 startException = e; 375 } 376 377 /* 378 * Wait for other side to close down. 379 */ 380 if (separateServerThread) { 381 if (serverThread != null) { 382 serverThread.join(); 383 } 384 } else { 385 if (clientThread != null) { 386 clientThread.join(); 387 } 388 } 389 } 390 391 /** 392 * Checks a validation failure to see if it failed for the reason we think 393 * it should. This comes in as an SSLException of some sort, but it 394 * encapsulates a ValidatorException which in turn encapsulates the 395 * CertPathValidatorException we are interested in. 396 * 397 * @param e the exception thrown at the top level 398 * @param reason the underlying CertPathValidatorException BasicReason 399 * we are expecting it to have. 400 * 401 * @return true if the reason matches up, false otherwise. 402 */ 403 static boolean checkClientValidationFailure(Exception e, 404 BasicReason reason) { 405 boolean result = false; 406 407 if (e instanceof SSLException) { 408 Throwable valExc = e.getCause(); 409 if (valExc instanceof sun.security.validator.ValidatorException) { 410 Throwable cause = valExc.getCause(); 411 if (cause instanceof CertPathValidatorException) { 412 CertPathValidatorException cpve = 413 (CertPathValidatorException)cause; 414 if (cpve.getReason() == reason) { 415 result = true; 416 } 417 } 418 } 419 } 420 return result; 421 } 422 423 TestResult getResult() { 424 TestResult tr = new TestResult(); 425 tr.clientExc = clientException; 426 tr.serverExc = serverException; 427 return tr; 428 } 429 430 final void startServer(ServerParameters servParams, boolean newThread) 431 throws Exception { 432 if (newThread) { 433 serverThread = new Thread() { 434 @Override 435 public void run() { 436 try { 437 doServerSide(servParams); 438 } catch (Exception e) { 439 /* 440 * Our server thread just died. 441 * 442 * Release the client, if not active already... 443 */ 444 System.err.println("Server died..."); 445 serverReady = true; 446 serverException = e; 447 } 448 } 449 }; 450 serverThread.start(); 451 } else { 452 try { 453 doServerSide(servParams); 454 } catch (Exception e) { 455 serverException = e; 456 } finally { 457 serverReady = true; 458 } 459 } 460 } 461 462 final void startClient(ClientParameters cliParams, boolean newThread) 463 throws Exception { 464 if (newThread) { 465 clientThread = new Thread() { 466 @Override 467 public void run() { 468 try { 469 doClientSide(cliParams); 470 } catch (Exception e) { 471 /* 472 * Our client thread just died. 473 */ 474 System.err.println("Client died..."); 475 clientException = e; 476 } 477 } 478 }; 479 clientThread.start(); 480 } else { 481 try { 482 doClientSide(cliParams); 483 } catch (Exception e) { 484 clientException = e; 485 } 486 } 487 } 488 489 /** 490 * Creates the PKI components necessary for this test, including 491 * Root CA, Intermediate CA and SSL server certificates, the keystores 492 * for each entity, a client trust store, and starts the OCSP responders. 493 */ 494 private static void createPKI() throws Exception { 495 CertificateBuilder cbld = new CertificateBuilder(); 496 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); 497 keyGen.initialize(2048); 498 KeyStore.Builder keyStoreBuilder = 499 KeyStore.Builder.newInstance("PKCS12", null, 500 new KeyStore.PasswordProtection(passwd.toCharArray())); 501 502 // Generate Root, IntCA, EE keys 503 KeyPair rootCaKP = keyGen.genKeyPair(); 504 log("Generated Root CA KeyPair"); 505 KeyPair intCaKP = keyGen.genKeyPair(); 506 log("Generated Intermediate CA KeyPair"); 507 KeyPair sslKP = keyGen.genKeyPair(); 508 log("Generated SSL Cert KeyPair"); 509 510 // Set up the Root CA Cert 511 cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany"); 512 cbld.setPublicKey(rootCaKP.getPublic()); 513 cbld.setSerialNumber(new BigInteger("1")); 514 // Make a 3 year validity starting from 60 days ago 515 long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60); 516 long end = start + TimeUnit.DAYS.toMillis(1085); 517 cbld.setValidity(new Date(start), new Date(end)); 518 addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic()); 519 addCommonCAExts(cbld); 520 // Make our Root CA Cert! 521 X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(), 522 "SHA256withRSA"); 523 log("Root CA Created:\n" + certInfo(rootCert)); 524 525 // Now build a keystore and add the keys and cert 526 rootKeystore = keyStoreBuilder.getKeyStore(); 527 Certificate[] rootChain = {rootCert}; 528 rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(), 529 passwd.toCharArray(), rootChain); 530 531 // Now fire up the OCSP responder 532 rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null); 533 rootOcsp.enableLog(debug); 534 rootOcsp.setNextUpdateInterval(3600); 535 rootOcsp.start(); 536 537 // Wait 5 seconds for server ready 538 for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) { 539 Thread.sleep(50); 540 } 541 if (!rootOcsp.isServerReady()) { 542 throw new RuntimeException("Server not ready yet"); 543 } 544 545 rootOcspPort = rootOcsp.getPort(); 546 String rootRespURI = "http://localhost:" + rootOcspPort; 547 log("Root OCSP Responder URI is " + rootRespURI); 548 549 // Now that we have the root keystore and OCSP responder we can 550 // create our intermediate CA. 551 cbld.reset(); 552 cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany"); 553 cbld.setPublicKey(intCaKP.getPublic()); 554 cbld.setSerialNumber(new BigInteger("100")); 555 // Make a 2 year validity starting from 30 days ago 556 start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30); 557 end = start + TimeUnit.DAYS.toMillis(730); 558 cbld.setValidity(new Date(start), new Date(end)); 559 addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic()); 560 addCommonCAExts(cbld); 561 cbld.addAIAExt(Collections.singletonList(rootRespURI)); 562 // Make our Intermediate CA Cert! 563 X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(), 564 "SHA256withRSA"); 565 log("Intermediate CA Created:\n" + certInfo(intCaCert)); 566 567 // Provide intermediate CA cert revocation info to the Root CA 568 // OCSP responder. 569 Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo = 570 new HashMap<>(); 571 revInfo.put(intCaCert.getSerialNumber(), 572 new SimpleOCSPServer.CertStatusInfo( 573 SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); 574 rootOcsp.updateStatusDb(revInfo); 575 576 // Now build a keystore and add the keys, chain and root cert as a TA 577 intKeystore = keyStoreBuilder.getKeyStore(); 578 Certificate[] intChain = {intCaCert, rootCert}; 579 intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(), 580 passwd.toCharArray(), intChain); 581 intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert); 582 583 // Now fire up the Intermediate CA OCSP responder 584 intOcsp = new SimpleOCSPServer(intKeystore, passwd, 585 INT_ALIAS, null); 586 intOcsp.enableLog(debug); 587 intOcsp.setNextUpdateInterval(3600); 588 intOcsp.start(); 589 590 // Wait 5 seconds for server ready 591 for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) { 592 Thread.sleep(50); 593 } 594 if (!intOcsp.isServerReady()) { 595 throw new RuntimeException("Server not ready yet"); 596 } 597 598 intOcspPort = intOcsp.getPort(); 599 String intCaRespURI = "http://localhost:" + intOcspPort; 600 log("Intermediate CA OCSP Responder URI is " + intCaRespURI); 601 602 // Last but not least, let's make our SSLCert and add it to its own 603 // Keystore 604 cbld.reset(); 605 cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany"); 606 cbld.setPublicKey(sslKP.getPublic()); 607 cbld.setSerialNumber(new BigInteger("4096")); 608 // Make a 1 year validity starting from 7 days ago 609 start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7); 610 end = start + TimeUnit.DAYS.toMillis(365); 611 cbld.setValidity(new Date(start), new Date(end)); 612 613 // Add extensions 614 addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic()); 615 boolean[] kuBits = {true, false, true, false, false, false, 616 false, false, false}; 617 cbld.addKeyUsageExt(kuBits); 618 List<String> ekuOids = new ArrayList<>(); 619 ekuOids.add("1.3.6.1.5.5.7.3.1"); 620 ekuOids.add("1.3.6.1.5.5.7.3.2"); 621 cbld.addExtendedKeyUsageExt(ekuOids); 622 cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost")); 623 cbld.addAIAExt(Collections.singletonList(intCaRespURI)); 624 // Make our SSL Server Cert! 625 X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(), 626 "SHA256withRSA"); 627 log("SSL Certificate Created:\n" + certInfo(sslCert)); 628 629 // Provide SSL server cert revocation info to the Intermeidate CA 630 // OCSP responder. 631 revInfo = new HashMap<>(); 632 revInfo.put(sslCert.getSerialNumber(), 633 new SimpleOCSPServer.CertStatusInfo( 634 SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); 635 intOcsp.updateStatusDb(revInfo); 636 637 // Now build a keystore and add the keys, chain and root cert as a TA 638 serverKeystore = keyStoreBuilder.getKeyStore(); 639 Certificate[] sslChain = {sslCert, intCaCert, rootCert}; 640 serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(), 641 passwd.toCharArray(), sslChain); 642 serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert); 643 644 // And finally a Trust Store for the client 645 trustStore = keyStoreBuilder.getKeyStore(); 646 trustStore.setCertificateEntry(ROOT_ALIAS, rootCert); 647 } 648 649 private static void addCommonExts(CertificateBuilder cbld, 650 PublicKey subjKey, PublicKey authKey) throws IOException { 651 cbld.addSubjectKeyIdExt(subjKey); 652 cbld.addAuthorityKeyIdExt(authKey); 653 } 654 655 private static void addCommonCAExts(CertificateBuilder cbld) 656 throws IOException { 657 cbld.addBasicConstraintsExt(true, true, -1); 658 // Set key usage bits for digitalSignature, keyCertSign and cRLSign 659 boolean[] kuBitSettings = {true, false, false, false, false, true, 660 true, false, false}; 661 cbld.addKeyUsageExt(kuBitSettings); 662 } 663 664 /** 665 * Helper routine that dumps only a few cert fields rather than 666 * the whole toString() output. 667 * 668 * @param cert an X509Certificate to be displayed 669 * 670 * @return the String output of the issuer, subject and 671 * serial number 672 */ 673 private static String certInfo(X509Certificate cert) { 674 StringBuilder sb = new StringBuilder(); 675 sb.append("Issuer: ").append(cert.getIssuerX500Principal()). 676 append("\n"); 677 sb.append("Subject: ").append(cert.getSubjectX500Principal()). 678 append("\n"); 679 sb.append("Serial: ").append(cert.getSerialNumber()).append("\n"); 680 return sb.toString(); 681 } 682 683 /** 684 * Log a message on stdout 685 * 686 * @param message The message to log 687 */ 688 private static void log(String message) { 689 if (debug) { 690 System.out.println(message); 691 } 692 } 693 694 // The following two classes are Simple nested class to group a handful 695 // of configuration parameters used before starting a client or server. 696 // We'll just access the data members directly for convenience. 697 static class ClientParameters { 698 boolean enabled = true; 699 PKIXBuilderParameters pkixParams = null; 700 PKIXRevocationChecker revChecker = null; 701 702 ClientParameters() { } 703 } 704 705 static class ServerParameters { 706 boolean enabled = true; 707 int cacheSize = 256; 708 int cacheLifetime = 3600; 709 int respTimeout = 5000; 710 String respUri = ""; 711 boolean respOverride = false; 712 boolean ignoreExts = false; 713 714 ServerParameters() { } 715 } 716 717 static class TestResult { 718 Exception serverExc = null; 719 Exception clientExc = null; 720 } 721 722 static class HtucSSLSocketFactory extends SSLSocketFactory { 723 SSLContext sslc = SSLContext.getInstance("TLS"); 724 725 HtucSSLSocketFactory(ClientParameters cliParams) 726 throws GeneralSecurityException { 727 super(); 728 729 // Create the Trust Manager Factory using the PKIX variant 730 TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); 731 732 // If we have a customized pkixParameters then use it 733 if (cliParams.pkixParams != null) { 734 // LIf we have a customized PKIXRevocationChecker, add 735 // it to the PKIXBuilderParameters. 736 if (cliParams.revChecker != null) { 737 cliParams.pkixParams.addCertPathChecker( 738 cliParams.revChecker); 739 } 740 741 ManagerFactoryParameters trustParams = 742 new CertPathTrustManagerParameters( 743 cliParams.pkixParams); 744 tmf.init(trustParams); 745 } else { 746 tmf.init(trustStore); 747 } 748 749 sslc.init(null, tmf.getTrustManagers(), null); 750 } 751 752 @Override 753 public Socket createSocket(Socket s, String host, int port, 754 boolean autoClose) throws IOException { 755 Socket sock = sslc.getSocketFactory().createSocket(s, host, port, 756 autoClose); 757 setCiphers(sock); 758 return sock; 759 } 760 761 @Override 762 public Socket createSocket(InetAddress host, int port) 763 throws IOException { 764 Socket sock = sslc.getSocketFactory().createSocket(host, port); 765 setCiphers(sock); 766 return sock; 767 } 768 769 @Override 770 public Socket createSocket(InetAddress host, int port, 771 InetAddress localAddress, int localPort) throws IOException { 772 Socket sock = sslc.getSocketFactory().createSocket(host, port, 773 localAddress, localPort); 774 setCiphers(sock); 775 return sock; 776 } 777 778 @Override 779 public Socket createSocket(String host, int port) 780 throws IOException { 781 Socket sock = sslc.getSocketFactory().createSocket(host, port); 782 setCiphers(sock); 783 return sock; 784 } 785 786 @Override 787 public Socket createSocket(String host, int port, 788 InetAddress localAddress, int localPort) 789 throws IOException { 790 Socket sock = sslc.getSocketFactory().createSocket(host, port, 791 localAddress, localPort); 792 setCiphers(sock); 793 return sock; 794 } 795 796 @Override 797 public String[] getDefaultCipherSuites() { 798 return sslc.getDefaultSSLParameters().getCipherSuites(); 799 } 800 801 @Override 802 public String[] getSupportedCipherSuites() { 803 return sslc.getSupportedSSLParameters().getCipherSuites(); 804 } 805 806 private static void setCiphers(Socket sock) { 807 if (sock instanceof SSLSocket) { 808 String[] ciphers = { "TLS_RSA_WITH_AES_128_CBC_SHA" }; 809 ((SSLSocket)sock).setEnabledCipherSuites(ciphers); 810 } 811 } 812 } 813 814} 815