test/jdk/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/StatusReqSelection.java
changeset 50768 68fa3d4026ea
parent 50767 356eaea05bf0
child 50769 1bf8f9840705
equal deleted inserted replaced
50767:356eaea05bf0 50768:68fa3d4026ea
     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 // See ../../../../RunStatReqSelect.java for the jtreg header
       
    28 
       
    29 package sun.security.ssl;
       
    30 
       
    31 import javax.net.ssl.*;
       
    32 import javax.net.ssl.SSLEngineResult.*;
       
    33 import javax.security.auth.x500.X500Principal;
       
    34 import java.io.*;
       
    35 import java.math.BigInteger;
       
    36 import java.security.*;
       
    37 import java.nio.*;
       
    38 import java.security.cert.X509Certificate;
       
    39 import java.security.cert.Extension;
       
    40 import java.util.ArrayList;
       
    41 import java.util.Collections;
       
    42 import java.util.Date;
       
    43 import java.util.HashMap;
       
    44 import java.util.List;
       
    45 import java.util.Map;
       
    46 import java.util.Objects;
       
    47 import java.util.concurrent.TimeUnit;
       
    48 
       
    49 import sun.security.provider.certpath.OCSPNonceExtension;
       
    50 import sun.security.provider.certpath.ResponderId;
       
    51 import sun.security.testlibrary.SimpleOCSPServer;
       
    52 import sun.security.testlibrary.CertificateBuilder;
       
    53 
       
    54 public class StatusReqSelection {
       
    55 
       
    56     /*
       
    57      * Enables logging of the SSLEngine operations.
       
    58      */
       
    59     private static final boolean logging = true;
       
    60 
       
    61     /*
       
    62      * Enables the JSSE system debugging system property:
       
    63      *
       
    64      *     -Djavax.net.debug=all
       
    65      *
       
    66      * This gives a lot of low-level information about operations underway,
       
    67      * including specific handshake messages, and might be best examined
       
    68      * after gaining some familiarity with this application.
       
    69      */
       
    70     private static final boolean debug = false;
       
    71 
       
    72     // The following items are used to set up the keystores.
       
    73     private static final String passwd = "passphrase";
       
    74     private static final String ROOT_ALIAS = "root";
       
    75     private static final String INT_ALIAS = "intermediate";
       
    76     private static final String SSL_ALIAS = "ssl";
       
    77 
       
    78     // PKI and server components we will need for this test
       
    79     private static KeyManagerFactory kmf;
       
    80     private static TrustManagerFactory tmf;
       
    81     private static KeyStore rootKeystore;       // Root CA Keystore
       
    82     private static KeyStore intKeystore;        // Intermediate CA Keystore
       
    83     private static KeyStore serverKeystore;     // SSL Server Keystore
       
    84     private static KeyStore trustStore;         // SSL Client trust store
       
    85     private static SimpleOCSPServer rootOcsp;   // Root CA OCSP Responder
       
    86     private static int rootOcspPort;            // Port for root OCSP
       
    87     private static SimpleOCSPServer intOcsp;    // Intermediate CA OCSP server
       
    88     private static int intOcspPort;             // Port for intermediate OCSP
       
    89     private static SSLContext ctxStaple;        // SSLContext for all tests
       
    90 
       
    91     // Some useful objects we will need for test purposes
       
    92     private static final SecureRandom RNG = new SecureRandom();
       
    93 
       
    94     // We'll be using these objects repeatedly to make hello messages
       
    95     private static final ProtocolVersion VER_1_0 = ProtocolVersion.TLS10;
       
    96     private static final ProtocolVersion VER_1_2 = ProtocolVersion.TLS12;
       
    97     private static final CipherSuiteList SUITES = new CipherSuiteList(
       
    98             CipherSuite.valueOf("TLS_RSA_WITH_AES_128_GCM_SHA256"));
       
    99     private static final SessionId SID = new SessionId(new byte[0]);
       
   100     private static final HelloExtension RNIEXT =
       
   101             new RenegotiationInfoExtension(new byte[0], new byte[0]);
       
   102     private static final List<SignatureAndHashAlgorithm> algList =
       
   103             new ArrayList<SignatureAndHashAlgorithm>() {{
       
   104                add(SignatureAndHashAlgorithm.valueOf(4, 1, 0));
       
   105             }};         // List with only SHA256withRSA
       
   106     private static final SignatureAlgorithmsExtension SIGALGEXT =
       
   107             new SignatureAlgorithmsExtension(algList);
       
   108 
       
   109     /*
       
   110      * Main entry point for this test.
       
   111      */
       
   112     public static void main(String args[]) throws Exception {
       
   113         int testsPassed = 0;
       
   114 
       
   115         if (debug) {
       
   116             System.setProperty("javax.net.debug", "ssl");
       
   117         }
       
   118 
       
   119         // All tests will have stapling enabled on the server side
       
   120         System.setProperty("jdk.tls.server.enableStatusRequestExtension",
       
   121                 "true");
       
   122 
       
   123         // Create a single SSLContext that we can use for all tests
       
   124         ctxStaple = SSLContext.getInstance("TLS");
       
   125 
       
   126         // Create the PKI we will use for the test and start the OCSP servers
       
   127         createPKI();
       
   128 
       
   129         // Set up the KeyManagerFactory and TrustManagerFactory
       
   130         kmf = KeyManagerFactory.getInstance("PKIX");
       
   131         kmf.init(serverKeystore, passwd.toCharArray());
       
   132         tmf = TrustManagerFactory.getInstance("PKIX");
       
   133         tmf.init(trustStore);
       
   134 
       
   135         List<TestCase> testList = new ArrayList<TestCase>() {{
       
   136             add(new TestCase("ClientHello: No stapling extensions",
       
   137                     makeHelloNoStaplingExts(), false, false));
       
   138             add(new TestCase("ClientHello: Default status_request only",
       
   139                     makeDefaultStatReqOnly(), true, false));
       
   140             add(new TestCase("ClientHello: Default status_request_v2 only",
       
   141                     makeDefaultStatReqV2Only(), false, true));
       
   142             add(new TestCase("ClientHello: Both status_request exts, default",
       
   143                     makeDefaultStatReqBoth(), false, true));
       
   144             add(new TestCase(
       
   145                     "ClientHello: Hello with status_request and responder IDs",
       
   146                     makeStatReqWithRid(), false, false));
       
   147             add(new TestCase(
       
   148                     "ClientHello: Hello with status_request using no " +
       
   149                     "responder IDs but provides the OCSP nonce extension",
       
   150                     makeStatReqNoRidNonce(), true, false));
       
   151             add(new TestCase("ClientHello with default status_request and " +
       
   152                     "status_request_v2 with ResponderIds",
       
   153                     makeStatReqDefV2WithRid(), true, false));
       
   154             add(new TestCase("ClientHello with default status_request and " +
       
   155                     "status_request_v2 (OCSP_MULTI with ResponderId, " +
       
   156                     "OCSP as a default request)",
       
   157                     makeStatReqDefV2MultiWithRidSingleDef(), false, true));
       
   158             add(new TestCase("ClientHello with status_request and " +
       
   159                     "status_request_v2 and all OCSPStatusRequests use " +
       
   160                     "Responder IDs",
       
   161                     makeStatReqAllWithRid(), false, false));
       
   162             add(new TestCase("ClientHello with default status_request and " +
       
   163                     "status_request_v2 that has a default OCSP item and " +
       
   164                     "multiple OCSP_MULTI items, only one is default",
       
   165                     makeHelloMultiV2andSingle(), false, true));
       
   166         }};
       
   167 
       
   168         // Run the client and server property tests
       
   169         for (TestCase test : testList) {
       
   170             try {
       
   171                 log("*** Test: " + test.testName);
       
   172                 if (runTest(test)) {
       
   173                     log("PASS: status_request: " + test.statReqEnabled +
       
   174                             ", status_request_v2: " + test.statReqV2Enabled);
       
   175                     testsPassed++;
       
   176                 }
       
   177             } catch (Exception e) {
       
   178                 // If we get an exception, we'll count it as a failure
       
   179                 log("Test failure due to exception: " + e);
       
   180             }
       
   181             log("");
       
   182         }
       
   183 
       
   184         // Summary
       
   185         if (testsPassed != testList.size()) {
       
   186             throw new RuntimeException(testList.size() - testsPassed +
       
   187                     " tests failed out of " + testList.size() + " total.");
       
   188         } else {
       
   189             log("Total tests: " + testList.size() + ", all passed");
       
   190         }
       
   191     }
       
   192 
       
   193     private static boolean runTest(TestCase test) throws Exception {
       
   194         SSLEngineResult serverResult;
       
   195 
       
   196         // Create a Server SSLEngine to receive our customized ClientHello
       
   197         ctxStaple.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
       
   198         SSLEngine engine = ctxStaple.createSSLEngine();
       
   199         engine.setUseClientMode(false);
       
   200         engine.setNeedClientAuth(false);
       
   201 
       
   202         SSLSession session = engine.getSession();
       
   203         ByteBuffer serverOut = ByteBuffer.wrap("I'm a Server".getBytes());
       
   204         ByteBuffer serverIn =
       
   205                 ByteBuffer.allocate(session.getApplicationBufferSize() + 50);
       
   206         ByteBuffer sTOc =
       
   207                 ByteBuffer.allocateDirect(session.getPacketBufferSize());
       
   208 
       
   209         // Send the ClientHello ByteBuffer in the test case
       
   210         if (debug) {
       
   211             System.out.println("Sending Client Hello:\n" +
       
   212                     dumpHexBytes(test.data));
       
   213         }
       
   214 
       
   215         // Consume the client hello
       
   216         serverResult = engine.unwrap(test.data, serverIn);
       
   217         if (debug) {
       
   218             log("server unwrap: ", serverResult);
       
   219         }
       
   220         if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
       
   221             throw new SSLException("Server unwrap got status: " +
       
   222                     serverResult.getStatus());
       
   223         } else if (serverResult.getHandshakeStatus() !=
       
   224                 SSLEngineResult.HandshakeStatus.NEED_TASK) {
       
   225              throw new SSLException("Server unwrap expected NEED_TASK, got: " +
       
   226                     serverResult.getHandshakeStatus());
       
   227         }
       
   228         runDelegatedTasks(serverResult, engine);
       
   229         if (engine.getHandshakeStatus() !=
       
   230                 SSLEngineResult.HandshakeStatus.NEED_WRAP) {
       
   231             throw new SSLException("Expected NEED_WRAP, got: " +
       
   232                     engine.getHandshakeStatus());
       
   233         }
       
   234 
       
   235         // Generate a TLS record with the ServerHello
       
   236         serverResult = engine.wrap(serverOut, sTOc);
       
   237         if (debug) {
       
   238             log("client wrap: ", serverResult);
       
   239         }
       
   240         if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
       
   241             throw new SSLException("Client wrap got status: " +
       
   242                     serverResult.getStatus());
       
   243         }
       
   244         sTOc.flip();
       
   245 
       
   246         if (debug) {
       
   247             log("Server Response:\n" + dumpHexBytes(sTOc));
       
   248         }
       
   249 
       
   250         return checkServerHello(sTOc, test.statReqEnabled,
       
   251                 test.statReqV2Enabled);
       
   252     }
       
   253 
       
   254     /**
       
   255      * Make a TLSv1.2 ClientHello with only RNI and no stapling extensions
       
   256      */
       
   257     private static ByteBuffer makeHelloNoStaplingExts() throws IOException {
       
   258         // Craft the ClientHello byte buffer
       
   259         HelloExtensions exts = new HelloExtensions();
       
   260         exts.add(RNIEXT);
       
   261         exts.add(SIGALGEXT);
       
   262         return createTlsRecord(Record.ct_handshake, VER_1_2,
       
   263                 createClientHelloMsg(VER_1_2, SID, SUITES, exts));
       
   264     }
       
   265 
       
   266     /**
       
   267      * Make a TLSv1.2 ClientHello with the RNI and Status Request extensions
       
   268      */
       
   269     private static ByteBuffer makeDefaultStatReqOnly() throws IOException {
       
   270         // Craft the ClientHello byte buffer
       
   271         HelloExtensions exts = new HelloExtensions();
       
   272         exts.add(RNIEXT);
       
   273         exts.add(SIGALGEXT);
       
   274         exts.add(new CertStatusReqExtension(StatusRequestType.OCSP,
       
   275                 new OCSPStatusRequest(null, null)));
       
   276         return createTlsRecord(Record.ct_handshake, VER_1_2,
       
   277                 createClientHelloMsg(VER_1_2, SID, SUITES, exts));
       
   278     }
       
   279 
       
   280     /**
       
   281      * Make a TLSv1.2 ClientHello with the RNI and Status Request V2 extension
       
   282      */
       
   283     private static ByteBuffer makeDefaultStatReqV2Only() throws IOException {
       
   284         // Craft the ClientHello byte buffer
       
   285         HelloExtensions exts = new HelloExtensions();
       
   286         OCSPStatusRequest osr = new OCSPStatusRequest();
       
   287         List<CertStatusReqItemV2> itemList = new ArrayList<>(2);
       
   288         itemList.add(new CertStatusReqItemV2(StatusRequestType.OCSP_MULTI,
       
   289                 osr));
       
   290         itemList.add(new CertStatusReqItemV2(StatusRequestType.OCSP, osr));
       
   291 
       
   292         exts.add(RNIEXT);
       
   293         exts.add(SIGALGEXT);
       
   294         exts.add(new CertStatusReqListV2Extension(itemList));
       
   295         return createTlsRecord(Record.ct_handshake, VER_1_2,
       
   296                 createClientHelloMsg(VER_1_2, SID, SUITES, exts));
       
   297     }
       
   298     /**
       
   299      * Make a TLSv1.2 ClientHello with Status Request and Status Request V2
       
   300      * extensions.
       
   301      */
       
   302     private static ByteBuffer makeDefaultStatReqBoth() throws IOException {
       
   303         // Craft the ClientHello byte buffer
       
   304         HelloExtensions exts = new HelloExtensions();
       
   305         OCSPStatusRequest osr = new OCSPStatusRequest();
       
   306         List<CertStatusReqItemV2> itemList = new ArrayList<>(2);
       
   307         itemList.add(new CertStatusReqItemV2(StatusRequestType.OCSP_MULTI,
       
   308                 osr));
       
   309         itemList.add(new CertStatusReqItemV2(StatusRequestType.OCSP, osr));
       
   310 
       
   311         exts.add(RNIEXT);
       
   312         exts.add(SIGALGEXT);
       
   313         exts.add(new CertStatusReqExtension(StatusRequestType.OCSP,
       
   314                 new OCSPStatusRequest(null, null)));
       
   315         exts.add(new CertStatusReqListV2Extension(itemList));
       
   316         return createTlsRecord(Record.ct_handshake, VER_1_2,
       
   317                 createClientHelloMsg(VER_1_2, SID, SUITES, exts));
       
   318     }
       
   319 
       
   320     /**
       
   321      * Make a ClientHello using a status_request that has a single
       
   322      * responder ID in it.
       
   323      */
       
   324     private static ByteBuffer makeStatReqWithRid() throws IOException {
       
   325         HelloExtensions exts = new HelloExtensions();
       
   326         exts.add(RNIEXT);
       
   327         exts.add(SIGALGEXT);
       
   328         List<ResponderId> rids = new ArrayList<ResponderId>() {{
       
   329             add(new ResponderId(new X500Principal("CN=Foo")));
       
   330         }};
       
   331         exts.add(new CertStatusReqExtension(StatusRequestType.OCSP,
       
   332                 new OCSPStatusRequest(rids, null)));
       
   333         return createTlsRecord(Record.ct_handshake, VER_1_2,
       
   334                 createClientHelloMsg(VER_1_2, SID, SUITES, exts));
       
   335     }
       
   336 
       
   337     /**
       
   338      * Make a ClientHello using a status_request that has no
       
   339      * responder IDs but does provide the nonce extension.
       
   340      */
       
   341     private static ByteBuffer makeStatReqNoRidNonce() throws IOException {
       
   342         HelloExtensions exts = new HelloExtensions();
       
   343         exts.add(RNIEXT);
       
   344         exts.add(SIGALGEXT);
       
   345         List<Extension> ocspExts = new ArrayList<Extension>() {{
       
   346             add(new OCSPNonceExtension(16));
       
   347         }};
       
   348         exts.add(new CertStatusReqExtension(StatusRequestType.OCSP,
       
   349                 new OCSPStatusRequest(null, ocspExts)));
       
   350         return createTlsRecord(Record.ct_handshake, VER_1_2,
       
   351                 createClientHelloMsg(VER_1_2, SID, SUITES, exts));
       
   352     }
       
   353 
       
   354     /**
       
   355      * Make a ClientHello using a default status_request and a
       
   356      * status_request_v2 that has a single responder ID in it.
       
   357      */
       
   358     private static ByteBuffer makeStatReqDefV2WithRid() throws IOException {
       
   359         HelloExtensions exts = new HelloExtensions();
       
   360         List<ResponderId> rids = new ArrayList<ResponderId>() {{
       
   361             add(new ResponderId(new X500Principal("CN=Foo")));
       
   362         }};
       
   363         List<CertStatusReqItemV2> itemList = new ArrayList<>(2);
       
   364         itemList.add(new CertStatusReqItemV2(StatusRequestType.OCSP_MULTI,
       
   365                 new OCSPStatusRequest(rids, null)));
       
   366         itemList.add(new CertStatusReqItemV2(StatusRequestType.OCSP,
       
   367                 new OCSPStatusRequest(rids, null)));
       
   368 
       
   369         exts.add(RNIEXT);
       
   370         exts.add(SIGALGEXT);
       
   371         exts.add(new CertStatusReqExtension(StatusRequestType.OCSP,
       
   372                 new OCSPStatusRequest(null, null)));
       
   373         exts.add(new CertStatusReqListV2Extension(itemList));
       
   374         return createTlsRecord(Record.ct_handshake, VER_1_2,
       
   375                 createClientHelloMsg(VER_1_2, SID, SUITES, exts));
       
   376     }
       
   377 
       
   378     /**
       
   379      * Make a ClientHello using a default status_request and a
       
   380      * status_request_v2 that has a single responder ID in it for the
       
   381      * OCSP_MULTI request item and a default OCSP request item.
       
   382      */
       
   383     private static ByteBuffer makeStatReqDefV2MultiWithRidSingleDef()
       
   384             throws IOException {
       
   385         HelloExtensions exts = new HelloExtensions();
       
   386         List<ResponderId> rids = new ArrayList<ResponderId>() {{
       
   387             add(new ResponderId(new X500Principal("CN=Foo")));
       
   388         }};
       
   389         List<CertStatusReqItemV2> itemList = new ArrayList<>(2);
       
   390         itemList.add(new CertStatusReqItemV2(StatusRequestType.OCSP_MULTI,
       
   391                 new OCSPStatusRequest(rids, null)));
       
   392         itemList.add(new CertStatusReqItemV2(StatusRequestType.OCSP,
       
   393                 new OCSPStatusRequest(null, null)));
       
   394 
       
   395         exts.add(RNIEXT);
       
   396         exts.add(SIGALGEXT);
       
   397         exts.add(new CertStatusReqExtension(StatusRequestType.OCSP,
       
   398                 new OCSPStatusRequest(null, null)));
       
   399         exts.add(new CertStatusReqListV2Extension(itemList));
       
   400         return createTlsRecord(Record.ct_handshake, VER_1_2,
       
   401                 createClientHelloMsg(VER_1_2, SID, SUITES, exts));
       
   402     }
       
   403 
       
   404     /**
       
   405      * Make a ClientHello using status_request and status_request_v2 where
       
   406      * all underlying OCSPStatusRequests use responder IDs.
       
   407      */
       
   408     private static ByteBuffer makeStatReqAllWithRid() throws IOException {
       
   409         HelloExtensions exts = new HelloExtensions();
       
   410         List<ResponderId> rids = new ArrayList<ResponderId>() {{
       
   411             add(new ResponderId(new X500Principal("CN=Foo")));
       
   412         }};
       
   413         List<CertStatusReqItemV2> itemList = new ArrayList<>(2);
       
   414         itemList.add(new CertStatusReqItemV2(StatusRequestType.OCSP_MULTI,
       
   415                 new OCSPStatusRequest(rids, null)));
       
   416         itemList.add(new CertStatusReqItemV2(StatusRequestType.OCSP,
       
   417                 new OCSPStatusRequest(rids, null)));
       
   418 
       
   419         exts.add(RNIEXT);
       
   420         exts.add(SIGALGEXT);
       
   421         exts.add(new CertStatusReqExtension(StatusRequestType.OCSP,
       
   422                 new OCSPStatusRequest(rids, null)));
       
   423         exts.add(new CertStatusReqListV2Extension(itemList));
       
   424         return createTlsRecord(Record.ct_handshake, VER_1_2,
       
   425                 createClientHelloMsg(VER_1_2, SID, SUITES, exts));
       
   426     }
       
   427 
       
   428     /**
       
   429      * Make a TLSv1.2 ClientHello multiple CertStatusReqItemV2s of different
       
   430      * types.  One of the middle items should be acceptable while the others
       
   431      * have responder IDs.  The status_request (v1) should also be acceptable
       
   432      * but should be overridden in favor of the status_request_v2.
       
   433      */
       
   434     private static ByteBuffer makeHelloMultiV2andSingle() throws IOException {
       
   435         // Craft the ClientHello byte buffer
       
   436         HelloExtensions exts = new HelloExtensions();
       
   437         List<ResponderId> fooRid = Collections.singletonList(
       
   438                 new ResponderId(new X500Principal("CN=Foo")));
       
   439         List<ResponderId> barRid = Collections.singletonList(
       
   440                 new ResponderId(new X500Principal("CN=Bar")));
       
   441         List<CertStatusReqItemV2> itemList = new ArrayList<>();
       
   442         itemList.add(new CertStatusReqItemV2(StatusRequestType.OCSP,
       
   443                 new OCSPStatusRequest(null, null)));
       
   444         itemList.add(new CertStatusReqItemV2(StatusRequestType.OCSP_MULTI,
       
   445                 new OCSPStatusRequest(fooRid, null)));
       
   446         itemList.add(new CertStatusReqItemV2(StatusRequestType.OCSP_MULTI,
       
   447                 new OCSPStatusRequest(null, null)));
       
   448         itemList.add(new CertStatusReqItemV2(StatusRequestType.OCSP_MULTI,
       
   449                 new OCSPStatusRequest(barRid, null)));
       
   450 
       
   451         exts.add(RNIEXT);
       
   452         exts.add(SIGALGEXT);
       
   453         exts.add(new CertStatusReqExtension(StatusRequestType.OCSP,
       
   454                 new OCSPStatusRequest(null, null)));
       
   455         exts.add(new CertStatusReqListV2Extension(itemList));
       
   456         return createTlsRecord(Record.ct_handshake, VER_1_2,
       
   457                 createClientHelloMsg(VER_1_2, SID, SUITES, exts));
       
   458     }
       
   459 
       
   460     /**
       
   461      * Wrap a TLS content message into a TLS record header
       
   462      *
       
   463      * @param contentType a byte containing the content type value
       
   464      * @param pv the protocol version for this record
       
   465      * @param data a byte buffer containing the message data
       
   466      * @return
       
   467      */
       
   468     private static ByteBuffer createTlsRecord(byte contentType,
       
   469             ProtocolVersion pv, ByteBuffer data) {
       
   470         int msgLen = (data != null) ? data.limit() : 0;
       
   471 
       
   472         // Allocate enough space to hold the TLS record header + the message
       
   473         ByteBuffer recordBuf = ByteBuffer.allocate(msgLen + 5);
       
   474         recordBuf.put(contentType);
       
   475         recordBuf.putShort((short)pv.v);
       
   476         recordBuf.putShort((short)msgLen);
       
   477         if (msgLen > 0) {
       
   478             recordBuf.put(data);
       
   479         }
       
   480 
       
   481         recordBuf.flip();
       
   482         return recordBuf;
       
   483     }
       
   484 
       
   485     /**
       
   486      * Craft and encode a ClientHello message as a byte array.
       
   487      *
       
   488      * @param pv the protocol version asserted in the hello message.
       
   489      * @param sessId the session ID for this hello message.
       
   490      * @param suites a list consisting of one or more cipher suite objects
       
   491      * @param extensions a list of HelloExtension objects
       
   492      *
       
   493      * @return a byte array containing the encoded ClientHello message.
       
   494      */
       
   495     private static ByteBuffer createClientHelloMsg(ProtocolVersion pv,
       
   496             SessionId sessId, CipherSuiteList suites,
       
   497             HelloExtensions extensions) throws IOException {
       
   498         ByteBuffer msgBuf;
       
   499 
       
   500         HandshakeOutStream hsos =
       
   501                 new HandshakeOutStream(new SSLEngineOutputRecord());
       
   502 
       
   503         // Construct the client hello object from the first 3 parameters
       
   504         HandshakeMessage.ClientHello cHello =
       
   505                 new HandshakeMessage.ClientHello(RNG, pv, sessId, suites,
       
   506                         false);
       
   507 
       
   508         // Use the HelloExtensions provided by the caller
       
   509         if (extensions != null) {
       
   510             cHello.extensions = extensions;
       
   511         }
       
   512 
       
   513         cHello.send(hsos);
       
   514         msgBuf = ByteBuffer.allocate(hsos.size() + 4);
       
   515 
       
   516         // Combine the handshake type with the length
       
   517         msgBuf.putInt((HandshakeMessage.ht_client_hello << 24) |
       
   518                 (hsos.size() & 0x00FFFFFF));
       
   519         msgBuf.put(hsos.toByteArray());
       
   520         msgBuf.flip();
       
   521         return msgBuf;
       
   522     }
       
   523 
       
   524     /*
       
   525      * If the result indicates that we have outstanding tasks to do,
       
   526      * go ahead and run them in this thread.
       
   527      */
       
   528     private static void runDelegatedTasks(SSLEngineResult result,
       
   529             SSLEngine engine) throws Exception {
       
   530 
       
   531         if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
       
   532             Runnable runnable;
       
   533             while ((runnable = engine.getDelegatedTask()) != null) {
       
   534                 if (debug) {
       
   535                     log("\trunning delegated task...");
       
   536                 }
       
   537                 runnable.run();
       
   538             }
       
   539             HandshakeStatus hsStatus = engine.getHandshakeStatus();
       
   540             if (hsStatus == HandshakeStatus.NEED_TASK) {
       
   541                 throw new Exception(
       
   542                     "handshake shouldn't need additional tasks");
       
   543             }
       
   544             if (debug) {
       
   545                 log("\tnew HandshakeStatus: " + hsStatus);
       
   546             }
       
   547         }
       
   548     }
       
   549 
       
   550     private static void log(String str, SSLEngineResult result) {
       
   551         if (!logging) {
       
   552             return;
       
   553         }
       
   554         HandshakeStatus hsStatus = result.getHandshakeStatus();
       
   555         log(str +
       
   556             result.getStatus() + "/" + hsStatus + ", " +
       
   557             result.bytesConsumed() + "/" + result.bytesProduced() +
       
   558             " bytes");
       
   559         if (hsStatus == HandshakeStatus.FINISHED) {
       
   560             log("\t...ready for application data");
       
   561         }
       
   562     }
       
   563 
       
   564     private static void log(String str) {
       
   565         if (logging) {
       
   566             System.out.println(str);
       
   567         }
       
   568     }
       
   569 
       
   570     /**
       
   571      * Dump a ByteBuffer as a hexdump to stdout.  The dumping routine will
       
   572      * start at the current position of the buffer and run to its limit.
       
   573      * After completing the dump, the position will be returned to its
       
   574      * starting point.
       
   575      *
       
   576      * @param data the ByteBuffer to dump to stdout.
       
   577      *
       
   578      * @return the hexdump of the byte array.
       
   579      */
       
   580     private static String dumpHexBytes(ByteBuffer data) {
       
   581         StringBuilder sb = new StringBuilder();
       
   582         if (data != null) {
       
   583             int i = 0;
       
   584             data.mark();
       
   585             while (data.hasRemaining()) {
       
   586                 if (i % 16 == 0 && i != 0) {
       
   587                     sb.append("\n");
       
   588                 }
       
   589                 sb.append(String.format("%02X ", data.get()));
       
   590                 i++;
       
   591             }
       
   592             data.reset();
       
   593         }
       
   594 
       
   595         return sb.toString();
       
   596     }
       
   597 
       
   598     /**
       
   599      * Tests the ServerHello for the presence (or not) of the status_request
       
   600      * or status_request_v2 hello extension.  It is assumed that the provided
       
   601      * ByteBuffer has its position set at the first byte of the TLS record
       
   602      * containing the ServerHello and contains the entire hello message.  Upon
       
   603      * successful completion of this method the ByteBuffer will have its
       
   604      * position reset to the initial offset in the buffer.  If an exception is
       
   605      * thrown the position at the time of the exception will be preserved.
       
   606      *
       
   607      * @param statReqPresent true if the status_request hello extension should
       
   608      * be present.
       
   609      * @param statReqV2Present true if the status_request_v2 hello extension
       
   610      * should be present.
       
   611      *
       
   612      * @return true if the ServerHello's extension set matches the presence
       
   613      *      booleans for status_request and status_request_v2.  False if
       
   614      *      not, or if the TLS record or message is of the wrong type.
       
   615      */
       
   616     private static boolean checkServerHello(ByteBuffer data,
       
   617             boolean statReqPresent, boolean statReqV2Present) {
       
   618         boolean hasV1 = false;
       
   619         boolean hasV2 = false;
       
   620         Objects.requireNonNull(data);
       
   621         int startPos = data.position();
       
   622         data.mark();
       
   623 
       
   624         // Process the TLS record header
       
   625         int type = Byte.toUnsignedInt(data.get());
       
   626         int ver_major = Byte.toUnsignedInt(data.get());
       
   627         int ver_minor = Byte.toUnsignedInt(data.get());
       
   628         int recLen = Short.toUnsignedInt(data.getShort());
       
   629 
       
   630         // Simple sanity checks
       
   631         if (type != 22) {
       
   632             log("Not a handshake: Type = " + type);
       
   633             return false;
       
   634         } else if (recLen > data.remaining()) {
       
   635             log("Incomplete record in buffer: Record length = " + recLen +
       
   636                     ", Remaining = " + data.remaining());
       
   637             return false;
       
   638         }
       
   639 
       
   640         // Grab the handshake message header.
       
   641         int msgHdr = data.getInt();
       
   642         int msgType = (msgHdr >> 24) & 0x000000FF;
       
   643         int msgLen = msgHdr & 0x00FFFFFF;
       
   644 
       
   645         // More simple sanity checks
       
   646         if (msgType != 2) {
       
   647             log("Not a ServerHello: Type = " + msgType);
       
   648             return false;
       
   649         }
       
   650 
       
   651         // Skip over the protocol version and server random
       
   652         data.position(data.position() + 34);
       
   653 
       
   654         // Jump past the session ID
       
   655         int sessLen = Byte.toUnsignedInt(data.get());
       
   656         if (sessLen != 0) {
       
   657             data.position(data.position() + sessLen);
       
   658         }
       
   659 
       
   660         // Skip the cipher suite and compression method
       
   661         data.position(data.position() + 3);
       
   662 
       
   663         // Go through the extensions and look for the request extension
       
   664         // expected by the caller.
       
   665         int extsLen = Short.toUnsignedInt(data.getShort());
       
   666         while (data.position() < recLen + startPos + 5) {
       
   667             int extType = Short.toUnsignedInt(data.getShort());
       
   668             int extLen = Short.toUnsignedInt(data.getShort());
       
   669             hasV1 |= (extType == ExtensionType.EXT_STATUS_REQUEST.id);
       
   670             hasV2 |= (extType == ExtensionType.EXT_STATUS_REQUEST_V2.id);
       
   671             data.position(data.position() + extLen);
       
   672         }
       
   673 
       
   674         if (hasV1 != statReqPresent) {
       
   675             log("The status_request extension is " +
       
   676                     "inconsistent with the expected result: expected = " +
       
   677                     statReqPresent + ", actual = " + hasV1);
       
   678         }
       
   679         if (hasV2 != statReqV2Present) {
       
   680             log("The status_request_v2 extension is " +
       
   681                     "inconsistent with the expected result: expected = " +
       
   682                     statReqV2Present + ", actual = " + hasV2);
       
   683         }
       
   684 
       
   685         // Reset the position to the initial spot at the start of this method.
       
   686         data.reset();
       
   687 
       
   688         return ((hasV1 == statReqPresent) && (hasV2 == statReqV2Present));
       
   689     }
       
   690 
       
   691     /**
       
   692      * Creates the PKI components necessary for this test, including
       
   693      * Root CA, Intermediate CA and SSL server certificates, the keystores
       
   694      * for each entity, a client trust store, and starts the OCSP responders.
       
   695      */
       
   696     private static void createPKI() throws Exception {
       
   697         CertificateBuilder cbld = new CertificateBuilder();
       
   698         KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
       
   699         keyGen.initialize(2048);
       
   700         KeyStore.Builder keyStoreBuilder =
       
   701                 KeyStore.Builder.newInstance("PKCS12", null,
       
   702                         new KeyStore.PasswordProtection(passwd.toCharArray()));
       
   703 
       
   704         // Generate Root, IntCA, EE keys
       
   705         KeyPair rootCaKP = keyGen.genKeyPair();
       
   706         log("Generated Root CA KeyPair");
       
   707         KeyPair intCaKP = keyGen.genKeyPair();
       
   708         log("Generated Intermediate CA KeyPair");
       
   709         KeyPair sslKP = keyGen.genKeyPair();
       
   710         log("Generated SSL Cert KeyPair");
       
   711 
       
   712         // Set up the Root CA Cert
       
   713         cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany");
       
   714         cbld.setPublicKey(rootCaKP.getPublic());
       
   715         cbld.setSerialNumber(new BigInteger("1"));
       
   716         // Make a 3 year validity starting from 60 days ago
       
   717         long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60);
       
   718         long end = start + TimeUnit.DAYS.toMillis(1085);
       
   719         cbld.setValidity(new Date(start), new Date(end));
       
   720         addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic());
       
   721         addCommonCAExts(cbld);
       
   722         // Make our Root CA Cert!
       
   723         X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(),
       
   724                 "SHA256withRSA");
       
   725         log("Root CA Created:\n" + certInfo(rootCert));
       
   726 
       
   727         // Now build a keystore and add the keys and cert
       
   728         rootKeystore = keyStoreBuilder.getKeyStore();
       
   729         java.security.cert.Certificate[] rootChain = {rootCert};
       
   730         rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(),
       
   731                 passwd.toCharArray(), rootChain);
       
   732 
       
   733         // Now fire up the OCSP responder
       
   734         rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null);
       
   735         rootOcsp.enableLog(debug);
       
   736         rootOcsp.setNextUpdateInterval(3600);
       
   737         rootOcsp.start();
       
   738 
       
   739         // Wait 5 seconds for server ready
       
   740         for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) {
       
   741             Thread.sleep(50);
       
   742         }
       
   743         if (!rootOcsp.isServerReady()) {
       
   744             throw new RuntimeException("Server not ready yet");
       
   745         }
       
   746 
       
   747         rootOcspPort = rootOcsp.getPort();
       
   748         String rootRespURI = "http://localhost:" + rootOcspPort;
       
   749         log("Root OCSP Responder URI is " + rootRespURI);
       
   750 
       
   751         // Now that we have the root keystore and OCSP responder we can
       
   752         // create our intermediate CA.
       
   753         cbld.reset();
       
   754         cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany");
       
   755         cbld.setPublicKey(intCaKP.getPublic());
       
   756         cbld.setSerialNumber(new BigInteger("100"));
       
   757         // Make a 2 year validity starting from 30 days ago
       
   758         start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30);
       
   759         end = start + TimeUnit.DAYS.toMillis(730);
       
   760         cbld.setValidity(new Date(start), new Date(end));
       
   761         addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic());
       
   762         addCommonCAExts(cbld);
       
   763         cbld.addAIAExt(Collections.singletonList(rootRespURI));
       
   764         // Make our Intermediate CA Cert!
       
   765         X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(),
       
   766                 "SHA256withRSA");
       
   767         log("Intermediate CA Created:\n" + certInfo(intCaCert));
       
   768 
       
   769         // Provide intermediate CA cert revocation info to the Root CA
       
   770         // OCSP responder.
       
   771         Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
       
   772             new HashMap<>();
       
   773         revInfo.put(intCaCert.getSerialNumber(),
       
   774                 new SimpleOCSPServer.CertStatusInfo(
       
   775                         SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
       
   776         rootOcsp.updateStatusDb(revInfo);
       
   777 
       
   778         // Now build a keystore and add the keys, chain and root cert as a TA
       
   779         intKeystore = keyStoreBuilder.getKeyStore();
       
   780         java.security.cert.Certificate[] intChain = {intCaCert, rootCert};
       
   781         intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(),
       
   782                 passwd.toCharArray(), intChain);
       
   783         intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
       
   784 
       
   785         // Now fire up the Intermediate CA OCSP responder
       
   786         intOcsp = new SimpleOCSPServer(intKeystore, passwd,
       
   787                 INT_ALIAS, null);
       
   788         intOcsp.enableLog(debug);
       
   789         intOcsp.setNextUpdateInterval(3600);
       
   790         intOcsp.start();
       
   791 
       
   792         // Wait 5 seconds for server ready
       
   793         for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) {
       
   794             Thread.sleep(50);
       
   795         }
       
   796         if (!intOcsp.isServerReady()) {
       
   797             throw new RuntimeException("Server not ready yet");
       
   798         }
       
   799 
       
   800         intOcspPort = intOcsp.getPort();
       
   801         String intCaRespURI = "http://localhost:" + intOcspPort;
       
   802         log("Intermediate CA OCSP Responder URI is " + intCaRespURI);
       
   803 
       
   804         // Last but not least, let's make our SSLCert and add it to its own
       
   805         // Keystore
       
   806         cbld.reset();
       
   807         cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany");
       
   808         cbld.setPublicKey(sslKP.getPublic());
       
   809         cbld.setSerialNumber(new BigInteger("4096"));
       
   810         // Make a 1 year validity starting from 7 days ago
       
   811         start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);
       
   812         end = start + TimeUnit.DAYS.toMillis(365);
       
   813         cbld.setValidity(new Date(start), new Date(end));
       
   814 
       
   815         // Add extensions
       
   816         addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic());
       
   817         boolean[] kuBits = {true, false, true, false, false, false,
       
   818             false, false, false};
       
   819         cbld.addKeyUsageExt(kuBits);
       
   820         List<String> ekuOids = new ArrayList<>();
       
   821         ekuOids.add("1.3.6.1.5.5.7.3.1");
       
   822         ekuOids.add("1.3.6.1.5.5.7.3.2");
       
   823         cbld.addExtendedKeyUsageExt(ekuOids);
       
   824         cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost"));
       
   825         cbld.addAIAExt(Collections.singletonList(intCaRespURI));
       
   826         // Make our SSL Server Cert!
       
   827         X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(),
       
   828                 "SHA256withRSA");
       
   829         log("SSL Certificate Created:\n" + certInfo(sslCert));
       
   830 
       
   831         // Provide SSL server cert revocation info to the Intermeidate CA
       
   832         // OCSP responder.
       
   833         revInfo = new HashMap<>();
       
   834         revInfo.put(sslCert.getSerialNumber(),
       
   835                 new SimpleOCSPServer.CertStatusInfo(
       
   836                         SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
       
   837         intOcsp.updateStatusDb(revInfo);
       
   838 
       
   839         // Now build a keystore and add the keys, chain and root cert as a TA
       
   840         serverKeystore = keyStoreBuilder.getKeyStore();
       
   841         java.security.cert.Certificate[] sslChain = {sslCert, intCaCert, rootCert};
       
   842         serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(),
       
   843                 passwd.toCharArray(), sslChain);
       
   844         serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
       
   845 
       
   846         // And finally a Trust Store for the client
       
   847         trustStore = keyStoreBuilder.getKeyStore();
       
   848         trustStore.setCertificateEntry(ROOT_ALIAS, rootCert);
       
   849     }
       
   850 
       
   851     private static void addCommonExts(CertificateBuilder cbld,
       
   852             PublicKey subjKey, PublicKey authKey) throws IOException {
       
   853         cbld.addSubjectKeyIdExt(subjKey);
       
   854         cbld.addAuthorityKeyIdExt(authKey);
       
   855     }
       
   856 
       
   857     private static void addCommonCAExts(CertificateBuilder cbld)
       
   858             throws IOException {
       
   859         cbld.addBasicConstraintsExt(true, true, -1);
       
   860         // Set key usage bits for digitalSignature, keyCertSign and cRLSign
       
   861         boolean[] kuBitSettings = {true, false, false, false, false, true,
       
   862             true, false, false};
       
   863         cbld.addKeyUsageExt(kuBitSettings);
       
   864     }
       
   865 
       
   866     /**
       
   867      * Helper routine that dumps only a few cert fields rather than
       
   868      * the whole toString() output.
       
   869      *
       
   870      * @param cert an X509Certificate to be displayed
       
   871      *
       
   872      * @return the String output of the issuer, subject and
       
   873      * serial number
       
   874      */
       
   875     private static String certInfo(X509Certificate cert) {
       
   876         StringBuilder sb = new StringBuilder();
       
   877         sb.append("Issuer: ").append(cert.getIssuerX500Principal()).
       
   878                 append("\n");
       
   879         sb.append("Subject: ").append(cert.getSubjectX500Principal()).
       
   880                 append("\n");
       
   881         sb.append("Serial: ").append(cert.getSerialNumber()).append("\n");
       
   882         return sb.toString();
       
   883     }
       
   884 
       
   885     private static class TestCase {
       
   886         public final String testName;
       
   887         public final ByteBuffer data;
       
   888         public final boolean statReqEnabled;
       
   889         public final boolean statReqV2Enabled;
       
   890 
       
   891         TestCase(String name, ByteBuffer buffer, boolean srEn, boolean srv2En) {
       
   892             testName = (name != null) ? name : "";
       
   893             data = Objects.requireNonNull(buffer,
       
   894                     "TestCase requires a non-null ByteBuffer");
       
   895             statReqEnabled = srEn;
       
   896             statReqV2Enabled = srv2En;
       
   897         }
       
   898     }
       
   899 }