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
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/