You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by cl...@apache.org on 2016/08/15 17:58:37 UTC

[2/3] activemq-artemis git commit: ARTEMIS-656 support host verification for SSL cert

ARTEMIS-656 support host verification for SSL cert


Project: http://git-wip-us.apache.org/repos/asf/activemq-artemis/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-artemis/commit/cfbe06f3
Tree: http://git-wip-us.apache.org/repos/asf/activemq-artemis/tree/cfbe06f3
Diff: http://git-wip-us.apache.org/repos/asf/activemq-artemis/diff/cfbe06f3

Branch: refs/heads/master
Commit: cfbe06f3bc4173fc19324de1d5b811067e2d1aa8
Parents: 113c2a3
Author: jbertram <jb...@apache.org>
Authored: Thu Aug 11 14:32:56 2016 -0500
Committer: Clebert Suconic <cl...@apache.org>
Committed: Mon Aug 15 13:58:25 2016 -0400

----------------------------------------------------------------------
 .../remoting/impl/netty/NettyConnector.java     |  20 ++++-
 .../remoting/impl/netty/TransportConstants.java |   6 ++
 .../core/remoting/impl/netty/NettyAcceptor.java |  23 +++++-
 docs/user-manual/en/configuring-transports.md   |  12 +++
 .../ssl/CoreClientOverOneWaySSLTest.java        |  76 ++++++++++++++++-
 .../ssl/CoreClientOverTwoWaySSLTest.java        |  81 ++++++++++++++++++-
 .../verified-client-side-keystore.jceks         | Bin 0 -> 2203 bytes
 .../resources/verified-client-side-keystore.jks | Bin 0 -> 2226 bytes
 .../verified-client-side-truststore.jceks       | Bin 0 -> 868 bytes
 .../verified-client-side-truststore.jks         | Bin 0 -> 935 bytes
 .../verified-server-side-keystore.jceks         | Bin 0 -> 1248 bytes
 .../resources/verified-server-side-keystore.jks | Bin 0 -> 2225 bytes
 .../verified-server-side-truststore.jceks       | Bin 0 -> 935 bytes
 .../verified-server-side-truststore.jks         | Bin 0 -> 935 bytes
 14 files changed, 212 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/cfbe06f3/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyConnector.java
----------------------------------------------------------------------
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 62c405b..49c936b 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);

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/cfbe06f3/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/TransportConstants.java
----------------------------------------------------------------------
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 53dc204..40aed3d 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);

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/cfbe06f3/artemis-server/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyAcceptor.java
----------------------------------------------------------------------
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 f5742c5..ce506cb 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);
    }
 

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/cfbe06f3/docs/user-manual/en/configuring-transports.md
----------------------------------------------------------------------
diff --git a/docs/user-manual/en/configuring-transports.md b/docs/user-manual/en/configuring-transports.md
index 872fe2f..a44da35 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

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/cfbe06f3/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverOneWaySSLTest.java
----------------------------------------------------------------------
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 50ac998..de46bcd 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;
@@ -124,6 +135,56 @@ public class CoreClientOverOneWaySSLTest extends ActiveMQTestBase {
    }
 
    @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();
       server.createQueue(CoreClientOverOneWaySSLTest.QUEUE, CoreClientOverOneWaySSLTest.QUEUE, null, false, false);
@@ -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<String, Object> 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);

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/cfbe06f3/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverTwoWaySSLTest.java
----------------------------------------------------------------------
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 0d553ad..403ebc3 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;
@@ -149,6 +160,72 @@ public class CoreClientOverTwoWaySSLTest extends ActiveMQTestBase {
    }
 
    @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);
       tc.getParams().put(TransportConstants.TRUSTSTORE_PROVIDER_PROP_NAME, storeType);
@@ -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);

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/cfbe06f3/tests/unit-tests/src/test/resources/verified-client-side-keystore.jceks
----------------------------------------------------------------------
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 0000000..250832b
Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-client-side-keystore.jceks differ

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/cfbe06f3/tests/unit-tests/src/test/resources/verified-client-side-keystore.jks
----------------------------------------------------------------------
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 0000000..88e7e40
Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-client-side-keystore.jks differ

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/cfbe06f3/tests/unit-tests/src/test/resources/verified-client-side-truststore.jceks
----------------------------------------------------------------------
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 0000000..ad63172
Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-client-side-truststore.jceks differ

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/cfbe06f3/tests/unit-tests/src/test/resources/verified-client-side-truststore.jks
----------------------------------------------------------------------
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 0000000..1d992c7
Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-client-side-truststore.jks differ

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/cfbe06f3/tests/unit-tests/src/test/resources/verified-server-side-keystore.jceks
----------------------------------------------------------------------
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 0000000..7a46162
Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-server-side-keystore.jceks differ

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/cfbe06f3/tests/unit-tests/src/test/resources/verified-server-side-keystore.jks
----------------------------------------------------------------------
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 0000000..55c7603
Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-server-side-keystore.jks differ

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/cfbe06f3/tests/unit-tests/src/test/resources/verified-server-side-truststore.jceks
----------------------------------------------------------------------
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 0000000..e2bd4b3
Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-server-side-truststore.jceks differ

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/cfbe06f3/tests/unit-tests/src/test/resources/verified-server-side-truststore.jks
----------------------------------------------------------------------
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 0000000..8d2288a
Binary files /dev/null and b/tests/unit-tests/src/test/resources/verified-server-side-truststore.jks differ