Skip to content

Allow device certificate update #522

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
Jan 24, 2025
121 changes: 97 additions & 24 deletions src/ArduinoIoTCloudTCP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
#ifdef BOARD_HAS_SECRET_KEY
, _password("")
#endif
#if defined(BOARD_HAS_SECURE_ELEMENT)
, _writeCertOnConnect(false)
#endif
, _mqttClient{nullptr}
, _messageTopicOut("")
, _messageTopicIn("")
Expand All @@ -80,11 +83,6 @@ int ArduinoIoTCloudTCP::begin(ConnectionHandler & connection, bool const enable_
{
_connection = &connection;
_brokerAddress = brokerAddress;
#ifdef BOARD_HAS_SECRET_KEY
_brokerPort = _password.length() ? DEFAULT_BROKER_PORT_USER_PASS_AUTH : brokerPort;
#else
_brokerPort = brokerPort;
#endif

/* Setup broker TLS client */
_brokerClient.begin(connection);
Expand All @@ -94,20 +92,7 @@ int ArduinoIoTCloudTCP::begin(ConnectionHandler & connection, bool const enable_
_otaClient.begin(connection);
#endif

/* Setup TimeService */
_time_service.begin(_connection);

/* Setup retry timers */
_connection_attempt.begin(AIOT_CONFIG_RECONNECTION_RETRY_DELAY_ms, AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms);
return begin(enable_watchdog, _brokerAddress, _brokerPort);
}

int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, uint16_t brokerPort)
{
_brokerAddress = brokerAddress;
_brokerPort = brokerPort;

#if defined(BOARD_HAS_SECRET_KEY)
#if defined (BOARD_HAS_SECRET_KEY)
/* If board is not configured for username and password login */
if(!_password.length())
{
Expand All @@ -129,23 +114,44 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
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("ArduinoIoTCloudTCP::%s could not read device certificate.", __FUNCTION__);
return 0;
if (!_writeCertOnConnect) {
/* No update pending read certificate stored in secure element */
if (!SElementArduinoCloudCertificate::read(_selement, _cert, SElementArduinoCloudSlot::CompressedCertificate))
{
DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not read device certificate.", __FUNCTION__);
return 0;
}
}
#if !defined(BOARD_HAS_OFFLOADED_ECCX08)
_brokerClient.setEccSlot(static_cast<int>(SElementArduinoCloudSlot::Key), _cert.bytes(), _cert.length());
#if OTA_ENABLED
_otaClient.setEccSlot(static_cast<int>(SElementArduinoCloudSlot::Key), _cert.bytes(), _cert.length());
#endif
#endif
_brokerPort = (brokerPort == DEFAULT_BROKER_PORT_AUTO) ? mqttPort() : brokerPort;
#endif

#if defined(BOARD_HAS_SECRET_KEY)
}
else
{
_brokerPort = (brokerPort == DEFAULT_BROKER_PORT_AUTO) ? DEFAULT_BROKER_PORT_USER_PASS_AUTH : brokerPort;
}
#endif

/* Setup TimeService */
_time_service.begin(_connection);

/* Setup retry timers */
_connection_attempt.begin(AIOT_CONFIG_RECONNECTION_RETRY_DELAY_ms, AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms);
return begin(enable_watchdog, _brokerAddress, _brokerPort);
}

int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, uint16_t brokerPort)
{
_brokerAddress = brokerAddress;
_brokerPort = brokerPort;

_mqttClient.setClient(_brokerClient);

#ifdef BOARD_HAS_SECRET_KEY
Expand Down Expand Up @@ -281,6 +287,17 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectMqttBroker()
/* Subscribe to message topic to receive commands */
_mqttClient.subscribe(_messageTopicIn);

#if defined(BOARD_HAS_SECURE_ELEMENT)
/* A device certificate update was pending */
if (_writeCertOnConnect)
{
if (SElementArduinoCloudCertificate::write(_selement, _cert, SElementArduinoCloudSlot::CompressedCertificate))
{
DEBUG_INFO("ArduinoIoTCloudTCP::%s device certificate update done.", __FUNCTION__);
_writeCertOnConnect = false;
}
}
#endif
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s connected to %s:%d", __FUNCTION__, _brokerAddress.c_str(), _brokerPort);
return State::Connected;
}
Expand Down Expand Up @@ -558,6 +575,62 @@ int ArduinoIoTCloudTCP::write(String const topic, byte const data[], int const l
return 0;
}

#if defined(BOARD_HAS_SECURE_ELEMENT)
int ArduinoIoTCloudTCP::mqttPort()
{
if (memcmp(DEPRECATED_BROKER_AUTHORITY_KEY_IDENTIFIER, _cert.authorityKeyIdentifierBytes() , ECP256_CERT_AUTHORITY_KEY_ID_LENGTH) == 0) {
return DEPRECATED_BROKER_PORT_SECURE_AUTH;
} else {
return DEFAULT_BROKER_PORT_SECURE_AUTH;
}
}

int ArduinoIoTCloudTCP::updateCertificate(String authorityKeyIdentifier, String serialNumber, String notBefore, String notAfter, String signature)
{
if (!_selement.begin())
{
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());
}
#endif
return 0;
}
if (!SElementArduinoCloudDeviceId::read(_selement, getDeviceId(), SElementArduinoCloudSlot::DeviceId))
{
DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not read device id.", __FUNCTION__);
return 0;
}
/* read certificate stored in secure element to compare AUTHORITY_KEY_ID */
if (!SElementArduinoCloudCertificate::read(_selement, _cert, SElementArduinoCloudSlot::CompressedCertificate))
{
DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not read device certificate.", __FUNCTION__);
return 0;
}
/* check if we need to update 0 = equal <0 = error skip rebuild */
if(SElementArduinoCloudCertificate::signatureCompare(_cert.signatureBytes(), signature) <= 0) {
DEBUG_INFO("ArduinoIoTCloudTCP::%s request skipped.", __FUNCTION__);
return 0;
}
/* rebuild device certificate */
if (SElementArduinoCloudCertificate::rebuild(_selement, _cert, getDeviceId(), notBefore, notAfter, serialNumber, authorityKeyIdentifier, signature))
{
DEBUG_INFO("ArduinoIoTCloudTCP::%s request started.", __FUNCTION__);
#if defined(BOARD_HAS_OFFLOADED_ECCX08)
if (SElementArduinoCloudCertificate::write(_selement, _cert, SElementArduinoCloudSlot::CompressedCertificate))
{
DEBUG_INFO("ArduinoIoTCloudTCP::%s update done.", __FUNCTION__);
}
#else
_writeCertOnConnect = true;
#endif
return 1;
}
return 0;
}
#endif

/******************************************************************************
* EXTERN DEFINITION
******************************************************************************/
Expand Down
37 changes: 24 additions & 13 deletions src/ArduinoIoTCloudTCP.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,14 @@
#if defined(BOARD_HAS_SECURE_ELEMENT)
#include <Arduino_SecureElement.h>
#include <utility/SElementArduinoCloudDeviceId.h>
#if !defined(BOARD_HAS_OFFLOADED_ECCX08)
#include <utility/SElementArduinoCloudCertificate.h>
#endif
#include <utility/SElementArduinoCloudCertificate.h>
#endif

#include <tls/utility/TLSClientMqtt.h>
#include <tls/utility/TLSClientOta.h>

#if OTA_ENABLED
#include <ota/OTA.h>
#include <ota/OTA.h>
#endif

#include "cbor/MessageDecoder.h"
Expand All @@ -49,9 +47,14 @@
/******************************************************************************
CONSTANTS
******************************************************************************/
static char const DEFAULT_BROKER_ADDRESS_SECURE_AUTH[] = "iot.arduino.cc";
static uint16_t const DEFAULT_BROKER_PORT_SECURE_AUTH = 8883;
static uint16_t const DEFAULT_BROKER_PORT_USER_PASS_AUTH = 8884;
static constexpr char DEFAULT_BROKER_ADDRESS[] = "iot.arduino.cc";
static constexpr uint16_t DEFAULT_BROKER_PORT_SECURE_AUTH = 8885;
static constexpr uint16_t DEPRECATED_BROKER_PORT_SECURE_AUTH = 8883;
static constexpr uint8_t DEPRECATED_BROKER_AUTHORITY_KEY_IDENTIFIER[] = {
0x5b, 0x3e, 0x2a, 0x6b, 0x8e, 0xc9, 0xb0, 0x1a, 0xa8, 0x54,
0xe6, 0x36, 0x9b, 0x8c, 0x09, 0xf9, 0xfc, 0xe1, 0xb9, 0x80 };
static constexpr uint16_t DEFAULT_BROKER_PORT_USER_PASS_AUTH = 8884;
static constexpr uint16_t DEFAULT_BROKER_PORT_AUTO = 0;

/******************************************************************************
* TYPEDEF
Expand All @@ -74,13 +77,17 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
virtual int connected () override;
virtual void printDebugInfo() override;

int begin(ConnectionHandler & connection, bool const enable_watchdog = true, String brokerAddress = DEFAULT_BROKER_ADDRESS_SECURE_AUTH, uint16_t brokerPort = DEFAULT_BROKER_PORT_SECURE_AUTH);
int begin(bool const enable_watchdog = true, String brokerAddress = DEFAULT_BROKER_ADDRESS_SECURE_AUTH, uint16_t brokerPort = DEFAULT_BROKER_PORT_SECURE_AUTH);
int begin(ConnectionHandler & connection, bool const enable_watchdog = true, String brokerAddress = DEFAULT_BROKER_ADDRESS, uint16_t brokerPort = DEFAULT_BROKER_PORT_AUTO);
int begin(bool const enable_watchdog = true, String brokerAddress = DEFAULT_BROKER_ADDRESS, uint16_t brokerPort = DEFAULT_BROKER_PORT_AUTO);

#ifdef BOARD_HAS_SECRET_KEY
#if defined(BOARD_HAS_SECURE_ELEMENT)
int updateCertificate(String authorityKeyIdentifier, String serialNumber, String notBefore, String notAfter, String signature);
#endif

#ifdef BOARD_HAS_SECRET_KEY
inline void setBoardId (String const device_id) { setDeviceId(device_id); }
inline void setSecretDeviceKey(String const password) { _password = password; }
#endif
#endif

inline String getBrokerAddress() const { return _brokerAddress; }
inline uint16_t getBrokerPort () const { return _brokerPort; }
Expand Down Expand Up @@ -142,9 +149,9 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass

#if defined(BOARD_HAS_SECURE_ELEMENT)
SecureElement _selement;
#if !defined(BOARD_HAS_OFFLOADED_ECCX08)
ECP256Certificate _cert;
#endif
/* Flag used to store updated device certificate after broker connection has succeeded */
bool _writeCertOnConnect;
#endif

TLSClientMqtt _brokerClient;
Expand Down Expand Up @@ -183,6 +190,10 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
void detachThing();
int write(String const topic, byte const data[], int const length);

#if defined(BOARD_HAS_SECURE_ELEMENT)
int mqttPort();
#endif

};

/******************************************************************************
Expand Down
27 changes: 27 additions & 0 deletions src/tls/AIoTCSSCert.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
* CONSTANTS
******************************************************************************/
static const char AIoTSSCert[] =
/* https://iot.arduino.cc:8883 */
"-----BEGIN CERTIFICATE-----\n"
"MIIBzzCCAXSgAwIBAgIUHxAd66fhJecnwaOR4+wNF03tSlkwCgYIKoZIzj0EAwIw\n"
"RTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkFyZHVpbm8gTExDIFVTMQswCQYDVQQL\n"
Expand All @@ -41,6 +42,32 @@ static const char AIoTSSCert[] =
"VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWz4qa47JsBqoVOY2m4wJ+fzhuYAwCgYI\n"
"KoZIzj0EAwIDSQAwRgIhAL/T3CNmaLUK3D8NDsNz4grH92CqEA3TIL/hApabawXY\n"
"AiEA6tnZ2lrNElKXCajtZg/hjWRE/+giFzBP8riar8qOz2w=\n"
"-----END CERTIFICATE-----\n"
/* https://iot.arduino.cc:8885 */
"-----BEGIN CERTIFICATE-----\n"
"MIIB0DCCAXagAwIBAgIUb62eK/Vv1baaPAaY5DADBUbxB1owCgYIKoZIzj0EAwIw\n"
"RTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkFyZHVpbm8gTExDIFVTMQswCQYDVQQL\n"
"EwJJVDEQMA4GA1UEAxMHQXJkdWlubzAgFw0yNTAxMTAxMDUzMjJaGA8yMDU1MDEw\n"
"MzEwNTMyMlowRTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkFyZHVpbm8gTExDIFVT\n"
"MQswCQYDVQQLEwJJVDEQMA4GA1UEAxMHQXJkdWlubzBZMBMGByqGSM49AgEGCCqG\n"
"SM49AwEHA0IABKHhU2w1UhozDegrrFsSwY9QN7M+ZJug7icCNceNWhBF0Mr1UuyX\n"
"8pr/gcbieZc/0znG16HMa2GFcPY7rmIdccijQjBAMA8GA1UdEwEB/wQFMAMBAf8w\n"
"DgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRCZSmE0ASI0cYD9AmzeOM7EijgPjAK\n"
"BggqhkjOPQQDAgNIADBFAiEAz6TLYP9eiVOr/cVU/11zwGofe/FoNe4p1BlzMl7G\n"
"VVACIG8tL3Ta2WbIOaUVpBL2gfLuI9WSW1sR++zXP+zFhmen\n"
"-----END CERTIFICATE-----\n"
/* https://iot.oniudra.cc:8885 */
"-----BEGIN CERTIFICATE-----\n"
"MIIBzzCCAXagAwIBAgIUI5fEitwlnwujc/mU0d8LnDiDXBIwCgYIKoZIzj0EAwIw\n"
"RTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkFyZHVpbm8gTExDIFVTMQswCQYDVQQL\n"
"EwJJVDEQMA4GA1UEAxMHQXJkdWlubzAgFw0yNTAxMDgxMTA4MzdaGA8yMDU1MDEw\n"
"MTExMDgzN1owRTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkFyZHVpbm8gTExDIFVT\n"
"MQswCQYDVQQLEwJJVDEQMA4GA1UEAxMHQXJkdWlubzBZMBMGByqGSM49AgEGCCqG\n"
"SM49AwEHA0IABBFwNODDPgC9C1kDmKBbawtQ31FmTudAXVpGSOUwcDX582z820cD\n"
"eIaCwOxghmI+p/CpOH63f5F6h23ErqZMBkijQjBAMA8GA1UdEwEB/wQFMAMBAf8w\n"
"DgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQdnBmQGLB7ls/r1Tetdp+MVMqxfTAK\n"
"BggqhkjOPQQDAgNHADBEAiBPSZ9HpF7MuFoK4Jsz//PHILQuHM4WmRopQR9ysSs0\n"
"HAIgNadMPgxv01dy59kCgzehgKzmKdTF0rG1SniYqnkLqPA=\n"
"-----END CERTIFICATE-----\n";

#endif /* #if defined(BOARD_HAS_SE050) || defined(BOARD_HAS_SOFTSE) */
Expand Down
Loading
Loading