Skip to content
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

Add function to rebuild ArduinoCloud device certificate #21

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/ECP256Certificate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
* INCLUDE
******************************************************************************/

#define _GNU_SOURCE
#include <string.h>
#include "ECP256Certificate.h"

/******************************************************************************
Expand Down Expand Up @@ -384,6 +386,17 @@ int ECP256Certificate::setSignature(const byte* signature, int signatureLen) {
return 0;
}

const byte * ECP256Certificate::authorityKeyId() const {
static const byte objectId[] = {0x06, 0x03, 0x55, 0x1D, 0x23};
byte * result = nullptr;
void * ptr = memmem(_certBuffer, _certBufferLen, objectId, sizeof(objectId));
if (ptr != nullptr) {
result = (byte*)ptr;
result += 11;
}
return result;
}

/******************************************************************************
* PRIVATE MEMBER FUNCTIONS
******************************************************************************/
Expand Down
3 changes: 3 additions & 0 deletions src/ECP256Certificate.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ class ECP256Certificate {
inline byte* bytes() { return _certBuffer; }
inline int length() { return _certBufferLen; }

/* Parsing Helpers */
const byte * authorityKeyId() const;

#if defined(SECURE_ELEMENT_IS_ECCX08)
/* Get Data to create ECCX08 compressed cert */
inline byte* compressedCertBytes() { return _compressedCert.data; }
Expand Down
26 changes: 26 additions & 0 deletions src/SecureElementConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,30 @@
#define SECURE_ELEMENT_IS_SOFTSE
#endif

#if defined __has_include
#if __has_include (<Arduino_DebugUtils.h>)
#include <Arduino_DebugUtils.h>
#endif
#endif

#ifndef DEBUG_ERROR
#define DEBUG_ERROR(fmt, ...)
#endif

#ifndef DEBUG_WARNING
#define DEBUG_WARNING(fmt, ...)
#endif

#ifndef DEBUG_INFO
#define DEBUG_INFO(fmt, ...)
#endif

#ifndef DEBUG_DEBUG
#define DEBUG_DEBUG(fmt, ...)
#endif

#ifndef DEBUG_VERBOSE
#define DEBUG_VERBOSE(fmt, ...)
#endif

#endif /* SECURE_ELEMENT_CONFIG_H_ */
85 changes: 85 additions & 0 deletions src/utility/SElementArduinoCloudCertificate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,30 @@

#include <utility/SElementArduinoCloudCertificate.h>

/******************************************************************************
* LOCAL MODULE FUNCTIONS
******************************************************************************/

static void hexStringToBytes(String in, byte out[], int length) {
int inLength = in.length();
in.toUpperCase();
int outLength = 0;

for (int i = 0; i < inLength && outLength < length; i += 2) {
char highChar = in[i];
char lowChar = in[i + 1];

byte highByte = (highChar <= '9') ? (highChar - '0') : (highChar + 10 - 'A');
byte lowByte = (lowChar <= '9') ? (lowChar - '0') : (lowChar + 10 - 'A');

out[outLength++] = (highByte << 4) | (lowByte & 0xF);
}
}

/******************************************************************************
* PUBLIC MEMBER FUNCTIONS
******************************************************************************/

int SElementArduinoCloudCertificate::write(SecureElement & se, ECP256Certificate & cert, const SElementArduinoCloudSlot certSlot)
{
#if defined(SECURE_ELEMENT_IS_SE050) || defined(SECURE_ELEMENT_IS_SOFTSE)
Expand Down Expand Up @@ -92,3 +116,64 @@ int SElementArduinoCloudCertificate::read(SecureElement & se, ECP256Certificate
#endif
return 1;
}

int SElementArduinoCloudCertificate::isAuthorityKeyIdDifferent(const ECP256Certificate & cert, const String& authorityKeyIdentifier)
{
byte authorityKeyIdentifierBytes[ECP256_CERT_AUTHORITY_KEY_ID_LENGTH];

if (authorityKeyIdentifier.length() == 0 || cert.authorityKeyId() == nullptr) {
DEBUG_ERROR("SEACC::%s input params error.", __FUNCTION__);
return -1;
}

hexStringToBytes(authorityKeyIdentifier, authorityKeyIdentifierBytes, sizeof(authorityKeyIdentifierBytes));

/* If authorityKeyId are matching there is no need to rebuild*/
if (memcmp(authorityKeyIdentifierBytes, cert.authorityKeyId() , ECP256_CERT_AUTHORITY_KEY_ID_LENGTH) == 0) {
DEBUG_VERBOSE("SEACC::%s authorityKeyIdentifierBytes are equal", __FUNCTION__);
return 0;
}
return 1;
}

int SElementArduinoCloudCertificate::rebuild(SecureElement & se, ECP256Certificate & cert, const String & deviceId, const String & notBefore, const String & notAfter, const String & serialNumber, const String & authorityKeyIdentifier, const String & signature, const SElementArduinoCloudSlot keySlot)
{
byte serialNumberBytes[ECP256_CERT_SERIAL_NUMBER_LENGTH];
byte authorityKeyIdentifierBytes[ECP256_CERT_AUTHORITY_KEY_ID_LENGTH];
byte signatureBytes[ECP256_CERT_SIGNATURE_LENGTH];

if (!deviceId.length() || !notBefore.length() || !notAfter.length() || !serialNumber.length() || !authorityKeyIdentifier.length() || !signature.length() ) {
DEBUG_ERROR("SEACC::%s input params error.", __FUNCTION__);
return 0;
}

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

if (!cert.begin()) {
DEBUG_ERROR("SEACC::%s cert begin error", __FUNCTION__);
return -1;
}

cert.setSubjectCommonName(deviceId);
cert.setIssuerCountryName("US");
cert.setIssuerOrganizationName("Arduino LLC US");
cert.setIssuerOrganizationalUnitName("IT");
cert.setIssuerCommonName("Arduino");
cert.setSignature(signatureBytes, sizeof(signatureBytes));
cert.setAuthorityKeyId(authorityKeyIdentifierBytes, sizeof(authorityKeyIdentifierBytes));
cert.setSerialNumber(serialNumberBytes, sizeof(serialNumberBytes));
cert.setIssueYear(notBefore.substring(0,4).toInt());
cert.setIssueMonth(notBefore.substring(5,7).toInt());
cert.setIssueDay(notBefore.substring(8,10).toInt());
cert.setIssueHour(notBefore.substring(11,13).toInt());
cert.setExpireYears(notAfter.substring(0,4).toInt() - notBefore.substring(0,4).toInt());


if (!SElementCertificate::build(se, cert, static_cast<int>(keySlot))) {
DEBUG_ERROR("SEACC::%s cert build error", __FUNCTION__);
return -1;
}
return 1;
}
5 changes: 5 additions & 0 deletions src/utility/SElementArduinoCloudCertificate.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ class SElementArduinoCloudCertificate : public SElementCertificate

static int write(SecureElement & se, ECP256Certificate & cert, const SElementArduinoCloudSlot certSlot);
static int read(SecureElement & se, ECP256Certificate & cert, const SElementArduinoCloudSlot certSlot, const SElementArduinoCloudSlot keySlot = SElementArduinoCloudSlot::Key);
static int isAuthorityKeyIdDifferent(const ECP256Certificate & cert, const String& authorityKeyIdentifier);
static int rebuild(SecureElement & se, ECP256Certificate & cert, const String & deviceId,
const String & notBefore, const String & notAfter, const String & serialNumber,
const String & authorityKeyIdentifier, const String & signature,
const SElementArduinoCloudSlot keySlot = SElementArduinoCloudSlot::Key);

};

Expand Down
Loading