I am following the Arduino (ESP32) WiFiClientSecure example code - and trying to connect while specifying a CA Certificate, such as:
client.connect(server, 443, test_ca_cert, test_client_cert, test_client_key)
(test_client_cert and test_client_key are NULL pointers). If test_ca_cert is a NULL pointer, the SSL connection is fine.
If I try to specify my own test_ca_cert, I always get:
CA cert: mbedtls_x509_crt_parse returned -0x2180 (which is an error code for "invalid format")
I have tried a multitude of things for the test_ca_cert such as a string with the PEM formatted cleartext (base64 encoded?) certificate, and a raw byte array of the DER certificate. Nothing seems to work.
Is this broken? Has it ever worked? (or been tested) There are no documented examples (that I could find).
So in format is the test_ca_cert (and/or others) supposed to be specified?
You can specify just caCert or Client+key or all 3.
They call the method below. see what it says about certificate format.
You can search on the web about mbedtls certificate formats also.
/**
* \brief Parse one or more certificates and add them
* to the chained list. Parses permissively. If some
* certificates can be parsed, the result is the number
* of failed certificates it encountered. If none complete
* correctly, the first error is returned.
*
* \param chain points to the start of the chain
* \param buf buffer holding the certificate data in PEM or DER format
* \param buflen size of the buffer
* (including the terminating null byte for PEM data)
*
* \return 0 if all certificates parsed successfully, a positive number
* if partly successful or a specific X509 or PEM error code
*/
int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen );
I figured it out by a combination of brute-force, and combing through some embdtls code online. The certificate has to be specified in exactly the format as follows - i.e. by embedding your own newlines in the array:
unsigned char test_ca_cert[] =
"-----BEGIN CERTIFICATE-----\n"
"MIIDpDCCAowCCQC7mCk5Iu3YmDANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMC\n"
"VVMxFjAUBgNVBAgMDU5ldyBIYW1wc2hpcmUxDzANBgNVBAcMBk5hc2h1YTEYMBYG\n"
"A1UECgwPYnJhZGdvb2RtYW4uY29tMR0wGwYDVQQDDBRCcmFkIEdvb2RtYW4gUm9v\n"
"dCBDQTEiMCAGCSqGSIb3DQEJARYTYnJhZEBicmFkZ29kbWFuLmNvbTAeFw0xNDEy\n"
"MDgwMTM2NDJaFw0yNDEyMDUwMTM2NDJaMIGTMQswCQYDVQQGEwJVUzEWMBQGA1UE\n"
"CAwNTmV3IEhhbXBzaGlyZTEPMA0GA1UEBwwGTmFzaHVhMRgwFgYDVQQKDA9icmFk\n"
"Z29vZG1hbi5jb20xHTAbBgNVBAMMFEJyYWQgR29vZG1hbiBSb290IENBMSIwIAYJ\n"
"KoZIhvcNAQkBFhNicmFkQGJyYWRnb2RtYW4uY29tMIIBIjANBgkqhkiG9w0BAQEF\n"
"AAOCAQ8AMIIBCgKCAQEAq0TfPz/2eH1vMhs5wKjZQU5KEpJH8n27jW3cSVPJPRHo\n"
"tn1S14zzaxuMYhZ1LQJgqT3/V9eVJdJkgoW54dgHLZVMb0xRilJPXNtR9WIZI+3r\n"
"6+7sm6OOhmxjOKUuTWdK+Rbx/KGU+xjQjlyw7Ir4hRLmfaNAw7gnZWyzVcJbvg8O\n"
"5JsReO4x4CnDveX0EJK6L9kNpTSLJZoFsVPdA3QJrxUYOw9s7gQYSjxx1SlcXqQQ\n"
"eWyJWF0FSkRcgRo4qu3JiV94kLUwYNno89G5kU1TnlK0d740KK/A3LN686HhtT66\n"
"XTtE/GLP9EUdlNgEkSoa00580iZqxYZBjlswa04qPQIDAQABMA0GCSqGSIb3DQEB\n"
"BQUAA4IBAQBqf27PAMC0cs5qgr6z5nUxSUN+o3Ap0YjNqrvBID0jQNPr3pfW8fy2\n"
"7dGa3ZAGwPnAmMvx2M6UF5GRYA7lAiC/jBmp0qrdekst4FBx5whJL6tt6sSSmeNp\n"
"4dF7OpGFFDeuBj1CJlN7dro+nd+wty9f7rpjNmGcNjD/vGOrk9T67uWB5NYDIrcn\n"
"rBOAVb+yBnDphBH7UIXWnSBCyDGD7SjAnWPQdH6uRAhVrbhIPylC50NwhqjlN5su\n"
"ll2eQ0Vfp5u+viLK441MwfF77CjhFMs50Ahu7y5ApRD9nzMdqav63dU4oKrdOJgK\n"
"yiUGy+6qJ0KK7FyaU4YKbcsqmd/kev9m\n"
"-----END CERTIFICATE-----\n";
Great! :)
Sorry for late answer, but for future reference here is an example of use with certificates: https://github.com/copercini/esp32-iot-examples/blob/master/ESP32_aws_iot/ESP32_aws_iot.ino
Hi @bkgoodman @copercini @me-no-dev
Can i use 1 CA Certificate for more esp32? Or can i get CA certificate with esp not using web browser?
Thanks a lot.
I tried to use my private key as a cert for a long time, thanks :+1:
Hello @bkgoodman , I was having the same issue and finally solved it by using
espClient.loadCACertificate(ca)
after the connect function.
Look at my following working code:
`#include "FS.h"
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
const char* ssid = "Your SSID name";
const char* password = "Your SSID password";
const char* mqtt_server = "test.mosquitto.org"; //MQTT broker ip
//IPAddress server(172, 16, 0, 95);
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
WiFiClientSecure espClient;
//SPIFFS.begin();
//File ca = SPIFFS.open("/mosquitto_or.der", "r");
//if(!ca) {
// Serial.println("FIle not Found!");
// return;
//}
//
//if(espClient.loadCertificate(ca)) {
// Serial.println("Loaded Cert");
//} else {
// Serial.println("Didn't load cert");
// return;
//}
PubSubClient client(mqtt_server,8883,callback,espClient); //set MQTT port number to 8883 as per //standard
long lastMsg = 0;
char msg[50];
int value = 0;
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
File ca = SPIFFS.open("/mosquitto_or.der", "r"); //replace ca.crt eith your uploaded file name
if (!ca) {
Serial.println("Failed to open ca file");
}
else
Serial.println("Success to open ca file");
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("ESP8266Client1")) {
Serial.println("connected");
if(espClient.loadCACert(ca))
Serial.println("loaded");
else
Serial.println("not loaded");
// Once connected, publish an announcement...
client.publish("outTopic", "hello world");
// ... and resubscribe
client.subscribe("inTopic");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
SPIFFS.begin();
setup_wifi();
delay(1000);
if (!SPIFFS.begin()) {
Serial.println("Failed to mount file system");
return;
}
client.setServer(mqtt_server, 8883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
long now = millis();
if (now - lastMsg > 2000) {
lastMsg = now;
++value;
snprintf (msg, 75, "hello world #%ld", value);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("outTopic", msg);
}
}`
Hi,
me too faced same issue. I am using a new platform which does not have file system.
int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen );
I tried with rn at the end for each line. Still no luck.
Finally got the issue, I was using buflen as strlen(buf); buflen should be +1 from the strlen.
(including the terminating null byte for PEM data)
Best of luck
Most helpful comment
I figured it out by a combination of brute-force, and combing through some embdtls code online. The certificate has to be specified in exactly the format as follows - i.e. by embedding your own newlines in the array: