Path: blob/master/test/jdk/javax/net/ssl/Stapling/HttpsUrlConnClient.java
41152 views
/*1* Copyright (c) 2015, 2018, 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 8046321 815382929* @summary OCSP Stapling for TLS30* @library ../../../../java/security/testlibrary31* @build CertificateBuilder SimpleOCSPServer32* @run main/othervm HttpsUrlConnClient33*/3435import java.io.*;36import java.math.BigInteger;37import java.security.KeyPair;38import java.security.KeyPairGenerator;39import java.net.Socket;40import java.net.URL;41import java.net.HttpURLConnection;42import java.net.InetAddress;43import javax.net.ssl.*;44import java.security.KeyStore;45import java.security.PublicKey;46import java.security.Security;47import java.security.GeneralSecurityException;48import java.security.cert.CertPathValidatorException;49import java.security.cert.CertPathValidatorException.BasicReason;50import java.security.cert.Certificate;51import java.security.cert.PKIXBuilderParameters;52import java.security.cert.X509CertSelector;53import java.security.cert.X509Certificate;54import java.security.cert.PKIXRevocationChecker;55import java.security.spec.PKCS8EncodedKeySpec;56import java.text.SimpleDateFormat;57import java.util.*;58import java.util.concurrent.TimeUnit;5960import sun.security.testlibrary.SimpleOCSPServer;61import sun.security.testlibrary.CertificateBuilder;62import sun.security.validator.ValidatorException;6364public class HttpsUrlConnClient {6566/*67* =============================================================68* Set the various variables needed for the tests, then69* specify what tests to run on each side.70*/7172static final byte[] LINESEP = { 10 };73static final Base64.Encoder B64E = Base64.getMimeEncoder(64, LINESEP);7475// Turn on TLS debugging76static boolean debug = true;7778/*79* Should we run the client or server in a separate thread?80* Both sides can throw exceptions, but do you have a preference81* as to which side should be the main thread.82*/83static boolean separateServerThread = true;84Thread clientThread = null;85Thread serverThread = null;8687static String passwd = "passphrase";88static String ROOT_ALIAS = "root";89static String INT_ALIAS = "intermediate";90static String SSL_ALIAS = "ssl";9192/*93* Is the server ready to serve?94*/95volatile static boolean serverReady = false;96volatile int serverPort = 0;9798volatile Exception serverException = null;99volatile Exception clientException = null;100101// PKI components we will need for this test102static KeyStore rootKeystore; // Root CA Keystore103static KeyStore intKeystore; // Intermediate CA Keystore104static KeyStore serverKeystore; // SSL Server Keystore105static KeyStore trustStore; // SSL Client trust store106static SimpleOCSPServer rootOcsp; // Root CA OCSP Responder107static int rootOcspPort; // Port number for root OCSP108static SimpleOCSPServer intOcsp; // Intermediate CA OCSP Responder109static int intOcspPort; // Port number for intermed. OCSP110111// Extra configuration parameters and constants112static final String[] TLS13ONLY = new String[] { "TLSv1.3" };113static final String[] TLS12MAX =114new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" };115116private static final String SIMPLE_WEB_PAGE = "<HTML>\n" +117"<HEAD><Title>Web Page!</Title></HEAD>\n" +118"<BODY><H1>Web Page!</H1></BODY>\n</HTML>";119private static final SimpleDateFormat utcDateFmt =120new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");121/*122* If the client or server is doing some kind of object creation123* that the other side depends on, and that thread prematurely124* exits, you may experience a hang. The test harness will125* terminate all hung threads after its timeout has expired,126* currently 3 minutes by default, but you might try to be127* smart about it....128*/129public static void main(String[] args) throws Exception {130if (debug) {131System.setProperty("javax.net.debug", "ssl:handshake");132}133134System.setProperty("javax.net.ssl.keyStore", "");135System.setProperty("javax.net.ssl.keyStorePassword", "");136System.setProperty("javax.net.ssl.trustStore", "");137System.setProperty("javax.net.ssl.trustStorePassword", "");138139// Create the PKI we will use for the test and start the OCSP servers140createPKI();141utcDateFmt.setTimeZone(TimeZone.getTimeZone("GMT"));142143testPKIXParametersRevEnabled(TLS12MAX);144testPKIXParametersRevEnabled(TLS13ONLY);145146// shut down the OCSP responders before finishing the test147intOcsp.stop();148rootOcsp.stop();149}150151/**152* Do a basic connection using PKIXParameters with revocation checking153* enabled and client-side OCSP disabled. It will only pass if all154* stapled responses are present, valid and have a GOOD status.155*/156static void testPKIXParametersRevEnabled(String[] allowedProts)157throws Exception {158ClientParameters cliParams = new ClientParameters();159cliParams.protocols = allowedProts;160ServerParameters servParams = new ServerParameters();161serverReady = false;162163System.out.println("=====================================");164System.out.println("Stapling enabled, PKIXParameters with");165System.out.println("Revocation checking enabled ");166System.out.println("=====================================");167168// Set the certificate entry in the intermediate OCSP responder169// with a revocation date of 8 hours ago.170X509Certificate sslCert =171(X509Certificate)serverKeystore.getCertificate(SSL_ALIAS);172Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =173new HashMap<>();174revInfo.put(sslCert.getSerialNumber(),175new SimpleOCSPServer.CertStatusInfo(176SimpleOCSPServer.CertStatus.CERT_STATUS_REVOKED,177new Date(System.currentTimeMillis() -178TimeUnit.HOURS.toMillis(8))));179intOcsp.updateStatusDb(revInfo);180181// Set up revocation checking on the client with no client-side182// OCSP fall-back183cliParams.pkixParams = new PKIXBuilderParameters(trustStore,184new X509CertSelector());185cliParams.pkixParams.setRevocationEnabled(true);186Security.setProperty("ocsp.enable", "false");187188HttpsUrlConnClient sslTest = new HttpsUrlConnClient(cliParams,189servParams);190TestResult tr = sslTest.getResult();191if (!checkClientValidationFailure(tr.clientExc, BasicReason.REVOKED)) {192if (tr.clientExc != null) {193throw tr.clientExc;194} else {195throw new RuntimeException(196"Expected client failure, but the client succeeded");197}198}199200// In this case the server should also have thrown an exception201// because of the client alert202if (tr.serverExc instanceof SSLHandshakeException) {203if (!tr.serverExc.getMessage().contains(204"bad_certificate_status_response")) {205throw tr.serverExc;206}207}208209System.out.println(" PASS");210System.out.println("=====================================\n");211}212213/*214* Define the server side of the test.215*216* If the server prematurely exits, serverReady will be set to true217* to avoid infinite hangs.218*/219void doServerSide(ServerParameters servParams) throws Exception {220221// Selectively enable or disable the feature222System.setProperty("jdk.tls.server.enableStatusRequestExtension",223Boolean.toString(servParams.enabled));224225// Set all the other operating parameters226System.setProperty("jdk.tls.stapling.cacheSize",227Integer.toString(servParams.cacheSize));228System.setProperty("jdk.tls.stapling.cacheLifetime",229Integer.toString(servParams.cacheLifetime));230System.setProperty("jdk.tls.stapling.responseTimeout",231Integer.toString(servParams.respTimeout));232System.setProperty("jdk.tls.stapling.responderURI", servParams.respUri);233System.setProperty("jdk.tls.stapling.responderOverride",234Boolean.toString(servParams.respOverride));235System.setProperty("jdk.tls.stapling.ignoreExtensions",236Boolean.toString(servParams.ignoreExts));237238// Set keystores and trust stores for the server239KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");240kmf.init(serverKeystore, passwd.toCharArray());241TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");242tmf.init(trustStore);243244SSLContext sslc = SSLContext.getInstance("TLS");245sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);246247SSLServerSocketFactory sslssf = sslc.getServerSocketFactory();248SSLServerSocket sslServerSocket =249(SSLServerSocket) sslssf.createServerSocket(serverPort);250251serverPort = sslServerSocket.getLocalPort();252log("Server Port is " + serverPort);253254// Dump the private key in PKCS8 format, not encrypted. This255// key dump can be used if the traffic was captured using tcpdump256// or wireshark to look into the encrypted packets for debug purposes.257if (debug) {258byte[] keybytes = serverKeystore.getKey(SSL_ALIAS,259passwd.toCharArray()).getEncoded();260PKCS8EncodedKeySpec p8spec = new PKCS8EncodedKeySpec(keybytes);261StringBuilder keyPem = new StringBuilder();262keyPem.append("-----BEGIN PRIVATE KEY-----\n");263keyPem.append(B64E.encodeToString(p8spec.getEncoded())).append("\n");264keyPem.append("-----END PRIVATE KEY-----\n");265log("Private key is:\n" + keyPem.toString());266}267268/*269* Signal Client, we're ready for his connect.270*/271serverReady = true;272273try (SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();274BufferedReader in = new BufferedReader(275new InputStreamReader(sslSocket.getInputStream()));276OutputStream out = sslSocket.getOutputStream()) {277StringBuilder hdrBldr = new StringBuilder();278String line;279while ((line = in.readLine()) != null && !line.isEmpty()) {280hdrBldr.append(line).append("\n");281}282String headerText = hdrBldr.toString();283log("Header Received: " + headerText.length() + " bytes\n" +284headerText);285286StringBuilder sb = new StringBuilder();287sb.append("HTTP/1.0 200 OK\r\n");288sb.append("Date: ").append(utcDateFmt.format(new Date())).289append("\r\n");290sb.append("Content-Type: text/html\r\n");291sb.append("Content-Length: ").append(SIMPLE_WEB_PAGE.length());292sb.append("\r\n\r\n");293out.write(sb.toString().getBytes("UTF-8"));294out.write(SIMPLE_WEB_PAGE.getBytes("UTF-8"));295out.flush();296log("Server replied with:\n" + sb.toString() + SIMPLE_WEB_PAGE);297}298}299300/*301* Define the client side of the test.302*303* If the server prematurely exits, serverReady will be set to true304* to avoid infinite hangs.305*/306void doClientSide(ClientParameters cliParams) throws Exception {307308// Wait 5 seconds for server ready309for (int i = 0; (i < 100 && !serverReady); i++) {310Thread.sleep(50);311}312if (!serverReady) {313throw new RuntimeException("Server not ready yet");314}315316// Selectively enable or disable the feature317System.setProperty("jdk.tls.client.enableStatusRequestExtension",318Boolean.toString(cliParams.enabled));319320HtucSSLSocketFactory sockFac = new HtucSSLSocketFactory(cliParams);321HttpsURLConnection.setDefaultSSLSocketFactory(sockFac);322URL location = new URL("https://localhost:" + serverPort);323HttpsURLConnection tlsConn =324(HttpsURLConnection)location.openConnection();325tlsConn.setConnectTimeout(5000);326tlsConn.setReadTimeout(5000);327tlsConn.setDoInput(true);328329try (InputStream in = tlsConn.getInputStream()) {330// Check the response331if (debug && tlsConn.getResponseCode() !=332HttpURLConnection.HTTP_OK) {333log("Received HTTP error: " + tlsConn.getResponseCode() +334" - " + tlsConn.getResponseMessage());335throw new IOException("HTTP error: " +336tlsConn.getResponseCode());337}338339int contentLength = tlsConn.getContentLength();340if (contentLength == -1) {341contentLength = Integer.MAX_VALUE;342}343byte[] response = new byte[contentLength > 2048 ? 2048 :344contentLength];345int total = 0;346while (total < contentLength) {347int count = in.read(response, total, response.length - total);348if (count < 0)349break;350351total += count;352log("Read " + count + " bytes (" + total + " total)");353if (total >= response.length && total < contentLength) {354response = Arrays.copyOf(response, total * 2);355}356}357response = Arrays.copyOf(response, total);358String webPage = new String(response, 0, total);359if (debug) {360log("Web page:\n" + webPage);361}362}363}364365/*366* Primary constructor, used to drive remainder of the test.367*368* Fork off the other side, then do your work.369*/370HttpsUrlConnClient(ClientParameters cliParams,371ServerParameters servParams) throws Exception {372Exception startException = null;373try {374if (separateServerThread) {375startServer(servParams, true);376startClient(cliParams, false);377} else {378startClient(cliParams, true);379startServer(servParams, false);380}381} catch (Exception e) {382startException = e;383}384385/*386* Wait for other side to close down.387*/388if (separateServerThread) {389if (serverThread != null) {390serverThread.join();391}392} else {393if (clientThread != null) {394clientThread.join();395}396}397}398399/**400* Checks a validation failure to see if it failed for the reason we think401* it should. This comes in as an SSLException of some sort, but it402* encapsulates a CertPathValidatorException at some point in the403* exception stack.404*405* @param e the exception thrown at the top level406* @param reason the underlying CertPathValidatorException BasicReason407* we are expecting it to have.408*409* @return true if the reason matches up, false otherwise.410*/411static boolean checkClientValidationFailure(Exception e,412BasicReason reason) {413boolean result = false;414415// Locate the CertPathValidatorException. If one416// Does not exist, then it's an automatic failure of417// the test.418Throwable curExc = e;419CertPathValidatorException cpve = null;420while (curExc != null) {421if (curExc instanceof CertPathValidatorException) {422cpve = (CertPathValidatorException)curExc;423}424curExc = curExc.getCause();425}426427// If we get through the loop and cpve is null then we428// we didn't find CPVE and this is a failure429if (cpve != null) {430if (cpve.getReason() == reason) {431result = true;432} else {433System.out.println("CPVE Reason Mismatch: Expected = " +434reason + ", Actual = " + cpve.getReason());435}436} else {437System.out.println("Failed to find an expected CPVE");438}439440return result;441}442443TestResult getResult() {444TestResult tr = new TestResult();445tr.clientExc = clientException;446tr.serverExc = serverException;447return tr;448}449450final void startServer(ServerParameters servParams, boolean newThread)451throws Exception {452if (newThread) {453serverThread = new Thread() {454@Override455public void run() {456try {457doServerSide(servParams);458} catch (Exception e) {459/*460* Our server thread just died.461*462* Release the client, if not active already...463*/464System.err.println("Server died...");465serverReady = true;466serverException = e;467}468}469};470serverThread.start();471} else {472try {473doServerSide(servParams);474} catch (Exception e) {475serverException = e;476} finally {477serverReady = true;478}479}480}481482final void startClient(ClientParameters cliParams, boolean newThread)483throws Exception {484if (newThread) {485clientThread = new Thread() {486@Override487public void run() {488try {489doClientSide(cliParams);490} catch (Exception e) {491/*492* Our client thread just died.493*/494System.err.println("Client died...");495clientException = e;496}497}498};499clientThread.start();500} else {501try {502doClientSide(cliParams);503} catch (Exception e) {504clientException = e;505}506}507}508509/**510* Creates the PKI components necessary for this test, including511* Root CA, Intermediate CA and SSL server certificates, the keystores512* for each entity, a client trust store, and starts the OCSP responders.513*/514private static void createPKI() throws Exception {515CertificateBuilder cbld = new CertificateBuilder();516KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");517keyGen.initialize(2048);518KeyStore.Builder keyStoreBuilder =519KeyStore.Builder.newInstance("PKCS12", null,520new KeyStore.PasswordProtection(passwd.toCharArray()));521522// Generate Root, IntCA, EE keys523KeyPair rootCaKP = keyGen.genKeyPair();524log("Generated Root CA KeyPair");525KeyPair intCaKP = keyGen.genKeyPair();526log("Generated Intermediate CA KeyPair");527KeyPair sslKP = keyGen.genKeyPair();528log("Generated SSL Cert KeyPair");529530// Set up the Root CA Cert531cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany");532cbld.setPublicKey(rootCaKP.getPublic());533cbld.setSerialNumber(new BigInteger("1"));534// Make a 3 year validity starting from 60 days ago535long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60);536long end = start + TimeUnit.DAYS.toMillis(1085);537cbld.setValidity(new Date(start), new Date(end));538addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic());539addCommonCAExts(cbld);540// Make our Root CA Cert!541X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(),542"SHA256withRSA");543log("Root CA Created:\n" + certInfo(rootCert));544545// Now build a keystore and add the keys and cert546rootKeystore = keyStoreBuilder.getKeyStore();547Certificate[] rootChain = {rootCert};548rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(),549passwd.toCharArray(), rootChain);550551// Now fire up the OCSP responder552rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null);553rootOcsp.enableLog(debug);554rootOcsp.setNextUpdateInterval(3600);555rootOcsp.start();556557// Wait 5 seconds for server ready558for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) {559Thread.sleep(50);560}561if (!rootOcsp.isServerReady()) {562throw new RuntimeException("Server not ready yet");563}564565rootOcspPort = rootOcsp.getPort();566String rootRespURI = "http://localhost:" + rootOcspPort;567log("Root OCSP Responder URI is " + rootRespURI);568569// Now that we have the root keystore and OCSP responder we can570// create our intermediate CA.571cbld.reset();572cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany");573cbld.setPublicKey(intCaKP.getPublic());574cbld.setSerialNumber(new BigInteger("100"));575// Make a 2 year validity starting from 30 days ago576start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30);577end = start + TimeUnit.DAYS.toMillis(730);578cbld.setValidity(new Date(start), new Date(end));579addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic());580addCommonCAExts(cbld);581cbld.addAIAExt(Collections.singletonList(rootRespURI));582// Make our Intermediate CA Cert!583X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(),584"SHA256withRSA");585log("Intermediate CA Created:\n" + certInfo(intCaCert));586587// Provide intermediate CA cert revocation info to the Root CA588// OCSP responder.589Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =590new HashMap<>();591revInfo.put(intCaCert.getSerialNumber(),592new SimpleOCSPServer.CertStatusInfo(593SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));594rootOcsp.updateStatusDb(revInfo);595596// Now build a keystore and add the keys, chain and root cert as a TA597intKeystore = keyStoreBuilder.getKeyStore();598Certificate[] intChain = {intCaCert, rootCert};599intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(),600passwd.toCharArray(), intChain);601intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);602603// Now fire up the Intermediate CA OCSP responder604intOcsp = new SimpleOCSPServer(intKeystore, passwd,605INT_ALIAS, null);606intOcsp.enableLog(debug);607intOcsp.setNextUpdateInterval(3600);608intOcsp.start();609610// Wait 5 seconds for server ready611for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) {612Thread.sleep(50);613}614if (!intOcsp.isServerReady()) {615throw new RuntimeException("Server not ready yet");616}617618intOcspPort = intOcsp.getPort();619String intCaRespURI = "http://localhost:" + intOcspPort;620log("Intermediate CA OCSP Responder URI is " + intCaRespURI);621622// Last but not least, let's make our SSLCert and add it to its own623// Keystore624cbld.reset();625cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany");626cbld.setPublicKey(sslKP.getPublic());627cbld.setSerialNumber(new BigInteger("4096"));628// Make a 1 year validity starting from 7 days ago629start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);630end = start + TimeUnit.DAYS.toMillis(365);631cbld.setValidity(new Date(start), new Date(end));632633// Add extensions634addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic());635boolean[] kuBits = {true, false, true, false, false, false,636false, false, false};637cbld.addKeyUsageExt(kuBits);638List<String> ekuOids = new ArrayList<>();639ekuOids.add("1.3.6.1.5.5.7.3.1");640ekuOids.add("1.3.6.1.5.5.7.3.2");641cbld.addExtendedKeyUsageExt(ekuOids);642cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost"));643cbld.addAIAExt(Collections.singletonList(intCaRespURI));644// Make our SSL Server Cert!645X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(),646"SHA256withRSA");647log("SSL Certificate Created:\n" + certInfo(sslCert));648649// Provide SSL server cert revocation info to the Intermeidate CA650// OCSP responder.651revInfo = new HashMap<>();652revInfo.put(sslCert.getSerialNumber(),653new SimpleOCSPServer.CertStatusInfo(654SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));655intOcsp.updateStatusDb(revInfo);656657// Now build a keystore and add the keys, chain and root cert as a TA658serverKeystore = keyStoreBuilder.getKeyStore();659Certificate[] sslChain = {sslCert, intCaCert, rootCert};660serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(),661passwd.toCharArray(), sslChain);662serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);663664// And finally a Trust Store for the client665trustStore = keyStoreBuilder.getKeyStore();666trustStore.setCertificateEntry(ROOT_ALIAS, rootCert);667}668669private static void addCommonExts(CertificateBuilder cbld,670PublicKey subjKey, PublicKey authKey) throws IOException {671cbld.addSubjectKeyIdExt(subjKey);672cbld.addAuthorityKeyIdExt(authKey);673}674675private static void addCommonCAExts(CertificateBuilder cbld)676throws IOException {677cbld.addBasicConstraintsExt(true, true, -1);678// Set key usage bits for digitalSignature, keyCertSign and cRLSign679boolean[] kuBitSettings = {true, false, false, false, false, true,680true, false, false};681cbld.addKeyUsageExt(kuBitSettings);682}683684/**685* Helper routine that dumps only a few cert fields rather than686* the whole toString() output.687*688* @param cert an X509Certificate to be displayed689*690* @return the String output of the issuer, subject and691* serial number692*/693private static String certInfo(X509Certificate cert) {694StringBuilder sb = new StringBuilder();695sb.append("Issuer: ").append(cert.getIssuerX500Principal()).696append("\n");697sb.append("Subject: ").append(cert.getSubjectX500Principal()).698append("\n");699sb.append("Serial: ").append(cert.getSerialNumber()).append("\n");700return sb.toString();701}702703/**704* Log a message on stdout705*706* @param message The message to log707*/708private static void log(String message) {709if (debug) {710System.out.println(message);711}712}713714// The following two classes are Simple nested class to group a handful715// of configuration parameters used before starting a client or server.716// We'll just access the data members directly for convenience.717static class ClientParameters {718boolean enabled = true;719PKIXBuilderParameters pkixParams = null;720PKIXRevocationChecker revChecker = null;721String[] protocols = null;722String[] cipherSuites = null;723724ClientParameters() { }725}726727static class ServerParameters {728boolean enabled = true;729int cacheSize = 256;730int cacheLifetime = 3600;731int respTimeout = 5000;732String respUri = "";733boolean respOverride = false;734boolean ignoreExts = false;735736ServerParameters() { }737}738739static class TestResult {740Exception serverExc = null;741Exception clientExc = null;742743@Override744public String toString() {745StringBuilder sb = new StringBuilder();746sb.append("Test Result:\n").747append("\tServer Exc = ").append(serverExc).append("\n").748append("\tClient Exc = ").append(clientExc).append("\n");749return sb.toString();750}751}752753static class HtucSSLSocketFactory extends SSLSocketFactory {754ClientParameters params;755SSLContext sslc = SSLContext.getInstance("TLS");756757HtucSSLSocketFactory(ClientParameters cliParams)758throws GeneralSecurityException {759super();760761// Create the Trust Manager Factory using the PKIX variant762TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");763764// If we have a customized pkixParameters then use it765if (cliParams.pkixParams != null) {766// LIf we have a customized PKIXRevocationChecker, add767// it to the PKIXBuilderParameters.768if (cliParams.revChecker != null) {769cliParams.pkixParams.addCertPathChecker(770cliParams.revChecker);771}772773ManagerFactoryParameters trustParams =774new CertPathTrustManagerParameters(775cliParams.pkixParams);776tmf.init(trustParams);777} else {778tmf.init(trustStore);779}780781sslc.init(null, tmf.getTrustManagers(), null);782params = cliParams;783}784785@Override786public Socket createSocket(Socket s, String host, int port,787boolean autoClose) throws IOException {788Socket sock = sslc.getSocketFactory().createSocket(s, host, port,789autoClose);790customizeSocket(sock);791return sock;792}793794@Override795public Socket createSocket(InetAddress host, int port)796throws IOException {797Socket sock = sslc.getSocketFactory().createSocket(host, port);798customizeSocket(sock);799return sock;800}801802@Override803public Socket createSocket(InetAddress host, int port,804InetAddress localAddress, int localPort) throws IOException {805Socket sock = sslc.getSocketFactory().createSocket(host, port,806localAddress, localPort);807customizeSocket(sock);808return sock;809}810811@Override812public Socket createSocket(String host, int port)813throws IOException {814Socket sock = sslc.getSocketFactory().createSocket(host, port);815customizeSocket(sock);816return sock;817}818819@Override820public Socket createSocket(String host, int port,821InetAddress localAddress, int localPort)822throws IOException {823Socket sock = sslc.getSocketFactory().createSocket(host, port,824localAddress, localPort);825customizeSocket(sock);826return sock;827}828829@Override830public String[] getDefaultCipherSuites() {831return sslc.getDefaultSSLParameters().getCipherSuites();832}833834@Override835public String[] getSupportedCipherSuites() {836return sslc.getSupportedSSLParameters().getCipherSuites();837}838839private void customizeSocket(Socket sock) {840if (sock instanceof SSLSocket) {841SSLSocket sslSock = (SSLSocket)sock;842if (params.protocols != null) {843sslSock.setEnabledProtocols(params.protocols);844}845if (params.cipherSuites != null) {846sslSock.setEnabledCipherSuites(params.cipherSuites);847}848}849}850}851852}853854855