1/*
2 * Copyright (c) 2015, 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 8046321 8153829
30 * @summary OCSP Stapling for TLS
31 * @library ../../../../java/security/testlibrary
32 * @build CertificateBuilder SimpleOCSPServer
33 * @run main/othervm HttpsUrlConnClient
34 */
35
36import java.io.*;
37import java.math.BigInteger;
38import java.security.KeyPair;
39import java.security.KeyPairGenerator;
40import java.net.Socket;
41import java.net.URL;
42import java.net.HttpURLConnection;
43import java.net.InetAddress;
44import javax.net.ssl.*;
45import java.security.KeyStore;
46import java.security.PublicKey;
47import java.security.Security;
48import java.security.GeneralSecurityException;
49import java.security.cert.CertPathValidatorException;
50import java.security.cert.CertPathValidatorException.BasicReason;
51import java.security.cert.Certificate;
52import java.security.cert.PKIXBuilderParameters;
53import java.security.cert.X509CertSelector;
54import java.security.cert.X509Certificate;
55import java.security.cert.PKIXRevocationChecker;
56import java.security.spec.PKCS8EncodedKeySpec;
57import java.text.SimpleDateFormat;
58import java.util.*;
59import java.util.concurrent.TimeUnit;
60
61import sun.security.testlibrary.SimpleOCSPServer;
62import sun.security.testlibrary.CertificateBuilder;
63import sun.security.validator.ValidatorException;
64
65public class HttpsUrlConnClient {
66
67    /*
68     * =============================================================
69     * Set the various variables needed for the tests, then
70     * specify what tests to run on each side.
71     */
72
73    static final byte[] LINESEP = { 10 };
74    static final Base64.Encoder B64E = Base64.getMimeEncoder(64, LINESEP);
75
76    // Turn on TLS debugging
77    static boolean debug = true;
78
79    /*
80     * Should we run the client or server in a separate thread?
81     * Both sides can throw exceptions, but do you have a preference
82     * as to which side should be the main thread.
83     */
84    static boolean separateServerThread = true;
85    Thread clientThread = null;
86    Thread serverThread = null;
87
88    static String passwd = "passphrase";
89    static String ROOT_ALIAS = "root";
90    static String INT_ALIAS = "intermediate";
91    static String SSL_ALIAS = "ssl";
92
93    /*
94     * Is the server ready to serve?
95     */
96    volatile static boolean serverReady = false;
97    volatile int serverPort = 0;
98
99    volatile Exception serverException = null;
100    volatile Exception clientException = null;
101
102    // PKI components we will need for this test
103    static KeyStore rootKeystore;           // Root CA Keystore
104    static KeyStore intKeystore;            // Intermediate CA Keystore
105    static KeyStore serverKeystore;         // SSL Server Keystore
106    static KeyStore trustStore;             // SSL Client trust store
107    static SimpleOCSPServer rootOcsp;       // Root CA OCSP Responder
108    static int rootOcspPort;                // Port number for root OCSP
109    static SimpleOCSPServer intOcsp;        // Intermediate CA OCSP Responder
110    static int intOcspPort;                 // Port number for intermed. OCSP
111
112    private static final String SIMPLE_WEB_PAGE = "<HTML>\n" +
113            "<HEAD><Title>Web Page!</Title></HEAD>\n" +
114            "<BODY><H1>Web Page!</H1></BODY>\n</HTML>";
115    private static final SimpleDateFormat utcDateFmt =
116            new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
117    /*
118     * If the client or server is doing some kind of object creation
119     * that the other side depends on, and that thread prematurely
120     * exits, you may experience a hang.  The test harness will
121     * terminate all hung threads after its timeout has expired,
122     * currently 3 minutes by default, but you might try to be
123     * smart about it....
124     */
125    public static void main(String[] args) throws Exception {
126        if (debug) {
127            System.setProperty("javax.net.debug", "ssl");
128        }
129
130        System.setProperty("javax.net.ssl.keyStore", "");
131        System.setProperty("javax.net.ssl.keyStorePassword", "");
132        System.setProperty("javax.net.ssl.trustStore", "");
133        System.setProperty("javax.net.ssl.trustStorePassword", "");
134
135        // Create the PKI we will use for the test and start the OCSP servers
136        createPKI();
137        utcDateFmt.setTimeZone(TimeZone.getTimeZone("GMT"));
138
139        testPKIXParametersRevEnabled();
140
141        // shut down the OCSP responders before finishing the test
142        intOcsp.stop();
143        rootOcsp.stop();
144    }
145
146    /**
147     * Do a basic connection using PKIXParameters with revocation checking
148     * enabled and client-side OCSP disabled.  It will only pass if all
149     * stapled responses are present, valid and have a GOOD status.
150     */
151    static void testPKIXParametersRevEnabled() throws Exception {
152        ClientParameters cliParams = new ClientParameters();
153        ServerParameters servParams = new ServerParameters();
154        serverReady = false;
155
156        System.out.println("=====================================");
157        System.out.println("Stapling enabled, PKIXParameters with");
158        System.out.println("Revocation checking enabled ");
159        System.out.println("=====================================");
160
161        // Set the certificate entry in the intermediate OCSP responder
162        // with a revocation date of 8 hours ago.
163        X509Certificate sslCert =
164                (X509Certificate)serverKeystore.getCertificate(SSL_ALIAS);
165        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
166            new HashMap<>();
167        revInfo.put(sslCert.getSerialNumber(),
168                new SimpleOCSPServer.CertStatusInfo(
169                        SimpleOCSPServer.CertStatus.CERT_STATUS_REVOKED,
170                        new Date(System.currentTimeMillis() -
171                                TimeUnit.HOURS.toMillis(8))));
172        intOcsp.updateStatusDb(revInfo);
173
174        // Set up revocation checking on the client with no client-side
175        // OCSP fall-back
176        cliParams.pkixParams = new PKIXBuilderParameters(trustStore,
177                new X509CertSelector());
178        cliParams.pkixParams.setRevocationEnabled(true);
179        Security.setProperty("ocsp.enable", "false");
180
181        HttpsUrlConnClient sslTest = new HttpsUrlConnClient(cliParams,
182                servParams);
183        TestResult tr = sslTest.getResult();
184        if (!checkClientValidationFailure(tr.clientExc, BasicReason.REVOKED)) {
185            if (tr.clientExc != null) {
186                throw tr.clientExc;
187            } else {
188                throw new RuntimeException(
189                        "Expected client failure, but the client succeeded");
190            }
191        }
192
193        // In this case the server should also have thrown an exception
194        // because of the client alert
195        if (tr.serverExc instanceof SSLHandshakeException) {
196            if (!tr.serverExc.getMessage().contains(
197                    "alert: bad_certificate_status_response")) {
198                throw tr.serverExc;
199            }
200        }
201
202        System.out.println("                PASS");
203        System.out.println("=====================================\n");
204    }
205
206    /*
207     * Define the server side of the test.
208     *
209     * If the server prematurely exits, serverReady will be set to true
210     * to avoid infinite hangs.
211     */
212    void doServerSide(ServerParameters servParams) throws Exception {
213
214        // Selectively enable or disable the feature
215        System.setProperty("jdk.tls.server.enableStatusRequestExtension",
216                Boolean.toString(servParams.enabled));
217
218        // Set all the other operating parameters
219        System.setProperty("jdk.tls.stapling.cacheSize",
220                Integer.toString(servParams.cacheSize));
221        System.setProperty("jdk.tls.stapling.cacheLifetime",
222                Integer.toString(servParams.cacheLifetime));
223        System.setProperty("jdk.tls.stapling.responseTimeout",
224                Integer.toString(servParams.respTimeout));
225        System.setProperty("jdk.tls.stapling.responderURI", servParams.respUri);
226        System.setProperty("jdk.tls.stapling.responderOverride",
227                Boolean.toString(servParams.respOverride));
228        System.setProperty("jdk.tls.stapling.ignoreExtensions",
229                Boolean.toString(servParams.ignoreExts));
230
231        // Set keystores and trust stores for the server
232        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
233        kmf.init(serverKeystore, passwd.toCharArray());
234        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
235        tmf.init(trustStore);
236
237        SSLContext sslc = SSLContext.getInstance("TLS");
238        sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
239
240        SSLServerSocketFactory sslssf = sslc.getServerSocketFactory();
241        SSLServerSocket sslServerSocket =
242            (SSLServerSocket) sslssf.createServerSocket(serverPort);
243
244        serverPort = sslServerSocket.getLocalPort();
245        log("Server Port is " + serverPort);
246
247        // Dump the private key in PKCS8 format, not encrypted.  This
248        // key dump can be used if the traffic was captured using tcpdump
249        // or wireshark to look into the encrypted packets for debug purposes.
250        if (debug) {
251            byte[] keybytes = serverKeystore.getKey(SSL_ALIAS,
252                    passwd.toCharArray()).getEncoded();
253            PKCS8EncodedKeySpec p8spec = new PKCS8EncodedKeySpec(keybytes);
254            StringBuilder keyPem = new StringBuilder();
255            keyPem.append("-----BEGIN PRIVATE KEY-----\n");
256            keyPem.append(B64E.encodeToString(p8spec.getEncoded())).append("\n");
257            keyPem.append("-----END PRIVATE KEY-----\n");
258            log("Private key is:\n" + keyPem.toString());
259        }
260
261        /*
262         * Signal Client, we're ready for his connect.
263         */
264        serverReady = true;
265
266        try (SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
267                BufferedReader in = new BufferedReader(
268                    new InputStreamReader(sslSocket.getInputStream()));
269                OutputStream out = sslSocket.getOutputStream()) {
270            StringBuilder hdrBldr = new StringBuilder();
271            String line;
272            while ((line = in.readLine()) != null && !line.isEmpty()) {
273                hdrBldr.append(line).append("\n");
274            }
275            String headerText = hdrBldr.toString();
276            log("Header Received: " + headerText.length() + " bytes\n" +
277                    headerText);
278
279            StringBuilder sb = new StringBuilder();
280            sb.append("HTTP/1.0 200 OK\r\n");
281            sb.append("Date: ").append(utcDateFmt.format(new Date())).
282                    append("\r\n");
283            sb.append("Content-Type: text/html\r\n");
284            sb.append("Content-Length: ").append(SIMPLE_WEB_PAGE.length());
285            sb.append("\r\n\r\n");
286            out.write(sb.toString().getBytes("UTF-8"));
287            out.write(SIMPLE_WEB_PAGE.getBytes("UTF-8"));
288            out.flush();
289            log("Server replied with:\n" + sb.toString() + SIMPLE_WEB_PAGE);
290        }
291    }
292
293    /*
294     * Define the client side of the test.
295     *
296     * If the server prematurely exits, serverReady will be set to true
297     * to avoid infinite hangs.
298     */
299    void doClientSide(ClientParameters cliParams) throws Exception {
300
301        // Wait 5 seconds for server ready
302        for (int i = 0; (i < 100 && !serverReady); i++) {
303            Thread.sleep(50);
304        }
305        if (!serverReady) {
306            throw new RuntimeException("Server not ready yet");
307        }
308
309        // Selectively enable or disable the feature
310        System.setProperty("jdk.tls.client.enableStatusRequestExtension",
311                Boolean.toString(cliParams.enabled));
312
313        HtucSSLSocketFactory sockFac = new HtucSSLSocketFactory(cliParams);
314        HttpsURLConnection.setDefaultSSLSocketFactory(sockFac);
315        URL location = new URL("https://localhost:" + serverPort);
316        HttpsURLConnection tlsConn =
317                (HttpsURLConnection)location.openConnection();
318        tlsConn.setConnectTimeout(5000);
319        tlsConn.setReadTimeout(5000);
320        tlsConn.setDoInput(true);
321
322        try (InputStream in = tlsConn.getInputStream()) {
323            // Check the response
324            if (debug && tlsConn.getResponseCode() !=
325                    HttpURLConnection.HTTP_OK) {
326                log("Received HTTP error: " + tlsConn.getResponseCode() +
327                        " - " + tlsConn.getResponseMessage());
328                throw new IOException("HTTP error: " +
329                        tlsConn.getResponseCode());
330            }
331
332            int contentLength = tlsConn.getContentLength();
333            if (contentLength == -1) {
334                contentLength = Integer.MAX_VALUE;
335            }
336            byte[] response = new byte[contentLength > 2048 ? 2048 : contentLength];
337            int total = 0;
338            while (total < contentLength) {
339                int count = in.read(response, total, response.length - total);
340                if (count < 0)
341                    break;
342
343                total += count;
344                log("Read " + count + " bytes (" + total + " total)");
345                if (total >= response.length && total < contentLength) {
346                    response = Arrays.copyOf(response, total * 2);
347                }
348            }
349            response = Arrays.copyOf(response, total);
350            String webPage = new String(response, 0, total);
351            if (debug) {
352                log("Web page:\n" + webPage);
353            }
354        }
355    }
356
357    /*
358     * Primary constructor, used to drive remainder of the test.
359     *
360     * Fork off the other side, then do your work.
361     */
362    HttpsUrlConnClient(ClientParameters cliParams,
363            ServerParameters servParams) throws Exception {
364        Exception startException = null;
365        try {
366            if (separateServerThread) {
367                startServer(servParams, true);
368                startClient(cliParams, false);
369            } else {
370                startClient(cliParams, true);
371                startServer(servParams, false);
372            }
373        } catch (Exception e) {
374            startException = e;
375        }
376
377        /*
378         * Wait for other side to close down.
379         */
380        if (separateServerThread) {
381            if (serverThread != null) {
382                serverThread.join();
383            }
384        } else {
385            if (clientThread != null) {
386                clientThread.join();
387            }
388        }
389    }
390
391    /**
392     * Checks a validation failure to see if it failed for the reason we think
393     * it should.  This comes in as an SSLException of some sort, but it
394     * encapsulates a ValidatorException which in turn encapsulates the
395     * CertPathValidatorException we are interested in.
396     *
397     * @param e the exception thrown at the top level
398     * @param reason the underlying CertPathValidatorException BasicReason
399     * we are expecting it to have.
400     *
401     * @return true if the reason matches up, false otherwise.
402     */
403    static boolean checkClientValidationFailure(Exception e,
404            BasicReason reason) {
405        boolean result = false;
406
407        if (e instanceof SSLException) {
408            Throwable valExc = e.getCause();
409            if (valExc instanceof sun.security.validator.ValidatorException) {
410                Throwable cause = valExc.getCause();
411                if (cause instanceof CertPathValidatorException) {
412                    CertPathValidatorException cpve =
413                            (CertPathValidatorException)cause;
414                    if (cpve.getReason() == reason) {
415                        result = true;
416                    }
417                }
418            }
419        }
420        return result;
421    }
422
423    TestResult getResult() {
424        TestResult tr = new TestResult();
425        tr.clientExc = clientException;
426        tr.serverExc = serverException;
427        return tr;
428    }
429
430    final void startServer(ServerParameters servParams, boolean newThread)
431            throws Exception {
432        if (newThread) {
433            serverThread = new Thread() {
434                @Override
435                public void run() {
436                    try {
437                        doServerSide(servParams);
438                    } catch (Exception e) {
439                        /*
440                         * Our server thread just died.
441                         *
442                         * Release the client, if not active already...
443                         */
444                        System.err.println("Server died...");
445                        serverReady = true;
446                        serverException = e;
447                    }
448                }
449            };
450            serverThread.start();
451        } else {
452            try {
453                doServerSide(servParams);
454            } catch (Exception e) {
455                serverException = e;
456            } finally {
457                serverReady = true;
458            }
459        }
460    }
461
462    final void startClient(ClientParameters cliParams, boolean newThread)
463            throws Exception {
464        if (newThread) {
465            clientThread = new Thread() {
466                @Override
467                public void run() {
468                    try {
469                        doClientSide(cliParams);
470                    } catch (Exception e) {
471                        /*
472                         * Our client thread just died.
473                         */
474                        System.err.println("Client died...");
475                        clientException = e;
476                    }
477                }
478            };
479            clientThread.start();
480        } else {
481            try {
482                doClientSide(cliParams);
483            } catch (Exception e) {
484                clientException = e;
485            }
486        }
487    }
488
489    /**
490     * Creates the PKI components necessary for this test, including
491     * Root CA, Intermediate CA and SSL server certificates, the keystores
492     * for each entity, a client trust store, and starts the OCSP responders.
493     */
494    private static void createPKI() throws Exception {
495        CertificateBuilder cbld = new CertificateBuilder();
496        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
497        keyGen.initialize(2048);
498        KeyStore.Builder keyStoreBuilder =
499                KeyStore.Builder.newInstance("PKCS12", null,
500                        new KeyStore.PasswordProtection(passwd.toCharArray()));
501
502        // Generate Root, IntCA, EE keys
503        KeyPair rootCaKP = keyGen.genKeyPair();
504        log("Generated Root CA KeyPair");
505        KeyPair intCaKP = keyGen.genKeyPair();
506        log("Generated Intermediate CA KeyPair");
507        KeyPair sslKP = keyGen.genKeyPair();
508        log("Generated SSL Cert KeyPair");
509
510        // Set up the Root CA Cert
511        cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany");
512        cbld.setPublicKey(rootCaKP.getPublic());
513        cbld.setSerialNumber(new BigInteger("1"));
514        // Make a 3 year validity starting from 60 days ago
515        long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60);
516        long end = start + TimeUnit.DAYS.toMillis(1085);
517        cbld.setValidity(new Date(start), new Date(end));
518        addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic());
519        addCommonCAExts(cbld);
520        // Make our Root CA Cert!
521        X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(),
522                "SHA256withRSA");
523        log("Root CA Created:\n" + certInfo(rootCert));
524
525        // Now build a keystore and add the keys and cert
526        rootKeystore = keyStoreBuilder.getKeyStore();
527        Certificate[] rootChain = {rootCert};
528        rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(),
529                passwd.toCharArray(), rootChain);
530
531        // Now fire up the OCSP responder
532        rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null);
533        rootOcsp.enableLog(debug);
534        rootOcsp.setNextUpdateInterval(3600);
535        rootOcsp.start();
536
537        // Wait 5 seconds for server ready
538        for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) {
539            Thread.sleep(50);
540        }
541        if (!rootOcsp.isServerReady()) {
542            throw new RuntimeException("Server not ready yet");
543        }
544
545        rootOcspPort = rootOcsp.getPort();
546        String rootRespURI = "http://localhost:" + rootOcspPort;
547        log("Root OCSP Responder URI is " + rootRespURI);
548
549        // Now that we have the root keystore and OCSP responder we can
550        // create our intermediate CA.
551        cbld.reset();
552        cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany");
553        cbld.setPublicKey(intCaKP.getPublic());
554        cbld.setSerialNumber(new BigInteger("100"));
555        // Make a 2 year validity starting from 30 days ago
556        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30);
557        end = start + TimeUnit.DAYS.toMillis(730);
558        cbld.setValidity(new Date(start), new Date(end));
559        addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic());
560        addCommonCAExts(cbld);
561        cbld.addAIAExt(Collections.singletonList(rootRespURI));
562        // Make our Intermediate CA Cert!
563        X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(),
564                "SHA256withRSA");
565        log("Intermediate CA Created:\n" + certInfo(intCaCert));
566
567        // Provide intermediate CA cert revocation info to the Root CA
568        // OCSP responder.
569        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
570            new HashMap<>();
571        revInfo.put(intCaCert.getSerialNumber(),
572                new SimpleOCSPServer.CertStatusInfo(
573                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
574        rootOcsp.updateStatusDb(revInfo);
575
576        // Now build a keystore and add the keys, chain and root cert as a TA
577        intKeystore = keyStoreBuilder.getKeyStore();
578        Certificate[] intChain = {intCaCert, rootCert};
579        intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(),
580                passwd.toCharArray(), intChain);
581        intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
582
583        // Now fire up the Intermediate CA OCSP responder
584        intOcsp = new SimpleOCSPServer(intKeystore, passwd,
585                INT_ALIAS, null);
586        intOcsp.enableLog(debug);
587        intOcsp.setNextUpdateInterval(3600);
588        intOcsp.start();
589
590        // Wait 5 seconds for server ready
591        for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) {
592            Thread.sleep(50);
593        }
594        if (!intOcsp.isServerReady()) {
595            throw new RuntimeException("Server not ready yet");
596        }
597
598        intOcspPort = intOcsp.getPort();
599        String intCaRespURI = "http://localhost:" + intOcspPort;
600        log("Intermediate CA OCSP Responder URI is " + intCaRespURI);
601
602        // Last but not least, let's make our SSLCert and add it to its own
603        // Keystore
604        cbld.reset();
605        cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany");
606        cbld.setPublicKey(sslKP.getPublic());
607        cbld.setSerialNumber(new BigInteger("4096"));
608        // Make a 1 year validity starting from 7 days ago
609        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);
610        end = start + TimeUnit.DAYS.toMillis(365);
611        cbld.setValidity(new Date(start), new Date(end));
612
613        // Add extensions
614        addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic());
615        boolean[] kuBits = {true, false, true, false, false, false,
616            false, false, false};
617        cbld.addKeyUsageExt(kuBits);
618        List<String> ekuOids = new ArrayList<>();
619        ekuOids.add("1.3.6.1.5.5.7.3.1");
620        ekuOids.add("1.3.6.1.5.5.7.3.2");
621        cbld.addExtendedKeyUsageExt(ekuOids);
622        cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost"));
623        cbld.addAIAExt(Collections.singletonList(intCaRespURI));
624        // Make our SSL Server Cert!
625        X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(),
626                "SHA256withRSA");
627        log("SSL Certificate Created:\n" + certInfo(sslCert));
628
629        // Provide SSL server cert revocation info to the Intermeidate CA
630        // OCSP responder.
631        revInfo = new HashMap<>();
632        revInfo.put(sslCert.getSerialNumber(),
633                new SimpleOCSPServer.CertStatusInfo(
634                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
635        intOcsp.updateStatusDb(revInfo);
636
637        // Now build a keystore and add the keys, chain and root cert as a TA
638        serverKeystore = keyStoreBuilder.getKeyStore();
639        Certificate[] sslChain = {sslCert, intCaCert, rootCert};
640        serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(),
641                passwd.toCharArray(), sslChain);
642        serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
643
644        // And finally a Trust Store for the client
645        trustStore = keyStoreBuilder.getKeyStore();
646        trustStore.setCertificateEntry(ROOT_ALIAS, rootCert);
647    }
648
649    private static void addCommonExts(CertificateBuilder cbld,
650            PublicKey subjKey, PublicKey authKey) throws IOException {
651        cbld.addSubjectKeyIdExt(subjKey);
652        cbld.addAuthorityKeyIdExt(authKey);
653    }
654
655    private static void addCommonCAExts(CertificateBuilder cbld)
656            throws IOException {
657        cbld.addBasicConstraintsExt(true, true, -1);
658        // Set key usage bits for digitalSignature, keyCertSign and cRLSign
659        boolean[] kuBitSettings = {true, false, false, false, false, true,
660            true, false, false};
661        cbld.addKeyUsageExt(kuBitSettings);
662    }
663
664    /**
665     * Helper routine that dumps only a few cert fields rather than
666     * the whole toString() output.
667     *
668     * @param cert an X509Certificate to be displayed
669     *
670     * @return the String output of the issuer, subject and
671     * serial number
672     */
673    private static String certInfo(X509Certificate cert) {
674        StringBuilder sb = new StringBuilder();
675        sb.append("Issuer: ").append(cert.getIssuerX500Principal()).
676                append("\n");
677        sb.append("Subject: ").append(cert.getSubjectX500Principal()).
678                append("\n");
679        sb.append("Serial: ").append(cert.getSerialNumber()).append("\n");
680        return sb.toString();
681    }
682
683    /**
684     * Log a message on stdout
685     *
686     * @param message The message to log
687     */
688    private static void log(String message) {
689        if (debug) {
690            System.out.println(message);
691        }
692    }
693
694    // The following two classes are Simple nested class to group a handful
695    // of configuration parameters used before starting a client or server.
696    // We'll just access the data members directly for convenience.
697    static class ClientParameters {
698        boolean enabled = true;
699        PKIXBuilderParameters pkixParams = null;
700        PKIXRevocationChecker revChecker = null;
701
702        ClientParameters() { }
703    }
704
705    static class ServerParameters {
706        boolean enabled = true;
707        int cacheSize = 256;
708        int cacheLifetime = 3600;
709        int respTimeout = 5000;
710        String respUri = "";
711        boolean respOverride = false;
712        boolean ignoreExts = false;
713
714        ServerParameters() { }
715    }
716
717    static class TestResult {
718        Exception serverExc = null;
719        Exception clientExc = null;
720    }
721
722    static class HtucSSLSocketFactory extends SSLSocketFactory {
723        SSLContext sslc = SSLContext.getInstance("TLS");
724
725        HtucSSLSocketFactory(ClientParameters cliParams)
726                throws GeneralSecurityException {
727            super();
728
729            // Create the Trust Manager Factory using the PKIX variant
730            TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
731
732            // If we have a customized pkixParameters then use it
733            if (cliParams.pkixParams != null) {
734                // LIf we have a customized PKIXRevocationChecker, add
735                // it to the PKIXBuilderParameters.
736                if (cliParams.revChecker != null) {
737                    cliParams.pkixParams.addCertPathChecker(
738                            cliParams.revChecker);
739                }
740
741                ManagerFactoryParameters trustParams =
742                        new CertPathTrustManagerParameters(
743                                cliParams.pkixParams);
744                tmf.init(trustParams);
745            } else {
746                tmf.init(trustStore);
747            }
748
749            sslc.init(null, tmf.getTrustManagers(), null);
750        }
751
752        @Override
753        public Socket createSocket(Socket s, String host, int port,
754                boolean autoClose) throws IOException {
755            Socket sock =  sslc.getSocketFactory().createSocket(s, host, port,
756                    autoClose);
757            setCiphers(sock);
758            return sock;
759        }
760
761        @Override
762        public Socket createSocket(InetAddress host, int port)
763                throws IOException {
764            Socket sock = sslc.getSocketFactory().createSocket(host, port);
765            setCiphers(sock);
766            return sock;
767        }
768
769        @Override
770        public Socket createSocket(InetAddress host, int port,
771                InetAddress localAddress, int localPort) throws IOException {
772            Socket sock = sslc.getSocketFactory().createSocket(host, port,
773                    localAddress, localPort);
774            setCiphers(sock);
775            return sock;
776        }
777
778        @Override
779        public Socket createSocket(String host, int port)
780                throws IOException {
781            Socket sock =  sslc.getSocketFactory().createSocket(host, port);
782            setCiphers(sock);
783            return sock;
784        }
785
786        @Override
787        public Socket createSocket(String host, int port,
788                InetAddress localAddress, int localPort)
789                throws IOException {
790            Socket sock =  sslc.getSocketFactory().createSocket(host, port,
791                    localAddress, localPort);
792            setCiphers(sock);
793            return sock;
794        }
795
796        @Override
797        public String[] getDefaultCipherSuites() {
798            return sslc.getDefaultSSLParameters().getCipherSuites();
799        }
800
801        @Override
802        public String[] getSupportedCipherSuites() {
803            return sslc.getSupportedSSLParameters().getCipherSuites();
804        }
805
806        private static void setCiphers(Socket sock) {
807            if (sock instanceof SSLSocket) {
808                String[] ciphers = { "TLS_RSA_WITH_AES_128_CBC_SHA" };
809                ((SSLSocket)sock).setEnabledCipherSuites(ciphers);
810            }
811        }
812    }
813
814}
815