# HG changeset patch # User jnimeh # Date 1527190320 25200 # Node ID 0cabcf9cb31b43c8504992a27212d284675fda3a # Parent afb358e14f2916692fd30d45c8b326c2393567eb TLS 1.3 support in OCSP stapling jtreg tests Summary: Adds test cases for OCSP stapling using the TLS 1.3 handshake diff -r afb358e14f29 -r 0cabcf9cb31b test/jdk/javax/net/ssl/Stapling/SSLEngineWithStapling.java --- a/test/jdk/javax/net/ssl/Stapling/SSLEngineWithStapling.java Thu May 24 11:34:31 2018 -0700 +++ b/test/jdk/javax/net/ssl/Stapling/SSLEngineWithStapling.java Thu May 24 12:32:00 2018 -0700 @@ -106,7 +106,7 @@ * including specific handshake messages, and might be best examined * after gaining some familiarity with this application. */ - private static final boolean debug = false; + private static final boolean debug = true; private SSLEngine clientEngine; // client Engine private ByteBuffer clientOut; // write side of clientEngine @@ -142,12 +142,17 @@ static SimpleOCSPServer intOcsp; // Intermediate CA OCSP Responder static int intOcspPort; // Port number for intermed. OCSP + // Extra configuration parameters and constants + static final String[] TLS13ONLY = new String[] { "TLSv1.3" }; + static final String[] TLS12MAX = + new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" }; + /* * Main entry point for this test. */ public static void main(String args[]) throws Exception { if (debug) { - System.setProperty("javax.net.debug", "ssl"); + System.setProperty("javax.net.debug", "ssl:handshake"); } // Create the PKI we will use for the test and start the OCSP servers @@ -166,16 +171,23 @@ TimeUnit.HOURS.toMillis(8)))); intOcsp.updateStatusDb(revInfo); - SSLEngineWithStapling test = new SSLEngineWithStapling(); - try { - test.runTest(); - throw new RuntimeException("Expected failure due to revocation " + - "did not occur"); - } catch (Exception e) { - if (!checkClientValidationFailure(e, - CertPathValidatorException.BasicReason.REVOKED)) { - System.out.println("*** Didn't find the exception we wanted"); - throw e; + // Create a list of TLS protocol configurations we can use to + // drive tests with different handshaking models. + List allowedProtList = List.of(TLS12MAX, TLS13ONLY); + + for (String[] protocols : allowedProtList) { + SSLEngineWithStapling test = new SSLEngineWithStapling(); + try { + test.runTest(protocols); + throw new RuntimeException("Expected failure due to " + + "revocation did not occur"); + } catch (Exception e) { + if (!checkClientValidationFailure(e, + CertPathValidatorException.BasicReason.REVOKED)) { + System.out.println( + "*** Didn't find the exception we wanted"); + throw e; + } } } @@ -218,10 +230,10 @@ * One could easily separate these phases into separate * sections of code. */ - private void runTest() throws Exception { + private void runTest(String[] protocols) throws Exception { boolean dataDone = false; - createSSLEngines(); + createSSLEngines(protocols); createBuffers(); SSLEngineResult clientResult; // results from client's last operation @@ -290,7 +302,7 @@ * Using the SSLContext created during object creation, * create/configure the SSLEngines we'll use for this test. */ - private void createSSLEngines() throws Exception { + private void createSSLEngines(String[] protocols) throws Exception { // Initialize the KeyManager and TrustManager for the server KeyManagerFactory servKmf = KeyManagerFactory.getInstance("PKIX"); servKmf.init(serverKeystore, passwd.toCharArray()); @@ -309,10 +321,10 @@ cliTmf.init(mfp); // Create the SSLContexts from the factories - SSLContext servCtx = SSLContext.getInstance("TLSv1.2"); + SSLContext servCtx = SSLContext.getInstance("TLS"); servCtx.init(servKmf.getKeyManagers(), servTmf.getTrustManagers(), null); - SSLContext cliCtx = SSLContext.getInstance("TLSv1.2"); + SSLContext cliCtx = SSLContext.getInstance("TLS"); cliCtx.init(null, cliTmf.getTrustManagers(), null); @@ -321,6 +333,7 @@ * handshake. */ serverEngine = servCtx.createSSLEngine(); + serverEngine.setEnabledProtocols(protocols); serverEngine.setUseClientMode(false); serverEngine.setNeedClientAuth(false); @@ -328,6 +341,7 @@ * Similar to above, but using client mode instead. */ clientEngine = cliCtx.createSSLEngine("client", 80); + clientEngine.setEnabledProtocols(protocols); clientEngine.setUseClientMode(true); } diff -r afb358e14f29 -r 0cabcf9cb31b test/jdk/javax/net/ssl/Stapling/SSLSocketWithStapling.java --- a/test/jdk/javax/net/ssl/Stapling/SSLSocketWithStapling.java Thu May 24 11:34:31 2018 -0700 +++ b/test/jdk/javax/net/ssl/Stapling/SSLSocketWithStapling.java Thu May 24 12:32:00 2018 -0700 @@ -35,6 +35,10 @@ import java.io.*; import java.math.BigInteger; +import java.net.InetAddress; +import java.net.Socket; +import java.net.ServerSocket; +import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.KeyPairGenerator; import javax.net.ssl.*; @@ -71,7 +75,7 @@ */ // Turn on TLS debugging - static boolean debug = false; + static final boolean debug = false; /* * Should we run the client or server in a separate thread? @@ -106,6 +110,11 @@ static SimpleOCSPServer intOcsp; // Intermediate CA OCSP Responder static int intOcspPort; // Port number for intermed. OCSP + // Extra configuration parameters and constants + static final String[] TLS13ONLY = new String[] { "TLSv1.3" }; + static final String[] TLS12MAX = + new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" }; + /* * If the client or server is doing some kind of object creation * that the other side depends on, and that thread prematurely @@ -116,20 +125,31 @@ */ public static void main(String[] args) throws Exception { if (debug) { - System.setProperty("javax.net.debug", "ssl"); + System.setProperty("javax.net.debug", "ssl:handshake"); } try { // Create the PKI we will use for the test and start the OCSP servers createPKI(); - testAllDefault(); - testPKIXParametersRevEnabled(); - testRevokedCertificate(); - testHardFailFallback(); - testSoftFailFallback(); - testLatencyNoStaple(false); - testLatencyNoStaple(true); + testAllDefault(false); + testAllDefault(true); + testPKIXParametersRevEnabled(false); + testPKIXParametersRevEnabled(true); + testRevokedCertificate(false); + testRevokedCertificate(true); + testRevokedIntermediate(false); + testRevokedIntermediate(true); + testMissingIntermediate(false); + testMissingIntermediate(true); + testHardFailFallback(false); + testHardFailFallback(true); + testSoftFailFallback(false); + testSoftFailFallback(true); + testLatencyNoStaple(false, false); + testLatencyNoStaple(false, true); + testLatencyNoStaple(true, false); + testLatencyNoStaple(true, true); } finally { // shut down the OCSP responders before finishing the test intOcsp.stop(); @@ -140,9 +160,16 @@ /** * Default test using no externally-configured PKIXBuilderParameters */ - static void testAllDefault() throws Exception { + static void testAllDefault(boolean isTls13) throws Exception { ClientParameters cliParams = new ClientParameters(); ServerParameters servParams = new ServerParameters(); + if (isTls13) { + cliParams.protocols = TLS13ONLY; + servParams.protocols = TLS13ONLY; + } else { + cliParams.protocols = TLS12MAX; + servParams.protocols = TLS12MAX; + } serverReady = false; Map revInfo = new HashMap<>(); @@ -188,9 +215,16 @@ * enabled and client-side OCSP disabled. It will only pass if all * stapled responses are present, valid and have a GOOD status. */ - static void testPKIXParametersRevEnabled() throws Exception { + static void testPKIXParametersRevEnabled(boolean isTls13) throws Exception { ClientParameters cliParams = new ClientParameters(); ServerParameters servParams = new ServerParameters(); + if (isTls13) { + cliParams.protocols = TLS13ONLY; + servParams.protocols = TLS13ONLY; + } else { + cliParams.protocols = TLS12MAX; + servParams.protocols = TLS12MAX; + } serverReady = false; System.out.println("====================================="); @@ -222,9 +256,16 @@ * pass if the OCSP response is found, since we will check the * CertPathValidatorException reason for revoked status. */ - static void testRevokedCertificate() throws Exception { + static void testRevokedCertificate(boolean isTls13) throws Exception { ClientParameters cliParams = new ClientParameters(); ServerParameters servParams = new ServerParameters(); + if (isTls13) { + cliParams.protocols = TLS13ONLY; + servParams.protocols = TLS13ONLY; + } else { + cliParams.protocols = TLS12MAX; + servParams.protocols = TLS12MAX; + } serverReady = false; Map revInfo = new HashMap<>(); @@ -274,13 +315,146 @@ } /** + * Perform a test where the intermediate CA certificate is revoked and + * placed in the TLS handshake. Client-side OCSP is disabled, so this + * test will only pass if the OCSP response for the intermediate CA is + * found and placed into the CertificateStatus or Certificate message + * (depending on the protocol version) since we will check + * the CertPathValidatorException reason for revoked status. + */ + static void testRevokedIntermediate(boolean isTls13) throws Exception { + ClientParameters cliParams = new ClientParameters(); + ServerParameters servParams = new ServerParameters(); + if (isTls13) { + cliParams.protocols = TLS13ONLY; + servParams.protocols = TLS13ONLY; + } else { + cliParams.protocols = TLS12MAX; + servParams.protocols = TLS12MAX; + } + serverReady = false; + Map revInfo = + new HashMap<>(); + + // We will prove revocation checking is disabled by marking the SSL + // certificate as revoked. The test would only pass if revocation + // checking did not happen. + X509Certificate intCACert = + (X509Certificate)intKeystore.getCertificate(INT_ALIAS); + Date fiveMinsAgo = new Date(System.currentTimeMillis() - + TimeUnit.MINUTES.toMillis(5)); + revInfo.put(intCACert.getSerialNumber(), + new SimpleOCSPServer.CertStatusInfo( + SimpleOCSPServer.CertStatus.CERT_STATUS_REVOKED, + fiveMinsAgo)); + rootOcsp.updateStatusDb(revInfo); + + System.out.println("==============================================="); + System.out.println("Stapling enabled, detect revoked CA certificate"); + System.out.println("==============================================="); + + cliParams.pkixParams = new PKIXBuilderParameters(trustStore, + new X509CertSelector()); + cliParams.pkixParams.setRevocationEnabled(true); + Security.setProperty("ocsp.enable", "false"); + + SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams, + servParams); + TestResult tr = sslTest.getResult(); + if (!checkClientValidationFailure(tr.clientExc, BasicReason.REVOKED)) { + if (tr.clientExc != null) { + throw tr.clientExc; + } else { + throw new RuntimeException( + "Expected client failure, but the client succeeded"); + } + } + + // Return the ssl certificate to non-revoked status + revInfo.put(intCACert.getSerialNumber(), + new SimpleOCSPServer.CertStatusInfo( + SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); + rootOcsp.updateStatusDb(revInfo); + + System.out.println(" PASS"); + System.out.println("=======================================\n"); + } + + /** + * Test a case where OCSP stapling is attempted, but partially occurs + * because the root OCSP responder is unreachable. This should use a + * default hard-fail behavior. + */ + static void testMissingIntermediate(boolean isTls13) throws Exception { + ClientParameters cliParams = new ClientParameters(); + ServerParameters servParams = new ServerParameters(); + if (isTls13) { + cliParams.protocols = TLS13ONLY; + servParams.protocols = TLS13ONLY; + } else { + cliParams.protocols = TLS12MAX; + servParams.protocols = TLS12MAX; + } + serverReady = false; + + // Make the OCSP responder reject connections + rootOcsp.rejectConnections(); + + System.out.println("======================================="); + System.out.println("Stapling enbled in client and server,"); + System.out.println("but root OCSP responder disabled."); + System.out.println("PKIXParameters with Revocation checking"); + System.out.println("enabled."); + System.out.println("======================================="); + + Security.setProperty("ocsp.enable", "false"); + cliParams.pkixParams = new PKIXBuilderParameters(trustStore, + new X509CertSelector()); + cliParams.pkixParams.setRevocationEnabled(true); + + SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams, + servParams); + TestResult tr = sslTest.getResult(); + if (!checkClientValidationFailure(tr.clientExc, + BasicReason.UNDETERMINED_REVOCATION_STATUS)) { + if (tr.clientExc != null) { + throw tr.clientExc; + } else { + throw new RuntimeException( + "Expected client failure, but the client succeeded"); + } + } + + System.out.println(" PASS"); + System.out.println("=======================================\n"); + + // Make root OCSP responder accept connections + rootOcsp.acceptConnections(); + + // Wait 5 seconds for server ready + for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) { + Thread.sleep(50); + } + if (!rootOcsp.isServerReady()) { + throw new RuntimeException("Root OCSP responder not ready yet"); + } + } + + /** * Test a case where client-side stapling is attempted, but does not * occur because OCSP responders are unreachable. This should use a * default hard-fail behavior. */ - static void testHardFailFallback() throws Exception { + static void testHardFailFallback(boolean isTls13) throws Exception { ClientParameters cliParams = new ClientParameters(); ServerParameters servParams = new ServerParameters(); + if (isTls13) { + cliParams.protocols = TLS13ONLY; + servParams.protocols = TLS13ONLY; + } else { + cliParams.protocols = TLS12MAX; + servParams.protocols = TLS12MAX; + } serverReady = false; // make OCSP responders reject connections @@ -320,7 +494,8 @@ rootOcsp.acceptConnections(); // Wait 5 seconds for server ready - for (int i = 0; (i < 100 && (!intOcsp.isServerReady() || !rootOcsp.isServerReady())); i++) { + for (int i = 0; (i < 100 && (!intOcsp.isServerReady() || + !rootOcsp.isServerReady())); i++) { Thread.sleep(50); } if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) { @@ -333,9 +508,16 @@ * occur because OCSP responders are unreachable. Client-side OCSP * checking is enabled for this, with SOFT_FAIL. */ - static void testSoftFailFallback() throws Exception { + static void testSoftFailFallback(boolean isTls13) throws Exception { ClientParameters cliParams = new ClientParameters(); ServerParameters servParams = new ServerParameters(); + if (isTls13) { + cliParams.protocols = TLS13ONLY; + servParams.protocols = TLS13ONLY; + } else { + cliParams.protocols = TLS12MAX; + servParams.protocols = TLS12MAX; + } serverReady = false; // make OCSP responders reject connections @@ -401,9 +583,17 @@ * will change the result from the client failing with CPVE (no fallback) * to a pass (fallback active). */ - static void testLatencyNoStaple(Boolean fallback) throws Exception { + static void testLatencyNoStaple(Boolean fallback, boolean isTls13) + throws Exception { ClientParameters cliParams = new ClientParameters(); ServerParameters servParams = new ServerParameters(); + if (isTls13) { + cliParams.protocols = TLS13ONLY; + servParams.protocols = TLS13ONLY; + } else { + cliParams.protocols = TLS12MAX; + servParams.protocols = TLS12MAX; + } serverReady = false; // Give a 1 second delay before running the test. @@ -464,7 +654,8 @@ Thread.sleep(1000); // Wait 5 seconds for server ready - for (int i = 0; (i < 100 && (!intOcsp.isServerReady() || !rootOcsp.isServerReady())); i++) { + for (int i = 0; (i < 100 && (!intOcsp.isServerReady() || + !rootOcsp.isServerReady())); i++) { Thread.sleep(50); } if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) { @@ -503,10 +694,11 @@ TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(trustStore); - SSLContext sslc = SSLContext.getInstance("TLSv1.2"); + SSLContext sslc = SSLContext.getInstance("TLS"); sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - SSLServerSocketFactory sslssf = sslc.getServerSocketFactory(); + SSLServerSocketFactory sslssf = new CustomizedServerSocketFactory(sslc, + servParams.protocols, servParams.ciphers); try (SSLServerSocket sslServerSocket = (SSLServerSocket) sslssf.createServerSocket(serverPort)) { @@ -569,10 +761,11 @@ tmf.init(trustStore); } - SSLContext sslc = SSLContext.getInstance("TLSv1.2"); + SSLContext sslc = SSLContext.getInstance("TLS"); sslc.init(null, tmf.getTrustManagers(), null); - SSLSocketFactory sslsf = sslc.getSocketFactory(); + SSLSocketFactory sslsf = new CustomizedSocketFactory(sslc, + cliParams.protocols, cliParams.ciphers); try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket("localhost", serverPort); InputStream sslIS = sslSocket.getInputStream(); @@ -929,6 +1122,8 @@ boolean enabled = true; PKIXBuilderParameters pkixParams = null; PKIXRevocationChecker revChecker = null; + String[] protocols = null; + String[] ciphers = null; ClientParameters() { } } @@ -941,10 +1136,161 @@ String respUri = ""; boolean respOverride = false; boolean ignoreExts = false; + String[] protocols = null; + String[] ciphers = null; ServerParameters() { } } + static class CustomizedSocketFactory extends SSLSocketFactory { + final SSLContext sslc; + final String[] protocols; + final String[] cipherSuites; + + CustomizedSocketFactory(SSLContext ctx, String[] prots, String[] suites) + throws GeneralSecurityException { + super(); + sslc = (ctx != null) ? ctx : SSLContext.getDefault(); + protocols = prots; + cipherSuites = suites; + + // Create the Trust Manager Factory using the PKIX variant + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + } + + @Override + public Socket createSocket(Socket s, String host, int port, + boolean autoClose) throws IOException { + Socket sock = sslc.getSocketFactory().createSocket(s, host, port, + autoClose); + customizeSocket(sock); + return sock; + } + + @Override + public Socket createSocket(InetAddress host, int port) + throws IOException { + Socket sock = sslc.getSocketFactory().createSocket(host, port); + customizeSocket(sock); + return sock; + } + + @Override + public Socket createSocket(InetAddress host, int port, + InetAddress localAddress, int localPort) throws IOException { + Socket sock = sslc.getSocketFactory().createSocket(host, port, + localAddress, localPort); + customizeSocket(sock); + return sock; + } + + @Override + public Socket createSocket(String host, int port) + throws IOException { + Socket sock = sslc.getSocketFactory().createSocket(host, port); + customizeSocket(sock); + return sock; + } + + @Override + public Socket createSocket(String host, int port, + InetAddress localAddress, int localPort) + throws IOException { + Socket sock = sslc.getSocketFactory().createSocket(host, port, + localAddress, localPort); + customizeSocket(sock); + return sock; + } + + @Override + public String[] getDefaultCipherSuites() { + return sslc.getDefaultSSLParameters().getCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return sslc.getSupportedSSLParameters().getCipherSuites(); + } + + private void customizeSocket(Socket sock) { + if (sock instanceof SSLSocket) { + if (protocols != null) { + ((SSLSocket)sock).setEnabledProtocols(protocols); + } + if (cipherSuites != null) { + ((SSLSocket)sock).setEnabledCipherSuites(cipherSuites); + } + } + } + } + + static class CustomizedServerSocketFactory extends SSLServerSocketFactory { + final SSLContext sslc; + final String[] protocols; + final String[] cipherSuites; + + CustomizedServerSocketFactory(SSLContext ctx, String[] prots, String[] suites) + throws GeneralSecurityException { + super(); + sslc = (ctx != null) ? ctx : SSLContext.getDefault(); + protocols = prots; + cipherSuites = suites; + + // Create the Trust Manager Factory using the PKIX variant + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + } + + @Override + public ServerSocket createServerSocket(int port) throws IOException { + ServerSocket sock = + sslc.getServerSocketFactory().createServerSocket(port); + customizeSocket(sock); + return sock; + } + + @Override + public ServerSocket createServerSocket(int port, int backlog) + throws IOException { + ServerSocket sock = + sslc.getServerSocketFactory().createServerSocket(port, + backlog); + customizeSocket(sock); + return sock; + } + + @Override + public ServerSocket createServerSocket(int port, int backlog, + InetAddress ifAddress) throws IOException { + ServerSocket sock = + sslc.getServerSocketFactory().createServerSocket(port, + backlog, ifAddress); + customizeSocket(sock); + return sock; + } + + @Override + public String[] getDefaultCipherSuites() { + return sslc.getDefaultSSLParameters().getCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return sslc.getSupportedSSLParameters().getCipherSuites(); + } + + private void customizeSocket(ServerSocket sock) { + if (sock instanceof SSLServerSocket) { + if (protocols != null) { + ((SSLServerSocket)sock).setEnabledProtocols(protocols); + } + if (cipherSuites != null) { + ((SSLServerSocket)sock).setEnabledCipherSuites(cipherSuites); + } + } + } + } + + static class TestResult { Exception serverExc = null; Exception clientExc = null; diff -r afb358e14f29 -r 0cabcf9cb31b test/jdk/javax/net/ssl/Stapling/StapleEnableProps.java --- a/test/jdk/javax/net/ssl/Stapling/StapleEnableProps.java Thu May 24 11:34:31 2018 -0700 +++ b/test/jdk/javax/net/ssl/Stapling/StapleEnableProps.java Thu May 24 12:32:00 2018 -0700 @@ -132,9 +132,7 @@ System.setProperty("jdk.tls.client.enableStatusRequestExtension", "true"); -System.out.println("*** TEST 1 BEFORE: " + System.getProperty("jdk.tls.client.enableStatusRequestExtension")); SSLContext ctxStaple = SSLContext.getInstance("TLSv1.2"); -System.out.println("*** TEST 1 AFTER: " + System.getProperty("jdk.tls.client.enableStatusRequestExtension")); ctxStaple.init(null, tmf.getTrustManagers(), null); SSLEngine engine = ctxStaple.createSSLEngine(); engine.setUseClientMode(true); @@ -163,9 +161,7 @@ System.setProperty("jdk.tls.client.enableStatusRequestExtension", "false"); -System.out.println("*** TEST 2 BEFORE: " + System.getProperty("jdk.tls.client.enableStatusRequestExtension")); SSLContext ctxNoStaple = SSLContext.getInstance("TLSv1.2"); -System.out.println("*** TEST 2 AFTER: " + System.getProperty("jdk.tls.client.enableStatusRequestExtension")); ctxNoStaple.init(null, tmf.getTrustManagers(), null); engine = ctxNoStaple.createSSLEngine(); engine.setUseClientMode(true);