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 SSLEngineWithStapling 34 */ 35 36 /** 37 * A SSLEngine usage example which simplifies the presentation 38 * by removing the I/O and multi-threading concerns. 39 * 40 * The test creates two SSLEngines, simulating a client and server. 41 * The "transport" layer consists two byte buffers: think of them 42 * as directly connected pipes. 43 * 44 * Note, this is a *very* simple example: real code will be much more 45 * involved. For example, different threading and I/O models could be 46 * used, transport mechanisms could close unexpectedly, and so on. 47 * 48 * When this application runs, notice that several messages 49 * (wrap/unwrap) pass before any application data is consumed or 50 * produced. (For more information, please see the SSL/TLS 51 * specifications.) There may several steps for a successful handshake, 52 * so it's typical to see the following series of operations: 53 * 54 * client server message 55 * ====== ====== ======= 56 * wrap() ... ClientHello 57 * ... unwrap() ClientHello 58 * ... wrap() ServerHello/Certificate 59 * unwrap() ... ServerHello/Certificate 60 * wrap() ... ClientKeyExchange 61 * wrap() ... ChangeCipherSpec 62 * wrap() ... Finished 63 * ... unwrap() ClientKeyExchange 64 * ... unwrap() ChangeCipherSpec 65 * ... unwrap() Finished 66 * ... wrap() ChangeCipherSpec 67 * ... wrap() Finished 68 * unwrap() ... ChangeCipherSpec 69 * unwrap() ... Finished 70 */ 71 72 import javax.net.ssl.*; 73 import javax.net.ssl.SSLEngineResult.*; 74 import java.io.*; 75 import java.math.BigInteger; 76 import java.security.*; 77 import java.nio.*; 78 import java.security.cert.CertPathValidatorException; 79 import java.security.cert.PKIXBuilderParameters; 80 import java.security.cert.X509Certificate; 81 import java.security.cert.X509CertSelector; 82 import java.util.ArrayList; 83 import java.util.Collections; 84 import java.util.Date; 85 import java.util.HashMap; 86 import java.util.List; 87 import java.util.Map; 88 import java.util.concurrent.TimeUnit; 89 90 import sun.security.testlibrary.SimpleOCSPServer; 91 import sun.security.testlibrary.CertificateBuilder; 92 93 public class SSLEngineWithStapling { 94 95 /* 96 * Enables logging of the SSLEngine operations. 97 */ 98 private static final boolean logging = true; 99 100 /* 101 * Enables the JSSE system debugging system property: 102 * 103 * -Djavax.net.debug=all 104 * 105 * This gives a lot of low-level information about operations underway, 106 * including specific handshake messages, and might be best examined 107 * after gaining some familiarity with this application. 108 */ 109 private static final boolean debug = false; 110 111 private SSLEngine clientEngine; // client Engine 112 private ByteBuffer clientOut; // write side of clientEngine 113 private ByteBuffer clientIn; // read side of clientEngine 114 115 private SSLEngine serverEngine; // server Engine 116 private ByteBuffer serverOut; // write side of serverEngine 117 private ByteBuffer serverIn; // read side of serverEngine 118 119 /* 120 * For data transport, this example uses local ByteBuffers. This 121 * isn't really useful, but the purpose of this example is to show 122 * SSLEngine concepts, not how to do network transport. 123 */ 124 private ByteBuffer cTOs; // "reliable" transport client->server 125 private ByteBuffer sTOc; // "reliable" transport server->client 126 127 /* 128 * The following is to set up the keystores. 129 */ 130 static final String passwd = "passphrase"; 131 static final String ROOT_ALIAS = "root"; 132 static final String INT_ALIAS = "intermediate"; 133 static final String SSL_ALIAS = "ssl"; 134 135 // PKI components we will need for this test 136 static KeyStore rootKeystore; // Root CA Keystore 137 static KeyStore intKeystore; // Intermediate CA Keystore 138 static KeyStore serverKeystore; // SSL Server Keystore 139 static KeyStore trustStore; // SSL Client trust store 140 static SimpleOCSPServer rootOcsp; // Root CA OCSP Responder 141 static int rootOcspPort; // Port number for root OCSP 142 static SimpleOCSPServer intOcsp; // Intermediate CA OCSP Responder 143 static int intOcspPort; // Port number for intermed. OCSP 144 145 /* 146 * Main entry point for this test. 147 */ 148 public static void main(String args[]) throws Exception { 149 if (debug) { 150 System.setProperty("javax.net.debug", "ssl"); 151 } 152 153 // Create the PKI we will use for the test and start the OCSP servers 154 createPKI(); 155 156 // Set the certificate entry in the intermediate OCSP responder 157 // with a revocation date of 8 hours ago. 158 X509Certificate sslCert = 159 (X509Certificate)serverKeystore.getCertificate(SSL_ALIAS); 160 Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo = 161 new HashMap<>(); 162 revInfo.put(sslCert.getSerialNumber(), 163 new SimpleOCSPServer.CertStatusInfo( 164 SimpleOCSPServer.CertStatus.CERT_STATUS_REVOKED, 165 new Date(System.currentTimeMillis() - 166 TimeUnit.HOURS.toMillis(8)))); 167 intOcsp.updateStatusDb(revInfo); 168 169 SSLEngineWithStapling test = new SSLEngineWithStapling(); 170 try { 171 test.runTest(); 172 throw new RuntimeException("Expected failure due to revocation " + 173 "did not occur"); 174 } catch (Exception e) { 175 if (!checkClientValidationFailure(e, 176 CertPathValidatorException.BasicReason.REVOKED)) { 177 System.out.println("*** Didn't find the exception we wanted"); 178 throw e; 179 } 180 } 181 182 System.out.println("Test Passed."); 183 } 184 185 /* 186 * Create an initialized SSLContext to use for these tests. 187 */ 188 public SSLEngineWithStapling() throws Exception { 189 System.setProperty("javax.net.ssl.keyStore", ""); 190 System.setProperty("javax.net.ssl.keyStorePassword", ""); 191 System.setProperty("javax.net.ssl.trustStore", ""); 192 System.setProperty("javax.net.ssl.trustStorePassword", ""); 193 194 // Enable OCSP Stapling on both client and server sides, but turn off 195 // client-side OCSP for revocation checking. This ensures that the 196 // revocation information from the test has to come via stapling. 197 System.setProperty("jdk.tls.client.enableStatusRequestExtension", 198 Boolean.toString(true)); 199 System.setProperty("jdk.tls.server.enableStatusRequestExtension", 200 Boolean.toString(true)); 201 Security.setProperty("ocsp.enable", "false"); 202 } 203 204 /* 205 * Run the test. 206 * 207 * Sit in a tight loop, both engines calling wrap/unwrap regardless 208 * of whether data is available or not. We do this until both engines 209 * report back they are closed. 210 * 211 * The main loop handles all of the I/O phases of the SSLEngine's 212 * lifetime: 213 * 214 * initial handshaking 215 * application data transfer 216 * engine closing 217 * 218 * One could easily separate these phases into separate 219 * sections of code. 220 */ 221 private void runTest() throws Exception { 222 boolean dataDone = false; 223 224 createSSLEngines(); 225 createBuffers(); 226 227 SSLEngineResult clientResult; // results from client's last operation 228 SSLEngineResult serverResult; // results from server's last operation 229 230 /* 231 * Examining the SSLEngineResults could be much more involved, 232 * and may alter the overall flow of the application. 233 * 234 * For example, if we received a BUFFER_OVERFLOW when trying 235 * to write to the output pipe, we could reallocate a larger 236 * pipe, but instead we wait for the peer to drain it. 237 */ 238 while (!isEngineClosed(clientEngine) || 239 !isEngineClosed(serverEngine)) { 240 241 log("================"); 242 243 clientResult = clientEngine.wrap(clientOut, cTOs); 244 log("client wrap: ", clientResult); 245 runDelegatedTasks(clientResult, clientEngine); 246 247 serverResult = serverEngine.wrap(serverOut, sTOc); 248 log("server wrap: ", serverResult); 249 runDelegatedTasks(serverResult, serverEngine); 250 251 cTOs.flip(); 252 sTOc.flip(); 253 254 log("----"); 255 256 clientResult = clientEngine.unwrap(sTOc, clientIn); 257 log("client unwrap: ", clientResult); 258 runDelegatedTasks(clientResult, clientEngine); 259 260 serverResult = serverEngine.unwrap(cTOs, serverIn); 261 log("server unwrap: ", serverResult); 262 runDelegatedTasks(serverResult, serverEngine); 263 264 cTOs.compact(); 265 sTOc.compact(); 266 267 /* 268 * After we've transfered all application data between the client 269 * and server, we close the clientEngine's outbound stream. 270 * This generates a close_notify handshake message, which the 271 * server engine receives and responds by closing itself. 272 */ 273 if (!dataDone && (clientOut.limit() == serverIn.position()) && 274 (serverOut.limit() == clientIn.position())) { 275 276 /* 277 * A sanity check to ensure we got what was sent. 278 */ 279 checkTransfer(serverOut, clientIn); 280 checkTransfer(clientOut, serverIn); 281 282 log("\tClosing clientEngine's *OUTBOUND*..."); 283 clientEngine.closeOutbound(); 284 dataDone = true; 285 } 286 } 287 } 288 289 /* 290 * Using the SSLContext created during object creation, 291 * create/configure the SSLEngines we'll use for this test. 292 */ 293 private void createSSLEngines() throws Exception { 294 // Initialize the KeyManager and TrustManager for the server 295 KeyManagerFactory servKmf = KeyManagerFactory.getInstance("PKIX"); 296 servKmf.init(serverKeystore, passwd.toCharArray()); 297 TrustManagerFactory servTmf = 298 TrustManagerFactory.getInstance("PKIX"); 299 servTmf.init(trustStore); 300 301 // Initialize the TrustManager for the client with revocation checking 302 PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(trustStore, 303 new X509CertSelector()); 304 pkixParams.setRevocationEnabled(true); 305 ManagerFactoryParameters mfp = 306 new CertPathTrustManagerParameters(pkixParams); 307 TrustManagerFactory cliTmf = 308 TrustManagerFactory.getInstance("PKIX"); 309 cliTmf.init(mfp); 310 311 // Create the SSLContexts from the factories 312 SSLContext servCtx = SSLContext.getInstance("TLSv1.2"); 313 servCtx.init(servKmf.getKeyManagers(), servTmf.getTrustManagers(), 314 null); 315 SSLContext cliCtx = SSLContext.getInstance("TLSv1.2"); 316 cliCtx.init(null, cliTmf.getTrustManagers(), null); 317 318 319 /* 320 * Configure the serverEngine to act as a server in the SSL/TLS 321 * handshake. 322 */ 323 serverEngine = servCtx.createSSLEngine(); 324 serverEngine.setUseClientMode(false); 325 serverEngine.setNeedClientAuth(false); 326 327 /* 328 * Similar to above, but using client mode instead. 329 */ 330 clientEngine = cliCtx.createSSLEngine("client", 80); 331 clientEngine.setUseClientMode(true); 332 } 333 334 /* 335 * Create and size the buffers appropriately. 336 */ 337 private void createBuffers() { 338 339 /* 340 * We'll assume the buffer sizes are the same 341 * between client and server. 342 */ 343 SSLSession session = clientEngine.getSession(); 344 int appBufferMax = session.getApplicationBufferSize(); 345 int netBufferMax = session.getPacketBufferSize(); 346 347 /* 348 * We'll make the input buffers a bit bigger than the max needed 349 * size, so that unwrap()s following a successful data transfer 350 * won't generate BUFFER_OVERFLOWS. 351 * 352 * We'll use a mix of direct and indirect ByteBuffers for 353 * tutorial purposes only. In reality, only use direct 354 * ByteBuffers when they give a clear performance enhancement. 355 */ 356 clientIn = ByteBuffer.allocate(appBufferMax + 50); 357 serverIn = ByteBuffer.allocate(appBufferMax + 50); 358 359 cTOs = ByteBuffer.allocateDirect(netBufferMax); 360 sTOc = ByteBuffer.allocateDirect(netBufferMax); 361 362 clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes()); 363 serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes()); 364 } 365 366 /* 367 * If the result indicates that we have outstanding tasks to do, 368 * go ahead and run them in this thread. 369 */ 370 private static void runDelegatedTasks(SSLEngineResult result, 371 SSLEngine engine) throws Exception { 372 373 if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { 374 Runnable runnable; 375 while ((runnable = engine.getDelegatedTask()) != null) { 376 log("\trunning delegated task..."); 377 runnable.run(); 378 } 379 HandshakeStatus hsStatus = engine.getHandshakeStatus(); 380 if (hsStatus == HandshakeStatus.NEED_TASK) { 381 throw new Exception( 382 "handshake shouldn't need additional tasks"); 383 } 384 log("\tnew HandshakeStatus: " + hsStatus); 385 } 386 } 387 388 private static boolean isEngineClosed(SSLEngine engine) { 389 return (engine.isOutboundDone() && engine.isInboundDone()); 390 } 391 392 /* 393 * Simple check to make sure everything came across as expected. 394 */ 395 private static void checkTransfer(ByteBuffer a, ByteBuffer b) 396 throws Exception { 397 a.flip(); 398 b.flip(); 399 400 if (!a.equals(b)) { 401 throw new Exception("Data didn't transfer cleanly"); 402 } else { 403 log("\tData transferred cleanly"); 404 } 405 406 a.position(a.limit()); 407 b.position(b.limit()); 408 a.limit(a.capacity()); 409 b.limit(b.capacity()); 410 } 411 412 /* 413 * Logging code 414 */ 415 private static boolean resultOnce = true; 416 417 private static void log(String str, SSLEngineResult result) { 418 if (!logging) { 419 return; 420 } 421 if (resultOnce) { 422 resultOnce = false; 423 System.out.println("The format of the SSLEngineResult is: \n" + 424 "\t\"getStatus() / getHandshakeStatus()\" +\n" + 425 "\t\"bytesConsumed() / bytesProduced()\"\n"); 426 } 427 HandshakeStatus hsStatus = result.getHandshakeStatus(); 428 log(str + 429 result.getStatus() + "/" + hsStatus + ", " + 430 result.bytesConsumed() + "/" + result.bytesProduced() + 431 " bytes"); 432 if (hsStatus == HandshakeStatus.FINISHED) { 433 log("\t...ready for application data"); 434 } 435 } 436 437 private static void log(String str) { 438 if (logging) { 439 System.out.println(str); 440 } 441 } 442 443 /** 444 * Creates the PKI components necessary for this test, including 445 * Root CA, Intermediate CA and SSL server certificates, the keystores 446 * for each entity, a client trust store, and starts the OCSP responders. 447 */ 448 private static void createPKI() throws Exception { 449 CertificateBuilder cbld = new CertificateBuilder(); 450 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); 451 keyGen.initialize(2048); 452 KeyStore.Builder keyStoreBuilder = 453 KeyStore.Builder.newInstance("PKCS12", null, 454 new KeyStore.PasswordProtection(passwd.toCharArray())); 455 456 // Generate Root, IntCA, EE keys 457 KeyPair rootCaKP = keyGen.genKeyPair(); 458 log("Generated Root CA KeyPair"); 459 KeyPair intCaKP = keyGen.genKeyPair(); 460 log("Generated Intermediate CA KeyPair"); 461 KeyPair sslKP = keyGen.genKeyPair(); 462 log("Generated SSL Cert KeyPair"); 463 464 // Set up the Root CA Cert 465 cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany"); 466 cbld.setPublicKey(rootCaKP.getPublic()); 467 cbld.setSerialNumber(new BigInteger("1")); 468 // Make a 3 year validity starting from 60 days ago 469 long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60); 470 long end = start + TimeUnit.DAYS.toMillis(1085); 471 cbld.setValidity(new Date(start), new Date(end)); 472 addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic()); 473 addCommonCAExts(cbld); 474 // Make our Root CA Cert! 475 X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(), 476 "SHA256withRSA"); 477 log("Root CA Created:\n" + certInfo(rootCert)); 478 479 // Now build a keystore and add the keys and cert 480 rootKeystore = keyStoreBuilder.getKeyStore(); 481 java.security.cert.Certificate[] rootChain = {rootCert}; 482 rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(), 483 passwd.toCharArray(), rootChain); 484 485 // Now fire up the OCSP responder 486 rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null); 487 rootOcsp.enableLog(logging); 488 rootOcsp.setNextUpdateInterval(3600); 489 rootOcsp.start(); 490 491 // Wait 5 seconds for server ready 492 for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) { 493 Thread.sleep(50); 494 } 495 if (!rootOcsp.isServerReady()) { 496 throw new RuntimeException("Server not ready yet"); 497 } 498 499 rootOcspPort = rootOcsp.getPort(); 500 String rootRespURI = "http://localhost:" + rootOcspPort; 501 log("Root OCSP Responder URI is " + rootRespURI); 502 503 // Now that we have the root keystore and OCSP responder we can 504 // create our intermediate CA. 505 cbld.reset(); 506 cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany"); 507 cbld.setPublicKey(intCaKP.getPublic()); 508 cbld.setSerialNumber(new BigInteger("100")); 509 // Make a 2 year validity starting from 30 days ago 510 start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30); 511 end = start + TimeUnit.DAYS.toMillis(730); 512 cbld.setValidity(new Date(start), new Date(end)); 513 addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic()); 514 addCommonCAExts(cbld); 515 cbld.addAIAExt(Collections.singletonList(rootRespURI)); 516 // Make our Intermediate CA Cert! 517 X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(), 518 "SHA256withRSA"); 519 log("Intermediate CA Created:\n" + certInfo(intCaCert)); 520 521 // Provide intermediate CA cert revocation info to the Root CA 522 // OCSP responder. 523 Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo = 524 new HashMap<>(); 525 revInfo.put(intCaCert.getSerialNumber(), 526 new SimpleOCSPServer.CertStatusInfo( 527 SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); 528 rootOcsp.updateStatusDb(revInfo); 529 530 // Now build a keystore and add the keys, chain and root cert as a TA 531 intKeystore = keyStoreBuilder.getKeyStore(); 532 java.security.cert.Certificate[] intChain = {intCaCert, rootCert}; 533 intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(), 534 passwd.toCharArray(), intChain); 535 intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert); 536 537 // Now fire up the Intermediate CA OCSP responder 538 intOcsp = new SimpleOCSPServer(intKeystore, passwd, 539 INT_ALIAS, null); 540 intOcsp.enableLog(logging); 541 intOcsp.setNextUpdateInterval(3600); 542 intOcsp.start(); 543 544 // Wait 5 seconds for server ready 545 for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) { 546 Thread.sleep(50); 547 } 548 if (!intOcsp.isServerReady()) { 549 throw new RuntimeException("Server not ready yet"); 550 } 551 552 intOcspPort = intOcsp.getPort(); 553 String intCaRespURI = "http://localhost:" + intOcspPort; 554 log("Intermediate CA OCSP Responder URI is " + intCaRespURI); 555 556 // Last but not least, let's make our SSLCert and add it to its own 557 // Keystore 558 cbld.reset(); 559 cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany"); 560 cbld.setPublicKey(sslKP.getPublic()); 561 cbld.setSerialNumber(new BigInteger("4096")); 562 // Make a 1 year validity starting from 7 days ago 563 start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7); 564 end = start + TimeUnit.DAYS.toMillis(365); 565 cbld.setValidity(new Date(start), new Date(end)); 566 567 // Add extensions 568 addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic()); 569 boolean[] kuBits = {true, false, true, false, false, false, 570 false, false, false}; 571 cbld.addKeyUsageExt(kuBits); 572 List<String> ekuOids = new ArrayList<>(); 573 ekuOids.add("1.3.6.1.5.5.7.3.1"); 574 ekuOids.add("1.3.6.1.5.5.7.3.2"); 575 cbld.addExtendedKeyUsageExt(ekuOids); 576 cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost")); 577 cbld.addAIAExt(Collections.singletonList(intCaRespURI)); 578 // Make our SSL Server Cert! 579 X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(), 580 "SHA256withRSA"); 581 log("SSL Certificate Created:\n" + certInfo(sslCert)); 582 583 // Provide SSL server cert revocation info to the Intermeidate CA 584 // OCSP responder. 585 revInfo = new HashMap<>(); 586 revInfo.put(sslCert.getSerialNumber(), 587 new SimpleOCSPServer.CertStatusInfo( 588 SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); 589 intOcsp.updateStatusDb(revInfo); 590 591 // Now build a keystore and add the keys, chain and root cert as a TA 592 serverKeystore = keyStoreBuilder.getKeyStore(); 593 java.security.cert.Certificate[] sslChain = {sslCert, intCaCert, rootCert}; 594 serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(), 595 passwd.toCharArray(), sslChain); 596 serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert); 597 598 // And finally a Trust Store for the client 599 trustStore = keyStoreBuilder.getKeyStore(); 600 trustStore.setCertificateEntry(ROOT_ALIAS, rootCert); 601 } 602 603 private static void addCommonExts(CertificateBuilder cbld, 604 PublicKey subjKey, PublicKey authKey) throws IOException { 605 cbld.addSubjectKeyIdExt(subjKey); 606 cbld.addAuthorityKeyIdExt(authKey); 607 } 608 609 private static void addCommonCAExts(CertificateBuilder cbld) 610 throws IOException { 611 cbld.addBasicConstraintsExt(true, true, -1); 612 // Set key usage bits for digitalSignature, keyCertSign and cRLSign 613 boolean[] kuBitSettings = {true, false, false, false, false, true, 614 true, false, false}; 615 cbld.addKeyUsageExt(kuBitSettings); 616 } 617 618 /** 619 * Helper routine that dumps only a few cert fields rather than 620 * the whole toString() output. 621 * 622 * @param cert an X509Certificate to be displayed 623 * 624 * @return the String output of the issuer, subject and 625 * serial number 626 */ 627 private static String certInfo(X509Certificate cert) { 628 StringBuilder sb = new StringBuilder(); 629 sb.append("Issuer: ").append(cert.getIssuerX500Principal()). 630 append("\n"); 631 sb.append("Subject: ").append(cert.getSubjectX500Principal()). 632 append("\n"); 633 sb.append("Serial: ").append(cert.getSerialNumber()).append("\n"); 634 return sb.toString(); 635 } 636 637 /** 638 * Checks a validation failure to see if it failed for the reason we think 639 * it should. This comes in as an SSLException of some sort, but it 640 * encapsulates a CertPathValidatorException at some point in the 641 * exception stack. 642 * 643 * @param e the exception thrown at the top level 644 * @param reason the underlying CertPathValidatorException BasicReason 645 * we are expecting it to have. 646 * 647 * @return true if the reason matches up, false otherwise. 648 */ 649 static boolean checkClientValidationFailure(Exception e, 650 CertPathValidatorException.BasicReason reason) { 651 boolean result = false; 652 653 // Locate the CertPathValidatorException. If one 654 // Does not exist, then it's an automatic failure of 655 // the test. 656 Throwable curExc = e; 657 CertPathValidatorException cpve = null; 658 while (curExc != null) { 659 if (curExc instanceof CertPathValidatorException) { 660 cpve = (CertPathValidatorException)curExc; 661 } 662 curExc = curExc.getCause(); 663 } 664 665 // If we get through the loop and cpve is null then we 666 // we didn't find CPVE and this is a failure 667 if (cpve != null) { 668 if (cpve.getReason() == reason) { 669 result = true; 670 } else { 671 System.out.println("CPVE Reason Mismatch: Expected = " + 672 reason + ", Actual = " + cpve.getReason()); 673 } 674 } else { 675 System.out.println("Failed to find an expected CPVE"); 676 } 677 678 return result; 679 } 680 }