diff --git a/examples/utility/Provisioning/Provisioning.ino b/examples/utility/Provisioning/Provisioning.ino index 29cb46793..1d5dce576 100644 --- a/examples/utility/Provisioning/Provisioning.ino +++ b/examples/utility/Provisioning/Provisioning.ino @@ -3,12 +3,12 @@ #include #include -#include +#include -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); @@ -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()); @@ -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); } @@ -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(); int outLength = 0; for (int i = 0; i < inLength && outLength < length; i += 2) { @@ -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); } } - diff --git a/src/ArduinoCloud.cpp b/src/ArduinoCloud.cpp index 05159a144..dddf3683d 100644 --- a/src/ArduinoCloud.cpp +++ b/src/ArduinoCloud.cpp @@ -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), @@ -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; } diff --git a/src/utility/ECCX08Cert.cpp b/src/utility/ECCX08Cert.cpp index 1311c3092..7d38969bc 100644 --- a/src/utility/ECCX08Cert.cpp +++ b/src/utility/ECCX08Cert.cpp @@ -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) { @@ -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) { @@ -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)); @@ -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; @@ -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; } @@ -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; @@ -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, @@ -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; @@ -367,7 +387,7 @@ int ECCX08CertClass::endReconstruction() *out++ = 0x02; // serial number - appendSerialNumber(serialNumber, out); + appendSerialNumber(serialNumberAndAuthorityKeyIdentifier.serialNumber, out); out += serialNumberLen; // ecdsaWithSHA256 @@ -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); @@ -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]; @@ -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 diff --git a/src/utility/ECCX08Cert.h b/src/utility/ECCX08Cert.h index 882ba76d1..2b35f7777 100644 --- a/src/utility/ECCX08Cert.h +++ b/src/utility/ECCX08Cert.h @@ -12,17 +12,18 @@ class ECCX08CertClass { int beginCSR(int keySlot, bool newPrivateKey = true); String endCSR(); - int beginStorage(int compressedCertSlot, int serialNumberSlot); + int beginStorage(int compressedCertSlot, int serialNumberAndAuthorityKeyIdentifierSlot); void setSignature(byte signature[]); void setIssueYear(int issueYear); void setIssueMonth(int issueMonth); void setIssueDay(int issueDay); void setIssueHour(int issueHour); void setExpireYears(int expireYears); - void setSerialNumber(byte serialNumber[]); + void setSerialNumber(const byte serialNumber[]); + void setAuthorityKeyIdentifier(const byte authorityKeyIdentifier[]); int endStorage(); - int beginReconstruction(int keySlot, int compressedCertSlot, int serialNumberSlot); + int beginReconstruction(int keySlot, int compressedCertSlot, int serialNumberAndAuthorityKeyIdentifierSlot); int endReconstruction(); byte* bytes(); @@ -54,6 +55,8 @@ class ECCX08CertClass { int publicKeyLength(); + int authorityKeyIdentifierLength(const byte authorityKeyIdentifier[]); + int signatureLength(const byte signature[]); int serialNumberLength(const byte serialNumber[]); @@ -72,6 +75,8 @@ class ECCX08CertClass { void appendPublicKey(const byte publicKey[], byte out[]); + void appendAuthorityKeyIdentifier(const byte authorityKeyIdentifier[], byte out[]); + void appendSignature(const byte signature[], byte out[]); void appendSerialNumber(const byte serialNumber[], byte out[]); @@ -87,7 +92,7 @@ class ECCX08CertClass { private: int _keySlot; int _compressedCertSlot; - int _serialNumberSlot; + int _serialNumberAndAuthorityKeyIdentifierSlot; String _issuerCountryName; String _issuerStateProvinceName; @@ -103,7 +108,7 @@ class ECCX08CertClass { String _subjectOrganizationalUnitName; String _subjectCommonName; - byte _temp[88]; + byte _temp[108]; byte* _bytes; int _length; };