|
|
|
@ -51,6 +51,18 @@ static const optiga_metadata_item KEY_USE_SIGN = {
|
|
|
|
|
static const optiga_metadata_item TYPE_PTFBIND = {
|
|
|
|
|
(const uint8_t[]){OPTIGA_DATA_TYPE_PTFBIND}, 1};
|
|
|
|
|
|
|
|
|
|
// Identifier of context-specific constructed tag 3, which is used for
|
|
|
|
|
// extensions in X.509.
|
|
|
|
|
#define DER_X509_EXTENSIONS 0xa3
|
|
|
|
|
|
|
|
|
|
// Identifier of context-specific primitive tag 0, which is used for
|
|
|
|
|
// keyIdentifier in authorityKeyIdentifier.
|
|
|
|
|
#define DER_X509_KEY_IDENTIFIER 0x80
|
|
|
|
|
|
|
|
|
|
// DER-encoded object identifier of the authority key identifier extension
|
|
|
|
|
// (id-ce-authorityKeyIdentifier).
|
|
|
|
|
const uint8_t OID_AUTHORITY_KEY_IDENTIFIER[] = {0x06, 0x03, 0x55, 0x1d, 0x23};
|
|
|
|
|
|
|
|
|
|
static bool optiga_paired(void) {
|
|
|
|
|
const char *details = "";
|
|
|
|
|
|
|
|
|
@ -540,26 +552,108 @@ static const uint8_t ECDSA_WITH_SHA256[] = {
|
|
|
|
|
};
|
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
|
|
static const uint8_t ROOT_PUBLIC_KEYS[][65] = {
|
|
|
|
|
{
|
|
|
|
|
// Production root public key.
|
|
|
|
|
0x04, 0xca, 0x97, 0x48, 0x0a, 0xc0, 0xd7, 0xb1, 0xe6, 0xef, 0xaf,
|
|
|
|
|
0xe5, 0x18, 0xcd, 0x43, 0x3c, 0xec, 0x2b, 0xf8, 0xab, 0x98, 0x22,
|
|
|
|
|
0xd7, 0x6e, 0xaf, 0xd3, 0x43, 0x63, 0xb5, 0x5d, 0x63, 0xe6, 0x03,
|
|
|
|
|
0x80, 0xbf, 0xf2, 0x0a, 0xcc, 0x75, 0xcd, 0xe0, 0x3c, 0xff, 0xcb,
|
|
|
|
|
0x50, 0xab, 0x6f, 0x8c, 0xe7, 0x0c, 0x87, 0x8e, 0x37, 0xeb, 0xc5,
|
|
|
|
|
0x8f, 0xf7, 0xcc, 0xa0, 0xa8, 0x3b, 0x16, 0xb1, 0x5f, 0xa5,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
// Development root public key.
|
|
|
|
|
0x04, 0x7f, 0x77, 0x36, 0x8d, 0xea, 0x2d, 0x4d, 0x61, 0xe9, 0x89,
|
|
|
|
|
0xf4, 0x74, 0xa5, 0x67, 0x23, 0xc3, 0x21, 0x2d, 0xac, 0xf8, 0xa8,
|
|
|
|
|
0x08, 0xd8, 0x79, 0x55, 0x95, 0xef, 0x38, 0x44, 0x14, 0x27, 0xc4,
|
|
|
|
|
0x38, 0x9b, 0xc4, 0x54, 0xf0, 0x20, 0x89, 0xd7, 0xf0, 0x8b, 0x87,
|
|
|
|
|
0x30, 0x05, 0xe4, 0xc2, 0x8d, 0x43, 0x24, 0x68, 0x99, 0x78, 0x71,
|
|
|
|
|
0xc0, 0xbf, 0x28, 0x6f, 0xd3, 0x86, 0x1e, 0x21, 0xe9, 0x6a,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
static bool get_authority_key_digest(DER_ITEM *tbs_cert,
|
|
|
|
|
const uint8_t **authority_key_digest) {
|
|
|
|
|
// Find the certificate extensions in the tbsCertificate.
|
|
|
|
|
DER_ITEM cert_item = {0};
|
|
|
|
|
bool found = false;
|
|
|
|
|
while (der_read_item(&tbs_cert->buf, &cert_item)) {
|
|
|
|
|
if (cert_item.id == DER_X509_EXTENSIONS) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
|
vcp_println("ERROR get_authority_key_digest, extensions not found.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Open the extensions sequence.
|
|
|
|
|
DER_ITEM extensions = {0};
|
|
|
|
|
if (!der_read_item(&cert_item.buf, &extensions) ||
|
|
|
|
|
extensions.id != DER_SEQUENCE) {
|
|
|
|
|
vcp_println("ERROR get_authority_key_digest, der_read_item extensions.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find the authority key identifier extension.
|
|
|
|
|
DER_ITEM extension = {0};
|
|
|
|
|
found = false;
|
|
|
|
|
while (der_read_item(&extensions.buf, &extension)) {
|
|
|
|
|
DER_ITEM extension_id = {0};
|
|
|
|
|
if (der_read_item(&extension.buf, &extension_id) &&
|
|
|
|
|
extension_id.buf.size == sizeof(OID_AUTHORITY_KEY_IDENTIFIER) &&
|
|
|
|
|
memcmp(extension_id.buf.data, OID_AUTHORITY_KEY_IDENTIFIER,
|
|
|
|
|
sizeof(OID_AUTHORITY_KEY_IDENTIFIER)) == 0) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
|
vcp_println(
|
|
|
|
|
"ERROR get_authority_key_digest, authority key identifier extension "
|
|
|
|
|
"not found.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find the authority key identifier extension's extnValue.
|
|
|
|
|
// Conforming CAs must mark this extension as non-critical, so there shouldn't
|
|
|
|
|
// be anything between the extension ID and value, but we search for the octet
|
|
|
|
|
// string to be on the safe side.
|
|
|
|
|
DER_ITEM extension_value = {0};
|
|
|
|
|
found = false;
|
|
|
|
|
while (der_read_item(&extension.buf, &extension_value)) {
|
|
|
|
|
if (extension_value.id == DER_OCTET_STRING) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
|
vcp_println(
|
|
|
|
|
"ERROR get_authority_key_digest, authority key identifier extnValue "
|
|
|
|
|
"not found.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Open the AuthorityKeyIdentifier sequence.
|
|
|
|
|
DER_ITEM auth_key_id = {0};
|
|
|
|
|
if (!der_read_item(&extension_value.buf, &auth_key_id) ||
|
|
|
|
|
auth_key_id.id != DER_SEQUENCE) {
|
|
|
|
|
vcp_println(
|
|
|
|
|
"ERROR get_authority_key_digest, failed to open authority key "
|
|
|
|
|
"identifier extnValue.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find the keyIdentifier field.
|
|
|
|
|
DER_ITEM key_id = {0};
|
|
|
|
|
found = false;
|
|
|
|
|
while (der_read_item(&auth_key_id.buf, &key_id)) {
|
|
|
|
|
if (key_id.id == DER_X509_KEY_IDENTIFIER) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
|
vcp_println(
|
|
|
|
|
"ERROR get_authority_key_digest, failed to find keyIdentifier field.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Return the pointer to the keyIdentifier data.
|
|
|
|
|
if (buffer_remaining(&key_id.buf) != SHA1_DIGEST_LENGTH ||
|
|
|
|
|
!buffer_ptr(&key_id.buf, authority_key_digest)) {
|
|
|
|
|
vcp_println(
|
|
|
|
|
"ERROR get_authority_key_digest, invalid length of keyIdentifier.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool check_device_cert_chain(const uint8_t *chain, size_t chain_size) {
|
|
|
|
|
// Checks the integrity of the device certificate chain to ensure that the
|
|
|
|
@ -593,6 +687,10 @@ bool check_device_cert_chain(const uint8_t *chain, size_t chain_size) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This will be populated with a pointer to the key identifier data of the
|
|
|
|
|
// AuthorityKeyIdentifier extension from the last certificate in the chain.
|
|
|
|
|
const uint8_t *authority_key_digest = NULL;
|
|
|
|
|
|
|
|
|
|
BUFFER_READER chain_reader = {0};
|
|
|
|
|
buffer_reader_init(&chain_reader, chain, chain_size);
|
|
|
|
|
int cert_count = 0;
|
|
|
|
@ -652,6 +750,13 @@ bool check_device_cert_chain(const uint8_t *chain, size_t chain_size) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the authority key identifier from the last certificate.
|
|
|
|
|
if (buffer_remaining(&chain_reader) == 0 &&
|
|
|
|
|
!get_authority_key_digest(&tbs_cert, &authority_key_digest)) {
|
|
|
|
|
// Error returned by get_authority_key_digest().
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Prepare the hash of tbsCertificate for the next signature verification.
|
|
|
|
|
sha256_Raw(tbs_cert.buf.data, tbs_cert.buf.size, digest);
|
|
|
|
|
|
|
|
|
@ -689,13 +794,18 @@ bool check_device_cert_chain(const uint8_t *chain, size_t chain_size) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify that the last certificate in the chain is valid for one of the known
|
|
|
|
|
// root public keys.
|
|
|
|
|
for (int i = 0; i < sizeof(ROOT_PUBLIC_KEYS) / sizeof(ROOT_PUBLIC_KEYS[0]);
|
|
|
|
|
++i) {
|
|
|
|
|
if (ecdsa_verify_digest(&nist256p1, ROOT_PUBLIC_KEYS[i], sig, digest) ==
|
|
|
|
|
// Verify that the signature of the last certificate in the chain matches its
|
|
|
|
|
// own AuthorityKeyIdentifier to verify the integrity of the certificate data.
|
|
|
|
|
uint8_t pub_key[65] = {0};
|
|
|
|
|
uint8_t pub_key_digest[SHA1_DIGEST_LENGTH] = {0};
|
|
|
|
|
for (int recid = 0; recid < 4; ++recid) {
|
|
|
|
|
if (ecdsa_recover_pub_from_sig(&nist256p1, pub_key, sig, digest, recid) ==
|
|
|
|
|
0) {
|
|
|
|
|
return true;
|
|
|
|
|
sha1_Raw(pub_key, sizeof(pub_key), pub_key_digest);
|
|
|
|
|
if (memcmp(authority_key_digest, pub_key_digest,
|
|
|
|
|
sizeof(pub_key_digest)) == 0) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|