Skip to main content

TLS in Java for MQTT

Use TLS in Java for MQTT

Abstract

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.

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.

    Note

    Do not use a client certificate in a client program to connect to a FairCom server that is not configured with a certificate.

  1. Create an MqttClient object with the following parameters:

    MqttClient tlsClient = new MqttClient( mqttURI, clientID, new MemoryPersistence() )
    1. The broker address.

    2. clientID

    3. MemoryPersistence()

  2. Create an SSLContext object.

    1. Generate a Certificate class object from the CA certificate file using the following code:

      Certificate caCertificate = CertificateFactory.getInstance( "X.509" ).generateCertificate( new FileInputStream( caCertFilename ) );
    2. With the generated Certificate, generate a KeyStore class object using the following code:

      Certificate caCertificate = CertificateFactory.getInstance( "X.509" ).generateCertificate( new FileInputStream( caCertFilename ) );
    3. Build a TrustManager from the KeyStore using the following code:

      TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm() ); trustManagerFactory.init( keyStore );
    4. Create an SSLContext class object from the TrustManager using the following code:

      SSLContext sslContext = SSLContext.getInstance( "TLS" ); sslContext.init( null, trustManagerFactory.getTrustManagers(), null );
  3. Instantiate a new MqttConnectOptions, and apply the SSLContext to it using the following code:

    MqttConnectOptions connOpts = new MqttConnectOptions(); connOpts.setSocketFactory( Objects.requireNonNull( sslContext ).getSocketFactory() );
  4. With the MqttClient, connect to the broker using the connection options using the following code:

    tlsClient.connect( connOpts );
  5. Create an MqttMessage class object, and set the QoS using the following code:

    MqttMessage message = new MqttMessage( messageBody.getBytes() ); message.setQos( 1 );
  6. Publish the message to the broker using the following code:

    tlsClient.publish( topic, message );
  7. Disconnect from the broker using the following code:

    tlsClient.disconnect();
Example 1. Complete 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 hostname JohnDoePC, then the mqttURI variable should be set to ssl://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 );
	}
}


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;
}