How to configure HermesJMS to use a specific client certificate when connecting via SSL?

420 views Asked by At

I have a Spring Boot Application that I've created instantiates an instance of ActiveMqSslBroker. I am attempting to connect to this broker using HermesJMS as a client.

I've configured the connection factory in Hermes as follows:

  • Class: org.apache.activemq.ActiveMQSslConnectionFactory
  • brokerURL: ssl://localhost:61616
  • keyStore: /path/to/client-keystore-containing-client-cert.ks
  • keyStoreKeyPassword: *****
  • keyStoreType: PKCS12
  • trustStore: /path/to/trust-store-containing-broker-cert.ts
  • trustStorePassword: ****
  • trustStoreType: PKCS12

The broker is configured in my spring-boot application as follows:

  • SSL Connector:
    • brokerUrl: ssl://localhost:61616
    • KeyManagers:
      • returned from KeyManagerFactory.getKeyManagers()
        • KeyStore: /path/to/key-store-containing-broker-cert.ks
    • TrustManagers:
      • returned from TrustManagerFactory.getTrustManagers()
        • TrustStore: /path/to/trust-store-containing-client-cert.ks

The broker is rejecting the connection requests from Hermes with the following error:

javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown

So apparently HermesJMS is not sending the client certificate that is contained in its configured keyStore. Does the key have to have a specific alias to be picked up and used by Hermes? Is there a property I can set to specify the alias from the keyStore to use?

1

There are 1 answers

0
dsharp On

Turns out it was user error. I had a couple of different session configured, and while flipping back and forth between my IDE and Hermes, I somehow ended up testing on a session that was using the wrong connection factory.

After switching to the right session, things started to work.

For completeness here is how I got things working:

In my Spring-Boot application I defined my BrokerService bean as follows:

@Bean
public BrokerService broker(
    @Value("${spring.activemq.broker-url}") String brokerUrl,
    @Qualifier("brokerTrustManagerFactory") TrustManagerFactory trustManagerFactory,
    @Qualifier("brokerKeyManagerFactory") KeyManagerFactory keyManagerFactory,
    @Qualifier("secureRandom") SecureRandom secureRandom
){
    SslBrokerService brokerService = new SslBrokerService();
    brokerService.addSslConnector(
        brokerUrl,
        keyManagerFactory.getKeyManagers(),
        trustManagerFactory.getTrustManagers(),
        secureRandom
    );
    return brokerService;
}

Here is how a connection factory could be configured in a client application:

@Bean
ConnectionFactory connectionFactory(
    @Value("${spring.activemq.broker-url}") String brokerUrl,
    @Value("${spring.activemq.trustStorePath}") String trustStorePath,
    @Value("${spring.activemq.trustStorePass}") String trustStorePass,
    @Value("${spring.activemq.keyStorePath}") String keyStorePath,
    @Value("${spring.activemq.keyStorePass}") String keyStorePass,
    @Value("${client.key.pass}") String clientKeyPass
) {
    ActiveMQSslConnectionFactory connectionFactory = 
        new ActiveMQSslConnectionFactory(brokerUrl);
    connectionFactory.setTrustStore(trustStorePath);
    connectionFactory.setTrustStorePassword(trustStorePass);
    connectionFactory.setTrustStoreType("PKCS12");
    connectionFactory.setKeyStore(keyStorePath);
    connectionFactory.setKeyStorePassword(keyStorePass);
    connectionFactory.setKeyStoreKeyPassword(clientKeyPass);
    connectionFactory.setKeyStoreType("PKCS12");
    return connectionFactory;
}

Hopefully someone will find this answer useful. Please note, the "spring.activemq.*" property names are not official property names recognized by Spring-Boot. They're just names that seemed to be used by a lot of the spring-boot activemq tutorials on the web.

Thanks, Dave