Skip to content

Commit 151bcd8

Browse files
committed
Address comments
Added an interface for device attestation revocation and the test implementation for the same.
1 parent 32c684e commit 151bcd8

10 files changed

+307
-172
lines changed

examples/chip-tool/commands/common/CHIPCommand.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,10 @@ CHIP_ERROR CHIPCommand::InitializeCommissioner(CommissionerIdentity & identity,
452452

453453
ReturnLogErrorOnFailure(mCredIssuerCmds->SetupDeviceAttestation(commissionerParams, sTrustStore));
454454

455-
mCredIssuerCmds->SetupDeviceAttestationRevocationSetPath(mDacRevocationSetPath.ValueOr(nullptr));
455+
if (mDacRevocationSetPath.HasValue())
456+
{
457+
ReturnLogErrorOnFailure(mCredIssuerCmds->SetDeviceAttestationRevocationSetPath(mDacRevocationSetPath.Value()));
458+
}
456459

457460
chip::Crypto::P256Keypair ephemeralKey;
458461

examples/chip-tool/commands/common/CredentialIssuerCommands.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,10 @@ class CredentialIssuerCommands
6868
*
6969
* @param[in] path Path to the JSON file containing list of revoked DACs or PAIs.
7070
* It can be generated using credentials/generate-revocation-set.py script
71+
*
72+
* @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error code.
7173
*/
72-
virtual void SetupDeviceAttestationRevocationSetPath(const char * path) = 0;
74+
virtual CHIP_ERROR SetDeviceAttestationRevocationSetPath(const char * path) = 0;
7375

7476
/**
7577
* @brief Add a list of additional non-default CD verifying keys (by certificate)

examples/chip-tool/commands/example/ExampleCredentialIssuerCommands.h

+7-7
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <credentials/DeviceAttestationCredsProvider.h>
2525
#include <credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h>
2626
#include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
27+
#include <credentials/attestation_verifier/TestDACRevocationDelegateImpl.h>
2728
#include <credentials/examples/DeviceAttestationCredsExample.h>
2829

2930
class ExampleCredentialIssuerCommands : public CredentialIssuerCommands
@@ -45,14 +46,12 @@ class ExampleCredentialIssuerCommands : public CredentialIssuerCommands
4546
return CHIP_NO_ERROR;
4647
}
4748

48-
void SetupDeviceAttestationRevocationSetPath(const char * path) override
49+
CHIP_ERROR SetDeviceAttestationRevocationSetPath(const char * path) override
4950
{
50-
if (path)
51-
{
52-
// As we know that we are using DefaultDACVerifier, we can downcast from
53-
// DeviceAttestationVerifier to DefaultDACVerifier to set the revocation set
54-
static_cast<chip::Credentials::DefaultDACVerifier *>(mDacVerifier)->SetDeviceAttestationRevocationSetPath(path);
55-
}
51+
VerifyOrReturnError(path != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
52+
ReturnErrorOnFailure(mTestDacRevocationDelegate.SetDeviceAttestationRevocationSetPath(path));
53+
mDacVerifier->SetRevocationDelegate(&mTestDacRevocationDelegate);
54+
return CHIP_NO_ERROR;
5655
}
5756

5857
chip::Controller::OperationalCredentialsDelegate * GetCredentialIssuer() override { return &mOpCredsIssuer; }
@@ -119,4 +118,5 @@ class ExampleCredentialIssuerCommands : public CredentialIssuerCommands
119118
private:
120119
chip::Controller::ExampleOperationalCredentialsIssuer mOpCredsIssuer;
121120
chip::Credentials::DeviceAttestationVerifier * mDacVerifier;
121+
chip::Credentials::TestDACRevocationDelegateImpl mTestDacRevocationDelegate;
122122
};

scripts/tools/check_includes_config.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@
137137

138138
'src/credentials/attestation_verifier/FileAttestationTrustStore.h': {'vector'},
139139
'src/credentials/attestation_verifier/FileAttestationTrustStore.cpp': {'string'},
140-
'src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp': {'fstream'},
140+
'src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp': {'fstream'},
141141

142142
'src/setup_payload/AdditionalDataPayload.h': {'string'},
143143
'src/setup_payload/AdditionalDataPayloadParser.cpp': {'vector', 'string'},

src/credentials/BUILD.gn

+2
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ static_library("default_attestation_verifier") {
158158
"attestation_verifier/DefaultDeviceAttestationVerifier.cpp",
159159
"attestation_verifier/DefaultDeviceAttestationVerifier.h",
160160
"attestation_verifier/DeviceAttestationDelegate.h",
161+
"attestation_verifier/TestDACRevocationDelegateImpl.cpp",
162+
"attestation_verifier/TestDACRevocationDelegateImpl.h",
161163
]
162164

163165
if (chip_device_platform == "esp32" || chip_device_platform == "nrfconnect" ||

src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp

+6-144
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,10 @@
2626

2727
#include <lib/core/CHIPError.h>
2828
#include <lib/core/Global.h>
29-
#include <lib/support/Base64.h>
30-
#include <lib/support/BytesToHex.h>
3129
#include <lib/support/CodeUtils.h>
3230
#include <lib/support/ScopedBuffer.h>
3331
#include <lib/support/Span.h>
3432

35-
#include <fstream>
36-
#include <json/json.h>
37-
#include <string.h>
38-
3933
using namespace chip::Crypto;
4034
using chip::TestCerts::GetTestPaaRootStore;
4135

@@ -613,149 +607,17 @@ CHIP_ERROR DefaultDACVerifier::VerifyNodeOperationalCSRInformation(const ByteSpa
613607
return CHIP_NO_ERROR;
614608
}
615609

616-
// This method parses the below JSON Scheme
617-
// [
618-
// {
619-
// "type": "revocation_set",
620-
// "issuer_subject_key_id": "63540E47F64B1C38D13884A462D16C195D8FFB3C",
621-
// "issuer_name": "MD0xJTAjBgNVBAMMHE1hdHRlciBEZXYgUEFJIDB4RkZGMSBubyBQSUQxFDASBgorBgEEAYKifAIBDARGRkYx",
622-
// "revoked_serial_numbers": [
623-
// "69CDF10DE9E54ED1"
624-
// ]
625-
// }
626-
// ]
627-
//
628-
bool DefaultDACVerifier::IsEntryExistsInRevocationSet(const CharSpan & akidHexStr, const CharSpan & issuerNameBase64Str,
629-
const CharSpan & serialNumberHexStr)
630-
{
631-
std::ifstream file(mDeviceAttestationRevocationSetPath);
632-
if (!file.is_open())
633-
{
634-
return false;
635-
}
636-
637-
// Parse the JSON data incrementally
638-
Json::CharReaderBuilder readerBuilder;
639-
Json::Value jsonData;
640-
std::string errs;
641-
642-
bool parsingSuccessful = Json::parseFromStream(readerBuilder, file, &jsonData, &errs);
643-
644-
// Close the file as it's no longer needed
645-
file.close();
646-
647-
if (!parsingSuccessful)
648-
{
649-
return false;
650-
}
651-
652-
for (const auto & revokedSet : jsonData)
653-
{
654-
if (strncmp(revokedSet["issuer_name"].asCString(), issuerNameBase64Str.data(), issuerNameBase64Str.size()) == 0 &&
655-
strncmp(revokedSet["issuer_subject_key_id"].asCString(), akidHexStr.data(), akidHexStr.size()) == 0)
656-
{
657-
for (const auto & revokedSerialNumber : revokedSet["revoked_serial_numbers"])
658-
{
659-
if (strncmp(revokedSerialNumber.asCString(), serialNumberHexStr.data(), serialNumberHexStr.size()) == 0)
660-
{
661-
return true;
662-
}
663-
}
664-
}
665-
}
666-
return false;
667-
}
668-
669-
CHIP_ERROR DefaultDACVerifier::GetAKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outAKIDHexStr)
670-
{
671-
uint8_t akidBuf[kAuthorityKeyIdentifierLength];
672-
MutableByteSpan akid(akidBuf);
673-
674-
CHIP_ERROR err = ExtractAKIDFromX509Cert(certDer, akid);
675-
VerifyOrReturnError(err == CHIP_NO_ERROR, err);
676-
VerifyOrReturnError(outAKIDHexStr.size() > akid.size() * 2, CHIP_ERROR_BUFFER_TOO_SMALL);
677-
678-
Encoding::HexFlags flags = Encoding::HexFlags::kUppercaseAndNullTerminate;
679-
err = BytesToHex(akid.data(), akid.size(), outAKIDHexStr.data(), outAKIDHexStr.size(), flags);
680-
VerifyOrReturnError(err == CHIP_NO_ERROR, err);
681-
682-
outAKIDHexStr.reduce_size(strlen(outAKIDHexStr.data()));
683-
return CHIP_NO_ERROR;
684-
}
685-
686-
CHIP_ERROR DefaultDACVerifier::GetSerialNumberHexStr(const ByteSpan & certDer, MutableCharSpan & outSerialNumberHexStr)
687-
{
688-
uint8_t serialNumberBuf[kMaxCertificateSerialNumberLength] = { 0 };
689-
MutableByteSpan serialNumber(serialNumberBuf);
690-
691-
CHIP_ERROR err = ExtractSerialNumberFromX509Cert(certDer, serialNumber);
692-
VerifyOrReturnError(err == CHIP_NO_ERROR, err);
693-
VerifyOrReturnError(outSerialNumberHexStr.size() > serialNumber.size() * 2, CHIP_ERROR_BUFFER_TOO_SMALL);
694-
695-
Encoding::HexFlags flags = Encoding::HexFlags::kUppercaseAndNullTerminate;
696-
err = BytesToHex(serialNumber.data(), serialNumber.size(), outSerialNumberHexStr.data(), outSerialNumberHexStr.size(), flags);
697-
VerifyOrReturnError(err == CHIP_NO_ERROR, err);
698-
699-
outSerialNumberHexStr.reduce_size(strlen(outSerialNumberHexStr.data()));
700-
return CHIP_NO_ERROR;
701-
}
702-
703-
CHIP_ERROR DefaultDACVerifier::GetIssuerNameBase64Str(const ByteSpan & certDer, MutableCharSpan & outIssuerNameBase64String)
704-
{
705-
uint8_t issuerBuf[kMaxCertificateDistinguishedNameLength] = { 0 };
706-
MutableByteSpan issuer(issuerBuf);
707-
708-
CHIP_ERROR err = ExtractIssuerFromX509Cert(certDer, issuer);
709-
VerifyOrReturnError(CHIP_NO_ERROR == err, err);
710-
VerifyOrReturnError(outIssuerNameBase64String.size() > BASE64_ENCODED_LEN(issuer.size()), CHIP_ERROR_BUFFER_TOO_SMALL);
711-
712-
uint32_t encodedLen = Base64Encode32(issuer.data(), static_cast<uint32_t>(issuer.size()), outIssuerNameBase64String.data());
713-
outIssuerNameBase64String.reduce_size(encodedLen);
714-
return CHIP_NO_ERROR;
715-
}
716-
717-
bool DefaultDACVerifier::IsCertificateRevoked(const ByteSpan & certDer)
718-
{
719-
static constexpr uint32_t maxIssuerBase64Len = BASE64_ENCODED_LEN(kMaxCertificateDistinguishedNameLength) + 1;
720-
721-
char issuerNameBuffer[maxIssuerBase64Len] = { 0 };
722-
char serialNumberHexStrBuffer[2 * kMaxCertificateSerialNumberLength + 1] = { 0 };
723-
char akidHexStrBuffer[2 * kAuthorityKeyIdentifierLength + 1] = { 0 };
724-
725-
MutableCharSpan issuerName(issuerNameBuffer);
726-
MutableCharSpan serialNumber(serialNumberHexStrBuffer);
727-
MutableCharSpan akid(akidHexStrBuffer);
728-
729-
CHIP_ERROR err = GetIssuerNameBase64Str(certDer, issuerName);
730-
VerifyOrReturnValue(err == CHIP_NO_ERROR, false);
731-
732-
err = GetSerialNumberHexStr(certDer, serialNumber);
733-
VerifyOrReturnValue(err == CHIP_NO_ERROR, false);
734-
735-
err = GetAKIDHexStr(certDer, akid);
736-
VerifyOrReturnValue(err == CHIP_NO_ERROR, false);
737-
738-
return IsEntryExistsInRevocationSet(akid, issuerName, serialNumber);
739-
}
740-
741610
void DefaultDACVerifier::CheckForRevokedDACChain(const AttestationInfo & info,
742611
Callback::Callback<OnAttestationInformationVerification> * onCompletion)
743612
{
744-
AttestationVerificationResult attestationError = AttestationVerificationResult::kSuccess;
745-
746-
if (mDeviceAttestationRevocationSetPath != nullptr)
613+
if (mRevocationDelegate != nullptr)
747614
{
748-
if (IsCertificateRevoked(info.dacDerBuffer))
749-
{
750-
attestationError = AttestationVerificationResult::kDacRevoked;
751-
}
752-
if (IsCertificateRevoked(info.paiDerBuffer))
753-
{
754-
attestationError = AttestationVerificationResult::kPaiRevoked;
755-
}
615+
mRevocationDelegate->CheckForRevokedDACChain(info, onCompletion);
616+
}
617+
else
618+
{
619+
onCompletion->mCall(onCompletion->mContext, info, AttestationVerificationResult::kSuccess);
756620
}
757-
758-
onCompletion->mCall(onCompletion->mContext, info, attestationError);
759621
}
760622

761623
bool CsaCdKeysTrustStore::IsCdTestKey(const ByteSpan & kid) const

src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h

-18
Original file line numberDiff line numberDiff line change
@@ -77,31 +77,13 @@ class DefaultDACVerifier : public DeviceAttestationVerifier
7777
void CheckForRevokedDACChain(const AttestationInfo & info,
7878
Callback::Callback<OnAttestationInformationVerification> * onCompletion) override;
7979

80-
// Set the path to the device attestation revocation set JSON file.
81-
// revocation set can be generated using credentials/generate-revocation-set.py script
82-
void SetDeviceAttestationRevocationSetPath(const char * path) { mDeviceAttestationRevocationSetPath = path; }
83-
8480
CsaCdKeysTrustStore * GetCertificationDeclarationTrustStore() override { return &mCdKeysTrustStore; }
8581

8682
protected:
8783
DefaultDACVerifier() {}
8884

8985
CsaCdKeysTrustStore mCdKeysTrustStore;
9086
const AttestationTrustStore * mAttestationTrustStore;
91-
92-
private:
93-
CHIP_ERROR GetAKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outAKIDHexString);
94-
CHIP_ERROR GetSerialNumberHexStr(const ByteSpan & certDer, MutableCharSpan & outSerialNumberHexString);
95-
CHIP_ERROR GetIssuerNameBase64Str(const ByteSpan & certDer, MutableCharSpan & outIssuerNameBase64String);
96-
97-
bool IsCertificateRevoked(const ByteSpan & certDer);
98-
99-
// Searches the revocation set and returns true if for the given AKID, issuer name and serial number
100-
// the entry is found in the revocation set, false otherwise.
101-
bool IsEntryExistsInRevocationSet(const CharSpan & akidHexStr, const CharSpan & issuerNameBase64Str,
102-
const CharSpan & serialNumberHexStr);
103-
104-
const char * mDeviceAttestationRevocationSetPath = nullptr;
10587
};
10688

10789
/**

src/credentials/attestation_verifier/DeviceAttestationVerifier.h

+28
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ class ArrayAttestationTrustStore : public AttestationTrustStore
259259
const size_t mNumCerts;
260260
};
261261

262+
class DeviceAttestationRevocationDelegate;
263+
262264
class DeviceAttestationVerifier
263265
{
264266
public:
@@ -409,13 +411,39 @@ class DeviceAttestationVerifier
409411
void EnableCdTestKeySupport(bool enabled) { mEnableCdTestKeySupport = enabled; }
410412
bool IsCdTestKeySupported() const { return mEnableCdTestKeySupport; }
411413

414+
void SetRevocationDelegate(DeviceAttestationRevocationDelegate * delegate) { mRevocationDelegate = delegate; }
415+
412416
protected:
413417
CHIP_ERROR ValidateAttestationSignature(const Crypto::P256PublicKey & pubkey, const ByteSpan & attestationElements,
414418
const ByteSpan & attestationChallenge, const Crypto::P256ECDSASignature & signature);
415419

416420
// Default to support the "development" test key for legacy purposes (since the DefaultDACVerifier)
417421
// always supported development keys.
418422
bool mEnableCdTestKeySupport = true;
423+
424+
DeviceAttestationRevocationDelegate * mRevocationDelegate = nullptr;
425+
};
426+
427+
/**
428+
* @brief Interface for checking the device attestation revocation status
429+
*
430+
*/
431+
class DeviceAttestationRevocationDelegate
432+
{
433+
public:
434+
DeviceAttestationRevocationDelegate() = default;
435+
virtual ~DeviceAttestationRevocationDelegate() = default;
436+
437+
/**
438+
* @brief Verify whether or not the given DAC chain is revoked.
439+
*
440+
* @param[in] info All of the information required to check for revoked DAC chain.
441+
* @param[in] onCompletion Callback handler to provide Attestation Information Verification result to the caller of
442+
* CheckForRevokedDACChain().
443+
*/
444+
virtual void
445+
CheckForRevokedDACChain(const DeviceAttestationVerifier::AttestationInfo & info,
446+
Callback::Callback<DeviceAttestationVerifier::OnAttestationInformationVerification> * onCompletion) = 0;
419447
};
420448

421449
/**

0 commit comments

Comments
 (0)