This tutorial shows how to implement TLS using the Paho Java library to secure an MQTT connection. This configuration loads the certificate from the file system at runtime.
Prerequisites
- Ensure you have properly enabled TLS and created and configured TLS certificates. See Secure MQTT with certificates.
- You must create a separate server certificate for each computer that runs a FairCom server. Each FairCom server must be configured to use the appropriate server certificate for the computer on which it runs
- Each user must have a unique client certificate. A client certificate allows a client program to identify itself to a FairCom server. Each program that wants to use a certificate must be configured to send the certificate to the server.
Do not use a client certificate in a client program to connect to a FairCom server that is not configured with a certificate.
- Create an
MqttClientobject with the following parameters:
MqttClient tlsClient = new MqttClient( mqttURI, clientID, new MemoryPersistence() )
- The broker address.
clientIDMemoryPersistence()
- Create an
SSLContextobject.
- Generate a
Certificateclass object from the CA certificate file using the following code:
Certificate caCertificate = CertificateFactory.getInstance( "X.509" ).generateCertificate( new FileInputStream( caCertFilename ) );
- With the generated
Certificate, generate aKeyStoreclass object using the following code:
Certificate caCertificate = CertificateFactory.getInstance( "X.509" ).generateCertificate( new FileInputStream( caCertFilename ) );
- Build a
TrustManagerfrom theKeyStoreusing the following code:
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm() ); trustManagerFactory.init( keyStore );
- Create an
SSLContextclass object from theTrustManagerusing the following code:
SSLContext sslContext = SSLContext.getInstance( "TLS" ); sslContext.init( null, trustManagerFactory.getTrustManagers(), null );
- Instantiate a new
MqttConnectOptions, and apply theSSLContextto it using the following code:
MqttConnectOptions connOpts = new MqttConnectOptions(); connOpts.setSocketFactory( Objects.requireNonNull( sslContext ).getSocketFactory() );
- With the
MqttClient, connect to the broker using the connection options using the following code:
tlsClient.connect( connOpts );
- Create an
MqttMessageclass object, and set the QoS using the following code:
MqttMessage message = new MqttMessage( messageBody.getBytes() ); message.setQos( 1 );
- Publish the message to the broker using the following code:
tlsClient.publish( topic, message );
- Disconnect from the broker using the following code:
tlsClient.disconnect();
Example 1. Complete main()
- The address used for the
mqttURIvariable must match the Common Name in the broker certificate — for example, if the broker certificate Common Name is set to hostnameJohnDoePC, then themqttURIvariable should be set tossl://JohnDoePC:8883or the code will throw an exception:
javax.net.ssl.SSLHandshakeException: No name matching localhost found
- Configuring the Edge broker to use the CA certificate is not necessary. However, if the Edge broker is configured to use the CA certificate, a client certificate and key must be added to the SSLContext.
public static void main( String[] args )
{
String mqttURI = "ssl://localhost:8883";
String clientID = "JavaMQTTS1";
String caCertificate = "C:/Certificates/ca.crt";
String topic = "test/JavaMqttTlsTest";
String messageBody = "Java MQTTS test";
// Create a client using the URI, client ID, and a simple MemoryPersistence object.
try( MqttClient tlsClient = new MqttClient( mqttURI, clientID, new MemoryPersistence() ) )
{
// Get an SSLContext class object to secure the connection.
SSLContext sslContext = getSslContextFromCertificate( caCertificate );
// Apply the SSLContext to the connection options.
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setSocketFactory( Objects.requireNonNull( sslContext ).getSocketFactory() );
// Connect to the broker with the secure connection options.
tlsClient.connect( connOpts );
// Prepare a message to send.
MqttMessage message = new MqttMessage( messageBody.getBytes() );
message.setQos( 1 );
// Publish a simple message.
tlsClient.publish( topic, message );
System.out.println( "The message has been published." );
// Disconnect from the broker.
tlsClient.disconnect();
}
catch( MqttException mqttException )
{
printException( Thread.currentThread().getStackTrace()[1].getMethodName(), mqttException );
}
}
Example 2. Complete getSslContextFromCertificate()
private static SSLContext getSslContextFromCertificate( String caCertFilename )
{
try
{
Certificate caCertificate = CertificateFactory.getInstance( "X.509" ).generateCertificate( new FileInputStream( caCertFilename ) );
KeyStore keyStore = KeyStore.getInstance( KeyStore.getDefaultType() );
keyStore.load( null, null );
keyStore.setCertificateEntry( String.valueOf( caCertificate.hashCode() ), caCertificate );
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm() );
trustManagerFactory.init( keyStore );
SSLContext sslContext = SSLContext.getInstance( "TLS" );
sslContext.init( null, trustManagerFactory.getTrustManagers(), null );
return sslContext;
}
catch( CertificateException | KeyStoreException | NoSuchAlgorithmException | KeyManagementException | IOException certificateException )
{
printException( Thread.currentThread().getStackTrace()[1].getMethodName(), certificateException );
}
return null;
}