1 /*
   2  * Copyright (c) 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 8145854 8153829
  30  * @summary SSLContextImpl.statusResponseManager should be generated if required
  31  * @library ../../../../java/security/testlibrary
  32  * @build CertificateBuilder SimpleOCSPServer
  33  * @run main/othervm StapleEnableProps
  34  */
  35 
  36 import javax.net.ssl.*;
  37 import javax.net.ssl.SSLEngineResult.*;
  38 import java.io.*;
  39 import java.math.BigInteger;
  40 import java.security.*;
  41 import java.nio.*;
  42 import java.security.cert.X509Certificate;
  43 import java.util.ArrayList;
  44 import java.util.Collections;
  45 import java.util.Date;
  46 import java.util.HashMap;
  47 import java.util.List;
  48 import java.util.Map;
  49 import java.util.Objects;
  50 import java.util.concurrent.TimeUnit;
  51 
  52 import sun.security.testlibrary.SimpleOCSPServer;
  53 import sun.security.testlibrary.CertificateBuilder;
  54 
  55 public class StapleEnableProps {
  56 
  57     /*
  58      * Enables logging of the SSLEngine operations.
  59      */
  60     private static final boolean logging = true;
  61 
  62     /*
  63      * Enables the JSSE system debugging system property:
  64      *
  65      *     -Djavax.net.debug=all
  66      *
  67      * This gives a lot of low-level information about operations underway,
  68      * including specific handshake messages, and might be best examined
  69      * after gaining some familiarity with this application.
  70      */
  71     private static final boolean debug = false;
  72 
  73     // These two ByteBuffer references will be used to hang onto ClientHello
  74     // messages with and without the status_request[_v2] extensions.  These
  75     // will be used in the server-side stapling tests.
  76     private static ByteBuffer cHelloStaple;
  77     private static ByteBuffer cHelloNoStaple;
  78 
  79     // The following items are used to set up the keystores.
  80     private static final String passwd = "passphrase";
  81     private static final String ROOT_ALIAS = "root";
  82     private static final String INT_ALIAS = "intermediate";
  83     private static final String SSL_ALIAS = "ssl";
  84 
  85     // PKI components we will need for this test
  86     private static KeyManagerFactory kmf;
  87     private static TrustManagerFactory tmf;
  88     private static KeyStore rootKeystore;       // Root CA Keystore
  89     private static KeyStore intKeystore;        // Intermediate CA Keystore
  90     private static KeyStore serverKeystore;     // SSL Server Keystore
  91     private static KeyStore trustStore;         // SSL Client trust store
  92     private static SimpleOCSPServer rootOcsp;   // Root CA OCSP Responder
  93     private static int rootOcspPort;            // Port for root OCSP
  94     private static SimpleOCSPServer intOcsp;    // Intermediate CA OCSP server
  95     private static int intOcspPort;             // Port for intermediate OCSP
  96 
  97     // A few helpful TLS definitions to make it easier
  98     private static final int HELLO_EXT_STATUS_REQ = 5;
  99     private static final int HELLO_EXT_STATUS_REQ_V2 = 17;
 100 
 101     /*
 102      * Main entry point for this test.
 103      */
 104     public static void main(String args[]) throws Exception {
 105         if (debug) {
 106             System.setProperty("javax.net.debug", "ssl");
 107         }
 108 
 109         // Create the PKI we will use for the test and start the OCSP servers
 110         createPKI();
 111 
 112         // Set up the KeyManagerFactory and TrustManagerFactory
 113         kmf = KeyManagerFactory.getInstance("PKIX");
 114         kmf.init(serverKeystore, passwd.toCharArray());
 115         tmf = TrustManagerFactory.getInstance("PKIX");
 116         tmf.init(trustStore);
 117 
 118         // Run the client and server property tests
 119         testClientProp();
 120         testServerProp();
 121 
 122     }
 123 
 124     private static void testClientProp() throws Exception {
 125         SSLEngineResult clientResult;
 126 
 127         // Test with the client-side enable property set to true
 128         System.out.println("=========================================");
 129         System.out.println("Client Test 1: " +
 130                 "jdk.tls.client.enableStatusRequestExtension = true");
 131         System.out.println("=========================================");
 132 
 133         System.setProperty("jdk.tls.client.enableStatusRequestExtension",
 134                 "true");
 135         SSLContext ctxStaple = SSLContext.getInstance("TLS");
 136         ctxStaple.init(null, tmf.getTrustManagers(), null);
 137         SSLEngine engine = ctxStaple.createSSLEngine();
 138         engine.setUseClientMode(true);
 139         SSLSession session = engine.getSession();
 140         ByteBuffer clientOut = ByteBuffer.wrap("I'm a Client".getBytes());
 141         ByteBuffer cTOs =
 142                 ByteBuffer.allocateDirect(session.getPacketBufferSize());
 143 
 144         // Create and check the ClientHello message
 145         clientResult = engine.wrap(clientOut, cTOs);
 146         log("client wrap: ", clientResult);
 147         if (clientResult.getStatus() != SSLEngineResult.Status.OK) {
 148             throw new SSLException("Client wrap got status: " +
 149                     clientResult.getStatus());
 150         }
 151         cTOs.flip();
 152         System.out.println(dumpHexBytes(cTOs));
 153         checkClientHello(cTOs, true, true);
 154         cHelloStaple = cTOs;
 155 
 156         // Test with the property set to false
 157         System.out.println("=========================================");
 158         System.out.println("Client Test 2: " +
 159                 "jdk.tls.client.enableStatusRequestExtension = false");
 160         System.out.println("=========================================");
 161 
 162         System.setProperty("jdk.tls.client.enableStatusRequestExtension",
 163                 "false");
 164         SSLContext ctxNoStaple = SSLContext.getInstance("TLS");
 165         ctxNoStaple.init(null, tmf.getTrustManagers(), null);
 166         engine = ctxNoStaple.createSSLEngine();
 167         engine.setUseClientMode(true);
 168         session = engine.getSession();
 169         cTOs = ByteBuffer.allocateDirect(session.getPacketBufferSize());
 170 
 171         // Create and check the ClientHello message
 172         clientResult = engine.wrap(clientOut, cTOs);
 173         log("client wrap: ", clientResult);
 174         if (clientResult.getStatus() != SSLEngineResult.Status.OK) {
 175             throw new SSLException("Client wrap got status: " +
 176                     clientResult.getStatus());
 177         }
 178         cTOs.flip();
 179         System.out.println(dumpHexBytes(cTOs));
 180         checkClientHello(cTOs, false, false);
 181         cHelloNoStaple = cTOs;
 182     }
 183 
 184     private static void testServerProp() throws Exception {
 185         SSLEngineResult serverResult;
 186         HandshakeStatus hsStat;
 187 
 188         // Test with the server-side enable property set to true
 189         System.out.println("=========================================");
 190         System.out.println("Server Test 1: " +
 191                 "jdk.tls.server.enableStatusRequestExtension = true");
 192         System.out.println("=========================================");
 193 
 194         System.setProperty("jdk.tls.server.enableStatusRequestExtension",
 195                 "true");
 196         SSLContext ctxStaple = SSLContext.getInstance("TLS");
 197         ctxStaple.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 198         SSLEngine engine = ctxStaple.createSSLEngine();
 199         engine.setUseClientMode(false);
 200         SSLSession session = engine.getSession();
 201         ByteBuffer serverOut = ByteBuffer.wrap("I'm a Server".getBytes());
 202         ByteBuffer serverIn =
 203                 ByteBuffer.allocate(session.getApplicationBufferSize() + 50);
 204         ByteBuffer sTOc =
 205                 ByteBuffer.allocateDirect(session.getPacketBufferSize());
 206 
 207         // Consume the client hello
 208         serverResult = engine.unwrap(cHelloStaple, serverIn);
 209         log("server unwrap: ", serverResult);
 210         if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
 211             throw new SSLException("Server unwrap got status: " +
 212                     serverResult.getStatus());
 213         } else if (serverResult.getHandshakeStatus() !=
 214                 SSLEngineResult.HandshakeStatus.NEED_TASK) {
 215              throw new SSLException("Server unwrap expected NEED_TASK, got: " +
 216                     serverResult.getHandshakeStatus());
 217         }
 218         runDelegatedTasks(serverResult, engine);
 219         if (engine.getHandshakeStatus() !=
 220                 SSLEngineResult.HandshakeStatus.NEED_WRAP) {
 221             throw new SSLException("Expected NEED_WRAP, got: " +
 222                     engine.getHandshakeStatus());
 223         }
 224 
 225         // Generate a TLS record with the ServerHello
 226         serverResult = engine.wrap(serverOut, sTOc);
 227         log("client wrap: ", serverResult);
 228         if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
 229             throw new SSLException("Client wrap got status: " +
 230                     serverResult.getStatus());
 231         }
 232         sTOc.flip();
 233         System.out.println(dumpHexBytes(sTOc));
 234         checkServerHello(sTOc, false, true);
 235 
 236         // Flip the client hello so we can reuse it in the next test.
 237         cHelloStaple.flip();
 238 
 239         // Test with the server-side enable property set to false
 240         System.out.println("=========================================");
 241         System.out.println("Server Test 2: " +
 242                 "jdk.tls.server.enableStatusRequestExtension = false");
 243         System.out.println("=========================================");
 244 
 245         System.setProperty("jdk.tls.server.enableStatusRequestExtension",
 246                 "false");
 247         SSLContext ctxNoStaple = SSLContext.getInstance("TLS");
 248         ctxNoStaple.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 249         engine = ctxNoStaple.createSSLEngine();
 250         engine.setUseClientMode(false);
 251         session = engine.getSession();
 252         serverIn = ByteBuffer.allocate(session.getApplicationBufferSize() + 50);
 253         sTOc = ByteBuffer.allocateDirect(session.getPacketBufferSize());
 254 
 255         // Consume the client hello
 256         serverResult = engine.unwrap(cHelloStaple, serverIn);
 257         log("server unwrap: ", serverResult);
 258         if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
 259             throw new SSLException("Server unwrap got status: " +
 260                     serverResult.getStatus());
 261         } else if (serverResult.getHandshakeStatus() !=
 262                 SSLEngineResult.HandshakeStatus.NEED_TASK) {
 263              throw new SSLException("Server unwrap expected NEED_TASK, got: " +
 264                     serverResult.getHandshakeStatus());
 265         }
 266         runDelegatedTasks(serverResult, engine);
 267         if (engine.getHandshakeStatus() !=
 268                 SSLEngineResult.HandshakeStatus.NEED_WRAP) {
 269             throw new SSLException("Expected NEED_WRAP, got: " +
 270                     engine.getHandshakeStatus());
 271         }
 272 
 273         // Generate a TLS record with the ServerHello
 274         serverResult = engine.wrap(serverOut, sTOc);
 275         log("client wrap: ", serverResult);
 276         if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
 277             throw new SSLException("Client wrap got status: " +
 278                     serverResult.getStatus());
 279         }
 280         sTOc.flip();
 281         System.out.println(dumpHexBytes(sTOc));
 282         checkServerHello(sTOc, false, false);
 283     }
 284 
 285     /*
 286      * If the result indicates that we have outstanding tasks to do,
 287      * go ahead and run them in this thread.
 288      */
 289     private static void runDelegatedTasks(SSLEngineResult result,
 290             SSLEngine engine) throws Exception {
 291 
 292         if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
 293             Runnable runnable;
 294             while ((runnable = engine.getDelegatedTask()) != null) {
 295                 log("\trunning delegated task...");
 296                 runnable.run();
 297             }
 298             HandshakeStatus hsStatus = engine.getHandshakeStatus();
 299             if (hsStatus == HandshakeStatus.NEED_TASK) {
 300                 throw new Exception(
 301                     "handshake shouldn't need additional tasks");
 302             }
 303             log("\tnew HandshakeStatus: " + hsStatus);
 304         }
 305     }
 306 
 307     private static void log(String str, SSLEngineResult result) {
 308         if (!logging) {
 309             return;
 310         }
 311         HandshakeStatus hsStatus = result.getHandshakeStatus();
 312         log(str +
 313             result.getStatus() + "/" + hsStatus + ", " +
 314             result.bytesConsumed() + "/" + result.bytesProduced() +
 315             " bytes");
 316         if (hsStatus == HandshakeStatus.FINISHED) {
 317             log("\t...ready for application data");
 318         }
 319     }
 320 
 321     private static void log(String str) {
 322         if (logging) {
 323             System.out.println(str);
 324         }
 325     }
 326 
 327     /**
 328      * Dump a ByteBuffer as a hexdump to stdout.  The dumping routine will
 329      * start at the current position of the buffer and run to its limit.
 330      * After completing the dump, the position will be returned to its
 331      * starting point.
 332      *
 333      * @param data the ByteBuffer to dump to stdout.
 334      *
 335      * @return the hexdump of the byte array.
 336      */
 337     private static String dumpHexBytes(ByteBuffer data) {
 338         StringBuilder sb = new StringBuilder();
 339         if (data != null) {
 340             int i = 0;
 341             data.mark();
 342             while (data.hasRemaining()) {
 343                 if (i % 16 == 0 && i != 0) {
 344                     sb.append("\n");
 345                 }
 346                 sb.append(String.format("%02X ", data.get()));
 347                 i++;
 348             }
 349             data.reset();
 350         }
 351 
 352         return sb.toString();
 353     }
 354 
 355     /**
 356      * Tests the ClientHello for the presence (or not) of the status_request
 357      * and status_request_v2 hello extensions.  It is assumed that the provided
 358      * ByteBuffer has its position set at the first byte of the TLS record
 359      * containing the ClientHello and contains the entire hello message.  Upon
 360      * successful completion of this method the ByteBuffer will have its
 361      * position reset to the initial offset in the buffer.  If an exception is
 362      * thrown the position at the time of the exception will be preserved.
 363      *
 364      * @param data the ByteBuffer containing the ClientHello bytes
 365      * @param statReqPresent true if the status_request hello extension should
 366      * be present.
 367      * @param statReqV2Present true if the status_request_v2 hello extension
 368      * should be present.
 369      *
 370      * @throws SSLException if the presence or lack of either the
 371      * status_request or status_request_v2 extensions is inconsistent with
 372      * the expected settings in the statReqPresent or statReqV2Present
 373      * parameters.
 374      */
 375     private static void checkClientHello(ByteBuffer data,
 376             boolean statReqPresent, boolean statReqV2Present)
 377             throws SSLException {
 378         boolean hasV1 = false;
 379         boolean hasV2 = false;
 380         Objects.requireNonNull(data);
 381         data.mark();
 382 
 383         // Process the TLS record header
 384         int type = Byte.toUnsignedInt(data.get());
 385         int ver_major = Byte.toUnsignedInt(data.get());
 386         int ver_minor = Byte.toUnsignedInt(data.get());
 387         int recLen = Short.toUnsignedInt(data.getShort());
 388 
 389         // Simple sanity checks
 390         if (type != 22) {
 391             throw new SSLException("Not a handshake: Type = " + type);
 392         } else if (recLen > data.remaining()) {
 393             throw new SSLException("Incomplete record in buffer: " +
 394                     "Record length = " + recLen + ", Remaining = " +
 395                     data.remaining());
 396         }
 397 
 398         // Grab the handshake message header.
 399         int msgHdr = data.getInt();
 400         int msgType = (msgHdr >> 24) & 0x000000FF;
 401         int msgLen = msgHdr & 0x00FFFFFF;
 402 
 403         // More simple sanity checks
 404         if (msgType != 1) {
 405             throw new SSLException("Not a ClientHello: Type = " + msgType);
 406         }
 407 
 408         // Skip over the protocol version and client random
 409         data.position(data.position() + 34);
 410 
 411         // Jump past the session ID (if there is one)
 412         int sessLen = Byte.toUnsignedInt(data.get());
 413         if (sessLen != 0) {
 414             data.position(data.position() + sessLen);
 415         }
 416 
 417         // Jump past the cipher suites
 418         int csLen = Short.toUnsignedInt(data.getShort());
 419         if (csLen != 0) {
 420             data.position(data.position() + csLen);
 421         }
 422 
 423         // ...and the compression
 424         int compLen = Byte.toUnsignedInt(data.get());
 425         if (compLen != 0) {
 426             data.position(data.position() + compLen);
 427         }
 428 
 429         // Now for the fun part.  Go through the extensions and look
 430         // for the two status request exts.
 431         int extsLen = Short.toUnsignedInt(data.getShort());
 432         while (data.hasRemaining()) {
 433             int extType = Short.toUnsignedInt(data.getShort());
 434             int extLen = Short.toUnsignedInt(data.getShort());
 435             hasV1 |= (extType == HELLO_EXT_STATUS_REQ);
 436             hasV2 |= (extType == HELLO_EXT_STATUS_REQ_V2);
 437             data.position(data.position() + extLen);
 438         }
 439 
 440         if (hasV1 != statReqPresent) {
 441             throw new SSLException("The status_request extension is " +
 442                     "inconsistent with the expected result: expected = " +
 443                     statReqPresent + ", actual = " + hasV1);
 444         } else if (hasV2 != statReqV2Present) {
 445             throw new SSLException("The status_request_v2 extension is " +
 446                     "inconsistent with the expected result: expected = " +
 447                     statReqV2Present + ", actual = " + hasV2);
 448         }
 449 
 450         // We should be at the end of the ClientHello
 451         data.reset();
 452     }
 453 
 454     /**
 455      * Tests the ServerHello for the presence (or not) of the status_request
 456      * or status_request_v2 hello extension.  It is assumed that the provided
 457      * ByteBuffer has its position set at the first byte of the TLS record
 458      * containing the ServerHello and contains the entire hello message.  Upon
 459      * successful completion of this method the ByteBuffer will have its
 460      * position reset to the initial offset in the buffer.  If an exception is
 461      * thrown the position at the time of the exception will be preserved.
 462      *
 463      * @param statReqPresent true if the status_request hello extension should
 464      * be present.
 465      * @param statReqV2Present true if the status_request_v2 hello extension
 466      * should be present.
 467      *
 468      * @throws SSLException if the presence or lack of either the
 469      * status_request or status_request_v2 extensions is inconsistent with
 470      * the expected settings in the statReqPresent or statReqV2Present
 471      * parameters.
 472      */
 473     private static void checkServerHello(ByteBuffer data,
 474             boolean statReqPresent, boolean statReqV2Present)
 475             throws SSLException {
 476         boolean hasV1 = false;
 477         boolean hasV2 = false;
 478         Objects.requireNonNull(data);
 479         int startPos = data.position();
 480         data.mark();
 481 
 482         // Process the TLS record header
 483         int type = Byte.toUnsignedInt(data.get());
 484         int ver_major = Byte.toUnsignedInt(data.get());
 485         int ver_minor = Byte.toUnsignedInt(data.get());
 486         int recLen = Short.toUnsignedInt(data.getShort());
 487 
 488         // Simple sanity checks
 489         if (type != 22) {
 490             throw new SSLException("Not a handshake: Type = " + type);
 491         } else if (recLen > data.remaining()) {
 492             throw new SSLException("Incomplete record in buffer: " +
 493                     "Record length = " + recLen + ", Remaining = " +
 494                     data.remaining());
 495         }
 496 
 497         // Grab the handshake message header.
 498         int msgHdr = data.getInt();
 499         int msgType = (msgHdr >> 24) & 0x000000FF;
 500         int msgLen = msgHdr & 0x00FFFFFF;
 501 
 502         // More simple sanity checks
 503         if (msgType != 2) {
 504             throw new SSLException("Not a ServerHello: Type = " + msgType);
 505         }
 506 
 507         // Skip over the protocol version and server random
 508         data.position(data.position() + 34);
 509 
 510         // Jump past the session ID
 511         int sessLen = Byte.toUnsignedInt(data.get());
 512         if (sessLen != 0) {
 513             data.position(data.position() + sessLen);
 514         }
 515 
 516         // Skip the cipher suite and compression method
 517         data.position(data.position() + 3);
 518 
 519         // Go through the extensions and look for the request extension
 520         // expected by the caller.
 521         int extsLen = Short.toUnsignedInt(data.getShort());
 522         while (data.position() < recLen + startPos + 5) {
 523             int extType = Short.toUnsignedInt(data.getShort());
 524             int extLen = Short.toUnsignedInt(data.getShort());
 525             hasV1 |= (extType == HELLO_EXT_STATUS_REQ);
 526             hasV2 |= (extType == HELLO_EXT_STATUS_REQ_V2);
 527             data.position(data.position() + extLen);
 528         }
 529 
 530         if (hasV1 != statReqPresent) {
 531             throw new SSLException("The status_request extension is " +
 532                     "inconsistent with the expected result: expected = " +
 533                     statReqPresent + ", actual = " + hasV1);
 534         } else if (hasV2 != statReqV2Present) {
 535             throw new SSLException("The status_request_v2 extension is " +
 536                     "inconsistent with the expected result: expected = " +
 537                     statReqV2Present + ", actual = " + hasV2);
 538         }
 539 
 540         // Reset the position to the initial spot at the start of this method.
 541         data.reset();
 542     }
 543 
 544     /**
 545      * Creates the PKI components necessary for this test, including
 546      * Root CA, Intermediate CA and SSL server certificates, the keystores
 547      * for each entity, a client trust store, and starts the OCSP responders.
 548      */
 549     private static void createPKI() throws Exception {
 550         CertificateBuilder cbld = new CertificateBuilder();
 551         KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
 552         keyGen.initialize(2048);
 553         KeyStore.Builder keyStoreBuilder =
 554                 KeyStore.Builder.newInstance("PKCS12", null,
 555                         new KeyStore.PasswordProtection(passwd.toCharArray()));
 556 
 557         // Generate Root, IntCA, EE keys
 558         KeyPair rootCaKP = keyGen.genKeyPair();
 559         log("Generated Root CA KeyPair");
 560         KeyPair intCaKP = keyGen.genKeyPair();
 561         log("Generated Intermediate CA KeyPair");
 562         KeyPair sslKP = keyGen.genKeyPair();
 563         log("Generated SSL Cert KeyPair");
 564 
 565         // Set up the Root CA Cert
 566         cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany");
 567         cbld.setPublicKey(rootCaKP.getPublic());
 568         cbld.setSerialNumber(new BigInteger("1"));
 569         // Make a 3 year validity starting from 60 days ago
 570         long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60);
 571         long end = start + TimeUnit.DAYS.toMillis(1085);
 572         cbld.setValidity(new Date(start), new Date(end));
 573         addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic());
 574         addCommonCAExts(cbld);
 575         // Make our Root CA Cert!
 576         X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(),
 577                 "SHA256withRSA");
 578         log("Root CA Created:\n" + certInfo(rootCert));
 579 
 580         // Now build a keystore and add the keys and cert
 581         rootKeystore = keyStoreBuilder.getKeyStore();
 582         java.security.cert.Certificate[] rootChain = {rootCert};
 583         rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(),
 584                 passwd.toCharArray(), rootChain);
 585 
 586         // Now fire up the OCSP responder
 587         rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null);
 588         rootOcsp.enableLog(logging);
 589         rootOcsp.setNextUpdateInterval(3600);
 590         rootOcsp.start();
 591 
 592         // Wait 5 seconds for server ready
 593         for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) {
 594             Thread.sleep(50);
 595         }
 596         if (!rootOcsp.isServerReady()) {
 597             throw new RuntimeException("Server not ready yet");
 598         }
 599 
 600         rootOcspPort = rootOcsp.getPort();
 601         String rootRespURI = "http://localhost:" + rootOcspPort;
 602         log("Root OCSP Responder URI is " + rootRespURI);
 603 
 604         // Now that we have the root keystore and OCSP responder we can
 605         // create our intermediate CA.
 606         cbld.reset();
 607         cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany");
 608         cbld.setPublicKey(intCaKP.getPublic());
 609         cbld.setSerialNumber(new BigInteger("100"));
 610         // Make a 2 year validity starting from 30 days ago
 611         start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30);
 612         end = start + TimeUnit.DAYS.toMillis(730);
 613         cbld.setValidity(new Date(start), new Date(end));
 614         addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic());
 615         addCommonCAExts(cbld);
 616         cbld.addAIAExt(Collections.singletonList(rootRespURI));
 617         // Make our Intermediate CA Cert!
 618         X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(),
 619                 "SHA256withRSA");
 620         log("Intermediate CA Created:\n" + certInfo(intCaCert));
 621 
 622         // Provide intermediate CA cert revocation info to the Root CA
 623         // OCSP responder.
 624         Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
 625             new HashMap<>();
 626         revInfo.put(intCaCert.getSerialNumber(),
 627                 new SimpleOCSPServer.CertStatusInfo(
 628                         SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
 629         rootOcsp.updateStatusDb(revInfo);
 630 
 631         // Now build a keystore and add the keys, chain and root cert as a TA
 632         intKeystore = keyStoreBuilder.getKeyStore();
 633         java.security.cert.Certificate[] intChain = {intCaCert, rootCert};
 634         intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(),
 635                 passwd.toCharArray(), intChain);
 636         intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
 637 
 638         // Now fire up the Intermediate CA OCSP responder
 639         intOcsp = new SimpleOCSPServer(intKeystore, passwd,
 640                 INT_ALIAS, null);
 641         intOcsp.enableLog(logging);
 642         intOcsp.setNextUpdateInterval(3600);
 643         intOcsp.start();
 644 
 645         // Wait 5 seconds for server ready
 646         for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) {
 647             Thread.sleep(50);
 648         }
 649         if (!intOcsp.isServerReady()) {
 650             throw new RuntimeException("Server not ready yet");
 651         }
 652 
 653         intOcspPort = intOcsp.getPort();
 654         String intCaRespURI = "http://localhost:" + intOcspPort;
 655         log("Intermediate CA OCSP Responder URI is " + intCaRespURI);
 656 
 657         // Last but not least, let's make our SSLCert and add it to its own
 658         // Keystore
 659         cbld.reset();
 660         cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany");
 661         cbld.setPublicKey(sslKP.getPublic());
 662         cbld.setSerialNumber(new BigInteger("4096"));
 663         // Make a 1 year validity starting from 7 days ago
 664         start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);
 665         end = start + TimeUnit.DAYS.toMillis(365);
 666         cbld.setValidity(new Date(start), new Date(end));
 667 
 668         // Add extensions
 669         addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic());
 670         boolean[] kuBits = {true, false, true, false, false, false,
 671             false, false, false};
 672         cbld.addKeyUsageExt(kuBits);
 673         List<String> ekuOids = new ArrayList<>();
 674         ekuOids.add("1.3.6.1.5.5.7.3.1");
 675         ekuOids.add("1.3.6.1.5.5.7.3.2");
 676         cbld.addExtendedKeyUsageExt(ekuOids);
 677         cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost"));
 678         cbld.addAIAExt(Collections.singletonList(intCaRespURI));
 679         // Make our SSL Server Cert!
 680         X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(),
 681                 "SHA256withRSA");
 682         log("SSL Certificate Created:\n" + certInfo(sslCert));
 683 
 684         // Provide SSL server cert revocation info to the Intermeidate CA
 685         // OCSP responder.
 686         revInfo = new HashMap<>();
 687         revInfo.put(sslCert.getSerialNumber(),
 688                 new SimpleOCSPServer.CertStatusInfo(
 689                         SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
 690         intOcsp.updateStatusDb(revInfo);
 691 
 692         // Now build a keystore and add the keys, chain and root cert as a TA
 693         serverKeystore = keyStoreBuilder.getKeyStore();
 694         java.security.cert.Certificate[] sslChain = {sslCert, intCaCert, rootCert};
 695         serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(),
 696                 passwd.toCharArray(), sslChain);
 697         serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
 698 
 699         // And finally a Trust Store for the client
 700         trustStore = keyStoreBuilder.getKeyStore();
 701         trustStore.setCertificateEntry(ROOT_ALIAS, rootCert);
 702     }
 703 
 704     private static void addCommonExts(CertificateBuilder cbld,
 705             PublicKey subjKey, PublicKey authKey) throws IOException {
 706         cbld.addSubjectKeyIdExt(subjKey);
 707         cbld.addAuthorityKeyIdExt(authKey);
 708     }
 709 
 710     private static void addCommonCAExts(CertificateBuilder cbld)
 711             throws IOException {
 712         cbld.addBasicConstraintsExt(true, true, -1);
 713         // Set key usage bits for digitalSignature, keyCertSign and cRLSign
 714         boolean[] kuBitSettings = {true, false, false, false, false, true,
 715             true, false, false};
 716         cbld.addKeyUsageExt(kuBitSettings);
 717     }
 718 
 719     /**
 720      * Helper routine that dumps only a few cert fields rather than
 721      * the whole toString() output.
 722      *
 723      * @param cert an X509Certificate to be displayed
 724      *
 725      * @return the String output of the issuer, subject and
 726      * serial number
 727      */
 728     private static String certInfo(X509Certificate cert) {
 729         StringBuilder sb = new StringBuilder();
 730         sb.append("Issuer: ").append(cert.getIssuerX500Principal()).
 731                 append("\n");
 732         sb.append("Subject: ").append(cert.getSubjectX500Principal()).
 733                 append("\n");
 734         sb.append("Serial: ").append(cert.getSerialNumber()).append("\n");
 735         return sb.toString();
 736     }
 737 }