Para añadir un nivel adicional de seguridad a los mensajes MQTT en la red, se incorpora SSL/TLS para un dispositivo ESP8266.

Para simplificar el ejemplo, la explicación supone que tiene operando el dispositico con
Mensajes con ESP8266-Parpadeo LED
y se ha habilitado un broker SSL/TLS con certificado "local" siguiendo el ejemplo de
MQTT – Mosquitto TLS
Librerías Arduino
Para manejar TLS en la conexión, se usa la libreria siguiente:
#include <WiFiClientSecure.h>
Servidor MQTT puerto
El primer valor a actualizar para mensajes TLS es el puerto, revise este valor antes de continuar.
// MQTT: Servidor
char* MQTT_IP = "192.168.10.40";
uint16_t MQTT_puerto = 8883;
Certificados TLS
Los certificados a usar corresponden al certificado de la autoridad y del servidor mqtt.
Para el certificado de la autoridad mqtt-ca.crt se usa el contenido del archivo abierto como texto.
El certificado del servidor mqtt-srv se usa en formato reducido de fingerprint, obtenido con la instruccion descrita anteriormente en la sección mosquitto TLS.
// Certificados TLS: Certificate Authority
const char caCert[] PROGMEM = R"EOF(-----BEGIN CERTIFICATE-----
MIIDRzCCAi+gAwIBAgIUMtlZSXzSZfHpBI0vrnxdLrQuNgwwDQYJKoZIhvcNAQEL
BQAwMzELMAkGA1UEBhMCRUMxDDAKBgNVBAcMA0d5ZTEWMBQGA1UEAwwNMTkyLjE2
.... // ....
OpA6IPNIHmDSSPxgejZq4booviVKro2/M++iOUuGj1jkjR6XSQ6x1JgK0DVyiBtD
4od+M4mYk7gz/CHgl1JEsTVPyUZK4OO/oxC7
-----END CERTIFICATE-----
)EOF";
// MQTT: cert SHA1 fingerprint
const uint8_t mqttCertFingerprint[] = {0x19,0x50,0x25,0x2C,0xD8,0x6A,0x54,0xE6,0xBC,0x8B,0xA4,0x5F,0x76,0x3F,0xD0,0x7D,0xE0,0x5F,0x7C,0x6C};
Conexiones WiFi Seguras
Para usar los componentes de WifiClient y PubsubClient se requiere añadir los detallas de los certificados, por lo que se sustituyen las línea como se muestra:
// Clientes WiFi y MQTT
//WiFiClient wificlient;
// PubSubClient mqttclient(wificlient);
// X.509 parsed CA Cert
X509List caCertX509(caCert);
// Secure client connection class
WiFiClientSecure wificlient;
// MQTT: Client connection
PubSubClient mqttclient(wificlient);
MQTT - Inicio
En la sección de inicio de MQTT se añaden las partes para que tome en cuenta los certificados al momento de realizar la conexión por Wifi
// Configura cliente TLS
// añade CA cert en los sitios de confianza
wificlient.setTrustAnchors(&caCertX509);
// Habilita self-signed cert
wificlient.allowSelfSignedCerts();
// añade fingerprint para validar conexión
wificlient.setFingerprint(mqttCertFingerprint);
El resto de las intrucciones se mantienen iguales al proceso anterior.
Ejemplo: Parpadea LED
/* ESP8266 Sensor Parpadea. edelros@espol.edu.ec
* con SSL/TLS, Para usar, actualice las secciones de:
* - WIFI:Router, MQTT:Servidor, MQTT:Dispositivo
* ESP-01 al usar GPIO1 y GPIO3,(Tx,Rx), NO USE Serial.print()
*/
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
// WIFI: conexión a Router
char* ssid = "miRouter";
char* password = "miRouterclave";
// MQTT: Servidor
char* MQTT_IP = "192.168.10.40";
uint16_t MQTT_puerto = 8883;
char* MQTT_usuario = "usuarioprueba";
char* MQTT_contrasena = "usuarioclave";
// MQTT: Dispositivo
char* MQTT_ID = "sensor01";
char* MQTT_TOPIC = "oficina/mensaje";
char MQTT_SensorEstado[10] = "OFF";
// Certificados TLS: Certificate Authority
const char caCert[] PROGMEM = R"EOF(-----BEGIN CERTIFICATE-----
MIIDRzCCAi+gAwIBAgIUMtlZSXzSZfHpBI0vrnxdLrQuNgwwDQYJKoZIhvcNAQEL
.......// ........
OpA6IPNIHmDSSPxgejZq4booviVKro2/M++iOUuGj1jkjR6XSQ6x1JgK0DVyiBtD
4od+M4mYk7gz/CHgl1JEsTVPyUZK4OO/oxC7
-----END CERTIFICATE-----
)EOF";
// MQTT: cert SHA1 fingerprint
const uint8_t mqttCertFingerprint[] = {0x19,0x50,0x25,0x2C,0xD8,0x6A,0x54,0xE6,0xBC,0x8B,0xA4,0x5F,0x76,0x3F,0xD0,0x7D,0xE0,0x5F,0x7C,0x6C};
// Sensor
const uint8_t sensor_pin = 1;
volatile boolean sensor_estado = false;
// LED monitor interno: ESP01-pin=1, ESP07-pin=2
const uint8_t LED_pin = 2;
// Mensajes por Puerto Serial
volatile boolean serial_msg = true;
// Clientes WiFi y MQTT
//WiFiClient wificlient;
// PubSubClient mqttclient(wificlient);
// X.509 parsed CA Cert
X509List caCertX509(caCert);
// Secure client connection class
WiFiClientSecure wificlient;
// MQTT: Client connection
PubSubClient mqttclient(wificlient);
void setup() {
if (serial_msg){
Serial.begin(74880);//74880, 115200
while (!Serial){delay(50);}
Serial.println("inicia setup");
}
// LED monitor, Enciende en LOW
pinMode(LED_pin, OUTPUT);
// conexión WIFI y MQTT
inicia_wifi();
if (WiFi.status() == WL_CONNECTED){
inicia_mqtt();
}
}
void loop() {
// Parpadea estado de sensor
if (sensor_estado==true){
sensor_estado = false;
}else{
sensor_estado = true;
}
// LED Monitor Parpadea, enciende en LOW
if (sensor_estado ==true) {
digitalWrite(LED_pin, LOW);
delay(1000); // un segundo
}
if (sensor_estado ==false) {
digitalWrite(LED_pin, HIGH);
delay(1000);
}
if (WiFi.status()==WL_CONNECTED) {
publica_estado();
}
//Revisa estado de Wifi o reintenta conexión
if (WiFi.status() != WL_CONNECTED){
inicia_wifi();
}else{
if (mqttclient.connected()==false){
inicia_mqtt(); // reintento
}
if (mqttclient.connected()==true){
mqttclient.loop();
}
}
yield(); // procesa wifi
}
sección de inicio MQTT completa:
void inicia_mqtt() {
int intentos = 5;
int cuenta = 0;
// Configura cliente TLS
// añade CA cert en los sitios de confianza
wificlient.setTrustAnchors(&caCertX509);
// Habilita self-signed cert
wificlient.allowSelfSignedCerts();
// añade fingerprint para validar conexión
wificlient.setFingerprint(mqttCertFingerprint);
mqttclient.setServer(MQTT_IP, MQTT_puerto);
mqttclient.connect(MQTT_ID, MQTT_usuario, MQTT_contrasena);
//mqttclient.setCallback(callback);
if (serial_msg){
Serial.print(" MQTT Conectando a ");
Serial.println(MQTT_IP);
}
while (!mqttclient.connected()&&(cuenta<=intentos)){
cuenta = cuenta + 1;
// LED Monitor parpadeo MQTT, enciende LOW
digitalWrite(LED_pin, LOW);
delay(600);
digitalWrite(LED_pin, HIGH);
delay(400);
if (serial_msg){
Serial.print(".");
}
}
// Si conectado, inicializa estado
if (mqttclient.connected()){
publica_estado();
}
if (serial_msg){
//Fin de "...."
Serial.println();
Serial.print("; MQTT Conectado: ";);
Serial.println(mqttclient.connected());
Serial.print("; MQTT Estado: ";);
Serial.println(mqttclient.state());
}
}
sección de publicación MQTT es igual que en el ejercicio que le precede
// Publicar el estados del dispositivo
void publica_estado() {
// formato para envio (Texto)
if (sensor_estado == true ){
snprintf(MQTT_SensorEstado,10, "ON");
}else{
snprintf(MQTT_SensorEstado,10, "OFF");
}
// publicar estados
if (mqttclient.connected()==true) {
mqttclient.publish(MQTT_TOPIC,MQTT_SensorEstado,true);
}
if (serial_msg){
if (mqttclient.connected()==true) {
Serial.println(MQTT_SensorEstado);
}
if (mqttclient.connected()==false) {
Serial.println("MQTT desconectado");
}
}
}
sección de inicio de Wifi es igual que en el ejercicio que le precede.
void inicia_wifi(){
int intentos = 10;
int cuenta = 0;
if (serial_msg){
Serial.print(" WIFI Conectando a ");
Serial.println(ssid);
}
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while ((WiFi.status() != WL_CONNECTED) && (cuenta < intentos)){
if (serial_msg){
Serial.print(".");
}
cuenta = cuenta+1;
// Parpadeo de Monitor enciende en LOW
digitalWrite(LED_pin, LOW);
delay(300);
digitalWrite(LED_pin, HIGH);
delay(200);
}
if (serial_msg){
Serial.println(); //Fin de "..."
if (WiFi.status() == WL_CONNECTED){
Serial.print(" Estado: ");
Serial.println(WiFi.status());
Serial.print(" MAC: ");
Serial.println(WiFi.macAddress());
Serial.print(" IP: ");
Serial.println(WiFi.localIP());
Serial.print(" RSSI: ");
Serial.println(WiFi.RSSI());
Serial.println();
}
if (WiFi.status() != WL_CONNECTED){
WiFi.printDiag(Serial);
Serial.println();
}
}
}
Referencia: https://blog.thewalr.us/2019/03/27/using-esp8266-as-an-iot-endpoint-with-encrypted-mqtt-transport/