blob: cc0a4b782db3e2d822c64b308400fd9387dc9758 [file] [log] [blame]
/*
* 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;
}
}