Community Edition
ThingsBoard Documentation
Cloud Professional Edition Community Edition Edge IoT Gateway License Server Trendz Analytics
Try it now Pricing
Documentation > Security > X.509 Certificate based authentication
Getting Started
Guides Installation Architecture API FAQ

X.509 Certificate Based Authentication

X.509 Certificate Based Authentication is used in Two-Way SSL connection. In this case, the certificate itself is the client’s ID, thus, Access Token is no longer needed.

Instructions below will describe how to generate a client-side certificate and connect to the server that is running MQTT over SSL. You will need to have the public key of the server certificate in PEM format. See following instructions for more details on server-side configuration.

Update keygen.properties file

Open the keygen.properties file, and update the values if needed:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
DOMAIN_SUFFIX="localhost"
ORGANIZATIONAL_UNIT=ThingsBoard
ORGANIZATION=ThingsBoard
CITY="San Francisco"
STATE_OR_PROVINCE=CA
TWO_LETTER_COUNTRY_CODE=US

SERVER_KEYSTORE_PASSWORD=server_ks_password
SERVER_KEY_PASSWORD=server_key_password

SERVER_KEY_ALIAS="serveralias"
SERVER_FILE_PREFIX="mqttserver"
SERVER_KEYSTORE_DIR="/etc/thingsboard/conf/"

CLIENT_KEYSTORE_PASSWORD=password
CLIENT_KEY_PASSWORD=password

CLIENT_KEY_ALIAS="clientalias"
CLIENT_FILE_PREFIX="mqttclient"
CLIENT_KEY_ALG="RSA"
CLIENT_KEY_SIZE="2048"

Run Client keygen script

Download and launch the client.keygen.sh script.

1
2
chmod +x client.keygen.sh
./client.keygen.sh

The script outputs the following files:

  • CLIENT_FILE_PREFIX.jks - Java Keystore file with the server certificate imported
  • CLIENT_FILE_PREFIX.nopass.pem - Client certificate file in PEM format to be used by non-java client
  • CLIENT_FILE_PREFIX.pub.pem - Client public key

Provision Client Public Key as Device Credentials

Go to ThingsBoard Web UI -> Devices -> Your Device -> Device Credentials. Select X.509 Certificate device credentials, insert the contents of CLIENT_FILE_PREFIX.pub.pem file and click save. Alternatively, the same can be done through the REST API.

Run Two-Way MQTT SSL Python Client

Download Python client example two-way-ssl-mqtt-client.py.

Note Script uses 8883 MQTT port and requires paho-mqtt library that you can install using the following command: pip3 install paho-mqtt

Run the script and follow steps in console:

1
python3 two-way-ssl-mqtt-client.py

If everything was configured correctly, the output should be like:

1
2
3
Connected with result code 0
Topic: v1/devices/me/attributes/response/1
Message: {}

To run Java client, import CLIENT_FILE_PREFIX.jks file as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import com.google.common.io.Resources;
import org.eclipse.paho.client.mqttv3.*;

import javax.net.ssl.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.*;
import java.security.cert.CertificateException;

public class MqttSslClient {

    private static final String MQTT_URL = "ssl://localhost:8883";

    private static final String clientId = "MQTT_SSL_JAVA_CLIENT";
    private static final String keyStoreFile = "mqttclient.jks";
    private static final String JKS="JKS";
    private static final String TLS="TLS";
    private static final String CLIENT_KEYSTORE_PASSWORD = "password";
    private static final String CLIENT_KEY_PASSWORD = "password";

    public static void main(String[] args) {

        try {

            URL ksUrl = Resources.getResource(keyStoreFile);
            File ksFile = new File(ksUrl.toURI());
            URL tsUrl = Resources.getResource(keyStoreFile);
            File tsFile = new File(tsUrl.toURI());

            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

            KeyStore trustStore = KeyStore.getInstance(JKS);
            trustStore.load(new FileInputStream(tsFile), CLIENT_KEYSTORE_PASSWORD.toCharArray());
            tmf.init(trustStore);
            KeyStore ks = KeyStore.getInstance(JKS);

            ks.load(new FileInputStream(ksFile), CLIENT_KEYSTORE_PASSWORD.toCharArray());
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(ks, CLIENT_KEY_PASSWORD.toCharArray());

            KeyManager[] km = kmf.getKeyManagers();
            TrustManager[] tm = tmf.getTrustManagers();
            SSLContext sslContext = SSLContext.getInstance(TLS);
            sslContext.init(km, tm, null);

            MqttConnectOptions options = new MqttConnectOptions();
            options.setSocketFactory(sslContext.getSocketFactory());
            MqttAsyncClient client = new MqttAsyncClient(MQTT_URL, clientId);
            client.connect(options);
            Thread.sleep(3000);
            MqttMessage message = new MqttMessage();
            message.setPayload("{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4}".getBytes());
            client.publish("v1/devices/me/telemetry", message);
            client.disconnect();
            System.out.println("Disconnected");
            System.exit(0);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}