Skip to content

Arduino UNO R4 WiFi: switch to client certificate and private key for authentication #414

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 5, 2024
1 change: 1 addition & 0 deletions .github/workflows/compile-examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ jobs:
- name: Arduino_ConnectionHandler
- name: Arduino_DebugUtils
- name: ArduinoMqttClient
- name: Arduino_SecureElement
# sketch paths to compile (recursive) for all boards
UNIVERSAL_SKETCH_PATHS: |
- examples/ArduinoIoTCloud-Advanced
Expand Down
105 changes: 0 additions & 105 deletions examples/utility/Provisioning/ECCX08TLSConfig.h

This file was deleted.

134 changes: 103 additions & 31 deletions examples/utility/Provisioning/Provisioning.ino
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
#include <ArduinoIoTCloud.h>
#include "ECCX08TLSConfig.h"

const bool DEBUG = true;

ArduinoIoTCloudCertClass Certificate;
CryptoUtil Crypto;
#include <Arduino_SecureElement.h>
#include <utility/SElementArduinoCloud.h>
#include <utility/SElementArduinoCloudCertificate.h>
#include <utility/SElementArduinoCloudDeviceId.h>
#include <utility/SElementCSR.h>

#ifdef ARDUINO_SAMD_MKR1000
#include <WiFi101.h>
#define LATEST_WIFI_FIRMWARE_VERSION WIFI_FIRMWARE_LATEST_MODEL_B
#endif
#if defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_NANO_RP2040_CONNECT)
#include <WiFiNINA.h>
#define LATEST_WIFI_FIRMWARE_VERSION WIFI_FIRMWARE_LATEST_VERSION
#endif
#if defined(ARDUINO_UNOR4_WIFI)
#include <WiFiS3.h>
#define LATEST_WIFI_FIRMWARE_VERSION WIFI_FIRMWARE_LATEST_VERSION
#endif

String promptAndReadLine(const char* prompt, const unsigned int timeout = 0);

void setup() {
Serial.begin(9600);
while (!Serial);

if (!Crypto.begin()) {
SecureElement secureElement;

if (!secureElement.begin()) {
Serial.println("No crypto present!");
while (1);
}

if (!Crypto.locked()) {
if (!secureElement.locked()) {
/* WARNING: This string is parsed from IoTCloud frontend */
String lockConfirm = promptAndReadLine("Your crypto is unlocked, would you like to lock it (y/N): ");
lockConfirm.toLowerCase();

Expand All @@ -24,12 +40,14 @@ void setup() {
while (1);
}

if (!Crypto.writeConfiguration(DEFAULT_ECCX08_TLS_CONFIG)) {
if (!secureElement.writeConfiguration()) {
/* WARNING: This string is parsed from IoTCloud frontend */
Serial.println("Writing crypto configuration failed!");
while (1);
}

if (!Crypto.lock()) {
if (!secureElement.lock()) {
/* WARNING: This string is parsed from IoTCloud frontend */
Serial.println("Locking crypto configuration failed!");
while (1);
}
Expand All @@ -38,36 +56,43 @@ void setup() {
Serial.println();
}

String csrConfirm = promptAndReadLine("Would you like to generate a new private key and CSR (y/N): ");
/* WARNING: This string is parsed from IoTCloud frontend */
String csrConfirm = promptAndReadLine("Would you like to generate a new private key and CSR (y/N): ", 5000);
csrConfirm.toLowerCase();

if (csrConfirm != "y") {
Serial.println("That's all folks");
while (1);
}

ECP256Certificate Certificate;

if (!Certificate.begin()) {
Serial.println("Error starting CSR generation!");
while (1);
}

String deviceId = promptAndReadLine("Please enter the device ID: ");
/* WARNING: This string is parsed from IoTCloud frontend */
String deviceId = promptAndReadLine("Please enter the device id: ");
Certificate.setSubjectCommonName(deviceId);

if (!Crypto.buildCSR(Certificate, CryptoSlot::Key, true)) {
if (!SElementCSR::build(secureElement, Certificate, (int)SElementArduinoCloudSlot::Key, true)) {
/* WARNING: This string is parsed from IoTCloud frontend */
Serial.println("Error generating CSR!");
while (1);
}

String csr = Certificate.getCSRPEM();

if (!csr) {
/* WARNING: This string is parsed from IoTCloud frontend */
Serial.println("Error generating CSR!");
while (1);
}

Serial.println("Generated CSR is:");
Serial.println();
/* WARNING: This string is parsed from IoTCloud frontend */
Serial.println(csr);

String issueYear = promptAndReadLine("Please enter the issue year of the certificate (2000 - 2031): ");
Expand All @@ -79,20 +104,21 @@ void setup() {
String authorityKeyIdentifier = promptAndReadLine("Please enter the certificates authority key identifier: ");
String signature = promptAndReadLine("Please enter the certificates signature: ");

byte serialNumberBytes[CERT_SERIAL_NUMBER_LENGTH];
byte authorityKeyIdentifierBytes[CERT_AUTHORITY_KEY_ID_LENGTH];
byte signatureBytes[CERT_SIGNATURE_LENGTH];
byte serialNumberBytes[ECP256_CERT_SERIAL_NUMBER_LENGTH];
byte authorityKeyIdentifierBytes[ECP256_CERT_AUTHORITY_KEY_ID_LENGTH];
byte signatureBytes[ECP256_CERT_SIGNATURE_LENGTH];

hexStringToBytes(serialNumber, serialNumberBytes, sizeof(serialNumberBytes));
hexStringToBytes(authorityKeyIdentifier, authorityKeyIdentifierBytes, sizeof(authorityKeyIdentifierBytes));
hexStringToBytes(signature, signatureBytes, sizeof(signatureBytes));

if (!Crypto.writeDeviceId(deviceId, CryptoSlot::DeviceId)) {
if (!SElementArduinoCloudDeviceId::write(secureElement, deviceId, SElementArduinoCloudSlot::DeviceId)) {
Serial.println("Error storing device ID!");
while (1);
}

if (!Certificate.begin()) {
/* WARNING: This string is parsed from IoTCloud frontend */
Serial.println("Error starting crypto storage!");
while (1);
}
Expand All @@ -111,20 +137,17 @@ void setup() {
Certificate.setIssueHour(issueHour.toInt());
Certificate.setExpireYears(expireYears.toInt());

if (!Crypto.buildCert(Certificate, CryptoSlot::Key)) {
if (!SElementArduinoCloudCertificate::build(secureElement, Certificate, static_cast<int>(SElementArduinoCloudSlot::Key))) {
Serial.println("Error building cert!");
while (1);
}
if (!Crypto.writeCert(Certificate, CryptoSlot::CompressedCertificate)) {

if (!SElementArduinoCloudCertificate::write(secureElement, Certificate, SElementArduinoCloudSlot::CompressedCertificate)) {
Serial.println("Error storing cert!");
while (1);
}

if (!DEBUG) {
return;
}

/* WARNING: This string is parsed from IoTCloud frontend */
Serial.println("Compressed cert = ");

const byte* certData = Certificate.bytes();
Expand All @@ -139,23 +162,72 @@ void setup() {
Serial.print(b, HEX);
}
Serial.println();


String cert = Certificate.getCertPEM();
if (!cert) {
Serial.println("Error generating cert!");
while (1);
}
Serial.println("Cert PEM = ");
Serial.println();
Serial.println(cert);


#ifdef LATEST_WIFI_FIRMWARE_VERSION
Serial.println("Checking firmware of WiFi module...");
Serial.println();
String fv = WiFi.firmwareVersion();
/* WARNING: This string is parsed from IoTCloud frontend */
Serial.print("Current firmware version: ");
/* WARNING: This string is parsed from IoTCloud frontend */
Serial.println(fv);

String latestFv = LATEST_WIFI_FIRMWARE_VERSION;
if (fv >= latestFv) {
/* WARNING: This string is parsed from IoTCloud frontend */
Serial.println("Latest firmware version correctly installed.");
} else {
/* WARNING: This string is parsed from IoTCloud frontend */
String latestFvStr = "The firmware is not up to date. Latest version available: " + latestFv;
Serial.println(latestFvStr);
}
#else
Serial.println();
/* WARNING: This string is parsed from IoTCloud frontend */
Serial.println("Program finished.");
#endif
}

void loop() {
}

String promptAndReadLine(const char* prompt) {
Serial.print(prompt);
String s = readLine();
String promptAndReadLine(const char* prompt, const unsigned int timeout) {
String s = "";
while(1) {
Serial.print(prompt);
s = readLine(timeout);
if (s.length() > 0) {
break;
}
}
Serial.println(s);

return s;
}

String readLine() {
String line;
bool isExpired(const unsigned int start, const unsigned int timeout) {
if (timeout) {
return (millis() - start) > timeout;
} else {
return false;
}
}

while (1) {
String readLine(const unsigned int timeout) {
String line;
const unsigned int start = millis();
while (!isExpired(start, timeout)) {
if (Serial.available()) {
char c = Serial.read();

Expand Down
12 changes: 11 additions & 1 deletion src/AIoTC_Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,21 @@
#define BOARD_STM32H7
#endif

#if defined(ARDUINO_UNOR4_WIFI) || defined(ARDUINO_EDGE_CONTROL)
#if defined(ARDUINO_EDGE_CONTROL)
#define BOARD_HAS_SECRET_KEY
#define HAS_TCP
#endif

#if defined(ARDUINO_UNOR4_WIFI)
#define BOARD_HAS_SOFTSE
#define BOARD_HAS_SECRET_KEY
#define HAS_TCP
#endif

#if defined(BOARD_HAS_SOFTSE) || defined(BOARD_HAS_OFFLOADED_ECCX08) || defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_SE050)
#define BOARD_HAS_SECURE_ELEMENT
#endif

/******************************************************************************
* CONSTANTS
******************************************************************************/
Expand Down
Loading