From 2f6cf5073c2933598b7920e1e386b5c9049a4a10 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 2 Feb 2024 16:12:07 +0100 Subject: [PATCH 01/10] Switch to Arduino_SecureElement library --- .../utility/Provisioning/ECCX08TLSConfig.h | 105 -- src/AIoTC_Config.h | 7 +- src/ArduinoIoTCloudTCP.cpp | 58 +- src/ArduinoIoTCloudTCP.h | 93 +- src/tls/AIoTCSSCert.h | 4 +- src/tls/utility/Cert.cpp | 918 ------------------ src/tls/utility/Cert.h | 187 ---- src/tls/utility/CryptoUtil.cpp | 211 ---- src/tls/utility/CryptoUtil.h | 91 -- 9 files changed, 86 insertions(+), 1588 deletions(-) delete mode 100644 examples/utility/Provisioning/ECCX08TLSConfig.h delete mode 100644 src/tls/utility/Cert.cpp delete mode 100644 src/tls/utility/Cert.h delete mode 100644 src/tls/utility/CryptoUtil.cpp delete mode 100644 src/tls/utility/CryptoUtil.h diff --git a/examples/utility/Provisioning/ECCX08TLSConfig.h b/examples/utility/Provisioning/ECCX08TLSConfig.h deleted file mode 100644 index 9126b3666..000000000 --- a/examples/utility/Provisioning/ECCX08TLSConfig.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - This file is part of ArduinoIoTCloud. - - Copyright 2019 ARDUINO SA (http://www.arduino.cc/) - - This software is released under the GNU General Public License version 3, - which covers the main part of arduino-cli. - The terms of this license can be found at: - https://www.gnu.org/licenses/gpl-3.0.en.html - - You can be released from the requirements of the above licenses by purchasing - a commercial license. Buying such a license is mandatory if you want to modify or - otherwise use the software for commercial activities involving the Arduino - software without disclosing the source code of your own applications. To purchase - a commercial license, send an email to license@arduino.cc. -*/ - -#ifndef _ECCX08_TLS_CONFIG_H_ -#define _ECCX08_TLS_CONFIG_H_ - -const byte DEFAULT_ECCX08_TLS_CONFIG[128] = { - // Read only - start - // SN[0:3] - 0x01, 0x23, 0x00, 0x00, - // RevNum - 0x00, 0x00, 0x50, 0x00, - // SN[4:8] - 0x00, 0x00, 0x00, 0x00, 0x00, - // Reserved - 0xC0, - // I2C_Enable - 0x71, - // Reserved - 0x00, - // Read only - end - // I2C_Address - 0xC0, - // Reserved - 0x00, - // OTPmode - 0x55, - // ChipMode - 0x00, - // SlotConfig - 0x83, 0x20, // External Signatures | Internal Signatures | IsSecret | Write Configure Never, Default: 0x83, 0x20, - 0x87, 0x20, // External Signatures | Internal Signatures | ECDH | IsSecret | Write Configure Never, Default: 0x87, 0x20, - 0x87, 0x20, // External Signatures | Internal Signatures | ECDH | IsSecret | Write Configure Never, Default: 0x8F, 0x20, - 0x87, 0x2F, // External Signatures | Internal Signatures | ECDH | IsSecret | WriteKey all slots | Write Configure Never, Default: 0xC4, 0x8F, - 0x87, 0x2F, // External Signatures | Internal Signatures | ECDH | IsSecret | WriteKey all slots | Write Configure Never, Default: 0x8F, 0x8F, - 0x8F, 0x8F, - 0x9F, 0x8F, - 0xAF, 0x8F, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0xAF, 0x8F, - // Counter[0] - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - // Counter[1] - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - // LastKeyUse - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - // Write via commands only - start - // UserExtra - 0x00, - // Selector - 0x00, - // LockValue - 0x55, - // LockConfig - 0x55, - // SlotLocked - 0xFF, 0xFF, - // Write via commands only - end - // RFU - 0x00, 0x00, - // X509format - 0x00, 0x00, 0x00, 0x00, - // KeyConfig - 0x33, 0x00, // Private | Public | P256 NIST ECC key, Default: 0x33, 0x00, - 0x33, 0x00, // Private | Public | P256 NIST ECC key, Default: 0x33, 0x00, - 0x33, 0x00, // Private | Public | P256 NIST ECC key, Default: 0x33, 0x00, - 0x33, 0x00, // Private | Public | P256 NIST ECC key, Default: 0x1C, 0x00, - 0x33, 0x00, // Private | Public | P256 NIST ECC key, Default: 0x1C, 0x00, - 0x1C, 0x00, - 0x1C, 0x00, - 0x1C, 0x00, - 0x3C, 0x00, - 0x3C, 0x00, - 0x3C, 0x00, - 0x3C, 0x00, - 0x3C, 0x00, - 0x3C, 0x00, - 0x3C, 0x00, - 0x1C, 0x00 -}; - -#endif /* _ECCX08_TLS_CONFIG_H_ */ diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index 3238c0952..7692e2f46 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -118,11 +118,16 @@ #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 HAS_TCP +#endif + /****************************************************************************** * CONSTANTS ******************************************************************************/ diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 5d284d671..e307efaa9 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -24,23 +24,16 @@ #ifdef HAS_TCP #include +#ifdef BOARD_HAS_SECRET_KEY + #include "tls/AIoTCUPCert.h" +#endif + #ifdef BOARD_HAS_ECCX08 #include "tls/BearSSLTrustAnchors.h" - #include "tls/utility/CryptoUtil.h" #endif -#ifdef BOARD_HAS_SE050 +#if defined(BOARD_HAS_SE050) || defined(BOARD_HAS_SOFTSE) #include "tls/AIoTCSSCert.h" - #include "tls/utility/CryptoUtil.h" -#endif - -#ifdef BOARD_HAS_OFFLOADED_ECCX08 - #include - #include "tls/utility/CryptoUtil.h" -#endif - -#ifdef BOARD_HAS_SECRET_KEY - #include "tls/AIoTCUPCert.h" #endif #if OTA_ENABLED @@ -90,9 +83,9 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP() #ifdef BOARD_HAS_ECCX08 , _sslClient(nullptr, ArduinoIoTCloudTrustAnchor, ArduinoIoTCloudTrustAnchor_NUM, getTime) #endif - #ifdef BOARD_HAS_SECRET_KEY +#ifdef BOARD_HAS_SECRET_KEY , _password("") - #endif +#endif , _mqttClient{nullptr} , _deviceTopicOut("") , _deviceTopicIn("") @@ -137,43 +130,50 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, DEBUG_VERBOSE("SHA256: HASH(%d) = %s", strlen(_ota_img_sha256.c_str()), _ota_img_sha256.c_str()); #endif /* OTA_ENABLED */ -#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) || defined(BOARD_HAS_SE050) +#if !defined(BOARD_HAS_SECRET_KEY) if (!_crypto.begin()) { DEBUG_ERROR("_crypto.begin() failed."); return 0; } - if (!_crypto.readDeviceId(getDeviceId(), CryptoSlot::DeviceId)) + if (!SElementArduinoCloudDeviceId::read(_crypto, getDeviceId(), SElementArduinoCloudSlot::DeviceId)) { DEBUG_ERROR("_crypto.readDeviceId(...) failed."); return 0; } #endif -#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_SE050) - if (!_crypto.readCert(_cert, CryptoSlot::CompressedCertificate)) +#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_SE050) || defined(BOARD_HAS_SOFTSE) + if (!SElementArduinoCloudCertificate::read(_crypto, _cert, SElementArduinoCloudSlot::CompressedCertificate)) { DEBUG_ERROR("Cryptography certificate reconstruction failure."); return 0; } - _sslClient.setEccSlot(static_cast(CryptoSlot::Key), _cert.bytes(), _cert.length()); + _sslClient.setEccSlot(static_cast(SElementArduinoCloudSlot::Key), _cert.bytes(), _cert.length()); #endif -#if defined(BOARD_HAS_ECCX08) + +#if defined(BOARD_HAS_SECRET_KEY) + #if defined(ARDUINO_EDGE_CONTROL) + _sslClient.appendCustomCACert(AIoTUPCert); + #elif defined(ARDUINO_ARCH_ESP32) + _sslClient.setCACertBundle(x509_crt_bundle); + #else + _sslClient.setInsecure(); + #endif +#else + #if defined(BOARD_HAS_ECCX08) _sslClient.setClient(_connection->getClient()); -#elif defined(ARDUINO_PORTENTA_C33) + #elif defined(BOARD_HAS_SE050) + #if defined(ARDUINO_PORTENTA_C33) _sslClient.setClient(_connection->getClient()); _sslClient.setCACert(AIoTSSCert); -#elif defined(BOARD_HAS_SE050) + #else _sslClient.appendCustomCACert(AIoTSSCert); -#elif defined(BOARD_ESP) - #if defined(ARDUINO_ARCH_ESP8266) - _sslClient.setInsecure(); - #else - _sslClient.setCACertBundle(x509_crt_bundle); + #endif + #elif defined(BOARD_HAS_SOFTSE) + _sslClient.setCACert(AIoTSSCert, strlen(AIoTSSCert)); #endif -#elif defined(ARDUINO_EDGE_CONTROL) - _sslClient.appendCustomCACert(AIoTUPCert); #endif _mqttClient.setClient(_sslClient); diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index 30ce1e27f..a36abfef3 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -23,31 +23,37 @@ ******************************************************************************/ #include - #include +#include -#ifdef BOARD_HAS_ECCX08 - #include "tls/BearSSLClient.h" - #include "tls/utility/CryptoUtil.h" -#elif defined(BOARD_ESP) - #include -#elif defined(ARDUINO_UNOR4_WIFI) - #include -#elif defined(ARDUINO_PORTENTA_C33) - #include "tls/utility/CryptoUtil.h" - #include -#elif defined(BOARD_HAS_SE050) - #include "tls/utility/CryptoUtil.h" - #include -#endif - -#ifdef BOARD_HAS_OFFLOADED_ECCX08 -#include "tls/utility/CryptoUtil.h" -#include +#if defined(BOARD_HAS_SECRET_KEY) + #if defined(BOARD_ESP) + #include + #elif defined(ARDUINO_EDGE_CONTROL) + #include + #endif +#else + #include + #include + #if defined(BOARD_HAS_OFFLOADED_ECCX08) + #else + #include + #ifdef BOARD_HAS_ECCX08 + #include "tls/BearSSLClient.h" + #elif defined(BOARD_HAS_OFFLOADED_ECCX08) + #include + #elif defined(BOARD_HAS_SE050) + #if defined(ARDUINO_PORTENTA_C33) + #include + #else + #include + #endif + #elif defined(BOARD_HAS_SOFTSE) + #include + #endif + #endif #endif -#include - /****************************************************************************** CONSTANTS ******************************************************************************/ @@ -79,7 +85,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass virtual int connected () override; virtual void printDebugInfo() override; - #if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) || defined(BOARD_HAS_SE050) + #if !defined(BOARD_HAS_SECRET_KEY) int begin(ConnectionHandler & connection, bool const enable_watchdog = true, String brokerAddress = DEFAULT_BROKER_ADDRESS_SECURE_AUTH, uint16_t brokerPort = DEFAULT_BROKER_PORT_SECURE_AUTH); #else int begin(ConnectionHandler & connection, bool const enable_watchdog = true, String brokerAddress = DEFAULT_BROKER_ADDRESS_USER_PASS_AUTH, uint16_t brokerPort = DEFAULT_BROKER_PORT_USER_PASS_AUTH); @@ -142,33 +148,32 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass int _mqtt_data_len; bool _mqtt_data_request_retransmit; - #if defined(BOARD_HAS_ECCX08) - ArduinoIoTCloudCertClass _cert; - BearSSLClient _sslClient; - CryptoUtil _crypto; - #elif defined(BOARD_HAS_OFFLOADED_ECCX08) - ArduinoIoTCloudCertClass _cert; - WiFiBearSSLClient _sslClient; - CryptoUtil _crypto; - #elif defined(BOARD_ESP) +#if defined(BOARD_HAS_SECRET_KEY) + String _password; + #if defined(BOARD_ESP) WiFiClientSecure _sslClient; - #elif defined(ARDUINO_UNOR4_WIFI) - WiFiSSLClient _sslClient; - #elif defined(ARDUINO_EDGE_CONTROL) + #elif defined(ARDUINO_EDGE_CONTROL) GSMSSLClient _sslClient; - #elif defined(ARDUINO_PORTENTA_C33) - ArduinoIoTCloudCertClass _cert; - SSLClient _sslClient; - CryptoUtil _crypto; + #endif +#else + SecureElement _crypto; + #if defined(BOARD_HAS_OFFLOADED_ECCX08) + WiFiBearSSLClient _sslClient; + #else + ECP256Certificate _cert; + #if defined(BOARD_HAS_ECCX08) + BearSSLClient _sslClient; #elif defined(BOARD_HAS_SE050) - ArduinoIoTCloudCertClass _cert; + #if defined(ARDUINO_PORTENTA_C33) + SSLClient _sslClient; + #else WiFiSSLSE050Client _sslClient; - CryptoUtil _crypto; - #endif - - #if defined (BOARD_HAS_SECRET_KEY) - String _password; + #endif + #elif defined(BOARD_HAS_SOFTSE) + WiFiSSLClient _sslClient; #endif + #endif +#endif MqttClient _mqttClient; diff --git a/src/tls/AIoTCSSCert.h b/src/tls/AIoTCSSCert.h index 1dc8206d9..29d71223b 100644 --- a/src/tls/AIoTCSSCert.h +++ b/src/tls/AIoTCSSCert.h @@ -24,7 +24,7 @@ ******************************************************************************/ #include -#ifdef BOARD_HAS_SE050 +#if defined(BOARD_HAS_SE050) || defined(BOARD_HAS_SOFTSE) /****************************************************************************** * CONSTANTS @@ -43,6 +43,6 @@ static const char AIoTSSCert[] = "AiEA6tnZ2lrNElKXCajtZg/hjWRE/+giFzBP8riar8qOz2w=\n" "-----END CERTIFICATE-----\n"; -#endif /* #ifdef BOARD_HAS_SE050 */ +#endif /* #if defined(BOARD_HAS_SE050) || defined(BOARD_HAS_SOFTSE) */ #endif /* _AIOTC_SS_CERT_H_ */ diff --git a/src/tls/utility/Cert.cpp b/src/tls/utility/Cert.cpp deleted file mode 100644 index f4ce3b42b..000000000 --- a/src/tls/utility/Cert.cpp +++ /dev/null @@ -1,918 +0,0 @@ -/* - This file is part of the ArduinoECCX08 library. - Copyright (c) 2019 Arduino SA. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/****************************************************************************** - * INCLUDE - ******************************************************************************/ - -#include - -#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) || defined(BOARD_HAS_SE050) - -#include "Cert.h" - -/****************************************************************************** - * DEFINE - ******************************************************************************/ - -#define ASN1_INTEGER 0x02 -#define ASN1_BIT_STRING 0x03 -#define ASN1_NULL 0x05 -#define ASN1_OBJECT_IDENTIFIER 0x06 -#define ASN1_PRINTABLE_STRING 0x13 -#define ASN1_SEQUENCE 0x30 -#define ASN1_SET 0x31 - -/****************************************************************************** - * LOCAL MODULE FUNCTIONS - ******************************************************************************/ - -static String base64Encode(const byte in[], unsigned int length, const char* prefix, const char* suffix) { - static const char* CODES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - - int b; - String out; - - int reserveLength = 4 * ((length + 2) / 3) + ((length / 3 * 4) / 76) + strlen(prefix) + strlen(suffix); - out.reserve(reserveLength); - - if (prefix) { - out += prefix; - } - - for (unsigned int i = 0; i < length; i += 3) { - if (i > 0 && (i / 3 * 4) % 76 == 0) { - out += '\n'; - } - - b = (in[i] & 0xFC) >> 2; - out += CODES[b]; - - b = (in[i] & 0x03) << 4; - if (i + 1 < length) { - b |= (in[i + 1] & 0xF0) >> 4; - out += CODES[b]; - b = (in[i + 1] & 0x0F) << 2; - if (i + 2 < length) { - b |= (in[i + 2] & 0xC0) >> 6; - out += CODES[b]; - b = in[i + 2] & 0x3F; - out += CODES[b]; - } else { - out += CODES[b]; - out += '='; - } - } else { - out += CODES[b]; - out += "=="; - } - } - - if (suffix) { - out += suffix; - } - - return out; -} - -/****************************************************************************** - * CTOR/DTOR - ******************************************************************************/ - -ArduinoIoTCloudCertClass::ArduinoIoTCloudCertClass() -: _certBuffer(nullptr) -, _certBufferLen(0) -, _publicKey(nullptr) -{ - -} - -ArduinoIoTCloudCertClass::~ArduinoIoTCloudCertClass() -{ - if (_certBuffer) { - free(_certBuffer); - _certBuffer = nullptr; - } -} - -/****************************************************************************** - * PUBLIC MEMBER FUNCTIONS - ******************************************************************************/ - -int ArduinoIoTCloudCertClass::begin() -{ - memset(_compressedCert.data, 0x00, CERT_COMPRESSED_CERT_LENGTH); - return 1; -} - -int ArduinoIoTCloudCertClass::buildCSR() -{ - int csrInfoLen = CSRInfoLength(); - int subjectLen = issuerOrSubjectLength(_subjectData); - - _certBufferLen = getCSRSize(); - _certBuffer = (byte*)malloc(_certBufferLen); - - if (_certBuffer == nullptr) { - return 0; - } - - byte* out = _certBuffer; - - // header - out += appendSequenceHeader(csrInfoLen, out); - - // version - out += appendVersion(0x00, out); - - // subject - out += appendSequenceHeader(subjectLen, out); - out += appendIssuerOrSubject(_subjectData, out); - - // public key - if (_publicKey == nullptr) { - return 0; - } - out += appendPublicKey(_publicKey, out); - - // terminator - *out++ = 0xa0; - *out++ = 0x00; - - return 1; -} - -int ArduinoIoTCloudCertClass::signCSR(byte * signature) -{ - /* copy old certbuffer in a temp buffer */ - byte* tempBuffer = (byte*)malloc(_certBufferLen); - - if (tempBuffer == nullptr) { - return 0; - } - - memcpy(tempBuffer, _certBuffer, _certBufferLen); - - _certBufferLen = getCSRSignedSize(signature); - _certBuffer = (byte*)realloc(_certBuffer, _certBufferLen); - - if (_certBuffer == nullptr) { - return 0; - } - - byte* out = _certBuffer; - - // header - out += appendSequenceHeader(getCSRSize() + signatureLength(signature), out); - - // info - memcpy(out, tempBuffer, getCSRSize()); - free(tempBuffer); - out += getCSRSize(); - - // signature - out += appendSignature(signature, out); - - return 1; -} - -String ArduinoIoTCloudCertClass::getCSRPEM() -{ - return base64Encode(_certBuffer, _certBufferLen, "-----BEGIN CERTIFICATE REQUEST-----\n", "\n-----END CERTIFICATE REQUEST-----\n"); -} - -int ArduinoIoTCloudCertClass::buildCert() -{ - _certBufferLen = getCertSize(); - _certBuffer = (byte*)malloc(_certBufferLen); - - if (_certBuffer == nullptr) { - return 0; - } - - uint8_t* out = _certBuffer; - - int certInfoLen = certInfoLength(); - - // header - out += appendSequenceHeader(certInfoLen, out); - - // version - *out++ = 0xA0; - *out++ = 0x03; - *out++ = 0x02; - *out++ = 0x01; - *out++ = 0x02; - - // serial number - out += appendSerialNumber(_compressedCert.slot.two.values.serialNumber, CERT_SERIAL_NUMBER_LENGTH, out); - - // signature type - out += appendEcdsaWithSHA256(out); - - // issuer - int issuerDataLen = issuerOrSubjectLength(_issuerData); - out += appendSequenceHeader(issuerDataLen, out); - out += appendIssuerOrSubject(_issuerData, out); - - // dates - DateInfo dateData; - getDateFromCompressedData(dateData); - - *out++ = ASN1_SEQUENCE; - *out++ = 30 + ((dateData.issueYear > 2049) ? 2 : 0) + (((dateData.issueYear + dateData.expireYears) > 2049) ? 2 : 0); - out += appendDate(dateData.issueYear, dateData.issueMonth, dateData.issueDay, dateData.issueHour, 0, 0, out); - out += appendDate(dateData.issueYear + dateData.expireYears, dateData.issueMonth, dateData.issueDay, dateData.issueHour, 0, 0, out); - - // subject - int subjectDataLen = issuerOrSubjectLength(_subjectData); - out += appendSequenceHeader(subjectDataLen, out); - out += appendIssuerOrSubject(_subjectData, out); - - // public key - if (_publicKey == nullptr) { - return 0; - } - out += appendPublicKey(_publicKey, out); - - int authorityKeyIdLen = authorityKeyIdLength(_compressedCert.slot.two.values.authorityKeyId, CERT_AUTHORITY_KEY_ID_LENGTH); - if (authorityKeyIdLen) - { - out += appendAuthorityKeyId(_compressedCert.slot.two.values.authorityKeyId, CERT_AUTHORITY_KEY_ID_LENGTH, out); - } - else - { - // null sequence - *out++ = 0xA3; - *out++ = 0x02; - *out++ = 0x30; - *out++ = 0x00; - } - - return 1; -} - -int ArduinoIoTCloudCertClass::signCert(const byte * signature) -{ - /* copy old certbuffer in a temp buffer */ - byte* tempBuffer = (byte*)malloc(_certBufferLen); - - if (tempBuffer == nullptr) { - return 0; - } - - memcpy(tempBuffer, _certBuffer, _certBufferLen); - - _certBufferLen = getCertSignedSize(signature); - _certBuffer = (byte*)realloc(_certBuffer, _certBufferLen); - - if (_certBuffer == nullptr) { - return 0; - } - - byte* out = _certBuffer; - - // header - out +=appendSequenceHeader(getCertSize() + signatureLength(signature), out); - - // info - memcpy(out, tempBuffer, getCertSize()); - free(tempBuffer); - out += getCertSize(); - - // signature - out += appendSignature(signature, out); - - return 1; -} - -int ArduinoIoTCloudCertClass::importCert(const byte certDER[], size_t derLen) -{ - _certBufferLen = derLen; - _certBuffer = (byte*)malloc(_certBufferLen); - - if (_certBuffer == nullptr) { - return 0; - } - - memcpy(_certBuffer, certDER, _certBufferLen); - - return 1; -} - -int ArduinoIoTCloudCertClass::signCert() -{ - return signCert(_compressedCert.slot.one.values.signature); -} - -String ArduinoIoTCloudCertClass::getCertPEM() -{ - return base64Encode(_certBuffer, _certBufferLen, "-----BEGIN CERTIFICATE-----\n", "\n-----END CERTIFICATE-----\n"); -} - -void ArduinoIoTCloudCertClass::getDateFromCompressedData(DateInfo& date) { - date.issueYear = (_compressedCert.slot.one.values.dates[0] >> 3) + 2000; - date.issueMonth = ((_compressedCert.slot.one.values.dates[0] & 0x07) << 1) | (_compressedCert.slot.one.values.dates[1] >> 7); - date.issueDay = (_compressedCert.slot.one.values.dates[1] & 0x7c) >> 2; - date.issueHour = ((_compressedCert.slot.one.values.dates[1] & 0x03) << 3) | (_compressedCert.slot.one.values.dates[2] >> 5); - date.expireYears = (_compressedCert.slot.one.values.dates[2] & 0x1f); -} - -void ArduinoIoTCloudCertClass::setIssueYear(int issueYear) { - _compressedCert.slot.one.values.dates[0] &= 0x07; - _compressedCert.slot.one.values.dates[0] |= (issueYear - 2000) << 3; -} - -void ArduinoIoTCloudCertClass::setIssueMonth(int issueMonth) { - _compressedCert.slot.one.values.dates[0] &= 0xf8; - _compressedCert.slot.one.values.dates[0] |= issueMonth >> 1; - - _compressedCert.slot.one.values.dates[1] &= 0x7f; - _compressedCert.slot.one.values.dates[1] |= issueMonth << 7; -} - -void ArduinoIoTCloudCertClass::setIssueDay(int issueDay) { - _compressedCert.slot.one.values.dates[1] &= 0x83; - _compressedCert.slot.one.values.dates[1] |= issueDay << 2; -} - -void ArduinoIoTCloudCertClass::setIssueHour(int issueHour) { - _compressedCert.slot.one.values.dates[2] &= 0x1f; - _compressedCert.slot.one.values.dates[2] |= issueHour << 5; - - _compressedCert.slot.one.values.dates[1] &= 0xfc; - _compressedCert.slot.one.values.dates[1] |= issueHour >> 3; -} - -void ArduinoIoTCloudCertClass::setExpireYears(int expireYears) { - _compressedCert.slot.one.values.dates[2] &= 0xe0; - _compressedCert.slot.one.values.dates[2] |= expireYears; -} - -int ArduinoIoTCloudCertClass::setSerialNumber(const uint8_t serialNumber[], int serialNumberLen) { - if (serialNumberLen == CERT_SERIAL_NUMBER_LENGTH) { - memcpy(_compressedCert.slot.two.values.serialNumber, serialNumber, CERT_SERIAL_NUMBER_LENGTH); - return 1; - } - return 0; -} - -int ArduinoIoTCloudCertClass::setAuthorityKeyId(const uint8_t authorityKeyId[], int authorityKeyIdLen) { - if (authorityKeyIdLen == CERT_AUTHORITY_KEY_ID_LENGTH) { - memcpy(_compressedCert.slot.two.values.authorityKeyId, authorityKeyId, CERT_AUTHORITY_KEY_ID_LENGTH); - return 1; - } - return 0; -} - -int ArduinoIoTCloudCertClass::setPublicKey(const byte* publicKey, int publicKeyLen) { - if (publicKeyLen == CERT_PUBLIC_KEY_LENGTH) { - _publicKey = publicKey; - return 1; - } - return 0; -} - -int ArduinoIoTCloudCertClass::setSignature(const byte* signature, int signatureLen) { - if (signatureLen == CERT_SIGNATURE_LENGTH) { - memcpy(_compressedCert.slot.one.values.signature, signature, CERT_SIGNATURE_LENGTH); - return 1; - } - return 0; -} - -/****************************************************************************** - * PRIVATE MEMBER FUNCTIONS - ******************************************************************************/ - -int ArduinoIoTCloudCertClass::versionLength() -{ - return 3; -} - -int ArduinoIoTCloudCertClass::issuerOrSubjectLength(const CertInfo& issuerOrSubjectData) -{ - int length = 0; - int countryNameLength = issuerOrSubjectData.countryName.length(); - int stateProvinceNameLength = issuerOrSubjectData.stateProvinceName.length(); - int localityNameLength = issuerOrSubjectData.localityName.length(); - int organizationNameLength = issuerOrSubjectData.organizationName.length(); - int organizationalUnitNameLength = issuerOrSubjectData.organizationalUnitName.length(); - int commonNameLength = issuerOrSubjectData.commonName.length(); - - if (countryNameLength) { - length += (11 + countryNameLength); - } - - if (stateProvinceNameLength) { - length += (11 + stateProvinceNameLength); - } - - if (localityNameLength) { - length += (11 + localityNameLength); - } - - if (organizationNameLength) { - length += (11 + organizationNameLength); - } - - if (organizationalUnitNameLength) { - length += (11 + organizationalUnitNameLength); - } - - if (commonNameLength) { - length += (11 + commonNameLength); - } - - return length; -} - -int ArduinoIoTCloudCertClass::sequenceHeaderLength(int length) -{ - if (length > 255) { - return 4; - } else if (length > 127) { - return 3; - } else { - return 2; - } -} - -int ArduinoIoTCloudCertClass::publicKeyLength() -{ - return (2 + 2 + 9 + 10 + 4 + 64); -} - -int ArduinoIoTCloudCertClass::signatureLength(const byte signature[]) -{ - const byte* r = &signature[0]; - const byte* s = &signature[32]; - - int rLength = 32; - int sLength = 32; - - while (*r == 0x00 && rLength) { - r++; - rLength--; - } - - if (*r & 0x80) { - rLength++; - } - - while (*s == 0x00 && sLength) { - s++; - sLength--; - } - - if (*s & 0x80) { - sLength++; - } - - return (21 + rLength + sLength); -} - -int ArduinoIoTCloudCertClass::serialNumberLength(const byte serialNumber[], int length) -{ - while (*serialNumber == 0 && length) { - serialNumber++; - length--; - } - - if (*serialNumber & 0x80) { - length++; - } - - return (2 + length); -} - -int ArduinoIoTCloudCertClass::authorityKeyIdLength(const byte authorityKeyId[], int length) { - bool set = false; - - // check if the authority key identifier is non-zero - for (int i = 0; i < length; i++) { - if (authorityKeyId[i] != 0) { - set = true; - break; - } - } - - return (set ? (length + 17) : 0); -} - -int ArduinoIoTCloudCertClass::CSRInfoLength() -{ - int versionLen = versionLength(); - int subjectLen = issuerOrSubjectLength(_subjectData); - int subjectHeaderLen = sequenceHeaderLength(subjectLen); - int publicKeyLen = publicKeyLength(); - - int csrInfoLen = versionLen + subjectHeaderLen + subjectLen + publicKeyLen + 2; - - return csrInfoLen; -} - -int ArduinoIoTCloudCertClass::getCSRSize() -{ - int csrInfoLen = CSRInfoLength(); - int csrInfoHeaderLen = sequenceHeaderLength(csrInfoLen); - - return (csrInfoLen + csrInfoHeaderLen); -} - -int ArduinoIoTCloudCertClass::getCSRSignedSize(byte * signature) -{ - int signatureLen = signatureLength(signature); - int csrLen = getCSRSize() + signatureLen; - return sequenceHeaderLength(csrLen) + csrLen; -} - -int ArduinoIoTCloudCertClass::certInfoLength() -{ - int datesSizeLen = 30; - DateInfo dates; - - getDateFromCompressedData(dates); - - if (dates.issueYear > 2049) { - // two more bytes for GeneralizedTime - datesSizeLen += 2; - } - - if ((dates.issueYear + dates.expireYears) > 2049) { - // two more bytes for GeneralizedTime - datesSizeLen += 2; - } - - int serialNumberLen = serialNumberLength(_compressedCert.slot.two.values.serialNumber, CERT_SERIAL_NUMBER_LENGTH); - - int issuerLen = issuerOrSubjectLength(_issuerData); - - int issuerHeaderLen = sequenceHeaderLength(issuerLen); - - int subjectLen = issuerOrSubjectLength(_subjectData); - - int subjectHeaderLen = sequenceHeaderLength(subjectLen); - - int publicKeyLen = publicKeyLength(); - - int certInfoLen = 5 + serialNumberLen + 12 + issuerHeaderLen + issuerLen + (datesSizeLen + 2) + - subjectHeaderLen + subjectLen + publicKeyLen; - - int authorityKeyIdLen = authorityKeyIdLength(_compressedCert.slot.two.values.authorityKeyId, CERT_AUTHORITY_KEY_ID_LENGTH); - - if (authorityKeyIdLen) - { - certInfoLen += authorityKeyIdLen; - } - else - { - certInfoLen += 4; - } - - return certInfoLen; -} - -int ArduinoIoTCloudCertClass::getCertSize() -{ - int certInfoLen = certInfoLength(); - int certInfoHeaderLen = sequenceHeaderLength(certInfoLen); - - return (certInfoLen + certInfoHeaderLen); -} - -int ArduinoIoTCloudCertClass::getCertSignedSize(const byte * signature) -{ - int signatureLen = signatureLength(signature); - int certLen = getCertSize() + signatureLen; - return sequenceHeaderLength(certLen) + certLen; -} - -int ArduinoIoTCloudCertClass::appendSequenceHeader(int length, byte out[]) -{ - *out++ = ASN1_SEQUENCE; - if (length > 255) { - *out++ = 0x82; - *out++ = (length >> 8) & 0xff; - } else if (length > 127) { - *out++ = 0x81; - } - *out++ = (length) & 0xff; - - if (length > 255) { - return 4; - } else if (length > 127) { - return 3; - } else { - return 2; - } -} - -int ArduinoIoTCloudCertClass::appendVersion(int version, byte out[]) -{ - out[0] = ASN1_INTEGER; - out[1] = 0x01; - out[2] = version; - - return versionLength(); -} - -int ArduinoIoTCloudCertClass::appendName(const String& name, int type, byte out[]) -{ - int nameLength = name.length(); - - *out++ = ASN1_SET; - *out++ = nameLength + 9; - - *out++ = ASN1_SEQUENCE; - *out++ = nameLength + 7; - - *out++ = ASN1_OBJECT_IDENTIFIER; - *out++ = 0x03; - *out++ = 0x55; - *out++ = 0x04; - *out++ = type; - - *out++ = ASN1_PRINTABLE_STRING; - *out++ = nameLength; - memcpy(out, name.c_str(), nameLength); - - return (nameLength + 11); -} - -int ArduinoIoTCloudCertClass::appendIssuerOrSubject(const CertInfo& issuerOrSubjectData, byte out[]) -{ - if (issuerOrSubjectData.countryName.length() > 0) { - out += appendName(issuerOrSubjectData.countryName, 0x06, out); - } - - if (issuerOrSubjectData.stateProvinceName.length() > 0) { - out += appendName(issuerOrSubjectData.stateProvinceName, 0x08, out); - } - - if (issuerOrSubjectData.localityName.length() > 0) { - out += appendName(issuerOrSubjectData.localityName, 0x07, out); - } - - if (issuerOrSubjectData.organizationName.length() > 0) { - out += appendName(issuerOrSubjectData.organizationName, 0x0a, out); - } - - if (issuerOrSubjectData.organizationalUnitName.length() > 0) { - out += appendName(issuerOrSubjectData.organizationalUnitName, 0x0b, out); - } - - if (issuerOrSubjectData.commonName.length() > 0) { - out += appendName(issuerOrSubjectData.commonName, 0x03, out); - } - - return issuerOrSubjectLength(issuerOrSubjectData); -} - -int ArduinoIoTCloudCertClass::appendPublicKey(const byte publicKey[], byte out[]) -{ - int subjectPublicKeyDataLength = 2 + 9 + 10 + 4 + 64; - - // subject public key - *out++ = ASN1_SEQUENCE; - *out++ = (subjectPublicKeyDataLength) & 0xff; - - *out++ = ASN1_SEQUENCE; - *out++ = 0x13; - - // EC public key - *out++ = ASN1_OBJECT_IDENTIFIER; - *out++ = 0x07; - *out++ = 0x2a; - *out++ = 0x86; - *out++ = 0x48; - *out++ = 0xce; - *out++ = 0x3d; - *out++ = 0x02; - *out++ = 0x01; - - // PRIME 256 v1 - *out++ = ASN1_OBJECT_IDENTIFIER; - *out++ = 0x08; - *out++ = 0x2a; - *out++ = 0x86; - *out++ = 0x48; - *out++ = 0xce; - *out++ = 0x3d; - *out++ = 0x03; - *out++ = 0x01; - *out++ = 0x07; - - *out++ = 0x03; - *out++ = 0x42; - *out++ = 0x00; - *out++ = 0x04; - - memcpy(out, publicKey, 64); - - return publicKeyLength(); -} - -int ArduinoIoTCloudCertClass::appendSignature(const byte signature[], byte out[]) -{ - // signature algorithm - *out++ = ASN1_SEQUENCE; - *out++ = 0x0a; - *out++ = ASN1_OBJECT_IDENTIFIER; - *out++ = 0x08; - - // ECDSA with SHA256 - *out++ = 0x2a; - *out++ = 0x86; - *out++ = 0x48; - *out++ = 0xce; - *out++ = 0x3d; - *out++ = 0x04; - *out++ = 0x03; - *out++ = 0x02; - - const byte* r = &signature[0]; - const byte* s = &signature[32]; - - int rLength = 32; - int sLength = 32; - - while (*r == 0 && rLength) { - r++; - rLength--; - } - - while (*s == 0 && sLength) { - s++; - sLength--; - } - - if (*r & 0x80) { - rLength++; - } - - if (*s & 0x80) { - sLength++; - } - - *out++ = ASN1_BIT_STRING; - *out++ = (rLength + sLength + 7); - *out++ = 0; - - *out++ = ASN1_SEQUENCE; - *out++ = (rLength + sLength + 4); - - *out++ = ASN1_INTEGER; - *out++ = rLength; - if ((*r & 0x80) && rLength) { - *out++ = 0; - rLength--; - } - memcpy(out, r, rLength); - out += rLength; - - *out++ = ASN1_INTEGER; - *out++ = sLength; - if ((*s & 0x80) && sLength) { - *out++ = 0; - sLength--; - } - memcpy(out, s, sLength); - out += rLength; - - return signatureLength(signature); -} - -int ArduinoIoTCloudCertClass::appendSerialNumber(const byte serialNumber[], int length, byte out[]) -{ - while (*serialNumber == 0 && length) { - serialNumber++; - length--; - } - - if (*serialNumber & 0x80) { - length++; - } - - *out++ = ASN1_INTEGER; - *out++ = length; - - if (*serialNumber & 0x80) { - *out++ = 0x00; - length--; - } - - memcpy(out, serialNumber, length); - - if (*serialNumber & 0x80) { - length++; - } - - return (2 + length); -} - -int ArduinoIoTCloudCertClass::appendDate(int year, int month, int day, int hour, int minute, int second, byte out[]) -{ - bool useGeneralizedTime = (year > 2049); - - if (useGeneralizedTime) { - *out++ = 0x18; - *out++ = 0x0f; - *out++ = '0' + (year / 1000); - *out++ = '0' + ((year % 1000) / 100); - *out++ = '0' + ((year % 100) / 10); - *out++ = '0' + (year % 10); - } else { - year -= 2000; - - *out++ = 0x17; - *out++ = 0x0d; - *out++ = '0' + (year / 10); - *out++ = '0' + (year % 10); - } - *out++ = '0' + (month / 10); - *out++ = '0' + (month % 10); - *out++ = '0' + (day / 10); - *out++ = '0' + (day % 10); - *out++ = '0' + (hour / 10); - *out++ = '0' + (hour % 10); - *out++ = '0' + (minute / 10); - *out++ = '0' + (minute % 10); - *out++ = '0' + (second / 10); - *out++ = '0' + (second % 10); - *out++ = 0x5a; // UTC - - return (useGeneralizedTime ? 17 : 15); -} - -int ArduinoIoTCloudCertClass::appendEcdsaWithSHA256(byte out[]) -{ - *out++ = ASN1_SEQUENCE; - *out++ = 0x0A; - *out++ = ASN1_OBJECT_IDENTIFIER; - *out++ = 0x08; - *out++ = 0x2A; - *out++ = 0x86; - *out++ = 0x48; - *out++ = 0xCE; - *out++ = 0x3D; - *out++ = 0x04; - *out++ = 0x03; - *out++ = 0x02; - - return 12; -} - -int ArduinoIoTCloudCertClass::appendAuthorityKeyId(const byte authorityKeyId[], int length, byte out[]) { - // [3] - *out++ = 0xa3; - *out++ = 0x23; - - // sequence - *out++ = ASN1_SEQUENCE; - *out++ = 0x21; - - // sequence - *out++ = ASN1_SEQUENCE; - *out++ = 0x1f; - - // 2.5.29.35 authorityKeyIdentifier(X.509 extension) - *out++ = 0x06; - *out++ = 0x03; - *out++ = 0x55; - *out++ = 0x1d; - *out++ = 0x23; - - // octet string - *out++ = 0x04; - *out++ = 0x18; - - // sequence - *out++ = ASN1_SEQUENCE; - *out++ = 0x16; - - *out++ = 0x80; - *out++ = 0x14; - - memcpy(out, authorityKeyId, length); - - return length + 17; -} - -#endif /* (BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) || defined(BOARD_HAS_SE050) */ diff --git a/src/tls/utility/Cert.h b/src/tls/utility/Cert.h deleted file mode 100644 index 9a74ea35b..000000000 --- a/src/tls/utility/Cert.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - This file is part of ArduinoIoTCloud. - - Copyright 2019 ARDUINO SA (http://www.arduino.cc/) - - This software is released under the GNU General Public License version 3, - which covers the main part of arduino-cli. - The terms of this license can be found at: - https://www.gnu.org/licenses/gpl-3.0.en.html - - You can be released from the requirements of the above licenses by purchasing - a commercial license. Buying such a license is mandatory if you want to modify or - otherwise use the software for commercial activities involving the Arduino - software without disclosing the source code of your own applications. To purchase - a commercial license, send an email to license@arduino.cc. -*/ - -#ifndef ARDUINO_IOT_CLOUD_CERT_H -#define ARDUINO_IOT_CLOUD_CERT_H - -/****************************************************************************** - * INCLUDE - ******************************************************************************/ - -#include - -#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) || defined(BOARD_HAS_SE050) - -/****************************************************************************** - * DEFINE - ******************************************************************************/ - -#define CERT_SERIAL_NUMBER_LENGTH 16 -#define CERT_AUTHORITY_KEY_ID_LENGTH 20 -#define CERT_PUBLIC_KEY_LENGTH 64 -#define CERT_SIGNATURE_LENGTH 64 -#define CERT_DATES_LENGTH 3 -#define CERT_COMPRESSED_CERT_SLOT_LENGTH 72 -#define CERT_COMPRESSED_CERT_LENGTH CERT_COMPRESSED_CERT_SLOT_LENGTH + CERT_SERIAL_NUMBER_LENGTH + CERT_AUTHORITY_KEY_ID_LENGTH - -#include - -class ArduinoIoTCloudCertClass { -public: - ArduinoIoTCloudCertClass(); - virtual ~ArduinoIoTCloudCertClass(); - - int begin(); - int end(); - - /* APIs used only for Certificate generation*/ - void setIssueYear(int issueYear); - void setIssueMonth(int issueMonth); - void setIssueDay(int issueDay); - void setIssueHour(int issueHour); - void setExpireYears(int expireYears); - int setSerialNumber(const uint8_t serialNumber[], int serialNumberLen); - int setAuthorityKeyId(const uint8_t authorityKeyId[], int authorityKeyIdLen); - - inline void setIssuerCountryName(const String& countryName) { _issuerData.countryName = countryName; } - inline void setIssuerStateProvinceName(const String& stateProvinceName) { _issuerData.stateProvinceName = stateProvinceName; } - inline void setIssuerLocalityName(const String& localityName) { _issuerData.localityName = localityName; } - inline void setIssuerOrganizationName(const String& organizationName) { _issuerData.organizationName = organizationName; } - inline void setIssuerOrganizationalUnitName(const String& organizationalUnitName) { _issuerData.organizationalUnitName = organizationalUnitName; } - inline void setIssuerCommonName(const String& commonName) { _issuerData.commonName = commonName; } - - /* APIs used for both CSR and Certificate generation */ - inline void setSubjectCountryName(const String& countryName) { _subjectData.countryName = countryName; } - inline void setSubjectStateProvinceName(const String& stateProvinceName) { _subjectData.stateProvinceName = stateProvinceName; } - inline void setSubjectLocalityName(const String& localityName) { _subjectData.localityName = localityName; } - inline void setSubjectOrganizationName(const String& organizationName) { _subjectData.organizationName = organizationName; } - inline void setSubjectOrganizationalUnitName(const String& organizationalUnitName) { _subjectData.organizationalUnitName = organizationalUnitName; } - inline void setSubjectCommonName(const String& commonName) { _subjectData.commonName = commonName; } - - int setPublicKey(const byte* publicKey, int publicKeyLen); - int setSignature(const byte* signature, int signatureLen); - - /* Get Buffer */ - inline byte* bytes() { return _certBuffer; } - inline int length() { return _certBufferLen; } - -#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) - /* Get Data to create ECCX08 compressed cert */ - inline byte* compressedCertBytes() { return _compressedCert.data; } - inline int compressedCertLenght() {return CERT_COMPRESSED_CERT_LENGTH; } - inline byte* compressedCertSignatureAndDatesBytes() { return _compressedCert.slot.one.data; } - inline int compressedCertSignatureAndDatesLength() {return CERT_COMPRESSED_CERT_SLOT_LENGTH; } - inline byte* compressedCertSerialAndAuthorityKeyIdBytes() { return _compressedCert.slot.two.data; } - inline int compressedCertSerialAndAuthorityKeyIdLenght() {return CERT_SERIAL_NUMBER_LENGTH + CERT_AUTHORITY_KEY_ID_LENGTH; } -#endif - - /* Build CSR */ - int buildCSR(); - int signCSR(byte signature[]); - String getCSRPEM(); - - /* Build Certificate */ - int buildCert(); - int signCert(const byte signature[]); - int signCert(); - String getCertPEM(); - - /* Import DER buffer into CertClass*/ - int importCert(const byte certDER[], size_t derLen); - -private: - - struct CertInfo { - String countryName; - String stateProvinceName; - String localityName; - String organizationName; - String organizationalUnitName; - String commonName; - }_issuerData, _subjectData; - - struct DateInfo { - int issueYear; - int issueMonth; - int issueDay; - int issueHour; - int expireYears; - }; - - union SignatureAndDateUType { - struct __attribute__((__packed__)) SignatureAndDateType { - byte signature[CERT_SIGNATURE_LENGTH]; - byte dates[CERT_DATES_LENGTH]; - byte unused[5]; - } values; - byte data[CERT_COMPRESSED_CERT_SLOT_LENGTH]; - }; - - union SerialNumberAndAuthorityKeyIdUType { - struct __attribute__((__packed__)) SerialNumberAndAuthorityKeyIdType { - byte serialNumber[CERT_SERIAL_NUMBER_LENGTH]; - byte authorityKeyId[CERT_AUTHORITY_KEY_ID_LENGTH]; - } values; - byte data[CERT_SERIAL_NUMBER_LENGTH + CERT_AUTHORITY_KEY_ID_LENGTH]; - }; - - union CompressedCertDataUType { - struct __attribute__((__packed__)) CompressedCertDataType { - SignatureAndDateUType one; - SerialNumberAndAuthorityKeyIdUType two; - }slot; - byte data[CERT_COMPRESSED_CERT_SLOT_LENGTH + CERT_SERIAL_NUMBER_LENGTH + CERT_AUTHORITY_KEY_ID_LENGTH]; - } _compressedCert; - - byte * _certBuffer; - int _certBufferLen; - - /* only raw EC X Y values 64 byte */ - const byte * _publicKey; - - int versionLength(); - int issuerOrSubjectLength(const CertInfo& issuerOrSubjectData); - int sequenceHeaderLength(int length); - int publicKeyLength(); - int signatureLength(const byte signature[]); - int serialNumberLength(const byte serialNumber[], int length); - int authorityKeyIdLength(const byte authorityKeyId[], int length); - int CSRInfoLength(); - int getCSRSize(); - int getCSRSignedSize(byte signature[]); - int certInfoLength(); - int getCertSize(); - int getCertSignedSize(const byte signature[]); - - void getDateFromCompressedData(DateInfo& date); - - int appendSequenceHeader(int length, byte out[]); - int appendVersion(int version, byte out[]); - int appendName(const String& name, int type, byte out[]); - int appendIssuerOrSubject(const CertInfo& issuerOrSubjectData, byte out[]); - int appendPublicKey(const byte publicKey[], byte out[]); - int appendSignature(const byte signature[], byte out[]); - int appendSerialNumber(const byte serialNumber[], int length, byte out[]); - int appendDate(int year, int month, int day, int hour, int minute, int second, byte out[]); - int appendEcdsaWithSHA256(byte out[]); - int appendAuthorityKeyId(const byte authorityKeyId[], int length, byte out[]); - -}; - -#endif /* BOARD_HAS_ECCX08 || BOARD_HAS_OFFLOADED_ECCX08 || BOARD_HAS_SE050*/ - -#endif /* ARDUINO_IOT_CLOUD_CERT_H */ diff --git a/src/tls/utility/CryptoUtil.cpp b/src/tls/utility/CryptoUtil.cpp deleted file mode 100644 index 24f03121d..000000000 --- a/src/tls/utility/CryptoUtil.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/* - This file is part of ArduinoIoTCloud. - - Copyright 2019 ARDUINO SA (http://www.arduino.cc/) - - This software is released under the GNU General Public License version 3, - which covers the main part of arduino-cli. - The terms of this license can be found at: - https://www.gnu.org/licenses/gpl-3.0.en.html - - You can be released from the requirements of the above licenses by purchasing - a commercial license. Buying such a license is mandatory if you want to modify or - otherwise use the software for commercial activities involving the Arduino - software without disclosing the source code of your own applications. To purchase - a commercial license, send an email to license@arduino.cc. -*/ - -/****************************************************************************** - * INCLUDE - ******************************************************************************/ - -#include - -#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) || defined(BOARD_HAS_SE050) - -#include "CryptoUtil.h" -#include "SHA256.h" - -/****************************************************************************** - * DEFINE - ******************************************************************************/ -#define CRYPTO_SHA256_BUFFER_LENGTH 32 -#define CRYPTO_CERT_BUFFER_LENGTH 1024 - -/************************************************************************************** - * CTOR/DTOR - **************************************************************************************/ -CryptoUtil::CryptoUtil() -#if defined(BOARD_HAS_SE050) -: _crypto {SE05X} -#else -: _crypto {ECCX08} -#endif -{ - -} - -/****************************************************************************** - * PUBLIC MEMBER FUNCTIONS - ******************************************************************************/ - -int CryptoUtil::buildCSR(ArduinoIoTCloudCertClass & cert, const CryptoSlot keySlot, bool newPrivateKey) -{ - byte publicKey[CERT_PUBLIC_KEY_LENGTH]; - byte signature[CERT_SIGNATURE_LENGTH]; - - if (newPrivateKey) { - if (!_crypto.generatePrivateKey(static_cast(keySlot), publicKey)) { - return 0; - } - } else { - if (!_crypto.generatePublicKey(static_cast(keySlot), publicKey)) { - return 0; - } - } - - /* Store public key in csr */ - if (!cert.setPublicKey(publicKey, CERT_PUBLIC_KEY_LENGTH)) { - return 0; - } - - /* Build CSR */ - if (!cert.buildCSR()) { - return 0; - } - - /* compute CSR SHA256 */ - SHA256 sha256; - byte sha256buf[CRYPTO_SHA256_BUFFER_LENGTH]; - sha256.begin(); - sha256.update(cert.bytes(), cert.length()); - sha256.finalize(sha256buf); - - if (!_crypto.ecSign(static_cast(keySlot), sha256buf, signature)) { - return 0; - } - - /* sign CSR */ - return cert.signCSR(signature); -} - -int CryptoUtil::buildCert(ArduinoIoTCloudCertClass & cert, const CryptoSlot keySlot) -{ - byte publicKey[CERT_PUBLIC_KEY_LENGTH]; - - if (!_crypto.generatePublicKey(static_cast(keySlot), publicKey)) { - return 0; - } - - /* Store public key in csr */ - if (!cert.setPublicKey(publicKey, CERT_PUBLIC_KEY_LENGTH)) { - return 0; - } - - /* Build CSR */ - if (!cert.buildCert()) { - return 0; - } - - /* sign CSR */ - return cert.signCert(); -} - -int CryptoUtil::readDeviceId(String & device_id, const CryptoSlot device_id_slot) -{ - byte device_id_bytes[CERT_COMPRESSED_CERT_SLOT_LENGTH] = {0}; - - if (!_crypto.readSlot(static_cast(device_id_slot), device_id_bytes, sizeof(device_id_bytes))) { - return 0; - } - - device_id = String(reinterpret_cast(device_id_bytes)); - return 1; -} - -int CryptoUtil::writeDeviceId(String & device_id, const CryptoSlot device_id_slot) -{ - byte device_id_bytes[CERT_COMPRESSED_CERT_SLOT_LENGTH] = {0}; - - device_id.getBytes(device_id_bytes, sizeof(device_id_bytes)); - - if (!_crypto.writeSlot(static_cast(device_id_slot), device_id_bytes, sizeof(device_id_bytes))) { - return 0; - } - return 1; -} - -int CryptoUtil::writeCert(ArduinoIoTCloudCertClass & cert, const CryptoSlot certSlot) -{ -#if defined(BOARD_HAS_SE050) - if (!_crypto.writeSlot(static_cast(certSlot), cert.bytes(), cert.length())) { - return 0; - } -#else - if (!_crypto.writeSlot(static_cast(certSlot), cert.compressedCertSignatureAndDatesBytes(), cert.compressedCertSignatureAndDatesLength())) { - return 0; - } - - if (!_crypto.writeSlot(static_cast(certSlot) + 1, cert.compressedCertSerialAndAuthorityKeyIdBytes(), cert.compressedCertSerialAndAuthorityKeyIdLenght())) { - return 0; - } -#endif - return 1; -} - -int CryptoUtil::readCert(ArduinoIoTCloudCertClass & cert, const CryptoSlot certSlot) -{ -#if defined(BOARD_HAS_SE050) - byte derBuffer[CRYPTO_CERT_BUFFER_LENGTH]; - size_t derLen; - if (!_crypto.readBinaryObject(static_cast(certSlot), derBuffer, sizeof(derBuffer), &derLen)) { - return 0; - } - - if (!cert.importCert(derBuffer, derLen)) { - return 0; - } -#else - String deviceId; - byte publicKey[CERT_PUBLIC_KEY_LENGTH]; - - cert.begin(); - - if (!readDeviceId(deviceId, CryptoSlot::DeviceId)) { - return 0; - } - - if (!_crypto.readSlot(static_cast(certSlot), cert.compressedCertSignatureAndDatesBytes(), cert.compressedCertSignatureAndDatesLength())) { - return 0; - } - - if (!_crypto.readSlot(static_cast(certSlot) + 1, cert.compressedCertSerialAndAuthorityKeyIdBytes(), cert.compressedCertSerialAndAuthorityKeyIdLenght())) { - return 0; - } - - if (!_crypto.generatePublicKey(static_cast(CryptoSlot::Key), publicKey)) { - return 0; - } - - cert.setSubjectCommonName(deviceId); - cert.setIssuerCountryName("US"); - cert.setIssuerOrganizationName("Arduino LLC US"); - cert.setIssuerOrganizationalUnitName("IT"); - cert.setIssuerCommonName("Arduino"); - - if (!cert.setPublicKey(publicKey, CERT_PUBLIC_KEY_LENGTH)) { - return 0; - } - - if (!cert.buildCert()) { - return 0; - } - - if (!cert.signCert()) { - return 0; - } -#endif - return 1; -} - -#endif /* (BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) || defined(BOARD_HAS_SE050) */ diff --git a/src/tls/utility/CryptoUtil.h b/src/tls/utility/CryptoUtil.h deleted file mode 100644 index ba75f7021..000000000 --- a/src/tls/utility/CryptoUtil.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - This file is part of ArduinoIoTCloud. - - Copyright 2019 ARDUINO SA (http://www.arduino.cc/) - - This software is released under the GNU General Public License version 3, - which covers the main part of arduino-cli. - The terms of this license can be found at: - https://www.gnu.org/licenses/gpl-3.0.en.html - - You can be released from the requirements of the above licenses by purchasing - a commercial license. Buying such a license is mandatory if you want to modify or - otherwise use the software for commercial activities involving the Arduino - software without disclosing the source code of your own applications. To purchase - a commercial license, send an email to license@arduino.cc. -*/ - -#ifndef ARDUINO_IOT_CLOUD_UTILITY_CRYPTO_CRYPTO_UTIL_H_ -#define ARDUINO_IOT_CLOUD_UTILITY_CRYPTO_CRYPTO_UTIL_H_ - -/****************************************************************************** - * INCLUDE - ******************************************************************************/ - -#include - -#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) || defined(BOARD_HAS_SE050) -#include -#include "Cert.h" - -#if defined(BOARD_HAS_SE050) -#include -#else -#include -#endif - -/****************************************************************************** - * DEFINE - ******************************************************************************/ -#if defined(BOARD_HAS_SE050) -#define CRYPTO_SLOT_OFFSET 100 -#else -#define CRYPTO_SLOT_OFFSET 0 -#endif - -/****************************************************************************** - TYPEDEF - ******************************************************************************/ -enum class CryptoSlot : int -{ - Key = (0 + CRYPTO_SLOT_OFFSET), - CompressedCertificate = (10 + CRYPTO_SLOT_OFFSET), - SerialNumberAndAuthorityKeyIdentifier = (11 + CRYPTO_SLOT_OFFSET), - DeviceId = (12 + CRYPTO_SLOT_OFFSET) -}; - -/****************************************************************************** - * CLASS DECLARATION - ******************************************************************************/ - -class CryptoUtil -{ -public: - - CryptoUtil(); - - inline int begin() { return _crypto.begin(); } - inline int locked() { return _crypto.locked(); } - inline int writeConfiguration(const byte config[]) { return _crypto.writeConfiguration(config); } - inline int lock() { return _crypto.lock(); } - - int buildCSR(ArduinoIoTCloudCertClass & cert, const CryptoSlot keySlot, bool newPrivateKey); - int buildCert(ArduinoIoTCloudCertClass & cert, const CryptoSlot keySlot); - - int readDeviceId(String & device_id, const CryptoSlot device_id_slot); - int writeDeviceId(String & device_id, const CryptoSlot device_id_slot); - int writeCert(ArduinoIoTCloudCertClass & cert, const CryptoSlot certSlot); - int readCert(ArduinoIoTCloudCertClass & cert, const CryptoSlot certSlot); - -private: -#if defined(BOARD_HAS_SE050) - SE05XClass & _crypto; -#else - ECCX08Class & _crypto; -#endif - -}; - -#endif /* BOARD_HAS_ECCX08 || BOARD_HAS_OFFLOADED_ECCX08 || BOARD_HAS_SE050 */ - -#endif /* ARDUINO_IOT_CLOUD_UTILITY_CRYPTO_CRYPTO_UTIL_H_ */ From d1208626b7a6dbdc70907fe85096b8649bab88b5 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 2 Feb 2024 16:21:04 +0100 Subject: [PATCH 02/10] Examples: update provisioning sketch - Use Arduino_SecureElement library - Add WiFi version check - Align code to "Cloud version" provisioning sketch --- .../utility/Provisioning/Provisioning.ino | 134 ++++++++++++++---- 1 file changed, 103 insertions(+), 31 deletions(-) diff --git a/examples/utility/Provisioning/Provisioning.ino b/examples/utility/Provisioning/Provisioning.ino index 97394fc2c..ebde2218b 100644 --- a/examples/utility/Provisioning/Provisioning.ino +++ b/examples/utility/Provisioning/Provisioning.ino @@ -1,21 +1,37 @@ -#include -#include "ECCX08TLSConfig.h" - -const bool DEBUG = true; - -ArduinoIoTCloudCertClass Certificate; -CryptoUtil Crypto; +#include +#include +#include +#include +#include + +#ifdef ARDUINO_SAMD_MKR1000 +#include +#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 +#define LATEST_WIFI_FIRMWARE_VERSION WIFI_FIRMWARE_LATEST_VERSION +#endif +#if defined(ARDUINO_UNOR4_WIFI) +#include +#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(); @@ -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); } @@ -38,7 +56,8 @@ 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") { @@ -46,15 +65,19 @@ void setup() { 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); } @@ -62,12 +85,14 @@ void setup() { 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): "); @@ -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); } @@ -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(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(); @@ -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(); From 6be3d18458eb926e01b703ab393e29d2488a815f Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 16 Feb 2024 13:47:36 +0100 Subject: [PATCH 03/10] Add common define for boards with secure element --- src/AIoTC_Config.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index 7692e2f46..e7500120f 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -128,6 +128,10 @@ #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 ******************************************************************************/ From f5564782031ff67d440cb6dca466f6c0099b91f2 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 16 Feb 2024 13:51:34 +0100 Subject: [PATCH 04/10] UNO R4 WiFi: allow both username/password and mTLS authentication --- src/AIoTC_Config.h | 1 + src/ArduinoIoTCloudTCP.cpp | 82 ++++++++++++++++++++---------------- src/ArduinoIoTCloudTCP.h | 86 ++++++++++++++++++-------------------- src/tls/AIoTCUPCert.h | 2 +- 4 files changed, 89 insertions(+), 82 deletions(-) diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index e7500120f..eef6a764b 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -125,6 +125,7 @@ #if defined(ARDUINO_UNOR4_WIFI) #define BOARD_HAS_SOFTSE + #define BOARD_HAS_SECRET_KEY #define HAS_TCP #endif diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index e307efaa9..e1a592452 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -24,7 +24,7 @@ #ifdef HAS_TCP #include -#ifdef BOARD_HAS_SECRET_KEY +#if defined(BOARD_HAS_SECRET_KEY) #include "tls/AIoTCUPCert.h" #endif @@ -114,8 +114,13 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP() int ArduinoIoTCloudTCP::begin(ConnectionHandler & connection, bool const enable_watchdog, String brokerAddress, uint16_t brokerPort) { _connection = &connection; +#ifdef BOARD_HAS_SECRET_KEY + _brokerAddress = _password.length() ? DEFAULT_BROKER_ADDRESS_USER_PASS_AUTH : brokerAddress; + _brokerPort = _password.length() ? DEFAULT_BROKER_PORT_USER_PASS_AUTH : brokerPort; +#else _brokerAddress = brokerAddress; _brokerPort = brokerPort; +#endif _time_service.begin(&connection); return begin(enable_watchdog, _brokerAddress, _brokerPort); } @@ -130,55 +135,60 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, DEBUG_VERBOSE("SHA256: HASH(%d) = %s", strlen(_ota_img_sha256.c_str()), _ota_img_sha256.c_str()); #endif /* OTA_ENABLED */ -#if !defined(BOARD_HAS_SECRET_KEY) - if (!_crypto.begin()) - { - DEBUG_ERROR("_crypto.begin() failed."); - return 0; - } - if (!SElementArduinoCloudDeviceId::read(_crypto, getDeviceId(), SElementArduinoCloudSlot::DeviceId)) +#if defined(BOARD_HAS_SECRET_KEY) + /* If board is not configured for username and password login */ + if(!_password.length()) { - DEBUG_ERROR("_crypto.readDeviceId(...) failed."); - return 0; - } #endif - -#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_SE050) || defined(BOARD_HAS_SOFTSE) - if (!SElementArduinoCloudCertificate::read(_crypto, _cert, SElementArduinoCloudSlot::CompressedCertificate)) - { - DEBUG_ERROR("Cryptography certificate reconstruction failure."); - return 0; +#if defined(BOARD_HAS_SECURE_ELEMENT) + if (!_crypto.begin()) + { + DEBUG_ERROR("_crypto.begin() failed."); + return 0; + } + if (!SElementArduinoCloudDeviceId::read(_crypto, getDeviceId(), SElementArduinoCloudSlot::DeviceId)) + { + DEBUG_ERROR("_crypto.readDeviceId(...) failed."); + return 0; + } + #if !defined(BOARD_HAS_OFFLOADED_ECCX08) + if (!SElementArduinoCloudCertificate::read(_crypto, _cert, SElementArduinoCloudSlot::CompressedCertificate)) + { + DEBUG_ERROR("Cryptography certificate reconstruction failure."); + return 0; + } + _sslClient.setEccSlot(static_cast(SElementArduinoCloudSlot::Key), _cert.bytes(), _cert.length()); + #endif +#endif +#if defined(BOARD_HAS_SECRET_KEY) } - _sslClient.setEccSlot(static_cast(SElementArduinoCloudSlot::Key), _cert.bytes(), _cert.length()); #endif +#if defined(BOARD_HAS_OFFLOADED_ECCX08) -#if defined(BOARD_HAS_SECRET_KEY) - #if defined(ARDUINO_EDGE_CONTROL) - _sslClient.appendCustomCACert(AIoTUPCert); - #elif defined(ARDUINO_ARCH_ESP32) - _sslClient.setCACertBundle(x509_crt_bundle); - #else - _sslClient.setInsecure(); - #endif -#else - #if defined(BOARD_HAS_ECCX08) +#elif defined(BOARD_HAS_ECCX08) _sslClient.setClient(_connection->getClient()); - #elif defined(BOARD_HAS_SE050) - #if defined(ARDUINO_PORTENTA_C33) +#elif defined(ARDUINO_PORTENTA_C33) _sslClient.setClient(_connection->getClient()); _sslClient.setCACert(AIoTSSCert); - #else +#elif defined(ARDUINO_NICLA_VISION) _sslClient.appendCustomCACert(AIoTSSCert); - #endif - #elif defined(BOARD_HAS_SOFTSE) - _sslClient.setCACert(AIoTSSCert, strlen(AIoTSSCert)); - #endif +#elif defined(ARDUINO_EDGE_CONTROL) + _sslClient.appendCustomCACert(AIoTUPCert); +#elif defined(ARDUINO_UNOR4_WIFI) + +#elif defined(ARDUINO_ARCH_ESP32) + _sslClient.setCACertBundle(x509_crt_bundle); +#elif defined(ARDUINO_ARCH_ESP8266) + _sslClient.setInsecure(); #endif _mqttClient.setClient(_sslClient); #ifdef BOARD_HAS_SECRET_KEY - _mqttClient.setUsernamePassword(getDeviceId(), _password); + if(_password.length()) + { + _mqttClient.setUsernamePassword(getDeviceId(), _password); + } #endif _mqttClient.onMessage(ArduinoIoTCloudTCP::onMessage); _mqttClient.setKeepAliveInterval(30 * 1000); diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index a36abfef3..b305b1b4e 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -26,42 +26,42 @@ #include #include -#if defined(BOARD_HAS_SECRET_KEY) - #if defined(BOARD_ESP) - #include - #elif defined(ARDUINO_EDGE_CONTROL) - #include - #endif -#else +#if defined(BOARD_HAS_SECURE_ELEMENT) #include #include - #if defined(BOARD_HAS_OFFLOADED_ECCX08) - #else + #if !defined(BOARD_HAS_OFFLOADED_ECCX08) #include - #ifdef BOARD_HAS_ECCX08 - #include "tls/BearSSLClient.h" - #elif defined(BOARD_HAS_OFFLOADED_ECCX08) - #include - #elif defined(BOARD_HAS_SE050) - #if defined(ARDUINO_PORTENTA_C33) - #include - #else - #include - #endif - #elif defined(BOARD_HAS_SOFTSE) - #include - #endif #endif #endif +#if defined(BOARD_HAS_OFFLOADED_ECCX08) + #include "WiFiSSLClient.h" +#elif defined(BOARD_HAS_ECCX08) + #include "tls/BearSSLClient.h" +#elif defined(ARDUINO_PORTENTA_C33) + #include +#elif defined(ARDUINO_NICLA_VISION) + #include +#elif defined(ARDUINO_EDGE_CONTROL) + #include +#elif defined(ARDUINO_UNOR4_WIFI) + #include +#elif defined(BOARD_ESP) + #include +#endif + /****************************************************************************** CONSTANTS ******************************************************************************/ - +#if defined(BOARD_HAS_SECURE_ELEMENT) static char const DEFAULT_BROKER_ADDRESS_SECURE_AUTH[] = "mqtts-sa.iot.arduino.cc"; static uint16_t const DEFAULT_BROKER_PORT_SECURE_AUTH = 8883; +#endif + +#if defined(BOARD_HAS_SECRET_KEY) static char const DEFAULT_BROKER_ADDRESS_USER_PASS_AUTH[] = "mqtts-up.iot.arduino.cc"; static uint16_t const DEFAULT_BROKER_PORT_USER_PASS_AUTH = 8884; +#endif /****************************************************************************** * TYPEDEF @@ -85,11 +85,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass virtual int connected () override; virtual void printDebugInfo() override; - #if !defined(BOARD_HAS_SECRET_KEY) int begin(ConnectionHandler & connection, bool const enable_watchdog = true, String brokerAddress = DEFAULT_BROKER_ADDRESS_SECURE_AUTH, uint16_t brokerPort = DEFAULT_BROKER_PORT_SECURE_AUTH); - #else - int begin(ConnectionHandler & connection, bool const enable_watchdog = true, String brokerAddress = DEFAULT_BROKER_ADDRESS_USER_PASS_AUTH, uint16_t brokerPort = DEFAULT_BROKER_PORT_USER_PASS_AUTH); - #endif int begin(bool const enable_watchdog = true, String brokerAddress = DEFAULT_BROKER_ADDRESS_SECURE_AUTH, uint16_t brokerPort = DEFAULT_BROKER_PORT_SECURE_AUTH); #ifdef BOARD_HAS_SECRET_KEY @@ -150,29 +146,29 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass #if defined(BOARD_HAS_SECRET_KEY) String _password; - #if defined(BOARD_ESP) - WiFiClientSecure _sslClient; - #elif defined(ARDUINO_EDGE_CONTROL) - GSMSSLClient _sslClient; - #endif -#else +#endif + +#if defined(BOARD_HAS_SECURE_ELEMENT) SecureElement _crypto; - #if defined(BOARD_HAS_OFFLOADED_ECCX08) - WiFiBearSSLClient _sslClient; - #else - ECP256Certificate _cert; - #if defined(BOARD_HAS_ECCX08) + #if !defined(BOARD_HAS_OFFLOADED_ECCX08) + ECP256Certificate _cert; + #endif +#endif + +#if defined(BOARD_HAS_OFFLOADED_ECCX08) + WiFiSSLClient _sslClient; +#elif defined(BOARD_HAS_ECCX08) BearSSLClient _sslClient; - #elif defined(BOARD_HAS_SE050) - #if defined(ARDUINO_PORTENTA_C33) +#elif defined(ARDUINO_PORTENTA_C33) SSLClient _sslClient; - #else +#elif defined(ARDUINO_NICLA_VISION) WiFiSSLSE050Client _sslClient; - #endif - #elif defined(BOARD_HAS_SOFTSE) +#elif defined(ARDUINO_EDGE_CONTROL) + GSMSSLClient _sslClient; +#elif defined(ARDUINO_UNOR4_WIFI) WiFiSSLClient _sslClient; - #endif - #endif +#elif defined(BOARD_ESP) + WiFiClientSecure _sslClient; #endif MqttClient _mqttClient; diff --git a/src/tls/AIoTCUPCert.h b/src/tls/AIoTCUPCert.h index ac3daa707..330b8cb78 100644 --- a/src/tls/AIoTCUPCert.h +++ b/src/tls/AIoTCUPCert.h @@ -24,7 +24,7 @@ ******************************************************************************/ #include -#ifdef ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_UNOR4_WIFI) /****************************************************************************** * CONSTANTS From 8a1ab608524abdf95bcfb05ee48f2c0255151ffb Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 16 Feb 2024 13:56:51 +0100 Subject: [PATCH 05/10] Add Arduino_SecureElement to compile examples workflow --- .github/workflows/compile-examples.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml index 46837b40d..baf9a4b1e 100644 --- a/.github/workflows/compile-examples.yml +++ b/.github/workflows/compile-examples.yml @@ -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 From 37442d2b2d03e851a0182a560e7842a251359af6 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 16 Feb 2024 16:58:02 +0100 Subject: [PATCH 06/10] Use the same url for username/password and mTLS connection --- src/ArduinoIoTCloudTCP.cpp | 3 +-- src/ArduinoIoTCloudTCP.h | 10 ++-------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index e1a592452..906cd2dcf 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -114,11 +114,10 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP() int ArduinoIoTCloudTCP::begin(ConnectionHandler & connection, bool const enable_watchdog, String brokerAddress, uint16_t brokerPort) { _connection = &connection; + _brokerAddress = brokerAddress; #ifdef BOARD_HAS_SECRET_KEY - _brokerAddress = _password.length() ? DEFAULT_BROKER_ADDRESS_USER_PASS_AUTH : brokerAddress; _brokerPort = _password.length() ? DEFAULT_BROKER_PORT_USER_PASS_AUTH : brokerPort; #else - _brokerAddress = brokerAddress; _brokerPort = brokerPort; #endif _time_service.begin(&connection); diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index b305b1b4e..18b5541b4 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -53,15 +53,9 @@ /****************************************************************************** CONSTANTS ******************************************************************************/ -#if defined(BOARD_HAS_SECURE_ELEMENT) -static char const DEFAULT_BROKER_ADDRESS_SECURE_AUTH[] = "mqtts-sa.iot.arduino.cc"; +static char const DEFAULT_BROKER_ADDRESS_SECURE_AUTH[] = "iot.arduino.cc"; static uint16_t const DEFAULT_BROKER_PORT_SECURE_AUTH = 8883; -#endif - -#if defined(BOARD_HAS_SECRET_KEY) -static char const DEFAULT_BROKER_ADDRESS_USER_PASS_AUTH[] = "mqtts-up.iot.arduino.cc"; static uint16_t const DEFAULT_BROKER_PORT_USER_PASS_AUTH = 8884; -#endif /****************************************************************************** * TYPEDEF @@ -151,7 +145,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass #if defined(BOARD_HAS_SECURE_ELEMENT) SecureElement _crypto; #if !defined(BOARD_HAS_OFFLOADED_ECCX08) - ECP256Certificate _cert; + ECP256Certificate _cert; #endif #endif From 27f536b4fa7d879b83046ad334d0b881185b1501 Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 27 Feb 2024 11:45:09 +0100 Subject: [PATCH 07/10] UNO R4 WiFi: add error message about fw version and device certificate --- src/ArduinoIoTCloudTCP.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 906cd2dcf..d08051a23 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -143,6 +143,11 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, if (!_crypto.begin()) { DEBUG_ERROR("_crypto.begin() failed."); +#if defined(ARDUINO_UNOWIFIR4) + if (String(WiFi.firmwareVersion()) < String("0.4.1")) { + DEBUG_ERROR("ArduinoIoTCloudTCP::%s In order to read device certificate, WiFi firmware needs to be >= 0.4.1, current %s", __FUNCTION__, WiFi.firmwareVersion()); + } +#endif return 0; } if (!SElementArduinoCloudDeviceId::read(_crypto, getDeviceId(), SElementArduinoCloudSlot::DeviceId)) From 863408476216c01820f67afe37b3fd3323996ebe Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 27 Feb 2024 11:49:42 +0100 Subject: [PATCH 08/10] Rename _crypto in _selement --- src/ArduinoIoTCloudTCP.cpp | 10 +++++----- src/ArduinoIoTCloudTCP.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index d08051a23..5c009c484 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -140,9 +140,9 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, { #endif #if defined(BOARD_HAS_SECURE_ELEMENT) - if (!_crypto.begin()) + if (!_selement.begin()) { - DEBUG_ERROR("_crypto.begin() failed."); + DEBUG_ERROR("_selement.begin() failed."); #if defined(ARDUINO_UNOWIFIR4) if (String(WiFi.firmwareVersion()) < String("0.4.1")) { DEBUG_ERROR("ArduinoIoTCloudTCP::%s In order to read device certificate, WiFi firmware needs to be >= 0.4.1, current %s", __FUNCTION__, WiFi.firmwareVersion()); @@ -150,13 +150,13 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, #endif return 0; } - if (!SElementArduinoCloudDeviceId::read(_crypto, getDeviceId(), SElementArduinoCloudSlot::DeviceId)) + if (!SElementArduinoCloudDeviceId::read(_selement, getDeviceId(), SElementArduinoCloudSlot::DeviceId)) { - DEBUG_ERROR("_crypto.readDeviceId(...) failed."); + DEBUG_ERROR("_selement.readDeviceId(...) failed."); return 0; } #if !defined(BOARD_HAS_OFFLOADED_ECCX08) - if (!SElementArduinoCloudCertificate::read(_crypto, _cert, SElementArduinoCloudSlot::CompressedCertificate)) + if (!SElementArduinoCloudCertificate::read(_selement, _cert, SElementArduinoCloudSlot::CompressedCertificate)) { DEBUG_ERROR("Cryptography certificate reconstruction failure."); return 0; diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index 18b5541b4..821fb9dda 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -143,7 +143,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass #endif #if defined(BOARD_HAS_SECURE_ELEMENT) - SecureElement _crypto; + SecureElement _selement; #if !defined(BOARD_HAS_OFFLOADED_ECCX08) ECP256Certificate _cert; #endif From 6575af1764554a358fd1b41dde31b948b8e3f154 Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 27 Feb 2024 11:53:09 +0100 Subject: [PATCH 09/10] Align style of secure element debug error prints --- src/ArduinoIoTCloudTCP.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 5c009c484..a78915031 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -142,7 +142,7 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, #if defined(BOARD_HAS_SECURE_ELEMENT) if (!_selement.begin()) { - DEBUG_ERROR("_selement.begin() failed."); + DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not initialize secure element.", __FUNCTION__); #if defined(ARDUINO_UNOWIFIR4) if (String(WiFi.firmwareVersion()) < String("0.4.1")) { DEBUG_ERROR("ArduinoIoTCloudTCP::%s In order to read device certificate, WiFi firmware needs to be >= 0.4.1, current %s", __FUNCTION__, WiFi.firmwareVersion()); @@ -152,13 +152,13 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, } if (!SElementArduinoCloudDeviceId::read(_selement, getDeviceId(), SElementArduinoCloudSlot::DeviceId)) { - DEBUG_ERROR("_selement.readDeviceId(...) failed."); + DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not read device id.", __FUNCTION__); return 0; } #if !defined(BOARD_HAS_OFFLOADED_ECCX08) if (!SElementArduinoCloudCertificate::read(_selement, _cert, SElementArduinoCloudSlot::CompressedCertificate)) { - DEBUG_ERROR("Cryptography certificate reconstruction failure."); + DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not read device certificate.", __FUNCTION__); return 0; } _sslClient.setEccSlot(static_cast(SElementArduinoCloudSlot::Key), _cert.bytes(), _cert.length()); From ae996ce7f9003c8e8991f191566f17eb25abaa2a Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 5 Mar 2024 10:17:58 +0100 Subject: [PATCH 10/10] Fix: use WiFiBearSSLClient for boards with offloaded ECCX08 --- src/ArduinoIoTCloudTCP.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index 821fb9dda..60b6649cc 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -150,7 +150,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass #endif #if defined(BOARD_HAS_OFFLOADED_ECCX08) - WiFiSSLClient _sslClient; + WiFiBearSSLClient _sslClient; #elif defined(BOARD_HAS_ECCX08) BearSSLClient _sslClient; #elif defined(ARDUINO_PORTENTA_C33)