ESP32通过TLS连接Mosquitto MQTT Broker证书验证失败问题
Looking at your error messages—Certificate verification failed on ESP32 and sslv3 alert bad certificate in Mosquitto logs—this boils down to a mismatch or misconfiguration in how your ESP32 is handling the TLS certificate chain, or how Mosquitto is configured to present its credentials. Let’s break down the most likely fixes step by step:
1. Use the CA Certificate, Not the Broker’s Server Certificate
Your current code uses secureClient.setCACert(mosq_cert) with what looks like the Mosquitto server’s certificate. This is incorrect: the ESP32 needs the root CA certificate that signed the broker’s server certificate to validate its authenticity. If you used OpenSSL to self-sign your certificates, you should have a separate ca.crt file—use that content for mosq_cert instead.
2. Fix Certificate Formatting Issues
Manual string concatenation with "..." can introduce hidden formatting errors (like missing newlines or extra spaces) that break TLS validation. Use a raw string literal to embed your certificate cleanly:
const char* ca_cert PROGMEM = R"EOF( -----BEGIN CERTIFICATE----- MIIFtTCCA52gAwIBAgIUK5VYs14dyCApkwl0eKBp2/Tt5dswDQYJKoZIhvcNAQEN BQAwajEXMBUGA1UEAwwOQW4gTVFUVCBicm9rZXIxFjAUBgNVBAoMDU93blRyYWNr ... (full CA certificate content) -----END CERTIFICATE----- )EOF";
Remove any leading/trailing blank lines in the certificate content—WiFiClientSecure is strict about valid PEM formatting.
3. Sync ESP32 System Time
TLS certificate validation checks the certificate’s expiration date. If your ESP32 doesn’t have an accurate system time, it will reject valid certificates. Add NTP sync right after connecting to WiFi:
configTime(28800, 0, "pool.ntp.org", "time.nist.gov"); // 28800 = UTC+8 offset time_t now = time(nullptr); while (now < 1600000000) { // Wait until time is synced to 2020+ delay(1000); now = time(nullptr); Serial.println("Waiting for time sync..."); }
4. Verify Mosquitto Configuration
Ensure your Mosquitto mosquitto.conf is set up correctly for TLS without requiring client certificates (since your ESP32 code doesn’t provide one):
listener 8883 cafile /path/to/your/ca.crt certfile /path/to/your/server.crt keyfile /path/to/your/server.key require_certificate false # Critical—disable if you don't use client certs
If require_certificate is set to true, Mosquitto will reject connections without a valid client certificate, triggering the "bad certificate" error.
5. Fix Hostname/IP Mismatch
Your certificate’s Common Name (CN) is "An MQTT broker"—this doesn’t match the IP or domain you’re using to connect to the broker. TLS requires the server’s hostname/IP to match the CN or Subject Alternative Name (SAN) in the certificate. To fix this:
- Regenerate your certificate with a CN that matches your broker’s IP or domain (add a SAN field for IP if connecting via IP)
- Or, for testing only, disable hostname validation on the ESP32 (not recommended for production):
secureClient.setInsecure();
Modified Example Code
Here’s a cleaned-up version of your code incorporating the fixes above:
#include <WiFi.h> #include <WiFiClientSecure.h> #include <PubSubClient.h> const char* ssid = "your_wifi_ssid"; const char* password = "your_wifi_password"; const char* mqtt_server = "broker_ip_or_domain"; const int mqtt_port = 8883; const char* clientId = "esp32_client"; WiFiClientSecure secureClient; PubSubClient client(secureClient); // Root CA certificate (raw string literal) const char* ca_cert PROGMEM = R"EOF( -----BEGIN CERTIFICATE----- MIIFtTCCA52gAwIBAgIUK5VYs14dyCApkwl0eKBp2/Tt5dswDQYJKoZIhvcNAQEN BQAwajEXMBUGA1UEAwwOQW4gTVFUVCBicm9rZXIxFjAUBgNVBAoMDU93blRyYWNr cy5vcmcxFDASBgNVBAsMC2dlbmVyYXRlLUNBMSEwHwYJKoZIhvcNAQkBFhJub2Jv ZHlAZXhhbXBsZS5uZXQwHhcNMjAxMjA5MTIzMjU3WhcNMzIxMjA2MTIzMjU3WjBq MRcwFQYDVQQDDA5BbiBNUVRUIGJyb2tlcjEWMBQGA1UECgwNT3duVHJhY2tzLm9y ZzEUMBIGA1UECwwLZ2VuZXJhdGUtQ0ExITAfBgkqhkiG9w0BCQEWEm5vYm9keUBl eGFtcGxlLm5ldDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL5CDqte kUzk75gYwgijZ1qzW962FSmtNntE1xONg2r2qsOgZoebNlTVJhy84OpiY+BV9wO9 JsJKg8xt1S5a85t2xk2reaesKr4bYz8QEzWtffKXyJ2Giv5zQF7hxsyhsamQ3IxU y6CcILxFS2Ig5ZSAvPNX7Hz1AtUpLAewu70Wyr+nSO318UnMVwczsotV0GTqI9KZ 4qZRhhEzRkYtk1HegqJ1k4QIKCktTCre4uW9r14NwB6q+Bei8Tz19jM0ubGjZX77 OYJY5LjWABNeYPi9aNDFs7cF7LqxPNsFT2z/Vj/qSg/5ISlhPs6PqG2shmZhbl8l nD4SfdKfJM6Zt3HpFuk1UyyXyBrscsaxKK99dbGrvul3iv+LyGBw2KQw3MsbZrqo o4sXLvz9TReZPqUZsfHj1mwU+dl6hV3Zg8I/E/gc9dIQibjRHAXxAZl/rR/UAkw8 HqqntiX5zid8bJ1vaYvJ5WFoAZPelDWrWLKOem4gy6h7+yeqXbAbcu8W2B89vG3k yE674ZKTsJ6vnchJqUGylrjbtieHI3hRL7vYhqKgbIuFZHZIFM1uBcOVptNL0yNp y2wL3xEMuElO5hJtmQMoobA8x5VfO5DWvNXa6vCv0OhXmXKq1k3rNfoInwEDi6Sg wJsyj9ig0IQTKP7kpyoO3sU5e7DXoJRf22vJAgMBAAGjUzBRMB0GA1UdDgQWBBTu jgPMXmq0vJKREyEp7TK2d05bVjAfBgNVHSMEGDAWgBTujgPMXmq0vJKREyEp7TK2 d05bVjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDQUAA4ICAQB+IGnyMcVA C1P+s5KDAmKI0SLP0b2jHuoTNq4O91lUjywhjgq81fVUu7WDBZhrvah5u1DPemev OypBYA9HIOYUuOKVXDivcKvP4C1+g9lOnrV9NMp66KHTZHCfBxgPmzxS9jGuJJgX nrs+XiJNNRFRFX76OlgXDjP3wIBSZ/00BBNLW1tt4Ti8LokuwM/gKfrSZDjbBkNC Jq3KZyL6pFcV7C9Xec4wl9Q9+2SE85WlZojoBCx7ElANDnt7YkRHKepb0vjsb7ZG xfHnHCS4yQPT/TLtwkDsvJe2tm/SkxFB2MfB7+tWV+/21YuFQpNaRHZXwLa/mZNG +qii1SGnBpBUl6YgTFA++mQqwEkxQGhrFf2FugdkzxAyQfGzvfIMcichMFS5uRgB +Z4ShbsvIjPiQN97QOS516M6+aUywrEStdzkacwoA443pXxJxCim6lTQMe2nT01F kOTd6yGLFkxWnOPIJCw9VsPCyRsUkJhqvAGrWsm8IT6BZcCPcvHYO8q7/u0g6if1 RHfX7LIZdB5f0NLmQedgyte70byjRGFVNfzHP65oYbuNCTFpPdJ1CMg/HXDNxYNd v/NTKIYsanoPeHZgp/6lX44NVIaoU9uNEpr+GePgfE/+r+OoIG2nx2zgcvhJAdjF pXVIrrNIAF3BIGK1Qop/KK+gaY/L8d+raQ== -----END CERTIFICATE----- )EOF"; void callback(char* topic, byte* payload, unsigned int length) { // Handle incoming messages here } void setup() { Serial.begin(115200); // Connect to WiFi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nConnected to WiFi"); // Sync system time via NTP configTime(28800, 0, "pool.ntp.org", "time.nist.gov"); time_t now = time(nullptr); while (now < 1600000000) { delay(1000); now = time(nullptr); Serial.println("Waiting for time sync..."); } Serial.println("Time synced successfully"); // Configure TLS client secureClient.setCACert(ca_cert); // Uncomment below only for testing (disables hostname validation) // secureClient.setInsecure(); // Configure MQTT client client.setServer(mqtt_server, mqtt_port); client.setCallback(callback); // Connect to MQTT broker while (!client.connect(clientId)) { Serial.print("Connection failed, rc="); Serial.print(client.state()); Serial.println(" - retrying in 2s"); delay(2000); } Serial.println("Connected to MQTT broker!"); } void loop() { client.loop(); }
Start with the first two fixes (using the CA cert and fixing formatting)—these are the most common culprits. If that doesn’t work, move on to time sync, Mosquitto config, and hostname matching.
内容的提问来源于stack exchange,提问作者user14389193

