Introduction.
(Updated: 04/11/2016)In this blog post I want to explore how to make secure the communication between an Intel Edison Board and a MQTT Broker, using Transport Layer Security (TLS).
With TLS you can make highly secure the communication between your devices and the broker, by:
- Authenticating the board (the device) against the broker;
- Encrypting all the the communication between the board and the broker; The channel is entirely encrypted and MQTT messages, sent over this channel, are not readable by others;
- Protecting the integrity of messages.
Security is OK, but encryption has its costs: an higher CPU usage and high latency. It is OK if you only need to send several hundreds of bytes/sec (as with our telemetry tests). But if you need to sustain high transmission rates you need to carefully consider the overhead (I don’t think you want to send a film streamed from the Edison, entirely encrypted, in real-time).
In a commercial/industrial scenario you would surely use certificates provided by a Trusted Provider (i.e.: Verisign). For our examples we don’t want to buy certificates and therefore we will use self-signed certificates. In other words we’re signing our certificates.
The configuration.
These are, at high level, the needed configuration steps:- Generate keys and a certificate for “Our Certification Authority"
- Generate the key-pair for the board;
- Generate the key-pair for the broker;
- Configure the MQTT broker in order to use TLS and use the generated keys.
- Configure the JVM on the board and Paho client in order to use TLS and generated keys.
We will do the first tests using Mosquitto.
We will generate key-pair and certificates using Openssl. In my case I have openssl on My MacBook and I will generate all the files using openssl.
A quick list of the commands to be used is found in : http://mosquitto.org/man/mosquitto-tls-7.html.
One advice: be consistent in your specification (always use the name of the server, the same company, the same Country..). You’re mimicking a certification authority that is giving certificates for your boards and server, they won’t accept “fake names”.
1. Generate keys and certificate for the Certification Authority
You're going to generate a self-signed certificate, contained in ca.crt file.
(don’t forget to remember the pass-phrase you set).openssl req -new -x509 -days 730 -extensions v3_ca -keyout ca.key -out ca.crt
2. Generate key-pair for the board (whose name is thunder10).
3. Generate key-pair for the broker.openssl genrsa -des3 -out client.key 2048openssl req -out client.csr -key client.key -newopenssl x509 -req -in client.csr -CA ../authority/ca.crt -CAkey ../authority/ca.key -CAcreateserial -out client.crt -days 730
openssl genrsa -des3 -out server.key 2048
openssl req -out server.csr -key server.key -new
After you have generated the key-pair for the broker (iotagateway1) you need to sign the certificate assigned to the broker using the keys of the CA.
4. This is the configuration for the Mosquitto Broker (mosquitto.conf):openssl x509 -req -in server.csr -CA ../authority/ca.crt -CAkey ../authority/ca.key -CAcreateserial -out server.crt -days 730Signature oksubject=/C=IT/ST=Italy/L=Rome/O=LSaetta/OU=IT/CN=iotgateway1/emailAddress=luigi.saetta@gmail.comGetting CA Private KeyEnter pass phrase for ../authority/ca.key:
listener 8883cafile /etc/mosquitto/ca_certificates/ca.crtcertfile /etc/mosquitto/certs/server.crtkeyfile /etc/mosquitto/certs/server.keytls_version tlsv1
CA certificate has been put under ca_certificates subdirectory.
Server key and certificate have been put under certs directory (these are default directories suggested by mosquitto installation, at least in RPI, which is the platform of my Broker).
You can now test the configuration sending tests messages using mosquitto_pub with this command:
mosquitto_pub -h iotgateway1 -m "Hello" -p 8883 -t thunder10 --cafile ./authority/ca.crt --key ./board/client.key --cert ./board/client.crt<supply pem passphrase>
(whereas I have put my files under board, authority subdirectories).
5. The final part is the configuration of the JVM and the Java program in order to use SSL.
First, the String specifying the BROKER has to change to
ssl:<broker_name>:8883
then, you have to import client key and CA certificate inside a Java Keystore.
I have used the App KeyStore Explorer.
Then, you need to add some code to the Java Client, based on Eclipse Paho
To read the keystone:
private KeyStore readKeyStore(){KeyStore keystore = null;try{FileInputStream is = new FileInputStream(config.KEYSTORE);keystore = KeyStore.getInstance(KeyStore.getDefaultType());String keypwd = config.KEYPWD;keystore.load(is, keypwd.toCharArray());} catch (Exception e){e.printStackTrace();}returnkeystore;}
To add options for SSL:
// verify is SSL is requestedif (config.BROKER.contains("ssl")){try{SSLContext sslContext = SSLContext.getInstance("SSL");TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());KeyStore keyStore = readKeyStore();trustManagerFactory.init(keyStore);sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());connOpts.setSocketFactory(sslContext.getSocketFactory());} catch (Exception e){e.printStackTrace();System.exit(-1);}}
As usual you will find all the code in my GitHub repository.
Some more comments about performances.
As I said before, TLS has its overhead, and with constrained devices you should always consider how much additional CPU you need.But, to be precise, the biggest overhead is in the session establishment phase, at the beginning, where client and server exchange the keys-pair and negotiate a symmetric session key, used for all the following communication.
Therefore, if your devices keeps a permanent connection, the overhead after is not so high, at least in terms of latency.
No comments:
Post a Comment