Enable Secure Communication with TLS and the Mosquitto Broker

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 server (or ‘broker’ in MQTT language). By default, Mosquitto is using a protocol without encryption. In “Introduction to Security and TLS (Transport Layer Security)” I have 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

TLS Handshaking with certificates and keys

Outline

This article walks though the basic principles and settings how to configure Mosquitto broker and MQTT client with the TLS (Transport Layer Security) protocol. TLS is the successor of SSL (Secure Sockets Layer), and is often used as 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 Mosquitto installer.

The steps are:

  1. Create a CA key pair
  2. Create CA certificate and sign it with the private key from step 1
  3. Create the broker key pair
  4. Create a CA certificate sign request using the key from step 3
  5. 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

Running as administrator

On the broker, I need the following things:

  • Certificate from the CA (Certificate Authority)
  • Server certificate, signed by CA with its private key
  • Server Private Key for decrypting of the incoming messages

1. 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 a 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

which gives

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 pass phrase 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-----

2. Create CA Certificate

Next I’m creating a certificate for the CA, using the key pair I have 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 new certificate, it will prompt 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 private key to be used for signing
  • -out: specifies the file name for the certificate (.crt)

This generates a certificate (m2mqtt_ca.crt). I have to provide an additional pass phrase 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 []:mail@hslu.ch

As common name I give the name of my host PC (which is acting as 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

Windows Certificate Viewer

3. Create 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 a 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 this password I would have to enter when I start the broker. Not something I want.

which gives

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

4. 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.

which gives:

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 []:mail@hslu.ch

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 which 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-----

5. 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 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

which gives:

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/emailAddress=mail@hslu.ch
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-----

Files

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:

  • <mosquitto>/certs/m2mqtt_ca.crt
  • <mosquitto>/certs/m2mqtt_srv.crt
  • <mosquitto>/certs/m2mqtt_srv.key

The ca.crt belongs to the client (needs to be copied there).

Mosquitto Configuration

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

Mosquitto

I launch my local Mosquitto broker with the -c option pointing to the modified configuration file:

mosquitto -c mosquitto.conf -v

This launches now the broker listening on the secure port 8883:

mosquitto listening on 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

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

Client connected to Port 8883 to broker

Summary

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.

Happy Encrypting 🙂

Links

 

Advertisements

15 thoughts on “Enable Secure Communication with TLS and the Mosquitto Broker

    • Hi Carl,
      thanks 🙂
      Yes, I plan to work on that part. I have it mostly working in lwip RAW mode using a TCP connection. What is not working fully yet is receiving TCP packets through the callbacks: they are asynchronous and I need to buffer them somehow. I have found some mbedTLS examples, but they are all using sockets which I don’t use/have in bare metal mode. So still a long way to go (and then to write the article of course). But that’s what long Easter weekends are for, right? 😉
      Erich

      Liked by 1 person

      • Hi Erich,

        I had worked on adding lwIP 2.0 support to KSDK/MCUx. Its Socket RTOS API is OK, but Bare-metal lwIP TCP RAW API is night-mare.

        I hardly suggest to try the FNET bare-metal TCP/IP stack (http://fnet.sourceforge.net/).
        It has user friendly bare-metal Socket API. Also, it contains k64+FNET+mbdtTLS server example which may be used as a reference.
        Based on my experience with many other stacks (RTCS, lwIP, uIP, InerNitche), the FNET is the most comfortable and easy to use for bare-metal (IMHO).

        Your BLOG is in my favorite one. Thank you,
        Andrey Butok

        Like

      • Hi Andrey,
        yes, I have found that using the bare metal RAW API is not that bad in lwip, once I get used to it. I faced more problems with its socket API, probably more because of the not complete MCUXpresso SDK intergration of the network driver and lwip (wrong priorities, things not reentrant, etc). I hesitated to use the FNET stack (btw, contratulations to that excellent work and I hear very good things about it) because my projects are using microcontrollers from different vendors, and here lwip is a perfect fit as it is available for many ports.
        Thanks!
        Erich

        Like

  1. Pingback: Easter Weekend Apple Juice Brined Pulled Pork Smoked on Beech Wood | MCU on Eclipse

  2. Pingback: Tutorial: Secure TLS Communication with MQTT using mbedTLS on top of lwip | MCU on Eclipse

  3. Pingback: Tuturial: mbedTLS SLL Certificate Verification with Mosquitto, lwip and MQTT | MCU on Eclipse

  4. Hi! This is probably the clearest guide to create self-signed certificates to use with mosquitto I’ve found. However there is a doubt I haven’t been able to solve: what commonName do I have to insert? I tried with my Raspberry hostname and it seems to fail (I get a SSL:CERTIFICATE_VERIFY_FAILED error), and I’ve read no IP should go in commonName. I’ll have my broker in a Raspberry Pi behind a router with port forwarding. Thanks

    Like

  5. Thanks very much.

    Also can you please explain , how to enable websockets over MQTT using libwebsocket .
    It will very helpful to me.

    Thanks,
    Archunan K

    Like

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s