From e66e762f55bceb5a0e212cebf7f145563939a06f Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Wed, 29 May 2024 13:01:12 +0530 Subject: [PATCH 01/19] dac revocation: default implementation of CheckForRevokedDACChain --- src/credentials/BUILD.gn | 2 + .../DefaultDeviceAttestationVerifier.cpp | 131 +++++++++++++++++- .../DefaultDeviceAttestationVerifier.h | 17 +++ 3 files changed, 149 insertions(+), 1 deletion(-) diff --git a/src/credentials/BUILD.gn b/src/credentials/BUILD.gn index df7afc0c1025ba..0ade3c13bcf072 100644 --- a/src/credentials/BUILD.gn +++ b/src/credentials/BUILD.gn @@ -13,6 +13,7 @@ # limitations under the License. import("//build_overrides/chip.gni") +import("//build_overrides/jsoncpp.gni") import("//build_overrides/nlassert.gni") import("${chip_root}/src/crypto/crypto.gni") import("${chip_root}/src/lib/core/core.gni") @@ -169,6 +170,7 @@ static_library("default_attestation_verifier") { ":test_paa_store", "${chip_root}/src/crypto", "${nlassert_root}:nlassert", + jsoncpp_root, ] } diff --git a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp index f3444b0c303940..73252e04962129 100644 --- a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp +++ b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp @@ -26,10 +26,16 @@ #include #include +#include +#include #include #include #include +#include +#include +#include + using namespace chip::Crypto; using chip::TestCerts::GetTestPaaRootStore; @@ -607,12 +613,135 @@ CHIP_ERROR DefaultDACVerifier::VerifyNodeOperationalCSRInformation(const ByteSpa return CHIP_NO_ERROR; } +bool DefaultDACVerifier::IsEntryExistsInRevocationSet(const CharSpan & akidHexStr, const CharSpan & issuerNameBase64Str, + const CharSpan & serialNumberHexStr) +{ + std::ifstream file(mDeviceAttestationRevocationSetPath); + if (!file.is_open()) + { + return false; + } + + // Parse the JSON data incrementally + Json::CharReaderBuilder readerBuilder; + Json::Value jsonData; + std::string errs; + + bool parsingSuccessful = Json::parseFromStream(readerBuilder, file, &jsonData, &errs); + + // Close the file as it's no longer needed + file.close(); + + if (!parsingSuccessful) + { + return false; + } + + for (const auto & revokedSet : jsonData) + { + if (strncmp(revokedSet["issuer_name"].asCString(), issuerNameBase64Str.data(), issuerNameBase64Str.size()) == 0 && + strncmp(revokedSet["issuer_subject_key_id"].asCString(), akidHexStr.data(), akidHexStr.size()) == 0) + { + for (const auto & revokedSerialNumber : revokedSet["revoked_serial_numbers"]) + { + if (strncmp(revokedSerialNumber.asCString(), serialNumberHexStr.data(), serialNumberHexStr.size()) == 0) + { + return true; + } + } + } + } + return false; +} + +CHIP_ERROR DefaultDACVerifier::GetAKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outAKIDHexStr) +{ + uint8_t akidBuf[kAuthorityKeyIdentifierLength]; + MutableByteSpan akid(akidBuf); + + CHIP_ERROR err = ExtractAKIDFromX509Cert(certDer, akid); + VerifyOrReturnError(err == CHIP_NO_ERROR, err); + VerifyOrReturnError(outAKIDHexStr.size() > akid.size() * 2, CHIP_ERROR_BUFFER_TOO_SMALL); + + Encoding::HexFlags flags = Encoding::HexFlags::kUppercaseAndNullTerminate; + err = BytesToHex(akid.data(), akid.size(), outAKIDHexStr.data(), outAKIDHexStr.size(), flags); + VerifyOrReturnError(err == CHIP_NO_ERROR, err); + + outAKIDHexStr.reduce_size(strlen(outAKIDHexStr.data())); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DefaultDACVerifier::GetSerialNumberHexStr(const ByteSpan & certDer, MutableCharSpan & outSerialNumberHexStr) +{ + uint8_t serialNumberBuf[kMaxCertificateSerialNumberLength] = { 0 }; + MutableByteSpan serialNumber(serialNumberBuf); + + CHIP_ERROR err = ExtractSerialNumberFromX509Cert(certDer, serialNumber); + VerifyOrReturnError(err == CHIP_NO_ERROR, err); + VerifyOrReturnError(outSerialNumberHexStr.size() > serialNumber.size() * 2, CHIP_ERROR_BUFFER_TOO_SMALL); + + Encoding::HexFlags flags = Encoding::HexFlags::kUppercaseAndNullTerminate; + err = BytesToHex(serialNumber.data(), serialNumber.size(), outSerialNumberHexStr.data(), outSerialNumberHexStr.size(), flags); + VerifyOrReturnError(err == CHIP_NO_ERROR, err); + + outSerialNumberHexStr.reduce_size(strlen(outSerialNumberHexStr.data())); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DefaultDACVerifier::GetIssuerNameBase64Str(const ByteSpan & certDer, MutableCharSpan & outIssuerNameBase64String) +{ + uint8_t issuerBuf[kMaxCertificateDistinguishedNameLength] = { 0 }; + MutableByteSpan issuer(issuerBuf); + + CHIP_ERROR err = ExtractIssuerFromX509Cert(certDer, issuer); + VerifyOrReturnError(CHIP_NO_ERROR == err, err); + VerifyOrReturnError(outIssuerNameBase64String.size() > BASE64_ENCODED_LEN(issuer.size()), CHIP_ERROR_BUFFER_TOO_SMALL); + + uint32_t encodedLen = Base64Encode32(issuer.data(), static_cast(issuer.size()), outIssuerNameBase64String.data()); + outIssuerNameBase64String.reduce_size(encodedLen); + return CHIP_NO_ERROR; +} + +bool DefaultDACVerifier::IsCertificateRevoked(const ByteSpan & certDer) +{ + static constexpr uint32_t maxIssuerBase64Len = BASE64_ENCODED_LEN(kMaxCertificateDistinguishedNameLength) + 1; + + char issuerNameBuffer[maxIssuerBase64Len] = { 0 }; + char serialNumberHexStrBuffer[2 * kMaxCertificateSerialNumberLength + 1] = { 0 }; + char akidHexStrBuffer[2 * kAuthorityKeyIdentifierLength + 1] = { 0 }; + + MutableCharSpan issuerName(issuerNameBuffer); + MutableCharSpan serialNumber(serialNumberHexStrBuffer); + MutableCharSpan akid(akidHexStrBuffer); + + CHIP_ERROR err = GetIssuerNameBase64Str(certDer, issuerName); + VerifyOrReturnValue(err == CHIP_NO_ERROR, false); + + err = GetSerialNumberHexStr(certDer, serialNumber); + VerifyOrReturnValue(err == CHIP_NO_ERROR, false); + + err = GetAKIDHexStr(certDer, akid); + VerifyOrReturnValue(err == CHIP_NO_ERROR, false); + + return IsEntryExistsInRevocationSet(akid, issuerName, serialNumber); +} + void DefaultDACVerifier::CheckForRevokedDACChain(const AttestationInfo & info, Callback::Callback * onCompletion) { AttestationVerificationResult attestationError = AttestationVerificationResult::kSuccess; - // TODO(#33124): Implement default version of CheckForRevokedDACChain + if (mDeviceAttestationRevocationSetPath != nullptr) + { + if (IsCertificateRevoked(info.dacDerBuffer)) + { + attestationError = AttestationVerificationResult::kDacRevoked; + } + if (IsCertificateRevoked(info.paiDerBuffer)) + { + attestationError = AttestationVerificationResult::kPaiRevoked; + } + } onCompletion->mCall(onCompletion->mContext, info, attestationError); } diff --git a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h index 346d098a58a337..8573897b8a1cc5 100644 --- a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h +++ b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h @@ -77,6 +77,9 @@ class DefaultDACVerifier : public DeviceAttestationVerifier void CheckForRevokedDACChain(const AttestationInfo & info, Callback::Callback * onCompletion) override; + // Set the path to the device attestation revocation set JSON file. + void SetDeviceAttestationRevocationSetPath(const char * path) { mDeviceAttestationRevocationSetPath = path; } + CsaCdKeysTrustStore * GetCertificationDeclarationTrustStore() override { return &mCdKeysTrustStore; } protected: @@ -84,6 +87,20 @@ class DefaultDACVerifier : public DeviceAttestationVerifier CsaCdKeysTrustStore mCdKeysTrustStore; const AttestationTrustStore * mAttestationTrustStore; + +private: + CHIP_ERROR GetAKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outAKIDHexString); + CHIP_ERROR GetSerialNumberHexStr(const ByteSpan & certDer, MutableCharSpan & outSerialNumberHexString); + CHIP_ERROR GetIssuerNameBase64Str(const ByteSpan & certDer, MutableCharSpan & outIssuerNameBase64String); + + bool IsCertificateRevoked(const ByteSpan & certDer); + + // Searches the revocation set and returns true if for the given AKID, issuer name and serial number + // the entry is found in the revocation set, false otherwise. + bool IsEntryExistsInRevocationSet(const CharSpan & akidHexStr, const CharSpan & issuerNameBase64Str, + const CharSpan & serialNumberHexStr); + + const char * mDeviceAttestationRevocationSetPath = nullptr; }; /** From 7bfe98cc23dd968d0cb28eb30f298358151dea0a Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Wed, 29 May 2024 13:03:32 +0530 Subject: [PATCH 02/19] option to configure the revocation set file in chip-tool --- examples/chip-tool/commands/common/CHIPCommand.cpp | 2 ++ examples/chip-tool/commands/common/CHIPCommand.h | 3 +++ .../commands/common/CredentialIssuerCommands.h | 9 +++++++++ .../example/ExampleCredentialIssuerCommands.h | 11 +++++++++++ 4 files changed, 25 insertions(+) diff --git a/examples/chip-tool/commands/common/CHIPCommand.cpp b/examples/chip-tool/commands/common/CHIPCommand.cpp index 7e871f8e781e14..6a25794f945b07 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.cpp +++ b/examples/chip-tool/commands/common/CHIPCommand.cpp @@ -452,6 +452,8 @@ CHIP_ERROR CHIPCommand::InitializeCommissioner(CommissionerIdentity & identity, ReturnLogErrorOnFailure(mCredIssuerCmds->SetupDeviceAttestation(commissionerParams, sTrustStore)); + mCredIssuerCmds->SetupDeviceAttestationRevocationSetPath(mDacRevocationSetPath.ValueOr(nullptr)); + chip::Crypto::P256Keypair ephemeralKey; if (fabricId != chip::kUndefinedFabricId) diff --git a/examples/chip-tool/commands/common/CHIPCommand.h b/examples/chip-tool/commands/common/CHIPCommand.h index 50ab851d284502..efc7cc4b7bbc82 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.h +++ b/examples/chip-tool/commands/common/CHIPCommand.h @@ -86,6 +86,8 @@ class CHIPCommand : public Command AddArgument("only-allow-trusted-cd-keys", 0, 1, &mOnlyAllowTrustedCdKeys, "Only allow trusted CD verifying keys (disallow test keys). If not provided or 0 (\"false\"), untrusted CD " "verifying keys are allowed. If 1 (\"true\"), test keys are disallowed."); + AddArgument("dac-revocation-set-path", &mDacRevocationSetPath, + "Path to json file containing the device attestation revocation set."); #if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED AddArgument("trace_file", &mTraceFile); AddArgument("trace_log", 0, 1, &mTraceLog); @@ -222,6 +224,7 @@ class CHIPCommand : public Command chip::Optional mCDTrustStorePath; chip::Optional mUseMaxSizedCerts; chip::Optional mOnlyAllowTrustedCdKeys; + chip::Optional mDacRevocationSetPath; // Cached trust store so commands other than the original startup command // can spin up commissioners as needed. diff --git a/examples/chip-tool/commands/common/CredentialIssuerCommands.h b/examples/chip-tool/commands/common/CredentialIssuerCommands.h index fd096b31835723..61d6fa233e509d 100644 --- a/examples/chip-tool/commands/common/CredentialIssuerCommands.h +++ b/examples/chip-tool/commands/common/CredentialIssuerCommands.h @@ -62,6 +62,15 @@ class CredentialIssuerCommands virtual CHIP_ERROR SetupDeviceAttestation(chip::Controller::SetupParams & setupParams, const chip::Credentials::AttestationTrustStore * trustStore) = 0; + /** + * @brief + * This function is used to set the path to Device Attestation revocation set JSON file. + * + * @param[in] path Path to the JSON file containing list of revoked DACs or PAIs. + * It can be generated using credentials/generate-revocation-set.py script + */ + virtual void SetupDeviceAttestationRevocationSetPath(const char * path) = 0; + /** * @brief Add a list of additional non-default CD verifying keys (by certificate) * diff --git a/examples/chip-tool/commands/example/ExampleCredentialIssuerCommands.h b/examples/chip-tool/commands/example/ExampleCredentialIssuerCommands.h index a23b45eae10627..4e926967aadc62 100644 --- a/examples/chip-tool/commands/example/ExampleCredentialIssuerCommands.h +++ b/examples/chip-tool/commands/example/ExampleCredentialIssuerCommands.h @@ -44,6 +44,17 @@ class ExampleCredentialIssuerCommands : public CredentialIssuerCommands return CHIP_NO_ERROR; } + + void SetupDeviceAttestationRevocationSetPath(const char * path) override + { + if (path) + { + // As we know that we are using DefaultDACVerifier, we can downcast from + // DeviceAttestationVerifier to DefaultDACVerifier to set the revocation set + static_cast(mDacVerifier)->SetDeviceAttestationRevocationSetPath(path); + } + } + chip::Controller::OperationalCredentialsDelegate * GetCredentialIssuer() override { return &mOpCredsIssuer; } void SetCredentialIssuerCATValues(chip::CATValues cats) override { mOpCredsIssuer.SetCATValuesForNextNOCRequest(cats); } CHIP_ERROR GenerateControllerNOCChain(chip::NodeId nodeId, chip::FabricId fabricId, const chip::CATValues & cats, From 20a0e0bb3748e0dedce4b82227ee8278e99df47f Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Wed, 29 May 2024 13:17:07 +0530 Subject: [PATCH 03/19] Added few comments --- .../DefaultDeviceAttestationVerifier.cpp | 13 +++++++++++++ .../DefaultDeviceAttestationVerifier.h | 1 + 2 files changed, 14 insertions(+) diff --git a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp index 73252e04962129..504c25e93f0fbf 100644 --- a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp +++ b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp @@ -613,6 +613,19 @@ CHIP_ERROR DefaultDACVerifier::VerifyNodeOperationalCSRInformation(const ByteSpa return CHIP_NO_ERROR; } + +// This method parses the below JSON Scheme +// [ +// { +// "type": "revocation_set", +// "issuer_subject_key_id": "63540E47F64B1C38D13884A462D16C195D8FFB3C", +// "issuer_name": "MD0xJTAjBgNVBAMMHE1hdHRlciBEZXYgUEFJIDB4RkZGMSBubyBQSUQxFDASBgorBgEEAYKifAIBDARGRkYx", +// "revoked_serial_numbers": [ +// "69CDF10DE9E54ED1" +// ] +// } +// ] +// bool DefaultDACVerifier::IsEntryExistsInRevocationSet(const CharSpan & akidHexStr, const CharSpan & issuerNameBase64Str, const CharSpan & serialNumberHexStr) { diff --git a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h index 8573897b8a1cc5..e499ae065caa14 100644 --- a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h +++ b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h @@ -78,6 +78,7 @@ class DefaultDACVerifier : public DeviceAttestationVerifier Callback::Callback * onCompletion) override; // Set the path to the device attestation revocation set JSON file. + // revocation set can be generated using credentials/generate-revocation-set.py script void SetDeviceAttestationRevocationSetPath(const char * path) { mDeviceAttestationRevocationSetPath = path; } CsaCdKeysTrustStore * GetCertificationDeclarationTrustStore() override { return &mCdKeysTrustStore; } From c4dd7d584969ad051023398fd8b5c65ba76559c4 Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Wed, 29 May 2024 13:27:22 +0530 Subject: [PATCH 04/19] restyle --- .../attestation_verifier/DefaultDeviceAttestationVerifier.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp index 504c25e93f0fbf..fbd909a13dc9f8 100644 --- a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp +++ b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp @@ -613,7 +613,6 @@ CHIP_ERROR DefaultDACVerifier::VerifyNodeOperationalCSRInformation(const ByteSpa return CHIP_NO_ERROR; } - // This method parses the below JSON Scheme // [ // { From bdaf0ad6e25345929f9fdaa900ce51819233e956 Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Wed, 29 May 2024 13:57:41 +0530 Subject: [PATCH 05/19] add fstream to allow list of DefaultDeviceAttestationVerifier --- scripts/tools/check_includes_config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/tools/check_includes_config.py b/scripts/tools/check_includes_config.py index 20c853b9906df8..c50d82ba657d19 100644 --- a/scripts/tools/check_includes_config.py +++ b/scripts/tools/check_includes_config.py @@ -137,6 +137,7 @@ 'src/credentials/attestation_verifier/FileAttestationTrustStore.h': {'vector'}, 'src/credentials/attestation_verifier/FileAttestationTrustStore.cpp': {'string'}, + 'src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp': {'fstream'}, 'src/setup_payload/AdditionalDataPayload.h': {'string'}, 'src/setup_payload/AdditionalDataPayloadParser.cpp': {'vector', 'string'}, From 981e03a1532c13928e1a0ffed9f9307b120dc9e1 Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Mon, 24 Jun 2024 12:36:36 +0530 Subject: [PATCH 06/19] Address comments Added an interface for device attestation revocation and the test implementation for the same. --- .../chip-tool/commands/common/CHIPCommand.cpp | 5 +- .../common/CredentialIssuerCommands.h | 4 +- .../example/ExampleCredentialIssuerCommands.h | 14 +- scripts/tools/check_includes_config.py | 2 +- src/credentials/BUILD.gn | 2 + .../DefaultDeviceAttestationVerifier.cpp | 150 +------------ .../DefaultDeviceAttestationVerifier.h | 18 -- .../DeviceAttestationVerifier.h | 28 +++ .../TestDACRevocationDelegateImpl.cpp | 197 ++++++++++++++++++ .../TestDACRevocationDelegateImpl.h | 59 ++++++ 10 files changed, 307 insertions(+), 172 deletions(-) create mode 100644 src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp create mode 100644 src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h diff --git a/examples/chip-tool/commands/common/CHIPCommand.cpp b/examples/chip-tool/commands/common/CHIPCommand.cpp index 6a25794f945b07..b953c2bc686133 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.cpp +++ b/examples/chip-tool/commands/common/CHIPCommand.cpp @@ -452,7 +452,10 @@ CHIP_ERROR CHIPCommand::InitializeCommissioner(CommissionerIdentity & identity, ReturnLogErrorOnFailure(mCredIssuerCmds->SetupDeviceAttestation(commissionerParams, sTrustStore)); - mCredIssuerCmds->SetupDeviceAttestationRevocationSetPath(mDacRevocationSetPath.ValueOr(nullptr)); + if (mDacRevocationSetPath.HasValue()) + { + ReturnLogErrorOnFailure(mCredIssuerCmds->SetDeviceAttestationRevocationSetPath(mDacRevocationSetPath.Value())); + } chip::Crypto::P256Keypair ephemeralKey; diff --git a/examples/chip-tool/commands/common/CredentialIssuerCommands.h b/examples/chip-tool/commands/common/CredentialIssuerCommands.h index 61d6fa233e509d..4df8cc19eff770 100644 --- a/examples/chip-tool/commands/common/CredentialIssuerCommands.h +++ b/examples/chip-tool/commands/common/CredentialIssuerCommands.h @@ -68,8 +68,10 @@ class CredentialIssuerCommands * * @param[in] path Path to the JSON file containing list of revoked DACs or PAIs. * It can be generated using credentials/generate-revocation-set.py script + * + * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error code. */ - virtual void SetupDeviceAttestationRevocationSetPath(const char * path) = 0; + virtual CHIP_ERROR SetDeviceAttestationRevocationSetPath(const char * path) = 0; /** * @brief Add a list of additional non-default CD verifying keys (by certificate) diff --git a/examples/chip-tool/commands/example/ExampleCredentialIssuerCommands.h b/examples/chip-tool/commands/example/ExampleCredentialIssuerCommands.h index 4e926967aadc62..e9c6df74b2855e 100644 --- a/examples/chip-tool/commands/example/ExampleCredentialIssuerCommands.h +++ b/examples/chip-tool/commands/example/ExampleCredentialIssuerCommands.h @@ -24,6 +24,7 @@ #include #include #include +#include #include class ExampleCredentialIssuerCommands : public CredentialIssuerCommands @@ -45,14 +46,12 @@ class ExampleCredentialIssuerCommands : public CredentialIssuerCommands return CHIP_NO_ERROR; } - void SetupDeviceAttestationRevocationSetPath(const char * path) override + CHIP_ERROR SetDeviceAttestationRevocationSetPath(const char * path) override { - if (path) - { - // As we know that we are using DefaultDACVerifier, we can downcast from - // DeviceAttestationVerifier to DefaultDACVerifier to set the revocation set - static_cast(mDacVerifier)->SetDeviceAttestationRevocationSetPath(path); - } + VerifyOrReturnError(path != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + ReturnErrorOnFailure(mTestDacRevocationDelegate.SetDeviceAttestationRevocationSetPath(path)); + mDacVerifier->SetRevocationDelegate(&mTestDacRevocationDelegate); + return CHIP_NO_ERROR; } chip::Controller::OperationalCredentialsDelegate * GetCredentialIssuer() override { return &mOpCredsIssuer; } @@ -119,4 +118,5 @@ class ExampleCredentialIssuerCommands : public CredentialIssuerCommands private: chip::Controller::ExampleOperationalCredentialsIssuer mOpCredsIssuer; chip::Credentials::DeviceAttestationVerifier * mDacVerifier; + chip::Credentials::TestDACRevocationDelegateImpl mTestDacRevocationDelegate; }; diff --git a/scripts/tools/check_includes_config.py b/scripts/tools/check_includes_config.py index c50d82ba657d19..2d0152a02c808b 100644 --- a/scripts/tools/check_includes_config.py +++ b/scripts/tools/check_includes_config.py @@ -137,7 +137,7 @@ 'src/credentials/attestation_verifier/FileAttestationTrustStore.h': {'vector'}, 'src/credentials/attestation_verifier/FileAttestationTrustStore.cpp': {'string'}, - 'src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp': {'fstream'}, + 'src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp': {'fstream'}, 'src/setup_payload/AdditionalDataPayload.h': {'string'}, 'src/setup_payload/AdditionalDataPayloadParser.cpp': {'vector', 'string'}, diff --git a/src/credentials/BUILD.gn b/src/credentials/BUILD.gn index 0ade3c13bcf072..35b0f15903cd1b 100644 --- a/src/credentials/BUILD.gn +++ b/src/credentials/BUILD.gn @@ -158,6 +158,8 @@ static_library("default_attestation_verifier") { "attestation_verifier/DefaultDeviceAttestationVerifier.cpp", "attestation_verifier/DefaultDeviceAttestationVerifier.h", "attestation_verifier/DeviceAttestationDelegate.h", + "attestation_verifier/TestDACRevocationDelegateImpl.cpp", + "attestation_verifier/TestDACRevocationDelegateImpl.h", ] if (chip_device_platform == "esp32" || chip_device_platform == "nrfconnect" || diff --git a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp index fbd909a13dc9f8..b594a10f69006e 100644 --- a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp +++ b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp @@ -26,16 +26,10 @@ #include #include -#include -#include #include #include #include -#include -#include -#include - using namespace chip::Crypto; using chip::TestCerts::GetTestPaaRootStore; @@ -613,149 +607,17 @@ CHIP_ERROR DefaultDACVerifier::VerifyNodeOperationalCSRInformation(const ByteSpa return CHIP_NO_ERROR; } -// This method parses the below JSON Scheme -// [ -// { -// "type": "revocation_set", -// "issuer_subject_key_id": "63540E47F64B1C38D13884A462D16C195D8FFB3C", -// "issuer_name": "MD0xJTAjBgNVBAMMHE1hdHRlciBEZXYgUEFJIDB4RkZGMSBubyBQSUQxFDASBgorBgEEAYKifAIBDARGRkYx", -// "revoked_serial_numbers": [ -// "69CDF10DE9E54ED1" -// ] -// } -// ] -// -bool DefaultDACVerifier::IsEntryExistsInRevocationSet(const CharSpan & akidHexStr, const CharSpan & issuerNameBase64Str, - const CharSpan & serialNumberHexStr) -{ - std::ifstream file(mDeviceAttestationRevocationSetPath); - if (!file.is_open()) - { - return false; - } - - // Parse the JSON data incrementally - Json::CharReaderBuilder readerBuilder; - Json::Value jsonData; - std::string errs; - - bool parsingSuccessful = Json::parseFromStream(readerBuilder, file, &jsonData, &errs); - - // Close the file as it's no longer needed - file.close(); - - if (!parsingSuccessful) - { - return false; - } - - for (const auto & revokedSet : jsonData) - { - if (strncmp(revokedSet["issuer_name"].asCString(), issuerNameBase64Str.data(), issuerNameBase64Str.size()) == 0 && - strncmp(revokedSet["issuer_subject_key_id"].asCString(), akidHexStr.data(), akidHexStr.size()) == 0) - { - for (const auto & revokedSerialNumber : revokedSet["revoked_serial_numbers"]) - { - if (strncmp(revokedSerialNumber.asCString(), serialNumberHexStr.data(), serialNumberHexStr.size()) == 0) - { - return true; - } - } - } - } - return false; -} - -CHIP_ERROR DefaultDACVerifier::GetAKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outAKIDHexStr) -{ - uint8_t akidBuf[kAuthorityKeyIdentifierLength]; - MutableByteSpan akid(akidBuf); - - CHIP_ERROR err = ExtractAKIDFromX509Cert(certDer, akid); - VerifyOrReturnError(err == CHIP_NO_ERROR, err); - VerifyOrReturnError(outAKIDHexStr.size() > akid.size() * 2, CHIP_ERROR_BUFFER_TOO_SMALL); - - Encoding::HexFlags flags = Encoding::HexFlags::kUppercaseAndNullTerminate; - err = BytesToHex(akid.data(), akid.size(), outAKIDHexStr.data(), outAKIDHexStr.size(), flags); - VerifyOrReturnError(err == CHIP_NO_ERROR, err); - - outAKIDHexStr.reduce_size(strlen(outAKIDHexStr.data())); - return CHIP_NO_ERROR; -} - -CHIP_ERROR DefaultDACVerifier::GetSerialNumberHexStr(const ByteSpan & certDer, MutableCharSpan & outSerialNumberHexStr) -{ - uint8_t serialNumberBuf[kMaxCertificateSerialNumberLength] = { 0 }; - MutableByteSpan serialNumber(serialNumberBuf); - - CHIP_ERROR err = ExtractSerialNumberFromX509Cert(certDer, serialNumber); - VerifyOrReturnError(err == CHIP_NO_ERROR, err); - VerifyOrReturnError(outSerialNumberHexStr.size() > serialNumber.size() * 2, CHIP_ERROR_BUFFER_TOO_SMALL); - - Encoding::HexFlags flags = Encoding::HexFlags::kUppercaseAndNullTerminate; - err = BytesToHex(serialNumber.data(), serialNumber.size(), outSerialNumberHexStr.data(), outSerialNumberHexStr.size(), flags); - VerifyOrReturnError(err == CHIP_NO_ERROR, err); - - outSerialNumberHexStr.reduce_size(strlen(outSerialNumberHexStr.data())); - return CHIP_NO_ERROR; -} - -CHIP_ERROR DefaultDACVerifier::GetIssuerNameBase64Str(const ByteSpan & certDer, MutableCharSpan & outIssuerNameBase64String) -{ - uint8_t issuerBuf[kMaxCertificateDistinguishedNameLength] = { 0 }; - MutableByteSpan issuer(issuerBuf); - - CHIP_ERROR err = ExtractIssuerFromX509Cert(certDer, issuer); - VerifyOrReturnError(CHIP_NO_ERROR == err, err); - VerifyOrReturnError(outIssuerNameBase64String.size() > BASE64_ENCODED_LEN(issuer.size()), CHIP_ERROR_BUFFER_TOO_SMALL); - - uint32_t encodedLen = Base64Encode32(issuer.data(), static_cast(issuer.size()), outIssuerNameBase64String.data()); - outIssuerNameBase64String.reduce_size(encodedLen); - return CHIP_NO_ERROR; -} - -bool DefaultDACVerifier::IsCertificateRevoked(const ByteSpan & certDer) -{ - static constexpr uint32_t maxIssuerBase64Len = BASE64_ENCODED_LEN(kMaxCertificateDistinguishedNameLength) + 1; - - char issuerNameBuffer[maxIssuerBase64Len] = { 0 }; - char serialNumberHexStrBuffer[2 * kMaxCertificateSerialNumberLength + 1] = { 0 }; - char akidHexStrBuffer[2 * kAuthorityKeyIdentifierLength + 1] = { 0 }; - - MutableCharSpan issuerName(issuerNameBuffer); - MutableCharSpan serialNumber(serialNumberHexStrBuffer); - MutableCharSpan akid(akidHexStrBuffer); - - CHIP_ERROR err = GetIssuerNameBase64Str(certDer, issuerName); - VerifyOrReturnValue(err == CHIP_NO_ERROR, false); - - err = GetSerialNumberHexStr(certDer, serialNumber); - VerifyOrReturnValue(err == CHIP_NO_ERROR, false); - - err = GetAKIDHexStr(certDer, akid); - VerifyOrReturnValue(err == CHIP_NO_ERROR, false); - - return IsEntryExistsInRevocationSet(akid, issuerName, serialNumber); -} - void DefaultDACVerifier::CheckForRevokedDACChain(const AttestationInfo & info, Callback::Callback * onCompletion) { - AttestationVerificationResult attestationError = AttestationVerificationResult::kSuccess; - - if (mDeviceAttestationRevocationSetPath != nullptr) + if (mRevocationDelegate != nullptr) { - if (IsCertificateRevoked(info.dacDerBuffer)) - { - attestationError = AttestationVerificationResult::kDacRevoked; - } - if (IsCertificateRevoked(info.paiDerBuffer)) - { - attestationError = AttestationVerificationResult::kPaiRevoked; - } + mRevocationDelegate->CheckForRevokedDACChain(info, onCompletion); + } + else + { + onCompletion->mCall(onCompletion->mContext, info, AttestationVerificationResult::kSuccess); } - - onCompletion->mCall(onCompletion->mContext, info, attestationError); } bool CsaCdKeysTrustStore::IsCdTestKey(const ByteSpan & kid) const diff --git a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h index e499ae065caa14..346d098a58a337 100644 --- a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h +++ b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h @@ -77,10 +77,6 @@ class DefaultDACVerifier : public DeviceAttestationVerifier void CheckForRevokedDACChain(const AttestationInfo & info, Callback::Callback * onCompletion) override; - // Set the path to the device attestation revocation set JSON file. - // revocation set can be generated using credentials/generate-revocation-set.py script - void SetDeviceAttestationRevocationSetPath(const char * path) { mDeviceAttestationRevocationSetPath = path; } - CsaCdKeysTrustStore * GetCertificationDeclarationTrustStore() override { return &mCdKeysTrustStore; } protected: @@ -88,20 +84,6 @@ class DefaultDACVerifier : public DeviceAttestationVerifier CsaCdKeysTrustStore mCdKeysTrustStore; const AttestationTrustStore * mAttestationTrustStore; - -private: - CHIP_ERROR GetAKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outAKIDHexString); - CHIP_ERROR GetSerialNumberHexStr(const ByteSpan & certDer, MutableCharSpan & outSerialNumberHexString); - CHIP_ERROR GetIssuerNameBase64Str(const ByteSpan & certDer, MutableCharSpan & outIssuerNameBase64String); - - bool IsCertificateRevoked(const ByteSpan & certDer); - - // Searches the revocation set and returns true if for the given AKID, issuer name and serial number - // the entry is found in the revocation set, false otherwise. - bool IsEntryExistsInRevocationSet(const CharSpan & akidHexStr, const CharSpan & issuerNameBase64Str, - const CharSpan & serialNumberHexStr); - - const char * mDeviceAttestationRevocationSetPath = nullptr; }; /** diff --git a/src/credentials/attestation_verifier/DeviceAttestationVerifier.h b/src/credentials/attestation_verifier/DeviceAttestationVerifier.h index f45ceae06c23fe..b7b11af2b3bdbf 100644 --- a/src/credentials/attestation_verifier/DeviceAttestationVerifier.h +++ b/src/credentials/attestation_verifier/DeviceAttestationVerifier.h @@ -259,6 +259,8 @@ class ArrayAttestationTrustStore : public AttestationTrustStore const size_t mNumCerts; }; +class DeviceAttestationRevocationDelegate; + class DeviceAttestationVerifier { public: @@ -409,6 +411,8 @@ class DeviceAttestationVerifier void EnableCdTestKeySupport(bool enabled) { mEnableCdTestKeySupport = enabled; } bool IsCdTestKeySupported() const { return mEnableCdTestKeySupport; } + void SetRevocationDelegate(DeviceAttestationRevocationDelegate * delegate) { mRevocationDelegate = delegate; } + protected: CHIP_ERROR ValidateAttestationSignature(const Crypto::P256PublicKey & pubkey, const ByteSpan & attestationElements, const ByteSpan & attestationChallenge, const Crypto::P256ECDSASignature & signature); @@ -416,6 +420,30 @@ class DeviceAttestationVerifier // Default to support the "development" test key for legacy purposes (since the DefaultDACVerifier) // always supported development keys. bool mEnableCdTestKeySupport = true; + + DeviceAttestationRevocationDelegate * mRevocationDelegate = nullptr; +}; + +/** + * @brief Interface for checking the device attestation revocation status + * + */ +class DeviceAttestationRevocationDelegate +{ +public: + DeviceAttestationRevocationDelegate() = default; + virtual ~DeviceAttestationRevocationDelegate() = default; + + /** + * @brief Verify whether or not the given DAC chain is revoked. + * + * @param[in] info All of the information required to check for revoked DAC chain. + * @param[in] onCompletion Callback handler to provide Attestation Information Verification result to the caller of + * CheckForRevokedDACChain(). + */ + virtual void + CheckForRevokedDACChain(const DeviceAttestationVerifier::AttestationInfo & info, + Callback::Callback * onCompletion) = 0; }; /** diff --git a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp new file mode 100644 index 00000000000000..4896ecf79046bf --- /dev/null +++ b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp @@ -0,0 +1,197 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace chip::Crypto; + +namespace chip { +namespace Credentials { + +namespace { +CHIP_ERROR BytesToHexStr(const ByteSpan & bytes, MutableCharSpan & outHexStr) +{ + Encoding::HexFlags flags = Encoding::HexFlags::kUppercase; + ReturnErrorOnFailure(BytesToHex(bytes.data(), bytes.size(), outHexStr.data(), outHexStr.size(), flags)); + outHexStr.reduce_size(2 * bytes.size()); + return CHIP_NO_ERROR; +} +} // anonymous namespace + +CHIP_ERROR TestDACRevocationDelegateImpl::SetDeviceAttestationRevocationSetPath(const char * path) +{ + VerifyOrReturnError(path != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + mDeviceAttestationRevocationSetPath = path; + return CHIP_NO_ERROR; +} + +// This method parses the below JSON Scheme +// [ +// { +// "type": "revocation_set", +// "issuer_subject_key_id": "63540E47F64B1C38D13884A462D16C195D8FFB3C", +// "issuer_name": "MD0xJTAjBgNVBAMMHE1hdHRlciBEZXYgUEFJIDB4RkZGMSBubyBQSUQxFDASBgorBgEEAYKifAIBDARGRkYx", +// "revoked_serial_numbers": [ +// "69CDF10DE9E54ED1" +// ] +// } +// ] +// +bool TestDACRevocationDelegateImpl::IsEntryInRevocationSet(const CharSpan & akidHexStr, const CharSpan & issuerNameBase64Str, + const CharSpan & serialNumberHexStr) +{ + std::ifstream file(mDeviceAttestationRevocationSetPath); + if (!file.is_open()) + { + ChipLogError(NotSpecified, "Failed to open file: %s", mDeviceAttestationRevocationSetPath); + return false; + } + + // Parse the JSON data incrementally + Json::CharReaderBuilder readerBuilder; + Json::Value jsonData; + std::string errs; + + bool parsingSuccessful = Json::parseFromStream(readerBuilder, file, &jsonData, &errs); + + // Close the file as it's no longer needed + file.close(); + + if (!parsingSuccessful) + { + ChipLogError(NotSpecified, "Failed to parse JSON: %s", errs.c_str()); + return false; + } + + std::string issuerName = std::string(issuerNameBase64Str.data(), issuerNameBase64Str.size()); + std::string serialNumber = std::string(serialNumberHexStr.data(), serialNumberHexStr.size()); + std::string akid = std::string(akidHexStr.data(), akidHexStr.size()); + + for (const auto & revokedSet : jsonData) + { + if (revokedSet["issuer_name"].asString() != issuerName) + { + continue; + } + if (revokedSet["issuer_subject_key_id"].asString() != akid) + { + continue; + } + for (const auto & revokedSerialNumber : revokedSet["revoked_serial_numbers"]) + { + if (revokedSerialNumber.asString() == serialNumber) + { + return true; + } + } + } + return false; +} + +CHIP_ERROR TestDACRevocationDelegateImpl::GetAKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outAKIDHexStr) +{ + uint8_t akidBuf[kAuthorityKeyIdentifierLength]; + MutableByteSpan akid(akidBuf); + + ReturnErrorOnFailure(ExtractAKIDFromX509Cert(certDer, akid)); + + return BytesToHexStr(akid, outAKIDHexStr); +} + +CHIP_ERROR TestDACRevocationDelegateImpl::GetSerialNumberHexStr(const ByteSpan & certDer, MutableCharSpan & outSerialNumberHexStr) +{ + uint8_t serialNumberBuf[kMaxCertificateSerialNumberLength] = { 0 }; + MutableByteSpan serialNumber(serialNumberBuf); + + ReturnErrorOnFailure(ExtractSerialNumberFromX509Cert(certDer, serialNumber)); + return BytesToHexStr(serialNumber, outSerialNumberHexStr); +} + +CHIP_ERROR TestDACRevocationDelegateImpl::GetIssuerNameBase64Str(const ByteSpan & certDer, + MutableCharSpan & outIssuerNameBase64String) +{ + uint8_t issuerBuf[kMaxCertificateDistinguishedNameLength] = { 0 }; + MutableByteSpan issuer(issuerBuf); + + ReturnErrorOnFailure(ExtractIssuerFromX509Cert(certDer, issuer)); + VerifyOrReturnError(outIssuerNameBase64String.size() >= BASE64_ENCODED_LEN(issuer.size()), CHIP_ERROR_BUFFER_TOO_SMALL); + + uint32_t encodedLen = Base64Encode32(issuer.data(), static_cast(issuer.size()), outIssuerNameBase64String.data()); + outIssuerNameBase64String.reduce_size(encodedLen); + return CHIP_NO_ERROR; +} + +bool TestDACRevocationDelegateImpl::IsCertificateRevoked(const ByteSpan & certDer) +{ + static constexpr uint32_t maxIssuerBase64Len = BASE64_ENCODED_LEN(kMaxCertificateDistinguishedNameLength); + + char issuerNameBuffer[maxIssuerBase64Len] = { 0 }; + char serialNumberHexStrBuffer[2 * kMaxCertificateSerialNumberLength] = { 0 }; + char akidHexStrBuffer[2 * kAuthorityKeyIdentifierLength] = { 0 }; + + MutableCharSpan issuerName(issuerNameBuffer); + MutableCharSpan serialNumber(serialNumberHexStrBuffer); + MutableCharSpan akid(akidHexStrBuffer); + + VerifyOrReturnValue(CHIP_NO_ERROR == GetIssuerNameBase64Str(certDer, issuerName), false); + ChipLogDetail(NotSpecified, "Issuer: %.*s", static_cast(issuerName.size()), issuerName.data()); + + VerifyOrReturnValue(CHIP_NO_ERROR == GetSerialNumberHexStr(certDer, serialNumber), false); + ChipLogDetail(NotSpecified, "Serial Number: %.*s", static_cast(serialNumber.size()), serialNumber.data()); + + VerifyOrReturnValue(CHIP_NO_ERROR == GetAKIDHexStr(certDer, akid), false); + ChipLogDetail(NotSpecified, "AKID: %.*s", static_cast(akid.size()), akid.data()); + + return IsEntryInRevocationSet(akid, issuerName, serialNumber); +} + +void TestDACRevocationDelegateImpl::CheckForRevokedDACChain( + const DeviceAttestationVerifier::AttestationInfo & info, + Callback::Callback * onCompletion) +{ + AttestationVerificationResult attestationError = AttestationVerificationResult::kSuccess; + + if (mDeviceAttestationRevocationSetPath != nullptr) + { + ChipLogDetail(NotSpecified, "Checking for revoked DAC in %s", mDeviceAttestationRevocationSetPath); + if (IsCertificateRevoked(info.dacDerBuffer)) + { + ChipLogProgress(NotSpecified, "Found revoked DAC in %s", mDeviceAttestationRevocationSetPath); + attestationError = AttestationVerificationResult::kDacRevoked; + } + + ChipLogDetail(NotSpecified, "Checking for revoked PAI in %s", mDeviceAttestationRevocationSetPath); + if (IsCertificateRevoked(info.paiDerBuffer)) + { + ChipLogProgress(NotSpecified, "Found revoked PAI in %s", mDeviceAttestationRevocationSetPath); + attestationError = AttestationVerificationResult::kPaiRevoked; + } + } + + onCompletion->mCall(onCompletion->mContext, info, attestationError); +} + +} // namespace Credentials +} // namespace chip diff --git a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h new file mode 100644 index 00000000000000..3d86353f54d752 --- /dev/null +++ b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h @@ -0,0 +1,59 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace chip { +namespace Credentials { + +class TestDACRevocationDelegateImpl : public DeviceAttestationRevocationDelegate +{ +public: + TestDACRevocationDelegateImpl() = default; + ~TestDACRevocationDelegateImpl() = default; + + /** + * @brief Verify whether or not the given DAC chain is revoked. + * + * @param[in] info All of the information required to check for revoked DAC chain. + * @param[in] onCompletion Callback handler to provide Attestation Information Verification result to the caller of + * CheckForRevokedDACChain(). + */ + void CheckForRevokedDACChain( + const DeviceAttestationVerifier::AttestationInfo & info, + Callback::Callback * onCompletion) override; + + // Set the path to the device attestation revocation set JSON file. + // revocation set can be generated using credentials/generate-revocation-set.py script + CHIP_ERROR SetDeviceAttestationRevocationSetPath(const char * path); + +private: + CHIP_ERROR GetAKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outAKIDHexStr); + CHIP_ERROR GetSerialNumberHexStr(const ByteSpan & certDer, MutableCharSpan & outSerialNumberHexStr); + CHIP_ERROR GetIssuerNameBase64Str(const ByteSpan & certDer, MutableCharSpan & outIssuerNameBase64String); + bool IsEntryInRevocationSet(const CharSpan & akidHexStr, const CharSpan & issuerNameBase64Str, + const CharSpan & serialNumberHexStr); + bool IsCertificateRevoked(const ByteSpan & certDer); + + const char * mDeviceAttestationRevocationSetPath = nullptr; +}; + +} // namespace Credentials +} // namespace chip From 87dee756bd323ae5f09d0441cce4a0b529f70db2 Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Tue, 25 Jun 2024 12:15:23 +0530 Subject: [PATCH 07/19] error code if dac and pai both are revoked --- .../attestation_verifier/DeviceAttestationVerifier.h | 2 ++ .../TestDACRevocationDelegateImpl.cpp | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/credentials/attestation_verifier/DeviceAttestationVerifier.h b/src/credentials/attestation_verifier/DeviceAttestationVerifier.h index b7b11af2b3bdbf..836968c255a518 100644 --- a/src/credentials/attestation_verifier/DeviceAttestationVerifier.h +++ b/src/credentials/attestation_verifier/DeviceAttestationVerifier.h @@ -79,6 +79,8 @@ enum class AttestationVerificationResult : uint16_t kInternalError = 900, + kPaiAndDacRevoked = 1000, + kNotImplemented = 0xFFFFU, // TODO: Add more attestation verification errors diff --git a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp index 4896ecf79046bf..979c609d121173 100644 --- a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp +++ b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp @@ -186,10 +186,17 @@ void TestDACRevocationDelegateImpl::CheckForRevokedDACChain( if (IsCertificateRevoked(info.paiDerBuffer)) { ChipLogProgress(NotSpecified, "Found revoked PAI in %s", mDeviceAttestationRevocationSetPath); - attestationError = AttestationVerificationResult::kPaiRevoked; + + if (attestationError == AttestationVerificationResult::kDacRevoked) + { + attestationError = AttestationVerificationResult::kPaiAndDacRevoked; + } + else + { + attestationError = AttestationVerificationResult::kPaiRevoked; + } } } - onCompletion->mCall(onCompletion->mContext, info, attestationError); } From 6eab6487aeb9dc9212a5e2dbc3d94b7f85da4a70 Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Tue, 25 Jun 2024 12:18:24 +0530 Subject: [PATCH 08/19] unit tests --- .../TestDeviceAttestationCredentials.cpp | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/src/credentials/tests/TestDeviceAttestationCredentials.cpp b/src/credentials/tests/TestDeviceAttestationCredentials.cpp index bf203c8321adf1..955361a51c9c00 100644 --- a/src/credentials/tests/TestDeviceAttestationCredentials.cpp +++ b/src/credentials/tests/TestDeviceAttestationCredentials.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,8 @@ #include "CHIPAttCert_test_vectors.h" +#include + using namespace chip; using namespace chip::Crypto; using namespace chip::Credentials; @@ -411,3 +414,158 @@ TEST_F(TestDeviceAttestationCredentials, TestAttestationTrustStore) } } } + +static void WriteTestRevokedData(const char * jsonData, const char * fileName) +{ + // write data to /tmp/sample_revoked_set.json using fstream APIs + std::ofstream file; + file.open(fileName, std::ofstream::out | std::ofstream::trunc); + file << jsonData; + file.close(); +} + +TEST_F(TestDeviceAttestationCredentials, TestDACRevocationDelegateImpl) +{ + uint8_t attestationElementsTestVector[] = { 0 }; + uint8_t attestationChallengeTestVector[] = { 0 }; + uint8_t attestationSignatureTestVector[] = { 0 }; + uint8_t attestationNonceTestVector[] = { 0 }; + + // Details for TestCerts::sTestCert_DAC_FFF1_8000_0004_Cert + // Issuer: MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw + // AKID: AF42B7094DEBD515EC6ECF33B81115225F325288 + // Serial Number: 0C694F7F866067B2 + // + // Details for TestCerts::sTestCert_PAI_FFF1_8000_Cert + // Issuer: MDAxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBQTEUMBIGCisGAQQBgqJ8AgEMBEZGRjE= + // AKID: 6AFD22771F511FECBF1641976710DCDC31A1717E + // Serial Number: 3E6CE6509AD840CD1 + Credentials::DeviceAttestationVerifier::AttestationInfo info( + ByteSpan(attestationElementsTestVector), ByteSpan(attestationChallengeTestVector), ByteSpan(attestationSignatureTestVector), + TestCerts::sTestCert_PAI_FFF1_8000_Cert, TestCerts::sTestCert_DAC_FFF1_8000_0004_Cert, ByteSpan(attestationNonceTestVector), + static_cast(0xFFF1), 0x8000); + + AttestationVerificationResult attestationResult = AttestationVerificationResult::kNotImplemented; + + Callback::Callback attestationInformationVerificationCallback( + OnAttestationInformationVerificationCallback, &attestationResult); + + TestDACRevocationDelegateImpl revocationDelegateImpl; + + // Test without revocation set + revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); + EXPECT_EQ(attestationResult, AttestationVerificationResult::kSuccess); + + const char * tmpJsonFile = "/tmp/sample_revoked_set.json"; + revocationDelegateImpl.SetDeviceAttestationRevocationSetPath(tmpJsonFile); + + // Test empty json + WriteTestRevokedData("", tmpJsonFile); + revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); + EXPECT_EQ(attestationResult, AttestationVerificationResult::kSuccess); + + // Test DAC is revoked + const char * jsonData = R"( + [{ + "type": "revocation_set", + "issuer_subject_key_id": "AF42B7094DEBD515EC6ECF33B81115225F325288", + "issuer_name": "MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw", + "revoked_serial_numbers": ["0C694F7F866067B2"] + }] + )"; + WriteTestRevokedData(jsonData, tmpJsonFile); + revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); + EXPECT_EQ(attestationResult, AttestationVerificationResult::kDacRevoked); + + // Test PAI is revoked + jsonData = R"( + [{ + "type": "revocation_set", + "issuer_subject_key_id": "6AFD22771F511FECBF1641976710DCDC31A1717E", + "issuer_name": "MDAxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBQTEUMBIGCisGAQQBgqJ8AgEMBEZGRjE=", + "revoked_serial_numbers": ["3E6CE6509AD840CD"] + }] + )"; + WriteTestRevokedData(jsonData, tmpJsonFile); + revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); + EXPECT_EQ(attestationResult, AttestationVerificationResult::kPaiRevoked); + + // Test DAC and PAI both revoked + jsonData = R"( + [{ + "type": "revocation_set", + "issuer_subject_key_id": "AF42B7094DEBD515EC6ECF33B81115225F325288", + "issuer_name": "MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw", + "revoked_serial_numbers": ["0C694F7F866067B2"] + }, + { + "type": "revocation_set", + "issuer_subject_key_id": "6AFD22771F511FECBF1641976710DCDC31A1717E", + "issuer_name": "MDAxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBQTEUMBIGCisGAQQBgqJ8AgEMBEZGRjE=", + "revoked_serial_numbers": ["3E6CE6509AD840CD"] + }] + )"; + WriteTestRevokedData(jsonData, tmpJsonFile); + revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); + EXPECT_EQ(attestationResult, AttestationVerificationResult::kPaiAndDacRevoked); + + // Test with another test DAC and PAI + Credentials::DeviceAttestationVerifier::AttestationInfo FFF2_8001_info( + ByteSpan(attestationElementsTestVector), ByteSpan(attestationChallengeTestVector), ByteSpan(attestationSignatureTestVector), + TestCerts::sTestCert_PAI_FFF2_8001_Cert, TestCerts::sTestCert_DAC_FFF2_8001_0008_Cert, ByteSpan(attestationNonceTestVector), + static_cast(0xFFF2), 0x8001); + revocationDelegateImpl.CheckForRevokedDACChain(FFF2_8001_info, &attestationInformationVerificationCallback); + EXPECT_EQ(attestationResult, AttestationVerificationResult::kSuccess); + + // Test issuer does not match + jsonData = R"( + [{ + "type": "revocation_set", + "issuer_subject_key_id": "BF42B7094DEBD515EC6ECF33B81115225F325289", + "issuer_name": "MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw", + "revoked_serial_numbers": ["0C694F7F866067B2"] + }] + )"; + WriteTestRevokedData(jsonData, tmpJsonFile); + revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); + EXPECT_EQ(attestationResult, AttestationVerificationResult::kSuccess); + + // Test subject key ID does not match + jsonData = R"( + [{ + "type": "revocation_set", + "issuer_subject_key_id": "BF42B7094DEBD515EC6ECF33B81115225F325289", + "issuer_name": "MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw", + "revoked_serial_numbers": ["0C694F7F866067B2"] + }] + )"; + WriteTestRevokedData(jsonData, tmpJsonFile); + revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); + EXPECT_EQ(attestationResult, AttestationVerificationResult::kSuccess); + + // Test serial number does not match + jsonData = R"( + [{ + "type": "revocation_set", + "issuer_subject_key_id": "AF42B7094DEBD515EC6ECF33B81115225F325288", + "issuer_name": "MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw", + "revoked_serial_numbers": ["3E6CE6509AD840CD1", "BC694F7F866067B1"] + }] + )"; + WriteTestRevokedData(jsonData, tmpJsonFile); + revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); + EXPECT_EQ(attestationResult, AttestationVerificationResult::kSuccess); + + // Test starting serial number bytes match but not all + jsonData = R"( + [{ + "type": "revocation_set", + "issuer_subject_key_id": "AF42B7094DEBD515EC6ECF33B81115225F325288", + "issuer_name": "MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw", + "revoked_serial_numbers": ["0C694F7F866067B21234"] + }] + )"; + WriteTestRevokedData(jsonData, tmpJsonFile); + revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); + EXPECT_EQ(attestationResult, AttestationVerificationResult::kSuccess); +} From 49c57c6221607faa261bd6c36685030a3efdaec4 Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Thu, 4 Jul 2024 17:49:16 +0530 Subject: [PATCH 09/19] Update examples/chip-tool/commands/common/CredentialIssuerCommands.h Co-authored-by: Boris Zbarsky --- examples/chip-tool/commands/common/CredentialIssuerCommands.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/chip-tool/commands/common/CredentialIssuerCommands.h b/examples/chip-tool/commands/common/CredentialIssuerCommands.h index 4df8cc19eff770..5ba497787cf749 100644 --- a/examples/chip-tool/commands/common/CredentialIssuerCommands.h +++ b/examples/chip-tool/commands/common/CredentialIssuerCommands.h @@ -64,7 +64,7 @@ class CredentialIssuerCommands /** * @brief - * This function is used to set the path to Device Attestation revocation set JSON file. + * This function is used to set the path to the Device Attestation revocation set JSON file. * * @param[in] path Path to the JSON file containing list of revoked DACs or PAIs. * It can be generated using credentials/generate-revocation-set.py script From 32b29677d1d6bb51e3704f994c9be8d11e726517 Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Fri, 5 Jul 2024 09:09:21 +0530 Subject: [PATCH 10/19] Move setting of revocation delegate to default verifier --- .../chip-tool/commands/common/CHIPCommand.cpp | 13 +++++++++---- .../commands/common/CredentialIssuerCommands.h | 17 +++++------------ .../example/ExampleCredentialIssuerCommands.h | 15 +++------------ .../DefaultDeviceAttestationVerifier.cpp | 5 +++-- .../DefaultDeviceAttestationVerifier.h | 10 ++++++++-- .../DeviceAttestationVerifier.h | 7 +------ 6 files changed, 29 insertions(+), 38 deletions(-) diff --git a/examples/chip-tool/commands/common/CHIPCommand.cpp b/examples/chip-tool/commands/common/CHIPCommand.cpp index b953c2bc686133..dd44799a340036 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.cpp +++ b/examples/chip-tool/commands/common/CHIPCommand.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -48,7 +49,9 @@ constexpr chip::FabricId kIdentityOtherFabricId = 4; constexpr char kPAATrustStorePathVariable[] = "CHIPTOOL_PAA_TRUST_STORE_PATH"; constexpr char kCDTrustStorePathVariable[] = "CHIPTOOL_CD_TRUST_STORE_PATH"; -const chip::Credentials::AttestationTrustStore * CHIPCommand::sTrustStore = nullptr; +const chip::Credentials::AttestationTrustStore * CHIPCommand::sTrustStore = nullptr; +chip::Credentials::DeviceAttestationRevocationDelegate * sRevocationDelegate = nullptr; + chip::Credentials::GroupDataProviderImpl CHIPCommand::sGroupDataProvider{ kMaxGroupsPerFabric, kMaxGroupKeysPerFabric }; // All fabrics share the same ICD client storage. chip::app::DefaultICDClientStorage CHIPCommand::sICDClientStorage; @@ -450,13 +453,15 @@ CHIP_ERROR CHIPCommand::InitializeCommissioner(CommissionerIdentity & identity, std::unique_ptr commissioner = std::make_unique(); chip::Controller::SetupParams commissionerParams; - ReturnLogErrorOnFailure(mCredIssuerCmds->SetupDeviceAttestation(commissionerParams, sTrustStore)); - if (mDacRevocationSetPath.HasValue()) { - ReturnLogErrorOnFailure(mCredIssuerCmds->SetDeviceAttestationRevocationSetPath(mDacRevocationSetPath.Value())); + static chip::Credentials::TestDACRevocationDelegateImpl testDacRevocationDelegate; + ReturnErrorOnFailure(testDacRevocationDelegate.SetDeviceAttestationRevocationSetPath(mDacRevocationSetPath.Value())); + sRevocationDelegate = &testDacRevocationDelegate; } + ReturnLogErrorOnFailure(mCredIssuerCmds->SetupDeviceAttestation(commissionerParams, sTrustStore, sRevocationDelegate)); + chip::Crypto::P256Keypair ephemeralKey; if (fabricId != chip::kUndefinedFabricId) diff --git a/examples/chip-tool/commands/common/CredentialIssuerCommands.h b/examples/chip-tool/commands/common/CredentialIssuerCommands.h index 5ba497787cf749..c438702f9fde8d 100644 --- a/examples/chip-tool/commands/common/CredentialIssuerCommands.h +++ b/examples/chip-tool/commands/common/CredentialIssuerCommands.h @@ -57,21 +57,14 @@ class CredentialIssuerCommands * Verifier. * @param[in] trustStore A pointer to the PAA trust store to use to find valid PAA roots. * - * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error code. - */ - virtual CHIP_ERROR SetupDeviceAttestation(chip::Controller::SetupParams & setupParams, - const chip::Credentials::AttestationTrustStore * trustStore) = 0; - - /** - * @brief - * This function is used to set the path to the Device Attestation revocation set JSON file. - * - * @param[in] path Path to the JSON file containing list of revoked DACs or PAIs. - * It can be generated using credentials/generate-revocation-set.py script + * @param[in] revocationDelegate A pointer to the Device Attestation Revocation Delegate for checking revoked DACs and PAIs. + * Default is nullptr. * * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error code. */ - virtual CHIP_ERROR SetDeviceAttestationRevocationSetPath(const char * path) = 0; + virtual CHIP_ERROR + SetupDeviceAttestation(chip::Controller::SetupParams & setupParams, const chip::Credentials::AttestationTrustStore * trustStore, + chip::Credentials::DeviceAttestationRevocationDelegate * revocationDelegate = nullptr) = 0; /** * @brief Add a list of additional non-default CD verifying keys (by certificate) diff --git a/examples/chip-tool/commands/example/ExampleCredentialIssuerCommands.h b/examples/chip-tool/commands/example/ExampleCredentialIssuerCommands.h index e9c6df74b2855e..495ae8d7a544d6 100644 --- a/examples/chip-tool/commands/example/ExampleCredentialIssuerCommands.h +++ b/examples/chip-tool/commands/example/ExampleCredentialIssuerCommands.h @@ -24,7 +24,6 @@ #include #include #include -#include #include class ExampleCredentialIssuerCommands : public CredentialIssuerCommands @@ -35,25 +34,18 @@ class ExampleCredentialIssuerCommands : public CredentialIssuerCommands return mOpCredsIssuer.Initialize(storage); } CHIP_ERROR SetupDeviceAttestation(chip::Controller::SetupParams & setupParams, - const chip::Credentials::AttestationTrustStore * trustStore) override + const chip::Credentials::AttestationTrustStore * trustStore, + chip::Credentials::DeviceAttestationRevocationDelegate * revocationDelegate) override { chip::Credentials::SetDeviceAttestationCredentialsProvider(chip::Credentials::Examples::GetExampleDACProvider()); - mDacVerifier = chip::Credentials::GetDefaultDACVerifier(trustStore); + mDacVerifier = chip::Credentials::GetDefaultDACVerifier(trustStore, revocationDelegate); setupParams.deviceAttestationVerifier = mDacVerifier; mDacVerifier->EnableCdTestKeySupport(mAllowTestCdSigningKey); return CHIP_NO_ERROR; } - CHIP_ERROR SetDeviceAttestationRevocationSetPath(const char * path) override - { - VerifyOrReturnError(path != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - ReturnErrorOnFailure(mTestDacRevocationDelegate.SetDeviceAttestationRevocationSetPath(path)); - mDacVerifier->SetRevocationDelegate(&mTestDacRevocationDelegate); - return CHIP_NO_ERROR; - } - chip::Controller::OperationalCredentialsDelegate * GetCredentialIssuer() override { return &mOpCredsIssuer; } void SetCredentialIssuerCATValues(chip::CATValues cats) override { mOpCredsIssuer.SetCATValuesForNextNOCRequest(cats); } CHIP_ERROR GenerateControllerNOCChain(chip::NodeId nodeId, chip::FabricId fabricId, const chip::CATValues & cats, @@ -118,5 +110,4 @@ class ExampleCredentialIssuerCommands : public CredentialIssuerCommands private: chip::Controller::ExampleOperationalCredentialsIssuer mOpCredsIssuer; chip::Credentials::DeviceAttestationVerifier * mDacVerifier; - chip::Credentials::TestDACRevocationDelegateImpl mTestDacRevocationDelegate; }; diff --git a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp index b594a10f69006e..14759d850ffc40 100644 --- a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp +++ b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp @@ -696,9 +696,10 @@ const AttestationTrustStore * GetTestAttestationTrustStore() return &gTestAttestationTrustStore.get(); } -DeviceAttestationVerifier * GetDefaultDACVerifier(const AttestationTrustStore * paaRootStore) +DeviceAttestationVerifier * GetDefaultDACVerifier(const AttestationTrustStore * paaRootStore, + DeviceAttestationRevocationDelegate * revocationDelegate) { - static DefaultDACVerifier defaultDACVerifier{ paaRootStore }; + static DefaultDACVerifier defaultDACVerifier{ paaRootStore, revocationDelegate }; return &defaultDACVerifier; } diff --git a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h index 346d098a58a337..e3206cd5d19476 100644 --- a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h +++ b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h @@ -57,7 +57,11 @@ class CsaCdKeysTrustStore : public WellKnownKeysTrustStore class DefaultDACVerifier : public DeviceAttestationVerifier { public: - DefaultDACVerifier(const AttestationTrustStore * paaRootStore) : mAttestationTrustStore(paaRootStore) {} + DefaultDACVerifier(const AttestationTrustStore * paaRootStore, + DeviceAttestationRevocationDelegate * revocationDelegate = nullptr) : + mAttestationTrustStore(paaRootStore), + mRevocationDelegate(revocationDelegate) + {} void VerifyAttestationInformation(const DeviceAttestationVerifier::AttestationInfo & info, Callback::Callback * onCompletion) override; @@ -84,6 +88,7 @@ class DefaultDACVerifier : public DeviceAttestationVerifier CsaCdKeysTrustStore mCdKeysTrustStore; const AttestationTrustStore * mAttestationTrustStore; + DeviceAttestationRevocationDelegate * mRevocationDelegate = nullptr; }; /** @@ -112,7 +117,8 @@ const AttestationTrustStore * GetTestAttestationTrustStore(); * process lifetime. In particular, after the first call it's not * possible to change which AttestationTrustStore is used by this verifier. */ -DeviceAttestationVerifier * GetDefaultDACVerifier(const AttestationTrustStore * paaRootStore); +DeviceAttestationVerifier * GetDefaultDACVerifier(const AttestationTrustStore * paaRootStore, + DeviceAttestationRevocationDelegate * revocationDelegate = nullptr); } // namespace Credentials } // namespace chip diff --git a/src/credentials/attestation_verifier/DeviceAttestationVerifier.h b/src/credentials/attestation_verifier/DeviceAttestationVerifier.h index 836968c255a518..91e244497c69e8 100644 --- a/src/credentials/attestation_verifier/DeviceAttestationVerifier.h +++ b/src/credentials/attestation_verifier/DeviceAttestationVerifier.h @@ -47,6 +47,7 @@ enum class AttestationVerificationResult : uint16_t kPaiVendorIdMismatch = 205, kPaiAuthorityNotFound = 206, kPaiMissing = 207, + kPaiAndDacRevoked = 208, kDacExpired = 300, kDacSignatureInvalid = 301, @@ -79,8 +80,6 @@ enum class AttestationVerificationResult : uint16_t kInternalError = 900, - kPaiAndDacRevoked = 1000, - kNotImplemented = 0xFFFFU, // TODO: Add more attestation verification errors @@ -413,8 +412,6 @@ class DeviceAttestationVerifier void EnableCdTestKeySupport(bool enabled) { mEnableCdTestKeySupport = enabled; } bool IsCdTestKeySupported() const { return mEnableCdTestKeySupport; } - void SetRevocationDelegate(DeviceAttestationRevocationDelegate * delegate) { mRevocationDelegate = delegate; } - protected: CHIP_ERROR ValidateAttestationSignature(const Crypto::P256PublicKey & pubkey, const ByteSpan & attestationElements, const ByteSpan & attestationChallenge, const Crypto::P256ECDSASignature & signature); @@ -422,8 +419,6 @@ class DeviceAttestationVerifier // Default to support the "development" test key for legacy purposes (since the DefaultDACVerifier) // always supported development keys. bool mEnableCdTestKeySupport = true; - - DeviceAttestationRevocationDelegate * mRevocationDelegate = nullptr; }; /** From 5b271ff26d80c286ed415fb40ea6723b225c9ab9 Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Tue, 9 Jul 2024 09:59:39 +0530 Subject: [PATCH 11/19] factor out getting of revocation delegate --- .../chip-tool/commands/common/CHIPCommand.cpp | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/examples/chip-tool/commands/common/CHIPCommand.cpp b/examples/chip-tool/commands/common/CHIPCommand.cpp index dd44799a340036..9651338e44891c 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.cpp +++ b/examples/chip-tool/commands/common/CHIPCommand.cpp @@ -90,6 +90,21 @@ CHIP_ERROR GetAttestationTrustStore(const char * paaTrustStorePath, const chip:: return CHIP_NO_ERROR; } +CHIP_ERROR GetAttestationRevocationDelegate(const char * revocationSetPath, chip::Credentials::DeviceAttestationRevocationDelegate ** revocationDelegate) +{ + if (revocationSetPath == nullptr) + { + *revocationDelegate = sRevocationDelegate; + return CHIP_NO_ERROR; + } + + static chip::Credentials::TestDACRevocationDelegateImpl testDacRevocationDelegate; + + ReturnErrorOnFailure(testDacRevocationDelegate.SetDeviceAttestationRevocationSetPath(revocationSetPath)); + *revocationDelegate = &testDacRevocationDelegate; + return CHIP_NO_ERROR; +} + } // namespace CHIP_ERROR CHIPCommand::MaybeSetUpStack() @@ -154,6 +169,8 @@ CHIP_ERROR CHIPCommand::MaybeSetUpStack() ReturnErrorOnFailure(GetAttestationTrustStore(mPaaTrustStorePath.ValueOr(nullptr), &sTrustStore)); + ReturnLogErrorOnFailure(GetAttestationRevocationDelegate(mDacRevocationSetPath.ValueOr(nullptr), &sRevocationDelegate)); + auto engine = chip::app::InteractionModelEngine::GetInstance(); VerifyOrReturnError(engine != nullptr, CHIP_ERROR_INCORRECT_STATE); ReturnLogErrorOnFailure(ChipToolCheckInDelegate()->Init(&sICDClientStorage, engine)); @@ -453,13 +470,6 @@ CHIP_ERROR CHIPCommand::InitializeCommissioner(CommissionerIdentity & identity, std::unique_ptr commissioner = std::make_unique(); chip::Controller::SetupParams commissionerParams; - if (mDacRevocationSetPath.HasValue()) - { - static chip::Credentials::TestDACRevocationDelegateImpl testDacRevocationDelegate; - ReturnErrorOnFailure(testDacRevocationDelegate.SetDeviceAttestationRevocationSetPath(mDacRevocationSetPath.Value())); - sRevocationDelegate = &testDacRevocationDelegate; - } - ReturnLogErrorOnFailure(mCredIssuerCmds->SetupDeviceAttestation(commissionerParams, sTrustStore, sRevocationDelegate)); chip::Crypto::P256Keypair ephemeralKey; From d9a6bbe73d7824e4d36ead246cd24ccb945f477c Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Tue, 9 Jul 2024 04:30:08 +0000 Subject: [PATCH 12/19] Restyled by clang-format --- examples/chip-tool/commands/common/CHIPCommand.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/chip-tool/commands/common/CHIPCommand.cpp b/examples/chip-tool/commands/common/CHIPCommand.cpp index 9651338e44891c..1a72bee03c6d46 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.cpp +++ b/examples/chip-tool/commands/common/CHIPCommand.cpp @@ -90,7 +90,8 @@ CHIP_ERROR GetAttestationTrustStore(const char * paaTrustStorePath, const chip:: return CHIP_NO_ERROR; } -CHIP_ERROR GetAttestationRevocationDelegate(const char * revocationSetPath, chip::Credentials::DeviceAttestationRevocationDelegate ** revocationDelegate) +CHIP_ERROR GetAttestationRevocationDelegate(const char * revocationSetPath, + chip::Credentials::DeviceAttestationRevocationDelegate ** revocationDelegate) { if (revocationSetPath == nullptr) { From d0f80af5e9a50d6eed4920f653c9ac2ed8f3be74 Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Mon, 22 Jul 2024 09:28:12 +0530 Subject: [PATCH 13/19] address reviews --- examples/chip-tool/BUILD.gn | 1 + src/credentials/BUILD.gn | 14 ++++++++++++++ .../DeviceAttestationVerifier.h | 2 -- .../TestDACRevocationDelegateImpl.cpp | 4 ++++ .../TestDACRevocationDelegateImpl.h | 1 + 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/examples/chip-tool/BUILD.gn b/examples/chip-tool/BUILD.gn index b5917f3bfaca62..94e1eebbde7508 100644 --- a/examples/chip-tool/BUILD.gn +++ b/examples/chip-tool/BUILD.gn @@ -109,6 +109,7 @@ static_library("chip-tool-utils") { "${chip_root}/src/app/tests/suites/commands/interaction_model", "${chip_root}/src/controller/data_model", "${chip_root}/src/credentials:file_attestation_trust_store", + "${chip_root}/src/credentials:test_dac_revocation_delegate", "${chip_root}/src/lib", "${chip_root}/src/lib/core:types", "${chip_root}/src/lib/support/jsontlv", diff --git a/src/credentials/BUILD.gn b/src/credentials/BUILD.gn index 35b0f15903cd1b..bf7ac546e8ca6f 100644 --- a/src/credentials/BUILD.gn +++ b/src/credentials/BUILD.gn @@ -189,3 +189,17 @@ static_library("file_attestation_trust_store") { "${nlassert_root}:nlassert", ] } + +static_library("test_dac_revocation_delegate") { + output_name = "libTestDACRevocationDelegate" + + sources = [ + "attestation_verifier/TestDACRevocationDelegateImpl.cpp", + "attestation_verifier/TestDACRevocationDelegateImpl.h", + ] + + public_deps = [ + ":credentials", + jsoncpp_root, + ] +} diff --git a/src/credentials/attestation_verifier/DeviceAttestationVerifier.h b/src/credentials/attestation_verifier/DeviceAttestationVerifier.h index 91e244497c69e8..e6915931a73b68 100644 --- a/src/credentials/attestation_verifier/DeviceAttestationVerifier.h +++ b/src/credentials/attestation_verifier/DeviceAttestationVerifier.h @@ -260,8 +260,6 @@ class ArrayAttestationTrustStore : public AttestationTrustStore const size_t mNumCerts; }; -class DeviceAttestationRevocationDelegate; - class DeviceAttestationVerifier { public: diff --git a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp index 979c609d121173..0c818ecda6c404 100644 --- a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp +++ b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp @@ -59,6 +59,10 @@ CHIP_ERROR TestDACRevocationDelegateImpl::SetDeviceAttestationRevocationSetPath( // } // ] // +// "issuer_subject_key_id" -> Subject key identifier of the CRL file's issuer, encoded as a hex string +// "issuer_name" -> Issuer field of the CRL file, encoded as a base64 string +// "revoked_serial_numbers" -> Serial numbers of revoked certificates, encoded as hex strings +// bool TestDACRevocationDelegateImpl::IsEntryInRevocationSet(const CharSpan & akidHexStr, const CharSpan & issuerNameBase64Str, const CharSpan & serialNumberHexStr) { diff --git a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h index 3d86353f54d752..43f517ee040a3e 100644 --- a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h +++ b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h @@ -42,6 +42,7 @@ class TestDACRevocationDelegateImpl : public DeviceAttestationRevocationDelegate // Set the path to the device attestation revocation set JSON file. // revocation set can be generated using credentials/generate-revocation-set.py script + // This API returns CHIP_ERROR_INVALID_ARGUMENT if the path is null. CHIP_ERROR SetDeviceAttestationRevocationSetPath(const char * path); private: From 5c48abbeff56db36a4ab2ff08b460eec91073a42 Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Mon, 22 Jul 2024 10:41:44 +0530 Subject: [PATCH 14/19] API to clear revocation set path, and minor cleanup and added a comment to explain the usage of --dac-revocation-set-path argument --- examples/chip-tool/commands/common/CHIPCommand.cpp | 4 +--- examples/chip-tool/commands/common/CHIPCommand.h | 4 ++++ .../attestation_verifier/TestDACRevocationDelegateImpl.h | 7 +++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/examples/chip-tool/commands/common/CHIPCommand.cpp b/examples/chip-tool/commands/common/CHIPCommand.cpp index 1a72bee03c6d46..6044475fddd791 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.cpp +++ b/examples/chip-tool/commands/common/CHIPCommand.cpp @@ -50,7 +50,7 @@ constexpr char kPAATrustStorePathVariable[] = "CHIPTOOL_PAA_TRUST_STORE_PATH constexpr char kCDTrustStorePathVariable[] = "CHIPTOOL_CD_TRUST_STORE_PATH"; const chip::Credentials::AttestationTrustStore * CHIPCommand::sTrustStore = nullptr; -chip::Credentials::DeviceAttestationRevocationDelegate * sRevocationDelegate = nullptr; +chip::Credentials::DeviceAttestationRevocationDelegate * CHIPCommand::sRevocationDelegate = nullptr; chip::Credentials::GroupDataProviderImpl CHIPCommand::sGroupDataProvider{ kMaxGroupsPerFabric, kMaxGroupKeysPerFabric }; // All fabrics share the same ICD client storage. @@ -95,12 +95,10 @@ CHIP_ERROR GetAttestationRevocationDelegate(const char * revocationSetPath, { if (revocationSetPath == nullptr) { - *revocationDelegate = sRevocationDelegate; return CHIP_NO_ERROR; } static chip::Credentials::TestDACRevocationDelegateImpl testDacRevocationDelegate; - ReturnErrorOnFailure(testDacRevocationDelegate.SetDeviceAttestationRevocationSetPath(revocationSetPath)); *revocationDelegate = &testDacRevocationDelegate; return CHIP_NO_ERROR; diff --git a/examples/chip-tool/commands/common/CHIPCommand.h b/examples/chip-tool/commands/common/CHIPCommand.h index efc7cc4b7bbc82..8438e4a00697f6 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.h +++ b/examples/chip-tool/commands/common/CHIPCommand.h @@ -230,6 +230,10 @@ class CHIPCommand : public Command // can spin up commissioners as needed. static const chip::Credentials::AttestationTrustStore * sTrustStore; + // Cached DAC revocation delegate, this can be set using "--dac-revocation-set-path" argument + // Once set this will be used by all commands. + static chip::Credentials::DeviceAttestationRevocationDelegate * sRevocationDelegate; + static void RunQueuedCommand(intptr_t commandArg); typedef decltype(RunQueuedCommand) MatterWorkCallback; static void RunCommandCleanup(intptr_t commandArg); diff --git a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h index 43f517ee040a3e..c575a5852af3ab 100644 --- a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h +++ b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h @@ -45,6 +45,13 @@ class TestDACRevocationDelegateImpl : public DeviceAttestationRevocationDelegate // This API returns CHIP_ERROR_INVALID_ARGUMENT if the path is null. CHIP_ERROR SetDeviceAttestationRevocationSetPath(const char * path); + // Clear the path to the device attestation revocation set JSON file. + // This can be used to skip the revocation check + void ClearDeviceAttestationRevocationSetPath() + { + mDeviceAttestationRevocationSetPath = nullptr; + } + private: CHIP_ERROR GetAKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outAKIDHexStr); CHIP_ERROR GetSerialNumberHexStr(const ByteSpan & certDer, MutableCharSpan & outSerialNumberHexStr); From 24b0499a72d974a2e8fae28d107222e5f796875c Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 22 Jul 2024 09:27:21 +0000 Subject: [PATCH 15/19] Restyled by clang-format --- examples/chip-tool/commands/common/CHIPCommand.cpp | 2 +- .../attestation_verifier/TestDACRevocationDelegateImpl.h | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/chip-tool/commands/common/CHIPCommand.cpp b/examples/chip-tool/commands/common/CHIPCommand.cpp index 6044475fddd791..1c3df517bd89d0 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.cpp +++ b/examples/chip-tool/commands/common/CHIPCommand.cpp @@ -49,7 +49,7 @@ constexpr chip::FabricId kIdentityOtherFabricId = 4; constexpr char kPAATrustStorePathVariable[] = "CHIPTOOL_PAA_TRUST_STORE_PATH"; constexpr char kCDTrustStorePathVariable[] = "CHIPTOOL_CD_TRUST_STORE_PATH"; -const chip::Credentials::AttestationTrustStore * CHIPCommand::sTrustStore = nullptr; +const chip::Credentials::AttestationTrustStore * CHIPCommand::sTrustStore = nullptr; chip::Credentials::DeviceAttestationRevocationDelegate * CHIPCommand::sRevocationDelegate = nullptr; chip::Credentials::GroupDataProviderImpl CHIPCommand::sGroupDataProvider{ kMaxGroupsPerFabric, kMaxGroupKeysPerFabric }; diff --git a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h index c575a5852af3ab..3960f4a6e5f2e9 100644 --- a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h +++ b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h @@ -47,10 +47,7 @@ class TestDACRevocationDelegateImpl : public DeviceAttestationRevocationDelegate // Clear the path to the device attestation revocation set JSON file. // This can be used to skip the revocation check - void ClearDeviceAttestationRevocationSetPath() - { - mDeviceAttestationRevocationSetPath = nullptr; - } + void ClearDeviceAttestationRevocationSetPath() { mDeviceAttestationRevocationSetPath = nullptr; } private: CHIP_ERROR GetAKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outAKIDHexStr); From 6214262be45f69eb3647c0d106c34a767ea7fb83 Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Wed, 24 Jul 2024 09:47:56 +0530 Subject: [PATCH 16/19] add some details about json schema --- .../TestDACRevocationDelegateImpl.cpp | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp index 0c818ecda6c404..a43c5729ae5c4d 100644 --- a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp +++ b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp @@ -49,20 +49,17 @@ CHIP_ERROR TestDACRevocationDelegateImpl::SetDeviceAttestationRevocationSetPath( // This method parses the below JSON Scheme // [ -// { -// "type": "revocation_set", -// "issuer_subject_key_id": "63540E47F64B1C38D13884A462D16C195D8FFB3C", -// "issuer_name": "MD0xJTAjBgNVBAMMHE1hdHRlciBEZXYgUEFJIDB4RkZGMSBubyBQSUQxFDASBgorBgEEAYKifAIBDARGRkYx", -// "revoked_serial_numbers": [ -// "69CDF10DE9E54ED1" -// ] -// } +// { +// "type": "revocation_set", +// "issuer_subject_key_id": "", +// "issuer_name": "", +// "revoked_serial_numbers: [ +// "serial1 bytes as base64", +// "serial2 bytes as base64" +// ] +// } // ] // -// "issuer_subject_key_id" -> Subject key identifier of the CRL file's issuer, encoded as a hex string -// "issuer_name" -> Issuer field of the CRL file, encoded as a base64 string -// "revoked_serial_numbers" -> Serial numbers of revoked certificates, encoded as hex strings -// bool TestDACRevocationDelegateImpl::IsEntryInRevocationSet(const CharSpan & akidHexStr, const CharSpan & issuerNameBase64Str, const CharSpan & serialNumberHexStr) { From 608ffba5a3186d73b106b7a64272cc62676def2d Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 24 Jul 2024 04:18:18 +0000 Subject: [PATCH 17/19] Restyled by whitespace --- .../attestation_verifier/TestDACRevocationDelegateImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp index a43c5729ae5c4d..b66f825091bf0d 100644 --- a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp +++ b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp @@ -49,7 +49,7 @@ CHIP_ERROR TestDACRevocationDelegateImpl::SetDeviceAttestationRevocationSetPath( // This method parses the below JSON Scheme // [ -// { +// { // "type": "revocation_set", // "issuer_subject_key_id": "", // "issuer_name": "", From 97c09350c19050495e115d352b03c6905206267f Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Thu, 25 Jul 2024 09:06:44 +0530 Subject: [PATCH 18/19] Add the help text in the argument --- examples/chip-tool/commands/common/CHIPCommand.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/chip-tool/commands/common/CHIPCommand.h b/examples/chip-tool/commands/common/CHIPCommand.h index 8438e4a00697f6..b48455ebed6821 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.h +++ b/examples/chip-tool/commands/common/CHIPCommand.h @@ -87,7 +87,9 @@ class CHIPCommand : public Command "Only allow trusted CD verifying keys (disallow test keys). If not provided or 0 (\"false\"), untrusted CD " "verifying keys are allowed. If 1 (\"true\"), test keys are disallowed."); AddArgument("dac-revocation-set-path", &mDacRevocationSetPath, - "Path to json file containing the device attestation revocation set."); + "Path to JSON file containing the device attestation revocation set. " + "This argument caches the path to the revocation set. Once set, this will be used by all commands in " + "interactive mode."); #if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED AddArgument("trace_file", &mTraceFile); AddArgument("trace_log", 0, 1, &mTraceLog); From a9d8e1d7ea18e772b69358c8157da65bf9fbf45b Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Mon, 29 Jul 2024 20:45:00 +0530 Subject: [PATCH 19/19] Address review comments and added some TODOs --- .../common/CredentialIssuerCommands.h | 7 +-- src/credentials/BUILD.gn | 3 - .../DefaultDeviceAttestationVerifier.h | 13 ++-- .../TestDACRevocationDelegateImpl.cpp | 60 ++++++++++++------- .../TestDACRevocationDelegateImpl.h | 7 ++- src/credentials/tests/BUILD.gn | 1 + .../TestDeviceAttestationCredentials.cpp | 2 + 7 files changed, 56 insertions(+), 37 deletions(-) diff --git a/examples/chip-tool/commands/common/CredentialIssuerCommands.h b/examples/chip-tool/commands/common/CredentialIssuerCommands.h index c438702f9fde8d..f8e225afec4c5e 100644 --- a/examples/chip-tool/commands/common/CredentialIssuerCommands.h +++ b/examples/chip-tool/commands/common/CredentialIssuerCommands.h @@ -58,13 +58,12 @@ class CredentialIssuerCommands * @param[in] trustStore A pointer to the PAA trust store to use to find valid PAA roots. * * @param[in] revocationDelegate A pointer to the Device Attestation Revocation Delegate for checking revoked DACs and PAIs. - * Default is nullptr. * * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error code. */ - virtual CHIP_ERROR - SetupDeviceAttestation(chip::Controller::SetupParams & setupParams, const chip::Credentials::AttestationTrustStore * trustStore, - chip::Credentials::DeviceAttestationRevocationDelegate * revocationDelegate = nullptr) = 0; + virtual CHIP_ERROR SetupDeviceAttestation(chip::Controller::SetupParams & setupParams, + const chip::Credentials::AttestationTrustStore * trustStore, + chip::Credentials::DeviceAttestationRevocationDelegate * revocationDelegate) = 0; /** * @brief Add a list of additional non-default CD verifying keys (by certificate) diff --git a/src/credentials/BUILD.gn b/src/credentials/BUILD.gn index bf7ac546e8ca6f..670cefcd209c10 100644 --- a/src/credentials/BUILD.gn +++ b/src/credentials/BUILD.gn @@ -158,8 +158,6 @@ static_library("default_attestation_verifier") { "attestation_verifier/DefaultDeviceAttestationVerifier.cpp", "attestation_verifier/DefaultDeviceAttestationVerifier.h", "attestation_verifier/DeviceAttestationDelegate.h", - "attestation_verifier/TestDACRevocationDelegateImpl.cpp", - "attestation_verifier/TestDACRevocationDelegateImpl.h", ] if (chip_device_platform == "esp32" || chip_device_platform == "nrfconnect" || @@ -172,7 +170,6 @@ static_library("default_attestation_verifier") { ":test_paa_store", "${chip_root}/src/crypto", "${nlassert_root}:nlassert", - jsoncpp_root, ] } diff --git a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h index e3206cd5d19476..7e0fc1c4378848 100644 --- a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h +++ b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h @@ -57,10 +57,10 @@ class CsaCdKeysTrustStore : public WellKnownKeysTrustStore class DefaultDACVerifier : public DeviceAttestationVerifier { public: - DefaultDACVerifier(const AttestationTrustStore * paaRootStore, - DeviceAttestationRevocationDelegate * revocationDelegate = nullptr) : - mAttestationTrustStore(paaRootStore), - mRevocationDelegate(revocationDelegate) + DefaultDACVerifier(const AttestationTrustStore * paaRootStore) : mAttestationTrustStore(paaRootStore) {} + + DefaultDACVerifier(const AttestationTrustStore * paaRootStore, DeviceAttestationRevocationDelegate * revocationDelegate) : + mAttestationTrustStore(paaRootStore), mRevocationDelegate(revocationDelegate) {} void VerifyAttestationInformation(const DeviceAttestationVerifier::AttestationInfo & info, @@ -83,6 +83,11 @@ class DefaultDACVerifier : public DeviceAttestationVerifier CsaCdKeysTrustStore * GetCertificationDeclarationTrustStore() override { return &mCdKeysTrustStore; } + void SetRevocationDelegate(DeviceAttestationRevocationDelegate * revocationDelegate) + { + mRevocationDelegate = revocationDelegate; + } + protected: DefaultDACVerifier() {} diff --git a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp index b66f825091bf0d..4e1978525e7327 100644 --- a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp +++ b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp @@ -40,13 +40,19 @@ CHIP_ERROR BytesToHexStr(const ByteSpan & bytes, MutableCharSpan & outHexStr) } } // anonymous namespace -CHIP_ERROR TestDACRevocationDelegateImpl::SetDeviceAttestationRevocationSetPath(const char * path) +CHIP_ERROR TestDACRevocationDelegateImpl::SetDeviceAttestationRevocationSetPath(std::string_view path) { - VerifyOrReturnError(path != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(path.empty() != true, CHIP_ERROR_INVALID_ARGUMENT); mDeviceAttestationRevocationSetPath = path; return CHIP_NO_ERROR; } +void TestDACRevocationDelegateImpl::ClearDeviceAttestationRevocationSetPath() +{ + // clear the string_view + mDeviceAttestationRevocationSetPath = mDeviceAttestationRevocationSetPath.substr(0, 0); +} + // This method parses the below JSON Scheme // [ // { @@ -63,10 +69,10 @@ CHIP_ERROR TestDACRevocationDelegateImpl::SetDeviceAttestationRevocationSetPath( bool TestDACRevocationDelegateImpl::IsEntryInRevocationSet(const CharSpan & akidHexStr, const CharSpan & issuerNameBase64Str, const CharSpan & serialNumberHexStr) { - std::ifstream file(mDeviceAttestationRevocationSetPath); + std::ifstream file(mDeviceAttestationRevocationSetPath.data()); if (!file.is_open()) { - ChipLogError(NotSpecified, "Failed to open file: %s", mDeviceAttestationRevocationSetPath); + ChipLogError(NotSpecified, "Failed to open file: %s", mDeviceAttestationRevocationSetPath.data()); return false; } @@ -139,7 +145,7 @@ CHIP_ERROR TestDACRevocationDelegateImpl::GetIssuerNameBase64Str(const ByteSpan ReturnErrorOnFailure(ExtractIssuerFromX509Cert(certDer, issuer)); VerifyOrReturnError(outIssuerNameBase64String.size() >= BASE64_ENCODED_LEN(issuer.size()), CHIP_ERROR_BUFFER_TOO_SMALL); - uint32_t encodedLen = Base64Encode32(issuer.data(), static_cast(issuer.size()), outIssuerNameBase64String.data()); + uint16_t encodedLen = Base64Encode(issuer.data(), static_cast(issuer.size()), outIssuerNameBase64String.data()); outIssuerNameBase64String.reduce_size(encodedLen); return CHIP_NO_ERROR; } @@ -165,6 +171,8 @@ bool TestDACRevocationDelegateImpl::IsCertificateRevoked(const ByteSpan & certDe VerifyOrReturnValue(CHIP_NO_ERROR == GetAKIDHexStr(certDer, akid), false); ChipLogDetail(NotSpecified, "AKID: %.*s", static_cast(akid.size()), akid.data()); + // TODO: Cross-validate the CRLSignerCertificate and CRLSignerDelegator per spec: #34587 + return IsEntryInRevocationSet(akid, issuerName, serialNumber); } @@ -174,30 +182,36 @@ void TestDACRevocationDelegateImpl::CheckForRevokedDACChain( { AttestationVerificationResult attestationError = AttestationVerificationResult::kSuccess; - if (mDeviceAttestationRevocationSetPath != nullptr) + if (mDeviceAttestationRevocationSetPath.empty()) { - ChipLogDetail(NotSpecified, "Checking for revoked DAC in %s", mDeviceAttestationRevocationSetPath); - if (IsCertificateRevoked(info.dacDerBuffer)) + + onCompletion->mCall(onCompletion->mContext, info, attestationError); + } + + ChipLogDetail(NotSpecified, "Checking for revoked DAC in %s", mDeviceAttestationRevocationSetPath.data()); + + if (IsCertificateRevoked(info.dacDerBuffer)) + { + ChipLogProgress(NotSpecified, "Found revoked DAC in %s", mDeviceAttestationRevocationSetPath.data()); + attestationError = AttestationVerificationResult::kDacRevoked; + } + + ChipLogDetail(NotSpecified, "Checking for revoked PAI in %s", mDeviceAttestationRevocationSetPath.data()); + + if (IsCertificateRevoked(info.paiDerBuffer)) + { + ChipLogProgress(NotSpecified, "Found revoked PAI in %s", mDeviceAttestationRevocationSetPath.data()); + + if (attestationError == AttestationVerificationResult::kDacRevoked) { - ChipLogProgress(NotSpecified, "Found revoked DAC in %s", mDeviceAttestationRevocationSetPath); - attestationError = AttestationVerificationResult::kDacRevoked; + attestationError = AttestationVerificationResult::kPaiAndDacRevoked; } - - ChipLogDetail(NotSpecified, "Checking for revoked PAI in %s", mDeviceAttestationRevocationSetPath); - if (IsCertificateRevoked(info.paiDerBuffer)) + else { - ChipLogProgress(NotSpecified, "Found revoked PAI in %s", mDeviceAttestationRevocationSetPath); - - if (attestationError == AttestationVerificationResult::kDacRevoked) - { - attestationError = AttestationVerificationResult::kPaiAndDacRevoked; - } - else - { - attestationError = AttestationVerificationResult::kPaiRevoked; - } + attestationError = AttestationVerificationResult::kPaiRevoked; } } + onCompletion->mCall(onCompletion->mContext, info, attestationError); } diff --git a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h index 3960f4a6e5f2e9..c820e56f5f6ce3 100644 --- a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h +++ b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h @@ -19,6 +19,7 @@ #include #include +#include namespace chip { namespace Credentials { @@ -43,11 +44,11 @@ class TestDACRevocationDelegateImpl : public DeviceAttestationRevocationDelegate // Set the path to the device attestation revocation set JSON file. // revocation set can be generated using credentials/generate-revocation-set.py script // This API returns CHIP_ERROR_INVALID_ARGUMENT if the path is null. - CHIP_ERROR SetDeviceAttestationRevocationSetPath(const char * path); + CHIP_ERROR SetDeviceAttestationRevocationSetPath(std::string_view path); // Clear the path to the device attestation revocation set JSON file. // This can be used to skip the revocation check - void ClearDeviceAttestationRevocationSetPath() { mDeviceAttestationRevocationSetPath = nullptr; } + void ClearDeviceAttestationRevocationSetPath(); private: CHIP_ERROR GetAKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outAKIDHexStr); @@ -57,7 +58,7 @@ class TestDACRevocationDelegateImpl : public DeviceAttestationRevocationDelegate const CharSpan & serialNumberHexStr); bool IsCertificateRevoked(const ByteSpan & certDer); - const char * mDeviceAttestationRevocationSetPath = nullptr; + std::string_view mDeviceAttestationRevocationSetPath; }; } // namespace Credentials diff --git a/src/credentials/tests/BUILD.gn b/src/credentials/tests/BUILD.gn index 99cb1e8e20d322..393b246ef20ee3 100644 --- a/src/credentials/tests/BUILD.gn +++ b/src/credentials/tests/BUILD.gn @@ -68,6 +68,7 @@ chip_test_suite("tests") { "${chip_root}/src/controller:controller", "${chip_root}/src/credentials", "${chip_root}/src/credentials:default_attestation_verifier", + "${chip_root}/src/credentials:test_dac_revocation_delegate", "${chip_root}/src/lib/core", "${chip_root}/src/lib/core:string-builder-adapters", "${chip_root}/src/lib/support:testing", diff --git a/src/credentials/tests/TestDeviceAttestationCredentials.cpp b/src/credentials/tests/TestDeviceAttestationCredentials.cpp index d2dc0317c94a5c..0f80df9fa9f6f4 100644 --- a/src/credentials/tests/TestDeviceAttestationCredentials.cpp +++ b/src/credentials/tests/TestDeviceAttestationCredentials.cpp @@ -419,6 +419,8 @@ TEST_F(TestDeviceAttestationCredentials, TestAttestationTrustStore) static void WriteTestRevokedData(const char * jsonData, const char * fileName) { + // TODO: Add option to load test data from the test without using file. #34588 + // write data to /tmp/sample_revoked_set.json using fstream APIs std::ofstream file; file.open(fileName, std::ofstream::out | std::ofstream::trunc);