Skip to content

Commit

Permalink
Add Identifier calculation for PDC certs
Browse files Browse the repository at this point in the history
  • Loading branch information
ksperling-apple committed Nov 1, 2023
1 parent 2b59ad9 commit 1ac1a64
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 13 deletions.
53 changes: 44 additions & 9 deletions src/credentials/CHIPCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1095,12 +1095,19 @@ DLL_EXPORT CHIP_ERROR ChipEpochToASN1Time(uint32_t epochTime, chip::ASN1::ASN1Un
return CHIP_NO_ERROR;
}

static CHIP_ERROR ValidateCertificateType(ChipCertificateData const & certData, CertType expectedType)
{
CertType certType;
ReturnErrorOnFailure(certData.mSubjectDN.GetCertType(certType));
VerifyOrReturnError(certType == expectedType, CHIP_ERROR_WRONG_CERT_TYPE);
return CHIP_NO_ERROR;
}

CHIP_ERROR ValidateChipRCAC(const ByteSpan & rcac)
{
ChipCertificateSet certSet;
ChipCertificateData certData;
ValidationContext validContext;
CertType certType;

// Note that this function doesn't check RCAC NotBefore / NotAfter time validity.
// It is assumed that RCAC should be valid at the time of installation by definition.
Expand All @@ -1109,8 +1116,7 @@ CHIP_ERROR ValidateChipRCAC(const ByteSpan & rcac)

ReturnErrorOnFailure(certSet.LoadCert(rcac, CertDecodeFlags::kGenerateTBSHash));

ReturnErrorOnFailure(certData.mSubjectDN.GetCertType(certType));
VerifyOrReturnError(certType == CertType::kRoot, CHIP_ERROR_WRONG_CERT_TYPE);
ReturnErrorOnFailure(ValidateCertificateType(certData, CertType::kRoot));

VerifyOrReturnError(certData.mSubjectDN.IsEqual(certData.mIssuerDN), CHIP_ERROR_WRONG_CERT_TYPE);

Expand Down Expand Up @@ -1434,14 +1440,17 @@ CHIP_ERROR InitNISubject(ChipDN & name)
return CHIP_NO_ERROR;
}

CHIP_ERROR ValidateChipNetworkIdentity(const ByteSpan & cert)
static void CalculateKeyIdentifierSha256(const P256PublicKeySpan & publicKey, MutableCertificateKeyId keyId)
{
ChipCertificateData certData;
ReturnErrorOnFailure(DecodeChipCert(cert, certData, CertDecodeFlags::kGenerateTBSHash));
uint8_t hash[kSHA256_Hash_Length];
static_assert(keyId.size() <= sizeof(hash)); // truncating 32 bytes down to 20
chip::Crypto::Hash_SHA256(publicKey.data(), publicKey.size(), hash);
memcpy(keyId.data(), hash, keyId.size());
}

CertType certType;
ReturnErrorOnFailure(certData.mSubjectDN.GetCertType(certType));
VerifyOrReturnError(certType == CertType::kNetworkIdentity, CHIP_ERROR_WRONG_CERT_TYPE);
static CHIP_ERROR ValidateChipNetworkIdentity(const ChipCertificateData & certData)
{
ReturnErrorOnFailure(ValidateCertificateType(certData, CertType::kNetworkIdentity));

VerifyOrReturnError(certData.mSerialNumber.data_equal(kNetworkIdentitySerialNumber), CHIP_ERROR_WRONG_CERT_TYPE);
VerifyOrReturnError(certData.mNotBeforeTime == kNetworkIdentityNotBeforeTime, CHIP_ERROR_WRONG_CERT_TYPE);
Expand All @@ -1462,5 +1471,31 @@ CHIP_ERROR ValidateChipNetworkIdentity(const ByteSpan & cert)
return CHIP_NO_ERROR;
}

CHIP_ERROR ValidateChipNetworkIdentity(const ByteSpan & cert)
{
ChipCertificateData certData;
ReturnErrorOnFailure(DecodeChipCert(cert, certData, CertDecodeFlags::kGenerateTBSHash));
ReturnErrorOnFailure(ValidateChipNetworkIdentity(certData));
return CHIP_NO_ERROR;
}

CHIP_ERROR ValidateChipNetworkIdentity(const ByteSpan & cert, MutableCertificateKeyId keyId)
{
ChipCertificateData certData;
ReturnErrorOnFailure(DecodeChipCert(cert, certData, CertDecodeFlags::kGenerateTBSHash));
ReturnErrorOnFailure(ValidateChipNetworkIdentity(certData));
CalculateKeyIdentifierSha256(certData.mPublicKey, keyId);
return CHIP_NO_ERROR;
}

CHIP_ERROR ExtractIdentifierFromChipNetworkIdentity(const ByteSpan & cert, MutableCertificateKeyId keyId)
{
ChipCertificateData certData;
ReturnErrorOnFailure(DecodeChipCert(cert, certData));
ReturnErrorOnFailure(ValidateCertificateType(certData, CertType::kNetworkIdentity));
CalculateKeyIdentifierSha256(certData.mPublicKey, keyId);
return CHIP_NO_ERROR;
}

} // namespace Credentials
} // namespace chip
26 changes: 25 additions & 1 deletion src/credentials/CHIPCert.h
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,16 @@ class ChipDN
*/
using CertificateKeyId = FixedByteSpan<kKeyIdentifierLength>;

/**
* @brief A mutable `CertificateKeyId`.
*/
using MutableCertificateKeyId = FixedSpan<uint8_t, kKeyIdentifierLength>;

/**
* @brief A storage type for `CertificateKeyId` and `MutableCertificateKeyId`.
*/
using CertificateKeyIdStorage = std::array<uint8_t, kKeyIdentifierLength>;

/**
* @brief A data structure for holding a P256 ECDSA signature, without the ownership of it.
*/
Expand Down Expand Up @@ -535,7 +545,11 @@ CHIP_ERROR ValidateChipRCAC(const ByteSpan & rcac);
* Accepts either a full certificate or the compact-pdc-identity format.
*
* This function parses the certificate, ensures the rigid fields have the values mandated by the
* specification, and validates the certificate signature.
* specification, and validates the certificate signature. Optionally, and only upon successful
* validation, the key identifier of the certificate will be calculated and returned in `keyId`.
*
* @param cert The network identity certificate to validate.
* @param[out] keyId The calculated key identifier of the network identity.
*
* @return CHIP_NO_ERROR on success, CHIP_ERROR_WRONG_CERT_TYPE if the certificate does
* not conform to the requirements for a Network Identity, CHIP_ERROR_INVALID_SIGNATURE
Expand All @@ -544,6 +558,7 @@ CHIP_ERROR ValidateChipRCAC(const ByteSpan & rcac);
* @see section 11.24 (Wi-Fi Authentication with Per-Device Credentials) of the Matter spec
*/
CHIP_ERROR ValidateChipNetworkIdentity(const ByteSpan & cert);
CHIP_ERROR ValidateChipNetworkIdentity(const ByteSpan & cert, MutableCertificateKeyId keyId);

struct FutureExtension
{
Expand Down Expand Up @@ -828,5 +843,14 @@ CHIP_ERROR ExtractSubjectDNFromChipCert(const ByteSpan & chipCert, ChipDN & dn);
*/
CHIP_ERROR ExtractSubjectDNFromX509Cert(const ByteSpan & x509Cert, ChipDN & dn);

/**
* Extracts the key identifier from a Network (Client) Identity in TLV-encoded form.
* Does NOT perform full validation of the identity certificate.
*
* @return CHIP_NO_ERROR on success, CHIP_ERROR_WRONG_CERT_TYPE if the certificate is
* not a Network (Client) Identity, or another CHIP_ERROR if parsing fails.
*/
CHIP_ERROR ExtractIdentifierFromChipNetworkIdentity(const ByteSpan & cert, MutableCertificateKeyId keyId);

} // namespace Credentials
} // namespace chip
4 changes: 4 additions & 0 deletions src/credentials/tests/CHIPCert_test_vectors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2573,5 +2573,9 @@ extern constexpr ByteSpan sTestCert_PDCID01_SubjectKeyId{};

extern constexpr ByteSpan sTestCert_PDCID01_AuthorityKeyId{};

extern constexpr ByteSpan sTestCert_PDCID01_KeyId((const uint8_t[]){
0x3A, 0x0E, 0x71, 0xE2, 0x09, 0x9A, 0x49, 0xDA, 0xC9, 0x74, 0xFE, 0xD0, 0x5E, 0xA5, 0x3E, 0xBA, 0xCE, 0x29, 0x33, 0x90,
});

} // namespace TestCerts
} // namespace chip
5 changes: 3 additions & 2 deletions src/credentials/tests/CHIPCert_test_vectors.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,9 @@ extern const ByteSpan sTestCert_PDCID01_ChipCompact;
extern const ByteSpan sTestCert_PDCID01_DER;
extern const ByteSpan sTestCert_PDCID01_PublicKey;
extern const ByteSpan sTestCert_PDCID01_PrivateKey;
extern const ByteSpan sTestCert_PDCID01_SubjectKeyId;
extern const ByteSpan sTestCert_PDCID01_AuthorityKeyId;
extern const ByteSpan sTestCert_PDCID01_SubjectKeyId; // empty
extern const ByteSpan sTestCert_PDCID01_AuthorityKeyId; // empty
extern const ByteSpan sTestCert_PDCID01_KeyId;

} // namespace TestCerts
} // namespace chip
25 changes: 24 additions & 1 deletion src/credentials/tests/TestChipCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2150,12 +2150,35 @@ static void TestChipCert_ExtractPublicKeyAndSKID(nlTestSuite * inSuite, void * i
static void TestChipCert_PDCIdentityValidation(nlTestSuite * inSuite, void * inContext)
{
CHIP_ERROR err;
CertificateKeyIdStorage keyId;

// Validate only
err = ValidateChipNetworkIdentity(sTestCert_PDCID01_Chip);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);

err = ValidateChipNetworkIdentity(sTestCert_PDCID01_ChipCompact);
// Validate and calculate identifier
keyId.fill(0xaa);
err = ValidateChipNetworkIdentity(sTestCert_PDCID01_Chip, keyId);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, CertificateKeyId(keyId).data_equal(sTestCert_PDCID01_KeyId));

// Validate and calculate identifier from compact representation
keyId.fill(0xaa);
err = ValidateChipNetworkIdentity(sTestCert_PDCID01_ChipCompact, keyId);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, CertificateKeyId(keyId).data_equal(sTestCert_PDCID01_KeyId));

// Extract identifier only
keyId.fill(0xaa);
err = ExtractIdentifierFromChipNetworkIdentity(sTestCert_PDCID01_Chip, keyId);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, CertificateKeyId(keyId).data_equal(sTestCert_PDCID01_KeyId));

// Extract identifier only from compact representation
keyId.fill(0xaa);
err = ExtractIdentifierFromChipNetworkIdentity(sTestCert_PDCID01_ChipCompact, keyId);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, CertificateKeyId(keyId).data_equal(sTestCert_PDCID01_KeyId));
}

/**
Expand Down

0 comments on commit 1ac1a64

Please sign in to comment.