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 }