How to go from MQTT to MQTTS with a TLS connector

We will look into using MQTT to save data and battery usage, but while still keeping it as secure as if it was MQTTS

MQTT is a widely used network protocol in IoT for sending messages between devices and a server. To keep the connection secure normally MQTTS is used. This uses more traffic and drains the battery. By using a TLS connector we can have the device use MQTT which Onomondo transforms into MQTTS. 

For this example I use the mqtt module for Node.js, but you should be able to replace it with any other implementation for your language. I also use test.mosquitto.org as the test MQTT server.

An example with MQTTS

This is a basic example on how to use MQTTS to connect to 

const fs = require('fs')
const mqtt = require('mqtt')

const ca = fs.readFileSync('./mosquitto.org.crt').toString()
const client = mqtt.connect('mqtts://test.mosquitto.org:8883', { ca })

client.on('message', (topic, payload) =>
console.log(`[messaged received] topic=${topic} payload=${payload.toString()}`)
)
client.on('connect', () => {
console.log('[connected]')
client.subscribe('helpomondo/testing', () =>
client.publish('helpomondo/testing', 'Hello from device')
)
})

Note that you need to have the mosquitto.org.crt on your device.
I used the Traffic Monitor to capture the packets going to/from the device. When I ran this example, this little example used 3.6 KB. Most of it is used esablishing the secure connection.

Let's see how we can do it better with a TLS connector.

Setting up the TLS connector

Now we need to create a new connector. For this example we need to set the host as test.mosquitto.org, port to 8883, and put the contents of mosquitto.org.crt into the connector setup. We also add two passthrough rules to pass all UDP and ICMP packets directly to the internet.

With this setup all TCP traffic going out from your device (no matter which ip/host it's supposed to go to) will go to test.mosquitto.org:8883 and Onomondo creates a TLS connection to that endpoint.

Your setup should look similar to this

image-png-nov-02-2021-02-50-47-01-pm

Now find your SIM on the SIMs page, and edit it. Set the connector to the one we've just created

image-png-nov-02-2021-02-55-09-50-pm

Example with MQTT

Let's go back to the code example and set it up to only use MQTT and not MQTTS.

const fs = require('fs')
const mqtt = require('mqtt')

const client = mqtt.connect('mqtt://test.mosquitto.org:8883')
// Notice how we went from `mqtts://` to `mqtt://` and removed the `ca`

client.on('message', (topic, payload) =>
console.log(`[messaged received] topic=${topic} payload=${payload.toString()}`)
)

client.on('connect', () => {
console.log('[connected]')
client.subscribe('helpomondo/testing', () =>
client.publish('helpomondo/testing', 'Hello from device')
)
})

So it's very similar to before, except a few key things. The protocol is now mqtt and not mqtts. We also removed the ca certificate file.

I used the Traffic Monitor to capture packets going to/from device. This example now uses 1.1 KB.

Benefits of using a TLS connector

  • Saves on data cost
    • Less data transferred
    • In this example we went from ~3.6 KB to ~1.1 KB. With IoT we often send very small messages so establishing a TLS connection can be quite expensive.
  • Saves on battery usage
  • No encryption on the device
    • Saves on battery usage by not having to handle encryption
    • No or less keys or certificates on the device that might need to be updated

Is this still secure?

A little-known fact about telco is that the traffic is actually secure from your device until it hits your provider. A SIM card mostly contains keys which are one end encryption, and the matching keys are on the providers side. That means that traffic is always encrypted until it gets to your provider (i.e. Onomondo), but then it goes on the Internet. Since most providers just pass traffic out on the Internet you need to encrypt it on the device. By using a TLS connector Onomondo makes sure that there is an encrypted connection between Onomondo and your endpoint.

So to sum up. Cellular traffic is already encrypted between device and provider. Then by adding a TLS connector the traffic is encrypted between Onomondo and your endpoint.

One extra little bonus

Remember how I mentioned that all TCP traffic going out of the device went to test.mosquitto.org:8883? This actually mean we no longer have to look up test.mosquitto.org on the device. So we can remove that hostname from our example and save that lookup for even more optimization

...

const client = mqtt.connect('mqtt://1.2.3.4')
// Notice how we removed the hostname. There's only an ip address now.

...

How to debug with the MQTT Explorer

To help testing this I found it very helpful to use MQTT Explorer. Then you can subscribe to helpomondo/testing and see if the device behaves as expected.

image-png-nov-02-2021-03-24-21-95-pm