SSL-соединение ESP32 работает, когда сертификат CA является константой, но не при чтении из файла

У меня есть следующий код Arduino, который я использую с ESP32:

  if(!SPIFFS.begin(true)) {
    Serial.println("Error mounting SPIFFS.");
  }

  File file = SPIFFS.open("/root.cer");

  if(!file) {
    Serial.println("Error opening the file.");
  }


  Serial.println("CA Root certificate: ");

  String ca_cert = file.readString();

  Serial.println(ca_cert);
  espClient.setCACert(ca_cert.c_str());

  file.close();

Это соответствующий код для загрузки файла и установки сертификата ЦС WiFiClientSecure. Этот код не работает.

Однако, если я заменю espClient.setCACert(ca_cert.c_str()); на espClient.setCACert(ROOTCERT);, где ROOTCERT определено как таковое:

#define ROOTCERT "-----BEGIN CERTIFICATE-----\n" \
"MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/\n" \
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" \
"DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow\n" \
"PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD\n" \
"Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" \
"AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O\n" \
"rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq\n" \
"OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b\n" \
"xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n" \
"7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD\n" \
"aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\n" \
"HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG\n" \
"SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69\n" \
"ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr\n" \
"AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz\n" \
"R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5\n" \
"JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo\n" \
"Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n" \
"-----END CERTIFICATE-----\n" 

Код работает.

Строка ROOTCERT берется непосредственно из файла сертификата, поэтому они должны быть идентичными.

Файл сертификата был загружен и экспортирован с помощью экспортера сертификатов Windows. Я пытался преобразовать окончания строк безрезультатно.

РЕДАКТИРОВАТЬ: я нашел подсказку.

Если я сделаю следующее:

String constString = ROOTCERT;
espClient.setCACert(constString.c_str());

Это также не работает.

И я добавил этот код:

 if(strcmp(constString.c_str(), ROOTCERT))
     Serial.println("Constant and converted string are equal.");
   else
     Serial.println("Constant and converted string are different.");

И он печатает «Постоянная и преобразованная строка различны».

Значит, это какая-то проблема с тем, как .c_str() что-то делает? Хотя я понятия не имею, что это может быть. При выводе на консоль все .c_str(), ROOTCERT и ca_cert String выглядят ИДЕНТИЧНО.

Я здесь совершенно запутался.

Оказывается, я использовал strcmp() неправильно. Все еще не работает.


person mdszy    schedule 07.06.2019    source источник
comment
Вы убедились, что они идентичны? Пробовали ли вы, чтобы ваш код сравнивал сертификат, который вы прочитали, с тем, который работает?   -  person romkey    schedule 08.06.2019
comment
У меня есть. Они одинаковые. Тем не менее, я добавил редактирование, которое, кажется, является ключом к тому, что происходит.   -  person mdszy    schedule 08.06.2019
comment
Ваше условие с strcmp() неверно. strcmp() возвращает 0 (ложь), если строки равны - у вас это наоборот.   -  person romkey    schedule 09.06.2019
comment
Тем не менее, он все еще сломан.   -  person mdszy    schedule 09.06.2019
comment
Если перед вызовом espClient.setCACert() вы добавите код, похожий на if(strcmp(ROOTCERT, ca_cert.c_str())) Serial.println("certificates differ"); else Serial.println("certificates identical");, какой результат вы увидите?   -  person romkey    schedule 09.06.2019
comment
Я предполагаю, что мне нужно сравнить результат strcmp() с 0, как вы сказали ранее, и я получаю идентичные сертификаты.   -  person mdszy    schedule 09.06.2019
comment
Код, который я написал, учитывает, что strcmp() возвращает 0 для равенства. Если вы добавите к нему == 0, вы перевернете его значение. Мне нужно точно знать, что вы добавили, чтобы понять, что означают результаты. Не могли бы вы вставить строки, которые вы добавили в комментарий?   -  person romkey    schedule 09.06.2019
comment
Я добавил if(strcmp(ROOTCERT, ca_cert.c_str()) == 0) Serial.println("Certs are the same."); else Serial.println("Certs are different.")   -  person mdszy    schedule 09.06.2019


Ответы (1)


Повозившись, я исправил это.

Итак, .c_str() — это просто еще один способ указать на внутренний буфер объекта String.

Как-то это все портило. Использование этого кода исправило это.

char *dest;

dest = (char *)malloc(sizeof(char) * (ca_cert.length()+1));
strcpy(dest, ca_cert.c_str());

espClient.setCACert(dest);
person mdszy    schedule 09.06.2019