Skip to content

Commit 17b25e8

Browse files
committed
ARTEMIS-5778 Improve OCSP revocation checker support
Add the parameters crcOptions and ocspResponderURL to customize the options and responder URL used by the OCSP revocation checker.
1 parent d31be17 commit 17b25e8

File tree

21 files changed

+867
-31
lines changed

21 files changed

+867
-31
lines changed

artemis-core-client/src/main/java/org/apache/activemq/artemis/core/client/ActiveMQClientLogger.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,9 @@ public interface ActiveMQClientLogger {
260260
@LogMessage(id = 212080, value = "Using legacy SSL store provider value: {}. Please use either 'keyStoreType' or 'trustStoreType' instead as appropriate.", level = LogMessage.Level.WARN)
261261
void oldStoreProvider(String value);
262262

263+
@LogMessage(id = 212081, value = "Soft failure checking the certificate [{}]: {}", level = LogMessage.Level.WARN)
264+
void softFailException(String certSubject, Exception e);
265+
263266
@LogMessage(id = 214000, value = "Failed to call onMessage", level = LogMessage.Level.ERROR)
264267
void onMessageError(Throwable e);
265268

artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyConnector.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,10 @@ public class NettyConnector extends AbstractConnector {
257257

258258
private String crlPath;
259259

260+
private String crcOptions;
261+
262+
private String ocspResponderURL;
263+
260264
private String enabledCipherSuites;
261265

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

453457
trustManagerFactoryPlugin = ConfigurationHelper.getStringProperty(TransportConstants.TRUST_MANAGER_FACTORY_PLUGIN_PROP_NAME, TransportConstants.DEFAULT_TRUST_MANAGER_FACTORY_PLUGIN, configuration);
458+
459+
crcOptions = ConfigurationHelper.getStringProperty(TransportConstants.CRC_OPTIONS_PROP_NAME, TransportConstants.DEFAULT_CRC_OPTIONS, configuration);
460+
461+
ocspResponderURL = ConfigurationHelper.getStringProperty(TransportConstants.OCSP_RESPONDER_URL_PROP_NAME, TransportConstants.DEFAULT_OCSP_RESPONDER_URL, configuration);
454462
} else {
455463
keyStoreProvider = TransportConstants.DEFAULT_KEYSTORE_PROVIDER;
456464
keyStoreType = TransportConstants.DEFAULT_KEYSTORE_TYPE;
457465
keyStorePath = TransportConstants.DEFAULT_KEYSTORE_PATH;
458466
keyStorePassword = TransportConstants.DEFAULT_KEYSTORE_PASSWORD;
459467
keyStoreAlias = TransportConstants.DEFAULT_KEYSTORE_ALIAS;
468+
crcOptions = TransportConstants.DEFAULT_CRC_OPTIONS;
469+
ocspResponderURL = TransportConstants.DEFAULT_OCSP_RESPONDER_URL;
460470
passwordCodecClass = TransportConstants.DEFAULT_PASSWORD_CODEC_CLASS;
461471
trustStoreProvider = TransportConstants.DEFAULT_TRUSTSTORE_PROVIDER;
462472
trustStoreType = TransportConstants.DEFAULT_TRUSTSTORE_TYPE;
@@ -522,6 +532,14 @@ private String getHttpUpgradeInfo() {
522532
return ", activemqServerName=" + serverName + ", httpUpgradeEndpoint=" + acceptor;
523533
}
524534

535+
public String getCrcOptions() {
536+
return crcOptions;
537+
}
538+
539+
public String getOcspResponderURL() {
540+
return ocspResponderURL;
541+
}
542+
525543
@Override
526544
public synchronized void start() {
527545
if (channelClazz != null) {
@@ -688,6 +706,8 @@ public void initChannel(Channel channel) throws Exception {
688706
.trustManagerFactoryPlugin(trustManagerFactoryPlugin)
689707
.crlPath(crlPath)
690708
.trustAll(trustAll)
709+
.crcOptions(crcOptions)
710+
.ocspResponderURL(ocspResponderURL)
691711
.build();
692712

693713
final SSLEngine engine;

artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/TransportConstants.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,10 @@ public class TransportConstants {
202202

203203
public static final String SOCKS_REMOTE_DNS_PROP_NAME = "socksRemoteDNS";
204204

205+
public static final String CRC_OPTIONS_PROP_NAME = "crcOptions";
206+
207+
public static final String OCSP_RESPONDER_URL_PROP_NAME = "ocspResponderURL";
208+
205209
public static final String AUTO_START = "autoStart";
206210

207211
public static final boolean DEFAULT_AUTO_START = true;
@@ -403,6 +407,10 @@ public class TransportConstants {
403407

404408
public static final String DEFAULT_ROUTER = null;
405409

410+
public static final String DEFAULT_CRC_OPTIONS = null;
411+
412+
public static final String DEFAULT_OCSP_RESPONDER_URL = null;
413+
406414
private static int parseDefaultVariable(String variableName, int defaultValue) {
407415
try {
408416
String variable = System.getProperty(TransportConstants.class.getName() + "." + variableName);
@@ -484,6 +492,8 @@ private static int parseDefaultVariable(String variableName, int defaultValue) {
484492
allowableAcceptorKeys.add(TransportConstants.AUTO_START);
485493
allowableAcceptorKeys.add(TransportConstants.ROUTER);
486494
allowableAcceptorKeys.add(TransportConstants.PROXY_PROTOCOL_ENABLED_PROP_NAME);
495+
allowableAcceptorKeys.add(TransportConstants.CRC_OPTIONS_PROP_NAME);
496+
allowableAcceptorKeys.add(TransportConstants.OCSP_RESPONDER_URL_PROP_NAME);
487497

488498
ALLOWABLE_ACCEPTOR_KEYS = Collections.unmodifiableSet(allowableAcceptorKeys);
489499

@@ -545,6 +555,8 @@ private static int parseDefaultVariable(String variableName, int defaultValue) {
545555
allowableConnectorKeys.add(TransportConstants.TRUST_MANAGER_FACTORY_PLUGIN_PROP_NAME);
546556
allowableConnectorKeys.add(TransportConstants.HANDSHAKE_TIMEOUT);
547557
allowableConnectorKeys.add(TransportConstants.CRL_PATH_PROP_NAME);
558+
allowableConnectorKeys.add(TransportConstants.CRC_OPTIONS_PROP_NAME);
559+
allowableConnectorKeys.add(TransportConstants.OCSP_RESPONDER_URL_PROP_NAME);
548560

549561
ALLOWABLE_CONNECTOR_KEYS = Collections.unmodifiableSet(allowableConnectorKeys);
550562

artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/ssl/SSLSupport.java

Lines changed: 129 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import javax.net.ssl.CertPathTrustManagerParameters;
2020
import javax.net.ssl.KeyManager;
2121
import javax.net.ssl.KeyManagerFactory;
22+
import javax.net.ssl.ManagerFactoryParameters;
2223
import javax.net.ssl.SSLContext;
2324
import javax.net.ssl.TrustManager;
2425
import javax.net.ssl.TrustManagerFactory;
@@ -37,14 +38,21 @@
3738
import java.security.Security;
3839
import java.security.UnrecoverableKeyException;
3940
import java.security.cert.CRL;
41+
import java.security.cert.CertPathBuilder;
42+
import java.security.cert.CertPathValidatorException;
4043
import java.security.cert.CertStore;
4144
import java.security.cert.Certificate;
4245
import java.security.cert.CertificateFactory;
4346
import java.security.cert.CollectionCertStoreParameters;
4447
import java.security.cert.PKIXBuilderParameters;
48+
import java.security.cert.PKIXCertPathChecker;
49+
import java.security.cert.PKIXRevocationChecker;
4550
import java.security.cert.X509CertSelector;
4651
import java.security.cert.X509Certificate;
4752
import java.util.Collection;
53+
import java.util.HashSet;
54+
import java.util.List;
55+
import java.util.Set;
4856

4957
import io.netty.handler.ssl.SslContext;
5058
import io.netty.handler.ssl.SslContextBuilder;
@@ -81,6 +89,8 @@ public class SSLSupport {
8189
private boolean trustAll = TransportConstants.DEFAULT_TRUST_ALL;
8290
private String trustManagerFactoryPlugin = TransportConstants.DEFAULT_TRUST_MANAGER_FACTORY_PLUGIN;
8391
private String keystoreAlias = TransportConstants.DEFAULT_KEYSTORE_ALIAS;
92+
private String crcOptions = TransportConstants.DEFAULT_CRC_OPTIONS;
93+
private String ocspResponderURL = TransportConstants.DEFAULT_OCSP_RESPONDER_URL;
8494

8595
public SSLSupport() {
8696
}
@@ -98,6 +108,8 @@ public SSLSupport(final SSLContextConfig config) {
98108
trustAll = config.isTrustAll();
99109
trustManagerFactoryPlugin = config.getTrustManagerFactoryPlugin();
100110
keystoreAlias = config.getKeystoreAlias();
111+
crcOptions = config.getCrcOptions();
112+
ocspResponderURL = config.getOcspResponderURL();
101113
}
102114

103115
public String getKeystoreProvider() {
@@ -217,6 +229,24 @@ public SSLSupport setTrustManagerFactoryPlugin(String trustManagerFactoryPlugin)
217229
return this;
218230
}
219231

232+
public String getCrcOptions() {
233+
return crcOptions;
234+
}
235+
236+
public SSLSupport setCrcOptions(String crcOptions) {
237+
this.crcOptions = crcOptions;
238+
return this;
239+
}
240+
241+
public String getOcspResponderURL() {
242+
return ocspResponderURL;
243+
}
244+
245+
public SSLSupport setOcspResponderURL(String ocspResponderURL) {
246+
this.ocspResponderURL = ocspResponderURL;
247+
return this;
248+
}
249+
220250
public SSLContext createContext() throws Exception {
221251
SSLContext context = SSLContext.getInstance("TLS");
222252
KeyManager[] keyManagers = loadKeyManagers();
@@ -287,29 +317,122 @@ private TrustManagerFactory loadTrustManagerFactory() throws Exception {
287317
} else {
288318
TrustManagerFactory trustMgrFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
289319
KeyStore trustStore = SSLSupport.loadKeystore(truststoreProvider, truststoreType, truststorePath, truststorePassword);
290-
boolean ocsp = Boolean.valueOf(Security.getProperty("ocsp.enable"));
291320

292-
boolean initialized = false;
293-
if ((ocsp || crlPath != null) && TrustManagerFactory.getDefaultAlgorithm().equalsIgnoreCase("PKIX")) {
321+
ManagerFactoryParameters managerFactoryParameters = null;
322+
boolean ocsp = Boolean.parseBoolean(Security.getProperty("ocsp.enable"));
323+
if ((ocsp || crlPath != null || crcOptions != null || ocspResponderURL != null) && checkPKIXTrustManagerFactory(trustMgrFactory)) {
294324
PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(trustStore, new X509CertSelector());
325+
295326
if (crlPath != null) {
296327
pkixParams.setRevocationEnabled(true);
297328
Collection<? extends CRL> crlList = loadCRL();
298329
if (crlList != null) {
299330
pkixParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(crlList)));
300331
}
301332
}
302-
trustMgrFactory.init(new CertPathTrustManagerParameters(pkixParams));
303-
initialized = true;
333+
334+
if (crcOptions != null || ocspResponderURL != null) {
335+
addCertPathCheckers(pkixParams);
336+
}
337+
338+
managerFactoryParameters = new CertPathTrustManagerParameters(pkixParams);
304339
}
305340

306-
if (!initialized) {
341+
if (managerFactoryParameters != null) {
342+
trustMgrFactory.init(managerFactoryParameters);
343+
} else {
307344
trustMgrFactory.init(trustStore);
308345
}
346+
309347
return trustMgrFactory;
310348
}
311349
}
312350

351+
private boolean checkPKIXTrustManagerFactory(TrustManagerFactory trustMgrFactory) {
352+
if (trustMgrFactory.getAlgorithm().equalsIgnoreCase("PKIX")) {
353+
return true;
354+
}
355+
356+
if (crlPath != null) {
357+
throw new IllegalStateException("The crlPath parameter is not supported with the algorithm "
358+
+ trustMgrFactory.getAlgorithm());
359+
}
360+
361+
if (crcOptions != null) {
362+
throw new IllegalStateException("The crcOptions parameter is not supported with the algorithm "
363+
+ trustMgrFactory.getAlgorithm());
364+
}
365+
366+
if (ocspResponderURL != null) {
367+
throw new IllegalStateException("The ocspResponderURL parameter is not supported with the algorithm "
368+
+ trustMgrFactory.getAlgorithm());
369+
}
370+
371+
return false;
372+
}
373+
374+
protected void addCertPathCheckers(PKIXBuilderParameters pkixParams) throws Exception {
375+
CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("PKIX");
376+
PKIXRevocationChecker revocationChecker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker();
377+
if (crcOptions != null) {
378+
revocationChecker.setOptions(loadRevocationOptions());
379+
}
380+
if (ocspResponderURL != null) {
381+
revocationChecker.setOcspResponder(new java.net.URI(ocspResponderURL));
382+
}
383+
pkixParams.addCertPathChecker(revocationChecker);
384+
385+
386+
// Add a certPathChecker to log soft fail exceptions caught by the revocation checker.
387+
pkixParams.addCertPathChecker(new PKIXCertPathChecker() {
388+
@Override
389+
public void init(boolean forward) throws CertPathValidatorException {
390+
}
391+
392+
@Override
393+
public boolean isForwardCheckingSupported() {
394+
return revocationChecker.isForwardCheckingSupported();
395+
}
396+
397+
@Override
398+
public Set<String> getSupportedExtensions() {
399+
return revocationChecker.getSupportedExtensions();
400+
}
401+
402+
@Override
403+
public void check(Certificate cert, Collection<String> unresolvedCritExts) throws CertPathValidatorException {
404+
List<CertPathValidatorException> softFailExceptions = revocationChecker.getSoftFailExceptions();
405+
406+
if (softFailExceptions != null) {
407+
for (CertPathValidatorException e : softFailExceptions) {
408+
// Filter soft failure exceptions related to cert.
409+
// The check method may be invoked for all certificates in the path and the list of
410+
// the soft failure exceptions is cleared only before the first certificate in the path.
411+
if (e.getIndex() >= 0 && e.getCertPath().getCertificates().get(e.getIndex()).equals(cert)) {
412+
String certSubject = null;
413+
if (cert instanceof X509Certificate) {
414+
certSubject = ((X509Certificate) cert).getSubjectX500Principal().getName();
415+
}
416+
417+
ActiveMQClientLogger.LOGGER.softFailException(certSubject, e);
418+
}
419+
}
420+
}
421+
}
422+
});
423+
}
424+
425+
protected Set<PKIXRevocationChecker.Option> loadRevocationOptions() {
426+
String[] revocationOptionNames = crcOptions.split(",");
427+
428+
Set<PKIXRevocationChecker.Option> revocationOptions = new HashSet<>();
429+
for (String revocationOptionName : revocationOptionNames) {
430+
revocationOptions.add(PKIXRevocationChecker.Option.valueOf(revocationOptionName));
431+
}
432+
433+
return revocationOptions;
434+
}
435+
313436
private TrustManager[] loadTrustManagers() throws Exception {
314437
TrustManagerFactory trustManagerFactory = loadTrustManagerFactory();
315438
if (trustManagerFactory == null) {

0 commit comments

Comments
 (0)