diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java b/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java index 9e82859..3b2acb0 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java @@ -69,9 +69,17 @@ public class WolfSSLContext extends SSLContextSpi { /* Get available wolfSSL cipher suites in IANA format */ ciphersIana = WolfSSL.getCiphersAvailableIana(this.currentVersion); + /* Allow ability for user to hard-code and override version, cipher + * suite, and NO_* disable options. Otherwise just sets defaults + * into ctxAttr. */ WolfSSLCustomUser ctxAttr = WolfSSLCustomUser.GetCtxAttributes (this.currentVersion, ciphersIana); + /* Explicitly set SSLContext version if overridden by + * WolfSSLCustomUser or specific SSLContext version was created + * by user. Otherwise use default of SSLv23. Starts at highest TLS + * protocol version supported by native wolfSSL then downgrades to + * minimum native downgrade version. */ if(ctxAttr.version == TLS_VERSION.TLSv1 || ctxAttr.version == TLS_VERSION.TLSv1_1 || ctxAttr.version == TLS_VERSION.TLSv1_2 || @@ -83,19 +91,29 @@ public class WolfSSLContext extends SSLContextSpi { "Invalid SSL/TLS protocol version"); } + /* Set SSLContext version. To be compatible with SunJSSE behavior, + * the enabled protocols are less than or equal to the version + * selected */ switch (this.currentVersion) { case TLSv1: method = WolfSSL.TLSv1_Method(); + ctxAttr.noOptions = ctxAttr.noOptions | + WolfSSL.SSL_OP_NO_TLSv1_1 | WolfSSL.SSL_OP_NO_TLSv1_2 | + WolfSSL.SSL_OP_NO_TLSv1_3; WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "creating WolfSSLContext with TLSv1"); break; case TLSv1_1: method = WolfSSL.TLSv1_1_Method(); + ctxAttr.noOptions = ctxAttr.noOptions | + WolfSSL.SSL_OP_NO_TLSv1_2 | WolfSSL.SSL_OP_NO_TLSv1_3; WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "creating WolfSSLContext with TLSv1_1"); break; case TLSv1_2: method = WolfSSL.TLSv1_2_Method(); + ctxAttr.noOptions = ctxAttr.noOptions | + WolfSSL.SSL_OP_NO_TLSv1_3; WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "creating WolfSSLContext with TLSv1_2"); break; @@ -130,15 +148,31 @@ public class WolfSSLContext extends SSLContextSpi { throw new IllegalArgumentException(e); } - /* auto-populate enabled ciphersuites with supported ones */ if(ctxAttr.list != null && ctxAttr.list.length > 0) { - params.setCipherSuites(ctxAttr.list); + ciphersIana = ctxAttr.list; } else { - params.setCipherSuites(WolfSSL.getCiphersIana()); + ciphersIana = WolfSSL.getCiphersIana(); } - /* auto-populate enabled protocols with supported ones */ - params.setProtocols(this.getProtocolsMask(ctxAttr.noOptions)); + enforceKeySizeLimitations(); + + /* TODO: filter cipher suite list and protocols to conform to + * limitations set by jdk.tls.disabledAlgorithms system property + * if set */ + + /* Auto-populate enabled ciphersuites with supported ones */ + params.setCipherSuites(ciphersIana); + + /* Auto-populate enabled protocols with supported ones. Protocols + * which have been disabled via system property get filtered in + * WolfSSLEngineHelper.sanitizeProtocols() */ + params.setProtocols(WolfSSLUtil.sanitizeProtocols( + this.getProtocolsMask(ctxAttr.noOptions))); + } + + private void enforceKeySizeLimitations() { + /* TODO: call WOLFSSL_CTX APIs to limit key sizes based on + * jdk.tls.disabledAlgorithms settings */ } private void LoadTrustedRootCerts() { diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLCustomUser.java b/src/java/com/wolfssl/provider/jsse/WolfSSLCustomUser.java index 2527979..10543f8 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLCustomUser.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLCustomUser.java @@ -23,53 +23,63 @@ package com.wolfssl.provider.jsse; import com.wolfssl.WolfSSL.TLS_VERSION; /** - * Base class is intended to give some customizing points. - * Currently it is limited to be invoked from WolfSSLContext.Create + * This class is intended to give some customization points to wolfJSSE + * for users who want to hard-code certain limitations for wolfJSSE in terms + * of protocol version support, cipher suite list, or native wolfSSL + * SSL_NO_* type options. + * + * Most users will want to take other approaches to limiting these features, + * as this approach will require modification of this class and a + * recompilation/reinstallation of the wolfJSSE JAR file. + * + * Currently these limitations are enforced upon invocation of the + * WolfSSLContext.init() method (createCtx()). * * @author wolfSSL */ public class WolfSSLCustomUser { - /** SSL/TLS version */ + /** SSL/TLS version to be used with new SSLContext objects. */ public TLS_VERSION version; - /** String array of allowed cipher suites */ + /** String array of allowed cipher suites for new SSLContext objects */ public String[] list; - /** Mask of options to set for the associated WOLFSSL_CTX */ + /** Mask of options to set for the associated native WOLFSSL_CTX */ public long noOptions; /** Default WolfSSLCustomUser constructor */ public WolfSSLCustomUser() { } /** - * callback for getting Context attributes before creating context, - * TLS protocol and Cipher list + * Factory method for getting SSLContext attributes before creating context, + * TLS protocol and Cipher list. wolfJSSE calls this internally to get + * values set below by the user, or passes defaults through from what + * was otherwise going to be used by wolfJSSE when creating the SSLContext. * - * WARNING: inappropriate code or use of this callback may cause - * serious security issue. + * WARNING: Inappropriate code or use of this feature may cause + * serious security issues! * - * @param version default version of TLS for refernce. - * @param list default cipher list for refernce. + * @param version Default version of TLS for reference. + * @param list Default cipher list for reference. * @return version: TLS protocol version to the context. The value - * has to be one compiled in. - * list: Cipher list allowed to the context. list has to - * contain subset of default cipher list. If it is - * null, default list is applied. + * needs to be one compiled into native wolfSSL. + * list: Cipher list allowed for use in the SSLContext. + * list needs to contain a subset of the default cipher + * list. If it is null, default list is applied. */ public static WolfSSLCustomUser GetCtxAttributes(TLS_VERSION version, String[] list) { WolfSSLCustomUser ctxAttr = new WolfSSLCustomUser(); - /*** - custom code - + /** + Insert custom code here, and remove/modify defaults below. Example: ctxAttr.NoOptions = WolfSSL.SSL_OP_NO_TLSv1 | WolfSSL.SSL_OP_NO_TLSv1_3; - - ***/ + */ ctxAttr.version = version; ctxAttr.list = list; ctxAttr.noOptions = 0; + return ctxAttr; } } diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java b/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java index 82728de..bc47656 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java @@ -24,11 +24,13 @@ import com.wolfssl.WolfSSL; import com.wolfssl.WolfSSLException; import com.wolfssl.WolfSSLSession; import java.util.Arrays; +import java.util.ArrayList; import java.util.List; import java.net.SocketTimeoutException; import javax.net.ssl.SSLException; import javax.net.ssl.X509TrustManager; import javax.net.ssl.SSLHandshakeException; +import java.security.Security; /** * This is a helper function to account for similar methods between SSLSocket @@ -221,7 +223,7 @@ public class WolfSSLEngineHelper { } } - this.params.setProtocols(p); + this.params.setProtocols(WolfSSLUtil.sanitizeProtocols(p)); } /** @@ -230,16 +232,18 @@ public class WolfSSLEngineHelper { * @return String array of enabled SSL/TLS protocols */ protected String[] getProtocols() { - return this.params.getProtocols(); + return WolfSSLUtil.sanitizeProtocols(this.params.getProtocols()); } /** - * Get all supported SSL/TLS protocols in native wolfSSL library + * Get all supported SSL/TLS protocols in native wolfSSL library, + * which are also allowed by 'jdk.tls.client.protocols' or + * 'jdk.tls.server.protocols' if set. * * @return String array of supported protocols */ protected String[] getAllProtocols() { - return WolfSSL.getProtocols(); + return WolfSSLUtil.sanitizeProtocols(WolfSSL.getProtocols()); } /** @@ -417,7 +421,9 @@ public class WolfSSLEngineHelper { } /* sets the protocol to use with WOLFSSL connections */ - private void setLocalProtocol(String[] p) { + private void setLocalProtocol(String[] p) + throws SSLException { + int i; long mask = 0; boolean[] set = new boolean[5]; @@ -428,6 +434,10 @@ public class WolfSSLEngineHelper { return; } + if (p.length == 0) { + throw new SSLException("No protocols enabled or available"); + } + for (i = 0; i < p.length; i++) { if (p[i].equals("TLSv1.3")) { set[0] = true; @@ -655,9 +665,10 @@ public class WolfSSLEngineHelper { } } - private void setLocalParams() { + private void setLocalParams() throws SSLException { this.setLocalCiphers(this.params.getCipherSuites()); - this.setLocalProtocol(this.params.getProtocols()); + this.setLocalProtocol( + WolfSSLUtil.sanitizeProtocols(this.params.getProtocols())); this.setLocalAuth(); this.setLocalServerNames(); this.setLocalSessionTicket(); diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLContextTest.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLContextTest.java index 7eb5921..ecc0bb7 100644 --- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLContextTest.java +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLContextTest.java @@ -27,12 +27,16 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import static org.junit.Assert.*; +import java.util.List; +import java.util.Arrays; import java.util.ArrayList; import com.wolfssl.WolfSSLException; import com.wolfssl.provider.jsse.WolfSSLContext; import java.io.FileInputStream; +import javax.net.SocketFactory; +import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.KeyManagerFactory; @@ -52,6 +56,7 @@ import java.security.KeyManagementException; import java.security.NoSuchProviderException; import java.security.NoSuchAlgorithmException; +import com.wolfssl.WolfSSL; import com.wolfssl.provider.jsse.WolfSSLProvider; public class WolfSSLContextTest { @@ -61,9 +66,10 @@ public class WolfSSLContextTest { private static final String ctxProvider = "wolfJSSE"; private static String[] allProtocols = { - "TLSV1", - "TLSV1.1", - "TLSV1.2", + "TLSv1", + "TLSv1.1", + "TLSv1.2", + "TLSv1.3", "TLS" }; @@ -95,6 +101,13 @@ public class WolfSSLContextTest { try { SSLContext ctx = SSLContext.getInstance(allProtocols[i], ctxProvider); + + if (WolfSSLTestFactory.securityPropContains( + "jdk.tls.disabledAlgorithms", allProtocols[i])) { + /* skip adding, protocol has been disabled */ + continue; + } + enabledProtocols.add(allProtocols[i]); } catch (NoSuchAlgorithmException e) { @@ -388,5 +401,266 @@ public class WolfSSLContextTest { System.out.println("\t... passed"); } + + /* Returns ArrayList of expected default SSLcontext protocols, assuming + * none have been disabled at the system level via system/security + * properties. The order of items in the list should also match expected + * order. */ + private ArrayList buildExpectedDefaultProtocolList( + String ctxProtocol) { + + ArrayList expected = new ArrayList(); + + /* already sorted highest to lowest (ie TLSv1.3, ..., TLSv1.1) */ + List enabledNativeProtocols = Arrays.asList(WolfSSL.getProtocols()); + + if (ctxProtocol == "TLS") { + if (enabledNativeProtocols.contains("TLSv1.3")) { + expected.add("TLSv1.3"); + } + if (enabledNativeProtocols.contains("TLSv1.2")) { + expected.add("TLSv1.2"); + } + if (enabledNativeProtocols.contains("TLSv1.1")) { + expected.add("TLSv1.1"); + } + if (enabledNativeProtocols.contains("TLSv1")) { + expected.add("TLSv1"); + } + } + + else if (ctxProtocol == "TLSv1.3") { + if (enabledNativeProtocols.contains("TLSv1.3")) { + expected.add("TLSv1.3"); + } + if (enabledNativeProtocols.contains("TLSv1.2")) { + expected.add("TLSv1.2"); + } + if (enabledNativeProtocols.contains("TLSv1.1")) { + expected.add("TLSv1.1"); + } + if (enabledNativeProtocols.contains("TLSv1")) { + expected.add("TLSv1"); + } + } + + else if (ctxProtocol == "TLSv1.2") { + if (enabledNativeProtocols.contains("TLSv1.2")) { + expected.add("TLSv1.2"); + } + if (enabledNativeProtocols.contains("TLSv1.1")) { + expected.add("TLSv1.1"); + } + if (enabledNativeProtocols.contains("TLSv1")) { + expected.add("TLSv1"); + } + } + + else if (ctxProtocol == "TLSv1.1") { + if (enabledNativeProtocols.contains("TLSv1.1")) { + expected.add("TLSv1.1"); + } + if (enabledNativeProtocols.contains("TLSv1")) { + expected.add("TLSv1"); + } + } + + else if (ctxProtocol == "TLSv1") { + if (enabledNativeProtocols.contains("TLSv1")) { + expected.add("TLSv1"); + } + } + + return expected; + } + + /* Tests that disabling protocols using the system property + * 'jdk.tls.disabledAlgorithms' works as expected. + */ + @Test + public void testJdkTlsDisabledAlgorithms() throws NoSuchProviderException, + NoSuchAlgorithmException, IllegalStateException, + KeyManagementException, IOException { + + SSLContext ctx = null; + SocketFactory sf = null; + SSLSocket sock = null; + String[] defaultSSLContextProtocols = null; + ArrayList expectedList = null; + + System.out.print("\tjdk.tls.disabledAlgorithms"); + + List enabledNativeProtocols = Arrays.asList(WolfSSL.getProtocols()); + if (enabledNativeProtocols == null) { + System.out.println("\t... failed"); + fail("WolfSSL.getProtocols() returned null"); + } + + /* Save original property value to reset after test */ + String originalProperty = + Security.getProperty("jdk.tls.disabledAlgorithms"); + + /* Test with no protocols disabled */ + Security.setProperty("jdk.tls.disabledAlgorithms", ""); + for (int i = 0; i < allProtocols.length; i++) { + + if (!enabledNativeProtocols.contains(allProtocols[i])) { + /* protocol not available in native library, skip */ + continue; + } + + ctx = SSLContext.getInstance(allProtocols[i]); + ctx.init(null, null, null); + + expectedList = buildExpectedDefaultProtocolList(allProtocols[i]); + defaultSSLContextProtocols = + ctx.getDefaultSSLParameters().getProtocols(); + + if (!Arrays.equals(defaultSSLContextProtocols, + expectedList.toArray(new String[expectedList.size()]))) { + System.out.print("\t... failed"); + fail("Default SSLContext protocol list did not " + + "match expected"); + } + + /* Also test SSLSocket.getEnabledProtocols() */ + sf = ctx.getSocketFactory(); + sock = (SSLSocket)sf.createSocket(); + String[] sockEnabledProtocols = sock.getEnabledProtocols(); + + if (!Arrays.equals(sockEnabledProtocols, + expectedList.toArray(new String[expectedList.size()]))) { + System.out.print("\t... failed"); + fail("Default SSLSocket protocol list did not " + + "match expected"); + } + } + + /* Test with each allProtocol disabled individually */ + for (int i = 0; i < allProtocols.length; i++) { + Security.setProperty("jdk.tls.disabledAlgorithms", allProtocols[i]); + for (int j = 0; j < allProtocols.length; j++) { + + if (!enabledNativeProtocols.contains(allProtocols[j])) { + /* protocol not available in native library, skip */ + continue; + } + + ctx = SSLContext.getInstance(allProtocols[j]); + ctx.init(null, null, null); + + expectedList = + buildExpectedDefaultProtocolList(allProtocols[j]); + /* remove protocol under test */ + expectedList.remove(allProtocols[i]); + defaultSSLContextProtocols = + ctx.getDefaultSSLParameters().getProtocols(); + + if (!Arrays.equals(defaultSSLContextProtocols, + expectedList.toArray( + new String[expectedList.size()]))) { + System.out.print("\t... failed"); + fail("Default SSLContext protocol list did not " + + "match expected"); + } + + /* Also test SSLSocket.getEnabledProtocols() */ + sf = ctx.getSocketFactory(); + sock = (SSLSocket)sf.createSocket(); + String[] sockEnabledProtocols = sock.getEnabledProtocols(); + + if (!Arrays.equals(sockEnabledProtocols, + expectedList.toArray( + new String[expectedList.size()]))) { + System.out.print("\t... failed"); + fail("Default SSLSocket protocol list did not " + + "match expected"); + } + } + } + + /* Test with TLSv1, TLSv1.1 protocols disabled */ + Security.setProperty("jdk.tls.disabledAlgorithms", "TLSv1, TLSv1.1"); + for (int i = 0; i < allProtocols.length; i++) { + + if (!enabledNativeProtocols.contains(allProtocols[i])) { + /* protocol not available in native library, skip */ + continue; + } + + ctx = SSLContext.getInstance(allProtocols[i]); + ctx.init(null, null, null); + + expectedList = buildExpectedDefaultProtocolList(allProtocols[i]); + expectedList.remove("TLSv1"); + expectedList.remove("TLSv1.1"); + defaultSSLContextProtocols = + ctx.getDefaultSSLParameters().getProtocols(); + + if (!Arrays.equals(defaultSSLContextProtocols, + expectedList.toArray(new String[expectedList.size()]))) { + System.out.print("\t... failed"); + fail("Default SSLContext protocol list did not " + + "match expected"); + } + + /* Also test SSLSocket.getEnabledProtocols() */ + sf = ctx.getSocketFactory(); + sock = (SSLSocket)sf.createSocket(); + String[] sockEnabledProtocols = sock.getEnabledProtocols(); + + if (!Arrays.equals(sockEnabledProtocols, + expectedList.toArray( + new String[expectedList.size()]))) { + System.out.print("\t... failed"); + fail("Default SSLSocket protocol list did not " + + "match expected"); + } + } + + /* Test with TLSv1.1, TLSv1.2 protocols disabled */ + Security.setProperty("jdk.tls.disabledAlgorithms", "TLSv1.1, TLSv1.2"); + for (int i = 0; i < allProtocols.length; i++) { + + if (!enabledNativeProtocols.contains(allProtocols[i])) { + /* protocol not available in native library, skip */ + continue; + } + + ctx = SSLContext.getInstance(allProtocols[i]); + ctx.init(null, null, null); + + expectedList = buildExpectedDefaultProtocolList(allProtocols[i]); + expectedList.remove("TLSv1.1"); + expectedList.remove("TLSv1.2"); + defaultSSLContextProtocols = + ctx.getDefaultSSLParameters().getProtocols(); + + if (!Arrays.equals(defaultSSLContextProtocols, + expectedList.toArray(new String[expectedList.size()]))) { + System.out.print("\t... failed"); + fail("Default SSLContext protocol list did not " + + "match expected"); + } + + /* Also test SSLSocket.getEnabledProtocols() */ + sf = ctx.getSocketFactory(); + sock = (SSLSocket)sf.createSocket(); + String[] sockEnabledProtocols = sock.getEnabledProtocols(); + + if (!Arrays.equals(sockEnabledProtocols, + expectedList.toArray( + new String[expectedList.size()]))) { + System.out.print("\t... failed"); + fail("Default SSLSocket protocol list did not " + + "match expected"); + } + } + + /* Restore original system property value */ + Security.setProperty("jdk.tls.disabledAlgorithms", originalProperty); + + System.out.println("\t... passed"); + } } diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java index cc7f8a8..44fa019 100644 --- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java @@ -396,6 +396,50 @@ public class WolfSSLSocketTest { System.out.println("\t... failed"); fail("SSLSocket.setEnabledProtocols() failed"); } + + /* test that removing protocols with jdk.tls.disabledAlgorithms + * behaves as expected */ + String originalProperty = + Security.getProperty("jdk.tls.disabledAlgorithms"); + + try { + Security.setProperty("jdk.tls.disabledAlgorithms", "TLSv1"); + s.setEnabledProtocols(new String[] {"TLSv1"}); + System.out.println("\t\t... failed"); + fail("SSLSocket.setEnabledProtocols() failed"); + } catch (IllegalArgumentException e) { + /* expected */ + } + + try { + Security.setProperty("jdk.tls.disabledAlgorithms", "TLSv1.1"); + s.setEnabledProtocols(new String[] {"TLSv1.1"}); + System.out.println("\t\t... failed"); + fail("SSLSocket.setEnabledProtocols() failed"); + } catch (IllegalArgumentException e) { + /* expected */ + } + + try { + Security.setProperty("jdk.tls.disabledAlgorithms", "TLSv1.2"); + s.setEnabledProtocols(new String[] {"TLSv1.2"}); + System.out.println("\t\t... failed"); + fail("SSLSocket.setEnabledProtocols() failed"); + } catch (IllegalArgumentException e) { + /* expected */ + } + + try { + Security.setProperty("jdk.tls.disabledAlgorithms", "TLSv1.3"); + s.setEnabledProtocols(new String[] {"TLSv1.3"}); + System.out.println("\t\t... failed"); + fail("SSLSocket.setEnabledProtocols() failed"); + } catch (IllegalArgumentException e) { + /* expected */ + } + + /* restore original property value */ + System.setProperty("jdk.tls.disabledAlgorithms", originalProperty); } System.out.println("\t... passed"); @@ -1206,7 +1250,9 @@ public class WolfSSLSocketTest { System.out.print("\tTLS 1.0 connection test"); /* skip if TLS 1.0 is not compiled in at native level */ - if (WolfSSL.TLSv1Enabled() == false) { + if (WolfSSL.TLSv1Enabled() == false || + WolfSSLTestFactory.securityPropContains( + "jdk.tls.disabledAlgorithms", "TLS")) { System.out.println("\t\t... skipped"); return; } @@ -1220,7 +1266,9 @@ public class WolfSSLSocketTest { System.out.print("\tTLS 1.1 connection test"); /* skip if TLS 1.1 is not compiled in at native level */ - if (WolfSSL.TLSv11Enabled() == false) { + if (WolfSSL.TLSv11Enabled() == false || + WolfSSLTestFactory.securityPropContains( + "jdk.tls.disabledAlgorithms", "TLSv1.1")) { System.out.println("\t\t... skipped"); return; } @@ -1234,7 +1282,9 @@ public class WolfSSLSocketTest { System.out.print("\tTLS 1.2 connection test"); /* skip if TLS 1.2 is not compiled in at native level */ - if (WolfSSL.TLSv12Enabled() == false) { + if (WolfSSL.TLSv12Enabled() == false || + WolfSSLTestFactory.securityPropContains( + "jdk.tls.disabledAlgorithms", "TLSv1.2")) { System.out.println("\t\t... skipped"); return; } @@ -1248,7 +1298,9 @@ public class WolfSSLSocketTest { System.out.print("\tTLS 1.3 connection test"); /* skip if TLS 1.3 is not compiled in at native level */ - if (WolfSSL.TLSv13Enabled() == false) { + if (WolfSSL.TLSv13Enabled() == false || + WolfSSLTestFactory.securityPropContains( + "jdk.tls.disabledAlgorithms", "TLSv1.3")) { System.out.println("\t\t... skipped"); return; } @@ -1301,6 +1353,60 @@ public class WolfSSLSocketTest { System.out.println("\t\t... passed"); } + @Test + public void testConnectionWithDisabledAlgorithms() throws Exception { + + System.out.print("\tConnection with disabled algorithms"); + + /* create new CTX */ + this.ctx = tf.createSSLContext("TLS", ctxProvider); + + /* save current system property value */ + String originalProperty = + Security.getProperty("jdk.tls.disabledAlgorithms"); + + for (int i = 0; i < enabledProtocols.size(); i++) { + + /* skip generic "TLS" */ + if (enabledProtocols.get(i).equals("TLS")) { + continue; + } + + /* create SSLServerSocket first to get ephemeral port */ + SSLServerSocket ss = (SSLServerSocket)ctx.getServerSocketFactory() + .createServerSocket(0); + + SSLSocket cs = (SSLSocket)ctx.getSocketFactory().createSocket(); + /* restrict to single protocol that is being disabled */ + cs.setEnabledProtocols(new String[] {enabledProtocols.get(i)}); + + /* disable protocol after socket setup, should fail connection */ + Security.setProperty("jdk.tls.disabledAlgorithms", + enabledProtocols.get(i)); + + /* don't need server since should throw exception before */ + cs.connect(new InetSocketAddress(ss.getLocalPort())); + + try { + cs.startHandshake(); + System.out.println("\t... failed"); + fail(); + + } catch (SSLException e) { + /* expected, should fail with + * "No protocols enabled or available" */ + } + + cs.close(); + ss.close(); + } + + /* restore system property */ + Security.setProperty("jdk.tls.disabledAlgorithms", originalProperty); + + System.out.println("\t... passed"); + } + @Test public void testSessionResumption() throws Exception { diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java index cbd05f0..43b5eb5 100644 --- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.security.Security; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; @@ -36,6 +37,8 @@ import java.security.NoSuchProviderException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; +import java.util.List; +import java.util.Arrays; import java.util.Enumeration; import java.util.logging.Level; import java.util.logging.Logger; @@ -787,4 +790,34 @@ class WolfSSLTestFactory { } return false; } + + /** + * Check if Security property contains a specific value. + * + * @param prop System Security property to check + * @param needle String value to search for in Security property + * + * @return true if found, otherwise false + */ + protected static boolean securityPropContains(String prop, String needle) { + + String secProp = null; + List propList = null; + + if (prop == null || needle == null) { + return false; + } + + /* make sure protocol has not been disabled at system level */ + secProp = Security.getProperty(prop); + /* Remove spaces after commas, split into List */ + secProp = secProp.replaceAll(", ",","); + propList = Arrays.asList(secProp.split(",")); + + if (propList.contains(needle)) { + return true; + } + + return false; + } }