0

I used this link to create the self signed root CA certificate and the server key pair

Used this link to generate the client key pair using the previously generated root certificate

Although the links are for setting up SSL for MosquittoMQ and my use case is for ActiveMQ, I believe the certificate generation procedure remains the same for either case.

The clients I'm using are Java clients. The broker keystore contains the root certificate and server public and private key bundled into a PKCS12 file, as required by the keystore, and the broker truststore contains the public key of the client. The client keystore contains the client public and private key bundled into a PKCS12 file and the client truststore contains the root certificate. The Java clients use port 61714 to connect to the broker. With above configuration of keystores and truststores I get the null cert chain exception. Could someone please tell me if this is the right way to configure the key and trust stores? Should the root certificate and server certificate be chained instead of being present separately within the broker keystore? I'm fairly new to this and am a bit lost.

The transport connector configuration of the ActiveMQ broker is shown below

    <managementContext>
            <managementContext createConnector="false"/>
</managementContext>
<sslContext> 
            <sslContext keyStore="file:${activemq.base}/conf/broker.ks"
              keyStorePassword="changeit" trustStore="file:${activemq.base}/conf/broker.ts"
              trustStorePassword="changeit"/> 
</sslContext>
<transportConnectors>
        <!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->
        <transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&amp;wireFormat.maxInactivityDuration=300000&amp;wireFormat.maxFrameSize=104857600&amp;jms.messagePrioritySupported=false"/>
        <transportConnector name="ssl" uri="ssl://0.0.0.0:61714?trace=true&amp;needClientAuth=true&amp;transport.enabledProtocols=TLSv1.2"/>
        <transportConnector name="amqp" uri="amqp://0.0.0.0:5672?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
        <transportConnector name="stomp" uri="stomp://0.0.0.0:61613?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
        <transportConnector name="mqtt" uri="mqtt://0.0.0.0:1883?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
        <transportConnector name="mqtt+ssl" uri="mqtt+ssl://0.0.0.0:8883?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
        <transportConnector name="ws" uri="ws://0.0.0.0:61614?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
</transportConnectors>

application.properties file on the Java client

# Embedded ActiveMQ Configuration
spring.activemq.in-memory=false
spring.activemq.pool.enabled=false
activemq.broker-url=tcp://localhost:61616
activemq.ssl-url=ssl://localhost:61714


# Spring JMS Settings
#spring.jms.pub-sub-domain=true

# Truststore used by client.
JMS_BROKER_TRUSTSTORE=E:\\apacheActiveMQ\\apache-activemq-5.13.0\\conf\\client.ts
JMS_BROKER_TRUSTSTORE_TYPE=JKS
JMS_BROKER_TRUSTSTORE_PASSWORD=changeit
# Keystore used by client.
JMS_BROKER_KEYSTORE=E:\\apacheActiveMQ\\apache-activemq- 5.13.0\\conf\\client.ks
JMS_BROKER_KEYSTORE_TYPE=JKS
JMS_BROKER_KEYSTORE_PASSWORD=changeit

File that deals with configuring the ActiveMQ connection factory on the Java client

@Bean
public ActiveMQSslConnectionFactory activeMQSslConnectionFactory() {
    ActiveMQSslConnectionFactory connectionFactory = new ActiveMQSslConnectionFactory(sslUrl);
    try {
        connectionFactory.setTrustStore(pathToTrustStore);
        connectionFactory.setTrustStorePassword(truststorePassword);
        connectionFactory.setKeyStore(pathToKeystore);
        connectionFactory.setKeyStorePassword(keystorePassword);
    } catch (Exception e) {
        System.out.println("Error");
    }
    return connectionFactory;
}

/**
 * Initialise {@link JmsTemplate} as required
 */
@Bean
public JmsTemplate jmsTemplate() {
    JmsTemplate jmsTemplate = new JmsTemplate();
    jmsTemplate.setConnectionFactory(activeMQSslConnectionFactory());
    jmsTemplate.setExplicitQosEnabled(true);

    //setting PuSubDomain to true configures JmsTemplate to work with topics instead of queues
    jmsTemplate.setPubSubDomain(true);
    jmsTemplate.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
    return jmsTemplate;
}

/**
 * Initialise {@link DefaultJmsListenerContainerFactory} as required
 */
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setConnectionFactory(activeMQSslConnectionFactory());
    //setting PuSubDomain to true configures the DefaultJmsListenerContainerFactory to work with topics instead of queues
    factory.setPubSubDomain(true);
    return factory;
}

1 Answers1

1

Answering my own question. Below is the mapping of the keystore/truststore and its contents

  • broker keystore : server key pair bundled into a PKCS12 file
  • broker truststore : root certificate
  • client keystore : client key pair bundled into a PKCS12 file
  • client truststore : root certificate

This is the correct configuration and things are working fine now. Not entirely sure why there's so little out there about configuring certificates for MQTT. I looked at a bunch of HTTPS examples and learnt that the certificates must be added into the keystores and truststores as shown above.