Path: blob/master/test/jdk/javax/net/ssl/Stapling/StapleEnableProps.java
41152 views
/*1* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223// SunJSSE does not support dynamic system properties, no way to re-use24// system properties in samevm/agentvm mode.2526/*27* @test28* @bug 8145854 815382929* @summary SSLContextImpl.statusResponseManager should be generated if required30* @library ../../../../java/security/testlibrary31* @build CertificateBuilder SimpleOCSPServer32* @run main/othervm StapleEnableProps33*/3435import javax.net.ssl.*;36import javax.net.ssl.SSLEngineResult.*;37import java.io.*;38import java.math.BigInteger;39import java.security.*;40import java.nio.*;41import java.security.cert.X509Certificate;42import java.util.ArrayList;43import java.util.Collections;44import java.util.Date;45import java.util.HashMap;46import java.util.List;47import java.util.Map;48import java.util.Objects;49import java.util.concurrent.TimeUnit;5051import sun.security.testlibrary.SimpleOCSPServer;52import sun.security.testlibrary.CertificateBuilder;5354public class StapleEnableProps {5556/*57* Enables logging of the SSLEngine operations.58*/59private static final boolean logging = true;6061/*62* Enables the JSSE system debugging system property:63*64* -Djavax.net.debug=all65*66* This gives a lot of low-level information about operations underway,67* including specific handshake messages, and might be best examined68* after gaining some familiarity with this application.69*/70private static final boolean debug = false;7172// These four ByteBuffer references will be used to hang onto ClientHello73// messages with and without the status_request[_v2] extensions. These74// will be used in the server-side stapling tests. There are two sets,75// one for 1.2 and earlier versions of the protocol and one for 1.376// and later versions, since the handshake and extension sets differ77// between the two sets.78private static ByteBuffer cHello12Staple;79private static ByteBuffer cHello12NoStaple;80private static ByteBuffer cHello13Staple;81private static ByteBuffer cHello13NoStaple;8283// The following items are used to set up the keystores.84private static final String passwd = "passphrase";85private static final String ROOT_ALIAS = "root";86private static final String INT_ALIAS = "intermediate";87private static final String SSL_ALIAS = "ssl";8889// PKI components we will need for this test90private static KeyManagerFactory kmf;91private static TrustManagerFactory tmf;92private static KeyStore rootKeystore; // Root CA Keystore93private static KeyStore intKeystore; // Intermediate CA Keystore94private static KeyStore serverKeystore; // SSL Server Keystore95private static KeyStore trustStore; // SSL Client trust store96private static SimpleOCSPServer rootOcsp; // Root CA OCSP Responder97private static int rootOcspPort; // Port for root OCSP98private static SimpleOCSPServer intOcsp; // Intermediate CA OCSP server99private static int intOcspPort; // Port for intermediate OCSP100101// Extra configuration parameters and constants102static final String[] TLS13ONLY = new String[] { "TLSv1.3" };103static final String[] TLS12MAX =104new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" };105106// A few helpful TLS definitions to make it easier107private static final int HELLO_EXT_STATUS_REQ = 5;108private static final int HELLO_EXT_STATUS_REQ_V2 = 17;109110/*111* Main entry point for this test.112*/113public static void main(String args[]) throws Exception {114if (debug) {115System.setProperty("javax.net.debug", "ssl:handshake,verbose");116}117118// Create the PKI we will use for the test and start the OCSP servers119createPKI();120121// Set up the KeyManagerFactory and TrustManagerFactory122kmf = KeyManagerFactory.getInstance("PKIX");123kmf.init(serverKeystore, passwd.toCharArray());124tmf = TrustManagerFactory.getInstance("PKIX");125tmf.init(trustStore);126127// Run the client and server property tests128testClientProp();129testServerProp();130131}132133private static void testClientProp() throws Exception {134SSLEngineResult clientResult;135136// Test with the client-side enable property set to true137System.out.println("=========================================");138System.out.println("Client Test 1: " +139"jdk.tls.client.enableStatusRequestExtension = true");140System.out.println("Version = TLS 1.2");141System.out.println("=========================================");142143System.setProperty("jdk.tls.client.enableStatusRequestExtension",144"true");145SSLContext ctxStaple = SSLContext.getInstance("TLS");146ctxStaple.init(null, tmf.getTrustManagers(), null);147SSLEngine engine = ctxStaple.createSSLEngine();148engine.setUseClientMode(true);149engine.setEnabledProtocols(TLS12MAX);150SSLSession session = engine.getSession();151ByteBuffer clientOut = ByteBuffer.wrap("I'm a Client".getBytes());152ByteBuffer cTOs =153ByteBuffer.allocateDirect(session.getPacketBufferSize());154155// Create and check the ClientHello message156clientResult = engine.wrap(clientOut, cTOs);157log("client wrap: ", clientResult);158if (clientResult.getStatus() != SSLEngineResult.Status.OK) {159throw new SSLException("Client wrap got status: " +160clientResult.getStatus());161}162cTOs.flip();163System.out.println(dumpHexBytes(cTOs));164checkClientHello(cTOs, true, true);165cHello12Staple = cTOs;166167// Test with the property set to false168System.out.println("=========================================");169System.out.println("Client Test 2: " +170"jdk.tls.client.enableStatusRequestExtension = false");171System.out.println("Version = TLS 1.2");172System.out.println("=========================================");173174System.setProperty("jdk.tls.client.enableStatusRequestExtension",175"false");176SSLContext ctxNoStaple = SSLContext.getInstance("TLS");177ctxNoStaple.init(null, tmf.getTrustManagers(), null);178engine = ctxNoStaple.createSSLEngine();179engine.setUseClientMode(true);180engine.setEnabledProtocols(TLS12MAX);181session = engine.getSession();182cTOs = ByteBuffer.allocateDirect(session.getPacketBufferSize());183184// Create and check the ClientHello message185clientResult = engine.wrap(clientOut, cTOs);186log("client wrap: ", clientResult);187if (clientResult.getStatus() != SSLEngineResult.Status.OK) {188throw new SSLException("Client wrap got status: " +189clientResult.getStatus());190}191cTOs.flip();192System.out.println(dumpHexBytes(cTOs));193checkClientHello(cTOs, false, false);194cHello12NoStaple = cTOs;195196// Turn the property back on to true and test using TLS 1.3197System.out.println("=========================================");198System.out.println("Client Test 3: " +199"jdk.tls.client.enableStatusRequestExtension = true");200System.out.println("Version = TLS 1.3");201System.out.println("=========================================");202203System.setProperty("jdk.tls.client.enableStatusRequestExtension",204"true");205ctxStaple = SSLContext.getInstance("TLS");206ctxStaple.init(null, tmf.getTrustManagers(), null);207engine = ctxStaple.createSSLEngine();208engine.setUseClientMode(true);209engine.setEnabledProtocols(TLS13ONLY);210session = engine.getSession();211cTOs = ByteBuffer.allocateDirect(session.getPacketBufferSize());212213// Create and check the ClientHello message214clientResult = engine.wrap(clientOut, cTOs);215log("client wrap: ", clientResult);216if (clientResult.getStatus() != SSLEngineResult.Status.OK) {217throw new SSLException("Client wrap got status: " +218clientResult.getStatus());219}220cTOs.flip();221System.out.println(dumpHexBytes(cTOs));222checkClientHello(cTOs, true, false);223cHello13Staple = cTOs;224225// Turn the property off again and test in a TLS 1.3 handshake226System.out.println("=========================================");227System.out.println("Client Test 4: " +228"jdk.tls.client.enableStatusRequestExtension = false");229System.out.println("Version = TLS 1.3");230System.out.println("=========================================");231232System.setProperty("jdk.tls.client.enableStatusRequestExtension",233"false");234ctxNoStaple = SSLContext.getInstance("TLS");235ctxNoStaple.init(null, tmf.getTrustManagers(), null);236engine = ctxNoStaple.createSSLEngine();237engine.setUseClientMode(true);238engine.setEnabledProtocols(TLS13ONLY);239session = engine.getSession();240cTOs = ByteBuffer.allocateDirect(session.getPacketBufferSize());241242// Create and check the ClientHello message243clientResult = engine.wrap(clientOut, cTOs);244log("client wrap: ", clientResult);245if (clientResult.getStatus() != SSLEngineResult.Status.OK) {246throw new SSLException("Client wrap got status: " +247clientResult.getStatus());248}249cTOs.flip();250System.out.println(dumpHexBytes(cTOs));251checkClientHello(cTOs, false, false);252cHello13NoStaple = cTOs;253254// A TLS 1.3-capable hello, one that is not strictly limited to255// the TLS 1.3 protocol should have both status_request and256// status_request_v2257System.out.println("=========================================");258System.out.println("Client Test 5: " +259"jdk.tls.client.enableStatusRequestExtension = true");260System.out.println("Version = TLS 1.3 capable [default hello]");261System.out.println("=========================================");262263System.setProperty("jdk.tls.client.enableStatusRequestExtension",264"true");265ctxStaple = SSLContext.getInstance("TLS");266ctxStaple.init(null, tmf.getTrustManagers(), null);267engine = ctxStaple.createSSLEngine();268engine.setUseClientMode(true);269// Note: Unlike the other tests, there is no explicit protocol setting270session = engine.getSession();271cTOs = ByteBuffer.allocateDirect(session.getPacketBufferSize());272273// Create and check the ClientHello message274clientResult = engine.wrap(clientOut, cTOs);275log("client wrap: ", clientResult);276if (clientResult.getStatus() != SSLEngineResult.Status.OK) {277throw new SSLException("Client wrap got status: " +278clientResult.getStatus());279}280cTOs.flip();281System.out.println(dumpHexBytes(cTOs));282checkClientHello(cTOs, true, true);283}284285private static void testServerProp() throws Exception {286SSLEngineResult serverResult;287HandshakeStatus hsStat;288289// Test with the server-side enable property set to true290System.out.println("=========================================");291System.out.println("Server Test 1: " +292"jdk.tls.server.enableStatusRequestExtension = true");293System.out.println("Version = TLS 1.2");294System.out.println("=========================================");295296System.setProperty("jdk.tls.server.enableStatusRequestExtension",297"true");298SSLContext ctxStaple = SSLContext.getInstance("TLS");299ctxStaple.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);300SSLEngine engine = ctxStaple.createSSLEngine();301engine.setUseClientMode(false);302engine.setEnabledProtocols(TLS12MAX);303SSLSession session = engine.getSession();304ByteBuffer serverOut = ByteBuffer.wrap("I'm a Server".getBytes());305ByteBuffer serverIn =306ByteBuffer.allocate(session.getApplicationBufferSize() + 50);307ByteBuffer sTOc =308ByteBuffer.allocateDirect(session.getPacketBufferSize());309310// Consume the client hello311serverResult = engine.unwrap(cHello12Staple, serverIn);312log("server unwrap: ", serverResult);313if (serverResult.getStatus() != SSLEngineResult.Status.OK) {314throw new SSLException("Server unwrap got status: " +315serverResult.getStatus());316} else if (serverResult.getHandshakeStatus() !=317SSLEngineResult.HandshakeStatus.NEED_TASK) {318throw new SSLException("Server unwrap expected NEED_TASK, got: " +319serverResult.getHandshakeStatus());320}321runDelegatedTasks(serverResult, engine);322if (engine.getHandshakeStatus() !=323SSLEngineResult.HandshakeStatus.NEED_WRAP) {324throw new SSLException("Expected NEED_WRAP, got: " +325engine.getHandshakeStatus());326}327328// Generate a TLS record with the ServerHello329serverResult = engine.wrap(serverOut, sTOc);330log("client wrap: ", serverResult);331if (serverResult.getStatus() != SSLEngineResult.Status.OK) {332throw new SSLException("Client wrap got status: " +333serverResult.getStatus());334}335sTOc.flip();336System.out.println(dumpHexBytes(sTOc));337checkServerHello(sTOc, false, true);338339// Flip the client hello so we can reuse it in the next test.340cHello12Staple.flip();341342// Test with the server-side enable property set to false343System.out.println("=========================================");344System.out.println("Server Test 2: " +345"jdk.tls.server.enableStatusRequestExtension = false");346System.out.println("Version = TLS 1.2");347System.out.println("=========================================");348349System.setProperty("jdk.tls.server.enableStatusRequestExtension",350"false");351SSLContext ctxNoStaple = SSLContext.getInstance("TLS");352ctxNoStaple.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);353engine = ctxNoStaple.createSSLEngine();354engine.setUseClientMode(false);355engine.setEnabledProtocols(TLS12MAX);356session = engine.getSession();357serverIn = ByteBuffer.allocate(session.getApplicationBufferSize() + 50);358sTOc = ByteBuffer.allocateDirect(session.getPacketBufferSize());359360// Consume the client hello361serverResult = engine.unwrap(cHello12Staple, serverIn);362log("server unwrap: ", serverResult);363if (serverResult.getStatus() != SSLEngineResult.Status.OK) {364throw new SSLException("Server unwrap got status: " +365serverResult.getStatus());366} else if (serverResult.getHandshakeStatus() !=367SSLEngineResult.HandshakeStatus.NEED_TASK) {368throw new SSLException("Server unwrap expected NEED_TASK, got: " +369serverResult.getHandshakeStatus());370}371runDelegatedTasks(serverResult, engine);372if (engine.getHandshakeStatus() !=373SSLEngineResult.HandshakeStatus.NEED_WRAP) {374throw new SSLException("Expected NEED_WRAP, got: " +375engine.getHandshakeStatus());376}377378// Generate a TLS record with the ServerHello379serverResult = engine.wrap(serverOut, sTOc);380log("client wrap: ", serverResult);381if (serverResult.getStatus() != SSLEngineResult.Status.OK) {382throw new SSLException("Client wrap got status: " +383serverResult.getStatus());384}385sTOc.flip();386System.out.println(dumpHexBytes(sTOc));387checkServerHello(sTOc, false, false);388}389390/*391* If the result indicates that we have outstanding tasks to do,392* go ahead and run them in this thread.393*/394private static void runDelegatedTasks(SSLEngineResult result,395SSLEngine engine) throws Exception {396397if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {398Runnable runnable;399while ((runnable = engine.getDelegatedTask()) != null) {400log("\trunning delegated task...");401runnable.run();402}403HandshakeStatus hsStatus = engine.getHandshakeStatus();404if (hsStatus == HandshakeStatus.NEED_TASK) {405throw new Exception(406"handshake shouldn't need additional tasks");407}408log("\tnew HandshakeStatus: " + hsStatus);409}410}411412private static void log(String str, SSLEngineResult result) {413if (!logging) {414return;415}416HandshakeStatus hsStatus = result.getHandshakeStatus();417log(str +418result.getStatus() + "/" + hsStatus + ", " +419result.bytesConsumed() + "/" + result.bytesProduced() +420" bytes");421if (hsStatus == HandshakeStatus.FINISHED) {422log("\t...ready for application data");423}424}425426private static void log(String str) {427if (logging) {428System.out.println(str);429}430}431432/**433* Dump a ByteBuffer as a hexdump to stdout. The dumping routine will434* start at the current position of the buffer and run to its limit.435* After completing the dump, the position will be returned to its436* starting point.437*438* @param data the ByteBuffer to dump to stdout.439*440* @return the hexdump of the byte array.441*/442private static String dumpHexBytes(ByteBuffer data) {443StringBuilder sb = new StringBuilder();444if (data != null) {445int i = 0;446data.mark();447while (data.hasRemaining()) {448if (i % 16 == 0 && i != 0) {449sb.append("\n");450}451sb.append(String.format("%02X ", data.get()));452i++;453}454data.reset();455}456457return sb.toString();458}459460/**461* Tests the ClientHello for the presence (or not) of the status_request462* and status_request_v2 hello extensions. It is assumed that the provided463* ByteBuffer has its position set at the first byte of the TLS record464* containing the ClientHello and contains the entire hello message. Upon465* successful completion of this method the ByteBuffer will have its466* position reset to the initial offset in the buffer. If an exception is467* thrown the position at the time of the exception will be preserved.468*469* @param data the ByteBuffer containing the ClientHello bytes470* @param statReqPresent true if the status_request hello extension should471* be present.472* @param statReqV2Present true if the status_request_v2 hello extension473* should be present.474*475* @throws SSLException if the presence or lack of either the476* status_request or status_request_v2 extensions is inconsistent with477* the expected settings in the statReqPresent or statReqV2Present478* parameters.479*/480private static void checkClientHello(ByteBuffer data,481boolean statReqPresent, boolean statReqV2Present)482throws SSLException {483boolean hasV1 = false;484boolean hasV2 = false;485Objects.requireNonNull(data);486data.mark();487488// Process the TLS record header489int type = Byte.toUnsignedInt(data.get());490int ver_major = Byte.toUnsignedInt(data.get());491int ver_minor = Byte.toUnsignedInt(data.get());492int recLen = Short.toUnsignedInt(data.getShort());493494// Simple sanity checks495if (type != 22) {496throw new SSLException("Not a handshake: Type = " + type);497} else if (recLen > data.remaining()) {498throw new SSLException("Incomplete record in buffer: " +499"Record length = " + recLen + ", Remaining = " +500data.remaining());501}502503// Grab the handshake message header.504int msgHdr = data.getInt();505int msgType = (msgHdr >> 24) & 0x000000FF;506int msgLen = msgHdr & 0x00FFFFFF;507508// More simple sanity checks509if (msgType != 1) {510throw new SSLException("Not a ClientHello: Type = " + msgType);511}512513// Skip over the protocol version and client random514data.position(data.position() + 34);515516// Jump past the session ID (if there is one)517int sessLen = Byte.toUnsignedInt(data.get());518if (sessLen != 0) {519data.position(data.position() + sessLen);520}521522// Jump past the cipher suites523int csLen = Short.toUnsignedInt(data.getShort());524if (csLen != 0) {525data.position(data.position() + csLen);526}527528// ...and the compression529int compLen = Byte.toUnsignedInt(data.get());530if (compLen != 0) {531data.position(data.position() + compLen);532}533534// Now for the fun part. Go through the extensions and look535// for the two status request exts.536int extsLen = Short.toUnsignedInt(data.getShort());537while (data.hasRemaining()) {538int extType = Short.toUnsignedInt(data.getShort());539int extLen = Short.toUnsignedInt(data.getShort());540hasV1 |= (extType == HELLO_EXT_STATUS_REQ);541hasV2 |= (extType == HELLO_EXT_STATUS_REQ_V2);542data.position(data.position() + extLen);543}544545if (hasV1 != statReqPresent) {546throw new SSLException("The status_request extension is " +547"inconsistent with the expected result: expected = " +548statReqPresent + ", actual = " + hasV1);549} else if (hasV2 != statReqV2Present) {550throw new SSLException("The status_request_v2 extension is " +551"inconsistent with the expected result: expected = " +552statReqV2Present + ", actual = " + hasV2);553}554555// We should be at the end of the ClientHello556data.reset();557}558559/**560* Tests the ServerHello for the presence (or not) of the status_request561* or status_request_v2 hello extension. It is assumed that the provided562* ByteBuffer has its position set at the first byte of the TLS record563* containing the ServerHello and contains the entire hello message. Upon564* successful completion of this method the ByteBuffer will have its565* position reset to the initial offset in the buffer. If an exception is566* thrown the position at the time of the exception will be preserved.567*568* @param statReqPresent true if the status_request hello extension should569* be present.570* @param statReqV2Present true if the status_request_v2 hello extension571* should be present.572*573* @throws SSLException if the presence or lack of either the574* status_request or status_request_v2 extensions is inconsistent with575* the expected settings in the statReqPresent or statReqV2Present576* parameters.577*/578private static void checkServerHello(ByteBuffer data,579boolean statReqPresent, boolean statReqV2Present)580throws SSLException {581boolean hasV1 = false;582boolean hasV2 = false;583Objects.requireNonNull(data);584int startPos = data.position();585data.mark();586587// Process the TLS record header588int type = Byte.toUnsignedInt(data.get());589int ver_major = Byte.toUnsignedInt(data.get());590int ver_minor = Byte.toUnsignedInt(data.get());591int recLen = Short.toUnsignedInt(data.getShort());592593// Simple sanity checks594if (type != 22) {595throw new SSLException("Not a handshake: Type = " + type);596} else if (recLen > data.remaining()) {597throw new SSLException("Incomplete record in buffer: " +598"Record length = " + recLen + ", Remaining = " +599data.remaining());600}601602// Grab the handshake message header.603int msgHdr = data.getInt();604int msgType = (msgHdr >> 24) & 0x000000FF;605int msgLen = msgHdr & 0x00FFFFFF;606607// More simple sanity checks608if (msgType != 2) {609throw new SSLException("Not a ServerHello: Type = " + msgType);610}611612// Skip over the protocol version and server random613data.position(data.position() + 34);614615// Jump past the session ID616int sessLen = Byte.toUnsignedInt(data.get());617if (sessLen != 0) {618data.position(data.position() + sessLen);619}620621// Skip the cipher suite and compression method622data.position(data.position() + 3);623624// Go through the extensions and look for the request extension625// expected by the caller.626int extsLen = Short.toUnsignedInt(data.getShort());627while (data.position() < recLen + startPos + 5) {628int extType = Short.toUnsignedInt(data.getShort());629int extLen = Short.toUnsignedInt(data.getShort());630hasV1 |= (extType == HELLO_EXT_STATUS_REQ);631hasV2 |= (extType == HELLO_EXT_STATUS_REQ_V2);632data.position(data.position() + extLen);633}634635if (hasV1 != statReqPresent) {636throw new SSLException("The status_request extension is " +637"inconsistent with the expected result: expected = " +638statReqPresent + ", actual = " + hasV1);639} else if (hasV2 != statReqV2Present) {640throw new SSLException("The status_request_v2 extension is " +641"inconsistent with the expected result: expected = " +642statReqV2Present + ", actual = " + hasV2);643}644645// Reset the position to the initial spot at the start of this method.646data.reset();647}648649/**650* Creates the PKI components necessary for this test, including651* Root CA, Intermediate CA and SSL server certificates, the keystores652* for each entity, a client trust store, and starts the OCSP responders.653*/654private static void createPKI() throws Exception {655CertificateBuilder cbld = new CertificateBuilder();656KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");657keyGen.initialize(2048);658KeyStore.Builder keyStoreBuilder =659KeyStore.Builder.newInstance("PKCS12", null,660new KeyStore.PasswordProtection(passwd.toCharArray()));661662// Generate Root, IntCA, EE keys663KeyPair rootCaKP = keyGen.genKeyPair();664log("Generated Root CA KeyPair");665KeyPair intCaKP = keyGen.genKeyPair();666log("Generated Intermediate CA KeyPair");667KeyPair sslKP = keyGen.genKeyPair();668log("Generated SSL Cert KeyPair");669670// Set up the Root CA Cert671cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany");672cbld.setPublicKey(rootCaKP.getPublic());673cbld.setSerialNumber(new BigInteger("1"));674// Make a 3 year validity starting from 60 days ago675long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60);676long end = start + TimeUnit.DAYS.toMillis(1085);677cbld.setValidity(new Date(start), new Date(end));678addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic());679addCommonCAExts(cbld);680// Make our Root CA Cert!681X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(),682"SHA256withRSA");683log("Root CA Created:\n" + certInfo(rootCert));684685// Now build a keystore and add the keys and cert686rootKeystore = keyStoreBuilder.getKeyStore();687java.security.cert.Certificate[] rootChain = {rootCert};688rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(),689passwd.toCharArray(), rootChain);690691// Now fire up the OCSP responder692rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null);693rootOcsp.enableLog(logging);694rootOcsp.setNextUpdateInterval(3600);695rootOcsp.start();696697// Wait 5 seconds for server ready698for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) {699Thread.sleep(50);700}701if (!rootOcsp.isServerReady()) {702throw new RuntimeException("Server not ready yet");703}704705rootOcspPort = rootOcsp.getPort();706String rootRespURI = "http://localhost:" + rootOcspPort;707log("Root OCSP Responder URI is " + rootRespURI);708709// Now that we have the root keystore and OCSP responder we can710// create our intermediate CA.711cbld.reset();712cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany");713cbld.setPublicKey(intCaKP.getPublic());714cbld.setSerialNumber(new BigInteger("100"));715// Make a 2 year validity starting from 30 days ago716start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30);717end = start + TimeUnit.DAYS.toMillis(730);718cbld.setValidity(new Date(start), new Date(end));719addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic());720addCommonCAExts(cbld);721cbld.addAIAExt(Collections.singletonList(rootRespURI));722// Make our Intermediate CA Cert!723X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(),724"SHA256withRSA");725log("Intermediate CA Created:\n" + certInfo(intCaCert));726727// Provide intermediate CA cert revocation info to the Root CA728// OCSP responder.729Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =730new HashMap<>();731revInfo.put(intCaCert.getSerialNumber(),732new SimpleOCSPServer.CertStatusInfo(733SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));734rootOcsp.updateStatusDb(revInfo);735736// Now build a keystore and add the keys, chain and root cert as a TA737intKeystore = keyStoreBuilder.getKeyStore();738java.security.cert.Certificate[] intChain = {intCaCert, rootCert};739intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(),740passwd.toCharArray(), intChain);741intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);742743// Now fire up the Intermediate CA OCSP responder744intOcsp = new SimpleOCSPServer(intKeystore, passwd,745INT_ALIAS, null);746intOcsp.enableLog(logging);747intOcsp.setNextUpdateInterval(3600);748intOcsp.start();749750// Wait 5 seconds for server ready751for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) {752Thread.sleep(50);753}754if (!intOcsp.isServerReady()) {755throw new RuntimeException("Server not ready yet");756}757758intOcspPort = intOcsp.getPort();759String intCaRespURI = "http://localhost:" + intOcspPort;760log("Intermediate CA OCSP Responder URI is " + intCaRespURI);761762// Last but not least, let's make our SSLCert and add it to its own763// Keystore764cbld.reset();765cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany");766cbld.setPublicKey(sslKP.getPublic());767cbld.setSerialNumber(new BigInteger("4096"));768// Make a 1 year validity starting from 7 days ago769start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);770end = start + TimeUnit.DAYS.toMillis(365);771cbld.setValidity(new Date(start), new Date(end));772773// Add extensions774addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic());775boolean[] kuBits = {true, false, true, false, false, false,776false, false, false};777cbld.addKeyUsageExt(kuBits);778List<String> ekuOids = new ArrayList<>();779ekuOids.add("1.3.6.1.5.5.7.3.1");780ekuOids.add("1.3.6.1.5.5.7.3.2");781cbld.addExtendedKeyUsageExt(ekuOids);782cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost"));783cbld.addAIAExt(Collections.singletonList(intCaRespURI));784// Make our SSL Server Cert!785X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(),786"SHA256withRSA");787log("SSL Certificate Created:\n" + certInfo(sslCert));788789// Provide SSL server cert revocation info to the Intermeidate CA790// OCSP responder.791revInfo = new HashMap<>();792revInfo.put(sslCert.getSerialNumber(),793new SimpleOCSPServer.CertStatusInfo(794SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));795intOcsp.updateStatusDb(revInfo);796797// Now build a keystore and add the keys, chain and root cert as a TA798serverKeystore = keyStoreBuilder.getKeyStore();799java.security.cert.Certificate[] sslChain = {sslCert, intCaCert, rootCert};800serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(),801passwd.toCharArray(), sslChain);802serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);803804// And finally a Trust Store for the client805trustStore = keyStoreBuilder.getKeyStore();806trustStore.setCertificateEntry(ROOT_ALIAS, rootCert);807}808809private static void addCommonExts(CertificateBuilder cbld,810PublicKey subjKey, PublicKey authKey) throws IOException {811cbld.addSubjectKeyIdExt(subjKey);812cbld.addAuthorityKeyIdExt(authKey);813}814815private static void addCommonCAExts(CertificateBuilder cbld)816throws IOException {817cbld.addBasicConstraintsExt(true, true, -1);818// Set key usage bits for digitalSignature, keyCertSign and cRLSign819boolean[] kuBitSettings = {true, false, false, false, false, true,820true, false, false};821cbld.addKeyUsageExt(kuBitSettings);822}823824/**825* Helper routine that dumps only a few cert fields rather than826* the whole toString() output.827*828* @param cert an X509Certificate to be displayed829*830* @return the String output of the issuer, subject and831* serial number832*/833private static String certInfo(X509Certificate cert) {834StringBuilder sb = new StringBuilder();835sb.append("Issuer: ").append(cert.getIssuerX500Principal()).836append("\n");837sb.append("Subject: ").append(cert.getSubjectX500Principal()).838append("\n");839sb.append("Serial: ").append(cert.getSerialNumber()).append("\n");840return sb.toString();841}842}843844845