Защита SSL-сертификата Arduino MKR wifi 1010

wifi mkr1010wifi

Я использую Arduino IDE v2.1.1 и Arduino MKR wifi 1010. Все работает нормально, и в данный момент мне нужно защитить Wi-Fi-соединение с помощью SSL-сертификата. Я сгенерировал сертификат SSL с помощью инструмента openssl, и теперь у меня есть следующие файлы, которые необходимо установить в контроллере:

  • ca.crt
  • client.crt
  • client.key

Как мне установить эти три файла на MKR wifi 1010, чтобы включить связь, защищенную сертификатом SSL? Мне не удалось найти руководство или пример в Интернете.

Позвольте мне объяснить, как я это делаю в данный момент. У меня есть действительный самозаверяющий сертификат ЦС, и я пытаюсь установить соединение SSL/TLS, используя только сертификат ЦС. Это мой код, который, к сожалению, не работает:

#include <WiFiNINA.h>
#include <ArduinoJson.h>
#include <ArduinoMqttClient.h>
#include <ArduinoBearSSL.h>
#include <ArduinoECCX08.h>
#include "secrets.h"

char wifiSsid[] = SECRET_WiFi_SSID;
char wifiPass[] = SECRET_WiFi_PASS;
char mqttUserId[] = MQTT_USERID;
char mqttPass[] = MQTT_PASS;
int status = WL_IDLE_STATUS;
const char* rootCAcertificate  = \
"-----BEGIN CERTIFICATE-----\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"-----END CERTIFICATE-----\n";

bool dev_debug_mode = IS_DEBUG;

WiFiClient    wifiClient;         // Используется для соединения через сокет TCP
BearSSLClient bearSslClient(wifiClient); // Используется для соединения SSL/TLS, интегрируется с ECCX08
MqttClient    mqttClient(bearSslClient); // Используется для использования протокола MQTT

const char mqttBroker[] = MQTT_BROKER_HOST;
int mqttPort = 8883;

const char deviceRegisterTopic[] = "device/register";

//устанавливаем интервал отправки сообщений Observation (измерение с датчика) (миллисекунды)
const long interval = 3000;

unsigned long previousMillis = 0;

bool deviceIsRegistered = false;

void setup() {
  //Инициализируем последовательный порт и ждем открытия порта:
  Serial.begin(9600);
  while (dev_debug_mode && !Serial) {
    ; // ждем подключения последовательного порта. Требуется только для собственного USB-порта — режим разработки. Его необходимо удалить при выпуске вживую!!!
  }

  // Проверяем наличие модуля крипточипа (необходим для BearSSL)
  if (!ECCX08.begin()) {
    Serial.println("No ECCX08 present!");
    while (1);
  }

  bearSslClient.setEccSlot(0, rootCAcertificate); // вставляем сертификат в слот 0 (ноль)

  // ================ НАСТРОЙКА SSL ================
  // Устанавливаем обратный вызов для получения текущего времени
  // (используется для проверки сертификата сервера)
  ArduinoBearSSL.onGetTime(getTime);

  // попытка подключения к сети Wi-Fi
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to network: ");
    Serial.println(wifiSsid);
    // Подключаемся к сети WPA/WPA2:
    status = WiFi.begin(wifiSsid, wifiPass);

    Serial.print("Attempt status: ");
    Serial.println(status);

    if(status != WL_CONNECTED) {
      // ожидание 10 секунд перед попыткой подключения, если это необходимо:
      delay(10000);
    }
  }

  // Соединение с сетью Wi-Fi установлено! отправка некоторых сообщений на консоль
  Serial.println("You're connected to the network");

  Serial.print("Attempting to connect to the MQTT broker: ");
  Serial.println(mqttBroker);
  Serial.println(mqttPort);

  mqttClient.setId(mqttUserId);

  // добавляем первый уровень защиты с использованием имени пользователя и пароля MQTT-брокера
  mqttClient.setUsernamePassword(mqttUserId, mqttPass);

  delay(30000);
  while (!mqttClient.connect(mqttBroker, mqttPort)) {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());
    delay(10000);
  }

  // Соединение MQTT-брокера установлено! отправка некоторых сообщений на консоль
  Serial.println("You're connected to the MQTT broker!");
  Serial.println();
}

void loop() {

  // регулярно вызываем poll(), чтобы библиотека могла отправлять сообщение MQTT в активное состояние, что
  // позволяет избежать отключения брокером
  mqttClient.poll();

  // если это текущее устройство еще не зарегистрировано, регистрируем устройство впервые
  if(!deviceIsRegistered) {
    Serial.print("Sending Device Register message to topic: ");
    Serial.println(deviceRegisterTopic);
    // СДЕЛАЙ ЧТО-НИБУДЬ
  }

  unsigned long currentMillis = millis();

  // отправка фактических данных измерений на сервер FHIR через некоторый интервал времени, например несколько секунд. Будет определено позже.
  if (currentMillis - previousMillis >= interval) {

    // сохраняем последний раз, когда было отправлено сообщение
    previousMillis = currentMillis;

    Serial.println();
  }
}

// ================================= Вспомогательные функции ============ ======================
unsigned long getTime() {
   Serial.print("Current WiFi time:");
   Serial.println(WiFi.getTime());
  // Получаем текущее время от модуля WiFi
  return WiFi.getTime();
}

в приведенном выше коде я использую BearSSLClient, и сертификат устанавливается вручную (я предпочитаю этот способ, поскольку для меня он более прозрачен) bearSslClient.setEccSlot(0, certificate ); — так устанавливается сертификат. Также я делаю следующий вызов: ArduinoBearSSL.onGetTime(getTime); - чтобы успеть. Сертификат CA проверяется с помощью инструмента openssl. Это действительный самозаверяющий корневой сертификат. Пожалуйста, любая помощь очень ценится. Я действительно в замешательстве, так как это должно работать, поскольку сертификат является действительным самозаверяющим сертификатом, и он подтверждается и проверяется с помощью инструмента openssl. Когда что-то должно работать, но не работает, и у меня нет никаких подробностей, кроме сообщения об ошибке -2, это сводит меня с ума ((((

@b1n3t спасибо чуваку за помощь. Я ценю это. Позвольте мне начать с одного: я занимаюсь разработкой программного обеспечения более 16 лет, но с аппаратным обеспечением, таким как микроконтроллеры и оборудование на базе архитектуры i8086, я работал более 10 лет назад. Я никогда глубоко не исследовал проблемы SSL/TLS. Теперь я рассмотрю ваши вопросы один за другим: да, я уверен, что внутренние часы Arduino точны, потому что я настроил себе взаимное соединение TLS с брокером MQTT AWS (Amazon) с включенными этими часами, и все работает нормально. Закрытый ключ может быть неправильно сохранен в ECC608. Это может быть проблемой, поскольку я не уверен на 100%, что сделал это правильно. Да, я проверил, что домен и порт брокера Mosquitto MQTT доступны с устройства, поскольку оно успешно подключается без взаимного TLS. Я могу отправить сообщение обратно и принудительно с устройства на сервер брокера Mosquitto MQ TT без взаимного TLS и без SSL. Да, я настроил Linux-сервер, чтобы разрешить 8883 внешнее соединение. Я использовал инструмент MQTT Explorer для установления взаимного соединения TLS с использованием корневого сертификата CA, сертификатов клиента и сервера с другого физического устройства в моей сети LAN, все работает гладко, он подключается через CA и сертификат клиента к серверу брокера MQTT и Я могу отправлять и получать сообщения. Здесь все хорошо. Позвольте мне захватить журналы и вернуться. Брокер настроен на доверие к ЦС, однако все сертификаты являются самоподписанными. Я боролся с этим уже около пяти дней и понял несколько важных вещей: ECC608 по умолчанию (с завода) находится в разблокированном состоянии, его нельзя использовать, пока он не заблокирован (вручную из кода) . Запрос на подпись сертификата должен быть сгенерирован на устройстве MRK WiFi 1010, а закрытый ключ хранится внутри устройства MKR WiFi 1010, это очень важная деталь. После этого CSR должен быть передан поставщику сертификации, и сертификат sercret должен быть сгенерирован на основе этого CSR (запрос подписи сертификата). Еще одна очень важная деталь заключается в том, что самозаверяющий сертификат, который я использую для разработки, может быть проблемой, поскольку он ВСЕГДА помечен как недействительный только потому, что он самоподписанный.

, 👍2

Обсуждение

Можете ли вы предоставить мне следующую информацию? Недавно я также рассмотрел сообщение -2, так что оно может помочь в устранении неполадок. Вы уверены, что внутренние часы Arduino точны? Вы храните свой закрытый ключ внутри ECC608? Ошибка -2 означает проблему с соединением на уровне сокета. Убедились ли вы, что домен и порт вашего MQTT-брокера доступны с устройства? Вы убедились, что порт 8883 открыт и брандмауэр не блокирует трафик MQTT через SSL? Можете ли вы поделиться своими журналами MQTT Broker? Можете ли вы захватывать SSL-трафик с помощью WireShark и делиться им? Настроен ли брокер доверять ЦС?, @b1n3t

@ b1n3t очень ценю ваш вклад, не могу ответить в комментариях, потому что количество символов ограничено, поэтому я обновил пост ответами., @Semen Shekhovtsov


1 ответ


1

Похоже, вы добились значительного прогресса. Честно говоря, я считаю, что проблема заключается в том, что ваш закрытый ключ не хранится в ECC608.

Если закрытый ключ не будет правильно сохранен в ECC608, рукопожатие TLS завершится неудачно. Вы упомянули, что ECC608 разблокирован по умолчанию. Вы правы: чтобы использовать безопасные функции чипа, его необходимо заблокировать. Однако, насколько я знаю, если он заблокирован, его нельзя разблокировать. Убедитесь, что вы выполнили необходимые шаги для сохранения вашего закрытого ключа в ECC608, а затем заблокировали его, чтобы защитить ключ. Я думаю, вы можете использовать библиотеку ArduinoECCX08, поскольку она, похоже, имеет ECCX08.begin(), ECCX08.lock(), ECCX08. генерироватьPrivateKey(slot). Ваш подход к созданию CSR непосредственно на устройстве MKR WiFi 1010 вполне уместен. Этот метод гарантирует, что закрытый ключ никогда не покинет устройство. Следовательно, в ЦС отправляется только публичная часть, даже если она самоподписанная. С помощью CSR получите сертификат вашего устройства. Этот сертификат в сочетании с закрытым ключом, надежно хранящимся в ECC608, должен облегчить установление связи TLS.

TL;DR: убедитесь, что вы правильно сохранили закрытый ключ в ECC608. Прежде чем блокировать ECC608, проверьте, работает ли закрытый ключ должным образом. Проверьте журналы брокера MQTT для дальнейшей отладки (если они будут предоставлены и когда у меня будет для этого время, я сделаю все возможное, чтобы точно определить ошибку) и попробуйте использовать WireShark для захвата SSL-трафика.

Насколько мне известно, удачи вам. Надеюсь, я смогу помочь, чувак.

,

привет. Не могли бы вы взглянуть на обновления в моем сегодняшнем вопросе? Эта проблема с SSL/TLS до сих пор не решена, и я понятия не имею, как с ней справиться., @Semen Shekhovtsov

@SemenShekhotsov я немного занят пару дней, когда будет время, постараюсь помочь., @b1n3t