Skip to content

[CM-22] Authority Key Identifier support #6

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 5 commits into from
Aug 28, 2018
Merged
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
47 changes: 24 additions & 23 deletions examples/utility/Provisioning/Provisioning.ino
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
#include <utility/ECCX08TLSConfig.h>

#include <ArduinoBearSSL.h>
#include <utility/ECCX08.h>
#include <ArduinoECCX08.h>

const int keySlot = 0;
const int compressedCertSlot = 10;
const int serialNumberSlot = 11;
const int thingIdSlot = 12;
const int keySlot = 0;
const int compressedCertSlot = 10;
const int serialNumberAndAuthorityKeyIdentifierSlot = 11;
const int thingIdSlot = 12;

void setup() {
Serial.begin(9600);
Expand Down Expand Up @@ -68,37 +68,38 @@ void setup() {
Serial.println();
Serial.println(csr);

String thingId = promptAndReadLine("Please enter the thing id: ");
String issueYear = promptAndReadLine("Please enter the issue year of the certificate (2000 - 2031): ");
String issueMonth = promptAndReadLine("Please enter the issue month of the certificate (1 - 12): ");
String issueDay = promptAndReadLine("Please enter the issue day of the certificate (1 - 31): ");
String issueHour = promptAndReadLine("Please enter the issue hour of the certificate (0 - 23): ");
String expireYears = promptAndReadLine("Please enter how many years the certificate is valid for (0 - 31): ");
String serialNumber = promptAndReadLine("Please enter the certificates serial number: ");
String signature = promptAndReadLine("Please enter the certificates signature: ");

serialNumber.toUpperCase();
signature.toUpperCase();
String thingId = promptAndReadLine("Please enter the thing id: ");
String issueYear = promptAndReadLine("Please enter the issue year of the certificate (2000 - 2031): ");
String issueMonth = promptAndReadLine("Please enter the issue month of the certificate (1 - 12): ");
String issueDay = promptAndReadLine("Please enter the issue day of the certificate (1 - 31): ");
String issueHour = promptAndReadLine("Please enter the issue hour of the certificate (0 - 23): ");
String expireYears = promptAndReadLine("Please enter how many years the certificate is valid for (0 - 31): ");
String serialNumber = promptAndReadLine("Please enter the certificates serial number: ");
String authorityKeyIdentifier = promptAndReadLine("Please enter the certificates authority key identifier: ");
String signature = promptAndReadLine("Please enter the certificates signature: ");

byte thingIdBytes[72];
byte serialNumberBytes[16];
byte authorityKeyIdentifierBytes[20];
byte signatureBytes[64];

thingId.getBytes(thingIdBytes, sizeof(thingIdBytes));
hexStringToBytes(serialNumber, serialNumberBytes, sizeof(serialNumberBytes));
hexStringToBytes(signature, signatureBytes, 64);

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

if (!ECCX08.writeSlot(thingIdSlot, thingIdBytes, sizeof(thingIdBytes))) {
Serial.println("Error storing thing id!");
while (1);
}

if (!ECCX08Cert.beginStorage(compressedCertSlot, serialNumberSlot)) {
if (!ECCX08Cert.beginStorage(compressedCertSlot, serialNumberAndAuthorityKeyIdentifierSlot)) {
Serial.println("Error starting ECCX08 storage!");
while (1);
}

ECCX08Cert.setSignature(signatureBytes);
ECCX08Cert.setAuthorityKeyIdentifier(authorityKeyIdentifierBytes);
ECCX08Cert.setSerialNumber(serialNumberBytes);
ECCX08Cert.setIssueYear(issueYear.toInt());
ECCX08Cert.setIssueMonth(issueMonth.toInt());
Expand All @@ -111,7 +112,7 @@ void setup() {
while (1);
}

if (!ECCX08Cert.beginReconstruction(keySlot, compressedCertSlot, serialNumberSlot)) {
if (!ECCX08Cert.beginReconstruction(keySlot, compressedCertSlot, serialNumberAndAuthorityKeyIdentifierSlot)) {
Serial.println("Error starting ECCX08 cert reconstruction!");
while (1);
}
Expand Down Expand Up @@ -175,8 +176,9 @@ String readLine() {
return line;
}

void hexStringToBytes(const String& in, byte out[], int length) {
void hexStringToBytes(String& in, byte out[], int length) {
int inLength = in.length();
in.toUpperCase();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authorityKeyIdentifier wasn't being capitalized. To prevent that from happening in the future, I added this line and remove the others about serialNumber and signature.

int outLength = 0;

for (int i = 0; i < inLength && outLength < length; i += 2) {
Expand All @@ -186,7 +188,6 @@ void hexStringToBytes(const String& in, byte out[], int length) {
byte highByte = (highChar <= '9') ? (highChar - '0') : (highChar + 10 - 'A');
byte lowByte = (lowChar <= '9') ? (lowChar - '0') : (lowChar + 10 - 'A');

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this mask will prevent lowByte to overflow

}
}

10 changes: 5 additions & 5 deletions src/ArduinoCloud.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@

const static char server[] = "a19g5nbe27wn47.iot.us-east-1.amazonaws.com"; //"xxxxxxxxxxxxxx.iot.xx-xxxx-x.amazonaws.com";

const static int keySlot = 0;
const static int compressedCertSlot = 10;
const static int serialNumberSlot = 11;
const static int thingIdSlot = 12;
const static int keySlot = 0;
const static int compressedCertSlot = 10;
const static int serialNumberAndAuthorityKeyIdentifierSlot = 11;
const static int thingIdSlot = 12;

ArduinoCloudClass::ArduinoCloudClass() :
_bearSslClient(NULL),
Expand Down Expand Up @@ -38,7 +38,7 @@ int ArduinoCloudClass::begin(Client& net)
}
_id = (char*)thingIdBytes;

if (!ECCX08Cert.beginReconstruction(keySlot, compressedCertSlot, serialNumberSlot)) {
if (!ECCX08Cert.beginReconstruction(keySlot, compressedCertSlot, serialNumberAndAuthorityKeyIdentifierSlot)) {
return 0;
}

Expand Down
115 changes: 95 additions & 20 deletions src/utility/ECCX08Cert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ struct __attribute__((__packed__)) CompressedCert {
byte unused[5];
};

#define SERIAL_NUMBER_LENGTH 16
#define SERIAL_NUMBER_LENGTH 16
#define AUTHORITY_KEY_IDENTIFIER_LENGTH 20

struct __attribute__((__packed__)) SerialNumberAndAuthorityKeyIdentifier {
byte serialNumber[SERIAL_NUMBER_LENGTH];
byte authorityKeyIdentifier[AUTHORITY_KEY_IDENTIFIER_LENGTH];
};

static String base64Encode(const byte in[], unsigned int length, const char* prefix, const char* suffix)
{
Expand Down Expand Up @@ -72,7 +78,7 @@ static String base64Encode(const byte in[], unsigned int length, const char* pre
ECCX08CertClass::ECCX08CertClass() :
_keySlot(-1),
_compressedCertSlot(-1),
_serialNumberSlot(-1),
_serialNumberAndAuthorityKeyIdentifierSlot(-1),
_bytes(NULL),
_length(0)
{
Expand Down Expand Up @@ -184,18 +190,18 @@ String ECCX08CertClass::endCSR()
return base64Encode(csr, csrLen + csrHeaderLen, "-----BEGIN CERTIFICATE REQUEST-----\n", "\n-----END CERTIFICATE REQUEST-----\n");
}

int ECCX08CertClass::beginStorage(int compressedCertSlot, int serialNumberSlot)
int ECCX08CertClass::beginStorage(int compressedCertSlot, int serialNumberAndAuthorityKeyIdentifierSlot)
{
if (compressedCertSlot < 8 || compressedCertSlot > 15) {
return 0;
}

if (serialNumberSlot < 8 || serialNumberSlot > 15) {
if (serialNumberAndAuthorityKeyIdentifierSlot < 8 || serialNumberAndAuthorityKeyIdentifierSlot > 15) {
return 0;
}

_compressedCertSlot = compressedCertSlot;
_serialNumberSlot = serialNumberSlot;
_serialNumberAndAuthorityKeyIdentifierSlot = serialNumberAndAuthorityKeyIdentifierSlot;

memset(_temp, 0x00, sizeof(_temp));

Expand Down Expand Up @@ -255,25 +261,30 @@ void ECCX08CertClass::setExpireYears(int expireYears)
compressedCert->dates[2] |= expireYears;
}

void ECCX08CertClass::setSerialNumber(byte serialNumber[])
void ECCX08CertClass::setSerialNumber(const byte serialNumber[])
{
memcpy(&_temp[72], serialNumber, SERIAL_NUMBER_LENGTH);
}

void ECCX08CertClass::setAuthorityKeyIdentifier(const byte authorityKeyIdentifier[])
{
memcpy(&_temp[88], authorityKeyIdentifier, AUTHORITY_KEY_IDENTIFIER_LENGTH);
}

int ECCX08CertClass::endStorage()
{
if (!ECCX08.writeSlot(_compressedCertSlot, &_temp[0], 72)) {
return 0;
}

if (!ECCX08.writeSlot(_serialNumberSlot, &_temp[72], SERIAL_NUMBER_LENGTH)) {
if (!ECCX08.writeSlot(_serialNumberAndAuthorityKeyIdentifierSlot, &_temp[72], SERIAL_NUMBER_LENGTH + AUTHORITY_KEY_IDENTIFIER_LENGTH)) {
return 0;
}

return 1;
}

int ECCX08CertClass::beginReconstruction(int keySlot, int compressedCertSlot, int serialNumberSlot)
int ECCX08CertClass::beginReconstruction(int keySlot, int compressedCertSlot, int serialNumberAndAuthorityKeyIdentifierSlot)
{
if (keySlot < 0 || keySlot > 8) {
return 0;
Expand All @@ -283,13 +294,13 @@ int ECCX08CertClass::beginReconstruction(int keySlot, int compressedCertSlot, in
return 0;
}

if (serialNumberSlot < 8 || serialNumberSlot > 15) {
if (serialNumberAndAuthorityKeyIdentifierSlot < 8 || serialNumberAndAuthorityKeyIdentifierSlot > 15) {
return 0;
}

_keySlot = keySlot;
_compressedCertSlot = compressedCertSlot;
_serialNumberSlot = serialNumberSlot;
_serialNumberAndAuthorityKeyIdentifierSlot = serialNumberAndAuthorityKeyIdentifierSlot;

return 1;
}
Expand All @@ -298,7 +309,7 @@ int ECCX08CertClass::endReconstruction()
{
byte publicKey[64];
struct CompressedCert compressedCert;
byte serialNumber[SERIAL_NUMBER_LENGTH];
struct SerialNumberAndAuthorityKeyIdentifier serialNumberAndAuthorityKeyIdentifier;

if (!ECCX08.generatePublicKey(_keySlot, publicKey)) {
return 0;
Expand All @@ -308,11 +319,11 @@ int ECCX08CertClass::endReconstruction()
return 0;
}

if (!ECCX08.readSlot(_serialNumberSlot, serialNumber, sizeof(serialNumber))) {
if (!ECCX08.readSlot(_serialNumberAndAuthorityKeyIdentifierSlot, (byte*)&serialNumberAndAuthorityKeyIdentifier, sizeof(serialNumberAndAuthorityKeyIdentifier))) {
return 0;
}

int serialNumberLen = serialNumberLength(serialNumber);
int serialNumberLen = serialNumberLength(serialNumberAndAuthorityKeyIdentifier.serialNumber);

int issuerLen = issuerOrSubjectLength(_issuerCountryName,
_issuerStateProvinceName,
Expand All @@ -334,10 +345,19 @@ int ECCX08CertClass::endReconstruction()

int publicKeyLen = publicKeyLength();

int authorityKeyIdentifierLen = authorityKeyIdentifierLength(serialNumberAndAuthorityKeyIdentifier.authorityKeyIdentifier);

int signatureLen = signatureLength(compressedCert.signature);

int certInfoLen = 5 + serialNumberLen + 12 + issuerHeaderLen + issuerLen + 32 +
subjectHeaderLen + subjectLen + publicKeyLen + 4;
subjectHeaderLen + subjectLen + publicKeyLen;

if (authorityKeyIdentifierLen) {
certInfoLen += authorityKeyIdentifierLen;
} else {
certInfoLen += 4;
}

int certInfoHeaderLen = sequenceHeaderLength(certInfoLen);

int certDataLen = certInfoLen + certInfoHeaderLen + signatureLen;
Expand Down Expand Up @@ -367,7 +387,7 @@ int ECCX08CertClass::endReconstruction()
*out++ = 0x02;

// serial number
appendSerialNumber(serialNumber, out);
appendSerialNumber(serialNumberAndAuthorityKeyIdentifier.serialNumber, out);
out += serialNumberLen;

// ecdsaWithSHA256
Expand Down Expand Up @@ -411,11 +431,16 @@ int ECCX08CertClass::endReconstruction()
appendPublicKey(publicKey, out);
out += publicKeyLen;

// null sequence
*out++ = 0xA3;
*out++ = 0x02;
*out++ = 0x30;
*out++ = 0x00;
if (authorityKeyIdentifierLen) {
appendAuthorityKeyIdentifier(serialNumberAndAuthorityKeyIdentifier.authorityKeyIdentifier, out);
out += authorityKeyIdentifierLen;
} else {
// null sequence
*out++ = 0xA3;
*out++ = 0x02;
*out++ = 0x30;
*out++ = 0x00;
}

// signature
appendSignature(compressedCert.signature, out);
Expand Down Expand Up @@ -546,6 +571,21 @@ int ECCX08CertClass::publicKeyLength()
return (2 + 2 + 9 + 10 + 4 + 64);
}

int ECCX08CertClass::authorityKeyIdentifierLength(const byte authorityKeyIdentifier[])
{
bool set = false;

// check if the authority key identifier is non-zero
for (int i = 0; i < AUTHORITY_KEY_IDENTIFIER_LENGTH; i++) {
if (authorityKeyIdentifier[i] != 0) {
set = true;
break;
}
}

return (set ? 37 : 0);
}

int ECCX08CertClass::signatureLength(const byte signature[])
{
const byte* r = &signature[0];
Expand Down Expand Up @@ -684,6 +724,41 @@ void ECCX08CertClass::appendPublicKey(const byte publicKey[], byte out[])
memcpy(out, publicKey, 64);
}

void ECCX08CertClass::appendAuthorityKeyIdentifier(const byte authorityKeyIdentifier[], 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, authorityKeyIdentifier, 20);
}

void ECCX08CertClass::appendSignature(const byte signature[], byte out[])
{
// signature algorithm
Expand Down
Loading