MQTT über TLS funktioniert nicht - Wemos D1 mini (ESP8266)

Ich möchte mich mit meinem MQTT-Broker über TLS verbinden. Leider schaffe ich es nicht mit meinem Wemos D1 mini.
Warum ich mir sehr sicher bin, dass es an der TLS-Verbindung des ESP8266 liegt:

  • ohne TLS funktioniert alles, auch mit User und Passwort
  • auf einem ESP32 funktioniert auch die TLS verbindung anstandslos (natürlich mit entsprechenden Codeanpassungen), der Broker scheint also auch korrekt konfiguriert worden zu sein

Unten habe ich meinen auf das Wesentliche gekürzten Code angehängt. An zwei Stellen habe ich Anpassungen unternommen. Diese sind markiert mit


///////// Änderungszeile /////////


Mit dem dort auskommentierten Teil funktioniert es noch. Mit dem gegenwärtigen Code bekomme ich aber als Fehler-Code "-2" beim Verbindungsversuch mit dem MQTT-Broker.

Was gilt es noch zu beachten beim ESP8266 um eine TLS-Verbindung aufbauen zu können?

Übrigens: Ich weiß, dass ich aktuell keinen Fingerprint überprüfe und es deshalb noch nicht wirklich sicher ist, aber eines nach dem anderen. Das müsste ja auch schon so gehen, zumindest klappt das auf dem ESP32 auch so...

#include <ESP8266WiFi.h>


#include <WiFiClientSecure.h> //#include <WiFiClient.h>  ///////// Änderungszeile /////////



#include <PubSubClient.h>


char* ssid = "WLAN-*****";
char* password =  "********";

char* mqttServer = "192.168.178.35";
int mqttPort = 8883;
const char* mqttUser = "esp8266";
const char* mqttPassword = "*****";

WiFiClientSecure espClient; //WiFiClient espClient;  ///////// Änderungszeile /////////



PubSubClient client(espClient);


// SETUP ///////////////////////////////////////////////////////////////////
void setup() {
 
Serial.begin(9600);

ConnectWLAN();
ConnectMQTT();

}
// ENDE SETUP /////////////////////////////////////////////////////////////

void loop(){
  client.loop();  //allow the client to process incoming messages and maintain its connection to the server
  
    
}


void ConnectWLAN() {
  
  if (WiFi.status() != WL_CONNECTED) {
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
      Serial.print("WiFi.status: ");
      Serial.println(WiFi.status());
      if (WiFi.status()==4) {
        Serial.println("Disconnecting...");
        //ESP.restart();
            WiFi.disconnect();
            WiFi.begin(ssid, password);
            delay(1000);
      }
    // wait 1 second for re-trying
      delay(1000);
      Serial.println("Connecting to WiFi..");
    }
    Serial.print("Connected to the WiFi network after: ");
    Serial.print(millis());
    Serial.println(" ms");
  }
}

void ConnectMQTT() {
  if (!client.connected()) {  
    client.setServer(mqttServer, mqttPort);
    client.setCallback(callback);
    
    while (!client.connected()) {
      Serial.print("Connecting to MQTT (");
      Serial.print(mqttServer);
      Serial.println(") ...");
   
      if (client.connect("Wemos_1",mqttUser,mqttPassword)) {
        Serial.println("connected to MQTT");  
      } else {
        Serial.print("failed with state ");
        Serial.println(client.state());
        delay(3000);
      }
    }
    String text="Hello (" + String(random(1000)) + ")";
    
    client.subscribe("control/Wemos_1/RGB_LED");
    client.publish("debug",text.c_str());
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  // Parameter verarbeiten
    String Top=String((char*)topic);
    byte msgByte[length+1];    //Temporäres Byte-Array um Null-Byte anhängen zu können
    for (int i = 0; i < length; i++) {
        msgByte[i] = payload[i];
    }
    msgByte[length] = '\0';
    String msg=String((char*)msgByte); //Mit (char*) wird ein Typecast vom Byte-Pointer msgByte zu einem char-Pointer durchgeführt. Dieser kann von der Stringfunktion in einen String umgewandelt werden.
    Serial.print("Received message [");
    Serial.print(Top);
    Serial.print("]: ");
    Serial.println(msg); 
  }

Danke schon mal für den ein oder anderen Tipp... Bin ziemlich ratlos...
Gruß Tobi

Ist der Port der Richtige für HTTPS?
Welchen HTTPS-Client benutzt Du?

Ich sehe nirgendwo, dass Du den SHA256-Code des Servers (setFingerprint) setzt.

Gruß Tommy

Der Port sollte stimmen. Zumindest ist das der Standardport für SSL/TLS bei MQTT.
Ich nutze (eigentlich?) keinen HTTPS-Client. Ich kommuniziere nur mit dem MQTT-Broker. Das ist bei mir mosquitto auf einem raspberry pi... Lässt sich bei MQTT überhaupt von HTTPS sprechen?

Zum Fingerprint: Wie ich oben schon geschrieben habe, ist der Umstand des fehlenden Fingerprints vielleicht ein Sicherheitsproblem, aber doch kein Grund keine Verbindung aufbauen zu können oder? Zumindest konnte ich auf einem ESP32 eine Verbindung ebenfalls ohne Fingerprint aufbauen...

Ich möchte erst die Verbindung so hinbekommen, dann kann ich mich daran machen, die Sache mit dem Fingerprint hinzuzufügen dachte ich mir. So weiß ich zumindest schon, dass nicht meine Fingerprint-Implementierung Schuld sein kann? Oder ist das hier etwa zwingend erforderlich für einen erfolgreichen Verbindungsaufbau?

Gruß Tobi

Bei BearSSL ist es Pflicht oder Du musst setInsecure benutzen.
Der normale Client kann keine verschlüsselte Verbindung handeln, wird also da auch keine eröffnen.

ESP32 != ESP8266

Gruß Tommy

hm... ich dachte das ist optional den Fingerprint zu prüfen oder nicht...

Aber ich hab dennoch Probleme, das umzusetzen. Ich glaub ich verwende gar kein BearSSL oder woran erkenne ich das denn überhaupt in meinem Code oben? Sry, bin da leider nicht so sehr in der Materie...

Ich verwende ja WiFiClientSecure und nicht BearSSL, verstehe ich da grad was total falsch?

Wie/Wo in meinem oberen Code muss ich denn setInsecure() implementieren?

Aus Mangel an besseren Ideen habe ich jetzt auch noch meinen Code wie folgt angepasst (praktisch mich an mqtt-mosquitto-esp8266-tls gehalten:

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>

#include <PubSubClient.h>


char* ssid = "WLAN-XYZ";
char* password =  "73366094292006561972";

char* mqttServer = "192.168.178.35";
int mqttPort = 8883;


const char* mqttUser = "esp32";
const char* mqttPassword = "K489CQpy9";

const char* mqtt_fprint ="01:CF:4E:E8:29:E0:EC:1A:A0:63:98:CC:52:2A:A4:81:DD:C0:BB:5E";

WiFiClientSecure espClient;

PubSubClient client(espClient);

void setup() {
  Serial.begin(9600);
  ConnectWLAN();
  ConnectMQTT();

}

void loop(){
  client.loop();  //allow the client to process incoming messages and maintain its connection to the server
}


void ConnectWLAN() {
  if (WiFi.status() != WL_CONNECTED) {
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
      Serial.print("WiFi.status: ");
      Serial.println(WiFi.status());
      if (WiFi.status()==4) {
        Serial.println("Disconnecting...");
        //ESP.restart();
            WiFi.disconnect();
            WiFi.begin(ssid, password);
            delay(1000);
      }
    // wait 1 second for re-trying
      delay(1000);
      Serial.println("Connecting to WiFi..");
    }
    Serial.print("Connected to the WiFi network after: ");
    Serial.print(millis());
    Serial.println(" ms");
  }
}

void ConnectMQTT() {
  if (!client.connected()) {  
    client.setServer(mqttServer, mqttPort);
    client.setCallback(callback);
    
    while (!client.connected()) {
      //verifyFingerprint();
      Serial.print("Connecting to MQTT (");
      Serial.print(mqttServer);
      Serial.println(") ...");
   
      if (client.connect("Wemos_1",mqttUser,mqttPassword)) {
        Serial.println("connected to MQTT");  
      } else {
        Serial.print("failed with state ");
        Serial.println(client.state());
        delay(3000);
      }
    }
    String text="Hello (" + String(random(1000)) + ")";
    
    client.subscribe("control/Wemos_1/RGB_LED");
    client.publish("debug",text.c_str());
  }
}

void verifyFingerprint() {
  if(client.connected() || espClient.connected()) return; //Already connected
  
  Serial.print("Checking TLS @ ");
  Serial.print(mqttServer);
  Serial.print("...");
  
  if (!espClient.connect(mqttServer, mqttPort)) {
    Serial.println("Connection failed. Rebooting.");
    Serial.flush();
    delay(15000);
    ESP.restart();
  }
  if (espClient.verify(mqtt_fprint, mqttServer)) {
    Serial.print("Connection secure -> .");
  } else {
    Serial.println("Connection insecure! Rebooting.");
    Serial.flush();
    delay(15000);
    ESP.restart();
  }
 
  espClient.stop();
 
  delay(100);
}

void callback(char* topic, byte* payload, unsigned int length) {
  // Parameter verarbeiten
    String Top=String((char*)topic);
    byte msgByte[length+1];    //Temporäres Byte-Array um Null-Byte anhängen zu können
    for (int i = 0; i < length; i++) {
        msgByte[i] = payload[i];
    }
    msgByte[length] = '\0';
    String msg=String((char*)msgByte); //Mit (char*) wird ein Typecast vom Byte-Pointer msgByte zu einem char-Pointer durchgeführt. Dieser kann von der Stringfunktion in einen String umgewandelt werden.
    Serial.print("Received message [");
    Serial.print(Top);
    Serial.print("]: ");
    Serial.println(msg); 
}

Bleibt leider beim gleichen Fehler...

Viele Grüße
Tobi

Dann schau mal in die WiFiClientSecure.h, die in Deiner IDE liegt. Da siehst Du, welche Implementierung angezogen wird.

Gruß Tommy

Moin zusammen,

wie ist der Status? Gibt es mittlerweile eine Routine/Lösung, wie der ESP8266 gesichert mit dem Broker kommunizert? Leider ist der Chat hier abgebrochen...

Auch Mama Google hat mir nicht geholfen, wie ich den D1mini mit TLS zum Broker verbinden kann.

Vielen Dank und schönen Sonntag noch!

Ralf

PS: gibt es ggf. eine alternative zum PubSubClient?

Ihr Lieben,

ich habe es dank dieses Videos ( ESP8266/ESP32 connecting to SSL/TLSv1.2 secured Mosquitto MQTT Broker - YouTube ) selber hinbekommen. Der Youtuber ist nicht so gut zu verstehen, aber es geht..

für mich : ~erledigt~

Schönen Restsonntag noch!

Ralf

Es wäre für Andere, die ebenfalls nach einer Lösung suchen, gut, wenn Du die Lösung hier posten würdest.

Gruß Tommy

@tommy56: Das mache ich morgen!

Gruß Ralf

PS: Ist im Video eigendlich ganz gut erklärt; auf Englisch; ... Falls jemand Hilfe braucht, dann kann er/sie mich gerne anschreiben.

Es ist in Foren üblich, dass die Lösung im Forum präsentiert wird.

Gruß Tommy

Ok... Ich versuche es mal, ohne das Rad gleich neu zu erfinden...

Mosquitto mit letsencrypt Zertifikaten laufen lassen habe ich hier entnommen.

Das wird im Video (oben) ab 5m26 auch noch einmal erklärt: Video

Ab 7m16s wird erklärt, wie die Zertifkikate für die weitere Nutzung des ESP kopiert / geholt werden können.

Diese Zertifikate werden dann für die secrets.h benötigt:
Für den PUB-KEY benötigt man den output dieses Befehls: openssl x509 -pubkey -noout -in ca.crt

und für den Fingerprint: openssl x509 -fingerprint -in ca.crt

Die Dateien der main.cpp und secret.h liegen auf GitHub

Ich glaube das war es..

Falls Fragen sind, bitte schreibt mir ne PN..
Ralf

Danke für die Infos.

Gruß Tommy