Skip to content

Commit a4a1d7e

Browse files
committed
WIP: device certificate update poc
1 parent c28ca7a commit a4a1d7e

File tree

5 files changed

+204
-0
lines changed

5 files changed

+204
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#include "arduino_secrets.h"
2+
/*
3+
Sketch generated by the Arduino IoT Cloud Thing "Untitled"
4+
https://create.arduino.cc/cloud/things/cc13b5b3-b496-44af-b55a-a20394c27398
5+
6+
Arduino IoT Cloud Variables description
7+
8+
The following variables are automatically generated and updated when changes are made to the Thing
9+
10+
int seconds;
11+
12+
Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
13+
which are called when their values are changed from the Dashboard.
14+
These functions are generated with the Thing and added at the end of this sketch.
15+
*/
16+
17+
#include "thingProperties.h"
18+
19+
20+
21+
void setup() {
22+
// Initialize serial and wait for port to open:
23+
Serial.begin(9600);
24+
// This delay gives the chance to wait for a Serial Monitor without blocking if none is found
25+
delay(1500);
26+
27+
// Defined in thingProperties.h
28+
initProperties();
29+
30+
// Connect to Arduino IoT Cloud
31+
ArduinoCloud.begin(ArduinoIoTPreferredConnection, true, "iot.oniudra.cc");
32+
33+
/*
34+
The following function allows you to obtain more information
35+
related to the state of network and IoT Cloud connection and errors
36+
the higher number the more granular information you’ll get.
37+
The default is 0 (only errors).
38+
Maximum is 4
39+
*/
40+
setDebugMessageLevel(2);
41+
ArduinoCloud.printDebugInfo();
42+
}
43+
44+
void loop() {
45+
ArduinoCloud.update();
46+
// Your code here
47+
seconds = millis()/1000;
48+
}
49+
50+
51+
52+
/*
53+
Since Seconds is READ_WRITE variable, onSecondsChange() is
54+
executed every time a new value is received from IoT Cloud.
55+
*/
56+
void onSecondsChange() {
57+
// Add your code here to act upon Seconds change
58+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#define SECRET_OPTIONAL_PASS ""
2+
#define SECRET_SSID ""
3+
4+
#define SECRET_ISSUE_YEAR ""
5+
#define SECRET_ISSUE_MONTH ""
6+
#define SECRET_ISSUE_DAY ""
7+
#define SECRET_ISSUE_HOUR ""
8+
#define SECRET_EXPIRE_YEARS ""
9+
#define SECRET_SERIAL_NUMBER ""
10+
#define SECRET_AUTHORITY_KEY_ID ""
11+
#define SECRET_SIGNATURE ""
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Code generated by Arduino IoT Cloud, DO NOT EDIT.
2+
3+
#include <ArduinoIoTCloud.h>
4+
#include <Arduino_ConnectionHandler.h>
5+
6+
const char SSID[] = SECRET_SSID; // Network SSID (name)
7+
const char PASS[] = SECRET_OPTIONAL_PASS; // Network password (use for WPA, or use as key for WEP)
8+
9+
const char ISSUE_YEAR[] = SECRET_ISSUE_YEAR;
10+
const char ISSUE_MONTH[] = SECRET_ISSUE_MONTH;
11+
const char ISSUE_DAY[] = SECRET_ISSUE_DAY;
12+
const char ISSUE_HOUR[] = SECRET_ISSUE_HOUR;
13+
const char EXPIRE_YEARS[] = SECRET_EXPIRE_YEARS;
14+
const char SERIAL_NUMBER[] = SECRET_SERIAL_NUMBER;
15+
const char AUTHORITY_KEY_ID[] = SECRET_AUTHORITY_KEY_ID;
16+
const char SIGNATURE[] = SECRET_SIGNATURE;
17+
18+
void onSecondsChange();
19+
20+
int seconds;
21+
22+
void initProperties(){
23+
24+
ArduinoCloud.addProperty(seconds, READWRITE, ON_CHANGE, onSecondsChange);
25+
ArduinoCloud.updateCertificate(ISSUE_YEAR, ISSUE_MONTH, ISSUE_DAY, ISSUE_HOUR, EXPIRE_YEARS, SERIAL_NUMBER, AUTHORITY_KEY_ID,SIGNATURE);
26+
27+
}
28+
29+
WiFiConnectionHandler ArduinoIoTPreferredConnection(SSID, PASS);

src/ArduinoIoTCloudTCP.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,108 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
204204
return 1;
205205
}
206206

207+
#if defined(BOARD_HAS_SECURE_ELEMENT)
208+
static void hexStringToBytes(String& in, byte out[], int length) {
209+
int inLength = in.length();
210+
in.toUpperCase();
211+
int outLength = 0;
212+
213+
for (int i = 0; i < inLength && outLength < length; i += 2) {
214+
char highChar = in[i];
215+
char lowChar = in[i + 1];
216+
217+
byte highByte = (highChar <= '9') ? (highChar - '0') : (highChar + 10 - 'A');
218+
byte lowByte = (lowChar <= '9') ? (lowChar - '0') : (lowChar + 10 - 'A');
219+
220+
out[outLength++] = (highByte << 4) | (lowByte & 0xF);
221+
}
222+
}
223+
224+
int ArduinoIoTCloudTCP::updateCertificate(String issueYear, String issueMonth, String issueDay, String issueHour, String expireYears, String serialNumber, String authorityKeyIdentifier, String signature)
225+
{
226+
ECP256Certificate Certificate;
227+
228+
byte serialNumberBytes[ECP256_CERT_SERIAL_NUMBER_LENGTH];
229+
byte authorityKeyIdentifierBytes[ECP256_CERT_AUTHORITY_KEY_ID_LENGTH];
230+
byte signatureBytes[ECP256_CERT_SIGNATURE_LENGTH];
231+
232+
hexStringToBytes(serialNumber, serialNumberBytes, sizeof(serialNumberBytes));
233+
hexStringToBytes(authorityKeyIdentifier, authorityKeyIdentifierBytes, sizeof(authorityKeyIdentifierBytes));
234+
hexStringToBytes(signature, signatureBytes, sizeof(signatureBytes));
235+
236+
if (!_selement.begin())
237+
{
238+
DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not initialize secure element.", __FUNCTION__);
239+
#if defined(ARDUINO_UNOWIFIR4)
240+
if (String(WiFi.firmwareVersion()) < String("0.4.1")) {
241+
DEBUG_ERROR("ArduinoIoTCloudTCP::%s In order to read device certificate, WiFi firmware needs to be >= 0.4.1, current %s", __FUNCTION__, WiFi.firmwareVersion());
242+
}
243+
#endif
244+
return 0;
245+
}
246+
if (!SElementArduinoCloudDeviceId::read(_selement, getDeviceId(), SElementArduinoCloudSlot::DeviceId))
247+
{
248+
DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not read device id.", __FUNCTION__);
249+
return 0;
250+
}
251+
if (!SElementArduinoCloudCertificate::read(_selement, _cert, SElementArduinoCloudSlot::CompressedCertificate))
252+
{
253+
DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not read device certificate.", __FUNCTION__);
254+
return 0;
255+
}
256+
257+
if (!Certificate.begin()) {
258+
/* WARNING: This string is parsed from IoTCloud frontend */
259+
Serial.println("Error starting crypto storage!");
260+
}
261+
262+
Certificate.setSubjectCommonName(getDeviceId());
263+
Certificate.setIssuerCountryName("US");
264+
Certificate.setIssuerOrganizationName("Arduino LLC US");
265+
Certificate.setIssuerOrganizationalUnitName("IT");
266+
Certificate.setIssuerCommonName("Arduino");
267+
Certificate.setSignature(signatureBytes, sizeof(signatureBytes));
268+
Certificate.setAuthorityKeyId(authorityKeyIdentifierBytes, sizeof(authorityKeyIdentifierBytes));
269+
Certificate.setSerialNumber(serialNumberBytes, sizeof(serialNumberBytes));
270+
Certificate.setIssueYear(issueYear.toInt());
271+
Certificate.setIssueMonth(issueMonth.toInt());
272+
Certificate.setIssueDay(issueDay.toInt());
273+
Certificate.setIssueHour(issueHour.toInt());
274+
Certificate.setExpireYears(expireYears.toInt());
275+
276+
if (!SElementArduinoCloudCertificate::build(_selement, Certificate, static_cast<int>(SElementArduinoCloudSlot::Key))) {
277+
Serial.println("Error building cert!");
278+
}
279+
280+
String cert = Certificate.getCertPEM();
281+
if (!cert) {
282+
Serial.println("Error generating cert!");
283+
}
284+
Serial.println("New Cert PEM = ");
285+
Serial.println();
286+
Serial.println(cert);
287+
288+
String oldcert = _cert.getCertPEM();
289+
if (!oldcert) {
290+
Serial.println("Error generating cert!");
291+
}
292+
Serial.println("Old Cert PEM = ");
293+
Serial.println();
294+
Serial.println(oldcert);
295+
296+
297+
Serial.println("We have a certificate update");
298+
299+
if ((Certificate.length() != _cert.length()) || memcmp(_cert.bytes(), Certificate.bytes(), _cert.length() ))
300+
{
301+
Serial.println("Certificate are different");
302+
if (!SElementArduinoCloudCertificate::write(_selement, Certificate, SElementArduinoCloudSlot::CompressedCertificate)) {
303+
Serial.println("Error storing cert!");
304+
}
305+
}
306+
}
307+
#endif
308+
207309
void ArduinoIoTCloudTCP::update()
208310
{
209311
/* Feed the watchdog. If any of the functions called below

src/ArduinoIoTCloudTCP.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
7777
int begin(ConnectionHandler & connection, bool const enable_watchdog = true, String brokerAddress = DEFAULT_BROKER_ADDRESS_SECURE_AUTH, uint16_t brokerPort = DEFAULT_BROKER_PORT_SECURE_AUTH);
7878
int begin(bool const enable_watchdog = true, String brokerAddress = DEFAULT_BROKER_ADDRESS_SECURE_AUTH, uint16_t brokerPort = DEFAULT_BROKER_PORT_SECURE_AUTH);
7979

80+
#if defined(BOARD_HAS_SECURE_ELEMENT)
81+
int updateCertificate(String issueYear, String issueMonth, String issueDay, String issueHour, String expireYears, String serialNumber, String authorityKeyIdentifier, String signature);
82+
#endif
83+
8084
#ifdef BOARD_HAS_SECRET_KEY
8185
inline void setBoardId (String const device_id) { setDeviceId(device_id); }
8286
inline void setSecretDeviceKey(String const password) { _password = password; }

0 commit comments

Comments
 (0)