Filter results by

SSL/TLS-Secured Links

Before we even started the MQTT tutorial on ARTIK Cloud Actions, we had already established a secure means of communicating sensor data to ARTIK Cloud and receiving appropriate Actions back for sending to the remote modules. But the local links were relatively unprotected, leaving a gaping security hole. In this tutorial, we plug that hole.


In preparation for this tutorial, you must:

  • Complete and understand the tutorial on ARTIK Cloud Actions, as the present tutorial suggests changes to code of that previous one.
  • Have available as many SSL/TLS-capable MQTT edge devices as possible for testing.

The "remote" ARTIK board from last time is sufficient as a securable MQTT edge device if you do not have others. However, the Particle Photon board cannot be used as it is not known to support SSL/TLS as of this writing.

The time for completing this installment of the tutorial series is approximately 1 hour.


The Arduino libraries offer Wi-Fi drivers that make it effortless to upgrade to secure Wi-Fi links – you simply replace WiFiClient with WiFiSSLClient. In our previous tutorials, that step alone was enough to secure MQTT as well, where the only SSL/TLS-enabled link was the one to the ARTIK Cloud MQTT server.

In that configuration, we were acting only as a client. As it falls on the server to provide certificates to clients while setting up the encrypted link, we did not need to consider anything further from our side – the standard CA certificate bundle that came with our Linux® installation was enough for verification.

However, had we chosen to secure the links between our local Mosquitto MQTT broker and its client devices (Node-RED and the "remote" ARTIK board), the broker would have needed to act as a secure server. For simplicity, and because we wanted to use the Particle Photon board to open and close our curtains, we chose not to.

Let's assume that we now have decided to make our entire system secure and free from outside threats. That means Mosquitto and all its clients must use SSL/TLS-secured links for all communication, leaving us responsible for generating and installing the proper certificates and keys using standard Linux methodologies.

Setting this up is not all that easy! Here, in brief, is what we'll need to do.

  1. "Name" the server and use that common name for every connection.
  2. Create a private server key.
  3. Create a key and certificate pair as a Certificate Authority (CA).
  4. Use the CA credentials to create a server certificate using the private server key.
  5. Store the created files in known locations where they can be found.
  6. Adjust all file paths to find the files in those locations.
  7. Modify programs to use the encryption library commands and the chosen server name.

You must follow the procedure carefully so as not to miss any steps. All are critical to making the security scheme work (it's "all or nothing").

Creating Certificates

Our security system will rely on two public "certificates", one from a trusted Certificate Authority (CA) and another derived from that and linked to your private server key.

  • You will start by generating a random private server key. Using that, you will create a "certificate signing request" (CSR) to send to a CA.
  • In our case, that CA happens to be you: You will be able to "sign" the CSR to create a server certificate.
  • You will copy that certificate file in advance onto each client that you want to allow to communicate with the server.
  • During operation, your server will serially transmit that certificate to each client who tries to connect. The client compares the two – if they match, you're connected.

Got it? Don't worry, we'll walk you through the steps.

About Certificate Infrastructure

We provide here a brief overview of SSL/TLS security. Skip to the Generate Certificates section if you don't need these details. If you would instead like even more background, Web resources like this one provide excellent discussions about who needs what keys and certificates.

TLS security is based on Public Key Infrastructure (PKI), where mated "public" and "private" keys are used. We'll take advantage of OpenSSL commands to create them.

Certificate Authority. The "Certificate Authority" (CA) is the entity empowered (by who? read below) to create a trustworthy public and private key pair.

The public key is inside a "certificate" that also contains institutional data about the entity – domain name, company name, e-mail contact, etc. It's that bound combination of key and origination data that makes the certificate traceable and trustworthy.

The private key is held only by its creator, who uses it to encrypt messages.

"Key" point: Someone reading data encrypted by the private key can decrypt it using only the corresponding public key.

The "business model" of the CA is to sell additional trustworthy certificates to you. The new certificates, linked to the CA's original certificate but using additional private keys, inherit the trustworthiness of the original. They are created for use on a specific server or client on your network, and contain data specific to you or your company.

Server Certificate. In our application, the MQTT broker/server requires such a server certificate, along with its original private key. Clients that will communicate with the MQTT server must have the original CA certificate (not the server certificate) copied to them ahead of time before they can trust a request to set up a secure link.

Who is Trustworty? If your server were open to the public, you would need to submit a Certificate Signing Request (CSR), with verifiable institutional information, to a trusted Certificate Authority (CA) – for example, Symantec or GoDaddy – to buy a "signed" server certificate. Your certificate would thereby inherit the trustworthiness of theirs.

You would encrypt data, using your own private server key, that could be decrypted by clients using your public server certificate, which gets transmitted at connect time. But a client user won't trust or use your transmitted server certificate unless they can verify that it derives from a CA certificate already installed on their system.

However, if your "users" will be local MQTT devices that you set up with a CA certificate of your choosing, and since you trust yourself, you can "self-sign" to avoid the expense of buying a CA certificate. The OpenSSL command sequence below does this – it signs the server certificate using the credentials from your own CA key and certificate, making you a "mini CA".

Expiration. Certificates must eventually expire. In the commands below, we choose an expiration of 10 years (3650 days). You can adjust this as needed.

Making Server Name Known to Clients

Until now, we have been able to provide clients with just a raw IP address to contact the MQTT broker. With SSL/TLS certificates involved, it's no longer that simple.

Each SSL/TLS client needs to know both an IP address and the server name of the broker. As part of the certificate validation process, the software will check the server name you use in code against the so-called Common Name in the transmitted server certificate to verify that they match. (Sorry, it won't work to just type in a fixed IP address for Common Name.)

There are automated ways to implement the name assignment using DNS and DHCP that might work for you. For example, you could assign names to IP addresses at your Wi-Fi gateway/router. You can investigate various approaches on your own to determine the one you want to take.

However, here we will choose a simple method: adding the remote server name and its IP address to the /etc/hosts file of each client.

For example, if you chose a Common Name of marks-iot-srvr for your server certificate, you would need to edit every hosts file to contain an entry like this:    marks-iot-srvr

A user-friendly way to do this would be to write a script that automatically figures out the broker IP address like we did in the Remote ARTIK Code, and then auto-generates /etc/hosts with the IP address and the Common Name you decided on. We've provided a starting point here.

Setting Up SSL/TLS Server

Generate Certificates

Follow the steps below to generate keys and certificates. You may need to repeat the process several times to get a solid understanding of why you are doing it. There is a lot to comprehend!

Note that both the CA and server OpenSSL calls will ask a series of questions about your organization. As you are the "mini CA", enter as much or as little information as you choose, with two exceptions.

Common Name. The "Common Name" on the server certificate must match the name that the ARTIK server will be known by in /etc/hosts files on both server and client as noted here. The Common Name on the CA certificate does not need to be the same and usually is different.

Pass phrase. Enter a simple pass phrase when requested, like 1234. We will be removing it in a later step so it doesn't matter what you choose.


  1. Go to the directory

  2. Generate a new private key for the server, in RSA encryption format.
    openssl genrsa -des3 -out m2mqtt_srv.key 2048

  3. Using that private key, generate a server "certificate signing request" (CSR) file.
    openssl req -key m2mqtt_srv.key -out m2mqtt_srv.csr -new

  4. Acting as your own "mini" X.509 Certificate Authority (CA), create your own CA private key file and CA certificate.
    openssl req -new -x509 -days 3650 -keyout ca.key -out ca.crt

  5. "Sign" the CSR, using your newly-minted CA credentials, to create your server certificate.
    openssl x509 -req -in m2mqtt_srv.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out m2mqtt_srv.crt -days 3650

You have now created a server private key to be kept securely on the Mosquitto server, and a mated server certificate that the server will automatically transmit to the MQTT client each time the client requests a connection. You will need to copy your CA certificate to each client in advance, thus establishing a "chain of trust" where the incoming server certificate can be recognized as having been "signed" by the trusted CA certificate on hand.

The files are written in ASCII format but are encoded. If you want to see the contents of the server certificate you just created, try this:

openssl x509 -in m2mqtt_srv.crt -noout -text

The command to look at the contents of a private key is similar:

openssl pkey -in m2mqtt_srv.key -noout -text

Disable Pass Phrase Question

During certificate creation, the openssl command asked for a pass phrase. On start-up, Mosquitto will wait for you to enter it. Since we are trying to run Mosquitto in the background, there will be no easy way for you to do so.

The sequence below removes the pass phrase from the server key file.

  1. Make a copy of the server key.
    cp m2mqtt_srv.key
  2. Strip out the password from the copied key, and overwrite the original file with the updated version.
    openssl rsa -in -out m2mqtt_srv.key
    Enter the pass phrase when requested.

When Mosquitto loads the updated m2mqtt_srv.key file, it will not stop for a pass phrase.

Relocate Files

The convention within Fedora is to move files to specific server directories as follows:

CA certificate: mv ca.crt /etc/pki/CA/certs/.
CA private key: mv ca.key /etc/pki/CA/private/.
Server certificate: mv m2mqtt_srv.crt /etc/pki/tls/certs/.
Server private key: mv m2mqtt_srv.key /etc/pki/tls/private/.

You may delete the .csr and .srl files, as they have served their purpose.

Copy your files as suggested by convention, or put them wherever you prefer. We will follow the convention in the remainder of this article, so if you choose to keep the files elsewhere, make sure to update the paths provided. Keep in mind that many Arduino libraries expect you to use these paths.

The master sketch running on the ARTIK server board acts as a client to the Mosquitto server, so don't forget to additionally copy the CA certificate to the expected place for clients (/etc/pki/tls/) as noted here.

Set File Paths in Mosquitto

You'll find in the /etc/mosquitto directory the mosquitto.conf.example file, which is well worth reading through if you have an hour to spare. If not, just create a mosquitto.conf file as we explain below to get the basic certificate structure in place.

  1. Enter the following lines in the mosquitto.conf file, or modify the existing lines.

     cafile /etc/pki/CA/certs/ca.crt  
     certfile /etc/pki/tls/certs/m2mqtt_srv.crt  
     keyfile /etc/pki/tls/private/m2mqtt_srv.key
     port 8883
  2. Make sure when you run Mosquitto that the command line can get to the config file. This could mean using
    mosquitto -c /etc/mosquitto/mosquitto.conf &
    or changing to that directory before calling
    mosquitto -c mosquitto.conf &
    or pre-specifying the path.

Modify Server Arduino Code

The code for the server must be upgraded to SSL/TLS operation. With reference to the Arduino master sketch code from the ARTIK Cloud Actions tutorial:

  • Remove the code that figures out the IP address. We're now using the name assigned in /etc/hosts.

  • Assign to mqttServerName the server name you've chosen (and put in the server certificate as Common Name).

  • Replace all instances of mqttServer with mqttServerName. Make sure that your code no longer uses the IP address directly.
  • Replace WiFiClient with WiFiSSLClient

  • Change the mqttPort value from 1883 to 8883.

Setting Up SSL/TLS Clients

Copy CA Certificate to Clients

Provide each Mosquitto client with a copy of your trusted CA certificate, and separately, an entry in the hosts file matching the Common Name you used on the server certificate.

  • Copy ca.crt to
    (you can instead put it in the root directory).
  • Use vi (or an automated script) to add the Common Name to the /etc/hosts file along with the server IP address.

Enable SSL/TLS on Node-RED

On the Node-RED canvas, edit the node address.

  • Double-click on an MQTT node, and click on the "pencil" icon.

  • On the Connection tab, change the port from 1883 to 8883.

  • On the Security tab, enable SSL/TLS.

    In our testing, it was not necessary to give Node-RED any information about the certificate location.

  • Click Update and finish out the editing session.

  • Click Deploy to save the changes.

Modify Client Arduino Code

The code for each client must be upgraded to SSL/TLS operation. With reference to the Arduino remote sketch code from the ARTIK Cloud Actions tutorial:

  • Remove the code that figures out the IP address for the broker. We're now using the name assigned in /etc/hosts (possibly by an external script).

  • Assign to mqttServerName the server name you've chosen (and put in the server certificate as Common Name).

  • Replace all instances of mqttServer with mqttServerName. Make sure that your code no longer uses the IP address directly.

  • Replace WiFiClient with WiFiSSLClient

  • Change the mqttPort value from 1883 to 8883.

You're done! You should now have working and secure MQTT links.


Basic Connection Checks

OpenSSL provides a way to test the remote SSL/TLS MQTT server port from the command line as a client. You can type in the host IP address directly, like this:

openssl s_client -connect

The outcome may help verify whether your problem is with the connection or within the Arduino sketch. It does not check certificate validity, however – a Web search will show how to do that with openssl if needed.

If you want to verify that your /etc/hosts file is correct, try something like this:

curl -vs --connect-timeout 2 marks-iot-srvr:8883 2>&1

Error Messages in Sketches

When using the Arduino IDE, a good way to see more debug information is to save the compiled binary as an .elf file and copy it to the ARTIK board as noted here, then run it in the foreground. Helpful tracing and error messages from the mbedTLS library will show up on the terminal emulator output.

x509_verify_cert() Failures

The SSL/TLS handshake will fail with a somewhat vague x509_verify_cert() error message for various reasons. The cause may not be readily apparent, but typically the error can occur if:

  • Common Name in the server certificate does not match mqttServerName supplied to the MQTT client.begin(mqttServerName, mqttPort, ipStack) command.
  • You call for 1024-bit instead of 2048-bit encryption when creating certificates.
  • The correct CA certificate is not found on the client, either in the /root or /etc/pki/tls directory.

ARTIK Master and Remote Connection Issues

If you are running the ARTIK master and remote boards along with Node-RED, you will (as before) have three clients to Mosquitto. Upon launching each of their respective programs, you should see a clear "New client connected" message from Mosquitto. In the case of the master and remote boards, you will see the name used in the code, "ARTIK-Master" or "ARTIK-Remote", along with the IP address.

If the Mosquitto connect message does not display board name, just the IP address, then you did not succeed in getting an SSL/TLS-secured connection. It is especially easy on the server side to miss one of these critical requirements:

  • Server name (such as marks-iot-srvr) and its IP address in /etc/hosts
  • Same server name in the mqttClient.begin() statement.
  • ca.crt copied to /etc/pki/tls/

OpenSSL vs NSS

While there are several options for managing certificates under Linux, in-depth discussion of cryptographic libraries is well beyond the scope of our article. We chose to use OpenSSL to take care of our needs; you may instead choose to use Network Security Services (NSS) or another method.

Here is why you need to consider such things. Remember how we used the curl command to check broker connectivity in our Remote ARTIK code? Our installed version of curl is pre-built to use NSS when it is called for an SSL/TLS-secured port. When we do so without the NSS certificate infrastructure in place, we'll get an error message.

For this particular case, we can work around it with the --insecure option to bypass the certificate check. We could also rebuild the command from source and configure it for OpenSSL protocols. Otherwise we'd have to support a duplicate certificate infrastructure (NSS as well as OpenSSL).

Last updated on: