This closes #1715
This commit is contained in:
commit
fee083a621
|
@ -206,6 +206,8 @@ public class NettyConnector extends AbstractConnector {
|
||||||
|
|
||||||
private String trustStorePassword;
|
private String trustStorePassword;
|
||||||
|
|
||||||
|
private String crlPath;
|
||||||
|
|
||||||
private String enabledCipherSuites;
|
private String enabledCipherSuites;
|
||||||
|
|
||||||
private String enabledProtocols;
|
private String enabledProtocols;
|
||||||
|
@ -338,6 +340,8 @@ public class NettyConnector extends AbstractConnector {
|
||||||
|
|
||||||
trustStorePassword = ConfigurationHelper.getPasswordProperty(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, TransportConstants.DEFAULT_TRUSTSTORE_PASSWORD, configuration, ActiveMQDefaultConfiguration.getPropMaskPassword(), ActiveMQDefaultConfiguration.getPropPasswordCodec());
|
trustStorePassword = ConfigurationHelper.getPasswordProperty(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, TransportConstants.DEFAULT_TRUSTSTORE_PASSWORD, configuration, ActiveMQDefaultConfiguration.getPropMaskPassword(), ActiveMQDefaultConfiguration.getPropPasswordCodec());
|
||||||
|
|
||||||
|
crlPath = ConfigurationHelper.getStringProperty(TransportConstants.CRL_PATH_PROP_NAME, TransportConstants.DEFAULT_CRL_PATH, configuration);
|
||||||
|
|
||||||
enabledCipherSuites = ConfigurationHelper.getStringProperty(TransportConstants.ENABLED_CIPHER_SUITES_PROP_NAME, TransportConstants.DEFAULT_ENABLED_CIPHER_SUITES, configuration);
|
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);
|
enabledProtocols = ConfigurationHelper.getStringProperty(TransportConstants.ENABLED_PROTOCOLS_PROP_NAME, TransportConstants.DEFAULT_ENABLED_PROTOCOLS, configuration);
|
||||||
|
@ -358,6 +362,7 @@ public class NettyConnector extends AbstractConnector {
|
||||||
trustStoreProvider = TransportConstants.DEFAULT_TRUSTSTORE_PROVIDER;
|
trustStoreProvider = TransportConstants.DEFAULT_TRUSTSTORE_PROVIDER;
|
||||||
trustStorePath = TransportConstants.DEFAULT_TRUSTSTORE_PATH;
|
trustStorePath = TransportConstants.DEFAULT_TRUSTSTORE_PATH;
|
||||||
trustStorePassword = TransportConstants.DEFAULT_TRUSTSTORE_PASSWORD;
|
trustStorePassword = TransportConstants.DEFAULT_TRUSTSTORE_PASSWORD;
|
||||||
|
crlPath = TransportConstants.DEFAULT_CRL_PATH;
|
||||||
enabledCipherSuites = TransportConstants.DEFAULT_ENABLED_CIPHER_SUITES;
|
enabledCipherSuites = TransportConstants.DEFAULT_ENABLED_CIPHER_SUITES;
|
||||||
enabledProtocols = TransportConstants.DEFAULT_ENABLED_PROTOCOLS;
|
enabledProtocols = TransportConstants.DEFAULT_ENABLED_PROTOCOLS;
|
||||||
verifyHost = TransportConstants.DEFAULT_VERIFY_HOST;
|
verifyHost = TransportConstants.DEFAULT_VERIFY_HOST;
|
||||||
|
@ -519,7 +524,7 @@ public class NettyConnector extends AbstractConnector {
|
||||||
if (System.getProperty(ACTIVEMQ_TRUSTSTORE_PASSWORD_PROP_NAME) != null) {
|
if (System.getProperty(ACTIVEMQ_TRUSTSTORE_PASSWORD_PROP_NAME) != null) {
|
||||||
realTrustStorePassword = System.getProperty(ACTIVEMQ_TRUSTSTORE_PASSWORD_PROP_NAME);
|
realTrustStorePassword = System.getProperty(ACTIVEMQ_TRUSTSTORE_PASSWORD_PROP_NAME);
|
||||||
}
|
}
|
||||||
context = SSLSupport.createContext(realKeyStoreProvider, realKeyStorePath, realKeyStorePassword, realTrustStoreProvider, realTrustStorePath, realTrustStorePassword, trustAll);
|
context = SSLSupport.createContext(realKeyStoreProvider, realKeyStorePath, realKeyStorePassword, realTrustStoreProvider, realTrustStorePath, realTrustStorePassword, trustAll, crlPath);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
close();
|
close();
|
||||||
|
|
|
@ -95,6 +95,8 @@ public class TransportConstants {
|
||||||
|
|
||||||
public static final String TRUSTSTORE_PASSWORD_PROP_NAME = "trustStorePassword";
|
public static final String TRUSTSTORE_PASSWORD_PROP_NAME = "trustStorePassword";
|
||||||
|
|
||||||
|
public static final String CRL_PATH_PROP_NAME = "crlPath";
|
||||||
|
|
||||||
public static final String ENABLED_CIPHER_SUITES_PROP_NAME = "enabledCipherSuites";
|
public static final String ENABLED_CIPHER_SUITES_PROP_NAME = "enabledCipherSuites";
|
||||||
|
|
||||||
public static final String ENABLED_PROTOCOLS_PROP_NAME = "enabledProtocols";
|
public static final String ENABLED_PROTOCOLS_PROP_NAME = "enabledProtocols";
|
||||||
|
@ -189,6 +191,8 @@ public class TransportConstants {
|
||||||
|
|
||||||
public static final String DEFAULT_TRUSTSTORE_PASSWORD = null;
|
public static final String DEFAULT_TRUSTSTORE_PASSWORD = null;
|
||||||
|
|
||||||
|
public static final String DEFAULT_CRL_PATH = null;
|
||||||
|
|
||||||
public static final String DEFAULT_ENABLED_CIPHER_SUITES = null;
|
public static final String DEFAULT_ENABLED_CIPHER_SUITES = null;
|
||||||
|
|
||||||
public static final String DEFAULT_ENABLED_PROTOCOLS = null;
|
public static final String DEFAULT_ENABLED_PROTOCOLS = null;
|
||||||
|
@ -310,6 +314,7 @@ public class TransportConstants {
|
||||||
allowableAcceptorKeys.add(ActiveMQDefaultConfiguration.getPropMaskPassword());
|
allowableAcceptorKeys.add(ActiveMQDefaultConfiguration.getPropMaskPassword());
|
||||||
allowableAcceptorKeys.add(ActiveMQDefaultConfiguration.getPropPasswordCodec());
|
allowableAcceptorKeys.add(ActiveMQDefaultConfiguration.getPropPasswordCodec());
|
||||||
allowableAcceptorKeys.add(TransportConstants.BACKLOG_PROP_NAME);
|
allowableAcceptorKeys.add(TransportConstants.BACKLOG_PROP_NAME);
|
||||||
|
allowableAcceptorKeys.add(TransportConstants.CRL_PATH_PROP_NAME);
|
||||||
|
|
||||||
ALLOWABLE_ACCEPTOR_KEYS = Collections.unmodifiableSet(allowableAcceptorKeys);
|
ALLOWABLE_ACCEPTOR_KEYS = Collections.unmodifiableSet(allowableAcceptorKeys);
|
||||||
|
|
||||||
|
@ -356,6 +361,7 @@ public class TransportConstants {
|
||||||
allowableConnectorKeys.add(TransportConstants.NETTY_CONNECT_TIMEOUT);
|
allowableConnectorKeys.add(TransportConstants.NETTY_CONNECT_TIMEOUT);
|
||||||
allowableConnectorKeys.add(TransportConstants.USE_DEFAULT_SSL_CONTEXT_PROP_NAME);
|
allowableConnectorKeys.add(TransportConstants.USE_DEFAULT_SSL_CONTEXT_PROP_NAME);
|
||||||
allowableConnectorKeys.add(TransportConstants.HANDSHAKE_TIMEOUT);
|
allowableConnectorKeys.add(TransportConstants.HANDSHAKE_TIMEOUT);
|
||||||
|
allowableConnectorKeys.add(TransportConstants.CRL_PATH_PROP_NAME);
|
||||||
|
|
||||||
ALLOWABLE_CONNECTOR_KEYS = Collections.unmodifiableSet(allowableConnectorKeys);
|
ALLOWABLE_CONNECTOR_KEYS = Collections.unmodifiableSet(allowableConnectorKeys);
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,15 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.core.remoting.impl.ssl;
|
package org.apache.activemq.artemis.core.remoting.impl.ssl;
|
||||||
|
|
||||||
|
import java.security.Security;
|
||||||
|
import java.security.cert.CRL;
|
||||||
|
import java.security.cert.CertStore;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.CollectionCertStoreParameters;
|
||||||
|
import java.security.cert.PKIXBuilderParameters;
|
||||||
|
import java.security.cert.X509CertSelector;
|
||||||
|
import java.util.Collection;
|
||||||
|
import javax.net.ssl.CertPathTrustManagerParameters;
|
||||||
import javax.net.ssl.KeyManager;
|
import javax.net.ssl.KeyManager;
|
||||||
import javax.net.ssl.KeyManagerFactory;
|
import javax.net.ssl.KeyManagerFactory;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
@ -30,11 +39,11 @@ import java.security.AccessController;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
import org.apache.activemq.artemis.utils.ClassloadingUtil;
|
import org.apache.activemq.artemis.utils.ClassloadingUtil;
|
||||||
|
|
||||||
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Please note, this class supports PKCS#11 keystores, but there are no specific tests in the ActiveMQ Artemis test-suite to
|
* Please note, this class supports PKCS#11 keystores, but there are no specific tests in the ActiveMQ Artemis test-suite to
|
||||||
* validate/verify this works because this requires a functioning PKCS#11 provider which is not available by default
|
* validate/verify this works because this requires a functioning PKCS#11 provider which is not available by default
|
||||||
|
@ -51,7 +60,18 @@ public class SSLSupport {
|
||||||
final String trustStorePath,
|
final String trustStorePath,
|
||||||
final String trustStorePassword) throws Exception {
|
final String trustStorePassword) throws Exception {
|
||||||
|
|
||||||
return SSLSupport.createContext(keystoreProvider, keystorePath, keystorePassword, trustStoreProvider, trustStorePath, trustStorePassword, false);
|
return SSLSupport.createContext(keystoreProvider, keystorePath, keystorePassword, trustStoreProvider, trustStorePath, trustStorePassword, false, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SSLContext createContext(final String keystoreProvider,
|
||||||
|
final String keystorePath,
|
||||||
|
final String keystorePassword,
|
||||||
|
final String trustStoreProvider,
|
||||||
|
final String trustStorePath,
|
||||||
|
final String trustStorePassword,
|
||||||
|
final String crlPath) throws Exception {
|
||||||
|
|
||||||
|
return SSLSupport.createContext(keystoreProvider, keystorePath, keystorePassword, trustStoreProvider, trustStorePath, trustStorePassword, false, crlPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SSLContext createContext(final String keystoreProvider,
|
public static SSLContext createContext(final String keystoreProvider,
|
||||||
|
@ -61,9 +81,20 @@ public class SSLSupport {
|
||||||
final String trustStorePath,
|
final String trustStorePath,
|
||||||
final String trustStorePassword,
|
final String trustStorePassword,
|
||||||
final boolean trustAll) throws Exception {
|
final boolean trustAll) throws Exception {
|
||||||
|
return SSLSupport.createContext(keystoreProvider, keystorePath, keystorePassword, trustStoreProvider, trustStorePath, trustStorePassword, trustAll, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SSLContext createContext(final String keystoreProvider,
|
||||||
|
final String keystorePath,
|
||||||
|
final String keystorePassword,
|
||||||
|
final String trustStoreProvider,
|
||||||
|
final String trustStorePath,
|
||||||
|
final String trustStorePassword,
|
||||||
|
final boolean trustAll,
|
||||||
|
final String crlPath) throws Exception {
|
||||||
SSLContext context = SSLContext.getInstance("TLS");
|
SSLContext context = SSLContext.getInstance("TLS");
|
||||||
KeyManager[] keyManagers = SSLSupport.loadKeyManagers(keystoreProvider, keystorePath, keystorePassword);
|
KeyManager[] keyManagers = SSLSupport.loadKeyManagers(keystoreProvider, keystorePath, keystorePassword);
|
||||||
TrustManager[] trustManagers = SSLSupport.loadTrustManager(trustStoreProvider, trustStorePath, trustStorePassword, trustAll);
|
TrustManager[] trustManagers = SSLSupport.loadTrustManager(trustStoreProvider, trustStorePath, trustStorePassword, trustAll, crlPath);
|
||||||
context.init(keyManagers, trustManagers, new SecureRandom());
|
context.init(keyManagers, trustManagers, new SecureRandom());
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
@ -93,18 +124,50 @@ public class SSLSupport {
|
||||||
private static TrustManager[] loadTrustManager(final String trustStoreProvider,
|
private static TrustManager[] loadTrustManager(final String trustStoreProvider,
|
||||||
final String trustStorePath,
|
final String trustStorePath,
|
||||||
final String trustStorePassword,
|
final String trustStorePassword,
|
||||||
final boolean trustAll) throws Exception {
|
final boolean trustAll,
|
||||||
|
final String crlPath) throws Exception {
|
||||||
if (trustAll) {
|
if (trustAll) {
|
||||||
//This is useful for testing but not should be used outside of that purpose
|
//This is useful for testing but not should be used outside of that purpose
|
||||||
return InsecureTrustManagerFactory.INSTANCE.getTrustManagers();
|
return InsecureTrustManagerFactory.INSTANCE.getTrustManagers();
|
||||||
} else if (trustStorePath == null && (trustStoreProvider == null || !"PKCS11".equals(trustStoreProvider.toUpperCase()))) {
|
} else if (trustStorePath == null && (trustStoreProvider == null || !"PKCS11".equals(trustStoreProvider.toUpperCase()))) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
TrustManagerFactory trustMgrFactory;
|
TrustManagerFactory trustMgrFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||||
KeyStore trustStore = SSLSupport.loadKeystore(trustStoreProvider, trustStorePath, trustStorePassword);
|
KeyStore trustStore = SSLSupport.loadKeystore(trustStoreProvider, trustStorePath, trustStorePassword);
|
||||||
trustMgrFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
boolean ocsp = Boolean.valueOf(Security.getProperty("ocsp.enable"));
|
||||||
trustMgrFactory.init(trustStore);
|
|
||||||
|
boolean initialized = false;
|
||||||
|
if ((ocsp || crlPath != null) && TrustManagerFactory.getDefaultAlgorithm().equalsIgnoreCase("PKIX")) {
|
||||||
|
PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(trustStore, new X509CertSelector());
|
||||||
|
if (crlPath != null) {
|
||||||
|
pkixParams.setRevocationEnabled(true);
|
||||||
|
Collection<? extends CRL> crlList = loadCRL(crlPath);
|
||||||
|
if (crlList != null) {
|
||||||
|
pkixParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(crlList)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trustMgrFactory.init(new CertPathTrustManagerParameters(pkixParams));
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
trustMgrFactory.init(trustStore);
|
||||||
|
}
|
||||||
|
|
||||||
return trustMgrFactory.getTrustManagers();
|
return trustMgrFactory.getTrustManagers();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Collection<? extends CRL> loadCRL(String crlPath) throws Exception {
|
||||||
|
if (crlPath == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
URL resource = SSLSupport.validateStoreURL(crlPath);
|
||||||
|
|
||||||
|
try (InputStream is = resource.openStream()) {
|
||||||
|
return CertificateFactory.getInstance("X.509").generateCRLs(is);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,6 +156,8 @@ public class NettyAcceptor extends AbstractAcceptor {
|
||||||
|
|
||||||
private final String trustStorePassword;
|
private final String trustStorePassword;
|
||||||
|
|
||||||
|
private final String crlPath;
|
||||||
|
|
||||||
private final String enabledCipherSuites;
|
private final String enabledCipherSuites;
|
||||||
|
|
||||||
private final String enabledProtocols;
|
private final String enabledProtocols;
|
||||||
|
@ -259,6 +261,8 @@ public class NettyAcceptor extends AbstractAcceptor {
|
||||||
|
|
||||||
trustStorePassword = ConfigurationHelper.getPasswordProperty(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, TransportConstants.DEFAULT_TRUSTSTORE_PASSWORD, configuration, ActiveMQDefaultConfiguration.getPropMaskPassword(), ActiveMQDefaultConfiguration.getPropPasswordCodec());
|
trustStorePassword = ConfigurationHelper.getPasswordProperty(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, TransportConstants.DEFAULT_TRUSTSTORE_PASSWORD, configuration, ActiveMQDefaultConfiguration.getPropMaskPassword(), ActiveMQDefaultConfiguration.getPropPasswordCodec());
|
||||||
|
|
||||||
|
crlPath = ConfigurationHelper.getStringProperty(TransportConstants.CRL_PATH_PROP_NAME, TransportConstants.DEFAULT_CRL_PATH, configuration);
|
||||||
|
|
||||||
enabledCipherSuites = ConfigurationHelper.getStringProperty(TransportConstants.ENABLED_CIPHER_SUITES_PROP_NAME, TransportConstants.DEFAULT_ENABLED_CIPHER_SUITES, configuration);
|
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);
|
enabledProtocols = ConfigurationHelper.getStringProperty(TransportConstants.ENABLED_PROTOCOLS_PROP_NAME, TransportConstants.DEFAULT_ENABLED_PROTOCOLS, configuration);
|
||||||
|
@ -273,6 +277,7 @@ public class NettyAcceptor extends AbstractAcceptor {
|
||||||
trustStoreProvider = TransportConstants.DEFAULT_TRUSTSTORE_PROVIDER;
|
trustStoreProvider = TransportConstants.DEFAULT_TRUSTSTORE_PROVIDER;
|
||||||
trustStorePath = TransportConstants.DEFAULT_TRUSTSTORE_PATH;
|
trustStorePath = TransportConstants.DEFAULT_TRUSTSTORE_PATH;
|
||||||
trustStorePassword = TransportConstants.DEFAULT_TRUSTSTORE_PASSWORD;
|
trustStorePassword = TransportConstants.DEFAULT_TRUSTSTORE_PASSWORD;
|
||||||
|
crlPath = TransportConstants.DEFAULT_CRL_PATH;
|
||||||
enabledCipherSuites = TransportConstants.DEFAULT_ENABLED_CIPHER_SUITES;
|
enabledCipherSuites = TransportConstants.DEFAULT_ENABLED_CIPHER_SUITES;
|
||||||
enabledProtocols = TransportConstants.DEFAULT_ENABLED_PROTOCOLS;
|
enabledProtocols = TransportConstants.DEFAULT_ENABLED_PROTOCOLS;
|
||||||
needClientAuth = TransportConstants.DEFAULT_NEED_CLIENT_AUTH;
|
needClientAuth = TransportConstants.DEFAULT_NEED_CLIENT_AUTH;
|
||||||
|
@ -453,7 +458,7 @@ public class NettyAcceptor extends AbstractAcceptor {
|
||||||
throw new IllegalArgumentException("If \"" + TransportConstants.SSL_ENABLED_PROP_NAME +
|
throw new IllegalArgumentException("If \"" + TransportConstants.SSL_ENABLED_PROP_NAME +
|
||||||
"\" is true then \"" + TransportConstants.KEYSTORE_PATH_PROP_NAME + "\" must be non-null " +
|
"\" is true then \"" + TransportConstants.KEYSTORE_PATH_PROP_NAME + "\" must be non-null " +
|
||||||
"unless an alternative \"" + TransportConstants.KEYSTORE_PROVIDER_PROP_NAME + "\" has been specified.");
|
"unless an alternative \"" + TransportConstants.KEYSTORE_PROVIDER_PROP_NAME + "\" has been specified.");
|
||||||
context = SSLSupport.createContext(keyStoreProvider, keyStorePath, keyStorePassword, trustStoreProvider, trustStorePath, trustStorePassword);
|
context = SSLSupport.createContext(keyStoreProvider, keyStorePath, keyStorePassword, trustStoreProvider, trustStorePath, trustStorePassword, crlPath);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
IllegalStateException ise = new IllegalStateException("Unable to create NettyAcceptor for " + host + ":" + port);
|
IllegalStateException ise = new IllegalStateException("Unable to create NettyAcceptor for " + host + ":" + port);
|
||||||
ise.initCause(e);
|
ise.initCause(e);
|
||||||
|
|
|
@ -102,6 +102,7 @@ under the License.
|
||||||
<module>xa-heuristic</module>
|
<module>xa-heuristic</module>
|
||||||
<module>xa-receive</module>
|
<module>xa-receive</module>
|
||||||
<module>xa-send</module>
|
<module>xa-send</module>
|
||||||
|
<module>ssl-enabled-crl-mqtt</module>
|
||||||
</modules>
|
</modules>
|
||||||
</profile>
|
</profile>
|
||||||
<profile>
|
<profile>
|
||||||
|
@ -173,6 +174,7 @@ under the License.
|
||||||
<module>xa-heuristic</module>
|
<module>xa-heuristic</module>
|
||||||
<module>xa-receive</module>
|
<module>xa-receive</module>
|
||||||
<module>xa-send</module>
|
<module>xa-send</module>
|
||||||
|
<module>ssl-enabled-crl-mqtt</module>
|
||||||
</modules>
|
</modules>
|
||||||
</profile>
|
</profile>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
<?xml version='1.0'?>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.apache.activemq.examples.broker</groupId>
|
||||||
|
<artifactId>jms-examples</artifactId>
|
||||||
|
<version>2.5.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>ssl-enabled-crl-mqtt</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<name>ActiveMQ Artemis Mqtt CRL Example</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<activemq.basedir>${project.basedir}/../../../..</activemq.basedir>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.activemq</groupId>
|
||||||
|
<artifactId>artemis-jms-client-all</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.fusesource.mqtt-client</groupId>
|
||||||
|
<artifactId>mqtt-client</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.activemq</groupId>
|
||||||
|
<artifactId>artemis-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>create</id>
|
||||||
|
<goals>
|
||||||
|
<goal>create</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<ignore>${noServer}</ignore>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>start</id>
|
||||||
|
<goals>
|
||||||
|
<goal>cli</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<ignore>${noServer}</ignore>
|
||||||
|
<spawn>true</spawn>
|
||||||
|
<testURI>tcp://localhost:61616</testURI>
|
||||||
|
<testUser>consumer</testUser>
|
||||||
|
<testPassword>activemq</testPassword>
|
||||||
|
<args>
|
||||||
|
<param>run</param>
|
||||||
|
</args>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>runClient</id>
|
||||||
|
<goals>
|
||||||
|
<goal>runClient</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<clientClass>org.apache.activemq.artemis.jms.example.MqttCrlEnabledExample</clientClass>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>stop</id>
|
||||||
|
<goals>
|
||||||
|
<goal>cli</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<ignore>${noServer}</ignore>
|
||||||
|
<args>
|
||||||
|
<param>stop</param>
|
||||||
|
</args>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.activemq.examples.broker</groupId>
|
||||||
|
<artifactId>ssl-enabled-crl-mqtt</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,98 @@
|
||||||
|
# ActiveMQ Artemis MQTT CRL Example
|
||||||
|
|
||||||
|
To run the example, simply type **mvn verify** from this directory, or **mvn -PnoServer verify** if you want to start and create the server manually.
|
||||||
|
|
||||||
|
This example shows you how to configure 2-way SSL with CRL along with 2 different connections, one with a valid certificate and another with a revoked certificate.
|
||||||
|
|
||||||
|
To configure 2-way SSL with CRL you need to configure the acceptor as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
<acceptor name="mqtt">tcp://0.0.0.0:1883?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=MQTT;useEpoll=true;sslEnabled=true;keyStorePath=${data.dir}/../etc/keystore1.jks;keyStorePassword=changeit;trustStorePath=${data.dir}/../etc/truststore.jks;keyStorePassword=changeit;crlPath=${data.dir}/../etc/root.crl.pem;needClientAuth=true</acceptor>`
|
||||||
|
```
|
||||||
|
|
||||||
|
In the server-side URL, the `keystore1.jks` is the key store file holding the server's key certificate. The `truststore.jks` is the file holding the certificates which the server trusts. The `root.crl.pem` is the file holding the revoked certificates. Notice also the `sslEnabled` and `needClientAuth` parameters which enable SSL and require clients to present their own certificate respectively.
|
||||||
|
|
||||||
|
The various keystore files are generated using the following commands. Keep in mind that each common name should be different and the passwords should be `changeit`.
|
||||||
|
|
||||||
|
```
|
||||||
|
openssl genrsa -out ca.key 2048
|
||||||
|
openssl req -new -x509 -days 1826 -key ca.key -out ca.crt
|
||||||
|
touch certindex
|
||||||
|
echo 01 > certserial
|
||||||
|
echo 01 > crlnumber
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create the ca.conf file:
|
||||||
|
|
||||||
|
```
|
||||||
|
[ ca ]
|
||||||
|
default_ca = myca
|
||||||
|
|
||||||
|
[ crl_ext ]
|
||||||
|
# issuerAltName=issuer:copy #this would copy the issuer name to altname
|
||||||
|
authorityKeyIdentifier=keyid:always
|
||||||
|
|
||||||
|
[ myca ]
|
||||||
|
dir = ./
|
||||||
|
new_certs_dir = $dir
|
||||||
|
unique_subject = no
|
||||||
|
certificate = $dir/ca.crt
|
||||||
|
database = $dir/certindex
|
||||||
|
private_key = $dir/ca.key
|
||||||
|
serial = $dir/certserial
|
||||||
|
default_days = 730
|
||||||
|
default_md = sha1
|
||||||
|
policy = myca_policy
|
||||||
|
x509_extensions = myca_extensions
|
||||||
|
crlnumber = $dir/crlnumber
|
||||||
|
default_crl_days = 730
|
||||||
|
|
||||||
|
[ myca_policy ]
|
||||||
|
commonName = supplied
|
||||||
|
stateOrProvinceName = supplied
|
||||||
|
countryName = optional
|
||||||
|
emailAddress = optional
|
||||||
|
organizationName = supplied
|
||||||
|
organizationalUnitName = optional
|
||||||
|
|
||||||
|
[ myca_extensions ]
|
||||||
|
basicConstraints = CA:false
|
||||||
|
subjectKeyIdentifier = hash
|
||||||
|
authorityKeyIdentifier = keyid:always
|
||||||
|
keyUsage = digitalSignature,keyEncipherment
|
||||||
|
extendedKeyUsage = serverAuth, clientAuth
|
||||||
|
crlDistributionPoints = URI:http://example.com/root.crl
|
||||||
|
subjectAltName = @alt_names
|
||||||
|
|
||||||
|
[alt_names]
|
||||||
|
DNS.1 = example.com
|
||||||
|
DNS.2 = *.example.com`
|
||||||
|
```
|
||||||
|
|
||||||
|
## Continue with the following commands:
|
||||||
|
|
||||||
|
```
|
||||||
|
openssl genrsa -out keystore1.key 2048
|
||||||
|
openssl req -new -key keystore1.key -out keystore1.csr
|
||||||
|
openssl ca -batch -config ca.conf -notext -in keystore1.csr -out keystore1.crt
|
||||||
|
openssl genrsa -out client_revoked.key 2048
|
||||||
|
openssl req -new -key client_revoked.key -out client_revoked.csr
|
||||||
|
openssl ca -batch -config ca.conf -notext -in client_revoked.csr -out client_revoked.crt
|
||||||
|
openssl genrsa -out client_not_revoked.key 2048
|
||||||
|
openssl req -new -key client_not_revoked.key -out client_not_revoked.csr
|
||||||
|
openssl ca -batch -config ca.conf -notext -in client_not_revoked.csr -out client_not_revoked.crt
|
||||||
|
openssl ca -config ca.conf -gencrl -keyfile ca.key -cert ca.crt -out root.crl.pem
|
||||||
|
openssl ca -config ca.conf -revoke client_revoked.crt -keyfile ca.key -cert ca.crt
|
||||||
|
openssl ca -config ca.conf -gencrl -keyfile ca.key -cert ca.crt -out root.crl.pem
|
||||||
|
|
||||||
|
openssl pkcs12 -export -name client_revoked -in client_revoked.crt -inkey client_revoked.key -out client_revoked.p12
|
||||||
|
keytool -importkeystore -destkeystore client_revoked.jks -srckeystore client_revoked.p12 -srcstoretype pkcs12 -alias client_revoked
|
||||||
|
|
||||||
|
openssl pkcs12 -export -name client_not_revoked -in client_not_revoked.crt -inkey client_not_revoked.key -out client_not_revoked.p12
|
||||||
|
keytool -importkeystore -destkeystore client_not_revoked.jks -srckeystore client_not_revoked.p12 -srcstoretype pkcs12 -alias client_not_revoked
|
||||||
|
|
||||||
|
openssl pkcs12 -export -name keystore1 -in keystore1.crt -inkey keystore1.key -out keystore1.p12
|
||||||
|
keytool -importkeystore -destkeystore keystore1.jks -srckeystore keystore1.p12 -srcstoretype pkcs12 -alias keystore1
|
||||||
|
|
||||||
|
keytool -import -trustcacerts -alias trust_key -file ca.crt -keystore truststore.jks
|
||||||
|
```
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* 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.activemq.artemis.jms.example;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.core.remoting.impl.ssl.SSLSupport;
|
||||||
|
import org.fusesource.mqtt.client.BlockingConnection;
|
||||||
|
import org.fusesource.mqtt.client.MQTT;
|
||||||
|
import org.fusesource.mqtt.client.Message;
|
||||||
|
import org.fusesource.mqtt.client.QoS;
|
||||||
|
import org.fusesource.mqtt.client.Topic;
|
||||||
|
|
||||||
|
public class MqttCrlEnabledExample {
|
||||||
|
|
||||||
|
public static void main(final String[] args) throws Exception {
|
||||||
|
boolean exception = false;
|
||||||
|
try {
|
||||||
|
callBroker("truststore.jks", "changeit", "client_revoked.jks", "changeit");
|
||||||
|
} catch (SSLException e) {
|
||||||
|
exception = true;
|
||||||
|
}
|
||||||
|
if (!exception) {
|
||||||
|
throw new RuntimeException("The connection should be revoked");
|
||||||
|
}
|
||||||
|
callBroker("truststore.jks", "changeit", "client_not_revoked.jks", "changeit");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void callBroker(String truststorePath, String truststorePass, String keystorePath, String keystorePass) throws Exception {
|
||||||
|
BlockingConnection connection = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
connection = retrieveMQTTConnection("ssl://localhost:1883", truststorePath, truststorePass, keystorePath, keystorePass);
|
||||||
|
// Subscribe to topics
|
||||||
|
Topic[] topics = {new Topic("test/+/some/#", QoS.AT_MOST_ONCE)};
|
||||||
|
connection.subscribe(topics);
|
||||||
|
|
||||||
|
// Publish Messages
|
||||||
|
String payload = "This is message 1";
|
||||||
|
|
||||||
|
connection.publish("test/1/some/la", payload.getBytes(), QoS.AT_LEAST_ONCE, false);
|
||||||
|
|
||||||
|
Message message = connection.receive(5, TimeUnit.SECONDS);
|
||||||
|
System.out.println("Message received: " + new String(message.getPayload()));
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BlockingConnection retrieveMQTTConnection(String host, String truststorePath, String truststorePass, String keystorePath, String keystorePass) throws Exception {
|
||||||
|
MQTT mqtt = new MQTT();
|
||||||
|
mqtt.setConnectAttemptsMax(0);
|
||||||
|
mqtt.setReconnectAttemptsMax(0);
|
||||||
|
mqtt.setHost(host);
|
||||||
|
mqtt.setSslContext(SSLSupport.createContext("JKS", keystorePath, keystorePass, "JKS", truststorePath, truststorePass));
|
||||||
|
mqtt.setCleanSession(true);
|
||||||
|
|
||||||
|
BlockingConnection connection = mqtt.blockingConnection();
|
||||||
|
connection.connect();
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-server.xsd">
|
||||||
|
<core xmlns="urn:activemq:core">
|
||||||
|
|
||||||
|
<security-enabled>false</security-enabled>
|
||||||
|
|
||||||
|
<acceptors>
|
||||||
|
<acceptor name="netty-acceptor">tcp://localhost:61616</acceptor>
|
||||||
|
<acceptor name="mqtt">tcp://0.0.0.0:1883?protocols=MQTT;sslEnabled=true;keyStorePath=keystore1.jks;keyStorePassword=changeit;trustStorePath=truststore.jks;keyStorePassword=changeit;crlPath=root.crl.pem;needClientAuth=true</acceptor>
|
||||||
|
</acceptors>
|
||||||
|
|
||||||
|
<wildcard-addresses>
|
||||||
|
<routing-enabled>true</routing-enabled>
|
||||||
|
<delimiter>/</delimiter>
|
||||||
|
<any-words>#</any-words>
|
||||||
|
<single-word>+</single-word>
|
||||||
|
</wildcard-addresses>
|
||||||
|
|
||||||
|
</core>
|
||||||
|
</configuration>
|
Binary file not shown.
|
@ -0,0 +1,12 @@
|
||||||
|
-----BEGIN X509 CRL-----
|
||||||
|
MIIB2DCBwQIBATANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJBVTETMBEGA1UE
|
||||||
|
CAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk
|
||||||
|
MRAwDgYDVQQDDAdhc2ZnZGZnMRAwDgYJKoZIhvcNAQkBFgFhFw0xNzEyMTQxODAw
|
||||||
|
NDVaFw0xOTEyMTQxODAwNDVaMBQwEgIBAhcNMTcxMjE0MTgwMDM2WqAOMAwwCgYD
|
||||||
|
VR0UBAMCAQIwDQYJKoZIhvcNAQEFBQADggEBACNiLQvZayn+ULeeSTnxcOOPaIku
|
||||||
|
1E5AGG3M6uUBalECEpstzmXQELdiZvQb2BMRb1hpm1pNJ8uITjrjeT6bf1+KGgeN
|
||||||
|
6lRMg36AwyQm8LGiE6ry9jF1OCHqERuImQUrRKWRUbL4hT79Fmji1xm9T9CA3RmE
|
||||||
|
hjN5oHXM5avF+pm6aU2L2bZ03DhU4Ur0rOd1DCXcGWiZc7VJEQicSrG2R8dagFO/
|
||||||
|
w0OUFiTahbdxSguNNU5kIuSltm4kfMM7GcFMb9/kMTTz/U+nUarm7ZzZozn7p/Sb
|
||||||
|
9FjJ39JzFwq0jTT2bK+3WEWagQs9eNWAPjb5F3ofBSUleZ1f3rdhWWCSS+A=
|
||||||
|
-----END X509 CRL-----
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -481,6 +481,15 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<nonFilteredFileExtensions>
|
||||||
|
<nonFilteredFileExtension>jks</nonFilteredFileExtension>
|
||||||
|
</nonFilteredFileExtensions>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,247 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.activemq.artemis.tests.integration.mqtt.imported;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||||
|
import org.apache.activemq.artemis.core.config.Configuration;
|
||||||
|
import org.apache.activemq.artemis.core.config.WildcardConfiguration;
|
||||||
|
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory;
|
||||||
|
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
|
||||||
|
import org.apache.activemq.artemis.core.remoting.impl.ssl.SSLSupport;
|
||||||
|
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||||
|
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||||
|
import org.fusesource.mqtt.client.BlockingConnection;
|
||||||
|
import org.fusesource.mqtt.client.MQTT;
|
||||||
|
import org.fusesource.mqtt.client.Message;
|
||||||
|
import org.fusesource.mqtt.client.QoS;
|
||||||
|
import org.fusesource.mqtt.client.Topic;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class MQTTSecurityCRLTest extends ActiveMQTestBase {
|
||||||
|
/**
|
||||||
|
* These artifacts are required for testing mqtt with CRL
|
||||||
|
* <p>
|
||||||
|
* openssl genrsa -out ca.key 2048
|
||||||
|
* openssl req -new -x509 -days 1826 -key ca.key -out ca.crt
|
||||||
|
* touch certindex
|
||||||
|
* echo 01 > certserial
|
||||||
|
* echo 01 > crlnumber
|
||||||
|
* <p>
|
||||||
|
* Create ca.conf file with
|
||||||
|
* <p>
|
||||||
|
* [ ca ]
|
||||||
|
* default_ca = myca
|
||||||
|
* <p>
|
||||||
|
* [ crl_ext ]
|
||||||
|
* # issuerAltName=issuer:copy #this would copy the issuer name to altname
|
||||||
|
* authorityKeyIdentifier=keyid:always
|
||||||
|
* <p>
|
||||||
|
* [ myca ]
|
||||||
|
* dir = ./
|
||||||
|
* new_certs_dir = $dir
|
||||||
|
* unique_subject = no
|
||||||
|
* certificate = $dir/ca.crt
|
||||||
|
* database = $dir/certindex
|
||||||
|
* private_key = $dir/ca.key
|
||||||
|
* serial = $dir/certserial
|
||||||
|
* default_days = 730
|
||||||
|
* default_md = sha1
|
||||||
|
* policy = myca_policy
|
||||||
|
* x509_extensions = myca_extensions
|
||||||
|
* crlnumber = $dir/crlnumber
|
||||||
|
* default_crl_days = 730
|
||||||
|
* <p>
|
||||||
|
* [ myca_policy ]
|
||||||
|
* commonName = supplied
|
||||||
|
* stateOrProvinceName = supplied
|
||||||
|
* countryName = optional
|
||||||
|
* emailAddress = optional
|
||||||
|
* organizationName = supplied
|
||||||
|
* organizationalUnitName = optional
|
||||||
|
* <p>
|
||||||
|
* [ myca_extensions ]
|
||||||
|
* basicConstraints = CA:false
|
||||||
|
* subjectKeyIdentifier = hash
|
||||||
|
* authorityKeyIdentifier = keyid:always
|
||||||
|
* keyUsage = digitalSignature,keyEncipherment
|
||||||
|
* extendedKeyUsage = serverAuth, clientAuth
|
||||||
|
* crlDistributionPoints = URI:http://example.com/root.crl
|
||||||
|
* subjectAltName = @alt_names
|
||||||
|
* <p>
|
||||||
|
* [alt_names]
|
||||||
|
* DNS.1 = example.com
|
||||||
|
* DNS.2 = *.example.com
|
||||||
|
* <p>
|
||||||
|
* Continue executing the commands:
|
||||||
|
* <p>
|
||||||
|
* openssl genrsa -out keystore1.key 2048
|
||||||
|
* openssl req -new -key keystore1.key -out keystore1.csr
|
||||||
|
* openssl ca -batch -config ca.conf -notext -in keystore1.csr -out keystore1.crt
|
||||||
|
* openssl genrsa -out client_revoked.key 2048
|
||||||
|
* openssl req -new -key client_revoked.key -out client_revoked.csr
|
||||||
|
* openssl ca -batch -config ca.conf -notext -in client_revoked.csr -out client_revoked.crt
|
||||||
|
* openssl genrsa -out client_not_revoked.key 2048
|
||||||
|
* openssl req -new -key client_not_revoked.key -out client_not_revoked.csr
|
||||||
|
* openssl ca -batch -config ca.conf -notext -in client_not_revoked.csr -out client_not_revoked.crt
|
||||||
|
* openssl ca -config ca.conf -gencrl -keyfile ca.key -cert ca.crt -out root.crl.pem
|
||||||
|
* openssl ca -config ca.conf -revoke client_revoked.crt -keyfile ca.key -cert ca.crt
|
||||||
|
* openssl ca -config ca.conf -gencrl -keyfile ca.key -cert ca.crt -out root.crl.pem
|
||||||
|
* <p>
|
||||||
|
* openssl pkcs12 -export -name client_revoked -in client_revoked.crt -inkey client_revoked.key -out client_revoked.p12
|
||||||
|
* keytool -importkeystore -destkeystore client_revoked.jks -srckeystore client_revoked.p12 -srcstoretype pkcs12 -alias client_revoked
|
||||||
|
* <p>
|
||||||
|
* openssl pkcs12 -export -name client_not_revoked -in client_not_revoked.crt -inkey client_not_revoked.key -out client_not_revoked.p12
|
||||||
|
* keytool -importkeystore -destkeystore client_not_revoked.jks -srckeystore client_not_revoked.p12 -srcstoretype pkcs12 -alias client_not_revoked
|
||||||
|
* <p>
|
||||||
|
* openssl pkcs12 -export -name keystore1 -in keystore1.crt -inkey keystore1.key -out keystore1.p12
|
||||||
|
* keytool -importkeystore -destkeystore keystore1.jks -srckeystore keystore1.p12 -srcstoretype pkcs12 -alias keystore1
|
||||||
|
* <p>
|
||||||
|
* keytool -import -trustcacerts -alias trust_key -file ca.crt -keystore truststore.jks
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Test(expected = SSLException.class)
|
||||||
|
public void crlRevokedTest() throws Exception {
|
||||||
|
|
||||||
|
ActiveMQServer server1 = initServer();
|
||||||
|
BlockingConnection connection1 = null;
|
||||||
|
try {
|
||||||
|
server1.start();
|
||||||
|
|
||||||
|
while (!server1.isStarted()) {
|
||||||
|
Thread.sleep(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
connection1 = retrieveMQTTConnection("ssl://localhost:1883", "truststore.jks", "changeit", "client_revoked.jks", "changeit");
|
||||||
|
|
||||||
|
// Subscribe to topics
|
||||||
|
Topic[] topics = {new Topic("test/+/some/#", QoS.AT_MOST_ONCE)};
|
||||||
|
connection1.subscribe(topics);
|
||||||
|
|
||||||
|
// Publish Messages
|
||||||
|
String payload1 = "This is message 1";
|
||||||
|
|
||||||
|
connection1.publish("test/1/some/la", payload1.getBytes(), QoS.AT_LEAST_ONCE, false);
|
||||||
|
|
||||||
|
Message message1 = connection1.receive(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
assertEquals(payload1, new String(message1.getPayload()));
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (connection1 != null) {
|
||||||
|
connection1.disconnect();
|
||||||
|
}
|
||||||
|
if (server1.isStarted()) {
|
||||||
|
server1.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void crlNotRevokedTest() throws Exception {
|
||||||
|
|
||||||
|
ActiveMQServer server1 = initServer();
|
||||||
|
BlockingConnection connection1 = null;
|
||||||
|
try {
|
||||||
|
server1.start();
|
||||||
|
|
||||||
|
while (!server1.isStarted()) {
|
||||||
|
Thread.sleep(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
connection1 = retrieveMQTTConnection("ssl://localhost:1883", "truststore.jks", "changeit", "client_not_revoked.jks", "changeit");
|
||||||
|
|
||||||
|
// Subscribe to topics
|
||||||
|
Topic[] topics = {new Topic("test/+/some/#", QoS.AT_MOST_ONCE)};
|
||||||
|
connection1.subscribe(topics);
|
||||||
|
|
||||||
|
// Publish Messages
|
||||||
|
String payload1 = "This is message 1";
|
||||||
|
|
||||||
|
connection1.publish("test/1/some/la", payload1.getBytes(), QoS.AT_LEAST_ONCE, false);
|
||||||
|
|
||||||
|
Message message1 = connection1.receive(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
assertEquals(payload1, new String(message1.getPayload()));
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (connection1 != null) {
|
||||||
|
connection1.disconnect();
|
||||||
|
}
|
||||||
|
if (server1.isStarted()) {
|
||||||
|
server1.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ActiveMQServer initServer() throws Exception {
|
||||||
|
Configuration configuration = createDefaultNettyConfig().setSecurityEnabled(false);
|
||||||
|
|
||||||
|
addMqttTransportConfiguration(configuration);
|
||||||
|
addWildCardConfiguration(configuration);
|
||||||
|
|
||||||
|
ActiveMQServer server = createServer(true, configuration);
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addWildCardConfiguration(Configuration configuration) {
|
||||||
|
WildcardConfiguration wildcardConfiguration = new WildcardConfiguration();
|
||||||
|
wildcardConfiguration.setAnyWords('#');
|
||||||
|
wildcardConfiguration.setDelimiter('/');
|
||||||
|
wildcardConfiguration.setRoutingEnabled(true);
|
||||||
|
wildcardConfiguration.setSingleWord('+');
|
||||||
|
|
||||||
|
configuration.setWildCardConfiguration(wildcardConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addMqttTransportConfiguration(Configuration configuration) throws IOException {
|
||||||
|
TransportConfiguration transportConfiguration = new TransportConfiguration(NettyAcceptorFactory.class.getCanonicalName(), null, "mqtt", null);
|
||||||
|
|
||||||
|
transportConfiguration.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
|
||||||
|
transportConfiguration.getParams().put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, "truststore.jks");
|
||||||
|
transportConfiguration.getParams().put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, "changeit");
|
||||||
|
transportConfiguration.getParams().put(TransportConstants.KEYSTORE_PATH_PROP_NAME, "keystore1.jks");
|
||||||
|
transportConfiguration.getParams().put(TransportConstants.KEYSTORE_PASSWORD_PROP_NAME, "changeit");
|
||||||
|
transportConfiguration.getParams().put(TransportConstants.CRL_PATH_PROP_NAME, "root.crl.pem");
|
||||||
|
transportConfiguration.getParams().put(TransportConstants.NEED_CLIENT_AUTH_PROP_NAME, "true");
|
||||||
|
transportConfiguration.getParams().put(TransportConstants.PORT_PROP_NAME, "1883");
|
||||||
|
transportConfiguration.getParams().put(TransportConstants.HOST_PROP_NAME, "localhost");
|
||||||
|
transportConfiguration.getParams().put(TransportConstants.PROTOCOLS_PROP_NAME, "MQTT");
|
||||||
|
|
||||||
|
configuration.getAcceptorConfigurations().add(transportConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockingConnection retrieveMQTTConnection(String host, String truststorePath, String truststorePass, String keystorePath, String keystorePass) throws Exception {
|
||||||
|
MQTT mqtt = new MQTT();
|
||||||
|
mqtt.setConnectAttemptsMax(1);
|
||||||
|
mqtt.setReconnectAttemptsMax(0);
|
||||||
|
mqtt.setHost(host);
|
||||||
|
SSLContext sslContext = SSLSupport.createContext(TransportConstants.DEFAULT_KEYSTORE_PROVIDER, keystorePath, keystorePass, TransportConstants.DEFAULT_TRUSTSTORE_PROVIDER, truststorePath, truststorePass);
|
||||||
|
mqtt.setSslContext(sslContext);
|
||||||
|
|
||||||
|
BlockingConnection connection = mqtt.blockingConnection();
|
||||||
|
connection.connect();
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,12 @@
|
||||||
|
-----BEGIN X509 CRL-----
|
||||||
|
MIIB2DCBwQIBATANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJBVTETMBEGA1UE
|
||||||
|
CAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk
|
||||||
|
MRAwDgYDVQQDDAdhc2ZnZGZnMRAwDgYJKoZIhvcNAQkBFgFhFw0xNzEyMTQxODAw
|
||||||
|
NDVaFw0xOTEyMTQxODAwNDVaMBQwEgIBAhcNMTcxMjE0MTgwMDM2WqAOMAwwCgYD
|
||||||
|
VR0UBAMCAQIwDQYJKoZIhvcNAQEFBQADggEBACNiLQvZayn+ULeeSTnxcOOPaIku
|
||||||
|
1E5AGG3M6uUBalECEpstzmXQELdiZvQb2BMRb1hpm1pNJ8uITjrjeT6bf1+KGgeN
|
||||||
|
6lRMg36AwyQm8LGiE6ry9jF1OCHqERuImQUrRKWRUbL4hT79Fmji1xm9T9CA3RmE
|
||||||
|
hjN5oHXM5avF+pm6aU2L2bZ03DhU4Ur0rOd1DCXcGWiZc7VJEQicSrG2R8dagFO/
|
||||||
|
w0OUFiTahbdxSguNNU5kIuSltm4kfMM7GcFMb9/kMTTz/U+nUarm7ZzZozn7p/Sb
|
||||||
|
9FjJ39JzFwq0jTT2bK+3WEWagQs9eNWAPjb5F3ofBSUleZ1f3rdhWWCSS+A=
|
||||||
|
-----END X509 CRL-----
|
Binary file not shown.
Loading…
Reference in New Issue