Hi
I am using a NodeMCU Esp8266 to send some sensor data to my Server using MQTT. I have my own CA certificate generated by my server for the SSL connection. This is an extension of https://forum.arduino.cc/t/secure-mqtt-in-arduino-uno-esp-8266/1140681 topic. A separate topic was created because the type and scope of the problem changed significantly.
Initially, I was unable to connect to my server over SSL but I could connect to my server after I included the following line in my code.
wifiClient.setInsecure()
But I think this makes my CA Certificate useless as I tried to replace it with some garbage string and was still able to connect to the server.
I think this makes my communication insecure. Is there any way to make my data sending secure?
I am still able to perfectly use my Python code in the first post on earlier topic to send data to my server properly.
In your code, the line wifiClient.setInsecure(); is basically telling the ESP8266 to ignore the certificate validation and connect insecurely. This is why you are able to connect even when using an incorrect certificate.
What you should do instead is to use wifiClient.setTrustAnchors(new BearSSL::X509List(rootCACertificate));. This is the correct way to load your CA certificate into the ESP8266 for it to validate the server's certificate during the SSL handshake.
However, the ESP8266 also needs to validate the date of the certificate, and it needs an accurate system time to do this. It has no Real-Time Clock (RTC), so it won't know the correct time on its own. This means you will also need to set the time on the ESP8266.
Here is how you could modify your setup() function:
void setup() {
Serial.begin(9600);
delay(10);
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi!");
// Configure NTP and get current time
configTime(0, 0, "pool.ntp.org"); // UTC
setClock(); // Wait for time synchronization
// Configure MQTT server and set SSL/TLS options
mqttClient.setServer(mqttServer, mqttPort);
mqttClient.setCallback(callback);
// Load root CA certificate into WiFiClientSecure object
wifiClient.setTrustAnchors(new BearSSL::X509List(rootCACertificate));
// Connect to MQTT broker
connectToMqtt();
}
void setClock() {
time_t now = time(nullptr);
while (now < 8 * 3600 * 2) { // Wait for the NTP time to be set
delay(500);
Serial.print(".");
now = time(nullptr);
}
struct tm timeinfo;
gmtime_r(&now, &timeinfo);
Serial.println(&timeinfo, "%Y/%m/%d %H:%M:%S"); // Print the time
}
In this code, configTime configures the ESP8266 to use the Network Time Protocol (NTP) to get the current time from an NTP server ("pool.ntp.org" in this case). setClock then waits for the time to be set before continuing with the rest of the setup.
Now, with the correct time set and the correct CA certificate loaded, the ESP8266 should be able to securely connect to your MQTT server using SSL/TLS. If it still cannot connect, double-check that your CA certificate is correct and that the server is properly configured for SSL/TLS. Also, keep in mind that the ESP8266 has limited resources, and handling SSL/TLS can be resource-intensive. If your application is complex, you may run into issues due to these resource constraints.
Thank You so Much for this. It is now working and connecting to the MQTT server properly. however, I got an error compiling the following line
Serial.println(&timeinfo, "%Y/%m/%d %H:%M:%S"); // Print the time
Compilation error: no matching function for call to 'println(tm*, const char [18])'
I commented out that print line to upload it and I was able to connect to my server properly.
Also, just out of curiosity, why does the wifiClient.setInsecure(); function enable the esp8266 to connect to a SSL server on port 8883 even without a valid certificate?