diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyConnector.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyConnector.java index 62c405b48b..49c936bfd3 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyConnector.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyConnector.java @@ -18,6 +18,7 @@ package org.apache.activemq.artemis.core.remoting.impl.netty; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; import java.io.IOException; import java.net.ConnectException; import java.net.Inet6Address; @@ -197,6 +198,8 @@ public class NettyConnector extends AbstractConnector { private String enabledProtocols; + private boolean verifyHost; + private boolean tcpNoDelay; private int tcpSendBufferSize; @@ -306,6 +309,8 @@ public class NettyConnector extends AbstractConnector { enabledCipherSuites = ConfigurationHelper.getStringProperty(TransportConstants.ENABLED_CIPHER_SUITES_PROP_NAME, TransportConstants.DEFAULT_ENABLED_CIPHER_SUITES, configuration); enabledProtocols = ConfigurationHelper.getStringProperty(TransportConstants.ENABLED_PROTOCOLS_PROP_NAME, TransportConstants.DEFAULT_ENABLED_PROTOCOLS, configuration); + + verifyHost = ConfigurationHelper.getBooleanProperty(TransportConstants.VERIFY_HOST_PROP_NAME, TransportConstants.DEFAULT_VERIFY_HOST, configuration); } else { keyStoreProvider = TransportConstants.DEFAULT_KEYSTORE_PROVIDER; @@ -316,6 +321,7 @@ public class NettyConnector extends AbstractConnector { trustStorePassword = TransportConstants.DEFAULT_TRUSTSTORE_PASSWORD; enabledCipherSuites = TransportConstants.DEFAULT_ENABLED_CIPHER_SUITES; enabledProtocols = TransportConstants.DEFAULT_ENABLED_PROTOCOLS; + verifyHost = TransportConstants.DEFAULT_VERIFY_HOST; } tcpNoDelay = ConfigurationHelper.getBooleanProperty(TransportConstants.TCP_NODELAY_PROPNAME, TransportConstants.DEFAULT_TCP_NODELAY, configuration); @@ -462,7 +468,13 @@ public class NettyConnector extends AbstractConnector { public void initChannel(Channel channel) throws Exception { final ChannelPipeline pipeline = channel.pipeline(); if (sslEnabled && !useServlet) { - SSLEngine engine = context.createSSLEngine(); + SSLEngine engine; + if (verifyHost) { + engine = context.createSSLEngine(host, port); + } + else { + engine = context.createSSLEngine(); + } engine.setUseClientMode(true); @@ -496,6 +508,12 @@ public class NettyConnector extends AbstractConnector { engine.setEnabledProtocols(originalProtocols); } + if (verifyHost) { + SSLParameters sslParameters = engine.getSSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + engine.setSSLParameters(sslParameters); + } + SslHandler handler = new SslHandler(engine); pipeline.addLast(handler); diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/TransportConstants.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/TransportConstants.java index 53dc204d83..40aed3d8e5 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/TransportConstants.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/TransportConstants.java @@ -87,6 +87,8 @@ public class TransportConstants { public static final String NEED_CLIENT_AUTH_PROP_NAME = "needClientAuth"; + public static final String VERIFY_HOST_PROP_NAME = "verifyHost"; + public static final String BACKLOG_PROP_NAME = "backlog"; public static final String NETTY_VERSION; @@ -155,6 +157,8 @@ public class TransportConstants { public static final boolean DEFAULT_NEED_CLIENT_AUTH = false; + public static final boolean DEFAULT_VERIFY_HOST = false; + public static final boolean DEFAULT_TCP_NODELAY = true; public static final int DEFAULT_TCP_SENDBUFFER_SIZE = 32768; @@ -226,6 +230,7 @@ public class TransportConstants { allowableAcceptorKeys.add(TransportConstants.ENABLED_CIPHER_SUITES_PROP_NAME); allowableAcceptorKeys.add(TransportConstants.ENABLED_PROTOCOLS_PROP_NAME); allowableAcceptorKeys.add(TransportConstants.NEED_CLIENT_AUTH_PROP_NAME); + allowableAcceptorKeys.add(TransportConstants.VERIFY_HOST_PROP_NAME); allowableAcceptorKeys.add(TransportConstants.TCP_NODELAY_PROPNAME); allowableAcceptorKeys.add(TransportConstants.TCP_SENDBUFFER_SIZE_PROPNAME); allowableAcceptorKeys.add(TransportConstants.TCP_RECEIVEBUFFER_SIZE_PROPNAME); @@ -270,6 +275,7 @@ public class TransportConstants { allowableConnectorKeys.add(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME); allowableConnectorKeys.add(TransportConstants.ENABLED_CIPHER_SUITES_PROP_NAME); allowableConnectorKeys.add(TransportConstants.ENABLED_PROTOCOLS_PROP_NAME); + allowableConnectorKeys.add(TransportConstants.VERIFY_HOST_PROP_NAME); allowableConnectorKeys.add(TransportConstants.TCP_NODELAY_PROPNAME); allowableConnectorKeys.add(TransportConstants.TCP_SENDBUFFER_SIZE_PROPNAME); allowableConnectorKeys.add(TransportConstants.TCP_RECEIVEBUFFER_SIZE_PROPNAME); diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyAcceptor.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyAcceptor.java index f5742c5915..783f4ac9c3 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyAcceptor.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyAcceptor.java @@ -19,12 +19,15 @@ package org.apache.activemq.artemis.core.remoting.impl.netty; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLParameters; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -138,6 +141,8 @@ public class NettyAcceptor extends AbstractAcceptor { private final boolean needClientAuth; + private final boolean verifyHost; + private final boolean tcpNoDelay; private final int backlog; @@ -224,6 +229,8 @@ public class NettyAcceptor extends AbstractAcceptor { enabledProtocols = ConfigurationHelper.getStringProperty(TransportConstants.ENABLED_PROTOCOLS_PROP_NAME, TransportConstants.DEFAULT_ENABLED_PROTOCOLS, configuration); needClientAuth = ConfigurationHelper.getBooleanProperty(TransportConstants.NEED_CLIENT_AUTH_PROP_NAME, TransportConstants.DEFAULT_NEED_CLIENT_AUTH, configuration); + + verifyHost = ConfigurationHelper.getBooleanProperty(TransportConstants.VERIFY_HOST_PROP_NAME, TransportConstants.DEFAULT_VERIFY_HOST, configuration); } else { keyStoreProvider = TransportConstants.DEFAULT_KEYSTORE_PROVIDER; @@ -235,6 +242,7 @@ public class NettyAcceptor extends AbstractAcceptor { enabledCipherSuites = TransportConstants.DEFAULT_ENABLED_CIPHER_SUITES; enabledProtocols = TransportConstants.DEFAULT_ENABLED_PROTOCOLS; needClientAuth = TransportConstants.DEFAULT_NEED_CLIENT_AUTH; + verifyHost = TransportConstants.DEFAULT_VERIFY_HOST; } tcpNoDelay = ConfigurationHelper.getBooleanProperty(TransportConstants.TCP_NODELAY_PROPNAME, TransportConstants.DEFAULT_TCP_NODELAY, configuration); @@ -391,7 +399,13 @@ public class NettyAcceptor extends AbstractAcceptor { ise.initCause(e); throw ise; } - SSLEngine engine = context.createSSLEngine(); + SSLEngine engine; + if (verifyHost) { + engine = context.createSSLEngine(host, port); + } + else { + engine = context.createSSLEngine(); + } engine.setUseClientMode(false); @@ -439,6 +453,13 @@ public class NettyAcceptor extends AbstractAcceptor { } engine.setEnabledProtocols(set.toArray(new String[set.size()])); + + if (verifyHost) { + SSLParameters sslParameters = engine.getSSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + engine.setSSLParameters(sslParameters); + } + return new SslHandler(engine); } @@ -742,12 +763,24 @@ public class NettyAcceptor extends AbstractAcceptor { @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { if (cause.getMessage() != null && cause.getMessage().startsWith(SSLHandshakeException.class.getName())) { - ActiveMQServerLogger.LOGGER.sslHandshakeFailed(ctx.channel().remoteAddress().toString(), cause.getMessage()); + Throwable rootCause = getRootCause(cause); + String errorMessage = rootCause.getClass().getName() + ": " + rootCause.getMessage(); + + ActiveMQServerLogger.LOGGER.sslHandshakeFailed(ctx.channel().remoteAddress().toString(), errorMessage); if (ActiveMQServerLogger.LOGGER.isDebugEnabled()) { ActiveMQServerLogger.LOGGER.debug("SSL handshake failed", cause); } } } + + private Throwable getRootCause(Throwable throwable) { + List list = new ArrayList<>(); + while (throwable != null && list.contains(throwable) == false) { + list.add(throwable); + throwable = throwable.getCause(); + } + return (list.size() < 2 ? throwable : list.get(list.size() - 1)); + } } } diff --git a/docs/user-manual/en/configuring-transports.md b/docs/user-manual/en/configuring-transports.md index 872fe2f514..a44da351aa 100644 --- a/docs/user-manual/en/configuring-transports.md +++ b/docs/user-manual/en/configuring-transports.md @@ -395,6 +395,18 @@ following additional properties: connecting to this acceptor that 2-way SSL is required. Valid values are `true` or `false`. Default is `false`. +- `verifyHost` + + When used on an `acceptor` the `CN` of the connecting client's SSL certificate + will be compared to its hostname to verify they match. This is useful + only for 2-way SSL. + + When used on a `connector` the `CN` of the server's SSL certificate will be + compared to its hostname to verify they match. This is useful for both 1-way + and 2-way SSL. + + Valid values are `true` or `false`. Default is `false`. + ## Configuring Netty HTTP Netty HTTP tunnels packets over the HTTP protocol. It can be useful in diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverOneWaySSLTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverOneWaySSLTest.java index 50ac9980ca..de46bcd871 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverOneWaySSLTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverOneWaySSLTest.java @@ -55,7 +55,10 @@ public class CoreClientOverOneWaySSLTest extends ActiveMQTestBase { @Parameterized.Parameters(name = "storeType={0}") public static Collection getParameters() { - return Arrays.asList(new Object[][]{{"JCEKS"}, {"JKS"}}); + return Arrays.asList(new Object[][]{ + {"JCEKS"}, + {"JKS"} + }); } public CoreClientOverOneWaySSLTest(String storeType) { @@ -78,6 +81,10 @@ public class CoreClientOverOneWaySSLTest extends ActiveMQTestBase { * keytool -export -keystore other-server-side-keystore.jks -file activemq-jks.cer -storepass secureexample * keytool -import -keystore other-client-side-truststore.jks -file activemq-jks.cer -storepass secureexample -keypass secureexample -noprompt * + * keytool -genkey -keystore verified-server-side-keystore.jks -storepass secureexample -keypass secureexample -dname "CN=localhost, OU=Artemis, O=ActiveMQ, L=AMQ, S=AMQ, C=AMQ" -keyalg RSA + * keytool -export -keystore verified-server-side-keystore.jks -file activemq-jks.cer -storepass secureexample + * keytool -import -keystore verified-client-side-truststore.jks -file activemq-jks.cer -storepass secureexample -keypass secureexample -noprompt + * * Commands to create the JCEKS artifacts: * keytool -genkey -keystore server-side-keystore.jceks -storetype JCEKS -storepass secureexample -keypass secureexample -dname "CN=ActiveMQ Artemis Server, OU=Artemis, O=ActiveMQ, L=AMQ, S=AMQ, C=AMQ" * keytool -export -keystore server-side-keystore.jceks -file activemq-jceks.cer -storetype jceks -storepass secureexample @@ -86,6 +93,10 @@ public class CoreClientOverOneWaySSLTest extends ActiveMQTestBase { * keytool -genkey -keystore other-server-side-keystore.jceks -storetype JCEKS -storepass secureexample -keypass secureexample -dname "CN=Other ActiveMQ Artemis Server, OU=Artemis, O=ActiveMQ, L=AMQ, S=AMQ, C=AMQ" * keytool -export -keystore other-server-side-keystore.jceks -file activemq-jceks.cer -storetype jceks -storepass secureexample * keytool -import -keystore other-client-side-truststore.jceks -storetype JCEKS -file activemq-jceks.cer -storepass secureexample -keypass secureexample -noprompt + * + * keytool -genkey -keystore verified-server-side-keystore.jceks -storetype JCEKS -storepass secureexample -keypass secureexample -dname "CN=localhost, OU=Artemis, O=ActiveMQ, L=AMQ, S=AMQ, C=AMQ" + * keytool -export -keystore verified-server-side-keystore.jceks -file activemq-jceks.cer -storetype jceks -storepass secureexample + * keytool -import -keystore verified-client-side-truststore.jceks -storetype JCEKS -file activemq-jceks.cer -storepass secureexample -keypass secureexample -noprompt */ private String storeType; private String SERVER_SIDE_KEYSTORE; @@ -123,6 +134,56 @@ public class CoreClientOverOneWaySSLTest extends ActiveMQTestBase { Assert.assertEquals(text, m.getBodyBuffer().readString()); } + @Test + public void testOneWaySSLVerifyHost() throws Exception { + createCustomSslServer(null, null, true); + String text = RandomUtil.randomString(); + + tc.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true); + tc.getParams().put(TransportConstants.TRUSTSTORE_PROVIDER_PROP_NAME, storeType); + tc.getParams().put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, "verified-" + CLIENT_SIDE_TRUSTSTORE); + tc.getParams().put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, PASSWORD); + tc.getParams().put(TransportConstants.VERIFY_HOST_PROP_NAME, true); + + ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(tc)); + ClientSessionFactory sf = addSessionFactory(createSessionFactory(locator)); + ClientSession session = addClientSession(sf.createSession(false, true, true)); + session.createQueue(CoreClientOverOneWaySSLTest.QUEUE, CoreClientOverOneWaySSLTest.QUEUE, false); + ClientProducer producer = addClientProducer(session.createProducer(CoreClientOverOneWaySSLTest.QUEUE)); + + ClientMessage message = createTextMessage(session, text); + producer.send(message); + + ClientConsumer consumer = addClientConsumer(session.createConsumer(CoreClientOverOneWaySSLTest.QUEUE)); + session.start(); + + Message m = consumer.receive(1000); + Assert.assertNotNull(m); + Assert.assertEquals(text, m.getBodyBuffer().readString()); + } + + @Test + public void testOneWaySSLVerifyHostNegative() throws Exception { + createCustomSslServer(null, null, false); + String text = RandomUtil.randomString(); + + tc.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true); + tc.getParams().put(TransportConstants.TRUSTSTORE_PROVIDER_PROP_NAME, storeType); + tc.getParams().put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, CLIENT_SIDE_TRUSTSTORE); + tc.getParams().put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, PASSWORD); + tc.getParams().put(TransportConstants.VERIFY_HOST_PROP_NAME, true); + + ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(tc)); + + try { + ClientSessionFactory sf = addSessionFactory(createSessionFactory(locator)); + fail("Creating a session here should fail due to a certificate with a CN that doesn't match the host name."); + } + catch (Exception e) { + // ignore + } + } + @Test public void testOneWaySSLReloaded() throws Exception { createCustomSslServer(); @@ -589,11 +650,22 @@ public class CoreClientOverOneWaySSLTest extends ActiveMQTestBase { } private void createCustomSslServer(String cipherSuites, String protocols) throws Exception { + createCustomSslServer(cipherSuites, protocols, false); + } + + private void createCustomSslServer(String cipherSuites, String protocols, boolean useVerifiedKeystore) throws Exception { Map params = new HashMap<>(); params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true); params.put(TransportConstants.KEYSTORE_PROVIDER_PROP_NAME, storeType); - params.put(TransportConstants.KEYSTORE_PATH_PROP_NAME, SERVER_SIDE_KEYSTORE); + + if (useVerifiedKeystore) { + params.put(TransportConstants.KEYSTORE_PATH_PROP_NAME, "verified-" + SERVER_SIDE_KEYSTORE); + } + else { + params.put(TransportConstants.KEYSTORE_PATH_PROP_NAME, SERVER_SIDE_KEYSTORE); + } params.put(TransportConstants.KEYSTORE_PASSWORD_PROP_NAME, PASSWORD); + params.put(TransportConstants.HOST_PROP_NAME, "localhost"); if (cipherSuites != null) { params.put(TransportConstants.ENABLED_CIPHER_SUITES_PROP_NAME, cipherSuites); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverTwoWaySSLTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverTwoWaySSLTest.java index 0d553adce9..403ebc33fa 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverTwoWaySSLTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverTwoWaySSLTest.java @@ -36,6 +36,7 @@ import org.apache.activemq.artemis.api.core.client.ClientSession; import org.apache.activemq.artemis.api.core.client.ClientSessionFactory; import org.apache.activemq.artemis.api.core.client.ActiveMQClient; import org.apache.activemq.artemis.api.core.client.ServerLocator; +import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptor; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.apache.activemq.artemis.utils.RandomUtil; import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl; @@ -56,7 +57,9 @@ public class CoreClientOverTwoWaySSLTest extends ActiveMQTestBase { @Parameterized.Parameters(name = "storeType={0}") public static Collection getParameters() { - return Arrays.asList(new Object[][]{{"JCEKS"}, {"JKS"}}); + return Arrays.asList(new Object[][]{ + {"JCEKS"}, + {"JKS"}}); } public CoreClientOverTwoWaySSLTest(String storeType) { @@ -77,10 +80,18 @@ public class CoreClientOverTwoWaySSLTest extends ActiveMQTestBase { * keytool -export -keystore client-side-keystore.jks -file activemq-jks.cer -storepass secureexample * keytool -import -keystore server-side-truststore.jks -file activemq-jks.cer -storepass secureexample -keypass secureexample -noprompt * + * keytool -genkey -keystore verified-client-side-keystore.jks -storepass secureexample -keypass secureexample -dname "CN=localhost, OU=Artemis, O=ActiveMQ, L=AMQ, S=AMQ, C=AMQ" -keyalg RSA + * keytool -export -keystore verified-client-side-keystore.jks -file activemq-jks.cer -storepass secureexample + * keytool -import -keystore verified-server-side-truststore.jks -file activemq-jks.cer -storepass secureexample -keypass secureexample -noprompt + * * Commands to create the JCEKS artifacts: * keytool -genkey -keystore client-side-keystore.jceks -storetype JCEKS -storepass secureexample -keypass secureexample -dname "CN=ActiveMQ Artemis Client, OU=Artemis, O=ActiveMQ, L=AMQ, S=AMQ, C=AMQ" -keyalg RSA * keytool -export -keystore client-side-keystore.jceks -file activemq-jceks.cer -storetype jceks -storepass secureexample * keytool -import -keystore server-side-truststore.jceks -storetype JCEKS -file activemq-jceks.cer -storepass secureexample -keypass secureexample -noprompt + * + * keytool -genkey -keystore verified-client-side-keystore.jceks -storetype JCEKS -storepass secureexample -keypass secureexample -dname "CN=localhost, OU=Artemis, O=ActiveMQ, L=AMQ, S=AMQ, C=AMQ" -keyalg RSA + * keytool -export -keystore verified-client-side-keystore.jceks -file activemq-jceks.cer -storetype jceks -storepass secureexample + * keytool -import -keystore verified-server-side-truststore.jceks -storetype JCEKS -file activemq-jceks.cer -storepass secureexample -keypass secureexample -noprompt */ private String storeType; @@ -148,6 +159,72 @@ public class CoreClientOverTwoWaySSLTest extends ActiveMQTestBase { Assert.assertEquals(text, m.getBodyBuffer().readString()); } + @Test + public void testTwoWaySSLVerifyClientHost() throws Exception { + NettyAcceptor acceptor = (NettyAcceptor) server.getRemotingService().getAcceptor("nettySSL"); + acceptor.getConfiguration().put(TransportConstants.VERIFY_HOST_PROP_NAME, true); + acceptor.getConfiguration().put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, "verified-" + SERVER_SIDE_TRUSTSTORE); + server.getRemotingService().stop(false); + server.getRemotingService().start(); + server.getRemotingService().startAcceptors(); + + String text = RandomUtil.randomString(); + + tc.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true); + tc.getParams().put(TransportConstants.TRUSTSTORE_PROVIDER_PROP_NAME, storeType); + tc.getParams().put(TransportConstants.KEYSTORE_PROVIDER_PROP_NAME, storeType); + tc.getParams().put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, CLIENT_SIDE_TRUSTSTORE); + tc.getParams().put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, PASSWORD); + tc.getParams().put(TransportConstants.KEYSTORE_PATH_PROP_NAME, "verified-" + CLIENT_SIDE_KEYSTORE); + tc.getParams().put(TransportConstants.KEYSTORE_PASSWORD_PROP_NAME, PASSWORD); + + server.getRemotingService().addIncomingInterceptor(new MyInterceptor()); + + ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(tc)); + ClientSessionFactory sf = createSessionFactory(locator); + ClientSession session = sf.createSession(false, true, true); + session.createQueue(CoreClientOverTwoWaySSLTest.QUEUE, CoreClientOverTwoWaySSLTest.QUEUE, false); + ClientProducer producer = session.createProducer(CoreClientOverTwoWaySSLTest.QUEUE); + + ClientMessage message = createTextMessage(session, text); + producer.send(message); + + ClientConsumer consumer = session.createConsumer(CoreClientOverTwoWaySSLTest.QUEUE); + session.start(); + + Message m = consumer.receive(1000); + Assert.assertNotNull(m); + Assert.assertEquals(text, m.getBodyBuffer().readString()); + } + + @Test + public void testTwoWaySSLVerifyClientHostNegative() throws Exception { + NettyAcceptor acceptor = (NettyAcceptor) server.getRemotingService().getAcceptor("nettySSL"); + acceptor.getConfiguration().put(TransportConstants.VERIFY_HOST_PROP_NAME, true); + server.getRemotingService().stop(false); + server.getRemotingService().start(); + server.getRemotingService().startAcceptors(); + + tc.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true); + tc.getParams().put(TransportConstants.TRUSTSTORE_PROVIDER_PROP_NAME, storeType); + tc.getParams().put(TransportConstants.KEYSTORE_PROVIDER_PROP_NAME, storeType); + tc.getParams().put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, CLIENT_SIDE_TRUSTSTORE); + tc.getParams().put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, PASSWORD); + tc.getParams().put(TransportConstants.KEYSTORE_PATH_PROP_NAME, CLIENT_SIDE_KEYSTORE); + tc.getParams().put(TransportConstants.KEYSTORE_PASSWORD_PROP_NAME, PASSWORD); + + server.getRemotingService().addIncomingInterceptor(new MyInterceptor()); + + ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(tc)); + try { + ClientSessionFactory sf = createSessionFactory(locator); + fail("Creating a session here should fail due to a certificate with a CN that doesn't match the host name."); + } + catch (Exception e) { + // ignore + } + } + @Test public void testTwoWaySSLWithoutClientKeyStore() throws Exception { tc.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true); @@ -183,7 +260,7 @@ public class CoreClientOverTwoWaySSLTest extends ActiveMQTestBase { params.put(TransportConstants.TRUSTSTORE_PROVIDER_PROP_NAME, storeType); params.put(TransportConstants.KEYSTORE_PROVIDER_PROP_NAME, storeType); params.put(TransportConstants.NEED_CLIENT_AUTH_PROP_NAME, true); - ConfigurationImpl config = createBasicConfig().addAcceptorConfiguration(new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params)); + ConfigurationImpl config = createBasicConfig().addAcceptorConfiguration(new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params, "nettySSL")); server = createServer(false, config); server.start(); waitForServerToStart(server); diff --git a/tests/unit-tests/src/test/resources/verified-client-side-keystore.jceks b/tests/unit-tests/src/test/resources/verified-client-side-keystore.jceks new file mode 100644 index 0000000000..250832ba8b Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-client-side-keystore.jceks differ diff --git a/tests/unit-tests/src/test/resources/verified-client-side-keystore.jks b/tests/unit-tests/src/test/resources/verified-client-side-keystore.jks new file mode 100644 index 0000000000..88e7e4031d Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-client-side-keystore.jks differ diff --git a/tests/unit-tests/src/test/resources/verified-client-side-truststore.jceks b/tests/unit-tests/src/test/resources/verified-client-side-truststore.jceks new file mode 100644 index 0000000000..ad63172317 Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-client-side-truststore.jceks differ diff --git a/tests/unit-tests/src/test/resources/verified-client-side-truststore.jks b/tests/unit-tests/src/test/resources/verified-client-side-truststore.jks new file mode 100644 index 0000000000..1d992c7d99 Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-client-side-truststore.jks differ diff --git a/tests/unit-tests/src/test/resources/verified-server-side-keystore.jceks b/tests/unit-tests/src/test/resources/verified-server-side-keystore.jceks new file mode 100644 index 0000000000..7a46162224 Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-server-side-keystore.jceks differ diff --git a/tests/unit-tests/src/test/resources/verified-server-side-keystore.jks b/tests/unit-tests/src/test/resources/verified-server-side-keystore.jks new file mode 100644 index 0000000000..55c7603abd Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-server-side-keystore.jks differ diff --git a/tests/unit-tests/src/test/resources/verified-server-side-truststore.jceks b/tests/unit-tests/src/test/resources/verified-server-side-truststore.jceks new file mode 100644 index 0000000000..e2bd4b3be0 Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-server-side-truststore.jceks differ diff --git a/tests/unit-tests/src/test/resources/verified-server-side-truststore.jks b/tests/unit-tests/src/test/resources/verified-server-side-truststore.jks new file mode 100644 index 0000000000..8d2288a07f Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-server-side-truststore.jks differ