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 }