1 /* 2 * Copyright (c) 2015, 2018, 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 36 import java.io.*; 37 import java.math.BigInteger; 38 import java.security.KeyPair; 39 import java.security.KeyPairGenerator; 40 import java.net.Socket; 41 import java.net.URL; 42 import java.net.HttpURLConnection; 43 import java.net.InetAddress; 44 import javax.net.ssl.*; 45 import java.security.KeyStore; 46 import java.security.PublicKey; 47 import java.security.Security; 48 import java.security.GeneralSecurityException; 49 import java.security.cert.CertPathValidatorException; 50 import java.security.cert.CertPathValidatorException.BasicReason; 51 import java.security.cert.Certificate; 52 import java.security.cert.PKIXBuilderParameters; 53 import java.security.cert.X509CertSelector; 54 import java.security.cert.X509Certificate; 55 import java.security.cert.PKIXRevocationChecker; 56 import java.security.spec.PKCS8EncodedKeySpec; 57 import java.text.SimpleDateFormat; 58 import java.util.*; 59 import java.util.concurrent.TimeUnit; 60 61 import sun.security.testlibrary.SimpleOCSPServer; 62 import sun.security.testlibrary.CertificateBuilder; 63 import sun.security.validator.ValidatorException; 64 65 public 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 "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("TLSv1.2"); 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 : 337 contentLength]; 338 int total = 0; 339 while (total < contentLength) { 340 int count = in.read(response, total, response.length - total); 341 if (count < 0) 342 break; 343 344 total += count; 345 log("Read " + count + " bytes (" + total + " total)"); 346 if (total >= response.length && total < contentLength) { 347 response = Arrays.copyOf(response, total * 2); 348 } 349 } 350 response = Arrays.copyOf(response, total); 351 String webPage = new String(response, 0, total); 352 if (debug) { 353 log("Web page:\n" + webPage); 354 } 355 } 356 } 357 358 /* 359 * Primary constructor, used to drive remainder of the test. 360 * 361 * Fork off the other side, then do your work. 362 */ 363 HttpsUrlConnClient(ClientParameters cliParams, 364 ServerParameters servParams) throws Exception { 365 Exception startException = null; 366 try { 367 if (separateServerThread) { 368 startServer(servParams, true); 369 startClient(cliParams, false); 370 } else { 371 startClient(cliParams, true); 372 startServer(servParams, false); 373 } 374 } catch (Exception e) { 375 startException = e; 376 } 377 378 /* 379 * Wait for other side to close down. 380 */ 381 if (separateServerThread) { 382 if (serverThread != null) { 383 serverThread.join(); 384 } 385 } else { 386 if (clientThread != null) { 387 clientThread.join(); 388 } 389 } 390 } 391 392 /** 393 * Checks a validation failure to see if it failed for the reason we think 394 * it should. This comes in as an SSLException of some sort, but it 395 * encapsulates a CertPathValidatorException at some point in the 396 * exception stack. 397 * 398 * @param e the exception thrown at the top level 399 * @param reason the underlying CertPathValidatorException BasicReason 400 * we are expecting it to have. 401 * 402 * @return true if the reason matches up, false otherwise. 403 */ 404 static boolean checkClientValidationFailure(Exception e, 405 BasicReason reason) { 406 boolean result = false; 407 408 // Locate the CertPathValidatorException. If one 409 // Does not exist, then it's an automatic failure of 410 // the test. 411 Throwable curExc = e; 412 CertPathValidatorException cpve = null; 413 while (curExc != null) { 414 if (curExc instanceof CertPathValidatorException) { 415 cpve = (CertPathValidatorException)curExc; 416 } 417 curExc = curExc.getCause(); 418 } 419 420 // If we get through the loop and cpve is null then we 421 // we didn't find CPVE and this is a failure 422 if (cpve != null) { 423 if (cpve.getReason() == reason) { 424 result = true; 425 } else { 426 System.out.println("CPVE Reason Mismatch: Expected = " + 427 reason + ", Actual = " + cpve.getReason()); 428 } 429 } else { 430 System.out.println("Failed to find an expected CPVE"); 431 } 432 433 return result; 434 } 435 436 TestResult getResult() { 437 TestResult tr = new TestResult(); 438 tr.clientExc = clientException; 439 tr.serverExc = serverException; 440 return tr; 441 } 442 443 final void startServer(ServerParameters servParams, boolean newThread) 444 throws Exception { 445 if (newThread) { 446 serverThread = new Thread() { 447 @Override 448 public void run() { 449 try { 450 doServerSide(servParams); 451 } catch (Exception e) { 452 /* 453 * Our server thread just died. 454 * 455 * Release the client, if not active already... 456 */ 457 System.err.println("Server died..."); 458 serverReady = true; 459 serverException = e; 460 } 461 } 462 }; 463 serverThread.start(); 464 } else { 465 try { 466 doServerSide(servParams); 467 } catch (Exception e) { 468 serverException = e; 469 } finally { 470 serverReady = true; 471 } 472 } 473 } 474 475 final void startClient(ClientParameters cliParams, boolean newThread) 476 throws Exception { 477 if (newThread) { 478 clientThread = new Thread() { 479 @Override 480 public void run() { 481 try { 482 doClientSide(cliParams); 483 } catch (Exception e) { 484 /* 485 * Our client thread just died. 486 */ 487 System.err.println("Client died..."); 488 clientException = e; 489 } 490 } 491 }; 492 clientThread.start(); 493 } else { 494 try { 495 doClientSide(cliParams); 496 } catch (Exception e) { 497 clientException = e; 498 } 499 } 500 } 501 502 /** 503 * Creates the PKI components necessary for this test, including 504 * Root CA, Intermediate CA and SSL server certificates, the keystores 505 * for each entity, a client trust store, and starts the OCSP responders. 506 */ 507 private static void createPKI() throws Exception { 508 CertificateBuilder cbld = new CertificateBuilder(); 509 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); 510 keyGen.initialize(2048); 511 KeyStore.Builder keyStoreBuilder = 512 KeyStore.Builder.newInstance("PKCS12", null, 513 new KeyStore.PasswordProtection(passwd.toCharArray())); 514 515 // Generate Root, IntCA, EE keys 516 KeyPair rootCaKP = keyGen.genKeyPair(); 517 log("Generated Root CA KeyPair"); 518 KeyPair intCaKP = keyGen.genKeyPair(); 519 log("Generated Intermediate CA KeyPair"); 520 KeyPair sslKP = keyGen.genKeyPair(); 521 log("Generated SSL Cert KeyPair"); 522 523 // Set up the Root CA Cert 524 cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany"); 525 cbld.setPublicKey(rootCaKP.getPublic()); 526 cbld.setSerialNumber(new BigInteger("1")); 527 // Make a 3 year validity starting from 60 days ago 528 long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60); 529 long end = start + TimeUnit.DAYS.toMillis(1085); 530 cbld.setValidity(new Date(start), new Date(end)); 531 addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic()); 532 addCommonCAExts(cbld); 533 // Make our Root CA Cert! 534 X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(), 535 "SHA256withRSA"); 536 log("Root CA Created:\n" + certInfo(rootCert)); 537 538 // Now build a keystore and add the keys and cert 539 rootKeystore = keyStoreBuilder.getKeyStore(); 540 Certificate[] rootChain = {rootCert}; 541 rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(), 542 passwd.toCharArray(), rootChain); 543 544 // Now fire up the OCSP responder 545 rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null); 546 rootOcsp.enableLog(debug); 547 rootOcsp.setNextUpdateInterval(3600); 548 rootOcsp.start(); 549 550 // Wait 5 seconds for server ready 551 for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) { 552 Thread.sleep(50); 553 } 554 if (!rootOcsp.isServerReady()) { 555 throw new RuntimeException("Server not ready yet"); 556 } 557 558 rootOcspPort = rootOcsp.getPort(); 559 String rootRespURI = "http://localhost:" + rootOcspPort; 560 log("Root OCSP Responder URI is " + rootRespURI); 561 562 // Now that we have the root keystore and OCSP responder we can 563 // create our intermediate CA. 564 cbld.reset(); 565 cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany"); 566 cbld.setPublicKey(intCaKP.getPublic()); 567 cbld.setSerialNumber(new BigInteger("100")); 568 // Make a 2 year validity starting from 30 days ago 569 start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30); 570 end = start + TimeUnit.DAYS.toMillis(730); 571 cbld.setValidity(new Date(start), new Date(end)); 572 addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic()); 573 addCommonCAExts(cbld); 574 cbld.addAIAExt(Collections.singletonList(rootRespURI)); 575 // Make our Intermediate CA Cert! 576 X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(), 577 "SHA256withRSA"); 578 log("Intermediate CA Created:\n" + certInfo(intCaCert)); 579 580 // Provide intermediate CA cert revocation info to the Root CA 581 // OCSP responder. 582 Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo = 583 new HashMap<>(); 584 revInfo.put(intCaCert.getSerialNumber(), 585 new SimpleOCSPServer.CertStatusInfo( 586 SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); 587 rootOcsp.updateStatusDb(revInfo); 588 589 // Now build a keystore and add the keys, chain and root cert as a TA 590 intKeystore = keyStoreBuilder.getKeyStore(); 591 Certificate[] intChain = {intCaCert, rootCert}; 592 intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(), 593 passwd.toCharArray(), intChain); 594 intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert); 595 596 // Now fire up the Intermediate CA OCSP responder 597 intOcsp = new SimpleOCSPServer(intKeystore, passwd, 598 INT_ALIAS, null); 599 intOcsp.enableLog(debug); 600 intOcsp.setNextUpdateInterval(3600); 601 intOcsp.start(); 602 603 // Wait 5 seconds for server ready 604 for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) { 605 Thread.sleep(50); 606 } 607 if (!intOcsp.isServerReady()) { 608 throw new RuntimeException("Server not ready yet"); 609 } 610 611 intOcspPort = intOcsp.getPort(); 612 String intCaRespURI = "http://localhost:" + intOcspPort; 613 log("Intermediate CA OCSP Responder URI is " + intCaRespURI); 614 615 // Last but not least, let's make our SSLCert and add it to its own 616 // Keystore 617 cbld.reset(); 618 cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany"); 619 cbld.setPublicKey(sslKP.getPublic()); 620 cbld.setSerialNumber(new BigInteger("4096")); 621 // Make a 1 year validity starting from 7 days ago 622 start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7); 623 end = start + TimeUnit.DAYS.toMillis(365); 624 cbld.setValidity(new Date(start), new Date(end)); 625 626 // Add extensions 627 addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic()); 628 boolean[] kuBits = {true, false, true, false, false, false, 629 false, false, false}; 630 cbld.addKeyUsageExt(kuBits); 631 List<String> ekuOids = new ArrayList<>(); 632 ekuOids.add("1.3.6.1.5.5.7.3.1"); 633 ekuOids.add("1.3.6.1.5.5.7.3.2"); 634 cbld.addExtendedKeyUsageExt(ekuOids); 635 cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost")); 636 cbld.addAIAExt(Collections.singletonList(intCaRespURI)); 637 // Make our SSL Server Cert! 638 X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(), 639 "SHA256withRSA"); 640 log("SSL Certificate Created:\n" + certInfo(sslCert)); 641 642 // Provide SSL server cert revocation info to the Intermeidate CA 643 // OCSP responder. 644 revInfo = new HashMap<>(); 645 revInfo.put(sslCert.getSerialNumber(), 646 new SimpleOCSPServer.CertStatusInfo( 647 SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); 648 intOcsp.updateStatusDb(revInfo); 649 650 // Now build a keystore and add the keys, chain and root cert as a TA 651 serverKeystore = keyStoreBuilder.getKeyStore(); 652 Certificate[] sslChain = {sslCert, intCaCert, rootCert}; 653 serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(), 654 passwd.toCharArray(), sslChain); 655 serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert); 656 657 // And finally a Trust Store for the client 658 trustStore = keyStoreBuilder.getKeyStore(); 659 trustStore.setCertificateEntry(ROOT_ALIAS, rootCert); 660 } 661 662 private static void addCommonExts(CertificateBuilder cbld, 663 PublicKey subjKey, PublicKey authKey) throws IOException { 664 cbld.addSubjectKeyIdExt(subjKey); 665 cbld.addAuthorityKeyIdExt(authKey); 666 } 667 668 private static void addCommonCAExts(CertificateBuilder cbld) 669 throws IOException { 670 cbld.addBasicConstraintsExt(true, true, -1); 671 // Set key usage bits for digitalSignature, keyCertSign and cRLSign 672 boolean[] kuBitSettings = {true, false, false, false, false, true, 673 true, false, false}; 674 cbld.addKeyUsageExt(kuBitSettings); 675 } 676 677 /** 678 * Helper routine that dumps only a few cert fields rather than 679 * the whole toString() output. 680 * 681 * @param cert an X509Certificate to be displayed 682 * 683 * @return the String output of the issuer, subject and 684 * serial number 685 */ 686 private static String certInfo(X509Certificate cert) { 687 StringBuilder sb = new StringBuilder(); 688 sb.append("Issuer: ").append(cert.getIssuerX500Principal()). 689 append("\n"); 690 sb.append("Subject: ").append(cert.getSubjectX500Principal()). 691 append("\n"); 692 sb.append("Serial: ").append(cert.getSerialNumber()).append("\n"); 693 return sb.toString(); 694 } 695 696 /** 697 * Log a message on stdout 698 * 699 * @param message The message to log 700 */ 701 private static void log(String message) { 702 if (debug) { 703 System.out.println(message); 704 } 705 } 706 707 // The following two classes are Simple nested class to group a handful 708 // of configuration parameters used before starting a client or server. 709 // We'll just access the data members directly for convenience. 710 static class ClientParameters { 711 boolean enabled = true; 712 PKIXBuilderParameters pkixParams = null; 713 PKIXRevocationChecker revChecker = null; 714 715 ClientParameters() { } 716 } 717 718 static class ServerParameters { 719 boolean enabled = true; 720 int cacheSize = 256; 721 int cacheLifetime = 3600; 722 int respTimeout = 5000; 723 String respUri = ""; 724 boolean respOverride = false; 725 boolean ignoreExts = false; 726 727 ServerParameters() { } 728 } 729 730 static class TestResult { 731 Exception serverExc = null; 732 Exception clientExc = null; 733 734 @Override 735 public String toString() { 736 StringBuilder sb = new StringBuilder(); 737 sb.append("Test Result:\n"). 738 append("\tServer Exc = ").append(serverExc).append("\n"). 739 append("\tClient Exc = ").append(clientExc).append("\n"); 740 return sb.toString(); 741 } 742 } 743 744 static class HtucSSLSocketFactory extends SSLSocketFactory { 745 SSLContext sslc = SSLContext.getInstance("TLSv1.2"); 746 747 HtucSSLSocketFactory(ClientParameters cliParams) 748 throws GeneralSecurityException { 749 super(); 750 751 // Create the Trust Manager Factory using the PKIX variant 752 TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); 753 754 // If we have a customized pkixParameters then use it 755 if (cliParams.pkixParams != null) { 756 // LIf we have a customized PKIXRevocationChecker, add 757 // it to the PKIXBuilderParameters. 758 if (cliParams.revChecker != null) { 759 cliParams.pkixParams.addCertPathChecker( 760 cliParams.revChecker); 761 } 762 763 ManagerFactoryParameters trustParams = 764 new CertPathTrustManagerParameters( 765 cliParams.pkixParams); 766 tmf.init(trustParams); 767 } else { 768 tmf.init(trustStore); 769 } 770 771 sslc.init(null, tmf.getTrustManagers(), null); 772 } 773 774 @Override 775 public Socket createSocket(Socket s, String host, int port, 776 boolean autoClose) throws IOException { 777 Socket sock = sslc.getSocketFactory().createSocket(s, host, port, 778 autoClose); 779 setCiphers(sock); 780 return sock; 781 } 782 783 @Override 784 public Socket createSocket(InetAddress host, int port) 785 throws IOException { 786 Socket sock = sslc.getSocketFactory().createSocket(host, port); 787 setCiphers(sock); 788 return sock; 789 } 790 791 @Override 792 public Socket createSocket(InetAddress host, int port, 793 InetAddress localAddress, int localPort) throws IOException { 794 Socket sock = sslc.getSocketFactory().createSocket(host, port, 795 localAddress, localPort); 796 setCiphers(sock); 797 return sock; 798 } 799 800 @Override 801 public Socket createSocket(String host, int port) 802 throws IOException { 803 Socket sock = sslc.getSocketFactory().createSocket(host, port); 804 setCiphers(sock); 805 return sock; 806 } 807 808 @Override 809 public Socket createSocket(String host, int port, 810 InetAddress localAddress, int localPort) 811 throws IOException { 812 Socket sock = sslc.getSocketFactory().createSocket(host, port, 813 localAddress, localPort); 814 setCiphers(sock); 815 return sock; 816 } 817 818 @Override 819 public String[] getDefaultCipherSuites() { 820 return sslc.getDefaultSSLParameters().getCipherSuites(); 821 } 822 823 @Override 824 public String[] getSupportedCipherSuites() { 825 return sslc.getSupportedSSLParameters().getCipherSuites(); 826 } 827 828 private static void setCiphers(Socket sock) { 829 if (sock instanceof SSLSocket) { 830 String[] ciphers = { "TLS_RSA_WITH_AES_128_CBC_SHA" }; 831 ((SSLSocket)sock).setEnabledCipherSuites(ciphers); 832 } 833 } 834 } 835 836 }