TLS in Java for MQTT
Use TLS in Java for MQTT
Use TLS in Java for MQTT
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.
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.
Note
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
MqttClient
object with the following parameters:MqttClient tlsClient = new MqttClient( mqttURI, clientID, new MemoryPersistence() )
The broker address.
clientID
MemoryPersistence()
Create an
SSLContext
object.Generate a
Certificate
class 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 aKeyStore
class object using the following code:Certificate caCertificate = CertificateFactory.getInstance( "X.509" ).generateCertificate( new FileInputStream( caCertFilename ) );
Build a
TrustManager
from theKeyStore
using the following code:TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm() ); trustManagerFactory.init( keyStore );
Create an
SSLContext
class object from theTrustManager
using the following code:SSLContext sslContext = SSLContext.getInstance( "TLS" ); sslContext.init( null, trustManagerFactory.getTrustManagers(), null );
Instantiate a new
MqttConnectOptions
, and apply theSSLContext
to 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
MqttMessage
class 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();
main()
Note
The address used for the
mqttURI
variable must match the Common Name in the broker certificate — for example, if the broker certificate Common Name is set to hostnameJohnDoePC
, then themqttURI
variable should be set tossl://JohnDoePC:8883
or 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 ); } }
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; }