Riprendiamo il tema sicurezza per i broker MQTT. In un precedente articolo, vi ho mostrato come gestire autenticazione e autorizzazione. La debolezza di tale configurazione è che le credenziali sono trasmesse in chiaro, è quindi possibile – se un attaccante può sniffare il traffico di rete – leggere utenza e password e quindi utilizzarle per impersonificare un client autorizzato.
Oggi vediamo come attivare la cifratura del canale di comunicazione tra client e broker utilizzando certificati SSL. Vi mostrerò inoltre come realizzare un programma per il chip esp32 che invii dati al broker su canale cifrato…
Certificato SSL
Per poter cifrare la comunicazione, dobbiamo fornire a mosquitto un certificato server.
Generiamo per prima cosa la chiave privata (algoritmo RSA, lunghezza 2048bit):
openssl genrsa -out mosquitto.key 2048 |
quindi creiamo il file CSR:
openssl req -new -out mosquitto.csr -key mosquitto.key |
compiliamo i vari campi; il più importante è il common name che identificherà il certificato:
Firmiamo quindi il file CSR con la nostra CA (o inviamolo ad una CA pubblica) per ottenere il certificato:
openssl ca -config openssl.cnf -extensions server_cert -notext -in mosquitto.csr -out mosquitto.cer |
Creiamo la cartella ssl all’interno della cartella dove abbiamo installato mosquitto e copiamo in tale cartella certificato e chiave privata appena generati e il certificato della CA:
Configurazione
Apriamo il file mosquitto.conf e inseriamo le seguenti righe:
La prima riga cambia la porta su cui il server mosquitto è normalmente in ascolto (1883) in 8883, porta di default per le connessioni in SSL.
Le successive tre indicano a mosquitto il path dei certificati (server e CA) e la chiave privata relativa al certificato server. L’ultima – non obbligatoria – forza l’uso del protocollo TLS v1.2, il più sicuro attualmente disponibile.
Una volta configurato il server, possiamo eseguirlo (-v per la modalità verbosa):
mosquitto.exe -c mosquitto.conf -v |
Per utilizzare gli strumenti mosquitto_pub e mosquitto_sub, dobbiamo specificare nuovi parametri:
mosquitto_sub.exe -p 8883 -t test --cafile .\ssl\ca.cer --insecure mosquitto_pub.exe -p 8883 -m 20 -t test --cafile .\ssl\ca.cer --insecure |
Con -p indichiamo la nuova porta utilizzata dal server, con –cafile indichiamo il percorso del certificato della CA che ha firmato il certificato esposto dal server mosquitto e infine con –insecure chiediamo ai due client di non verificare che il common name del certificato (nel mio esempio mymosquitto.local) corrisponda al nome del server.
esp32
Tuan PM ha sviluppato una libreria (espmqtt) per il framework esp-idf che implementa un completo client MQTT. La libreria inoltre supporta connessioni sicure, possiamo quindi utilizzarla per collegarci al server mosquitto con TLS attivo.
Copiamo il contenuto del repository Github della libreria nella cartella components del nostro progetto e includiamo il file header della libreria nel codice sorgente del nostro programma:
#include "mqtt.h"
|
La configurazione del client MQTT avviene tramite la struct mqtt_settings:
I parametri principali sono:
- il server (host) a cui collegarsi (si può utilizzare l’indirizzo IP o il nome DNS)
- la porta (port) su cui il server è in ascolto (di default sono 1883 o 8883 se è abilitato SSL)
- eventuali username e password da utilizzare se il server richiede autenticazione
- una o più funzioni di callback che la libreria espmqtt chiamerà al verificarsi dell’evento associato
L’interazione con il client MQTT avviene implementando – nel proprio programma – una o più funzioni di callback.
Ad esempio la connessione e disconnessione dal server MQTT avviene in questo modo:
Le funzioni connect_cb e disconnect_cb effettuano la connessione e la disconnessione dal server, mentre connected_cb e disconnected_cb vengono chiamate quando il relativo evento (connessione/disconnessione) avviene. Normalmente il nostro programma non andrà a ridefinire le funzioni principali, ma andrà ad implementare quelle relative agli eventi, per eseguire operazioni (ad esempio la sottoscrizione ad un topic) in contemporanea a tali eventi.
Preparata la configurazione del client MQTT, è possibile avviarlo con:
mqtt_start(&settings); |
Una volta effettuata la connessione al server (evento connected_cb) è possibile sottoscrivere topics e togliere la sottoscrizione o inviare messaggi con:
void mqtt_subscribe(mqtt_client *client, const char *topic, uint8_t qos); void mqtt_unsubscribe(mqtt_client *client, const char *topic); |
e
void mqtt_publish(mqtt_client* client, const char *topic, const char *data, int len, int qos, int retain); |
Demo
Ho preparato un esempio che mostra l’interazione tra una scheda di sviluppo esp32 e mosquitto, configurato in SSL.
Ho collegato alla scheda di sviluppo un sensore HTU21D come spiegato in un mio precedente articolo per inviare, ogni 5 secondi, i dati di temperatura e umidità rilevati. Per visualizzare i dati ricevuti dal broker MQTT, ho utilizzato un comodo programma opensource, HelloIoT.
Codice sorgente del programma e configurazione di HelloIoT si trovano nel mio repository Github; di seguito un filmato che mostra il programma in esecuzione (sottotitoli in italiano disponibili):