From 5592382a620bdbf8d9e2a51efef8580b5beb8ff4 Mon Sep 17 00:00:00 2001 From: Evgeny Margolis Date: Tue, 16 May 2023 04:42:54 -1000 Subject: [PATCH] Implemented ExtractSubjectFromX509Cert() and ExtractIssuerFromX509Cert() Helper Function (#26588) --- src/crypto/CHIPCryptoPAL.h | 27 ++-- src/crypto/CHIPCryptoPALOpenSSL.cpp | 51 +++++++ src/crypto/CHIPCryptoPALPSA.cpp | 52 ++++--- src/crypto/CHIPCryptoPALmbedTLS.cpp | 48 +++++-- src/crypto/tests/CHIPCryptoPALTest.cpp | 131 ++++++++++++++++++ .../common/crypto/CHIPCryptoPALTinyCrypt.cpp | 48 +++++-- .../silabs/SiWx917/CHIPCryptoPALTinyCrypt.cpp | 48 +++++-- .../silabs/efr32/CHIPCryptoPALPsaEfr32.cpp | 48 +++++-- 8 files changed, 377 insertions(+), 76 deletions(-) diff --git a/src/crypto/CHIPCryptoPAL.h b/src/crypto/CHIPCryptoPAL.h index 3640cdbc372ec9..c8da9f98a60415 100644 --- a/src/crypto/CHIPCryptoPAL.h +++ b/src/crypto/CHIPCryptoPAL.h @@ -43,14 +43,15 @@ namespace Crypto { constexpr size_t kMax_x509_Certificate_Length = 600; -constexpr size_t kP256_FE_Length = 32; -constexpr size_t kP256_ECDSA_Signature_Length_Raw = (2 * kP256_FE_Length); -constexpr size_t kP256_Point_Length = (2 * kP256_FE_Length + 1); -constexpr size_t kSHA256_Hash_Length = 32; -constexpr size_t kSHA1_Hash_Length = 20; -constexpr size_t kSubjectKeyIdentifierLength = kSHA1_Hash_Length; -constexpr size_t kAuthorityKeyIdentifierLength = kSHA1_Hash_Length; -constexpr size_t kMaxCertificateSerialNumberLength = 20; +constexpr size_t kP256_FE_Length = 32; +constexpr size_t kP256_ECDSA_Signature_Length_Raw = (2 * kP256_FE_Length); +constexpr size_t kP256_Point_Length = (2 * kP256_FE_Length + 1); +constexpr size_t kSHA256_Hash_Length = 32; +constexpr size_t kSHA1_Hash_Length = 20; +constexpr size_t kSubjectKeyIdentifierLength = kSHA1_Hash_Length; +constexpr size_t kAuthorityKeyIdentifierLength = kSHA1_Hash_Length; +constexpr size_t kMaxCertificateSerialNumberLength = 20; +constexpr size_t kMaxCertificateDistinguishedNameLength = 200; constexpr size_t CHIP_CRYPTO_GROUP_SIZE_BYTES = kP256_FE_Length; constexpr size_t CHIP_CRYPTO_PUBLIC_KEY_SIZE_BYTES = kP256_Point_Length; @@ -1572,6 +1573,16 @@ CHIP_ERROR ExtractAKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan **/ CHIP_ERROR ExtractSerialNumberFromX509Cert(const ByteSpan & certificate, MutableByteSpan & serialNumber); +/** + * @brief Extracts Subject Distinguished Name from X509 Certificate. The value is copied into buffer in a raw ASN.1 X.509 format. + **/ +CHIP_ERROR ExtractSubjectFromX509Cert(const ByteSpan & certificate, MutableByteSpan & subject); + +/** + * @brief Extracts Issuer Distinguished Name from X509 Certificate. The value is copied into buffer in a raw ASN.1 X.509 format. + **/ +CHIP_ERROR ExtractIssuerFromX509Cert(const ByteSpan & certificate, MutableByteSpan & issuer); + /** * @brief Checks for resigned version of the certificate in the list and returns it. * diff --git a/src/crypto/CHIPCryptoPALOpenSSL.cpp b/src/crypto/CHIPCryptoPALOpenSSL.cpp index 08ad564452cd90..b997ceed404193 100644 --- a/src/crypto/CHIPCryptoPALOpenSSL.cpp +++ b/src/crypto/CHIPCryptoPALOpenSSL.cpp @@ -2001,6 +2001,57 @@ CHIP_ERROR ExtractSerialNumberFromX509Cert(const ByteSpan & certificate, Mutable return err; } +namespace { +CHIP_ERROR ExtractRawDNFromX509Cert(bool extractSubject, const ByteSpan & certificate, MutableByteSpan & dn) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + int result = 1; + X509 * x509certificate = nullptr; + auto * pCertificate = Uint8::to_const_uchar(certificate.data()); + const unsigned char ** ppCertificate = &pCertificate; + X509_NAME * distinguishedName = nullptr; + const uint8_t * pDistinguishedName = nullptr; + size_t distinguishedNameLen = 0; + + VerifyOrReturnError(!certificate.empty() && CanCastTo(certificate.size()), CHIP_ERROR_INVALID_ARGUMENT); + + x509certificate = d2i_X509(nullptr, ppCertificate, static_cast(certificate.size())); + VerifyOrExit(x509certificate != nullptr, err = CHIP_ERROR_NO_MEMORY); + + if (extractSubject) + { + distinguishedName = X509_get_subject_name(x509certificate); + } + else + { + distinguishedName = X509_get_issuer_name(x509certificate); + } + VerifyOrExit(distinguishedName != nullptr, err = CHIP_ERROR_INTERNAL); + + result = X509_NAME_get0_der(distinguishedName, &pDistinguishedName, &distinguishedNameLen); + VerifyOrExit(result == 1, err = CHIP_ERROR_INTERNAL); + VerifyOrExit(distinguishedNameLen <= dn.size(), err = CHIP_ERROR_BUFFER_TOO_SMALL); + + memcpy(dn.data(), pDistinguishedName, distinguishedNameLen); + dn.reduce_size(distinguishedNameLen); + +exit: + X509_free(x509certificate); + + return err; +} +} // namespace + +CHIP_ERROR ExtractSubjectFromX509Cert(const ByteSpan & certificate, MutableByteSpan & subject) +{ + return ExtractRawDNFromX509Cert(true, certificate, subject); +} + +CHIP_ERROR ExtractIssuerFromX509Cert(const ByteSpan & certificate, MutableByteSpan & issuer) +{ + return ExtractRawDNFromX509Cert(false, certificate, issuer); +} + CHIP_ERROR ExtractVIDPIDFromX509Cert(const ByteSpan & certificate, AttestationCertVidPid & vidpid) { ASN1_OBJECT * commonNameObj = OBJ_txt2obj("2.5.4.3", 1); diff --git a/src/crypto/CHIPCryptoPALPSA.cpp b/src/crypto/CHIPCryptoPALPSA.cpp index 6a5e488031caac..28f3ba85c21053 100644 --- a/src/crypto/CHIPCryptoPALPSA.cpp +++ b/src/crypto/CHIPCryptoPALPSA.cpp @@ -1742,10 +1742,9 @@ CHIP_ERROR ExtractVIDPIDFromX509Cert(const ByteSpan & certificate, AttestationCe } namespace { - -#if defined(MBEDTLS_X509_CRT_PARSE_C) -CHIP_ERROR ExtractRawSubjectFromX509Cert(const ByteSpan & certificate, MutableByteSpan & subject) +CHIP_ERROR ExtractRawDNFromX509Cert(bool extractSubject, const ByteSpan & certificate, MutableByteSpan & dn) { +#if defined(MBEDTLS_X509_CRT_PARSE_C) CHIP_ERROR error = CHIP_NO_ERROR; int result = 0; uint8_t * p = nullptr; @@ -1758,29 +1757,50 @@ CHIP_ERROR ExtractRawSubjectFromX509Cert(const ByteSpan & certificate, MutableBy result = mbedtls_x509_crt_parse(&mbedCertificate, Uint8::to_const_uchar(certificate.data()), certificate.size()); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); - p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + if (extractSubject) + { + len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); + p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + } + else + { + len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(issuer_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); + p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(issuer_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + } - VerifyOrExit(len <= subject.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL); - memcpy(subject.data(), p, len); - subject.reduce_size(len); + VerifyOrExit(len <= dn.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(dn.data(), p, len); + dn.reduce_size(len); exit: - logMbedTLSError(result); + _log_mbedTLS_error(result); mbedtls_x509_crt_free(&mbedCertificate); - return error; -} +#else + (void) certificate; + (void) dn; + CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; #endif // defined(MBEDTLS_X509_CRT_PARSE_C) + return error; +} } // namespace +CHIP_ERROR ExtractSubjectFromX509Cert(const ByteSpan & certificate, MutableByteSpan & subject) +{ + return ExtractRawDNFromX509Cert(true, certificate, subject); +} + +CHIP_ERROR ExtractIssuerFromX509Cert(const ByteSpan & certificate, MutableByteSpan & issuer) +{ + return ExtractRawDNFromX509Cert(false, certificate, issuer); +} + CHIP_ERROR ReplaceCertIfResignedCertFound(const ByteSpan & referenceCertificate, const ByteSpan * candidateCertificates, size_t candidateCertificatesCount, ByteSpan & outCertificate) { #if defined(MBEDTLS_X509_CRT_PARSE_C) - constexpr size_t kMaxCertificateSubjectLength = 150; - uint8_t referenceSubjectBuf[kMaxCertificateSubjectLength]; + uint8_t referenceSubjectBuf[kMaxCertificateDistinguishedNameLength]; uint8_t referenceSKIDBuf[kSubjectKeyIdentifierLength]; MutableByteSpan referenceSubject(referenceSubjectBuf); MutableByteSpan referenceSKID(referenceSKIDBuf); @@ -1789,18 +1809,18 @@ CHIP_ERROR ReplaceCertIfResignedCertFound(const ByteSpan & referenceCertificate, ReturnErrorCodeIf(candidateCertificates == nullptr || candidateCertificatesCount == 0, CHIP_NO_ERROR); - ReturnErrorOnFailure(ExtractRawSubjectFromX509Cert(referenceCertificate, referenceSubject)); + ReturnErrorOnFailure(ExtractSubjectFromX509Cert(referenceCertificate, referenceSubject)); ReturnErrorOnFailure(ExtractSKIDFromX509Cert(referenceCertificate, referenceSKID)); for (size_t i = 0; i < candidateCertificatesCount; i++) { const ByteSpan candidateCertificate = candidateCertificates[i]; - uint8_t candidateSubjectBuf[kMaxCertificateSubjectLength]; + uint8_t candidateSubjectBuf[kMaxCertificateDistinguishedNameLength]; uint8_t candidateSKIDBuf[kSubjectKeyIdentifierLength]; MutableByteSpan candidateSubject(candidateSubjectBuf); MutableByteSpan candidateSKID(candidateSKIDBuf); - ReturnErrorOnFailure(ExtractRawSubjectFromX509Cert(candidateCertificate, candidateSubject)); + ReturnErrorOnFailure(ExtractSubjectFromX509Cert(candidateCertificate, candidateSubject)); ReturnErrorOnFailure(ExtractSKIDFromX509Cert(candidateCertificate, candidateSKID)); if (referenceSKID.data_equal(candidateSKID) && referenceSubject.data_equal(candidateSubject)) diff --git a/src/crypto/CHIPCryptoPALmbedTLS.cpp b/src/crypto/CHIPCryptoPALmbedTLS.cpp index ec11cd17a9f8aa..0865d467448d07 100644 --- a/src/crypto/CHIPCryptoPALmbedTLS.cpp +++ b/src/crypto/CHIPCryptoPALmbedTLS.cpp @@ -1859,9 +1859,9 @@ CHIP_ERROR ExtractVIDPIDFromX509Cert(const ByteSpan & certificate, AttestationCe } namespace { -#if defined(MBEDTLS_X509_CRT_PARSE_C) -CHIP_ERROR ExtractRawSubjectFromX509Cert(const ByteSpan & certificate, MutableByteSpan & subject) +CHIP_ERROR ExtractRawDNFromX509Cert(bool extractSubject, const ByteSpan & certificate, MutableByteSpan & dn) { +#if defined(MBEDTLS_X509_CRT_PARSE_C) CHIP_ERROR error = CHIP_NO_ERROR; int result = 0; uint8_t * p = nullptr; @@ -1874,28 +1874,50 @@ CHIP_ERROR ExtractRawSubjectFromX509Cert(const ByteSpan & certificate, MutableBy result = mbedtls_x509_crt_parse(&mbedCertificate, Uint8::to_const_uchar(certificate.data()), certificate.size()); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); - p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + if (extractSubject) + { + len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); + p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + } + else + { + len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(issuer_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); + p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(issuer_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + } - VerifyOrExit(len <= subject.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL); - memcpy(subject.data(), p, len); - subject.reduce_size(len); + VerifyOrExit(len <= dn.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(dn.data(), p, len); + dn.reduce_size(len); exit: _log_mbedTLS_error(result); mbedtls_x509_crt_free(&mbedCertificate); +#else + (void) certificate; + (void) dn; + CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; +#endif // defined(MBEDTLS_X509_CRT_PARSE_C) + return error; } -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) } // namespace +CHIP_ERROR ExtractSubjectFromX509Cert(const ByteSpan & certificate, MutableByteSpan & subject) +{ + return ExtractRawDNFromX509Cert(true, certificate, subject); +} + +CHIP_ERROR ExtractIssuerFromX509Cert(const ByteSpan & certificate, MutableByteSpan & issuer) +{ + return ExtractRawDNFromX509Cert(false, certificate, issuer); +} + CHIP_ERROR ReplaceCertIfResignedCertFound(const ByteSpan & referenceCertificate, const ByteSpan * candidateCertificates, size_t candidateCertificatesCount, ByteSpan & outCertificate) { #if defined(MBEDTLS_X509_CRT_PARSE_C) - constexpr size_t kMaxCertificateSubjectLength = 150; - uint8_t referenceSubjectBuf[kMaxCertificateSubjectLength]; + uint8_t referenceSubjectBuf[kMaxCertificateDistinguishedNameLength]; uint8_t referenceSKIDBuf[kSubjectKeyIdentifierLength]; MutableByteSpan referenceSubject(referenceSubjectBuf); MutableByteSpan referenceSKID(referenceSKIDBuf); @@ -1904,18 +1926,18 @@ CHIP_ERROR ReplaceCertIfResignedCertFound(const ByteSpan & referenceCertificate, ReturnErrorCodeIf(candidateCertificates == nullptr || candidateCertificatesCount == 0, CHIP_NO_ERROR); - ReturnErrorOnFailure(ExtractRawSubjectFromX509Cert(referenceCertificate, referenceSubject)); + ReturnErrorOnFailure(ExtractSubjectFromX509Cert(referenceCertificate, referenceSubject)); ReturnErrorOnFailure(ExtractSKIDFromX509Cert(referenceCertificate, referenceSKID)); for (size_t i = 0; i < candidateCertificatesCount; i++) { const ByteSpan candidateCertificate = candidateCertificates[i]; - uint8_t candidateSubjectBuf[kMaxCertificateSubjectLength]; + uint8_t candidateSubjectBuf[kMaxCertificateDistinguishedNameLength]; uint8_t candidateSKIDBuf[kSubjectKeyIdentifierLength]; MutableByteSpan candidateSubject(candidateSubjectBuf); MutableByteSpan candidateSKID(candidateSKIDBuf); - ReturnErrorOnFailure(ExtractRawSubjectFromX509Cert(candidateCertificate, candidateSubject)); + ReturnErrorOnFailure(ExtractSubjectFromX509Cert(candidateCertificate, candidateSubject)); ReturnErrorOnFailure(ExtractSKIDFromX509Cert(candidateCertificate, candidateSKID)); if (referenceSKID.data_equal(candidateSKID) && referenceSubject.data_equal(candidateSubject)) diff --git a/src/crypto/tests/CHIPCryptoPALTest.cpp b/src/crypto/tests/CHIPCryptoPALTest.cpp index 269acf11fb428b..117957bd091730 100644 --- a/src/crypto/tests/CHIPCryptoPALTest.cpp +++ b/src/crypto/tests/CHIPCryptoPALTest.cpp @@ -2174,6 +2174,135 @@ static void TestSerialNumber_x509Extraction(nlTestSuite * inSuite, void * inCont } } +static void TestSubject_x509Extraction(nlTestSuite * inSuite, void * inContext) +{ + using namespace TestCerts; + + HeapChecker heapChecker(inSuite); + CHIP_ERROR err = CHIP_NO_ERROR; + + struct TestCase + { + uint8_t Cert; + ChipDN mExpectedDN; + }; + + ChipDN subjectDN_Root01; + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == subjectDN_Root01.AddAttribute_MatterRCACId(0xCACACACA00000001)); + ChipDN subjectDN_ICA01; + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == subjectDN_ICA01.AddAttribute_MatterICACId(0xCACACACA00000003)); + ChipDN subjectDN_Node02_02; + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == subjectDN_Node02_02.AddAttribute_MatterNodeId(0xDEDEDEDE00020002)); + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == subjectDN_Node02_02.AddAttribute_MatterFabricId(0xFAB000000000001D)); + NL_TEST_ASSERT(inSuite, + CHIP_NO_ERROR == + subjectDN_Node02_02.AddAttribute_CommonName( + chip::CharSpan::fromCharString("TEST CERT COMMON NAME Attr for Node02_02"), false)); + ChipDN subjectDN_Node02_04; + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == subjectDN_Node02_04.AddAttribute_MatterCASEAuthTag(0xABCE1002)); + NL_TEST_ASSERT(inSuite, + CHIP_NO_ERROR == + subjectDN_Node02_04.AddAttribute_CommonName(chip::CharSpan::fromCharString("TestCert02_04"), false)); + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == subjectDN_Node02_04.AddAttribute_MatterFabricId(0xFAB000000000001D)); + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == subjectDN_Node02_04.AddAttribute_MatterCASEAuthTag(0xABCD0003)); + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == subjectDN_Node02_04.AddAttribute_MatterNodeId(0xDEDEDEDE00020004)); + ChipDN subjectDN_Node02_08; + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == subjectDN_Node02_08.AddAttribute_MatterCASEAuthTag(0xABCF00A0)); + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == subjectDN_Node02_08.AddAttribute_MatterNodeId(0xDEDEDEDE00020008)); + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == subjectDN_Node02_08.AddAttribute_MatterCASEAuthTag(0xABCD0020)); + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == subjectDN_Node02_08.AddAttribute_MatterFabricId(0xFAB000000000001D)); + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == subjectDN_Node02_08.AddAttribute_MatterCASEAuthTag(0xABCE0100)); + + // clang-format off + static TestCase sTestCases[] = { + // Cert Expected Output + // ============================================== + { TestCert::kRoot01, subjectDN_Root01 }, + { TestCert::kICA01, subjectDN_ICA01 }, + { TestCert::kNode02_02, subjectDN_Node02_02 }, + { TestCert::kNode02_04, subjectDN_Node02_04 }, + { TestCert::kNode02_08, subjectDN_Node02_08 }, + }; + // clang-format on + + for (auto & testCase : sTestCases) + { + ByteSpan cert; + err = GetTestCert(testCase.Cert, TestCertLoadFlags::kDERForm, cert); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + uint8_t subjectBuf[kMaxCertificateDistinguishedNameLength] = { 0 }; + MutableByteSpan subject(subjectBuf); + err = ExtractSubjectFromX509Cert(cert, subject); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + static uint8_t expectedSubjectBuf[kMaxCertificateDistinguishedNameLength] = { 0 }; + ASN1::ASN1Writer writer; + writer.Init(expectedSubjectBuf); + err = testCase.mExpectedDN.EncodeToASN1(writer); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + size_t expectedSubjectLen = writer.GetLengthWritten(); + NL_TEST_ASSERT(inSuite, expectedSubjectLen == subject.size()); + NL_TEST_ASSERT(inSuite, memcmp(subject.data(), expectedSubjectBuf, expectedSubjectLen) == 0); + } +} + +static void TestIssuer_x509Extraction(nlTestSuite * inSuite, void * inContext) +{ + using namespace TestCerts; + + HeapChecker heapChecker(inSuite); + CHIP_ERROR err = CHIP_NO_ERROR; + + struct TestCase + { + uint8_t Cert; + ChipDN mExpectedDN; + }; + + ChipDN issuerDN_Root01; + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == issuerDN_Root01.AddAttribute_MatterRCACId(0xCACACACA00000001)); + ChipDN issuerDN_ICA02; + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == issuerDN_ICA02.AddAttribute_MatterRCACId(0xCACACACA00000002)); + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == issuerDN_ICA02.AddAttribute_MatterFabricId(0xFAB000000000001D)); + ChipDN issuerDN_Node02_02; + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == issuerDN_Node02_02.AddAttribute_MatterICACId(0xCACACACA00000004)); + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == issuerDN_Node02_02.AddAttribute_MatterFabricId(0xFAB000000000001D)); + + // clang-format off + static TestCase sTestCases[] = { + // Cert Expected Output + // ============================================== + { TestCert::kRoot01, issuerDN_Root01 }, + { TestCert::kICA02, issuerDN_ICA02 }, + { TestCert::kNode02_02, issuerDN_Node02_02 }, + }; + // clang-format on + + for (auto & testCase : sTestCases) + { + ByteSpan cert; + err = GetTestCert(testCase.Cert, TestCertLoadFlags::kDERForm, cert); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + uint8_t issuerBuf[kMaxCertificateDistinguishedNameLength] = { 0 }; + MutableByteSpan issuer(issuerBuf); + err = ExtractIssuerFromX509Cert(cert, issuer); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + static uint8_t expectedIssuerBuf[kMaxCertificateDistinguishedNameLength] = { 0 }; + ASN1::ASN1Writer writer; + writer.Init(expectedIssuerBuf); + err = testCase.mExpectedDN.EncodeToASN1(writer); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + size_t expectedIssuerLen = writer.GetLengthWritten(); + NL_TEST_ASSERT(inSuite, expectedIssuerLen == issuer.size()); + NL_TEST_ASSERT(inSuite, memcmp(issuer.data(), expectedIssuerBuf, expectedIssuerLen) == 0); + } +} + static void TestVIDPID_StringExtraction(nlTestSuite * inSuite, void * inContext) { HeapChecker heapChecker(inSuite); @@ -2602,6 +2731,8 @@ static const nlTest sTests[] = { NL_TEST_DEF("Test Subject Key Id Extraction from x509 Certificate", TestSKID_x509Extraction), NL_TEST_DEF("Test Authority Key Id Extraction from x509 Certificate", TestAKID_x509Extraction), NL_TEST_DEF("Test Serial Number Extraction from x509 Certificate", TestSerialNumber_x509Extraction), + NL_TEST_DEF("Test Subject Extraction from x509 Certificate", TestSubject_x509Extraction), + NL_TEST_DEF("Test Issuer Extraction from x509 Certificate", TestIssuer_x509Extraction), NL_TEST_DEF("Test Vendor ID and Product ID Extraction from Attribute String", TestVIDPID_StringExtraction), NL_TEST_DEF("Test Vendor ID and Product ID Extraction from x509 Attestation Certificate", TestVIDPID_x509Extraction), NL_TEST_DEF("Test Replace Resigned Certificate Version if Found", TestX509_ReplaceCertIfResignedCertFound), diff --git a/src/platform/nxp/common/crypto/CHIPCryptoPALTinyCrypt.cpp b/src/platform/nxp/common/crypto/CHIPCryptoPALTinyCrypt.cpp index 292096f2a91fcd..b44916907cf1d5 100644 --- a/src/platform/nxp/common/crypto/CHIPCryptoPALTinyCrypt.cpp +++ b/src/platform/nxp/common/crypto/CHIPCryptoPALTinyCrypt.cpp @@ -1695,9 +1695,9 @@ CHIP_ERROR ExtractVIDPIDFromX509Cert(const ByteSpan & certificate, AttestationCe } namespace { -#if defined(MBEDTLS_X509_CRT_PARSE_C) -CHIP_ERROR ExtractRawSubjectFromX509Cert(const ByteSpan & certificate, MutableByteSpan & subject) +CHIP_ERROR ExtractRawDNFromX509Cert(bool extractSubject, const ByteSpan & certificate, MutableByteSpan & dn) { +#if defined(MBEDTLS_X509_CRT_PARSE_C) CHIP_ERROR error = CHIP_NO_ERROR; int result = 0; uint8_t * p = nullptr; @@ -1710,28 +1710,50 @@ CHIP_ERROR ExtractRawSubjectFromX509Cert(const ByteSpan & certificate, MutableBy result = mbedtls_x509_crt_parse(&mbedCertificate, Uint8::to_const_uchar(certificate.data()), certificate.size()); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); - p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + if (extractSubject) + { + len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); + p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + } + else + { + len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(issuer_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); + p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(issuer_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + } - VerifyOrExit(len <= subject.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL); - memcpy(subject.data(), p, len); - subject.reduce_size(len); + VerifyOrExit(len <= dn.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(dn.data(), p, len); + dn.reduce_size(len); exit: _log_mbedTLS_error(result); mbedtls_x509_crt_free(&mbedCertificate); +#else + (void) certificate; + (void) dn; + CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; +#endif // defined(MBEDTLS_X509_CRT_PARSE_C) + return error; } -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) } // namespace +CHIP_ERROR ExtractSubjectFromX509Cert(const ByteSpan & certificate, MutableByteSpan & subject) +{ + return ExtractRawDNFromX509Cert(true, certificate, subject); +} + +CHIP_ERROR ExtractIssuerFromX509Cert(const ByteSpan & certificate, MutableByteSpan & issuer) +{ + return ExtractRawDNFromX509Cert(false, certificate, issuer); +} + CHIP_ERROR ReplaceCertIfResignedCertFound(const ByteSpan & referenceCertificate, const ByteSpan * candidateCertificates, size_t candidateCertificatesCount, ByteSpan & outCertificate) { #if defined(MBEDTLS_X509_CRT_PARSE_C) - constexpr size_t kMaxCertificateSubjectLength = 150; - uint8_t referenceSubjectBuf[kMaxCertificateSubjectLength]; + uint8_t referenceSubjectBuf[kMaxCertificateDistinguishedNameLength]; uint8_t referenceSKIDBuf[kSubjectKeyIdentifierLength]; MutableByteSpan referenceSubject(referenceSubjectBuf); MutableByteSpan referenceSKID(referenceSKIDBuf); @@ -1740,18 +1762,18 @@ CHIP_ERROR ReplaceCertIfResignedCertFound(const ByteSpan & referenceCertificate, ReturnErrorCodeIf(candidateCertificates == nullptr || candidateCertificatesCount == 0, CHIP_NO_ERROR); - ReturnErrorOnFailure(ExtractRawSubjectFromX509Cert(referenceCertificate, referenceSubject)); + ReturnErrorOnFailure(ExtractSubjectFromX509Cert(referenceCertificate, referenceSubject)); ReturnErrorOnFailure(ExtractSKIDFromX509Cert(referenceCertificate, referenceSKID)); for (size_t i = 0; i < candidateCertificatesCount; i++) { const ByteSpan candidateCertificate = candidateCertificates[i]; - uint8_t candidateSubjectBuf[kMaxCertificateSubjectLength]; + uint8_t candidateSubjectBuf[kMaxCertificateDistinguishedNameLength]; uint8_t candidateSKIDBuf[kSubjectKeyIdentifierLength]; MutableByteSpan candidateSubject(candidateSubjectBuf); MutableByteSpan candidateSKID(candidateSKIDBuf); - ReturnErrorOnFailure(ExtractRawSubjectFromX509Cert(candidateCertificate, candidateSubject)); + ReturnErrorOnFailure(ExtractSubjectFromX509Cert(candidateCertificate, candidateSubject)); ReturnErrorOnFailure(ExtractSKIDFromX509Cert(candidateCertificate, candidateSKID)); if (referenceSKID.data_equal(candidateSKID) && referenceSubject.data_equal(candidateSubject)) diff --git a/src/platform/silabs/SiWx917/CHIPCryptoPALTinyCrypt.cpp b/src/platform/silabs/SiWx917/CHIPCryptoPALTinyCrypt.cpp index cfc4a5ec683cab..28224381971e2e 100644 --- a/src/platform/silabs/SiWx917/CHIPCryptoPALTinyCrypt.cpp +++ b/src/platform/silabs/SiWx917/CHIPCryptoPALTinyCrypt.cpp @@ -1695,9 +1695,9 @@ CHIP_ERROR ExtractVIDPIDFromX509Cert(const ByteSpan & certificate, AttestationCe } namespace { -#if defined(MBEDTLS_X509_CRT_PARSE_C) -CHIP_ERROR ExtractRawSubjectFromX509Cert(const ByteSpan & certificate, MutableByteSpan & subject) +CHIP_ERROR ExtractRawDNFromX509Cert(bool extractSubject, const ByteSpan & certificate, MutableByteSpan & dn) { +#if defined(MBEDTLS_X509_CRT_PARSE_C) CHIP_ERROR error = CHIP_NO_ERROR; int result = 0; uint8_t * p = nullptr; @@ -1710,28 +1710,50 @@ CHIP_ERROR ExtractRawSubjectFromX509Cert(const ByteSpan & certificate, MutableBy result = mbedtls_x509_crt_parse(&mbedCertificate, Uint8::to_const_uchar(certificate.data()), certificate.size()); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); - p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + if (extractSubject) + { + len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); + p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + } + else + { + len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(issuer_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); + p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(issuer_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + } - VerifyOrExit(len <= subject.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL); - memcpy(subject.data(), p, len); - subject.reduce_size(len); + VerifyOrExit(len <= dn.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(dn.data(), p, len); + dn.reduce_size(len); exit: _log_mbedTLS_error(result); mbedtls_x509_crt_free(&mbedCertificate); +#else + (void) certificate; + (void) dn; + CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; +#endif // defined(MBEDTLS_X509_CRT_PARSE_C) + return error; } -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) } // namespace +CHIP_ERROR ExtractSubjectFromX509Cert(const ByteSpan & certificate, MutableByteSpan & subject) +{ + return ExtractRawDNFromX509Cert(true, certificate, subject); +} + +CHIP_ERROR ExtractIssuerFromX509Cert(const ByteSpan & certificate, MutableByteSpan & issuer) +{ + return ExtractRawDNFromX509Cert(false, certificate, issuer); +} + CHIP_ERROR ReplaceCertIfResignedCertFound(const ByteSpan & referenceCertificate, const ByteSpan * candidateCertificates, size_t candidateCertificatesCount, ByteSpan & outCertificate) { #if defined(MBEDTLS_X509_CRT_PARSE_C) - constexpr size_t kMaxCertificateSubjectLength = 150; - uint8_t referenceSubjectBuf[kMaxCertificateSubjectLength]; + uint8_t referenceSubjectBuf[kMaxCertificateDistinguishedNameLength]; uint8_t referenceSKIDBuf[kSubjectKeyIdentifierLength]; MutableByteSpan referenceSubject(referenceSubjectBuf); MutableByteSpan referenceSKID(referenceSKIDBuf); @@ -1740,18 +1762,18 @@ CHIP_ERROR ReplaceCertIfResignedCertFound(const ByteSpan & referenceCertificate, ReturnErrorCodeIf(candidateCertificates == nullptr || candidateCertificatesCount == 0, CHIP_NO_ERROR); - ReturnErrorOnFailure(ExtractRawSubjectFromX509Cert(referenceCertificate, referenceSubject)); + ReturnErrorOnFailure(ExtractSubjectFromX509Cert(referenceCertificate, referenceSubject)); ReturnErrorOnFailure(ExtractSKIDFromX509Cert(referenceCertificate, referenceSKID)); for (size_t i = 0; i < candidateCertificatesCount; i++) { const ByteSpan candidateCertificate = candidateCertificates[i]; - uint8_t candidateSubjectBuf[kMaxCertificateSubjectLength]; + uint8_t candidateSubjectBuf[kMaxCertificateDistinguishedNameLength]; uint8_t candidateSKIDBuf[kSubjectKeyIdentifierLength]; MutableByteSpan candidateSubject(candidateSubjectBuf); MutableByteSpan candidateSKID(candidateSKIDBuf); - ReturnErrorOnFailure(ExtractRawSubjectFromX509Cert(candidateCertificate, candidateSubject)); + ReturnErrorOnFailure(ExtractSubjectFromX509Cert(candidateCertificate, candidateSubject)); ReturnErrorOnFailure(ExtractSKIDFromX509Cert(candidateCertificate, candidateSKID)); if (referenceSKID.data_equal(candidateSKID) && referenceSubject.data_equal(candidateSubject)) diff --git a/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp b/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp index 236efb1d453172..f4acdbc76c3804 100644 --- a/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp +++ b/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp @@ -2056,9 +2056,9 @@ CHIP_ERROR ExtractVIDPIDFromX509Cert(const ByteSpan & certificate, AttestationCe } namespace { -#if defined(MBEDTLS_X509_CRT_PARSE_C) -CHIP_ERROR ExtractRawSubjectFromX509Cert(const ByteSpan & certificate, MutableByteSpan & subject) +CHIP_ERROR ExtractRawDNFromX509Cert(bool extractSubject, const ByteSpan & certificate, MutableByteSpan & dn) { +#if defined(MBEDTLS_X509_CRT_PARSE_C) CHIP_ERROR error = CHIP_NO_ERROR; int result = 0; uint8_t * p = nullptr; @@ -2071,28 +2071,50 @@ CHIP_ERROR ExtractRawSubjectFromX509Cert(const ByteSpan & certificate, MutableBy result = mbedtls_x509_crt_parse(&mbedCertificate, Uint8::to_const_uchar(certificate.data()), certificate.size()); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); - p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + if (extractSubject) + { + len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); + p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + } + else + { + len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(issuer_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); + p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(issuer_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + } - VerifyOrExit(len <= subject.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL); - memcpy(subject.data(), p, len); - subject.reduce_size(len); + VerifyOrExit(len <= dn.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(dn.data(), p, len); + dn.reduce_size(len); exit: _log_mbedTLS_error(result); mbedtls_x509_crt_free(&mbedCertificate); +#else + (void) certificate; + (void) dn; + CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; +#endif // defined(MBEDTLS_X509_CRT_PARSE_C) + return error; } -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) } // namespace +CHIP_ERROR ExtractSubjectFromX509Cert(const ByteSpan & certificate, MutableByteSpan & subject) +{ + return ExtractRawDNFromX509Cert(true, certificate, subject); +} + +CHIP_ERROR ExtractIssuerFromX509Cert(const ByteSpan & certificate, MutableByteSpan & issuer) +{ + return ExtractRawDNFromX509Cert(false, certificate, issuer); +} + CHIP_ERROR ReplaceCertIfResignedCertFound(const ByteSpan & referenceCertificate, const ByteSpan * candidateCertificates, size_t candidateCertificatesCount, ByteSpan & outCertificate) { #if defined(MBEDTLS_X509_CRT_PARSE_C) - constexpr size_t kMaxCertificateSubjectLength = 150; - uint8_t referenceSubjectBuf[kMaxCertificateSubjectLength]; + uint8_t referenceSubjectBuf[kMaxCertificateDistinguishedNameLength]; uint8_t referenceSKIDBuf[kSubjectKeyIdentifierLength]; MutableByteSpan referenceSubject(referenceSubjectBuf); MutableByteSpan referenceSKID(referenceSKIDBuf); @@ -2101,18 +2123,18 @@ CHIP_ERROR ReplaceCertIfResignedCertFound(const ByteSpan & referenceCertificate, ReturnErrorCodeIf(candidateCertificates == nullptr || candidateCertificatesCount == 0, CHIP_NO_ERROR); - ReturnErrorOnFailure(ExtractRawSubjectFromX509Cert(referenceCertificate, referenceSubject)); + ReturnErrorOnFailure(ExtractSubjectFromX509Cert(referenceCertificate, referenceSubject)); ReturnErrorOnFailure(ExtractSKIDFromX509Cert(referenceCertificate, referenceSKID)); for (size_t i = 0; i < candidateCertificatesCount; i++) { const ByteSpan candidateCertificate = candidateCertificates[i]; - uint8_t candidateSubjectBuf[kMaxCertificateSubjectLength]; + uint8_t candidateSubjectBuf[kMaxCertificateDistinguishedNameLength]; uint8_t candidateSKIDBuf[kSubjectKeyIdentifierLength]; MutableByteSpan candidateSubject(candidateSubjectBuf); MutableByteSpan candidateSKID(candidateSKIDBuf); - ReturnErrorOnFailure(ExtractRawSubjectFromX509Cert(candidateCertificate, candidateSubject)); + ReturnErrorOnFailure(ExtractSubjectFromX509Cert(candidateCertificate, candidateSubject)); ReturnErrorOnFailure(ExtractSKIDFromX509Cert(candidateCertificate, candidateSKID)); if (referenceSKID.data_equal(candidateSKID) && referenceSubject.data_equal(candidateSubject))