IoT is, of course, all about connecting to the Internet. And even moreso, it is about security. Without security and without encrypted communication, anyone can see what I send or receive. And this is especially bad if passwords or usernames are sent in an unencrypted way. So encryption and secure communication are key. The solution is to use a connection that uses the TLS (Transport Layer Security) protocol.
I want to use TLS for my MQTT communication (see MQTT with lwIP and NXP FRDM-K64F Board). I’m still learning MQTT and about the fundamentals of security and security protocols. So this article is about what I have learned recently, and what I can use to make my data communication secure: Network stack architecture, symmetric and asymmetric encryption, and certificates.
This article walks through the basic principles for a secure communication using the TLS (Transport Layer Security) protocol, with MQTT in mind. TLS is the successor of SSL (Secure Sockets Layer), which are often used together (TLS/SSL). TLS (as the name indicates) is an encryption on the transport layer: That means that the application layer does not have to implement the encryption itself. Instead, it configures the transport layer to use the encryption protocol.
For an application (e.g. running on a microcontroller) to communicate with the Internet, it requires a communication stack (TCP/IP, e.g. lwIP) plus the needed hardware to communicate with the physical layer (e.g. the FRDM-K64F board). TCP/IP itself is the common ‘language’ for the application to communicate with the other side:
The same principle applies to running the MQTT Mosquitto broker (or any server) on my host machine.
MQTT is a special ‘language’ using TCP (Transmission Control Protocol), and basically sits between the application and the TCP/IP stack: The application uses the MQTT layer to talk and understand the ‘MQTT language’:
TCP/IP uses ‘sockets’ and/or ‘ports’. By default, Mosquitto is using port 1883 (see MQTT with lwIP and NXP FRDM-K64F Board), which does not use an encryption protocol. That means that potentially everyone can see the exchange of data between the MQTT broker and the clients. Having an unencrypted connection is a great way to start with MQTT, as it is simple and gives an easy way to start exploring it. Configuring encryption and using an encrypted connection, on the other hand, is much more complex. But once I have things working in an unencrypted fashion for testing purposes, I definitely want to use encrypted communication.
Instead of doing an ‘end-to-end’ encryption in the application itself, a better approach is to put in an encryption layer on top of the communication stack:
That way, the application (or MQTT language speaking part) does not need to implement the encryption protocol itself, it simply talks to the encryption layer, which will do all the work.
Encryption relies a lot on math, random number generators, and cryptographic algorithms. And with encryption, there is the need for ‘keys’: a sequence of bits and bytes tha are used to ‘lock’ (encrypt) and ‘unlock’ (decrypt) the data.
With symmetric encryption, the same key is used to encrypt and decrypt a message:
It means that everyone having that (blue) key will be able to decrypt the message. So the security depends on how securely I can distribute and keep that key.
With asymmetric encryption, I have a pair of mathematically connected keys: A shared green and a private red key. I keep the red key private and do not disclose and distribute it. The green key is public: Everyone can have it. Everyone can encrypt a message with the green public key, but only the one with the red private key is able to decrypt it:
But how can I know that the public key I have received is really from the person I think it is coming from? Maybe I think I have received the public key from the person I think it is, but what if, in reality, it is a ‘man in the middle’ intercepting all the messages and I have that middle man's public key instead?
This is where ‘certificates’ come into the play. Certificates are a kind of passport, provided by a ‘Certification Authority’ (CA), which testifies that the person in question is really that person.
In this example, Sue then can use the trusted certificate to extract the key. If that fails, Sue knows that the certificate with the key is not coming from Joe.
There are different ways and protocols to distribute the keys and certificates. Usually, the keys/certificates are pre-distributed (e.g. pre-installed on devices), or the secret information is built up and exchanged using a multi-stage protocol like TLS.
TLS exists in different versions (the current version is 1.2, with 1.3 in the draft state). TLS is using a special protocol called ‘Handshake’ to agree on the protocol and to exchange keys (see this link for details). Basically, the certificate is used to verify the server identity, and asymmetric encryption is used to exchange a shared secret key for symmetric encryption:
- Client sends a clear (unencrypted) ‘hello’ message to the server, asking for an encrypted session.
- Server responds with a server certificate, which includes the server public key in it.
- Client verifies the certificate and extracts the public key.
- Client uses the public key to send a ‘pre-master’ key he has generated to the server.
- The server uses its private key to extract the ‘pre-master’ key.
- Both the client and the server use the ‘pre-master’ key to compute a shared secret key.
- Client sends a message to the server encrypted by that shared secret key.
- The server decrypts the received message and checks it.
- If that passes, the server sends back an encrypted message using the shared secret key to the client to confirm that everything is ok.
- From this point on, both the client and server are using the shared secret key for their communication.
The graph here provides a good overview of the handshake process:
I don’t plan on implementing TLS or the cryptographic algorithms! Instead, I was looking for an open source library I could use. There are different vendors providing encryption middleware. For my project with MQTT, lwIP, and the FRDM-K64F I have found the following:
- OpenSSL (https://www.openssl.org/): very complete and capable open source implementation with good documentation. More targeting desktop and Linux machines, and less smaller embedded devices. I have a permissive license and am moving to the Apache license version. But because of the general overhead, I didn't consider it for use with the FRDM-K64F.
- wolfSSL (https://www.wolfssl.com/wolfSSL/Home.html), formerly CyaSSL: Targeting embedded devices, it would fit on the FRDM-K64F. The free Open Source (GPLv2 and GPLv3) version is restrictive, and the commercial one outside of my budget.
- CycloneSSL (https://www.oryx-embedded.com/cyclone_ssl.html): good features, but same as wolfSSL: GPL license and commercial version only.
- mbedTLS (https://tls.mbed.org/), formerly PolarSSL: owned by ARM, good documentation, and its Apache 2.0 license allows me to use it in both commercial and open source projects for free. And it seems to be used with lwIP too (more about this later).
The mbedTLS has been the most versatile and open library I have found, and this is why I have started using it in my project. More about that in a future article.
To use a secure data transport, I have to use encryption. Cryptographic algorithms are provided with several open source libraries, and the mbedTLS library seems to fit my needs best. Key (sic!) to encryption is the distribution and handling of keys and certificates. TLS (or the Transport Layer Security) is a protocol that manages key verification and distribution, which is provided in the mbedTLS library.
In the next article, I will cover how to enable TLS between an MQTT Mosquitto broker and the MQTT client, which is a lot about creating keys and certificates.
- Wikipedia: https://en.wikipedia.org/wiki/Transport_Layer_Security
- SLL for secure MQTT: http://rockingdlabs.dunmire.org/exercises-experiments/ssl-client-certs-to-secure-mqtt
- Behind the Scenes of SSL Cryptography: https://www.digicert.com/ssl-cryptography.htm
- ARM mbed TLS library: https://tls.mbed.org/