| /* |
| * |
| * Copyright (c) 2020-2022 Project CHIP Authors |
| * Copyright (c) 2019 Google LLC. |
| * Copyright (c) 2013-2017 Nest Labs, Inc. |
| * 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. |
| */ |
| |
| /** |
| * @file |
| * Unit tests for CHIP certificate functionality. |
| * |
| */ |
| |
| #include <credentials/CHIPCert.h> |
| #include <credentials/examples/LastKnownGoodTimeCertificateValidityPolicyExample.h> |
| #include <credentials/examples/StrictCertificateValidityPolicyExample.h> |
| #include <crypto/CHIPCryptoPAL.h> |
| #include <lib/core/ErrorStr.h> |
| #include <lib/core/PeerId.h> |
| #include <lib/core/TLV.h> |
| #include <lib/support/CHIPMem.h> |
| #include <lib/support/CodeUtils.h> |
| |
| #include <gtest/gtest.h> |
| |
| #include "CHIPCert_error_test_vectors.h" |
| #include "CHIPCert_test_vectors.h" |
| |
| using namespace chip; |
| using namespace chip::ASN1; |
| using namespace chip::TLV; |
| using namespace chip::Credentials; |
| using namespace chip::TestCerts; |
| using namespace chip::Crypto; |
| |
| enum |
| { |
| kStandardCertsCount = 3, |
| }; |
| |
| static constexpr BitFlags<CertDecodeFlags> sNullDecodeFlag; |
| static constexpr BitFlags<CertDecodeFlags> sGenTBSHashFlag(CertDecodeFlags::kGenerateTBSHash); |
| static constexpr BitFlags<CertDecodeFlags> sTrustAnchorFlag(CertDecodeFlags::kIsTrustAnchor); |
| |
| static constexpr BitFlags<TestCertLoadFlags> sNullLoadFlag; |
| static constexpr BitFlags<TestCertLoadFlags> sDerFormFlag(TestCertLoadFlags::kDERForm); |
| static constexpr BitFlags<TestCertLoadFlags> sSupIsCAFlag(TestCertLoadFlags::kSuppressIsCA); |
| static constexpr BitFlags<TestCertLoadFlags> sSupKeyUsageFlag(TestCertLoadFlags::kSuppressKeyUsage); |
| static constexpr BitFlags<TestCertLoadFlags> sSupKeyCertSignFlag(TestCertLoadFlags::kSuppressKeyCertSign); |
| static constexpr BitFlags<TestCertLoadFlags> sPathLenZeroFlag(TestCertLoadFlags::kSetPathLenConstZero); |
| |
| static constexpr BitFlags<KeyPurposeFlags> sNullKPFlag; |
| static constexpr BitFlags<KeyPurposeFlags> sSA(KeyPurposeFlags::kServerAuth); |
| static constexpr BitFlags<KeyPurposeFlags> sCA(KeyPurposeFlags::kClientAuth); |
| static constexpr BitFlags<KeyPurposeFlags> sCS(KeyPurposeFlags::kCodeSigning); |
| static constexpr BitFlags<KeyPurposeFlags> sEP(KeyPurposeFlags::kEmailProtection); |
| static constexpr BitFlags<KeyPurposeFlags> sTS(KeyPurposeFlags::kTimeStamping); |
| // static constexpr BitFlags<KeyPurposeFlags> sOS(KeyPurposeFlags::kOCSPSigning); // unused |
| static constexpr BitFlags<KeyPurposeFlags> sSAandCA(sSA, sCA); |
| static constexpr BitFlags<KeyPurposeFlags> sSAandCS(sSA, sCS); |
| static constexpr BitFlags<KeyPurposeFlags> sSAandEP(sSA, sEP); |
| static constexpr BitFlags<KeyPurposeFlags> sSAandTS(sSA, sTS); |
| |
| static constexpr BitFlags<KeyUsageFlags> sNullKUFlag; |
| static constexpr BitFlags<KeyUsageFlags> sDS(KeyUsageFlags::kDigitalSignature); |
| static constexpr BitFlags<KeyUsageFlags> sNR(KeyUsageFlags::kNonRepudiation); |
| static constexpr BitFlags<KeyUsageFlags> sKE(KeyUsageFlags::kKeyEncipherment); |
| static constexpr BitFlags<KeyUsageFlags> sDE(KeyUsageFlags::kDataEncipherment); |
| static constexpr BitFlags<KeyUsageFlags> sKA(KeyUsageFlags::kKeyAgreement); |
| static constexpr BitFlags<KeyUsageFlags> sKC(KeyUsageFlags::kKeyCertSign); |
| static constexpr BitFlags<KeyUsageFlags> sCR(KeyUsageFlags::kCRLSign); |
| static constexpr BitFlags<KeyUsageFlags> sEO(KeyUsageFlags::kEncipherOnly); |
| static constexpr BitFlags<KeyUsageFlags> sDO(KeyUsageFlags::kDecipherOnly); |
| static constexpr BitFlags<KeyUsageFlags> sDSandNR(sDS, sNR); |
| static constexpr BitFlags<KeyUsageFlags> sDSandKE(sDS, sKE); |
| static constexpr BitFlags<KeyUsageFlags> sDSandDE(sDS, sDE); |
| static constexpr BitFlags<KeyUsageFlags> sDSandKA(sDS, sKA); |
| static constexpr BitFlags<KeyUsageFlags> sDSandKC(sDS, sKC); |
| static constexpr BitFlags<KeyUsageFlags> sDSandCR(sDS, sCR); |
| static constexpr BitFlags<KeyUsageFlags> sDSandEO(sDS, sEO); |
| static constexpr BitFlags<KeyUsageFlags> sDSandDO(sDS, sDO); |
| static constexpr BitFlags<KeyUsageFlags> sKCandDS(sKC, sDS); |
| static constexpr BitFlags<KeyUsageFlags> sKCandNR(sKC, sNR); |
| static constexpr BitFlags<KeyUsageFlags> sKCandKE(sKC, sKE); |
| static constexpr BitFlags<KeyUsageFlags> sKCandDE(sKC, sDE); |
| static constexpr BitFlags<KeyUsageFlags> sKCandKA(sKC, sKA); |
| static constexpr BitFlags<KeyUsageFlags> sKCandCR(sKC, sCR); |
| static constexpr BitFlags<KeyUsageFlags> sKCandEO(sKC, sEO); |
| static constexpr BitFlags<KeyUsageFlags> sKCandDO(sKC, sDO); |
| |
| constexpr uint8_t sOID_Extension_SubjectAltName[] = { 0x55, 0x1d, 0x11 }; |
| constexpr char kExtension_SubjectAltName[] = "test@example.com"; |
| |
| FutureExtension ext{ ByteSpan(sOID_Extension_SubjectAltName), |
| ByteSpan(reinterpret_cast<uint8_t *>(const_cast<char *>(kExtension_SubjectAltName)), |
| strlen(kExtension_SubjectAltName)) }; |
| Optional<FutureExtension> kSubjectAltNameAsFutureExt(ext); |
| |
| static CHIP_ERROR LoadTestCertSet01(ChipCertificateSet & certSet) |
| { |
| CHIP_ERROR err; |
| |
| err = LoadTestCert(certSet, TestCert::kRoot01, sNullLoadFlag, sTrustAnchorFlag); |
| SuccessOrExit(err); |
| |
| err = LoadTestCert(certSet, TestCert::kICA01, sNullLoadFlag, sGenTBSHashFlag); |
| SuccessOrExit(err); |
| |
| err = LoadTestCert(certSet, TestCert::kNode01_01, sNullLoadFlag, sGenTBSHashFlag); |
| SuccessOrExit(err); |
| |
| exit: |
| return err; |
| } |
| |
| static CHIP_ERROR SetCurrentTime(ValidationContext & validContext, uint16_t year, uint8_t mon, uint8_t day, uint8_t hour = 0, |
| uint8_t min = 0, uint8_t sec = 0) |
| { |
| ASN1UniversalTime currentTime; |
| |
| currentTime.Year = year; |
| currentTime.Month = mon; |
| currentTime.Day = day; |
| currentTime.Hour = hour; |
| currentTime.Minute = min; |
| currentTime.Second = sec; |
| |
| return validContext.SetEffectiveTimeFromAsn1Time<CurrentChipEpochTime>(currentTime); |
| } |
| |
| static CHIP_ERROR SetLastKnownGoodTime(ValidationContext & validContext, uint16_t year, uint8_t mon, uint8_t day, uint8_t hour = 0, |
| uint8_t min = 0, uint8_t sec = 0) |
| { |
| ASN1UniversalTime lastKnownGoodTime; |
| |
| lastKnownGoodTime.Year = year; |
| lastKnownGoodTime.Month = mon; |
| lastKnownGoodTime.Day = day; |
| lastKnownGoodTime.Hour = hour; |
| lastKnownGoodTime.Minute = min; |
| lastKnownGoodTime.Second = sec; |
| |
| return validContext.SetEffectiveTimeFromAsn1Time<LastKnownGoodChipEpochTime>(lastKnownGoodTime); |
| } |
| |
| static void ClearTimeSource(ValidationContext & validContext) |
| { |
| validContext.mEffectiveTime = EffectiveTime{}; |
| } |
| |
| struct TestChipCert : public ::testing::Test |
| { |
| static void SetUpTestSuite() { ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR); } |
| static void TearDownTestSuite() { chip::Platform::MemoryShutdown(); } |
| }; |
| |
| TEST_F(TestChipCert, TestChipCert_ChipToX509) |
| { |
| CHIP_ERROR err; |
| ByteSpan inCert; |
| ByteSpan expectedOutCert; |
| uint8_t outCertBuf[kMaxDERCertLength]; |
| |
| for (size_t i = 0; i < gNumTestCerts; i++) |
| { |
| TestCert certType = gTestCerts[i]; |
| |
| err = GetTestCert(certType, sNullLoadFlag, inCert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| err = GetTestCert(certType, sDerFormFlag, expectedOutCert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| MutableByteSpan outCert(outCertBuf); |
| err = ConvertChipCertToX509Cert(inCert, outCert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_TRUE(expectedOutCert.data_equal(outCert)); |
| } |
| |
| // Error Case: |
| MutableByteSpan outCert(outCertBuf); |
| err = ConvertChipCertToX509Cert(sTestCert_Node01_01_Err01_Chip, outCert); |
| EXPECT_EQ(err, CHIP_ERROR_INVALID_TLV_TAG); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_ChipToX509_ErrorCases) |
| { |
| CHIP_ERROR err; |
| uint8_t outCertBuf[kMaxDERCertLength]; |
| |
| for (auto chipCert : gTestCert_ChipToX509_ErrorCases) |
| { |
| MutableByteSpan outCert(outCertBuf); |
| |
| err = ConvertChipCertToX509Cert(chipCert, outCert); |
| EXPECT_NE(err, CHIP_NO_ERROR); |
| } |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_ChipCertLoad_ErrorCases) |
| { |
| CHIP_ERROR err; |
| ChipCertificateSet certSet; |
| |
| err = certSet.Init(1); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| for (auto chipCert : gTestCert_ChipCertLoad_ErrorCases) |
| { |
| err = certSet.LoadCert(chipCert, sNullDecodeFlag); |
| EXPECT_NE(err, CHIP_NO_ERROR); |
| |
| certSet.Clear(); |
| } |
| |
| certSet.Release(); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_ValidateChipRCAC_ErrorCases) |
| { |
| CHIP_ERROR err; |
| |
| for (auto chipCert : gTestCert_ValidateChipRCAC_ErrorCases) |
| { |
| err = ValidateChipRCAC(chipCert); |
| EXPECT_NE(err, CHIP_NO_ERROR); |
| } |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_GetCertType_ErrorCases) |
| { |
| CHIP_ERROR err; |
| ChipCertificateSet certSet; |
| |
| err = certSet.Init(1); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| for (auto chipCert : gTestCert_GetCertType_ErrorCases) |
| { |
| CertType certType; |
| |
| err = certSet.LoadCert(chipCert, sNullDecodeFlag); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| err = certSet.GetCertSet()->mSubjectDN.GetCertType(certType); |
| EXPECT_TRUE(err != CHIP_NO_ERROR || certType == CertType::kNotSpecified); |
| |
| certSet.Clear(); |
| } |
| |
| certSet.Release(); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_X509ToChip) |
| { |
| CHIP_ERROR err; |
| ByteSpan inCert; |
| ByteSpan expectedOutCert; |
| uint8_t outCertBuf[kMaxCHIPCertLength]; |
| |
| for (size_t i = 0; i < gNumTestCerts; i++) |
| { |
| TestCert certType = gTestCerts[i]; |
| |
| err = GetTestCert(certType, sDerFormFlag, inCert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| err = GetTestCert(certType, sNullLoadFlag, expectedOutCert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| MutableByteSpan outCert(outCertBuf); |
| err = ConvertX509CertToChipCert(inCert, outCert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_TRUE(expectedOutCert.data_equal(outCert)); |
| } |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_X509ToChip_ErrorCases) |
| { |
| CHIP_ERROR err; |
| uint8_t outCertBuf[kMaxCHIPCertLength]; |
| |
| for (auto derCert : gTestCert_X509ToChip_ErrorCases) |
| { |
| MutableByteSpan outCert(outCertBuf); |
| |
| err = ConvertX509CertToChipCert(derCert, outCert); |
| EXPECT_NE(err, CHIP_NO_ERROR); |
| } |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_ChipDN) |
| { |
| const static char noc_rdn[] = "Test NOC"; |
| const static char noc_rdn2[] = "John"; |
| const static CATValues noc_cats = { { 0xABCD0001, chip::kUndefinedCAT, chip::kUndefinedCAT } }; |
| |
| ChipDN chip_dn; |
| CertType certType = CertType::kFirmwareSigning; // Start with non-default value |
| |
| EXPECT_TRUE(chip_dn.IsEmpty()); |
| EXPECT_EQ(chip_dn.RDNCount(), 0); |
| EXPECT_EQ(chip_dn.GetCertType(certType), CHIP_NO_ERROR); |
| EXPECT_TRUE(chip_dn.IsEmpty()); |
| EXPECT_EQ(certType, CertType::kNotSpecified); |
| |
| EXPECT_EQ(chip_dn.AddAttribute_CommonName(CharSpan(noc_rdn, strlen(noc_rdn)), false), CHIP_NO_ERROR); |
| EXPECT_EQ(chip_dn.AddAttribute_MatterNodeId(0xAAAABBBBCCCCDDDD), CHIP_NO_ERROR); |
| EXPECT_EQ(chip_dn.AddAttribute_MatterFabricId(0xFAB00000FAB00001), CHIP_NO_ERROR); |
| EXPECT_EQ(chip_dn.AddAttribute_GivenName(CharSpan(noc_rdn2, strlen(noc_rdn2)), true), CHIP_NO_ERROR); |
| EXPECT_EQ(chip_dn.AddCATs(noc_cats), CHIP_NO_ERROR); |
| EXPECT_EQ(chip_dn.RDNCount(), 5); |
| |
| EXPECT_EQ(chip_dn.AddAttribute_GivenName(CharSpan(noc_rdn2, strlen(noc_rdn2)), true), CHIP_ERROR_NO_MEMORY); |
| EXPECT_EQ(chip_dn.RDNCount(), 5); |
| |
| EXPECT_EQ(chip_dn.GetCertType(certType), CHIP_NO_ERROR); |
| EXPECT_EQ(certType, CertType::kNode); |
| |
| uint64_t certId; |
| EXPECT_EQ(chip_dn.GetCertChipId(certId), CHIP_NO_ERROR); |
| EXPECT_EQ(certId, 0xAAAABBBBCCCCDDDD); |
| |
| uint64_t fabricId; |
| EXPECT_EQ(chip_dn.GetCertFabricId(fabricId), CHIP_NO_ERROR); |
| EXPECT_EQ(fabricId, 0xFAB00000FAB00001); |
| |
| chip_dn.Clear(); |
| EXPECT_EQ(chip_dn.GetCertType(certType), CHIP_NO_ERROR); |
| EXPECT_TRUE(chip_dn.IsEmpty()); |
| EXPECT_EQ(certType, CertType::kNotSpecified); |
| |
| CATValues noc_cats2; |
| chip::CATValues::Serialized serializedCATs; |
| EXPECT_EQ(noc_cats.Serialize(serializedCATs), CHIP_NO_ERROR); |
| EXPECT_EQ(noc_cats2.Deserialize(serializedCATs), CHIP_NO_ERROR); |
| EXPECT_EQ(memcmp(&noc_cats, &noc_cats2, chip::CATValues::kSerializedLength), 0); |
| |
| CATValues noc_cats3 = { { 0xABCD0001, 0xFFEEAA00, 0x0001F012 } }; |
| EXPECT_EQ(noc_cats3.Serialize(serializedCATs), CHIP_NO_ERROR); |
| EXPECT_EQ(noc_cats2.Deserialize(serializedCATs), CHIP_NO_ERROR); |
| EXPECT_EQ(memcmp(&noc_cats3, &noc_cats2, chip::CATValues::kSerializedLength), 0); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_CertValidation) |
| { |
| CHIP_ERROR err; |
| ChipCertificateSet certSet; |
| ValidationContext validContext; |
| enum |
| { |
| kMaxCertsPerTestCase = 10 |
| }; |
| |
| struct ValidationTestCase |
| { |
| int mSubjectCertIndex; |
| uint8_t mValidateFlags; |
| CertType mRequiredCertType; |
| CHIP_ERROR mExpectedResult; |
| int mExpectedCertIndex; |
| int mExpectedTrustAnchorIndex; |
| struct |
| { |
| TestCert Type; |
| BitFlags<CertDecodeFlags> DecodeFlags; |
| BitFlags<TestCertLoadFlags> LoadFlags; |
| } InputCerts[kMaxCertsPerTestCase]; |
| }; |
| |
| // Short-hand names to make the test cases table more concise. |
| const auto CTNS = CertType::kNotSpecified; |
| const auto CTCA = CertType::kICA; |
| const auto CTNode = CertType::kNode; |
| |
| // clang-format off |
| static const ValidationTestCase sValidationTestCases[] = { |
| // Reqd Exp Exp Cert Cert |
| // Subj Valid Cert Cert TA Cert Decode Load |
| // Ind Flags Type Expected Result Index Index Type Flags Flags |
| // ================================================================================================================================== |
| |
| // Basic validation of node certificate with different load orders. |
| { 2, 0, CTNS, CHIP_NO_ERROR, 2, 0, { { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| { 1, 0, CTNS, CHIP_NO_ERROR, 1, 0, { { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| { 0, 0, CTNS, CHIP_NO_ERROR, 0, 2, { { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag } } }, |
| |
| // Basic validation of certificate, which is signed by Root. |
| { 0, 0, CTNS, CHIP_NO_ERROR, 0, 1, { { TestCert::kNode01_02, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag } } }, |
| { 0, 0, CTNS, CHIP_NO_ERROR, 0, 2, { { TestCert::kNode01_02, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag } } }, |
| { 0, 0, CTNS, CHIP_NO_ERROR, 0, 3, { { TestCert::kNode01_02, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kRoot02, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag } } }, |
| |
| // Basic validation of node certificates chaining up to another root. |
| { 2, 0, CTNS, CHIP_NO_ERROR, 2, 0, { { TestCert::kRoot02, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kICA02, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kNode02_01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| { 1, 0, CTNS, CHIP_NO_ERROR, 1, 0, { { TestCert::kRoot02, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kNode02_01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA02, sGenTBSHashFlag, sNullLoadFlag } } }, |
| { 0, 0, CTNS, CHIP_NO_ERROR, 0, 2, { { TestCert::kNode02_01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA02, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kRoot02, sTrustAnchorFlag, sNullLoadFlag } } }, |
| { 0, 0, CTNS, CHIP_NO_ERROR, 0, 2, { { TestCert::kNode02_02, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA02, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kRoot02, sTrustAnchorFlag, sNullLoadFlag } } }, |
| { 0, 0, CTNS, CHIP_NO_ERROR, 0, 2, { { TestCert::kNode02_03, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA02, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kRoot02, sTrustAnchorFlag, sNullLoadFlag } } }, |
| { 0, 0, CTNS, CHIP_NO_ERROR, 0, 2, { { TestCert::kNode02_04, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA02, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kRoot02, sTrustAnchorFlag, sNullLoadFlag } } }, |
| { 0, 0, CTNS, CHIP_NO_ERROR, 0, 2, { { TestCert::kNode02_05, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA02, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kRoot02, sTrustAnchorFlag, sNullLoadFlag } } }, |
| { 0, 0, CTNS, CHIP_NO_ERROR, 0, 2, { { TestCert::kNode02_06, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA02, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kRoot02, sTrustAnchorFlag, sNullLoadFlag } } }, |
| |
| // Failure due to presence of "critical" future-extension in the kNode02_07 node certificate. |
| { 0, 0, CTNS, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED, 0, 2, { { TestCert::kNode02_07, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA02, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kRoot02, sTrustAnchorFlag, sNullLoadFlag } } }, |
| |
| // Validation with two copies of root certificate, one trusted, one untrusted. |
| { 2, 0, CTNS, CHIP_NO_ERROR, 2, 1, { { TestCert::kRoot01, sNullDecodeFlag, sNullLoadFlag }, |
| { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| |
| // Validation with two trusted certificates. |
| { 2, 0, CTNS, CHIP_NO_ERROR, 2, 1, { { TestCert::kRoot02, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| |
| // Failure due to missing CA certificate. |
| { 1, 0, CTNS, CHIP_ERROR_CA_CERT_NOT_FOUND, -1, -1, { { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| { 2, 0, CTNS, CHIP_ERROR_CA_CERT_NOT_FOUND, -1, -1, { { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kICA02, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| |
| // Failure due to missing root certificate. |
| { 1, 0, CTNS, CHIP_ERROR_CA_CERT_NOT_FOUND, -1, -1, { { TestCert::kICA01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| { 1, 0, CTNS, CHIP_ERROR_CA_CERT_NOT_FOUND, -1, -1, { { TestCert::kRoot02, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| |
| // Failure due to lack of TBS hash. |
| { 1, 0, CTNS, CHIP_ERROR_INVALID_ARGUMENT, -1, -1, { { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kNode01_01, sNullDecodeFlag, sNullLoadFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| |
| // Failure due to untrusted root. |
| { 1, 0, CTNS, CHIP_ERROR_CA_CERT_NOT_FOUND, -1, -1, { { TestCert::kRoot01, sNullDecodeFlag, sNullLoadFlag }, |
| { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| |
| // Failure due to intermediate cert with isCA flag = false |
| { 2, 0, CTNS, CHIP_ERROR_CA_CERT_NOT_FOUND, -1, -1, { { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sSupIsCAFlag }, |
| { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| |
| // Failure due to CA cert with no key usage. |
| { 2, 0, CTNS, CHIP_ERROR_CA_CERT_NOT_FOUND, -1, -1, { { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sSupKeyUsageFlag }, |
| { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| |
| // Failure due to CA cert with no cert sign key usage. |
| { 2, 0, CTNS, CHIP_ERROR_CA_CERT_NOT_FOUND, -1, -1, { { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sSupKeyCertSignFlag }, |
| { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| |
| // Failure due to 3-level deep cert chain and root cert with path constraint == 0 |
| { 2, 0, CTNS, CHIP_ERROR_CA_CERT_NOT_FOUND, -1, -1, { { TestCert::kRoot01, sTrustAnchorFlag, sPathLenZeroFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| |
| // Require a specific certificate type. |
| { 2, 0, CTNode, CHIP_NO_ERROR, 2, 0, { { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| |
| // Failure due to required certificate type not found. |
| { 2, 0, CTCA, CHIP_ERROR_WRONG_CERT_TYPE, -1, -1, { { TestCert::kRoot01, sTrustAnchorFlag, sNullLoadFlag }, |
| { TestCert::kICA01, sGenTBSHashFlag, sNullLoadFlag }, |
| { TestCert::kNode01_01, sGenTBSHashFlag, sNullLoadFlag } } }, |
| }; |
| // clang-format on |
| |
| for (const auto & testCase : sValidationTestCases) |
| { |
| const ChipCertificateData * resultCert = nullptr; |
| err = certSet.Init(kMaxCertsPerTestCase); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| for (auto inputCert : testCase.InputCerts) |
| { |
| if (inputCert.Type != TestCert::kNone) |
| { |
| err = LoadTestCert(certSet, inputCert.Type, inputCert.LoadFlags, inputCert.DecodeFlags); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| } |
| } |
| // Make sure the test case is valid. |
| EXPECT_TRUE(testCase.mSubjectCertIndex >= 0 && testCase.mSubjectCertIndex < certSet.GetCertCount()); |
| if (testCase.mExpectedResult == CHIP_NO_ERROR) |
| { |
| EXPECT_TRUE(testCase.mExpectedCertIndex >= 0 && testCase.mExpectedCertIndex < certSet.GetCertCount()); |
| EXPECT_TRUE(testCase.mExpectedTrustAnchorIndex >= 0 && testCase.mExpectedTrustAnchorIndex < certSet.GetCertCount()); |
| } |
| |
| // Initialize the validation context. |
| validContext.Reset(); |
| err = SetCurrentTime(validContext, 2021, 1, 1); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| validContext.mRequiredKeyUsages.Set(KeyUsageFlags::kDigitalSignature); |
| validContext.mRequiredKeyPurposes.Set(KeyPurposeFlags::kServerAuth); |
| validContext.mRequiredKeyPurposes.Set(KeyPurposeFlags::kClientAuth); |
| validContext.mRequiredCertType = testCase.mRequiredCertType; |
| |
| // Locate the subject DN and key id that will be used as input the FindValidCert() method. |
| const ChipDN & subjectDN = certSet.GetCertSet()[testCase.mSubjectCertIndex].mSubjectDN; |
| const CertificateKeyId & subjectKeyId = certSet.GetCertSet()[testCase.mSubjectCertIndex].mSubjectKeyId; |
| |
| // Invoke the FindValidCert() method (the method being tested). |
| err = certSet.FindValidCert(subjectDN, subjectKeyId, validContext, &resultCert); |
| EXPECT_EQ(err, testCase.mExpectedResult); |
| |
| // If the test case is expected to be successful... |
| if (err == CHIP_NO_ERROR) |
| { |
| // Verify that the method found the correct certificate. |
| EXPECT_EQ(resultCert, &certSet.GetCertSet()[testCase.mExpectedCertIndex]); |
| |
| // Verify that the method selected the correct trust anchor. |
| EXPECT_EQ(validContext.mTrustAnchor, &certSet.GetCertSet()[testCase.mExpectedTrustAnchorIndex]); |
| } |
| |
| // Clear the certificate set. |
| certSet.Release(); |
| } |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_CertValidTime) |
| { |
| CHIP_ERROR err; |
| ChipCertificateSet certSet; |
| ValidationContext validContext; |
| |
| err = certSet.Init(kStandardCertsCount); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| err = LoadTestCertSet01(certSet); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| validContext.Reset(); |
| validContext.mRequiredKeyUsages.Set(KeyUsageFlags::kDigitalSignature); |
| validContext.mRequiredKeyPurposes.Set(KeyPurposeFlags::kServerAuth); |
| validContext.mRequiredKeyPurposes.Set(KeyPurposeFlags::kClientAuth); |
| |
| Credentials::StrictCertificateValidityPolicyExample strictCertificateValidityPolicy; |
| Credentials::LastKnownGoodTimeCertificateValidityPolicyExample lastKnownGoodTimeValidityPolicy; |
| |
| // No time source available. |
| ClearTimeSource(validContext); |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictCertificateValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimeValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Current time before certificate validity period. |
| err = SetCurrentTime(validContext, 2020, 1, 3); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_NOT_VALID_YET); |
| // Strict policy |
| validContext.mValidityPolicy = &strictCertificateValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_NOT_VALID_YET); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimeValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_NOT_VALID_YET); |
| |
| // Current time 1 second before validity period. |
| err = SetCurrentTime(validContext, 2020, 10, 15, 14, 23, 42); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_NOT_VALID_YET); |
| // Strict policy |
| validContext.mValidityPolicy = &strictCertificateValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_NOT_VALID_YET); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimeValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_NOT_VALID_YET); |
| |
| // Current time 1st second of validity period. |
| err = SetCurrentTime(validContext, 2020, 10, 15, 14, 23, 43); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictCertificateValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimeValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Current time within validity period. |
| err = SetCurrentTime(validContext, 2022, 02, 23, 12, 30, 01); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictCertificateValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimeValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Current time at last second of validity period. |
| err = SetCurrentTime(validContext, 2040, 10, 15, 14, 23, 42); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictCertificateValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimeValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Current time at 1 second after end of certificate validity period. |
| err = SetCurrentTime(validContext, 2040, 10, 15, 14, 23, 43); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| // Strict policy |
| validContext.mValidityPolicy = &strictCertificateValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimeValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| |
| // Current time after end of certificate validity period. |
| err = SetCurrentTime(validContext, 2042, 4, 25, 0, 0, 0); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| // Strict policy |
| validContext.mValidityPolicy = &strictCertificateValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimeValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| |
| // Last known good time before certificate validity period. |
| // We can't invalidate based on NotBefore with Last Known Good Time. |
| // Hence, we expect CHIP_NO_ERROR. |
| err = SetLastKnownGoodTime(validContext, 2020, 1, 3); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictCertificateValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimeValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Last known good time 1 second before certificate validity period. |
| // We can't invalidate based on NotBefore with Last Known Good Time. |
| // Hence, we expect CHIP_NO_ERROR. |
| err = SetLastKnownGoodTime(validContext, 2020, 10, 15, 14, 23, 42); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictCertificateValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimeValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Last Known Good Time 1st second of validity period. |
| err = SetLastKnownGoodTime(validContext, 2020, 10, 15, 14, 23, 43); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictCertificateValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimeValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Last Known Good Time within validity period. |
| err = SetLastKnownGoodTime(validContext, 2022, 02, 23, 12, 30, 01); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictCertificateValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimeValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Last Known Good Time at last second of validity period. |
| err = SetLastKnownGoodTime(validContext, 2040, 10, 15, 14, 23, 42); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictCertificateValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimeValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Last Known Good Time at 1 second after end of certificate validity period. |
| err = SetLastKnownGoodTime(validContext, 2040, 10, 15, 14, 23, 43); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictCertificateValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimeValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| |
| // Last Known Good Time after end of certificate validity period. |
| err = SetLastKnownGoodTime(validContext, 2042, 4, 25, 0, 0, 0); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictCertificateValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimeValidityPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| |
| certSet.Release(); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_ValidateChipRCAC) |
| { |
| struct RCACTestCase |
| { |
| TestCert Cert; |
| CHIP_ERROR mExpectedResult; |
| }; |
| |
| // clang-format off |
| static RCACTestCase sRCACTestCases[] = { |
| // Cert Expected Result |
| // ==================================================== |
| { TestCert::kRoot01, CHIP_NO_ERROR }, |
| { TestCert::kRoot02, CHIP_NO_ERROR }, |
| { TestCert::kICA01, CHIP_ERROR_WRONG_CERT_TYPE }, |
| { TestCert::kICA02, CHIP_ERROR_WRONG_CERT_TYPE }, |
| { TestCert::kICA01_1, CHIP_ERROR_WRONG_CERT_TYPE }, |
| { TestCert::kFWSign01, CHIP_ERROR_WRONG_CERT_TYPE }, |
| { TestCert::kNode01_01, CHIP_ERROR_WRONG_CERT_TYPE }, |
| { TestCert::kNode02_08, CHIP_ERROR_WRONG_CERT_TYPE }, |
| }; |
| // clang-format on |
| |
| for (auto & testCase : sRCACTestCases) |
| { |
| ByteSpan cert; |
| EXPECT_EQ(GetTestCert(testCase.Cert, sNullLoadFlag, cert), CHIP_NO_ERROR); |
| EXPECT_EQ(ValidateChipRCAC(cert), testCase.mExpectedResult); |
| } |
| } |
| |
| class AlwaysAcceptValidityPolicy : public CertificateValidityPolicy |
| { |
| public: |
| ~AlwaysAcceptValidityPolicy() {} |
| |
| CHIP_ERROR ApplyCertificateValidityPolicy(const ChipCertificateData * cert, uint8_t depth, |
| CertificateValidityResult result) override |
| { |
| return CHIP_NO_ERROR; |
| } |
| }; |
| |
| class AlwaysRejectValidityPolicy : public CertificateValidityPolicy |
| { |
| public: |
| ~AlwaysRejectValidityPolicy() {} |
| |
| CHIP_ERROR ApplyCertificateValidityPolicy(const ChipCertificateData * cert, uint8_t depth, |
| CertificateValidityResult result) override |
| { |
| return CHIP_ERROR_CERT_EXPIRED; |
| } |
| }; |
| |
| TEST_F(TestChipCert, TestChipCert_CertValidityPolicyInjection) |
| { |
| CHIP_ERROR err; |
| ChipCertificateSet certSet; |
| ValidationContext validContext; |
| StrictCertificateValidityPolicyExample strictPolicy; |
| LastKnownGoodTimeCertificateValidityPolicyExample lastKnownGoodTimePolicy; |
| AlwaysAcceptValidityPolicy alwaysAcceptPolicy; |
| AlwaysRejectValidityPolicy alwaysRejectPolicy; |
| |
| err = certSet.Init(kStandardCertsCount); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| err = LoadTestCertSet01(certSet); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| validContext.Reset(); |
| validContext.mRequiredKeyUsages.Set(KeyUsageFlags::kDigitalSignature); |
| validContext.mRequiredKeyPurposes.Set(KeyPurposeFlags::kServerAuth); |
| validContext.mRequiredKeyPurposes.Set(KeyPurposeFlags::kClientAuth); |
| |
| // Current time unknown. |
| |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimePolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Always accept policy |
| validContext.mValidityPolicy = &alwaysAcceptPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Always reject policy |
| validContext.mValidityPolicy = &alwaysRejectPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_NE(err, CHIP_NO_ERROR); |
| |
| // Curent time before certificate validity period. |
| err = SetCurrentTime(validContext, 2020, 1, 3); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_NOT_VALID_YET); |
| // Strict policy |
| validContext.mValidityPolicy = &strictPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_NOT_VALID_YET); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimePolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_NOT_VALID_YET); |
| // Always accept policy |
| validContext.mValidityPolicy = &alwaysAcceptPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Always reject policy |
| validContext.mValidityPolicy = &alwaysRejectPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_NE(err, CHIP_NO_ERROR); |
| |
| // Last known good time before certificate validity period. |
| err = SetLastKnownGoodTime(validContext, 2020, 1, 3); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Always accept policy |
| validContext.mValidityPolicy = &alwaysAcceptPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Always reject policy |
| validContext.mValidityPolicy = &alwaysRejectPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_NE(err, CHIP_NO_ERROR); |
| |
| // Current time during validity period |
| err = SetCurrentTime(validContext, 2022, 02, 23, 12, 30, 01); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Always accept policy |
| validContext.mValidityPolicy = &alwaysAcceptPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Always reject policy |
| validContext.mValidityPolicy = &alwaysRejectPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_NE(err, CHIP_NO_ERROR); |
| |
| // Last Known Good Time during validity period |
| err = SetLastKnownGoodTime(validContext, 2022, 02, 23, 12, 30, 01); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimePolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Always accept policy |
| validContext.mValidityPolicy = &alwaysAcceptPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Always reject policy |
| validContext.mValidityPolicy = &alwaysRejectPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_NE(err, CHIP_NO_ERROR); |
| |
| // Current time after end of certificate validity period. |
| err = SetCurrentTime(validContext, 2042, 4, 25, 0, 0, 0); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| // Strict policy |
| validContext.mValidityPolicy = &strictPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimePolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| // Always accept policy |
| validContext.mValidityPolicy = &alwaysAcceptPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Always reject policy |
| validContext.mValidityPolicy = &alwaysRejectPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_NE(err, CHIP_NO_ERROR); |
| |
| // Last Known Good Time after end of certificate validity period. |
| err = SetLastKnownGoodTime(validContext, 2042, 4, 25, 0, 0, 0); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Default policy |
| validContext.mValidityPolicy = nullptr; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Strict policy |
| validContext.mValidityPolicy = &strictPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| // Last Known Good Time policy |
| validContext.mValidityPolicy = &lastKnownGoodTimePolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_ERROR_CERT_EXPIRED); |
| // Always accept policy |
| validContext.mValidityPolicy = &alwaysAcceptPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| // Always reject policy |
| validContext.mValidityPolicy = &alwaysRejectPolicy; |
| err = certSet.ValidateCert(certSet.GetLastCert(), validContext); |
| EXPECT_NE(err, CHIP_NO_ERROR); |
| |
| certSet.Release(); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_CertUsage) |
| { |
| CHIP_ERROR err; |
| ChipCertificateSet certSet; |
| ValidationContext validContext; |
| ChipCertificateData certDataArray[kStandardCertsCount]; |
| |
| struct UsageTestCase |
| { |
| uint8_t mCertIndex; |
| BitFlags<KeyUsageFlags> mRequiredKeyUsages; |
| BitFlags<KeyPurposeFlags> mRequiredKeyPurposes; |
| CHIP_ERROR mExpectedResult; |
| }; |
| |
| // clang-format off |
| static UsageTestCase sUsageTestCases[] = { |
| // Cert Key |
| // Ind Usages Key Purposes Expected Result |
| // ========================================================================= |
| |
| // ----- Key Usages for leaf Certificate ----- |
| { 2, sDS, sNullKPFlag, CHIP_NO_ERROR }, |
| { 2, sNR, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sKE, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sDE, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sKA, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sKC, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sCR, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sEO, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sDO, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sDSandNR, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sDSandKE, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sDSandDE, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sDSandKA, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sDSandKC, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sDSandCR, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sDSandEO, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sDSandDO, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| |
| // ----- Key Usages for CA Certificate ----- |
| { 1, sDS, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sNR, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sKE, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sDE, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sKA, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sKC, sNullKPFlag, CHIP_NO_ERROR }, |
| { 1, sCR, sNullKPFlag, CHIP_NO_ERROR }, |
| { 1, sEO, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sDO, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sKCandDS, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sKCandNR, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sKCandKE, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sKCandDE, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sKCandKA, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sKCandCR, sNullKPFlag, CHIP_NO_ERROR }, |
| { 1, sKCandEO, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sKCandDO, sNullKPFlag, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| |
| // ----- Key Purposes for leaf Certificate ----- |
| { 2, sNullKUFlag, sSA, CHIP_NO_ERROR }, |
| { 2, sNullKUFlag, sCA, CHIP_NO_ERROR }, |
| { 2, sNullKUFlag, sCS, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sNullKUFlag, sEP, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sNullKUFlag, sTS, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sNullKUFlag, sSAandCA, CHIP_NO_ERROR }, |
| { 2, sNullKUFlag, sSAandCS, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sNullKUFlag, sSAandEP, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sNullKUFlag, sSAandTS, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| |
| // ----- Key Purposes for CA Certificate ----- |
| { 1, sNullKUFlag, sSA, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sNullKUFlag, sCA, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sNullKUFlag, sCS, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sNullKUFlag, sEP, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sNullKUFlag, sTS, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sNullKUFlag, sSAandCA, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sNullKUFlag, sSAandCS, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sNullKUFlag, sSAandEP, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 1, sNullKUFlag, sSAandTS, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| |
| // ----- Combinations ----- |
| { 2, sDSandNR, sSAandCA, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sDS, sSAandCS, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sDSandKE, sSAandCA, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED }, |
| { 2, sDS, sSAandCA, CHIP_NO_ERROR }, |
| }; |
| // clang-format on |
| size_t sNumUsageTestCases = ArraySize(sUsageTestCases); |
| |
| err = certSet.Init(certDataArray, ArraySize(certDataArray)); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| err = LoadTestCertSet01(certSet); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| for (size_t i = 0; i < sNumUsageTestCases; i++) |
| { |
| validContext.Reset(); |
| validContext.mRequiredKeyUsages = sUsageTestCases[i].mRequiredKeyUsages; |
| validContext.mRequiredKeyPurposes = sUsageTestCases[i].mRequiredKeyPurposes; |
| |
| err = SetCurrentTime(validContext, 2020, 10, 16); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| err = certSet.ValidateCert(&certSet.GetCertSet()[sUsageTestCases[i].mCertIndex], validContext); |
| EXPECT_EQ(err, sUsageTestCases[i].mExpectedResult); |
| } |
| |
| certSet.Release(); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_CertType) |
| { |
| CHIP_ERROR err; |
| ChipCertificateData certData; |
| |
| struct TestCase |
| { |
| TestCert Cert; |
| CertType ExpectedCertType; |
| }; |
| |
| // clang-format off |
| static TestCase sTestCases[] = { |
| // Cert ExpectedCertType |
| // ============================================================= |
| { TestCert::kRoot01, CertType::kRoot }, |
| { TestCert::kRoot02, CertType::kRoot }, |
| { TestCert::kICA01, CertType::kICA }, |
| { TestCert::kICA02, CertType::kICA }, |
| { TestCert::kICA01_1, CertType::kICA }, |
| { TestCert::kFWSign01, CertType::kFirmwareSigning }, |
| { TestCert::kNode01_01, CertType::kNode }, |
| { 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 = DecodeTestCert(certData, testCase.Cert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| err = certData.mSubjectDN.GetCertType(certType); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| EXPECT_EQ(certType, testCase.ExpectedCertType); |
| } |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_CertId) |
| { |
| CHIP_ERROR err; |
| ChipCertificateData certData; |
| |
| struct TestCase |
| { |
| TestCert Cert; |
| uint64_t ExpectedCertId; |
| }; |
| |
| // clang-format off |
| static TestCase sTestCases[] = { |
| // Cert ExpectedCertId |
| // ============================================================= |
| { TestCert::kRoot01, 0xCACACACA00000001 }, |
| { TestCert::kRoot02, 0xCACACACA00000002 }, |
| { TestCert::kICA01, 0xCACACACA00000003 }, |
| { TestCert::kICA02, 0xCACACACA00000004 }, |
| { TestCert::kICA01_1, 0xCACACACA00000005 }, |
| { TestCert::kFWSign01, 0xFFFFFFFF00000001 }, |
| { TestCert::kNode01_01, 0xDEDEDEDE00010001 }, |
| { 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 = DecodeTestCert(certData, testCase.Cert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| err = certData.mSubjectDN.GetCertChipId(chipId); |
| if (testCase.ExpectedCertId != 0) |
| { |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_EQ(chipId, testCase.ExpectedCertId); |
| } |
| else |
| { |
| EXPECT_EQ(err, CHIP_ERROR_WRONG_CERT_DN); |
| } |
| } |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_DecodingOptions) |
| { |
| CHIP_ERROR err; |
| ByteSpan cert; |
| ChipCertificateData certData; |
| |
| err = GetTestCert(TestCert::kRoot01, sNullLoadFlag, cert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Decode with default (null) options |
| err = DecodeChipCert(cert, certData); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_FALSE(certData.mCertFlags.Has(CertFlags::kIsTrustAnchor)); |
| |
| // Decode as trust anchor |
| err = DecodeChipCert(cert, certData, CertDecodeFlags::kIsTrustAnchor); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_TRUE(certData.mCertFlags.Has(CertFlags::kIsTrustAnchor)); |
| |
| // Decode with TBS Hash calculation |
| err = DecodeChipCert(cert, certData, CertDecodeFlags::kGenerateTBSHash); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_TRUE(certData.mCertFlags.Has(CertFlags::kTBSHashPresent)); |
| // When the TBS hash is available signature verification should work |
| err = VerifyCertSignature(certData, certData); // test cert is a self-signed root |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_LoadDuplicateCerts) |
| { |
| CHIP_ERROR err; |
| ChipCertificateSet certSet; |
| ValidationContext validContext; |
| |
| err = certSet.Init(kStandardCertsCount); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Let's load two distinct certificates, and make sure cert count is 2 |
| err = LoadTestCert(certSet, TestCert::kRoot01, sNullLoadFlag, sTrustAnchorFlag); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| err = LoadTestCert(certSet, TestCert::kICA01, sNullLoadFlag, sGenTBSHashFlag); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_EQ(certSet.GetCertCount(), 2); |
| |
| // Let's load a previously loaded cert and make sure cert count is still 2 |
| err = LoadTestCert(certSet, TestCert::kRoot01, sNullLoadFlag, sTrustAnchorFlag); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_EQ(certSet.GetCertCount(), 2); |
| |
| // Let's load the other previously loaded cert and make sure cert count is still 2 |
| err = LoadTestCert(certSet, TestCert::kICA01, sNullLoadFlag, sGenTBSHashFlag); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_EQ(certSet.GetCertCount(), 2); |
| |
| // Let's load a new cert and make sure cert count updates to 3 |
| err = LoadTestCert(certSet, TestCert::kNode01_01, sNullLoadFlag, sGenTBSHashFlag); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_EQ(certSet.GetCertCount(), 3); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_GenerateRootCert) |
| { |
| // Generate a new keypair for cert signing |
| P256Keypair keypair; |
| EXPECT_EQ(keypair.Initialize(ECPKeyTarget::ECDSA), CHIP_NO_ERROR); |
| |
| uint8_t signed_cert[kMaxDERCertLength]; |
| |
| ChipCertificateData certData; |
| |
| ChipDN root_dn; |
| EXPECT_EQ(root_dn.AddAttribute_MatterRCACId(0xabcdabcd), CHIP_NO_ERROR); |
| |
| X509CertRequestParams root_params = { 1234, 631161876, 729942000, root_dn, root_dn }; |
| MutableByteSpan signed_cert_span(signed_cert); |
| EXPECT_EQ(NewRootX509Cert(root_params, keypair, signed_cert_span), CHIP_NO_ERROR); |
| |
| uint8_t outCertBuf[kMaxCHIPCertLength]; |
| MutableByteSpan outCert(outCertBuf); |
| |
| EXPECT_EQ(ConvertX509CertToChipCert(signed_cert_span, outCert), CHIP_NO_ERROR); |
| |
| EXPECT_EQ(DecodeChipCert(outCert, certData), CHIP_NO_ERROR); |
| |
| // Test with FutureExtension |
| X509CertRequestParams root_params2 = { 1234, 631161876, 729942000, root_dn, root_dn, kSubjectAltNameAsFutureExt }; |
| MutableByteSpan signed_cert_span2(signed_cert); |
| EXPECT_EQ(NewRootX509Cert(root_params2, keypair, signed_cert_span2), CHIP_NO_ERROR); |
| outCert = MutableByteSpan(outCertBuf); |
| |
| EXPECT_EQ(ConvertX509CertToChipCert(signed_cert_span2, outCert), CHIP_NO_ERROR); |
| EXPECT_EQ(DecodeChipCert(outCert, certData), CHIP_NO_ERROR); |
| |
| // Test with no defined notAfter time. |
| { |
| X509CertRequestParams root_params3 = { .SerialNumber = 1234, |
| .ValidityStart = 631161876, |
| .ValidityEnd = kNullCertTime, |
| .SubjectDN = root_dn, |
| .IssuerDN = root_dn }; |
| MutableByteSpan signed_cert_span_no_expiry(signed_cert); |
| |
| EXPECT_EQ(NewRootX509Cert(root_params3, keypair, signed_cert_span_no_expiry), CHIP_NO_ERROR); |
| outCert = MutableByteSpan(outCertBuf); |
| |
| EXPECT_EQ(ConvertX509CertToChipCert(signed_cert_span_no_expiry, outCert), CHIP_NO_ERROR); |
| EXPECT_EQ(DecodeChipCert(outCert, certData), CHIP_NO_ERROR); |
| EXPECT_EQ(certData.mNotAfterTime, kNullCertTime); |
| } |
| |
| // Test error case: root cert subject provided ICA OID Attribute. |
| root_params.SubjectDN.Clear(); |
| EXPECT_EQ(root_params.SubjectDN.AddAttribute_MatterICACId(0xabcdabcd), CHIP_NO_ERROR); |
| root_params.IssuerDN.Clear(); |
| EXPECT_EQ(root_params.IssuerDN.AddAttribute_MatterICACId(0xabcdabcd), CHIP_NO_ERROR); |
| MutableByteSpan signed_cert_span1(signed_cert); |
| EXPECT_EQ(NewRootX509Cert(root_params, keypair, signed_cert_span1), CHIP_ERROR_INVALID_ARGUMENT); |
| |
| // Test error case: root cert provided different subject and issuer DNs. |
| root_params.SubjectDN.Clear(); |
| EXPECT_EQ(root_params.SubjectDN.AddAttribute_MatterRCACId(0xabcdabcd), CHIP_NO_ERROR); |
| root_params.IssuerDN.Clear(); |
| EXPECT_EQ(root_params.IssuerDN.AddAttribute_MatterRCACId(0xffffeeee), CHIP_NO_ERROR); |
| EXPECT_EQ(NewRootX509Cert(root_params, keypair, signed_cert_span1), CHIP_ERROR_INVALID_ARGUMENT); |
| |
| // Test that serial number cannot be negative |
| root_params.IssuerDN.Clear(); |
| EXPECT_EQ(root_params.IssuerDN.AddAttribute_MatterRCACId(0xabcdabcd), CHIP_NO_ERROR); |
| root_params.SerialNumber = -1; |
| EXPECT_EQ(NewRootX509Cert(root_params, keypair, signed_cert_span1), CHIP_ERROR_INVALID_ARGUMENT); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_GenerateRootFabCert) |
| { |
| // Generate a new keypair for cert signing |
| P256Keypair keypair; |
| EXPECT_EQ(keypair.Initialize(ECPKeyTarget::ECDSA), CHIP_NO_ERROR); |
| |
| uint8_t signed_cert[kMaxDERCertLength]; |
| |
| ChipCertificateData certData; |
| |
| uint8_t outCertBuf[kMaxCHIPCertLength]; |
| MutableByteSpan outCert(outCertBuf); |
| |
| ChipDN root_dn; |
| EXPECT_EQ(root_dn.AddAttribute_MatterRCACId(0xabcdabcd), CHIP_NO_ERROR); |
| EXPECT_EQ(root_dn.AddAttribute_MatterFabricId(0xabcd), CHIP_NO_ERROR); |
| |
| X509CertRequestParams root_params_fabric = { 1234, 631161876, 729942000, root_dn, root_dn }; |
| |
| MutableByteSpan signed_cert_span(signed_cert); |
| EXPECT_EQ(NewRootX509Cert(root_params_fabric, keypair, signed_cert_span), CHIP_NO_ERROR); |
| |
| EXPECT_EQ(ConvertX509CertToChipCert(signed_cert_span, outCert), CHIP_NO_ERROR); |
| |
| EXPECT_EQ(DecodeChipCert(outCert, certData), CHIP_NO_ERROR); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_GenerateICACert) |
| { |
| // Generate a new keypair for cert signing |
| P256Keypair keypair; |
| EXPECT_EQ(keypair.Initialize(ECPKeyTarget::ECDSA), CHIP_NO_ERROR); |
| |
| uint8_t signed_cert[kMaxDERCertLength]; |
| |
| uint8_t outCertBuf[kMaxCHIPCertLength]; |
| MutableByteSpan outCert(outCertBuf); |
| |
| ChipCertificateData certData; |
| |
| ChipDN ica_dn; |
| EXPECT_EQ(ica_dn.AddAttribute_MatterICACId(0xABCDABCDABCDABCD), CHIP_NO_ERROR); |
| ChipDN issuer_dn; |
| EXPECT_EQ(issuer_dn.AddAttribute_MatterRCACId(0x43215678FEDCABCD), CHIP_NO_ERROR); |
| |
| X509CertRequestParams ica_params = { 1234, 631161876, 729942000, ica_dn, issuer_dn }; |
| P256Keypair ica_keypair; |
| EXPECT_EQ(ica_keypair.Initialize(ECPKeyTarget::ECDSA), CHIP_NO_ERROR); |
| |
| MutableByteSpan signed_cert_span(signed_cert); |
| EXPECT_EQ(NewICAX509Cert(ica_params, ica_keypair.Pubkey(), keypair, signed_cert_span), CHIP_NO_ERROR); |
| |
| EXPECT_EQ(ConvertX509CertToChipCert(signed_cert_span, outCert), CHIP_NO_ERROR); |
| |
| EXPECT_EQ(DecodeChipCert(outCert, certData), CHIP_NO_ERROR); |
| |
| // Test with FutureExtension |
| X509CertRequestParams ica_params2 = { 1234, 631161876, 729942000, ica_dn, issuer_dn, kSubjectAltNameAsFutureExt }; |
| MutableByteSpan signed_cert_span2(signed_cert); |
| EXPECT_EQ(NewICAX509Cert(ica_params2, ica_keypair.Pubkey(), keypair, signed_cert_span2), CHIP_NO_ERROR); |
| outCert = MutableByteSpan(outCertBuf); |
| |
| EXPECT_EQ(ConvertX509CertToChipCert(signed_cert_span2, outCert), CHIP_NO_ERROR); |
| EXPECT_EQ(DecodeChipCert(outCert, certData), CHIP_NO_ERROR); |
| |
| // Test error case: ICA cert subject provided a node ID attribute |
| ica_params.SubjectDN.Clear(); |
| EXPECT_EQ(ica_params.SubjectDN.AddAttribute_MatterNodeId(0xABCDABCDABCDABCD), CHIP_NO_ERROR); |
| EXPECT_EQ(ica_params.SubjectDN.AddAttribute_MatterFabricId(0xFAB00000FAB00001), CHIP_NO_ERROR); |
| MutableByteSpan signed_cert_span1(signed_cert); |
| EXPECT_EQ(NewICAX509Cert(ica_params, ica_keypair.Pubkey(), keypair, signed_cert_span1), CHIP_ERROR_INVALID_ARGUMENT); |
| |
| // Test that serial number cannot be negative |
| ica_params.SubjectDN.Clear(); |
| EXPECT_EQ(ica_params.SubjectDN.AddAttribute_MatterICACId(0xABCDABCDABCDABCD), CHIP_NO_ERROR); |
| ica_params.SerialNumber = -1; |
| EXPECT_EQ(NewICAX509Cert(ica_params, ica_keypair.Pubkey(), keypair, signed_cert_span1), CHIP_ERROR_INVALID_ARGUMENT); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_GenerateNOCRoot) |
| { |
| // Generate a new keypair for cert signing |
| P256Keypair keypair; |
| EXPECT_EQ(keypair.Initialize(ECPKeyTarget::ECDSA), CHIP_NO_ERROR); |
| |
| uint8_t signed_cert[kMaxDERCertLength]; |
| |
| uint8_t outCertBuf[kMaxCHIPCertLength]; |
| MutableByteSpan outCert(outCertBuf); |
| |
| ChipCertificateData certData; |
| |
| ChipDN noc_dn; |
| EXPECT_EQ(noc_dn.AddAttribute_MatterNodeId(0xABCDABCDABCDABCD), CHIP_NO_ERROR); |
| EXPECT_EQ(noc_dn.AddAttribute_MatterFabricId(0xFAB00000FAB00001), CHIP_NO_ERROR); |
| ChipDN issuer_dn; |
| EXPECT_EQ(issuer_dn.AddAttribute_MatterRCACId(0x8888999944442222), CHIP_NO_ERROR); |
| |
| X509CertRequestParams noc_params = { 123456, 631161876, 729942000, noc_dn, issuer_dn }; |
| P256Keypair noc_keypair; |
| EXPECT_EQ(noc_keypair.Initialize(ECPKeyTarget::ECDSA), CHIP_NO_ERROR); |
| |
| MutableByteSpan signed_cert_span(signed_cert, sizeof(signed_cert)); |
| EXPECT_EQ(NewNodeOperationalX509Cert(noc_params, noc_keypair.Pubkey(), keypair, signed_cert_span), CHIP_NO_ERROR); |
| |
| EXPECT_EQ(ConvertX509CertToChipCert(signed_cert_span, outCert), CHIP_NO_ERROR); |
| |
| EXPECT_EQ(DecodeChipCert(outCert, certData), CHIP_NO_ERROR); |
| |
| // Test with FutureExtension |
| X509CertRequestParams noc_params2 = { 123456, 631161876, 729942000, noc_dn, issuer_dn, kSubjectAltNameAsFutureExt }; |
| MutableByteSpan signed_cert_span2(signed_cert); |
| EXPECT_EQ(NewNodeOperationalX509Cert(noc_params2, noc_keypair.Pubkey(), keypair, signed_cert_span2), CHIP_NO_ERROR); |
| outCert = MutableByteSpan(outCertBuf); |
| |
| EXPECT_EQ(ConvertX509CertToChipCert(signed_cert_span2, outCert), CHIP_NO_ERROR); |
| EXPECT_EQ(DecodeChipCert(outCert, certData), CHIP_NO_ERROR); |
| |
| // Test error case: NOC cert subject doesn't have NodeId attribute |
| noc_params.SubjectDN.Clear(); |
| EXPECT_EQ(noc_params.SubjectDN.AddAttribute_MatterFabricId(0xFAB00000FAB00001), CHIP_NO_ERROR); |
| |
| MutableByteSpan signed_cert_span1(signed_cert, sizeof(signed_cert)); |
| EXPECT_EQ(NewNodeOperationalX509Cert(noc_params, noc_keypair.Pubkey(), keypair, signed_cert_span1), |
| CHIP_ERROR_INVALID_ARGUMENT); |
| |
| // Test error case: NOC cert subject doesn't have fabric ID attribute |
| noc_params.SubjectDN.Clear(); |
| EXPECT_EQ(noc_params.SubjectDN.AddAttribute_MatterNodeId(0xABCDABCDABCDABCD), CHIP_NO_ERROR); |
| |
| EXPECT_EQ(NewNodeOperationalX509Cert(noc_params, noc_keypair.Pubkey(), keypair, signed_cert_span1), CHIP_ERROR_WRONG_CERT_DN); |
| |
| // Test error case: issuer cert DN type is Node certificate |
| noc_params.SubjectDN.Clear(); |
| EXPECT_EQ(noc_params.SubjectDN.AddAttribute_MatterNodeId(0xABCDABCDABCDABCD), CHIP_NO_ERROR); |
| EXPECT_EQ(noc_params.SubjectDN.AddAttribute_MatterFabricId(0xFAB00000FAB00001), CHIP_NO_ERROR); |
| noc_params.IssuerDN.Clear(); |
| EXPECT_EQ(noc_params.IssuerDN.AddAttribute_MatterNodeId(0x8888999944442222), CHIP_NO_ERROR); |
| EXPECT_EQ(noc_params.IssuerDN.AddAttribute_MatterFabricId(0xFAB00000FAB00001), CHIP_NO_ERROR); |
| |
| EXPECT_EQ(NewNodeOperationalX509Cert(noc_params, noc_keypair.Pubkey(), keypair, signed_cert_span1), |
| CHIP_ERROR_INVALID_ARGUMENT); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_GenerateNOCICA) |
| { |
| // Generate a new keypair for cert signing |
| P256Keypair keypair; |
| EXPECT_EQ(keypair.Initialize(ECPKeyTarget::ECDSA), CHIP_NO_ERROR); |
| |
| uint8_t signed_cert[kMaxDERCertLength]; |
| |
| uint8_t outCertBuf[kMaxCHIPCertLength]; |
| MutableByteSpan outCert(outCertBuf); |
| |
| uint8_t outCertDERBuf[kMaxDERCertLength]; |
| MutableByteSpan outCertDER(outCertDERBuf); |
| |
| ChipCertificateData certData; |
| |
| const static char noc_cn_rdn[] = "Test NOC"; |
| const static char noc_givenname_rdn[] = "John"; |
| const static char noc_name_rdn[] = "Smith"; |
| |
| ChipDN noc_dn; |
| EXPECT_EQ(noc_dn.AddAttribute_CommonName(CharSpan(noc_cn_rdn, strlen(noc_cn_rdn)), false), CHIP_NO_ERROR); |
| EXPECT_EQ(noc_dn.AddAttribute_MatterNodeId(0xAAAABBBBCCCCDDDD), CHIP_NO_ERROR); |
| EXPECT_EQ(noc_dn.AddAttribute_MatterFabricId(0xFAB00000FAB00001), CHIP_NO_ERROR); |
| EXPECT_EQ(noc_dn.AddAttribute_GivenName(CharSpan(noc_givenname_rdn, strlen(noc_givenname_rdn)), true), CHIP_NO_ERROR); |
| EXPECT_EQ(noc_dn.AddAttribute_Name(CharSpan(noc_name_rdn, strlen(noc_name_rdn)), true), CHIP_NO_ERROR); |
| |
| ChipDN ica_dn; |
| EXPECT_EQ(ica_dn.AddAttribute_MatterICACId(0x8888999944442222), CHIP_NO_ERROR); |
| EXPECT_EQ(ica_dn.AddAttribute_MatterFabricId(0xFAB00000FAB00001), CHIP_NO_ERROR); |
| |
| X509CertRequestParams noc_params = { 12348765, 631161876, 729942000, noc_dn, ica_dn }; |
| P256Keypair noc_keypair; |
| EXPECT_EQ(noc_keypair.Initialize(ECPKeyTarget::ECDSA), CHIP_NO_ERROR); |
| |
| MutableByteSpan signed_cert_span(signed_cert); |
| EXPECT_EQ(NewNodeOperationalX509Cert(noc_params, noc_keypair.Pubkey(), keypair, signed_cert_span), CHIP_NO_ERROR); |
| |
| EXPECT_EQ(ConvertX509CertToChipCert(signed_cert_span, outCert), CHIP_NO_ERROR); |
| |
| EXPECT_EQ(ConvertChipCertToX509Cert(outCert, outCertDER), CHIP_NO_ERROR); |
| EXPECT_TRUE(signed_cert_span.data_equal(outCertDER)); |
| |
| EXPECT_EQ(DecodeChipCert(outCert, certData), CHIP_NO_ERROR); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_VerifyGeneratedCerts) |
| { |
| // Generate a new keypair for cert signing |
| P256Keypair keypair; |
| EXPECT_EQ(keypair.Initialize(ECPKeyTarget::ECDSA), CHIP_NO_ERROR); |
| |
| static uint8_t root_cert[kMaxDERCertLength]; |
| |
| ChipDN root_dn; |
| EXPECT_EQ(root_dn.AddAttribute_MatterRCACId(0xAAAABBBBCCCCDDDD), CHIP_NO_ERROR); |
| EXPECT_EQ(root_dn.AddAttribute_MatterFabricId(0xFAB0000000008888), CHIP_NO_ERROR); |
| |
| X509CertRequestParams root_params = { 1234, 631161876, 729942000, root_dn, root_dn }; |
| MutableByteSpan root_cert_span(root_cert); |
| EXPECT_EQ(NewRootX509Cert(root_params, keypair, root_cert_span), CHIP_NO_ERROR); |
| |
| static uint8_t ica_cert[kMaxDERCertLength]; |
| |
| ChipDN ica_dn; |
| EXPECT_EQ(ica_dn.AddAttribute_MatterICACId(0xAABBCCDDAABBCCDD), CHIP_NO_ERROR); |
| EXPECT_EQ(ica_dn.AddAttribute_MatterFabricId(0xFAB0000000008888), CHIP_NO_ERROR); |
| |
| X509CertRequestParams ica_params = { 12345, 631161876, 729942000, ica_dn, root_dn }; |
| P256Keypair ica_keypair; |
| EXPECT_EQ(ica_keypair.Initialize(ECPKeyTarget::ECDSA), CHIP_NO_ERROR); |
| |
| MutableByteSpan ica_cert_span(ica_cert); |
| EXPECT_EQ(NewICAX509Cert(ica_params, ica_keypair.Pubkey(), keypair, ica_cert_span), CHIP_NO_ERROR); |
| |
| static uint8_t noc_cert[kMaxDERCertLength]; |
| |
| ChipDN noc_dn; |
| EXPECT_EQ(noc_dn.AddAttribute_MatterNodeId(0xAABBCCDDAABBCCDD), CHIP_NO_ERROR); |
| EXPECT_EQ(noc_dn.AddAttribute_MatterFabricId(0xFAB0000000008888), CHIP_NO_ERROR); |
| |
| X509CertRequestParams noc_params = { 123456, 631161876, 729942000, noc_dn, ica_dn }; |
| P256Keypair noc_keypair; |
| EXPECT_EQ(noc_keypair.Initialize(ECPKeyTarget::ECDSA), CHIP_NO_ERROR); |
| |
| MutableByteSpan noc_cert_span(noc_cert, sizeof(noc_cert)); |
| EXPECT_EQ(NewNodeOperationalX509Cert(noc_params, noc_keypair.Pubkey(), ica_keypair, noc_cert_span), CHIP_NO_ERROR); |
| |
| ChipCertificateSet certSet; |
| EXPECT_EQ(certSet.Init(3), CHIP_NO_ERROR); |
| |
| static uint8_t chipRootCertBuf[kMaxCHIPCertLength]; |
| static uint8_t chipICACertBuf[kMaxCHIPCertLength]; |
| static uint8_t chipNOCCertBuf[kMaxCHIPCertLength]; |
| MutableByteSpan chipRootCert(chipRootCertBuf); |
| MutableByteSpan chipICACert(chipICACertBuf); |
| MutableByteSpan chipNOCCert(chipNOCCertBuf); |
| |
| EXPECT_EQ(ConvertX509CertToChipCert(root_cert_span, chipRootCert), CHIP_NO_ERROR); |
| EXPECT_EQ(certSet.LoadCert(chipRootCert, sTrustAnchorFlag), CHIP_NO_ERROR); |
| |
| EXPECT_EQ(ConvertX509CertToChipCert(ica_cert_span, chipICACert), CHIP_NO_ERROR); |
| EXPECT_EQ(certSet.LoadCert(chipICACert, sGenTBSHashFlag), CHIP_NO_ERROR); |
| |
| EXPECT_EQ(ConvertX509CertToChipCert(noc_cert_span, chipNOCCert), CHIP_NO_ERROR); |
| EXPECT_EQ(certSet.LoadCert(chipNOCCert, sGenTBSHashFlag), CHIP_NO_ERROR); |
| |
| ValidationContext validContext; |
| |
| validContext.Reset(); |
| EXPECT_EQ(SetCurrentTime(validContext, 2022, 1, 1), CHIP_NO_ERROR); |
| validContext.mRequiredKeyUsages.Set(KeyUsageFlags::kDigitalSignature); |
| validContext.mRequiredKeyPurposes.Set(KeyPurposeFlags::kServerAuth); |
| validContext.mRequiredKeyPurposes.Set(KeyPurposeFlags::kClientAuth); |
| |
| // Locate the subject DN and key id that will be used as input the FindValidCert() method. |
| const ChipDN & subjectDN = certSet.GetCertSet()[2].mSubjectDN; |
| const CertificateKeyId & subjectKeyId = certSet.GetCertSet()[2].mSubjectKeyId; |
| |
| const ChipCertificateData * resultCert = nullptr; |
| EXPECT_EQ(certSet.FindValidCert(subjectDN, subjectKeyId, validContext, &resultCert), CHIP_NO_ERROR); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_VerifyGeneratedCertsNoICA) |
| { |
| // Generate a new keypair for cert signing |
| P256Keypair keypair; |
| EXPECT_EQ(keypair.Initialize(ECPKeyTarget::ECDSA), CHIP_NO_ERROR); |
| |
| static uint8_t root_cert[kMaxDERCertLength]; |
| |
| const static char root_cn_rdn[] = "Test Root Operational Cert"; |
| |
| ChipDN root_dn; |
| EXPECT_EQ(root_dn.AddAttribute_CommonName(CharSpan(root_cn_rdn, strlen(root_cn_rdn)), false), CHIP_NO_ERROR); |
| EXPECT_EQ(root_dn.AddAttribute_MatterRCACId(0xAAAABBBBCCCCDDDD), CHIP_NO_ERROR); |
| EXPECT_EQ(root_dn.AddAttribute_MatterFabricId(0xFAB0000000008888), CHIP_NO_ERROR); |
| |
| X509CertRequestParams root_params = { 1234, 631161876, 729942000, root_dn, root_dn }; |
| MutableByteSpan root_cert_span(root_cert); |
| EXPECT_EQ(NewRootX509Cert(root_params, keypair, root_cert_span), CHIP_NO_ERROR); |
| |
| static uint8_t noc_cert[kMaxDERCertLength]; |
| |
| const static char noc_cn_rdn[] = "Test NOC"; |
| |
| ChipDN noc_dn; |
| EXPECT_EQ(noc_dn.AddAttribute_CommonName(CharSpan(noc_cn_rdn, strlen(noc_cn_rdn)), true), CHIP_NO_ERROR); |
| EXPECT_EQ(noc_dn.AddAttribute_MatterNodeId(0xAABBCCDDAABBCCDD), CHIP_NO_ERROR); |
| EXPECT_EQ(noc_dn.AddAttribute_MatterFabricId(0xFAB0000000008888), CHIP_NO_ERROR); |
| EXPECT_EQ(noc_dn.AddAttribute_MatterCASEAuthTag(0xABCD0010), CHIP_NO_ERROR); |
| |
| X509CertRequestParams noc_params = { 1234, 631161876, 729942000, noc_dn, root_dn }; |
| P256Keypair noc_keypair; |
| EXPECT_EQ(noc_keypair.Initialize(ECPKeyTarget::ECDSA), CHIP_NO_ERROR); |
| |
| MutableByteSpan noc_cert_span(noc_cert); |
| EXPECT_EQ(NewNodeOperationalX509Cert(noc_params, noc_keypair.Pubkey(), keypair, noc_cert_span), CHIP_NO_ERROR); |
| |
| ChipCertificateSet certSet; |
| EXPECT_EQ(certSet.Init(2), CHIP_NO_ERROR); |
| |
| static uint8_t chipRootCertBuf[kMaxCHIPCertLength]; |
| static uint8_t chipNOCCertBuf[kMaxCHIPCertLength]; |
| MutableByteSpan chipRootCert(chipRootCertBuf); |
| MutableByteSpan chipNOCCert(chipNOCCertBuf); |
| |
| EXPECT_EQ(ConvertX509CertToChipCert(root_cert_span, chipRootCert), CHIP_NO_ERROR); |
| EXPECT_EQ(certSet.LoadCert(chipRootCert, sTrustAnchorFlag), CHIP_NO_ERROR); |
| |
| EXPECT_EQ(ConvertX509CertToChipCert(noc_cert_span, chipNOCCert), CHIP_NO_ERROR); |
| EXPECT_EQ(certSet.LoadCert(chipNOCCert, sGenTBSHashFlag), CHIP_NO_ERROR); |
| |
| ValidationContext validContext; |
| |
| validContext.Reset(); |
| EXPECT_EQ(SetCurrentTime(validContext, 2022, 1, 1), CHIP_NO_ERROR); |
| validContext.mRequiredKeyUsages.Set(KeyUsageFlags::kDigitalSignature); |
| validContext.mRequiredKeyPurposes.Set(KeyPurposeFlags::kServerAuth); |
| validContext.mRequiredKeyPurposes.Set(KeyPurposeFlags::kClientAuth); |
| |
| // Locate the subject DN and key id that will be used as input the FindValidCert() method. |
| const ChipDN & subjectDN = certSet.GetCertSet()[1].mSubjectDN; |
| const CertificateKeyId & subjectKeyId = certSet.GetCertSet()[1].mSubjectKeyId; |
| |
| const ChipCertificateData * resultCert = nullptr; |
| EXPECT_EQ(certSet.FindValidCert(subjectDN, subjectKeyId, validContext, &resultCert), CHIP_NO_ERROR); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_ExtractNodeIdFabricId) |
| { |
| struct TestCase |
| { |
| TestCert Cert; |
| TestCert ICACert; |
| uint64_t ExpectedNodeId; |
| uint64_t ExpectedFabricId; |
| }; |
| |
| // clang-format off |
| static constexpr TestCase sTestCases[] = { |
| // Cert ICA ExpectedNodeId ExpectedFabricId |
| // ============================================================= |
| { TestCert::kNode01_01, TestCert::kICA01, 0xDEDEDEDE00010001, 0xFAB000000000001D }, |
| { TestCert::kNode01_02, TestCert::kNone, 0xDEDEDEDE00010002, 0xFAB000000000001D }, |
| { TestCert::kNode02_01, TestCert::kICA02, 0xDEDEDEDE00020001, 0xFAB000000000001D }, |
| { TestCert::kNode02_02, TestCert::kICA02, 0xDEDEDEDE00020002, 0xFAB000000000001D }, |
| { TestCert::kNode02_03, TestCert::kICA02, 0xDEDEDEDE00020003, 0xFAB000000000001D }, |
| { TestCert::kNode02_04, TestCert::kICA02, 0xDEDEDEDE00020004, 0xFAB000000000001D }, |
| { TestCert::kNode02_05, TestCert::kICA02, 0xDEDEDEDE00020005, 0xFAB000000000001D }, |
| { TestCert::kNode02_06, TestCert::kICA02, 0xDEDEDEDE00020006, 0xFAB000000000001D }, |
| { TestCert::kNode02_07, TestCert::kICA02, 0xDEDEDEDE00020007, 0xFAB000000000001D }, |
| { TestCert::kNode02_08, TestCert::kICA02, 0xDEDEDEDE00020008, 0xFAB000000000001D }, |
| }; |
| // clang-format on |
| |
| // Test node ID and fabric ID extraction from the raw ByteSpan form. |
| for (auto & testCase : sTestCases) |
| { |
| ByteSpan cert; |
| CHIP_ERROR err = GetTestCert(testCase.Cert, sNullLoadFlag, cert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| NodeId nodeId; |
| FabricId fabricId; |
| err = ExtractNodeIdFabricIdFromOpCert(cert, &nodeId, &fabricId); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_EQ(nodeId, testCase.ExpectedNodeId); |
| EXPECT_EQ(fabricId, testCase.ExpectedFabricId); |
| } |
| |
| // Test node ID and fabric ID extraction from the parsed form. |
| ChipCertificateSet certSet; |
| for (auto & testCase : sTestCases) |
| { |
| CHIP_ERROR err = certSet.Init(1); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| err = LoadTestCert(certSet, testCase.Cert, sNullLoadFlag, sNullDecodeFlag); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| NodeId nodeId; |
| FabricId fabricId; |
| err = ExtractNodeIdFabricIdFromOpCert(certSet.GetCertSet()[0], &nodeId, &fabricId); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_EQ(nodeId, testCase.ExpectedNodeId); |
| EXPECT_EQ(fabricId, testCase.ExpectedFabricId); |
| certSet.Release(); |
| } |
| |
| // Test fabric ID extraction from the raw ByteSpan form. |
| for (auto & testCase : sTestCases) |
| { |
| ByteSpan cert; |
| CHIP_ERROR err = GetTestCert(testCase.Cert, sNullLoadFlag, cert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| FabricId fabricId; |
| err = ExtractFabricIdFromCert(cert, &fabricId); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_EQ(fabricId, testCase.ExpectedFabricId); |
| } |
| |
| // Test fabric ID extraction from the parsed form. |
| for (auto & testCase : sTestCases) |
| { |
| CHIP_ERROR err = certSet.Init(1); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| err = LoadTestCert(certSet, testCase.Cert, sNullLoadFlag, sNullDecodeFlag); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| FabricId fabricId; |
| err = ExtractFabricIdFromCert(certSet.GetCertSet()[0], &fabricId); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_EQ(fabricId, testCase.ExpectedFabricId); |
| certSet.Release(); |
| } |
| |
| // Test fabric ID extraction from the raw ByteSpan form of ICA Cert that doesn't have FabricId. |
| { |
| ByteSpan cert; |
| CHIP_ERROR err = GetTestCert(TestCert::kICA01, sNullLoadFlag, cert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| FabricId fabricId; |
| err = ExtractFabricIdFromCert(cert, &fabricId); |
| EXPECT_EQ(err, CHIP_ERROR_NOT_FOUND); |
| } |
| |
| // Test extraction from the parsed form of ICA Cert that doesn't have FabricId. |
| { |
| CHIP_ERROR err = certSet.Init(1); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| err = LoadTestCert(certSet, TestCert::kICA01, sNullLoadFlag, sNullDecodeFlag); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| FabricId fabricId; |
| err = ExtractFabricIdFromCert(certSet.GetCertSet()[0], &fabricId); |
| EXPECT_EQ(err, CHIP_ERROR_NOT_FOUND); |
| certSet.Release(); |
| } |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_ExtractOperationalDiscoveryId) |
| { |
| struct TestCase |
| { |
| TestCert Noc; |
| TestCert Rcac; |
| uint64_t ExpectedNodeId; |
| uint64_t ExpectedFabricId; |
| uint64_t ExpectedCompressedFabricId; |
| }; |
| |
| // clang-format off |
| static constexpr TestCase sTestCases[] = { |
| // Cert ICA ExpectedNodeId ExpectedFabricId ExpectedCompressedFabricId |
| // =========================================================================================================== |
| { TestCert::kNode01_01, TestCert::kRoot01, 0xDEDEDEDE00010001, 0xFAB000000000001D, 0x3893C4324526C775 }, |
| { TestCert::kNode01_02, TestCert::kRoot01, 0xDEDEDEDE00010002, 0xFAB000000000001D, 0x3893C4324526C775 }, |
| { TestCert::kNode02_01, TestCert::kRoot02, 0xDEDEDEDE00020001, 0xFAB000000000001D, 0x89E8911178DAC089 }, |
| { TestCert::kNode02_02, TestCert::kRoot02, 0xDEDEDEDE00020002, 0xFAB000000000001D, 0x89E8911178DAC089 }, |
| { TestCert::kNode02_03, TestCert::kRoot02, 0xDEDEDEDE00020003, 0xFAB000000000001D, 0x89E8911178DAC089 }, |
| { TestCert::kNode02_04, TestCert::kRoot02, 0xDEDEDEDE00020004, 0xFAB000000000001D, 0x89E8911178DAC089 }, |
| { TestCert::kNode02_05, TestCert::kRoot02, 0xDEDEDEDE00020005, 0xFAB000000000001D, 0x89E8911178DAC089 }, |
| { TestCert::kNode02_06, TestCert::kRoot02, 0xDEDEDEDE00020006, 0xFAB000000000001D, 0x89E8911178DAC089 }, |
| { TestCert::kNode02_07, TestCert::kRoot02, 0xDEDEDEDE00020007, 0xFAB000000000001D, 0x89E8911178DAC089 }, |
| { TestCert::kNode02_08, TestCert::kRoot02, 0xDEDEDEDE00020008, 0xFAB000000000001D, 0x89E8911178DAC089 }, |
| }; |
| // clang-format on |
| |
| for (auto & testCase : sTestCases) |
| { |
| ByteSpan noc; |
| ByteSpan rcac; |
| CHIP_ERROR err = GetTestCert(testCase.Noc, sNullLoadFlag, noc); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| err = GetTestCert(testCase.Rcac, sNullLoadFlag, rcac); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| // Extract Node ID and Fabric ID from the leaf node certificate. |
| NodeId nodeId; |
| FabricId fabricId; |
| err = ExtractNodeIdFabricIdFromOpCert(noc, &nodeId, &fabricId); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_EQ(nodeId, testCase.ExpectedNodeId); |
| EXPECT_EQ(fabricId, testCase.ExpectedFabricId); |
| |
| // Extract Node ID, Fabric ID and Compressed Fabric ID from the |
| // NOC and root certificate. |
| CompressedFabricId compressedFabricId; |
| err = ExtractNodeIdFabricIdCompressedFabricIdFromOpCerts(rcac, noc, compressedFabricId, fabricId, nodeId); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_EQ(compressedFabricId, testCase.ExpectedCompressedFabricId); |
| EXPECT_EQ(fabricId, testCase.ExpectedFabricId); |
| EXPECT_EQ(nodeId, testCase.ExpectedNodeId); |
| } |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_ExtractAndValidateCATsFromOpCert) |
| { |
| struct TestCase |
| { |
| TestCert Cert; |
| CATValues ExpectedCATs; |
| }; |
| |
| // clang-format off |
| static constexpr TestCase sTestCases[] = { |
| // Cert CATs |
| // ============================================================================ |
| { TestCert::kNode01_01, { { kUndefinedCAT, kUndefinedCAT, kUndefinedCAT } } }, |
| { TestCert::kNode01_02, { { kUndefinedCAT, kUndefinedCAT, kUndefinedCAT } } }, |
| { TestCert::kNode02_01, { { kUndefinedCAT, kUndefinedCAT, kUndefinedCAT } } }, |
| { TestCert::kNode02_02, { { kUndefinedCAT, kUndefinedCAT, kUndefinedCAT } } }, |
| { TestCert::kNode02_03, { { 0xABCD0001, kUndefinedCAT, kUndefinedCAT } } }, |
| { TestCert::kNode02_04, { { 0xABCE1002, 0xABCD0003, kUndefinedCAT } } }, |
| { TestCert::kNode02_05, { { 0xABCD0010, 0xABCE1008, kUndefinedCAT } } }, |
| { TestCert::kNode02_06, { { kUndefinedCAT, kUndefinedCAT, kUndefinedCAT } } }, |
| { TestCert::kNode02_07, { { kUndefinedCAT, kUndefinedCAT, kUndefinedCAT } } }, |
| { TestCert::kNode02_08, { { 0xABCF00A0, 0xABCD0020, 0xABCE0100 } } }, |
| }; |
| // clang-format on |
| |
| // Test extraction from the raw ByteSpan form. |
| for (auto & testCase : sTestCases) |
| { |
| ByteSpan cert; |
| CHIP_ERROR err = GetTestCert(testCase.Cert, sNullLoadFlag, cert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| CATValues cats; |
| err = ExtractCATsFromOpCert(cert, cats); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_EQ(memcmp(&cats, &testCase.ExpectedCATs, sizeof(cats)), 0); |
| } |
| |
| // Test extraction from the parsed form. |
| ChipCertificateSet certSet; |
| for (auto & testCase : sTestCases) |
| { |
| CHIP_ERROR err = certSet.Init(1); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| err = LoadTestCert(certSet, testCase.Cert, sNullLoadFlag, sNullDecodeFlag); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| CATValues cats; |
| err = ExtractCATsFromOpCert(certSet.GetCertSet()[0], cats); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_EQ(memcmp(&cats, &testCase.ExpectedCATs, sizeof(cats)), 0); |
| |
| certSet.Release(); |
| } |
| |
| // Error case: trying to extract CAT from Root Cert. |
| { |
| CHIP_ERROR err = certSet.Init(1); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| err = LoadTestCert(certSet, TestCert::kRoot01, sNullLoadFlag, sNullDecodeFlag); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| CATValues cats; |
| err = ExtractCATsFromOpCert(certSet.GetCertSet()[0], cats); |
| EXPECT_EQ(err, CHIP_ERROR_INVALID_ARGUMENT); |
| |
| certSet.Release(); |
| } |
| |
| // Error case: NOC with invalid CAT version. |
| { |
| CATValues cats; |
| CHIP_ERROR err = ExtractCATsFromOpCert(ByteSpan(sChipTest_NOC_Subject_CAT_Invalid_Cert_CHIP), cats); |
| EXPECT_EQ(err, CHIP_ERROR_INVALID_ARGUMENT); |
| } |
| |
| // Error case: NOC with multiple versions of the same CAT tag. |
| { |
| CATValues cats; |
| CHIP_ERROR err = ExtractCATsFromOpCert(ByteSpan(sChipTest_NOC_Subject_CAT_Twice_Cert_CHIP), cats); |
| EXPECT_EQ(err, CHIP_ERROR_WRONG_CERT_DN); |
| } |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_ExtractSubjectDNFromChipCert) |
| { |
| struct TestCase |
| { |
| TestCert Cert; |
| ChipDN ExpectedSubjectDN; |
| }; |
| |
| ChipDN expectedSubjectDN_Root01; |
| EXPECT_EQ(expectedSubjectDN_Root01.AddAttribute_MatterRCACId(0xCACACACA00000001), CHIP_NO_ERROR); |
| |
| ChipDN expectedSubjectDN_Root02; |
| EXPECT_EQ(expectedSubjectDN_Root02.AddAttribute_MatterRCACId(0xCACACACA00000002), CHIP_NO_ERROR); |
| EXPECT_EQ(expectedSubjectDN_Root02.AddAttribute_MatterFabricId(0xFAB000000000001D), CHIP_NO_ERROR); |
| |
| ChipDN expectedSubjectDN_ICA02; |
| EXPECT_EQ(expectedSubjectDN_ICA02.AddAttribute_MatterICACId(0xCACACACA00000004), CHIP_NO_ERROR); |
| EXPECT_EQ(expectedSubjectDN_ICA02.AddAttribute_MatterFabricId(0xFAB000000000001D), CHIP_NO_ERROR); |
| |
| ChipDN expectedSubjectDN_Node01_01; |
| EXPECT_EQ(expectedSubjectDN_Node01_01.AddAttribute_MatterNodeId(0xDEDEDEDE00010001), CHIP_NO_ERROR); |
| EXPECT_EQ(expectedSubjectDN_Node01_01.AddAttribute_MatterFabricId(0xFAB000000000001D), CHIP_NO_ERROR); |
| |
| const static char commonName_RDN[] = "TestCert02_03"; |
| |
| ChipDN expectedSubjectDN_Node02_03; |
| EXPECT_EQ(expectedSubjectDN_Node02_03.AddAttribute_MatterNodeId(0xDEDEDEDE00020003), CHIP_NO_ERROR); |
| EXPECT_EQ(expectedSubjectDN_Node02_03.AddAttribute_MatterFabricId(0xFAB000000000001D), CHIP_NO_ERROR); |
| EXPECT_EQ(expectedSubjectDN_Node02_03.AddAttribute_CommonName(CharSpan(commonName_RDN, strlen(commonName_RDN)), false), |
| CHIP_NO_ERROR); |
| EXPECT_EQ(expectedSubjectDN_Node02_03.AddAttribute_MatterCASEAuthTag(0xABCD0001), CHIP_NO_ERROR); |
| |
| // clang-format off |
| TestCase sTestCases[] = { |
| // Cert SubjectDN |
| // ============================================================================ |
| { TestCert::kRoot01, expectedSubjectDN_Root01 }, |
| { TestCert::kRoot02, expectedSubjectDN_Root02 }, |
| { TestCert::kICA02, expectedSubjectDN_ICA02 }, |
| { TestCert::kNode01_01, expectedSubjectDN_Node01_01 }, |
| { TestCert::kNode02_03, expectedSubjectDN_Node02_03 }, |
| { TestCert::kPDCID01, {} }, |
| }; |
| // clang-format on |
| |
| // Test extraction from the raw ByteSpan form. |
| for (auto & testCase : sTestCases) |
| { |
| ByteSpan cert; |
| CHIP_ERROR err = GetTestCert(testCase.Cert, sNullLoadFlag, cert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| ChipDN subjectDN; |
| err = ExtractSubjectDNFromChipCert(cert, subjectDN); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| if (!testCase.ExpectedSubjectDN.IsEmpty()) |
| { |
| EXPECT_TRUE(subjectDN.IsEqual(testCase.ExpectedSubjectDN)); |
| } |
| } |
| |
| // Test extraction from the X509 ByteSpan form. |
| for (auto & testCase : sTestCases) |
| { |
| ByteSpan cert; |
| CHIP_ERROR err = GetTestCert(testCase.Cert, TestCertLoadFlags::kDERForm, cert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| ChipDN subjectDN; |
| err = ExtractSubjectDNFromX509Cert(cert, subjectDN); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| if (!testCase.ExpectedSubjectDN.IsEmpty()) |
| { |
| EXPECT_TRUE(subjectDN.IsEqual(testCase.ExpectedSubjectDN)); |
| } |
| } |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_ExtractPublicKeyAndSKID) |
| { |
| struct TestCase |
| { |
| TestCert Cert; |
| ByteSpan ExpectedPublicKey; |
| ByteSpan ExpectedSKID; |
| }; |
| |
| // clang-format off |
| static const TestCase sTestCases[] = { |
| // Cert ExpectedPublicKey ExpectedSKID |
| // ======================================================================================= |
| { TestCert::kRoot01, sTestCert_Root01_PublicKey, sTestCert_Root01_SubjectKeyId }, |
| { TestCert::kRoot02, sTestCert_Root02_PublicKey, sTestCert_Root02_SubjectKeyId }, |
| { TestCert::kICA01, sTestCert_ICA01_PublicKey, sTestCert_ICA01_SubjectKeyId }, |
| { TestCert::kICA02, sTestCert_ICA02_PublicKey, sTestCert_ICA02_SubjectKeyId }, |
| { TestCert::kICA01_1, sTestCert_ICA01_1_PublicKey, sTestCert_ICA01_1_SubjectKeyId }, |
| { TestCert::kNode01_01, sTestCert_Node01_01_PublicKey, sTestCert_Node01_01_SubjectKeyId }, |
| { TestCert::kNode01_02, sTestCert_Node01_02_PublicKey, sTestCert_Node01_02_SubjectKeyId }, |
| { TestCert::kNode02_01, sTestCert_Node02_01_PublicKey, sTestCert_Node02_01_SubjectKeyId }, |
| { TestCert::kNode02_02, sTestCert_Node02_02_PublicKey, sTestCert_Node02_02_SubjectKeyId }, |
| { TestCert::kNode02_03, sTestCert_Node02_03_PublicKey, sTestCert_Node02_03_SubjectKeyId }, |
| { TestCert::kNode02_04, sTestCert_Node02_04_PublicKey, sTestCert_Node02_04_SubjectKeyId }, |
| { TestCert::kNode02_05, sTestCert_Node02_05_PublicKey, sTestCert_Node02_05_SubjectKeyId }, |
| { 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 |
| |
| for (auto & testCase : sTestCases) |
| { |
| ByteSpan cert; |
| CHIP_ERROR err = GetTestCert(testCase.Cert, sNullLoadFlag, cert); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| |
| P256PublicKeySpan publicKey; |
| err = ExtractPublicKeyFromChipCert(cert, publicKey); |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_TRUE(publicKey.data_equal(testCase.ExpectedPublicKey)); |
| |
| CertificateKeyId skid; |
| err = ExtractSKIDFromChipCert(cert, skid); |
| if (!testCase.ExpectedSKID.empty()) |
| { |
| EXPECT_EQ(err, CHIP_NO_ERROR); |
| EXPECT_TRUE(skid.data_equal(testCase.ExpectedSKID)); |
| } |
| else |
| { |
| EXPECT_EQ(err, CHIP_ERROR_NOT_FOUND); |
| } |
| } |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_PDCIdentityValidation) |
| { |
| CertificateKeyIdStorage keyId; |
| |
| // Test with both the full and compact TLV representations |
| for (auto && cert : { sTestCert_PDCID01_Chip, sTestCert_PDCID01_ChipCompact }) |
| { |
| // Validate only |
| EXPECT_EQ(ValidateChipNetworkIdentity(cert), CHIP_NO_ERROR); |
| |
| // Validate and calculate identifier |
| keyId.fill(0xaa); |
| EXPECT_EQ(ValidateChipNetworkIdentity(cert, keyId), CHIP_NO_ERROR); |
| EXPECT_TRUE(CertificateKeyId(keyId).data_equal(sTestCert_PDCID01_KeyId)); |
| |
| // Extract identifier only |
| keyId.fill(0xaa); |
| EXPECT_EQ(ExtractIdentifierFromChipNetworkIdentity(cert, keyId), CHIP_NO_ERROR); |
| EXPECT_TRUE(CertificateKeyId(keyId).data_equal(sTestCert_PDCID01_KeyId)); |
| } |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_PDCIdentityGeneration) |
| { |
| // Generate a new keypair |
| P256Keypair keypair; |
| EXPECT_EQ(keypair.Initialize(ECPKeyTarget::ECDSA), CHIP_NO_ERROR); |
| |
| // Generate an identity certificate based on the keypair |
| uint8_t buffer[kMaxCHIPCompactNetworkIdentityLength]; |
| MutableByteSpan cert(buffer); |
| EXPECT_EQ(NewChipNetworkIdentity(keypair, cert), CHIP_NO_ERROR); |
| EXPECT_EQ(ValidateChipNetworkIdentity(cert), CHIP_NO_ERROR); |
| |
| // It should round-trip to X.509 DER and back, and remain valid. |
| uint8_t derBuffer[kMaxDERCertLength]; |
| MutableByteSpan derCert(derBuffer); |
| EXPECT_EQ(ConvertChipCertToX509Cert(cert, derCert), CHIP_NO_ERROR); |
| uint8_t tlvBuffer[kMaxCHIPCertLength]; |
| MutableByteSpan tlvCert(tlvBuffer); // won't be compact after round-tripping |
| EXPECT_EQ(ConvertX509CertToChipCert(derCert, tlvCert), CHIP_NO_ERROR); |
| EXPECT_EQ(ValidateChipNetworkIdentity(tlvCert), CHIP_NO_ERROR); |
| } |
| |
| TEST_F(TestChipCert, TestChipCert_KeypairConversion) |
| { |
| P256SerializedKeypair keypair; |
| EXPECT_EQ(GetTestCertKeypair(kPDCID01, keypair), CHIP_NO_ERROR); |
| |
| uint8_t buffer[kP256ECPrivateKeyDERLength]; |
| MutableByteSpan keypairDer(buffer); |
| EXPECT_EQ(ConvertECDSAKeypairRawToDER(keypair, keypairDer), CHIP_NO_ERROR); |
| |
| // Technically the curve name and public key are optional in the DER format, |
| // but both our code and standard tools include them, so we can just compare. |
| EXPECT_TRUE(keypairDer.data_equal(sTestCert_PDCID01_KeypairDER)); |
| } |