MQTT is a lightweight and broadly used Internet protocol (see MQTT with lwIP and NXP FRDM-K64F Board). And probably the majority of IoT applications today are using Mosquitto as a server (or ‘broker’ in MQTT language). By default, Mosquitto uses a protocol without encryption. In Introduction to Security and TLS (Transport Layer Security), I covered the basics and needs for encryption. This article is about how to enable Mosquitto and clients to use the TLS protocol.
TLS Handshaking with certificates and keys
This article walks through the basic principles and settings to configure Mosquitto brokers and MQTT clients with the TLS (Transport Layer Security) protocol. TLS is the successor of SSL (Secure Sockets Layer) and is often used as a combination of TLS/SSL. To use TLS between the broker and the client, a set of keys and certificates has to be generated and deployed, along with configuration settings on the broker and the client.
In this article, I’m using the following set of software and tools:
- Broker: Mosquitto version 1.4.11 (build date 20/02/2017)
- Key and certificate generation: OpenSSL 1.0.2j 26 Sep 2016
- MQTT client: MQTT.fx 1.3.1
See MQTT with lwip and NXP FRDM-K64F Board about how to install the above tools. On Windows, OpenSSL gets installed with the Mosquitto installer.
The steps are:
- Create a CA key pair
- Create CA certificate and sign it with the private key from step 1
- Create the broker key pair
- Create a CA certificate sign request using the key from step 3
- Use the CA certificate from step 2 to sign the request from step 4
It is important that you run the openssl tool in administrator mode!
Running as administrator
On the broker, I need the following things:
- Certificate from the CA (Certificate Authority)
- Server certificate, signed by the CA with its private key
- Server Private Key for decrypting of the incoming messages
Create CA Key Pair
Run as administrator the following command:
openssl genrsa -des3 -out m2mqtt_ca.key 2048
Options used (see https://wiki.openssl.org/index.php/Manual:Genrsa(1)):
- genrsa: Generate an RSA private key
- -des3: Using DES3 cipher for the key generation
- -out: Specifies the output file name (.key)
- 2048: Number of bits for the private key
C:\tmp\ssl>openssl genrsa -des3 -out m2mqtt_ca.key 2048 Generating RSA private key, 2048 bit long modulus ...................................+++ ..+++ e is 65537 (0x10001) Enter pass phrase for m2mqtt_ca.key: Verifying - Enter pass phrase for m2mqtt_ca.key:
The passphrase is used to protect the private key. The generated private file m2mqtt_ca.key looks like this and has both the private and public key:
-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,F908DA05008A3132 alfCGiw0kcL7zfQvEBAE3gAs0o1IAbDtJpsJDok4Q9XlU+D8P8STQA0TFmhTCN1I <more text here> Lvme6Tl4b7kfFc3rvXf3tZwCVy8UOLzv9wbVdKwvwxnpm0ANKi8317vpbwb9Mrmy -----END RSA PRIVATE KEY-----
Create CA Certificate
Next, I’m creating a certificate for the CA using the key pair I created in step 1:
openssl req -new -x509 -days 3650 -key m2mqtt_ca.key -out m2mqtt_ca.crt
Options used (see https://wiki.openssl.org/index.php/Manual:Req(1)):
- req: Certificate request and certification utility.
- -new: Generate a new certificate. It will prompt the user for several input fields.
- -x509: Create a self-signed certificate.
- -days: Specify the number of days the certificate is valid.
- -key: Key file with the private key to be used for signing.
- -out: Specifies the file name for the certificate (.crt).
This generates a certificate certificate (m2mqtt_ca.crt). I have to provide an additional passphrase for the PEM (container for multiple items, see http://how2ssl.com/articles/working_with_pem_files/).
C:\tmp\ssl>openssl req -new -x509 -days 3650 -key m2mqtt_ca.key -out m2mqtt_ca.crt Enter pass phrase for m2mqtt_ca.key: You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:CH State or Province Name (full name) [Some-State]:Switzerland Locality Name (eg, city) :Lucerne Organization Name (eg, company) [Internet Widgits Pty Ltd]:HSLU Organizational Unit Name (eg, section) :T&A Common Name (e.g. server FQDN or YOUR name) :ErichStyger-PC Email Address :firstname.lastname@example.org
As a common name, I give the name of my host PC (which is acting as the CA for me). The generated certificate m2mqtt_ca.crt looks like this:
-----BEGIN CERTIFICATE----- MIID6DCCAtCgAwIBAgIJAP8FtRqBHYWxMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYD <some more text here> x9uEvaymIwyH7HNUOi9K3ycizDvCBSASPJ+XGHK/r6cPOybzNzTG6bLrg08= -----END CERTIFICATE-----
On Windows, I can use the Certificate viewer to inspect it:
Windows Certificate Viewer
Create a Mosquitto Broker Key Pair
Next, I’m creating a private key for the server (m2mqtt_srv.key) with:
openssl genrsa -out m2mqtt_srv.key 2048
Options used (see https://wiki.openssl.org/index.php/Manual:Genrsa(1)):
- genrsa: Generate an RSA private key.
- -out: Specifies the output file name (.key).
- 2048: Number of bits for the private key.
Note that I’m not using the -des3 option, as otherwise the key will be password protected, and I would have to enter this password when I start the broker. Not something I want.
C:\tmp\ssl>openssl genrsa -out m2mqtt_srv.key 2048 Generating RSA private key, 2048 bit long modulus ........................++++++ ..........++++++ e is 65537 (0x10001)
If you get a “unable to write ‘random state'” in the output, make sure you run the command prompt as Administrator!
The private key file looks like this:
-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA4PZ20QWql4IU0RFO6NCCqjQgWnXa3P8Coyy20tmc2bnfZBcY <more text here> ub3uwTWCLTbpHP8AueLJlTMWU/en88Ed4T2hXMRnzetmKWMsJ9XW3g== -----END RSA PRIVATE KEY-----
Create Certificate Request from CA
That key we need to be certified, so we create a certificate request for it, and the certificate needs to be signed by the CA:
openssl req -new -out m2mqtt_srv.csr -key m2mqtt_srv.key
Parameters used (see https://wiki.openssl.org/index.php/Manual:Req(1)):
- req: Certificate request and certification utility.
- -new: Create new request file file.
- -out: File name for the certificate signing request (.csr).
- -key: File name of the key to be certified.
C:\tmp\ssl>openssl req -new -out m2mqtt_srv.csr -key m2mqtt_srv.key You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:CH State or Province Name (full name) [Some-State]:Switzerland Locality Name (eg, city) :Lucerne Organization Name (eg, company) [Internet Widgits Pty Ltd]:HSLU Organizational Unit Name (eg, section) :T&A Common Name (e.g. server FQDN or YOUR name) :ErichStyger-PC Email Address :email@example.com Please enter the following 'extra' attributes to be sent with your certificate request A challenge password : An optional company name :
I’m using ‘ErichStyger-PC’ because this is the machine that will run the broker.
This creates the m2mqtt_srv.csr (Certificate sign request) which looks like this:
-----BEGIN CERTIFICATE REQUEST----- MIICzjCCAbYCAQAwgYgxCzAJBgNVBAYTAkNIMRQwEgYDVQQIDAtTd2l0emVybGFu <more text here> 4PwJlZU81GN+fLwR01iTT6MhwjbKNouPjtMsI30SpPZxhNIBrsSYdESD/Abp+g3j Bv0= -----END CERTIFICATE REQUEST-----
Verify and Sign the Certificate Request
The last step is to sign the server request through the CA to get the broker certificate:
openssl x509 -req -in m2mqtt_srv.csr -CA m2mqtt_ca.crt -CAkey m2mqtt_ca.key -CAcreateserial -out m2mqtt_srv.crt -days 3650
With the following options (see https://wiki.openssl.org/index.php/Manual:X509(1)):
- x509: Certificate display and signing utility.
- -req: A certificate request is expected as the input.
- -in: Input file for the certificate.
- -CA: Specifies the file to be signed.
- -CAkey: CA private key to sign the certificate with.
- -Cacreateserial: The serial number file gets created if it does not exist.
- -out: Output file name.
- -days: How long the certificate shall be valid.
C:\tmp\ssl>openssl x509 -req -in m2mqtt_srv.csr -CA m2mqtt_ca.crt -CAkey m2mqtt_ca.key -CAcreateserial -out m2mqtt_srv.crt -days 3650 Signature ok subject=/C=CH/ST=Switzerland/L=Lucerne/O=HSLU/OU=T&A/CN=ErichStyger-PC/emailAddressfirstname.lastname@example.org Getting CA Private Key Enter pass phrase for m2mqtt_ca.key:
The output file looks like this:
-----BEGIN CERTIFICATE----- MIIDBjCCAe4CCQDiXkSmKAt/BDANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJD <more lines here> OezkwBv5rqmBajfux+DasTjXg1Cfe7QcRdSYrnwLMYAIjkpT8LCGvQLxdxjyF8X3 2LWbh6UQSitcVw== -----END CERTIFICATE-----
This has created the following files:
m2mqtt_ca.crt : CA Certificate m2mqtt_ca.key : CA key pair (private, public) m2mqtt_ca.srl : CA serial number file m2mqtt_srv.crt : server certificate m2mqtt_srv.csr : certificate sign request, not needed any more m2mqtt_srv.key : server key pair
Inside the Mosquitto installation, create a folder (e.g. ‘certs’ if it does not already exist) and copy the following files we have created in the previous steps:
The ca.crt belongs to the client (needs to be copied there).
Using a text editor, open and edit <mosquitto>/mosquitto.conf:
Under Windows, make sure you have administrative rights to edit the configuration file. Best if you edit a copy outside of the c:/program files folder (where Mosquitto is installed by default) and copy the file into the program file folder.
Use port 8883 as default port:
# ================================================================= # Default listener # ================================================================= # IP address/hostname to bind the default listener to. If not # given, the default listener will not be bound to a specific # address and so will be accessible to all network interfaces. # bind_address ip-address/host name #bind_address # Port to use for the default listener. port 8883
Specify the certificate and key files:
# ----------------------------------------------------------------- # Certificate based SSL/TLS support # ----------------------------------------------------------------- # The following options can be used to enable SSL/TLS support for # this listener. Note that the recommended port for MQTT over TLS # is 8883, but this must be set manually. # # See also the mosquitto-tls man page. # At least one of cafile or capath must be defined. They both # define methods of accessing the PEM encoded Certificate # Authority certificates that have signed your server certificate # and that you wish to trust. # cafile defines the path to a file containing the CA certificates. # capath defines a directory that will be searched for files # containing the CA certificates. For capath to work correctly, the # certificate files must have ".crt" as the file ending and you must run # "c_rehash <path to capath>" each time you add/remove a certificate. #capath cafile C:\Program Files (x86)\mosquitto\certs\m2mqtt_ca.crt # Path to the PEM encoded server certificate. certfile C:\Program Files (x86)\mosquitto\certs\m2mqtt_srv.crt # Path to the PEM encoded keyfile. keyfile C:\Program Files (x86)\mosquitto\certs\m2mqtt_srv.key # This option defines the version of the TLS protocol to use for this listener. # The default value allows v1.2, v1.1 and v1.0, if they are all supported by # the version of openssl that the broker was compiled against. For openssl >= # 1.0.1 the valid values are tlsv1.2 tlsv1.1 and tlsv1. For openssl < 1.0.1 the # valid values are tlsv1. tls_version tlsv1
I launch my local Mosquitto broker with the -c option pointing to the modified configuration file:
mosquitto -c mosquitto.conf -v
This launches the broker listening on the secure port 8883:
Mosquitto listening on port 8883
Server Certificate for the Client
In the client (e.g. MQTT.fx), I have to load the certificate of the server:
Configured Server Certificate in MQTT Client
With this, I can connect to the broker in a secure way:
Client connected to Port 8883 to broker
Establishing a secure TLS connection to the Mosquitto broker requires key and certificate files. Creating all these files with the correct settings is not the easiest thing, but is rewarded with a secure way to communicate with the MQTT broker.
In a next article, I plan to write about how to use TLS with lwIP and the mbedTLS library on the NXP FRDM-K64F board.