Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ public interface ActiveMQClientLogger {
@LogMessage(id = 212080, value = "Using legacy SSL store provider value: {}. Please use either 'keyStoreType' or 'trustStoreType' instead as appropriate.", level = LogMessage.Level.WARN)
void oldStoreProvider(String value);

@LogMessage(id = 212081, value = "Soft failure checking the certificate [{}]: {}", level = LogMessage.Level.WARN)
void softFailException(String certSubject, Exception e);

@LogMessage(id = 214000, value = "Failed to call onMessage", level = LogMessage.Level.ERROR)
void onMessageError(Throwable e);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,10 @@ public class NettyConnector extends AbstractConnector {

private String crlPath;

private String crcOptions;

private String ocspResponderURL;

private String enabledCipherSuites;

private String enabledProtocols;
Expand Down Expand Up @@ -451,12 +455,18 @@ public NettyConnector(final Map<String, Object> configuration,
useDefaultSslContext = ConfigurationHelper.getBooleanProperty(TransportConstants.USE_DEFAULT_SSL_CONTEXT_PROP_NAME, TransportConstants.DEFAULT_USE_DEFAULT_SSL_CONTEXT, configuration);

trustManagerFactoryPlugin = ConfigurationHelper.getStringProperty(TransportConstants.TRUST_MANAGER_FACTORY_PLUGIN_PROP_NAME, TransportConstants.DEFAULT_TRUST_MANAGER_FACTORY_PLUGIN, configuration);

crcOptions = ConfigurationHelper.getStringProperty(TransportConstants.CRC_OPTIONS_PROP_NAME, TransportConstants.DEFAULT_CRC_OPTIONS, configuration);

ocspResponderURL = ConfigurationHelper.getStringProperty(TransportConstants.OCSP_RESPONDER_URL_PROP_NAME, TransportConstants.DEFAULT_OCSP_RESPONDER_URL, configuration);
} else {
keyStoreProvider = TransportConstants.DEFAULT_KEYSTORE_PROVIDER;
keyStoreType = TransportConstants.DEFAULT_KEYSTORE_TYPE;
keyStorePath = TransportConstants.DEFAULT_KEYSTORE_PATH;
keyStorePassword = TransportConstants.DEFAULT_KEYSTORE_PASSWORD;
keyStoreAlias = TransportConstants.DEFAULT_KEYSTORE_ALIAS;
crcOptions = TransportConstants.DEFAULT_CRC_OPTIONS;
ocspResponderURL = TransportConstants.DEFAULT_OCSP_RESPONDER_URL;
passwordCodecClass = TransportConstants.DEFAULT_PASSWORD_CODEC_CLASS;
trustStoreProvider = TransportConstants.DEFAULT_TRUSTSTORE_PROVIDER;
trustStoreType = TransportConstants.DEFAULT_TRUSTSTORE_TYPE;
Expand Down Expand Up @@ -522,6 +532,14 @@ private String getHttpUpgradeInfo() {
return ", activemqServerName=" + serverName + ", httpUpgradeEndpoint=" + acceptor;
}

public String getCrcOptions() {
return crcOptions;
}

public String getOcspResponderURL() {
return ocspResponderURL;
}

@Override
public synchronized void start() {
if (channelClazz != null) {
Expand Down Expand Up @@ -688,6 +706,8 @@ public void initChannel(Channel channel) throws Exception {
.trustManagerFactoryPlugin(trustManagerFactoryPlugin)
.crlPath(crlPath)
.trustAll(trustAll)
.crcOptions(crcOptions)
.ocspResponderURL(ocspResponderURL)
.build();

final SSLEngine engine;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ public class TransportConstants {

public static final String SOCKS_REMOTE_DNS_PROP_NAME = "socksRemoteDNS";

public static final String CRC_OPTIONS_PROP_NAME = "crcOptions";

public static final String OCSP_RESPONDER_URL_PROP_NAME = "ocspResponderURL";

public static final String AUTO_START = "autoStart";

public static final boolean DEFAULT_AUTO_START = true;
Expand Down Expand Up @@ -403,6 +407,10 @@ public class TransportConstants {

public static final String DEFAULT_ROUTER = null;

public static final String DEFAULT_CRC_OPTIONS = null;

public static final String DEFAULT_OCSP_RESPONDER_URL = null;

private static int parseDefaultVariable(String variableName, int defaultValue) {
try {
String variable = System.getProperty(TransportConstants.class.getName() + "." + variableName);
Expand Down Expand Up @@ -484,6 +492,8 @@ private static int parseDefaultVariable(String variableName, int defaultValue) {
allowableAcceptorKeys.add(TransportConstants.AUTO_START);
allowableAcceptorKeys.add(TransportConstants.ROUTER);
allowableAcceptorKeys.add(TransportConstants.PROXY_PROTOCOL_ENABLED_PROP_NAME);
allowableAcceptorKeys.add(TransportConstants.CRC_OPTIONS_PROP_NAME);
allowableAcceptorKeys.add(TransportConstants.OCSP_RESPONDER_URL_PROP_NAME);

ALLOWABLE_ACCEPTOR_KEYS = Collections.unmodifiableSet(allowableAcceptorKeys);

Expand Down Expand Up @@ -545,6 +555,8 @@ private static int parseDefaultVariable(String variableName, int defaultValue) {
allowableConnectorKeys.add(TransportConstants.TRUST_MANAGER_FACTORY_PLUGIN_PROP_NAME);
allowableConnectorKeys.add(TransportConstants.HANDSHAKE_TIMEOUT);
allowableConnectorKeys.add(TransportConstants.CRL_PATH_PROP_NAME);
allowableConnectorKeys.add(TransportConstants.CRC_OPTIONS_PROP_NAME);
allowableConnectorKeys.add(TransportConstants.OCSP_RESPONDER_URL_PROP_NAME);

ALLOWABLE_CONNECTOR_KEYS = Collections.unmodifiableSet(allowableConnectorKeys);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import javax.net.ssl.CertPathTrustManagerParameters;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.ManagerFactoryParameters;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
Expand All @@ -37,14 +38,21 @@
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CRL;
import java.security.cert.CertPathBuilder;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXCertPathChecker;
import java.security.cert.PKIXRevocationChecker;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
Expand Down Expand Up @@ -81,6 +89,8 @@ public class SSLSupport {
private boolean trustAll = TransportConstants.DEFAULT_TRUST_ALL;
private String trustManagerFactoryPlugin = TransportConstants.DEFAULT_TRUST_MANAGER_FACTORY_PLUGIN;
private String keystoreAlias = TransportConstants.DEFAULT_KEYSTORE_ALIAS;
private String crcOptions = TransportConstants.DEFAULT_CRC_OPTIONS;
private String ocspResponderURL = TransportConstants.DEFAULT_OCSP_RESPONDER_URL;

public SSLSupport() {
}
Expand All @@ -98,6 +108,8 @@ public SSLSupport(final SSLContextConfig config) {
trustAll = config.isTrustAll();
trustManagerFactoryPlugin = config.getTrustManagerFactoryPlugin();
keystoreAlias = config.getKeystoreAlias();
crcOptions = config.getCrcOptions();
ocspResponderURL = config.getOcspResponderURL();
}

public String getKeystoreProvider() {
Expand Down Expand Up @@ -217,6 +229,24 @@ public SSLSupport setTrustManagerFactoryPlugin(String trustManagerFactoryPlugin)
return this;
}

public String getCrcOptions() {
return crcOptions;
}

public SSLSupport setCrcOptions(String crcOptions) {
this.crcOptions = crcOptions;
return this;
}

public String getOcspResponderURL() {
return ocspResponderURL;
}

public SSLSupport setOcspResponderURL(String ocspResponderURL) {
this.ocspResponderURL = ocspResponderURL;
return this;
}

public SSLContext createContext() throws Exception {
SSLContext context = SSLContext.getInstance("TLS");
KeyManager[] keyManagers = loadKeyManagers();
Expand Down Expand Up @@ -287,29 +317,122 @@ private TrustManagerFactory loadTrustManagerFactory() throws Exception {
} else {
TrustManagerFactory trustMgrFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore trustStore = SSLSupport.loadKeystore(truststoreProvider, truststoreType, truststorePath, truststorePassword);
boolean ocsp = Boolean.valueOf(Security.getProperty("ocsp.enable"));

boolean initialized = false;
if ((ocsp || crlPath != null) && TrustManagerFactory.getDefaultAlgorithm().equalsIgnoreCase("PKIX")) {
ManagerFactoryParameters managerFactoryParameters = null;
boolean ocsp = Boolean.parseBoolean(Security.getProperty("ocsp.enable"));
if ((ocsp || crlPath != null || crcOptions != null || ocspResponderURL != null) && checkPKIXTrustManagerFactory(trustMgrFactory)) {
PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(trustStore, new X509CertSelector());

if (crlPath != null) {
pkixParams.setRevocationEnabled(true);
Collection<? extends CRL> crlList = loadCRL();
if (crlList != null) {
pkixParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(crlList)));
}
}
trustMgrFactory.init(new CertPathTrustManagerParameters(pkixParams));
initialized = true;

if (crcOptions != null || ocspResponderURL != null) {
addCertPathCheckers(pkixParams);
}

managerFactoryParameters = new CertPathTrustManagerParameters(pkixParams);
}

if (!initialized) {
if (managerFactoryParameters != null) {
trustMgrFactory.init(managerFactoryParameters);
} else {
trustMgrFactory.init(trustStore);
}

return trustMgrFactory;
}
}

private boolean checkPKIXTrustManagerFactory(TrustManagerFactory trustMgrFactory) {
if (trustMgrFactory.getAlgorithm().equalsIgnoreCase("PKIX")) {
return true;
}

if (crlPath != null) {
throw new IllegalStateException("The crlPath parameter is not supported with the algorithm "
+ trustMgrFactory.getAlgorithm());
}

if (crcOptions != null) {
throw new IllegalStateException("The crcOptions parameter is not supported with the algorithm "
+ trustMgrFactory.getAlgorithm());
}

if (ocspResponderURL != null) {
throw new IllegalStateException("The ocspResponderURL parameter is not supported with the algorithm "
+ trustMgrFactory.getAlgorithm());
}

return false;
}

protected void addCertPathCheckers(PKIXBuilderParameters pkixParams) throws Exception {
CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("PKIX");
PKIXRevocationChecker revocationChecker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker();
if (crcOptions != null) {
revocationChecker.setOptions(loadRevocationOptions());
}
if (ocspResponderURL != null) {
revocationChecker.setOcspResponder(new java.net.URI(ocspResponderURL));
}
pkixParams.addCertPathChecker(revocationChecker);


// Add a certPathChecker to log soft fail exceptions caught by the revocation checker.
pkixParams.addCertPathChecker(new PKIXCertPathChecker() {
@Override
public void init(boolean forward) throws CertPathValidatorException {
}

@Override
public boolean isForwardCheckingSupported() {
return revocationChecker.isForwardCheckingSupported();
}

@Override
public Set<String> getSupportedExtensions() {
return revocationChecker.getSupportedExtensions();
}

@Override
public void check(Certificate cert, Collection<String> unresolvedCritExts) throws CertPathValidatorException {
List<CertPathValidatorException> softFailExceptions = revocationChecker.getSoftFailExceptions();

if (softFailExceptions != null) {
for (CertPathValidatorException e : softFailExceptions) {
// Filter soft failure exceptions related to cert.
// The check method may be invoked for all certificates in the path and the list of
// the soft failure exceptions is cleared only before the first certificate in the path.
if (e.getIndex() >= 0 && e.getCertPath().getCertificates().get(e.getIndex()).equals(cert)) {
String certSubject = null;
if (cert instanceof X509Certificate) {
certSubject = ((X509Certificate) cert).getSubjectX500Principal().getName();
}

ActiveMQClientLogger.LOGGER.softFailException(certSubject, e);
}
}
}
}
});
}

protected Set<PKIXRevocationChecker.Option> loadRevocationOptions() {
String[] revocationOptionNames = crcOptions.split(",");

Set<PKIXRevocationChecker.Option> revocationOptions = new HashSet<>();
for (String revocationOptionName : revocationOptionNames) {
revocationOptions.add(PKIXRevocationChecker.Option.valueOf(revocationOptionName));
}

return revocationOptions;
}

private TrustManager[] loadTrustManagers() throws Exception {
TrustManagerFactory trustManagerFactory = loadTrustManagerFactory();
if (trustManagerFactory == null) {
Expand Down
Loading