MQTT TLS Connection on ESP8266

Hello,

I am pretty new to the whole ESP-IoT-Arduino topic (~1 week ago I bought my first hardware). For a project I am trying to connect my ESP8266 to my MQTT Broker (mosquitto on a raspberrypi). When i'm running following code:

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

const char* cfg_wifi_ssid = "ssid";
const char* cfg_wifi_pwd = "pw";
const char* mqtt_server = "my.rasp.dns";
const unsigned int mqtt_port = 8883;
const char* mqtt_user =   "testUser";
const char* mqtt_pass =   "1234";

const char ca_cert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----

-----END CERTIFICATE-----
)EOF";

WiFiClientSecure espClient;
PubSubClient client(espClient);

void setup() {
  Serial.begin(9600);
  Serial.println("TestMQTT");

  WiFi.mode(WIFI_STA);
  WiFi.begin(cfg_wifi_ssid, cfg_wifi_pwd);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);

  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    verifyFingerprint();
    if (client.connect("huan", mqtt_user, mqtt_pass)) {
      Serial.println("connected");
      client.subscribe("/test");
    }else{
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");

  char message[length + 1];
  for (int i = 0; i < length; i++) {
    message[i] = (char)payload[i];
  }
  message[length] = '\0';
  Serial.println(message);
}

void verifyFingerprint() {
  if(client.connected() || espClient.connected()) return;
  
  Serial.print("Checking TLS @ ");
  Serial.print(mqtt_server);
  Serial.print("...");
  Serial.println("");
  
  BearSSL::X509List cert(ca_cert);
  espClient.setTrustAnchors(&cert);
  
  if (!espClient.connect(mqtt_server, mqtt_port)) {
    Serial.println("Connection failed. Rebooting.");
    ESP.restart();
  }
  if (espClient.verify(ca_cert, mqtt_server)) {
    Serial.print("Connection secure -> .");
  } else {
    Serial.println("Connection insecure! Rebooting.");
    ESP.restart();
  }

  espClient.stop();

  delay(100);
}

unsigned int counter = 0;

void loop() {

  client.loop();
  
  delay(1000);
}

I get this output:

15:24:20.509 -> TestMQTT
15:24:21.052 -> .
15:24:21.052 -> WiFi connected
15:24:21.052 -> IP address:
15:24:21.085 -> xxxxxx
15:24:21.085 -> Attempting MQTT connection...Checking TLS @ xxxxxx...
15:24:22.146 -> Connection secure -> .failed, rc=-2 try again in 5 seconds

So the TLS part seems to be working. However I cannot connect to the broker anymore. Any ideas, why this is happening? Or any advices for improvement?

I would like to learn this stuff really quickly, so be harsh with me.

Thanks in advance.

Edit: When using mosquitto_pub/mosquitto_sub on the raspberrypi with TLS it works without any problems!

So the TLS part seems to be working.

No, it doesn't. The connection failed.

Are you sure the ESP has the necessary information to resolve "my.raspi.dns"? Have you tried to provide an IP address there instead of a DNS name? Keep in mind you cannot use mDNS names as you might use on the Raspberry Pi. The ESP (by default) only knows to resolve DNS host names, mDNS needs much more to get the names resolved.

The code that is responsible for the TLS verification is this:

  if (espClient.verify(ca_cert, mqtt_server)) {
    Serial.print("Connection secure -> .");

And obviously the "Connection secure" is printed in the Serial Monitor. That's why I am pretty sure that the WifiClientSecure can verify the server's certificate.

Or is there anythign i am missing?

Furthermore:

pylon:
Are you sure the ESP has the necessary information to resolve "my.raspi.dns"? Have you tried to provide an IP address there instead of a DNS name?

Yes, I can connect to it without any problem if I replace the WifiClientSecure with a WifiClient. So the DNS name is not the problem

And obviously the "Connection secure" is printed in the Serial Monitor. That's why I am pretty sure that the WifiClientSecure can verify the server's certificate.

Yes, that's true, but nevertheless the TLS connection fails. I agree that you already connected to check the certificate and I cannot find an obvious bug at the moment. I would try to enable the debugging output for the BearSSL part by setting the debug level to SSL+TLS_MEM in the IDE. This should show you what problems the board gets.

You may want to check this out. It's a PoC I've been following to get my MQTT client working.

Posting in reply to this old topic to ensure others find the same info I was searching for.