Skip to content

Commit

Permalink
Make PAA trust store configurable (#12277)
Browse files Browse the repository at this point in the history
* Make PAA store configurable

PAA store used by DefaultDeviceAttestationVerifier could not be
replaced, forcing a few fixed test roots to always be used and
nothing else, unless completely forking the
DefaultDeviceAttestationVerifier.

- This PR introduces the `PaaRootStore` interface, which the
  default `DeviceAttestationVerifier` expects to get configured
  at in constructor.
- Examples were modified to use the default test PAA root store
- Unit tests updated to use the testing root store
- Refactored simple array-based Root store to self-extract
  the SKID

Testing done: added new units tests which pass, ran cert tests,
validated attestation succeeds the same as before with test keys.

Fixed #11913

* Restyled by clang-format

* Address review comments

- Rename PaaRootStore to AttestationTrustStore
- Add comments about ArrayAttestationtTrustStore lifecycle
- Remove debug print

* Fix python build

* Fix tv-app scoping issue

* Attempt to debug Darwin error

* Restyled by clang-format

* Remove debug logging used to diagnose CI

Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
2 people authored and pull[bot] committed Aug 15, 2023
1 parent e4058ec commit 1194735
Show file tree
Hide file tree
Showing 16 changed files with 314 additions and 128 deletions.
5 changes: 4 additions & 1 deletion examples/chip-tool/commands/common/CHIPCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ CHIP_ERROR CHIPCommand::Run()
chip::Platform::ScopedMemoryBuffer<uint8_t> rcac;

chip::Credentials::SetDeviceAttestationCredentialsProvider(chip::Credentials::Examples::GetExampleDACProvider());
chip::Credentials::SetDeviceAttestationVerifier(chip::Credentials::GetDefaultDACVerifier());

// TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available
const chip::Credentials::AttestationTrustStore * testingRootStore = chip::Credentials::GetTestAttestationTrustStore();
chip::Credentials::SetDeviceAttestationVerifier(chip::Credentials::GetDefaultDACVerifier(testingRootStore));

VerifyOrReturnError(noc.Alloc(chip::Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY);
VerifyOrReturnError(icac.Alloc(chip::Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY);
Expand Down
4 changes: 3 additions & 1 deletion examples/platform/linux/AppMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,9 @@ CHIP_ERROR InitCommissioner()
ReturnErrorOnFailure(gCommissioner.SetUdcListenPort(LinuxDeviceOptions::GetInstance().unsecuredCommissionerPort));

// Initialize device attestation verifier
SetDeviceAttestationVerifier(GetDefaultDACVerifier());
// TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available
const chip::Credentials::AttestationTrustStore * testingRootStore = chip::Credentials::GetTestAttestationTrustStore();
SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore));

chip::Platform::ScopedMemoryBuffer<uint8_t> noc;
VerifyOrReturnError(noc.Alloc(chip::Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY);
Expand Down
8 changes: 6 additions & 2 deletions examples/tv-casting-app/linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,12 @@ int main(int argc, char * argv[])
// Initialize device attestation config
SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider());

// Initialize device attestation verifier
SetDeviceAttestationVerifier(GetDefaultDACVerifier());
// Initialize device attestation verifier from a constant version
{
// TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available
const chip::Credentials::AttestationTrustStore * testingRootStore = chip::Credentials::GetTestAttestationTrustStore();
SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore));
}

if (!chip::ArgParser::ParseArgs(argv[0], argc, argv, allOptions))
{
Expand Down
4 changes: 3 additions & 1 deletion src/controller/java/AndroidDeviceControllerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,9 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(Jav
wrapper->SetJavaObjectRef(vm, deviceControllerObj);

// Initialize device attestation verifier
SetDeviceAttestationVerifier(GetDefaultDACVerifier());
// TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available
const chip::Credentials::AttestationTrustStore * testingRootStore = chip::Credentials::GetTestAttestationTrustStore();
SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore));

chip::Controller::FactoryInitParams initParams;
chip::Controller::SetupParams setupParams;
Expand Down
4 changes: 3 additions & 1 deletion src/controller/python/ChipDeviceController-ScriptBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,9 @@ ChipError::StorageType pychip_DeviceController_NewDeviceController(chip::Control
}

// Initialize device attestation verifier
SetDeviceAttestationVerifier(GetDefaultDACVerifier());
// TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available
const chip::Credentials::AttestationTrustStore * testingRootStore = chip::Credentials::GetTestAttestationTrustStore();
SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore));

CHIP_ERROR err = sOperationalCredentialsIssuer.Initialize(sStorageDelegate);
VerifyOrReturnError(err == CHIP_NO_ERROR, err.AsInteger());
Expand Down
8 changes: 5 additions & 3 deletions src/controller/python/chip/internal/CommissionerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ extern "C" chip::Controller::DeviceCommissioner * pychip_internal_Commissioner_N
chip::Platform::ScopedMemoryBuffer<uint8_t> rcac;
chip::Crypto::P256Keypair ephemeralKey;

// Initialize device attestation verifier
// TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available
const chip::Credentials::AttestationTrustStore * testingRootStore = chip::Credentials::GetTestAttestationTrustStore();
chip::Credentials::SetDeviceAttestationVerifier(chip::Credentials::GetDefaultDACVerifier(testingRootStore));

err = gFabricStorage.Initialize(&gServerStorage);
SuccessOrExit(err);

Expand All @@ -116,9 +121,6 @@ extern "C" chip::Controller::DeviceCommissioner * pychip_internal_Commissioner_N
commissionerParams.pairingDelegate = &gPairingDelegate;
commissionerParams.storageDelegate = &gServerStorage;

// Initialize device attestation verifier
chip::Credentials::SetDeviceAttestationVerifier(chip::Credentials::GetDefaultDACVerifier());

err = ephemeralKey.Initialize();
SuccessOrExit(err);

Expand Down
2 changes: 1 addition & 1 deletion src/credentials/CHIPCert.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
namespace chip {
namespace Credentials {

static constexpr uint32_t kKeyIdentifierLength = 20;
static constexpr uint32_t kKeyIdentifierLength = static_cast<uint32_t>(Crypto::kSubjectKeyIdentifierLength);
static constexpr uint32_t kChip32bitAttrUTF8Length = 8;
static constexpr uint32_t kChip64bitAttrUTF8Length = 16;
static constexpr uint16_t kX509NoWellDefinedExpirationDateYear = 9999;
Expand Down
81 changes: 81 additions & 0 deletions src/credentials/DeviceAttestationVerifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,87 @@ struct DeviceInfoForAttestation
uint16_t paaVendorId = VendorId::NotSpecified;
};

/**
* @brief Helper utility to model a basic trust store usable for device attestation verifiers.
*
* API is synchronous. Real commissioner implementations may entirely
* hide Product Attestation Authority cert lookup behind the DeviceAttestationVerifier and
* never use this interface at all. It is provided as a utility to help build DeviceAttestationVerifier
* implementations suitable for testing or examples.
*/
class AttestationTrustStore
{
public:
AttestationTrustStore() = default;
virtual ~AttestationTrustStore() = default;

// Not copyable
AttestationTrustStore(const AttestationTrustStore &) = delete;
AttestationTrustStore & operator=(const AttestationTrustStore &) = delete;

/**
* @brief Look-up a PAA cert by SKID
*
* The implementations of this interface must have access to a set of PAAs to trust.
*
* Interface is synchronous, and therefore this should not be used unless to expose a PAA
* store that is both fully local and quick to access.
*
* @param[in] skid Buffer containing the subject key identifier (SKID) of the PAA to look-up
* @param[inout] outPaaDerBuffer Buffer to receive the contents of the PAA root cert, if found.
* Size will be updated to match actual size.
*
* @returns CHIP_NO_ERROR on success, CHIP_INVALID_ARGUMENT if `skid` or `outPaaDerBuffer` arguments
* are not usable, CHIP_BUFFER_TOO_SMALL if certificate doesn't fit in `outPaaDerBuffer`
* span, CHIP_ERROR_CA_CERT_NOT_FOUND if no PAA found that matches `skid.
*
*/
virtual CHIP_ERROR GetProductAttestationAuthorityCert(const ByteSpan & skid, MutableByteSpan & outPaaDerBuffer) const = 0;
};

/**
* @brief Basic AttestationTrustStore that holds all data within caller-owned memory.
*
* This is useful to wrap a fixed constant array of certificates into a trust store
* implementation.
*/

class ArrayAttestationTrustStore : public AttestationTrustStore
{
public:
ArrayAttestationTrustStore(const ByteSpan * derCerts, size_t numCerts) : mDerCerts(derCerts), mNumCerts(numCerts) {}

CHIP_ERROR GetProductAttestationAuthorityCert(const ByteSpan & skid, MutableByteSpan & outPaaDerBuffer) const override
{
VerifyOrReturnError(!skid.empty() && (skid.data() != nullptr), CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(skid.size() == Crypto::kSubjectKeyIdentifierLength, CHIP_ERROR_INVALID_ARGUMENT);

size_t paaIdx;
ByteSpan candidate;

for (paaIdx = 0; paaIdx < mNumCerts; ++paaIdx)
{
uint8_t skidBuf[Crypto::kSubjectKeyIdentifierLength] = { 0 };
candidate = mDerCerts[paaIdx];
MutableByteSpan candidateSkidSpan{ skidBuf };
VerifyOrReturnError(CHIP_NO_ERROR == Crypto::ExtractSKIDFromX509Cert(candidate, candidateSkidSpan),
CHIP_ERROR_INTERNAL);

if (skid.data_equal(candidateSkidSpan))
{
// Found a match
return CopySpanToMutableSpan(candidate, outPaaDerBuffer);
}
}

return CHIP_ERROR_CA_CERT_NOT_FOUND;
}

protected:
const ByteSpan * mDerCerts;
const size_t mNumCerts;
};

class DeviceAttestationVerifier
{
public:
Expand Down
Loading

0 comments on commit 1194735

Please sign in to comment.