From 1472952e400b6fe8d7fbd5fef3b2ec7377435046 Mon Sep 17 00:00:00 2001 From: Karsten Sperling <113487422+ksperling-apple@users.noreply.github.com> Date: Wed, 1 Nov 2023 17:42:00 +1300 Subject: [PATCH] Add basic support for recognizing and validating Network Identity certs (#30114) * Make BitFlags more constexpr friendly * Add basic support for recognizing and validating Network Identity certs This involves changing some Extract*FromCert methods from using ChipCertificateSet to load the certificate to just using DecodeChipCert, since ChipCertificateSet makes additional assumptions. Also remove unused ChipCertificateData.mCertificate member * Address review comments --- src/credentials/CHIPCert.cpp | 89 +++++----- src/credentials/CHIPCert.h | 17 +- src/credentials/CHIPCertToX509.cpp | 7 +- src/credentials/CHIPCert_Internal.h | 39 ++++ .../tests/CHIPCert_test_vectors.cpp | 113 ++++++++++++ src/credentials/tests/CHIPCert_test_vectors.h | 10 ++ src/credentials/tests/TestChipCert.cpp | 167 ++++++++++-------- src/crypto/tests/CHIPCryptoPALTest.cpp | 22 ++- src/lib/support/BitFlags.h | 12 +- 9 files changed, 351 insertions(+), 125 deletions(-) create mode 100644 src/credentials/CHIPCert_Internal.h diff --git a/src/credentials/CHIPCert.cpp b/src/credentials/CHIPCert.cpp index 425d30a2d9a396..93f924f42051a7 100644 --- a/src/credentials/CHIPCert.cpp +++ b/src/credentials/CHIPCert.cpp @@ -31,7 +31,7 @@ #include -#include +#include #include #include #include @@ -468,6 +468,7 @@ ChipCertificateData::~ChipCertificateData() {} void ChipCertificateData::Clear() { + mSerialNumber = ByteSpan(); mSubjectDN.Clear(); mIssuerDN.Clear(); mSubjectKeyId = CertificateKeyId(); @@ -612,6 +613,13 @@ CHIP_ERROR ChipDN::GetCertType(CertType & certType) const bool catsPresent = false; uint8_t rdnCount = RDNCount(); + if (rdnCount == 1 && rdn[0].mAttrOID == kOID_AttributeType_CommonName && !rdn[0].mAttrIsPrintableString && + rdn[0].mString.data_equal(kNetworkIdentityCN)) + { + certType = CertType::kNetworkIdentity; + return CHIP_NO_ERROR; + } + certType = CertType::kNotSpecified; for (uint8_t i = 0; i < rdnCount; i++) @@ -672,6 +680,7 @@ CHIP_ERROR ChipDN::GetCertType(CertType & certType) const CHIP_ERROR ChipDN::GetCertChipId(uint64_t & chipId) const { uint8_t rdnCount = RDNCount(); + bool foundId = false; chipId = 0; @@ -683,15 +692,17 @@ CHIP_ERROR ChipDN::GetCertChipId(uint64_t & chipId) const case kOID_AttributeType_MatterICACId: case kOID_AttributeType_MatterNodeId: case kOID_AttributeType_MatterFirmwareSigningId: - VerifyOrReturnError(chipId == 0, CHIP_ERROR_WRONG_CERT_DN); + VerifyOrReturnError(!foundId, CHIP_ERROR_WRONG_CERT_DN); - chipId = rdn[i].mChipVal; + chipId = rdn[i].mChipVal; + foundId = true; break; default: break; } } + VerifyOrReturnError(foundId, CHIP_ERROR_WRONG_CERT_DN); return CHIP_NO_ERROR; } @@ -1304,78 +1315,48 @@ CHIP_ERROR ExtractCATsFromOpCert(const ChipCertificateData & opcert, CATValues & CHIP_ERROR ExtractFabricIdFromCert(const ByteSpan & opcert, FabricId * fabricId) { - ChipCertificateSet certSet; ChipCertificateData certData; - ReturnErrorOnFailure(certSet.Init(&certData, 1)); - ReturnErrorOnFailure(certSet.LoadCert(opcert, BitFlags())); + ReturnErrorOnFailure(DecodeChipCert(opcert, certData)); return ExtractFabricIdFromCert(certData, fabricId); } CHIP_ERROR ExtractNodeIdFabricIdFromOpCert(const ByteSpan & opcert, NodeId * nodeId, FabricId * fabricId) { - ChipCertificateSet certSet; ChipCertificateData certData; - - ReturnErrorOnFailure(certSet.Init(&certData, 1)); - - ReturnErrorOnFailure(certSet.LoadCert(opcert, BitFlags())); - + ReturnErrorOnFailure(DecodeChipCert(opcert, certData)); return ExtractNodeIdFabricIdFromOpCert(certData, nodeId, fabricId); } CHIP_ERROR ExtractPublicKeyFromChipCert(const ByteSpan & chipCert, P256PublicKeySpan & publicKey) { - ChipCertificateSet certSet; ChipCertificateData certData; - - ReturnErrorOnFailure(certSet.Init(&certData, 1)); - - ReturnErrorOnFailure(certSet.LoadCert(chipCert, BitFlags())); - + ReturnErrorOnFailure(DecodeChipCert(chipCert, certData)); publicKey = certData.mPublicKey; - return CHIP_NO_ERROR; } CHIP_ERROR ExtractNotBeforeFromChipCert(const ByteSpan & chipCert, chip::System::Clock::Seconds32 & notBeforeChipEpochTime) { - ChipCertificateSet certSet; ChipCertificateData certData; - - ReturnErrorOnFailure(certSet.Init(&certData, 1)); - - ReturnErrorOnFailure(certSet.LoadCert(chipCert, BitFlags())); - + ReturnErrorOnFailure(DecodeChipCert(chipCert, certData)); notBeforeChipEpochTime = chip::System::Clock::Seconds32(certData.mNotBeforeTime); - return CHIP_NO_ERROR; } CHIP_ERROR ExtractSKIDFromChipCert(const ByteSpan & chipCert, CertificateKeyId & skid) { - ChipCertificateSet certSet; ChipCertificateData certData; - - ReturnErrorOnFailure(certSet.Init(&certData, 1)); - - ReturnErrorOnFailure(certSet.LoadCert(chipCert, BitFlags())); - + ReturnErrorOnFailure(DecodeChipCert(chipCert, certData)); + VerifyOrReturnError(certData.mCertFlags.Has(CertFlags::kExtPresent_AuthKeyId), CHIP_ERROR_NOT_FOUND); skid = certData.mSubjectKeyId; - return CHIP_NO_ERROR; } CHIP_ERROR ExtractSubjectDNFromChipCert(const ByteSpan & chipCert, ChipDN & dn) { - ChipCertificateSet certSet; ChipCertificateData certData; - - ReturnErrorOnFailure(certSet.Init(&certData, 1)); - - ReturnErrorOnFailure(certSet.LoadCert(chipCert, BitFlags())); - + ReturnErrorOnFailure(DecodeChipCert(chipCert, certData)); dn = certData.mSubjectDN; - return CHIP_NO_ERROR; } @@ -1446,5 +1427,33 @@ CHIP_ERROR CertificateValidityPolicy::ApplyDefaultPolicy(const ChipCertificateDa } } +CHIP_ERROR ValidateChipNetworkIdentity(const ByteSpan & cert) +{ + ChipCertificateData certData; + ReturnErrorOnFailure(DecodeChipCert(cert, certData, CertDecodeFlags::kGenerateTBSHash)); + + CertType certType; + ReturnErrorOnFailure(certData.mSubjectDN.GetCertType(certType)); + VerifyOrReturnError(certType == CertType::kNetworkIdentity, CHIP_ERROR_WRONG_CERT_TYPE); + + VerifyOrReturnError(certData.mSerialNumber.data_equal(kNetworkIdentitySerialNumber), CHIP_ERROR_WRONG_CERT_TYPE); + VerifyOrReturnError(certData.mNotBeforeTime == kNetworkIdentityNotBeforeTime, CHIP_ERROR_WRONG_CERT_TYPE); + VerifyOrReturnError(certData.mNotAfterTime == kNetworkIdentityNotAfterTime, CHIP_ERROR_WRONG_CERT_TYPE); + VerifyOrReturnError(certData.mIssuerDN.IsEqual(certData.mSubjectDN), CHIP_ERROR_WRONG_CERT_TYPE); + + VerifyOrReturnError(certData.mCertFlags.Has(CertFlags::kExtPresent_BasicConstraints) && + !certData.mCertFlags.Has(CertFlags::kIsCA), + CHIP_ERROR_WRONG_CERT_TYPE); + VerifyOrReturnError(certData.mCertFlags.Has(CertFlags::kExtPresent_KeyUsage) && + certData.mKeyUsageFlags == kNetworkIdentityKeyUsage, + CHIP_ERROR_WRONG_CERT_TYPE); + VerifyOrReturnError(certData.mCertFlags.Has(CertFlags::kExtPresent_ExtendedKeyUsage) && + certData.mKeyPurposeFlags == kNetworkIdentityKeyPurpose, + CHIP_ERROR_WRONG_CERT_TYPE); + + ReturnErrorOnFailure(VerifyCertSignature(certData, certData)); + return CHIP_NO_ERROR; +} + } // namespace Credentials } // namespace chip diff --git a/src/credentials/CHIPCert.h b/src/credentials/CHIPCert.h index 69041f018d773d..0f8ba1df4b2955 100644 --- a/src/credentials/CHIPCert.h +++ b/src/credentials/CHIPCert.h @@ -112,6 +112,7 @@ enum class CertType : uint8_t firmware image signing is manufacturer-specific. The CHIP certificate format supports encoding of firmware signing certificates if chosen by the manufacturer to use them. */ + kNetworkIdentity = 0x05, /**< A CHIP Network (Client) Identity. */ }; /** X.509 Certificate Key Purpose Flags @@ -428,7 +429,7 @@ struct ChipCertificateData void Clear(); bool IsEqual(const ChipCertificateData & other) const; - ByteSpan mCertificate; /**< Original raw buffer data. */ + ByteSpan mSerialNumber; /**< Certificate Serial Number. */ ChipDN mSubjectDN; /**< Certificate Subject DN. */ ChipDN mIssuerDN; /**< Certificate Issuer DN. */ CertificateKeyId mSubjectKeyId; /**< Certificate Subject public key identifier. */ @@ -529,6 +530,20 @@ CHIP_ERROR VerifyCertSignature(const ChipCertificateData & cert, const ChipCerti */ CHIP_ERROR ValidateChipRCAC(const ByteSpan & rcac); +/** + * Validates a Network (Client) Identity in TLV-encoded form. + * + * This function parses the certificate, ensures the rigid fields have the values mandated by the + * specification, and validates the certificate signature. + * + * @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 + * if the certificate has an invalid signature, or another CHIP_ERROR. + * + * @see section 11.24 (Wi-Fi Authentication with Per-Device Credentials) of the Matter spec + */ +CHIP_ERROR ValidateChipNetworkIdentity(const ByteSpan & cert); + struct FutureExtension { ByteSpan OID; diff --git a/src/credentials/CHIPCertToX509.cpp b/src/credentials/CHIPCertToX509.cpp index 228aaf276796bf..47781c59d57eec 100644 --- a/src/credentials/CHIPCertToX509.cpp +++ b/src/credentials/CHIPCertToX509.cpp @@ -511,11 +511,12 @@ static CHIP_ERROR DecodeConvertTBSCert(TLVReader & reader, ASN1Writer & writer, } ASN1_END_CONSTRUCTED; - ReturnErrorOnFailure(reader.Next(kTLVType_ByteString, ContextTag(kTag_SerialNumber))); - // serialNumber CertificateSerialNumber // CertificateSerialNumber ::= INTEGER - ReturnErrorOnFailure(writer.PutValue(kASN1TagClass_Universal, kASN1UniversalTag_Integer, false, reader)); + ReturnErrorOnFailure(reader.Next(kTLVType_ByteString, ContextTag(kTag_SerialNumber))); + ReturnErrorOnFailure(reader.Get(certData.mSerialNumber)); + ReturnErrorOnFailure(writer.PutValue(kASN1TagClass_Universal, kASN1UniversalTag_Integer, false, + certData.mSerialNumber.data(), static_cast(certData.mSerialNumber.size()))); // signature AlgorithmIdentifier // AlgorithmIdentifier ::= SEQUENCE diff --git a/src/credentials/CHIPCert_Internal.h b/src/credentials/CHIPCert_Internal.h new file mode 100644 index 00000000000000..9e61905b538c6f --- /dev/null +++ b/src/credentials/CHIPCert_Internal.h @@ -0,0 +1,39 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace chip { +namespace Credentials { + +// Constants for Network (Client) Identities as per section 11.24 (Wi-Fi +// Authentication with Per-Device Credentials) of the Matter spec. +inline constexpr CharSpan kNetworkIdentityCN = "*"_span; +inline constexpr ByteSpan kNetworkIdentitySerialNumber = ByteSpan((uint8_t[1]){ 1 }); + +inline constexpr uint32_t kNetworkIdentityNotBeforeTime = 1; +inline constexpr uint32_t kNetworkIdentityNotAfterTime = kNullCertTime; + +inline constexpr auto kNetworkIdentityKeyUsage = BitFlags(KeyUsageFlags::kDigitalSignature); +inline constexpr auto kNetworkIdentityKeyPurpose = + BitFlags(KeyPurposeFlags::kClientAuth, KeyPurposeFlags::kServerAuth); + +} // namespace Credentials +} // namespace chip diff --git a/src/credentials/tests/CHIPCert_test_vectors.cpp b/src/credentials/tests/CHIPCert_test_vectors.cpp index eb84e7d3dabb11..4d457551110e04 100644 --- a/src/credentials/tests/CHIPCert_test_vectors.cpp +++ b/src/credentials/tests/CHIPCert_test_vectors.cpp @@ -50,6 +50,7 @@ extern const TestCert gTestCerts[] = { TestCert::kNode02_06, TestCert::kNode02_07, TestCert::kNode02_08, + TestCert::kPDCID01, }; // clang-format on @@ -87,6 +88,7 @@ CHIP_ERROR GetTestCert(TestCert certType, BitFlags certLoadFl SELECT_CERT(Node02_06); SELECT_CERT(Node02_07); SELECT_CERT(Node02_08); + SELECT_CERT(PDCID01); #undef SELECT_CERT @@ -123,6 +125,7 @@ const char * GetTestCertName(TestCert certType) NAME_CERT(Node02_06); NAME_CERT(Node02_07); NAME_CERT(Node02_08); + NAME_CERT(PDCID01); #undef NAME_CERT @@ -160,6 +163,7 @@ CHIP_ERROR GetTestCertPubkey(TestCert certType, ByteSpan & pubkey) SELECT_PUBKEY(Node02_06); SELECT_PUBKEY(Node02_07); SELECT_PUBKEY(Node02_08); + SELECT_PUBKEY(PDCID01); #undef SELECT_PUBKEY @@ -200,6 +204,7 @@ CHIP_ERROR GetTestCertSKID(TestCert certType, ByteSpan & skid) SELECT_SKID(Node02_06); SELECT_SKID(Node02_07); SELECT_SKID(Node02_08); + SELECT_SKID(PDCID01); #undef SELECT_SKID @@ -240,6 +245,7 @@ CHIP_ERROR GetTestCertAKID(TestCert certType, ByteSpan & akid) SELECT_AKID(Node02_06); SELECT_AKID(Node02_07); SELECT_AKID(Node02_08); + SELECT_AKID(PDCID01); #undef SELECT_AKID @@ -249,6 +255,14 @@ CHIP_ERROR GetTestCertAKID(TestCert certType, ByteSpan & akid) return err; } +CHIP_ERROR DecodeTestCert(ChipCertificateData & certData, TestCert certType) +{ + ByteSpan cert; + ReturnErrorOnFailure(GetTestCert(certType, {}, cert)); + ReturnErrorOnFailure(DecodeChipCert(cert, certData)); + return CHIP_NO_ERROR; +} + CHIP_ERROR LoadTestCert(ChipCertificateSet & certSet, TestCert certType, BitFlags certLoadFlags, BitFlags decodeFlags) { @@ -2450,5 +2464,104 @@ extern constexpr ByteSpan sTestCert_Node02_08_AuthorityKeyId((const uint8_t[]){ 0xE1, 0xE7, 0x6E, 0x67, 0x77, 0x85, 0x1D, 0xD7, 0x74, 0x16, 0xBD, 0xDD, 0x35, 0xEC, 0x3C, 0x13, 0x7C, 0x47, 0x29, 0xDC, }); +/************** Test PDCID01 Certificate ************** +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: CN=* + Validity + Not Before: Jan 1 00:00:01 2000 GMT + Not After : Dec 31 23:59:59 9999 GMT + Subject: CN=* + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:39:cc:d4:ac:7e:59:68:bd:f1:b0:80:11:1d:92: + 53:64:94:fc:51:62:4c:70:aa:6d:73:08:da:ed:f3: + a1:5e:38:69:17:7b:1b:f3:d0:90:47:eb:f0:6b:e8: + dd:17:be:23:f2:fb:3d:63:90:c6:cf:82:80:2f:62: + d0:53:62:c0:08 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Key Usage: critical + Digital Signature + X509v3 Extended Key Usage: critical + TLS Web Client Authentication, TLS Web Server Authentication + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:21:00:e9:43:b6:16:f3:1a:f3:81:52:e7:37:41:f7: + 47:28:db:7d:56:87:b5:94:c0:2e:0f:5f:ee:3a:60:bf:36:44: + a9:02:20:1c:85:2c:fd:6b:15:d8:f8:fe:19:93:4d:af:2f:91: + 93:fd:2c:bc:4e:23:50:0a:31:7d:a4:a0:79:b2:db:69:42 + +-----BEGIN CERTIFICATE----- +MIIBSjCB8aADAgECAgEBMAoGCCqGSM49BAMCMAwxCjAIBgNVBAMMASowIBcNMDAw +MTAxMDAwMDAxWhgPOTk5OTEyMzEyMzU5NTlaMAwxCjAIBgNVBAMMASowWTATBgcq +hkjOPQIBBggqhkjOPQMBBwNCAAQ5zNSsfllovfGwgBEdklNklPxRYkxwqm1zCNrt +86FeOGkXexvz0JBH6/Br6N0XviPy+z1jkMbPgoAvYtBTYsAIo0IwQDAMBgNVHRMB +Af8EAjAAMA4GA1UdDwEB/wQEAwIHgDAgBgNVHSUBAf8EFjAUBggrBgEFBQcDAgYI +KwYBBQUHAwEwCgYIKoZIzj0EAwIDSAAwRQIhAOlDthbzGvOBUuc3QfdHKNt9Voe1 +lMAuD1/uOmC/NkSpAiAchSz9axXY+P4Zk02vL5GT/Sy8TiNQCjF9pKB5sttpQg== +-----END CERTIFICATE----- + +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIAgMqGL8i1LKFupDgkl42mQgn1XS3oMd7nCENcUEwV6roAoGCCqGSM49 +AwEHoUQDQgAEOczUrH5ZaL3xsIARHZJTZJT8UWJMcKptcwja7fOhXjhpF3sb89CQ +R+vwa+jdF74j8vs9Y5DGz4KAL2LQU2LACA== +-----END EC PRIVATE KEY----- +*/ + +extern constexpr ByteSpan sTestCert_PDCID01_Chip((const uint8_t[]){ + 0x15, 0x30, 0x01, 0x01, 0x01, 0x24, 0x02, 0x01, 0x37, 0x03, 0x2c, 0x01, 0x01, 0x2a, 0x18, 0x24, 0x04, 0x01, 0x24, 0x05, 0x00, + 0x37, 0x06, 0x2c, 0x01, 0x01, 0x2a, 0x18, 0x24, 0x07, 0x01, 0x24, 0x08, 0x01, 0x30, 0x09, 0x41, 0x04, 0x39, 0xcc, 0xd4, 0xac, + 0x7e, 0x59, 0x68, 0xbd, 0xf1, 0xb0, 0x80, 0x11, 0x1d, 0x92, 0x53, 0x64, 0x94, 0xfc, 0x51, 0x62, 0x4c, 0x70, 0xaa, 0x6d, 0x73, + 0x08, 0xda, 0xed, 0xf3, 0xa1, 0x5e, 0x38, 0x69, 0x17, 0x7b, 0x1b, 0xf3, 0xd0, 0x90, 0x47, 0xeb, 0xf0, 0x6b, 0xe8, 0xdd, 0x17, + 0xbe, 0x23, 0xf2, 0xfb, 0x3d, 0x63, 0x90, 0xc6, 0xcf, 0x82, 0x80, 0x2f, 0x62, 0xd0, 0x53, 0x62, 0xc0, 0x08, 0x37, 0x0a, 0x35, + 0x01, 0x28, 0x01, 0x18, 0x24, 0x02, 0x01, 0x36, 0x03, 0x04, 0x02, 0x04, 0x01, 0x18, 0x18, 0x30, 0x0b, 0x40, 0xe9, 0x43, 0xb6, + 0x16, 0xf3, 0x1a, 0xf3, 0x81, 0x52, 0xe7, 0x37, 0x41, 0xf7, 0x47, 0x28, 0xdb, 0x7d, 0x56, 0x87, 0xb5, 0x94, 0xc0, 0x2e, 0x0f, + 0x5f, 0xee, 0x3a, 0x60, 0xbf, 0x36, 0x44, 0xa9, 0x1c, 0x85, 0x2c, 0xfd, 0x6b, 0x15, 0xd8, 0xf8, 0xfe, 0x19, 0x93, 0x4d, 0xaf, + 0x2f, 0x91, 0x93, 0xfd, 0x2c, 0xbc, 0x4e, 0x23, 0x50, 0x0a, 0x31, 0x7d, 0xa4, 0xa0, 0x79, 0xb2, 0xdb, 0x69, 0x42, 0x18, +}); + +extern constexpr ByteSpan sTestCert_PDCID01_DER((const uint8_t[]){ + 0x30, 0x82, 0x01, 0x4a, 0x30, 0x81, 0xf1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x0c, 0x31, 0x0a, 0x30, 0x08, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x01, 0x2a, 0x30, + 0x20, 0x17, 0x0d, 0x30, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x5a, 0x18, 0x0f, 0x39, 0x39, 0x39, + 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x0c, 0x31, 0x0a, 0x30, 0x08, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x01, 0x2a, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x39, 0xcc, 0xd4, 0xac, 0x7e, 0x59, 0x68, 0xbd, 0xf1, 0xb0, + 0x80, 0x11, 0x1d, 0x92, 0x53, 0x64, 0x94, 0xfc, 0x51, 0x62, 0x4c, 0x70, 0xaa, 0x6d, 0x73, 0x08, 0xda, 0xed, 0xf3, 0xa1, 0x5e, + 0x38, 0x69, 0x17, 0x7b, 0x1b, 0xf3, 0xd0, 0x90, 0x47, 0xeb, 0xf0, 0x6b, 0xe8, 0xdd, 0x17, 0xbe, 0x23, 0xf2, 0xfb, 0x3d, 0x63, + 0x90, 0xc6, 0xcf, 0x82, 0x80, 0x2f, 0x62, 0xd0, 0x53, 0x62, 0xc0, 0x08, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0c, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, + 0x03, 0x02, 0x07, 0x80, 0x30, 0x20, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30, 0x0a, 0x06, 0x08, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xe9, 0x43, 0xb6, 0x16, 0xf3, + 0x1a, 0xf3, 0x81, 0x52, 0xe7, 0x37, 0x41, 0xf7, 0x47, 0x28, 0xdb, 0x7d, 0x56, 0x87, 0xb5, 0x94, 0xc0, 0x2e, 0x0f, 0x5f, 0xee, + 0x3a, 0x60, 0xbf, 0x36, 0x44, 0xa9, 0x02, 0x20, 0x1c, 0x85, 0x2c, 0xfd, 0x6b, 0x15, 0xd8, 0xf8, 0xfe, 0x19, 0x93, 0x4d, 0xaf, + 0x2f, 0x91, 0x93, 0xfd, 0x2c, 0xbc, 0x4e, 0x23, 0x50, 0x0a, 0x31, 0x7d, 0xa4, 0xa0, 0x79, 0xb2, 0xdb, 0x69, 0x42, +}); + +extern constexpr ByteSpan sTestCert_PDCID01_PublicKey((const uint8_t[]){ + 0x04, 0x39, 0xcc, 0xd4, 0xac, 0x7e, 0x59, 0x68, 0xbd, 0xf1, 0xb0, 0x80, 0x11, 0x1d, 0x92, 0x53, 0x64, + 0x94, 0xfc, 0x51, 0x62, 0x4c, 0x70, 0xaa, 0x6d, 0x73, 0x08, 0xda, 0xed, 0xf3, 0xa1, 0x5e, 0x38, 0x69, + 0x17, 0x7b, 0x1b, 0xf3, 0xd0, 0x90, 0x47, 0xeb, 0xf0, 0x6b, 0xe8, 0xdd, 0x17, 0xbe, 0x23, 0xf2, 0xfb, + 0x3d, 0x63, 0x90, 0xc6, 0xcf, 0x82, 0x80, 0x2f, 0x62, 0xd0, 0x53, 0x62, 0xc0, 0x08, +}); + +extern constexpr ByteSpan sTestCert_PDCID01_PrivateKey((const uint8_t[]){ + 0x08, 0x0c, 0xa8, 0x62, 0xfc, 0x8b, 0x52, 0xca, 0x16, 0xea, 0x43, 0x82, 0x49, 0x78, 0xda, 0x64, + 0x20, 0x9f, 0x55, 0xd2, 0xde, 0x83, 0x1d, 0xee, 0x70, 0x84, 0x35, 0xc5, 0x04, 0xc1, 0x5e, 0xab, +}); + +extern constexpr ByteSpan sTestCert_PDCID01_SubjectKeyId{}; + +extern constexpr ByteSpan sTestCert_PDCID01_AuthorityKeyId{}; + } // namespace TestCerts } // namespace chip diff --git a/src/credentials/tests/CHIPCert_test_vectors.h b/src/credentials/tests/CHIPCert_test_vectors.h index 521426ee3e5084..d14cad56ffcab0 100644 --- a/src/credentials/tests/CHIPCert_test_vectors.h +++ b/src/credentials/tests/CHIPCert_test_vectors.h @@ -55,6 +55,7 @@ enum TestCert kNode02_07 = 15, kNode02_08 = 16, kRoot03 = 17, + kPDCID01 = 18, }; // Special flags to alter how certificates are fetched/loaded. @@ -73,6 +74,8 @@ extern const char * GetTestCertName(TestCert certType); extern CHIP_ERROR GetTestCertPubkey(TestCert certType, ByteSpan & pubkey); extern CHIP_ERROR GetTestCertSKID(TestCert certType, ByteSpan & skid); extern CHIP_ERROR GetTestCertAKID(TestCert certType, ByteSpan & akid); + +extern CHIP_ERROR DecodeTestCert(ChipCertificateData & certData, TestCert certType); extern CHIP_ERROR LoadTestCert(ChipCertificateSet & certSet, TestCert certType, BitFlags certLoadFlags, BitFlags decodeFlags); @@ -202,5 +205,12 @@ extern const ByteSpan sTestCert_Node02_08_PrivateKey; extern const ByteSpan sTestCert_Node02_08_SubjectKeyId; extern const ByteSpan sTestCert_Node02_08_AuthorityKeyId; +extern const ByteSpan sTestCert_PDCID01_Chip; +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; + } // namespace TestCerts } // namespace chip diff --git a/src/credentials/tests/TestChipCert.cpp b/src/credentials/tests/TestChipCert.cpp index ff79157815a79e..d16cd7efc26231 100644 --- a/src/credentials/tests/TestChipCert.cpp +++ b/src/credentials/tests/TestChipCert.cpp @@ -52,55 +52,55 @@ enum kStandardCertsCount = 3, }; -static const BitFlags sNullDecodeFlag; -static const BitFlags sGenTBSHashFlag(CertDecodeFlags::kGenerateTBSHash); -static const BitFlags sTrustAnchorFlag(CertDecodeFlags::kIsTrustAnchor); - -static const BitFlags sNullLoadFlag; -static const BitFlags sDerFormFlag(TestCertLoadFlags::kDERForm); -static const BitFlags sSupIsCAFlag(TestCertLoadFlags::kSuppressIsCA); -static const BitFlags sSupKeyUsageFlag(TestCertLoadFlags::kSuppressKeyUsage); -static const BitFlags sSupKeyCertSignFlag(TestCertLoadFlags::kSuppressKeyCertSign); -static const BitFlags sPathLenZeroFlag(TestCertLoadFlags::kSetPathLenConstZero); - -static const BitFlags sNullKPFlag; -static const BitFlags sSA(KeyPurposeFlags::kServerAuth); -static const BitFlags sCA(KeyPurposeFlags::kClientAuth); -static const BitFlags sCS(KeyPurposeFlags::kCodeSigning); -static const BitFlags sEP(KeyPurposeFlags::kEmailProtection); -static const BitFlags sTS(KeyPurposeFlags::kTimeStamping); -static const BitFlags sOS(KeyPurposeFlags::kOCSPSigning); -static const BitFlags sSAandCA(sSA, sCA); -static const BitFlags sSAandCS(sSA, sCS); -static const BitFlags sSAandEP(sSA, sEP); -static const BitFlags sSAandTS(sSA, sTS); - -static const BitFlags sNullKUFlag; -static const BitFlags sDS(KeyUsageFlags::kDigitalSignature); -static const BitFlags sNR(KeyUsageFlags::kNonRepudiation); -static const BitFlags sKE(KeyUsageFlags::kKeyEncipherment); -static const BitFlags sDE(KeyUsageFlags::kDataEncipherment); -static const BitFlags sKA(KeyUsageFlags::kKeyAgreement); -static const BitFlags sKC(KeyUsageFlags::kKeyCertSign); -static const BitFlags sCR(KeyUsageFlags::kCRLSign); -static const BitFlags sEO(KeyUsageFlags::kEncipherOnly); -static const BitFlags sDO(KeyUsageFlags::kDecipherOnly); -static const BitFlags sDSandNR(sDS, sNR); -static const BitFlags sDSandKE(sDS, sKE); -static const BitFlags sDSandDE(sDS, sDE); -static const BitFlags sDSandKA(sDS, sKA); -static const BitFlags sDSandKC(sDS, sKC); -static const BitFlags sDSandCR(sDS, sCR); -static const BitFlags sDSandEO(sDS, sEO); -static const BitFlags sDSandDO(sDS, sDO); -static const BitFlags sKCandDS(sKC, sDS); -static const BitFlags sKCandNR(sKC, sNR); -static const BitFlags sKCandKE(sKC, sKE); -static const BitFlags sKCandDE(sKC, sDE); -static const BitFlags sKCandKA(sKC, sKA); -static const BitFlags sKCandCR(sKC, sCR); -static const BitFlags sKCandEO(sKC, sEO); -static const BitFlags sKCandDO(sKC, sDO); +static constexpr BitFlags sNullDecodeFlag; +static constexpr BitFlags sGenTBSHashFlag(CertDecodeFlags::kGenerateTBSHash); +static constexpr BitFlags sTrustAnchorFlag(CertDecodeFlags::kIsTrustAnchor); + +static constexpr BitFlags sNullLoadFlag; +static constexpr BitFlags sDerFormFlag(TestCertLoadFlags::kDERForm); +static constexpr BitFlags sSupIsCAFlag(TestCertLoadFlags::kSuppressIsCA); +static constexpr BitFlags sSupKeyUsageFlag(TestCertLoadFlags::kSuppressKeyUsage); +static constexpr BitFlags sSupKeyCertSignFlag(TestCertLoadFlags::kSuppressKeyCertSign); +static constexpr BitFlags sPathLenZeroFlag(TestCertLoadFlags::kSetPathLenConstZero); + +static constexpr BitFlags sNullKPFlag; +static constexpr BitFlags sSA(KeyPurposeFlags::kServerAuth); +static constexpr BitFlags sCA(KeyPurposeFlags::kClientAuth); +static constexpr BitFlags sCS(KeyPurposeFlags::kCodeSigning); +static constexpr BitFlags sEP(KeyPurposeFlags::kEmailProtection); +static constexpr BitFlags sTS(KeyPurposeFlags::kTimeStamping); +// static constexpr BitFlags sOS(KeyPurposeFlags::kOCSPSigning); // unused +static constexpr BitFlags sSAandCA(sSA, sCA); +static constexpr BitFlags sSAandCS(sSA, sCS); +static constexpr BitFlags sSAandEP(sSA, sEP); +static constexpr BitFlags sSAandTS(sSA, sTS); + +static constexpr BitFlags sNullKUFlag; +static constexpr BitFlags sDS(KeyUsageFlags::kDigitalSignature); +static constexpr BitFlags sNR(KeyUsageFlags::kNonRepudiation); +static constexpr BitFlags sKE(KeyUsageFlags::kKeyEncipherment); +static constexpr BitFlags sDE(KeyUsageFlags::kDataEncipherment); +static constexpr BitFlags sKA(KeyUsageFlags::kKeyAgreement); +static constexpr BitFlags sKC(KeyUsageFlags::kKeyCertSign); +static constexpr BitFlags sCR(KeyUsageFlags::kCRLSign); +static constexpr BitFlags sEO(KeyUsageFlags::kEncipherOnly); +static constexpr BitFlags sDO(KeyUsageFlags::kDecipherOnly); +static constexpr BitFlags sDSandNR(sDS, sNR); +static constexpr BitFlags sDSandKE(sDS, sKE); +static constexpr BitFlags sDSandDE(sDS, sDE); +static constexpr BitFlags sDSandKA(sDS, sKA); +static constexpr BitFlags sDSandKC(sDS, sKC); +static constexpr BitFlags sDSandCR(sDS, sCR); +static constexpr BitFlags sDSandEO(sDS, sEO); +static constexpr BitFlags sDSandDO(sDS, sDO); +static constexpr BitFlags sKCandDS(sKC, sDS); +static constexpr BitFlags sKCandNR(sKC, sNR); +static constexpr BitFlags sKCandKE(sKC, sKE); +static constexpr BitFlags sKCandDE(sKC, sDE); +static constexpr BitFlags sKCandKA(sKC, sKA); +static constexpr BitFlags sKCandCR(sKC, sCR); +static constexpr BitFlags sKCandEO(sKC, sEO); +static constexpr BitFlags sKCandDO(sKC, sDO); constexpr uint8_t sOID_Extension_SubjectAltName[] = { 0x55, 0x1d, 0x11 }; constexpr char kExtension_SubjectAltName[] = "test@example.com"; @@ -1187,7 +1187,7 @@ static void TestChipCert_CertUsage(nlTestSuite * inSuite, void * inContext) static void TestChipCert_CertType(nlTestSuite * inSuite, void * inContext) { CHIP_ERROR err; - ChipCertificateSet certSet; + ChipCertificateData certData; struct TestCase { @@ -1209,31 +1209,27 @@ static void TestChipCert_CertType(nlTestSuite * inSuite, void * inContext) { TestCert::kNode01_02, CertType::kNode }, { TestCert::kNode02_01, CertType::kNode }, { TestCert::kNode02_02, CertType::kNode }, + { TestCert::kPDCID01, CertType::kNetworkIdentity }, }; // clang-format on for (const auto & testCase : sTestCases) { CertType certType; - err = certSet.Init(1); + err = DecodeTestCert(certData, testCase.Cert); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - err = LoadTestCert(certSet, testCase.Cert, sNullLoadFlag, sNullDecodeFlag); - NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - - err = certSet.GetCertSet()->mSubjectDN.GetCertType(certType); + err = certData.mSubjectDN.GetCertType(certType); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); NL_TEST_ASSERT(inSuite, certType == testCase.ExpectedCertType); - certSet.Release(); } } static void TestChipCert_CertId(nlTestSuite * inSuite, void * inContext) { CHIP_ERROR err; - ChipCertificateSet certSet; - ChipCertificateData certData[1]; + ChipCertificateData certData; struct TestCase { @@ -1255,23 +1251,26 @@ static void TestChipCert_CertId(nlTestSuite * inSuite, void * inContext) { TestCert::kNode01_02, 0xDEDEDEDE00010002 }, { TestCert::kNode02_01, 0xDEDEDEDE00020001 }, { TestCert::kNode02_02, 0xDEDEDEDE00020002 }, + { TestCert::kPDCID01, 0 }, }; // clang-format on for (const auto & testCase : sTestCases) { uint64_t chipId; - err = certSet.Init(certData, 1); + err = DecodeTestCert(certData, testCase.Cert); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - err = LoadTestCert(certSet, testCase.Cert, sNullLoadFlag, sNullDecodeFlag); - NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - - err = certSet.GetCertSet()->mSubjectDN.GetCertChipId(chipId); - NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - - NL_TEST_ASSERT(inSuite, chipId == testCase.ExpectedCertId); - certSet.Release(); + err = certData.mSubjectDN.GetCertChipId(chipId); + if (testCase.ExpectedCertId != 0) + { + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, chipId == testCase.ExpectedCertId); + } + else + { + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_WRONG_CERT_DN); + } } } @@ -2052,6 +2051,7 @@ static void TestChipCert_ExtractSubjectDNFromChipCert(nlTestSuite * inSuite, voi { TestCert::kICA02, expectedSubjectDN_ICA02 }, { TestCert::kNode01_01, expectedSubjectDN_Node01_01 }, { TestCert::kNode02_03, expectedSubjectDN_Node02_03 }, + { TestCert::kPDCID01, {} }, }; // clang-format on @@ -2065,7 +2065,11 @@ static void TestChipCert_ExtractSubjectDNFromChipCert(nlTestSuite * inSuite, voi ChipDN subjectDN; err = ExtractSubjectDNFromChipCert(cert, subjectDN); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, subjectDN.IsEqual(testCase.ExpectedSubjectDN)); + + if (!testCase.ExpectedSubjectDN.IsEmpty()) + { + NL_TEST_ASSERT(inSuite, subjectDN.IsEqual(testCase.ExpectedSubjectDN)); + } } // Test extraction from the X509 ByteSpan form. @@ -2078,7 +2082,11 @@ static void TestChipCert_ExtractSubjectDNFromChipCert(nlTestSuite * inSuite, voi ChipDN subjectDN; err = ExtractSubjectDNFromX509Cert(cert, subjectDN); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, subjectDN.IsEqual(testCase.ExpectedSubjectDN)); + + if (!testCase.ExpectedSubjectDN.IsEmpty()) + { + NL_TEST_ASSERT(inSuite, subjectDN.IsEqual(testCase.ExpectedSubjectDN)); + } } } @@ -2110,6 +2118,7 @@ static void TestChipCert_ExtractPublicKeyAndSKID(nlTestSuite * inSuite, void * i { TestCert::kNode02_06, sTestCert_Node02_06_PublicKey, sTestCert_Node02_06_SubjectKeyId }, { TestCert::kNode02_07, sTestCert_Node02_07_PublicKey, sTestCert_Node02_07_SubjectKeyId }, { TestCert::kNode02_08, sTestCert_Node02_08_PublicKey, sTestCert_Node02_08_SubjectKeyId }, + { TestCert::kPDCID01, sTestCert_PDCID01_PublicKey, ByteSpan() }, }; // clang-format on @@ -2126,11 +2135,26 @@ static void TestChipCert_ExtractPublicKeyAndSKID(nlTestSuite * inSuite, void * i CertificateKeyId skid; err = ExtractSKIDFromChipCert(cert, skid); - NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, skid.data_equal(testCase.ExpectedSKID)); + if (!testCase.ExpectedSKID.empty()) + { + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, skid.data_equal(testCase.ExpectedSKID)); + } + else + { + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_NOT_FOUND); + } } } +static void TestChipCert_PDCIdentityValidation(nlTestSuite * inSuite, void * inContext) +{ + CHIP_ERROR err; + + err = ValidateChipNetworkIdentity(sTestCert_PDCID01_Chip); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); +} + /** * Set up the test suite. */ @@ -2189,6 +2213,7 @@ static const nlTest sTests[] = { NL_TEST_DEF("Test extracting and validating CASE Authenticated Tags from NOC", TestChipCert_ExtractAndValidateCATsFromOpCert), NL_TEST_DEF("Test extracting Subject DN from chip certificate", TestChipCert_ExtractSubjectDNFromChipCert), NL_TEST_DEF("Test extracting PublicKey and SKID from chip certificate", TestChipCert_ExtractPublicKeyAndSKID), + NL_TEST_DEF("Test PDC Identity Validation", TestChipCert_PDCIdentityValidation), NL_TEST_SENTINEL() }; // clang-format on diff --git a/src/crypto/tests/CHIPCryptoPALTest.cpp b/src/crypto/tests/CHIPCryptoPALTest.cpp index a79961dbe07c99..38343a60d52e5c 100644 --- a/src/crypto/tests/CHIPCryptoPALTest.cpp +++ b/src/crypto/tests/CHIPCryptoPALTest.cpp @@ -2201,8 +2201,15 @@ static void TestSKID_x509Extraction(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); err = ExtractSKIDFromX509Cert(cert, skidOut); - NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, skidSpan.data_equal(skidOut)); + if (!skidSpan.empty()) + { + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, skidSpan.data_equal(skidOut)); + } + else + { + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_NOT_FOUND); + } } } @@ -2228,8 +2235,15 @@ static void TestAKID_x509Extraction(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); err = ExtractAKIDFromX509Cert(cert, akidOut); - NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, akidSpan.data_equal(akidOut)); + if (!akidSpan.empty()) + { + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, akidSpan.data_equal(akidOut)); + } + else + { + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_NOT_FOUND); + } } } diff --git a/src/lib/support/BitFlags.h b/src/lib/support/BitFlags.h index ec64f19f5f9676..3cc7dc4a24fdb2 100644 --- a/src/lib/support/BitFlags.h +++ b/src/lib/support/BitFlags.h @@ -50,19 +50,19 @@ class BitFlags BitFlags(const BitFlags & other) = default; BitFlags & operator=(const BitFlags &) = default; - explicit BitFlags(FlagsEnum value) : mValue(static_cast(value)) {} - explicit BitFlags(IntegerType value) : mValue(value) {} + explicit constexpr BitFlags(FlagsEnum value) : mValue(static_cast(value)) {} + explicit constexpr BitFlags(IntegerType value) : mValue(value) {} template - BitFlags(FlagsEnum flag, Args &&... args) : mValue(Or(flag, std::forward(args)...)) + constexpr BitFlags(FlagsEnum flag, Args &&... args) : mValue(Or(flag, std::forward(args)...)) {} template - BitFlags(const BitFlags & flags, Args &&... args) : mValue(Or(flags, std::forward(args)...)) + constexpr BitFlags(const BitFlags & flags, Args &&... args) : mValue(Or(flags, std::forward(args)...)) {} template - BitFlags(IntegerType value, Args &&... args) : mValue(value | Or(std::forward(args)...)) + constexpr BitFlags(IntegerType value, Args &&... args) : mValue(value | Or(std::forward(args)...)) {} /** @@ -221,7 +221,7 @@ class BitFlags * * @note This is intended to be used only to store flags into a raw binary record. */ - IntegerType Raw() const { return mValue; } + constexpr IntegerType Raw() const { return mValue; } /** * Get the address of the flags as a pointer to the underlying integer type.