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