Arduino-esp32: Can't specify CA Certificate with WifiClientSecure

Created on 16 Feb 2017  路  10Comments  路  Source: espressif/arduino-esp32

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).

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:

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";

All 10 comments

I have not per say tested that, but you can find the source of the Arduino library here and the IDF lib here.

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DrewHoyt picture DrewHoyt  路  4Comments

maxpromer picture maxpromer  路  3Comments

AsafFisher picture AsafFisher  路  4Comments

docloulou picture docloulou  路  3Comments

lonerzzz picture lonerzzz  路  3Comments