| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.qpid.jms.transports; |
| |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| import static org.junit.Assume.assumeTrue; |
| |
| import java.io.IOException; |
| import java.security.UnrecoverableKeyException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import javax.net.ssl.SSLContext; |
| import javax.net.ssl.SSLEngine; |
| |
| import org.apache.qpid.jms.test.QpidJmsTestCase; |
| import org.junit.Test; |
| |
| import io.netty.buffer.PooledByteBufAllocator; |
| import io.netty.handler.ssl.OpenSsl; |
| import io.netty.handler.ssl.OpenSslEngine; |
| import io.netty.handler.ssl.SslContext; |
| import io.netty.handler.ssl.SslHandler; |
| |
| /** |
| * Tests for the TransportSupport class. |
| */ |
| public class TransportSupportTest extends QpidJmsTestCase { |
| |
| public static final String PASSWORD = "password"; |
| |
| public static final String BROKER_JKS_KEYSTORE = "src/test/resources/broker-jks.keystore"; |
| public static final String BROKER_JKS_TRUSTSTORE = "src/test/resources/broker-jks.truststore"; |
| public static final String CLIENT_JKS_KEYSTORE = "src/test/resources/client-jks.keystore"; |
| public static final String CLIENT_JKS_TRUSTSTORE = "src/test/resources/client-jks.truststore"; |
| |
| public static final String BROKER_JCEKS_KEYSTORE = "src/test/resources/broker-jceks.keystore"; |
| public static final String BROKER_JCEKS_TRUSTSTORE = "src/test/resources/broker-jceks.truststore"; |
| public static final String CLIENT_JCEKS_KEYSTORE = "src/test/resources/client-jceks.keystore"; |
| public static final String CLIENT_JCEKS_TRUSTSTORE = "src/test/resources/client-jceks.truststore"; |
| |
| public static final String BROKER_PKCS12_KEYSTORE = "src/test/resources/broker-pkcs12.keystore"; |
| public static final String BROKER_PKCS12_TRUSTSTORE = "src/test/resources/broker-pkcs12.truststore"; |
| public static final String CLIENT_PKCS12_KEYSTORE = "src/test/resources/client-pkcs12.keystore"; |
| public static final String CLIENT_PKCS12_TRUSTSTORE = "src/test/resources/client-pkcs12.truststore"; |
| |
| public static final String KEYSTORE_JKS_TYPE = "jks"; |
| public static final String KEYSTORE_JCEKS_TYPE = "jceks"; |
| public static final String KEYSTORE_PKCS12_TYPE = "pkcs12"; |
| |
| public static final String[] ENABLED_PROTOCOLS = new String[] { "TLSv1" }; |
| |
| // Currently the OpenSSL implementation cannot disable SSLv2Hello |
| public static final String[] ENABLED_OPENSSL_PROTOCOLS = new String[] { "SSLv2Hello", "TLSv1" }; |
| |
| private static final String ALIAS_DOES_NOT_EXIST = "alias.does.not.exist"; |
| private static final String ALIAS_CA_CERT = "ca"; |
| |
| @Test |
| public void testLegacySslProtocolsDisabledByDefaultJDK() throws Exception { |
| TransportOptions options = createJksSslOptions(null); |
| |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createJdkSslEngine(null, context, options); |
| assertNotNull(engine); |
| |
| List<String> engineProtocols = Arrays.asList(engine.getEnabledProtocols()); |
| assertFalse("SSLv3 should not be enabled by default", engineProtocols.contains("SSLv3")); |
| assertFalse("SSLv2Hello should not be enabled by default", engineProtocols.contains("SSLv2Hello")); |
| } |
| |
| @Test |
| public void testLegacySslProtocolsDisabledByDefaultOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createJksSslOptions(null); |
| |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createOpenSslEngine(PooledByteBufAllocator.DEFAULT, null, context, options); |
| assertNotNull(engine); |
| |
| List<String> engineProtocols = Arrays.asList(engine.getEnabledProtocols()); |
| assertFalse("SSLv3 should not be enabled by default", engineProtocols.contains("SSLv3")); |
| |
| // TODO - Netty is currently unable to disable OpenSSL SSLv2Hello so we are stuck with it for now. |
| // assertFalse("SSLv2Hello should not be enabled by default", engineProtocols.contains("SSLv2Hello")); |
| } |
| |
| @Test |
| public void testCreateSslContextJksStoreJDK() throws Exception { |
| TransportOptions options = createJksSslOptions(); |
| |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| assertNotNull(context); |
| |
| assertEquals("TLS", context.getProtocol()); |
| } |
| |
| @Test |
| public void testCreateSslContextJksStoreOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createJksSslOptions(); |
| |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| assertNotNull(context); |
| |
| // TODO There is no means currently of getting the protocol from the netty SslContext. |
| // assertEquals("TLS", context.getProtocol()); |
| } |
| |
| @Test |
| public void testCreateSslContextJksStoreWithConfiguredContextProtocolJDK() throws Exception { |
| TransportOptions options = createJksSslOptions(); |
| String contextProtocol = "TLSv1.2"; |
| options.setContextProtocol(contextProtocol); |
| |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| assertNotNull(context); |
| |
| assertEquals(contextProtocol, context.getProtocol()); |
| } |
| |
| @Test |
| public void testCreateSslContextJksStoreWithConfiguredContextProtocolOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createJksSslOptions(); |
| String contextProtocol = "TLSv1.2"; |
| options.setContextProtocol(contextProtocol); |
| |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| assertNotNull(context); |
| |
| // TODO There is no means currently of getting the protocol from the netty SslContext. |
| // assertEquals(contextProtocol, context.getProtocol()); |
| } |
| |
| @Test |
| public void testCreateSslContextNoKeyStorePasswordJDK() throws Exception { |
| TransportOptions options = createJksSslOptions(); |
| options.setKeyStorePassword(null); |
| try { |
| TransportSupport.createJdkSslContext(options); |
| fail("Expected an exception to be thrown"); |
| } catch (UnrecoverableKeyException e) { |
| // Expected |
| } catch (IllegalArgumentException iae) { |
| // Expected in certain cases |
| String message = iae.getMessage(); |
| assertTrue("Unexpected message: " + message, message.contains("password can't be null")); |
| } |
| } |
| |
| @Test |
| public void testCreateSslContextNoKeyStorePasswordOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createJksSslOptions(); |
| options.setKeyStorePassword(null); |
| |
| try { |
| TransportSupport.createOpenSslContext(options); |
| fail("Expected an exception to be thrown"); |
| } catch (UnrecoverableKeyException e) { |
| // Expected |
| } catch (IllegalArgumentException iae) { |
| // Expected in certain cases |
| String message = iae.getMessage(); |
| assertTrue("Unexpected message: " + message, message.contains("password can't be null")); |
| } |
| } |
| |
| @Test(expected = IOException.class) |
| public void testCreateSslContextWrongKeyStorePasswordJDK() throws Exception { |
| TransportOptions options = createJksSslOptions(); |
| options.setKeyStorePassword("wrong"); |
| TransportSupport.createJdkSslContext(options); |
| } |
| |
| @Test(expected = IOException.class) |
| public void testCreateSslContextWrongKeyStorePasswordOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createJksSslOptions(); |
| options.setKeyStorePassword("wrong"); |
| TransportSupport.createOpenSslContext(options); |
| } |
| |
| @Test(expected = IOException.class) |
| public void testCreateSslContextBadPathToKeyStoreJDK() throws Exception { |
| TransportOptions options = createJksSslOptions(); |
| options.setKeyStoreLocation(CLIENT_JKS_KEYSTORE + ".bad"); |
| TransportSupport.createJdkSslContext(options); |
| } |
| |
| @Test(expected = IOException.class) |
| public void testCreateSslContextBadPathToKeyStoreOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createJksSslOptions(); |
| options.setKeyStoreLocation(CLIENT_JKS_KEYSTORE + ".bad"); |
| TransportSupport.createOpenSslContext(options); |
| } |
| |
| @Test(expected = IOException.class) |
| public void testCreateSslContextWrongTrustStorePasswordJDK() throws Exception { |
| TransportOptions options = createJksSslOptions(); |
| options.setTrustStorePassword("wrong"); |
| TransportSupport.createJdkSslContext(options); |
| } |
| |
| @Test(expected = IOException.class) |
| public void testCreateSslContextWrongTrustStorePasswordOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createJksSslOptions(); |
| options.setTrustStorePassword("wrong"); |
| TransportSupport.createOpenSslContext(options); |
| } |
| |
| @Test(expected = IOException.class) |
| public void testCreateSslContextBadPathToTrustStoreJDK() throws Exception { |
| TransportOptions options = createJksSslOptions(); |
| options.setTrustStoreLocation(CLIENT_JKS_TRUSTSTORE + ".bad"); |
| TransportSupport.createJdkSslContext(options); |
| } |
| |
| @Test(expected = IOException.class) |
| public void testCreateSslContextBadPathToTrustStoreOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createJksSslOptions(); |
| options.setTrustStoreLocation(CLIENT_JKS_TRUSTSTORE + ".bad"); |
| TransportSupport.createOpenSslContext(options); |
| } |
| |
| @Test |
| public void testCreateSslContextJceksStoreJDK() throws Exception { |
| TransportOptions options = createJceksSslOptions(); |
| |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| assertNotNull(context); |
| |
| assertEquals("TLS", context.getProtocol()); |
| } |
| |
| @Test |
| public void testCreateSslContextJceksStoreOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createJceksSslOptions(); |
| |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| assertNotNull(context); |
| assertTrue(context.isClient()); |
| } |
| |
| @Test |
| public void testCreateSslContextPkcs12StoreJDK() throws Exception { |
| TransportOptions options = createPkcs12SslOptions(); |
| |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| assertNotNull(context); |
| |
| assertEquals("TLS", context.getProtocol()); |
| } |
| |
| @Test |
| public void testCreateSslContextPkcs12StoreOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createPkcs12SslOptions(); |
| |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| assertNotNull(context); |
| assertTrue(context.isClient()); |
| } |
| |
| @Test(expected = IOException.class) |
| public void testCreateSslContextIncorrectStoreTypeJDK() throws Exception { |
| TransportOptions options = createPkcs12SslOptions(); |
| options.setStoreType(KEYSTORE_JCEKS_TYPE); |
| TransportSupport.createJdkSslContext(options); |
| } |
| |
| @Test(expected = IOException.class) |
| public void testCreateSslContextIncorrectStoreTypeOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createPkcs12SslOptions(); |
| options.setStoreType(KEYSTORE_JCEKS_TYPE); |
| TransportSupport.createOpenSslContext(options); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromPkcs12StoreJDK() throws Exception { |
| TransportOptions options = createPkcs12SslOptions(); |
| |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createJdkSslEngine(null, context, options); |
| assertNotNull(engine); |
| |
| List<String> engineProtocols = Arrays.asList(engine.getEnabledProtocols()); |
| assertFalse(engineProtocols.isEmpty()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromPkcs12StoreOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createPkcs12SslOptions(); |
| |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createOpenSslEngine(PooledByteBufAllocator.DEFAULT, null, context, options); |
| assertNotNull(engine); |
| |
| List<String> engineProtocols = Arrays.asList(engine.getEnabledProtocols()); |
| assertFalse(engineProtocols.isEmpty()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromPkcs12StoreWithExplicitEnabledProtocolsJDK() throws Exception { |
| TransportOptions options = createPkcs12SslOptions(ENABLED_PROTOCOLS); |
| |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createJdkSslEngine(null, context, options); |
| assertNotNull(engine); |
| |
| assertArrayEquals("Enabled protocols not as expected", ENABLED_PROTOCOLS, engine.getEnabledProtocols()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromPkcs12StoreWithExplicitEnabledProtocolsOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createPkcs12SslOptions(ENABLED_PROTOCOLS); |
| |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createOpenSslEngine(PooledByteBufAllocator.DEFAULT, null, context, options); |
| assertNotNull(engine); |
| |
| assertArrayEquals("Enabled protocols not as expected", ENABLED_OPENSSL_PROTOCOLS, engine.getEnabledProtocols()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJksStoreJDK() throws Exception { |
| TransportOptions options = createJksSslOptions(); |
| |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createJdkSslEngine(null, context, options); |
| assertNotNull(engine); |
| |
| List<String> engineProtocols = Arrays.asList(engine.getEnabledProtocols()); |
| assertFalse(engineProtocols.isEmpty()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJksStoreOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createJksSslOptions(); |
| |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createOpenSslEngine(PooledByteBufAllocator.DEFAULT, null, context, options); |
| assertNotNull(engine); |
| |
| List<String> engineProtocols = Arrays.asList(engine.getEnabledProtocols()); |
| assertFalse(engineProtocols.isEmpty()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJksStoreWithExplicitEnabledProtocolsJDK() throws Exception { |
| TransportOptions options = createJksSslOptions(ENABLED_PROTOCOLS); |
| |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createJdkSslEngine(null, context, options); |
| assertNotNull(engine); |
| |
| assertArrayEquals("Enabled protocols not as expected", ENABLED_PROTOCOLS, engine.getEnabledProtocols()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJksStoreWithExplicitEnabledProtocolsOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createJksSslOptions(ENABLED_PROTOCOLS); |
| |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createOpenSslEngine(PooledByteBufAllocator.DEFAULT, null, context, options); |
| assertNotNull(engine); |
| |
| assertArrayEquals("Enabled protocols not as expected", ENABLED_OPENSSL_PROTOCOLS, engine.getEnabledProtocols()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJksStoreWithExplicitDisabledProtocolsJDK() throws Exception { |
| // Discover the default enabled protocols |
| TransportOptions options = createJksSslOptions(); |
| SSLEngine directEngine = createSSLEngineDirectly(options); |
| String[] protocols = directEngine.getEnabledProtocols(); |
| assertTrue("There were no initial protocols to choose from!", protocols.length > 0); |
| |
| // Pull out one to disable specifically |
| String[] disabledProtocol = new String[] { protocols[protocols.length - 1] }; |
| String[] trimmedProtocols = Arrays.copyOf(protocols, protocols.length - 1); |
| options.setDisabledProtocols(disabledProtocol); |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| SSLEngine engine = TransportSupport.createJdkSslEngine(null, context, options); |
| |
| // verify the option took effect |
| assertNotNull(engine); |
| assertArrayEquals("Enabled protocols not as expected", trimmedProtocols, engine.getEnabledProtocols()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJksStoreWithExplicitDisabledProtocolsOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| // Discover the default enabled protocols |
| TransportOptions options = createJksSslOptions(); |
| SSLEngine directEngine = createOpenSSLEngineDirectly(options); |
| String[] protocols = directEngine.getEnabledProtocols(); |
| assertTrue("There were no initial protocols to choose from!", protocols.length > 0); |
| |
| // Pull out one to disable specifically |
| String[] disabledProtocol = new String[] { protocols[protocols.length - 1] }; |
| String[] trimmedProtocols = Arrays.copyOf(protocols, protocols.length - 1); |
| options.setDisabledProtocols(disabledProtocol); |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| SSLEngine engine = TransportSupport.createOpenSslEngine(PooledByteBufAllocator.DEFAULT, null, context, options); |
| |
| // verify the option took effect |
| assertNotNull(engine); |
| assertArrayEquals("Enabled protocols not as expected", trimmedProtocols, engine.getEnabledProtocols()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJksStoreWithExplicitEnabledAndDisabledProtocolsJDK() throws Exception { |
| // Discover the default enabled protocols |
| TransportOptions options = createJksSslOptions(); |
| SSLEngine directEngine = createSSLEngineDirectly(options); |
| String[] protocols = directEngine.getEnabledProtocols(); |
| assertTrue("There were no initial protocols to choose from!", protocols.length > 1); |
| |
| // Pull out two to enable, and one to disable specifically |
| String protocol1 = protocols[0]; |
| String protocol2 = protocols[1]; |
| String[] enabledProtocols = new String[] { protocol1, protocol2 }; |
| String[] disabledProtocol = new String[] { protocol1 }; |
| String[] remainingProtocols = new String[] { protocol2 }; |
| options.setEnabledProtocols(enabledProtocols); |
| options.setDisabledProtocols(disabledProtocol); |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| SSLEngine engine = TransportSupport.createJdkSslEngine(null, context, options); |
| |
| // verify the option took effect, that the disabled protocols were removed from the enabled list. |
| assertNotNull(engine); |
| assertArrayEquals("Enabled protocols not as expected", remainingProtocols, engine.getEnabledProtocols()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJksStoreWithExplicitEnabledAndDisabledProtocolsOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| // Discover the default enabled protocols |
| TransportOptions options = createJksSslOptions(); |
| SSLEngine directEngine = createOpenSSLEngineDirectly(options); |
| String[] protocols = directEngine.getEnabledProtocols(); |
| assertTrue("There were no initial protocols to choose from!", protocols.length > 1); |
| |
| // Pull out two to enable, and one to disable specifically |
| String protocol1 = protocols[0]; |
| String protocol2 = protocols[1]; |
| String[] enabledProtocols = new String[] { protocol1, protocol2 }; |
| String[] disabledProtocol = new String[] { protocol1 }; |
| String[] remainingProtocols = new String[] { protocol2 }; |
| options.setEnabledProtocols(enabledProtocols); |
| options.setDisabledProtocols(disabledProtocol); |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| SSLEngine engine = TransportSupport.createOpenSslEngine(PooledByteBufAllocator.DEFAULT, null, context, options); |
| |
| // Because Netty cannot currently disable SSLv2Hello in OpenSSL we need to account for it popping up. |
| ArrayList<String> remainingProtocolsList = new ArrayList<>(Arrays.asList(remainingProtocols)); |
| if (!remainingProtocolsList.contains("SSLv2Hello")) { |
| remainingProtocolsList.add(0, "SSLv2Hello"); |
| } |
| |
| remainingProtocols = remainingProtocolsList.toArray(new String[remainingProtocolsList.size()]); |
| |
| // verify the option took effect, that the disabled protocols were removed from the enabled list. |
| assertNotNull(engine); |
| assertEquals("Enabled protocols not as expected", remainingProtocolsList.size(), engine.getEnabledProtocols().length); |
| assertTrue("Enabled protocols not as expected", remainingProtocolsList.containsAll(Arrays.asList(engine.getEnabledProtocols()))); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJksStoreWithExplicitEnabledCiphersJDK() throws Exception { |
| // Discover the default enabled ciphers |
| TransportOptions options = createJksSslOptions(); |
| SSLEngine directEngine = createSSLEngineDirectly(options); |
| String[] ciphers = directEngine.getEnabledCipherSuites(); |
| assertTrue("There were no initial ciphers to choose from!", ciphers.length > 0); |
| |
| // Pull out one to enable specifically |
| String cipher = ciphers[0]; |
| String[] enabledCipher = new String[] { cipher }; |
| options.setEnabledCipherSuites(enabledCipher); |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| SSLEngine engine = TransportSupport.createJdkSslEngine(null, context, options); |
| |
| // verify the option took effect |
| assertNotNull(engine); |
| assertArrayEquals("Enabled ciphers not as expected", enabledCipher, engine.getEnabledCipherSuites()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJksStoreWithExplicitEnabledCiphersOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| // Discover the default enabled ciphers |
| TransportOptions options = createJksSslOptions(); |
| SSLEngine directEngine = createOpenSSLEngineDirectly(options); |
| String[] ciphers = directEngine.getEnabledCipherSuites(); |
| assertTrue("There were no initial ciphers to choose from!", ciphers.length > 0); |
| |
| // Pull out one to enable specifically |
| String cipher = ciphers[0]; |
| String[] enabledCipher = new String[] { cipher }; |
| options.setEnabledCipherSuites(enabledCipher); |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| SSLEngine engine = TransportSupport.createOpenSslEngine(PooledByteBufAllocator.DEFAULT, null, context, options); |
| |
| // verify the option took effect |
| assertNotNull(engine); |
| assertArrayEquals("Enabled ciphers not as expected", enabledCipher, engine.getEnabledCipherSuites()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJksStoreWithExplicitDisabledCiphersJDK() throws Exception { |
| // Discover the default enabled ciphers |
| TransportOptions options = createJksSslOptions(); |
| SSLEngine directEngine = createSSLEngineDirectly(options); |
| String[] ciphers = directEngine.getEnabledCipherSuites(); |
| assertTrue("There were no initial ciphers to choose from!", ciphers.length > 0); |
| |
| // Pull out one to disable specifically |
| String[] disabledCipher = new String[] { ciphers[ciphers.length - 1] }; |
| String[] trimmedCiphers = Arrays.copyOf(ciphers, ciphers.length - 1); |
| options.setDisabledCipherSuites(disabledCipher); |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| SSLEngine engine = TransportSupport.createJdkSslEngine(null, context, options); |
| |
| // verify the option took effect |
| assertNotNull(engine); |
| assertArrayEquals("Enabled ciphers not as expected", trimmedCiphers, engine.getEnabledCipherSuites()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJksStoreWithExplicitDisabledCiphersOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| // Discover the default enabled ciphers |
| TransportOptions options = createJksSslOptions(); |
| SSLEngine directEngine = createOpenSSLEngineDirectly(options); |
| String[] ciphers = directEngine.getEnabledCipherSuites(); |
| assertTrue("There were no initial ciphers to choose from!", ciphers.length > 0); |
| |
| // Pull out one to disable specifically |
| String[] disabledCipher = new String[] { ciphers[ciphers.length - 1] }; |
| String[] trimmedCiphers = Arrays.copyOf(ciphers, ciphers.length - 1); |
| options.setDisabledCipherSuites(disabledCipher); |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| SSLEngine engine = TransportSupport.createOpenSslEngine(PooledByteBufAllocator.DEFAULT, null, context, options); |
| |
| // verify the option took effect |
| assertNotNull(engine); |
| assertArrayEquals("Enabled ciphers not as expected", trimmedCiphers, engine.getEnabledCipherSuites()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJksStoreWithExplicitEnabledAndDisabledCiphersJDK() throws Exception { |
| // Discover the default enabled ciphers |
| TransportOptions options = createJksSslOptions(); |
| SSLEngine directEngine = createSSLEngineDirectly(options); |
| String[] ciphers = directEngine.getEnabledCipherSuites(); |
| assertTrue("There werent enough initial ciphers to choose from!", ciphers.length > 1); |
| |
| // Pull out two to enable, and one to disable specifically |
| String cipher1 = ciphers[0]; |
| String cipher2 = ciphers[1]; |
| String[] enabledCiphers = new String[] { cipher1, cipher2 }; |
| String[] disabledCipher = new String[] { cipher1 }; |
| String[] remainingCipher = new String[] { cipher2 }; |
| options.setEnabledCipherSuites(enabledCiphers); |
| options.setDisabledCipherSuites(disabledCipher); |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| SSLEngine engine = TransportSupport.createJdkSslEngine(null, context, options); |
| |
| // verify the option took effect, that the disabled ciphers were removed from the enabled list. |
| assertNotNull(engine); |
| assertArrayEquals("Enabled ciphers not as expected", remainingCipher, engine.getEnabledCipherSuites()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJksStoreWithExplicitEnabledAndDisabledCiphersOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| // Discover the default enabled ciphers |
| TransportOptions options = createJksSslOptions(); |
| SSLEngine directEngine = createOpenSSLEngineDirectly(options); |
| String[] ciphers = directEngine.getEnabledCipherSuites(); |
| assertTrue("There werent enough initial ciphers to choose from!", ciphers.length > 1); |
| |
| // Pull out two to enable, and one to disable specifically |
| String cipher1 = ciphers[0]; |
| String cipher2 = ciphers[1]; |
| String[] enabledCiphers = new String[] { cipher1, cipher2 }; |
| String[] disabledCipher = new String[] { cipher1 }; |
| String[] remainingCipher = new String[] { cipher2 }; |
| options.setEnabledCipherSuites(enabledCiphers); |
| options.setDisabledCipherSuites(disabledCipher); |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| SSLEngine engine = TransportSupport.createOpenSslEngine(PooledByteBufAllocator.DEFAULT, null, context, options); |
| |
| // verify the option took effect, that the disabled ciphers were removed from the enabled list. |
| assertNotNull(engine); |
| assertArrayEquals("Enabled ciphers not as expected", remainingCipher, engine.getEnabledCipherSuites()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJceksStoreJDK() throws Exception { |
| TransportOptions options = createJceksSslOptions(); |
| |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createJdkSslEngine(null, context, options); |
| assertNotNull(engine); |
| |
| List<String> engineProtocols = Arrays.asList(engine.getEnabledProtocols()); |
| assertFalse(engineProtocols.isEmpty()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJceksStoreOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = createJceksSslOptions(); |
| |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createOpenSslEngine(PooledByteBufAllocator.DEFAULT, null, context, options); |
| assertNotNull(engine); |
| |
| List<String> engineProtocols = Arrays.asList(engine.getEnabledProtocols()); |
| assertFalse(engineProtocols.isEmpty()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJceksStoreWithExplicitEnabledProtocolsJDK() throws Exception { |
| TransportOptions options = createJceksSslOptions(ENABLED_PROTOCOLS); |
| |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createJdkSslEngine(null, context, options); |
| assertNotNull(engine); |
| |
| assertArrayEquals("Enabled protocols not as expected", ENABLED_PROTOCOLS, engine.getEnabledProtocols()); |
| } |
| |
| @Test |
| public void testCreateSslEngineFromJceksStoreWithExplicitEnabledProtocolsOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| // Try and disable all but the one we really want but for now expect that this one plus SSLv2Hello |
| // is going to come back until the netty code can successfully disable them all. |
| TransportOptions options = createJceksSslOptions(ENABLED_PROTOCOLS); |
| |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createOpenSslEngine(PooledByteBufAllocator.DEFAULT, null, context, options); |
| assertNotNull(engine); |
| |
| assertArrayEquals("Enabled protocols not as expected", ENABLED_OPENSSL_PROTOCOLS, engine.getEnabledProtocols()); |
| } |
| |
| @Test |
| public void testCreateSslEngineWithVerifyHostJDK() throws Exception { |
| TransportOptions options = createJksSslOptions(); |
| options.setVerifyHost(true); |
| |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createJdkSslEngine(null, context, options); |
| assertNotNull(engine); |
| |
| assertEquals("HTTPS", engine.getSSLParameters().getEndpointIdentificationAlgorithm()); |
| } |
| |
| @Test |
| public void testCreateSslEngineWithVerifyHostOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| assumeTrue(OpenSsl.supportsHostnameValidation()); |
| |
| TransportOptions options = createJksSslOptions(); |
| options.setVerifyHost(true); |
| |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createOpenSslEngine(PooledByteBufAllocator.DEFAULT, null, context, options); |
| assertNotNull(engine); |
| |
| assertEquals("HTTPS", engine.getSSLParameters().getEndpointIdentificationAlgorithm()); |
| } |
| |
| @Test |
| public void testCreateSslEngineWithoutVerifyHostJDK() throws Exception { |
| TransportOptions options = createJksSslOptions(); |
| options.setVerifyHost(false); |
| |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createJdkSslEngine(null, context, options); |
| assertNotNull(engine); |
| |
| assertNull(engine.getSSLParameters().getEndpointIdentificationAlgorithm()); |
| } |
| |
| @Test |
| public void testCreateSslEngineWithoutVerifyHostOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| assumeTrue(OpenSsl.supportsHostnameValidation()); |
| |
| TransportOptions options = createJksSslOptions(); |
| options.setVerifyHost(false); |
| |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| assertNotNull(context); |
| |
| SSLEngine engine = TransportSupport.createOpenSslEngine(PooledByteBufAllocator.DEFAULT, null, context, options); |
| assertNotNull(engine); |
| |
| assertNull(engine.getSSLParameters().getEndpointIdentificationAlgorithm()); |
| } |
| |
| @Test |
| public void testCreateSslContextWithKeyAliasWhichDoesntExist() throws Exception { |
| TransportOptions options = createJksSslOptions(); |
| options.setKeyAlias(ALIAS_DOES_NOT_EXIST); |
| |
| try { |
| TransportSupport.createJdkSslContext(options); |
| fail("Expected exception to be thrown"); |
| } catch (IllegalArgumentException iae) { |
| // Expected |
| } |
| } |
| |
| @Test |
| public void testCreateSslContextWithKeyAliasWhichRepresentsNonKeyEntry() throws Exception { |
| TransportOptions options = createJksSslOptions(); |
| options.setKeyAlias(ALIAS_CA_CERT); |
| |
| try { |
| TransportSupport.createJdkSslContext(options); |
| fail("Expected exception to be thrown"); |
| } catch (IllegalArgumentException iae) { |
| // Expected |
| } |
| } |
| |
| @Test(timeout = 100000) |
| public void testIsOpenSSLPossible() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = new TransportOptions(); |
| options.setUseOpenSSL(false); |
| assertFalse(TransportSupport.isOpenSSLPossible(options)); |
| |
| options.setUseOpenSSL(true); |
| assertTrue(TransportSupport.isOpenSSLPossible(options)); |
| } |
| |
| @Test(timeout = 100000) |
| public void testIsOpenSSLPossibleWhenHostNameVerificationConfigured() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| assumeTrue(OpenSsl.supportsHostnameValidation()); |
| |
| TransportOptions options = new TransportOptions(); |
| options.setUseOpenSSL(true); |
| |
| options.setVerifyHost(false); |
| assertTrue(TransportSupport.isOpenSSLPossible(options)); |
| |
| options.setVerifyHost(true); |
| assertTrue(TransportSupport.isOpenSSLPossible(options)); |
| } |
| |
| @Test(timeout = 100000) |
| public void testIsOpenSSLPossibleWhenKeyAliasIsSpecified() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| assumeTrue(OpenSsl.supportsHostnameValidation()); |
| |
| TransportOptions options = new TransportOptions(); |
| options.setUseOpenSSL(true); |
| options.setKeyAlias("alias"); |
| |
| assertFalse(TransportSupport.isOpenSSLPossible(options)); |
| } |
| |
| @Test(timeout = 100000) |
| public void testCreateSslHandlerJDK() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = new TransportOptions(); |
| options.setUseOpenSSL(false); |
| |
| SslHandler handler = TransportSupport.createSslHandler(null, null, options); |
| assertNotNull(handler); |
| assertFalse(handler.engine() instanceof OpenSslEngine); |
| } |
| |
| @Test(timeout = 100000) |
| public void testCreateSslHandlerOpenSSL() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = new TransportOptions(); |
| options.setUseOpenSSL(true); |
| |
| SslHandler handler = TransportSupport.createSslHandler(PooledByteBufAllocator.DEFAULT, null, options); |
| assertNotNull(handler); |
| assertTrue(handler.engine() instanceof OpenSslEngine); |
| } |
| |
| @Test(timeout = 100000) |
| public void testCreateOpenSSLEngineFailsWhenAllocatorMissing() throws Exception { |
| assumeTrue(OpenSsl.isAvailable()); |
| assumeTrue(OpenSsl.supportsKeyManagerFactory()); |
| |
| TransportOptions options = new TransportOptions(); |
| options.setUseOpenSSL(true); |
| |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| try { |
| TransportSupport.createOpenSslEngine(null, null, context, options); |
| fail("Should throw IllegalArgumentException for null allocator."); |
| } catch (IllegalArgumentException iae) {} |
| } |
| |
| private TransportOptions createJksSslOptions() { |
| return createJksSslOptions(null); |
| } |
| |
| private TransportOptions createJksSslOptions(String[] enabledProtocols) { |
| TransportOptions options = new TransportOptions(); |
| |
| options.setKeyStoreLocation(CLIENT_JKS_KEYSTORE); |
| options.setTrustStoreLocation(CLIENT_JKS_TRUSTSTORE); |
| options.setStoreType(KEYSTORE_JKS_TYPE); |
| options.setKeyStorePassword(PASSWORD); |
| options.setTrustStorePassword(PASSWORD); |
| if (enabledProtocols != null) { |
| options.setEnabledProtocols(enabledProtocols); |
| } |
| |
| return options; |
| } |
| |
| private TransportOptions createJceksSslOptions() { |
| return createJceksSslOptions(null); |
| } |
| |
| private TransportOptions createJceksSslOptions(String[] enabledProtocols) { |
| TransportOptions options = new TransportOptions(); |
| |
| options.setKeyStoreLocation(CLIENT_JCEKS_KEYSTORE); |
| options.setTrustStoreLocation(CLIENT_JCEKS_TRUSTSTORE); |
| options.setStoreType(KEYSTORE_JCEKS_TYPE); |
| options.setKeyStorePassword(PASSWORD); |
| options.setTrustStorePassword(PASSWORD); |
| if (enabledProtocols != null) { |
| options.setEnabledProtocols(enabledProtocols); |
| } |
| |
| return options; |
| } |
| |
| private TransportOptions createPkcs12SslOptions() { |
| return createPkcs12SslOptions(null); |
| } |
| |
| private TransportOptions createPkcs12SslOptions(String[] enabledProtocols) { |
| TransportOptions options = new TransportOptions(); |
| |
| options.setKeyStoreLocation(CLIENT_PKCS12_KEYSTORE); |
| options.setTrustStoreLocation(CLIENT_PKCS12_TRUSTSTORE); |
| options.setStoreType(KEYSTORE_PKCS12_TYPE); |
| options.setKeyStorePassword(PASSWORD); |
| options.setTrustStorePassword(PASSWORD); |
| if (enabledProtocols != null) { |
| options.setEnabledProtocols(enabledProtocols); |
| } |
| |
| return options; |
| } |
| |
| private SSLEngine createSSLEngineDirectly(TransportOptions options) throws Exception { |
| SSLContext context = TransportSupport.createJdkSslContext(options); |
| SSLEngine engine = context.createSSLEngine(); |
| return engine; |
| } |
| |
| private SSLEngine createOpenSSLEngineDirectly(TransportOptions options) throws Exception { |
| SslContext context = TransportSupport.createOpenSslContext(options); |
| SSLEngine engine = context.newEngine(PooledByteBufAllocator.DEFAULT); |
| return engine; |
| } |
| } |