From 83591d7d7fcd77ce37e6c2b31677a2fb26950784 Mon Sep 17 00:00:00 2001 From: Tennessee Carmel-Veilleux Date: Thu, 25 Nov 2021 16:54:43 -0500 Subject: [PATCH] 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 --- .../chip-tool/commands/common/CHIPCommand.cpp | 5 +- examples/platform/linux/AppMain.cpp | 4 +- examples/tv-casting-app/linux/main.cpp | 4 +- .../java/AndroidDeviceControllerWrapper.cpp | 4 +- .../ChipDeviceController-ScriptBinding.cpp | 4 +- .../python/chip/internal/CommissionerImpl.cpp | 4 +- src/credentials/CHIPCert.h | 2 +- src/credentials/DeviceAttestationVerifier.h | 74 +++++++++++ .../DefaultDeviceAttestationVerifier.cpp | 124 +++++++++--------- .../DefaultDeviceAttestationVerifier.h | 22 +++- .../tests/TestCertificationDeclaration.cpp | 4 +- .../TestDeviceAttestationCredentials.cpp | 73 ++++++++++- src/crypto/CHIPCryptoPAL.h | 2 + src/crypto/tests/CHIPCryptoPALTest.cpp | 4 +- .../Framework/CHIP/CHIPDeviceController.mm | 4 +- src/protocols/secure_channel/CASESession.h | 2 +- 16 files changed, 253 insertions(+), 83 deletions(-) diff --git a/examples/chip-tool/commands/common/CHIPCommand.cpp b/examples/chip-tool/commands/common/CHIPCommand.cpp index 44921d77b457f9..a2c8aa7724eb7f 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.cpp +++ b/examples/chip-tool/commands/common/CHIPCommand.cpp @@ -45,7 +45,10 @@ CHIP_ERROR CHIPCommand::Run() chip::Platform::ScopedMemoryBuffer rcac; chip::Credentials::SetDeviceAttestationCredentialsProvider(chip::Credentials::Examples::GetExampleDACProvider()); - chip::Credentials::SetDeviceAttestationVerifier(chip::Credentials::GetDefaultDACVerifier()); + + // TODO: Replace testingRootStore with a PaaRootStore that has the necessary official PAA roots available + const chip::Credentials::PaaRootStore * testingRootStore = chip::Credentials::GetTestPaaRootStore(); + 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); diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp index 5b79f089d13674..5efb8ad663372f 100644 --- a/examples/platform/linux/AppMain.cpp +++ b/examples/platform/linux/AppMain.cpp @@ -234,7 +234,9 @@ CHIP_ERROR InitCommissioner() ReturnErrorOnFailure(gCommissioner.SetUdcListenPort(LinuxDeviceOptions::GetInstance().unsecuredCommissionerPort)); // Initialize device attestation verifier - SetDeviceAttestationVerifier(GetDefaultDACVerifier()); + // TODO: Replace testingRootStore with a PaaRootStore that has the necessary official PAA roots available + const chip::Credentials::PaaRootStore * testingRootStore = chip::Credentials::GetTestPaaRootStore(); + SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore)); chip::Platform::ScopedMemoryBuffer noc; VerifyOrReturnError(noc.Alloc(chip::Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY); diff --git a/examples/tv-casting-app/linux/main.cpp b/examples/tv-casting-app/linux/main.cpp index e2b356db9ae093..daf3faf1016fc7 100644 --- a/examples/tv-casting-app/linux/main.cpp +++ b/examples/tv-casting-app/linux/main.cpp @@ -196,7 +196,9 @@ int main(int argc, char * argv[]) SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); // Initialize device attestation verifier - SetDeviceAttestationVerifier(GetDefaultDACVerifier()); + // TODO: Replace testingRootStore with a PaaRootStore that has the necessary official PAA roots available + const chip::Credentials::PaaRootStore * testingRootStore = chip::Credentials::GetTestPaaRootStore(); + SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore)); if (!chip::ArgParser::ParseArgs(argv[0], argc, argv, allOptions)) { diff --git a/src/controller/java/AndroidDeviceControllerWrapper.cpp b/src/controller/java/AndroidDeviceControllerWrapper.cpp index bb18387a38a488..62a9d755a4b6ec 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.cpp +++ b/src/controller/java/AndroidDeviceControllerWrapper.cpp @@ -204,7 +204,9 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(Jav wrapper->SetJavaObjectRef(vm, deviceControllerObj); // Initialize device attestation verifier - SetDeviceAttestationVerifier(GetDefaultDACVerifier()); + // TODO: Replace testingRootStore with a PaaRootStore that has the necessary official PAA roots available + const chip::Credentials::PaaRootStore * testingRootStore = chip::Credentials::GetTestPaaRootStore(); + SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore)); chip::Controller::FactoryInitParams initParams; chip::Controller::SetupParams setupParams; diff --git a/src/controller/python/ChipDeviceController-ScriptBinding.cpp b/src/controller/python/ChipDeviceController-ScriptBinding.cpp index 9c1b09388d0f7f..7d7953392a49c6 100644 --- a/src/controller/python/ChipDeviceController-ScriptBinding.cpp +++ b/src/controller/python/ChipDeviceController-ScriptBinding.cpp @@ -182,7 +182,9 @@ ChipError::StorageType pychip_DeviceController_NewDeviceController(chip::Control } // Initialize device attestation verifier - SetDeviceAttestationVerifier(GetDefaultDACVerifier()); + // TODO: Replace testingRootStore with a PaaRootStore that has the necessary official PAA roots available + const chip::Credentials::PaaRootStore * testingRootStore = chip::Credentials::GetTestPaaRootStore(); + SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore)); CHIP_ERROR err = sOperationalCredentialsIssuer.Initialize(sStorageDelegate); VerifyOrReturnError(err == CHIP_NO_ERROR, err.AsInteger()); diff --git a/src/controller/python/chip/internal/CommissionerImpl.cpp b/src/controller/python/chip/internal/CommissionerImpl.cpp index 4386fc16ab549b..51c4e3d8c2d192 100644 --- a/src/controller/python/chip/internal/CommissionerImpl.cpp +++ b/src/controller/python/chip/internal/CommissionerImpl.cpp @@ -117,7 +117,9 @@ extern "C" chip::Controller::DeviceCommissioner * pychip_internal_Commissioner_N commissionerParams.storageDelegate = &gServerStorage; // Initialize device attestation verifier - chip::Credentials::SetDeviceAttestationVerifier(chip::Credentials::GetDefaultDACVerifier()); + // TODO: Replace testingRootStore with a PaaRootStore that has the necessary official PAA roots available + const chip::Credentials::PaaRootStore * testingRootStore = chip::Credentials::GetTestPaaRootStore(); + chip::Credentials::SetDeviceAttestationVerifier(chip::Credentials::GetDefaultDACVerifier(testingRootStore)); err = ephemeralKey.Initialize(); SuccessOrExit(err); diff --git a/src/credentials/CHIPCert.h b/src/credentials/CHIPCert.h index 762e0f25f209f6..b957e60283b638 100644 --- a/src/credentials/CHIPCert.h +++ b/src/credentials/CHIPCert.h @@ -42,7 +42,7 @@ namespace chip { namespace Credentials { -static constexpr uint32_t kKeyIdentifierLength = 20; +static constexpr uint32_t kKeyIdentifierLength = static_cast(Crypto::kSubjectKeyIdentifierLength); static constexpr uint32_t kChip32bitAttrUTF8Length = 8; static constexpr uint32_t kChip64bitAttrUTF8Length = 16; static constexpr uint16_t kX509NoWellDefinedExpirationDateYear = 9999; diff --git a/src/credentials/DeviceAttestationVerifier.h b/src/credentials/DeviceAttestationVerifier.h index 09d843153943d5..8e44a9e81195d5 100644 --- a/src/credentials/DeviceAttestationVerifier.h +++ b/src/credentials/DeviceAttestationVerifier.h @@ -99,6 +99,80 @@ struct DeviceInfoForAttestation uint16_t paaVendorId = VendorId::NotSpecified; }; +/** + * @brief Helper utility to model a PAA store. + * + * API is synchronous. Real commissioner implementations may entirely + * hide PAA 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 PaaRootStore +{ +public: + PaaRootStore() = default; + virtual ~PaaRootStore() = default; + + // Not copyable + PaaRootStore(const PaaRootStore &) = delete; + PaaRootStore & operator=(const PaaRootStore &) = 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; +}; + +class ArrayPaaRootStore : public PaaRootStore +{ +public: + explicit ArrayPaaRootStore(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); + + printf("data: %p, size: %zu\n", skid.data(), skid.size()); + if (skid.data_equal(candidateSkidSpan)) + { + // Found a match + return CopySpanToMutableSpan(candidate, outPaaDerBuffer); + } + } + + return CHIP_ERROR_CA_CERT_NOT_FOUND; + } + +protected: + const ByteSpan * mDerCerts; + size_t mNumCerts; +}; + class DeviceAttestationVerifier { public: diff --git a/src/credentials/examples/DefaultDeviceAttestationVerifier.cpp b/src/credentials/examples/DefaultDeviceAttestationVerifier.cpp index b6cf795092fd47..1813332a78917b 100644 --- a/src/credentials/examples/DefaultDeviceAttestationVerifier.cpp +++ b/src/credentials/examples/DefaultDeviceAttestationVerifier.cpp @@ -34,31 +34,21 @@ namespace Credentials { namespace { -CHIP_ERROR GetProductAttestationAuthorityCert(const ByteSpan & skid, MutableByteSpan & outDacBuffer) -{ - struct PAALookupTable - { - const uint8_t mPAACertificate[kMax_x509_Certificate_Length]; - const uint8_t mSKID[kKeyIdentifierLength]; - }; - - static PAALookupTable - sPAALookupTable[] = { - { /* - credentials/test/attestation/Chip-Test-PAA-FFF1-Cert.pem - -----BEGIN CERTIFICATE----- - MIIBmTCCAT+gAwIBAgIIaDhPq7kZ/N8wCgYIKoZIzj0EAwIwHzEdMBsGA1UEAwwU - TWF0dGVyIFRlc3QgUEFBIEZGRjEwIBcNMjEwNjI4MTQyMzQzWhgPOTk5OTEyMzEy - MzU5NTlaMB8xHTAbBgNVBAMMFE1hdHRlciBUZXN0IFBBQSBGRkYxMFkwEwYHKoZI - zj0CAQYIKoZIzj0DAQcDQgAEG5isW7wR3GoXVaBbCsXha6AsRu5vwrvnb/fPbKeq - Tp/R15jcvvtP6uIl03c8kTSMwm1JMTHjCWMtXp7zHRLek6NjMGEwDwYDVR0TAQH/ - BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFO8Y4OzUZgQ03w28kR7U - UhaZZoOfMB8GA1UdIwQYMBaAFO8Y4OzUZgQ03w28kR7UUhaZZoOfMAoGCCqGSM49 - BAMCA0gAMEUCIQCn+l+nZv/3tf0VjNNPYl1IkSAOBYUO8SX23udWVPmXNgIgI7Ub - bkJTKCjbCZIDNwUNcPC2tyzNPLeB5nGsIl31Rys= - -----END CERTIFICATE----- - */ - { 0x30, 0x82, 0x01, 0x99, 0x30, 0x82, 0x01, 0x3F, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x68, 0x38, 0x4F, 0xAB, +/* +credentials/test/attestation/Chip-Test-PAA-FFF1-Cert.pem +-----BEGIN CERTIFICATE----- +MIIBmTCCAT+gAwIBAgIIaDhPq7kZ/N8wCgYIKoZIzj0EAwIwHzEdMBsGA1UEAwwU +TWF0dGVyIFRlc3QgUEFBIEZGRjEwIBcNMjEwNjI4MTQyMzQzWhgPOTk5OTEyMzEy +MzU5NTlaMB8xHTAbBgNVBAMMFE1hdHRlciBUZXN0IFBBQSBGRkYxMFkwEwYHKoZI +zj0CAQYIKoZIzj0DAQcDQgAEG5isW7wR3GoXVaBbCsXha6AsRu5vwrvnb/fPbKeq +Tp/R15jcvvtP6uIl03c8kTSMwm1JMTHjCWMtXp7zHRLek6NjMGEwDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFO8Y4OzUZgQ03w28kR7U +UhaZZoOfMB8GA1UdIwQYMBaAFO8Y4OzUZgQ03w28kR7UUhaZZoOfMAoGCCqGSM49 +BAMCA0gAMEUCIQCn+l+nZv/3tf0VjNNPYl1IkSAOBYUO8SX23udWVPmXNgIgI7Ub +bkJTKCjbCZIDNwUNcPC2tyzNPLeB5nGsIl31Rys= +-----END CERTIFICATE----- +*/ +const uint8_t kChipTestPaaFff1[] = { 0x30, 0x82, 0x01, 0x99, 0x30, 0x82, 0x01, 0x3F, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x68, 0x38, 0x4F, 0xAB, 0xB9, 0x19, 0xFC, 0xDF, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30, 0x1F, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x14, 0x4D, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x41, 0x41, 0x20, 0x46, 0x46, 0x46, 0x31, 0x30, 0x20, 0x17, 0x0D, 0x32, 0x31, 0x30, 0x36, @@ -79,24 +69,23 @@ CHIP_ERROR GetProductAttestationAuthorityCert(const ByteSpan & skid, MutableByte 0x30, 0x45, 0x02, 0x21, 0x00, 0xA7, 0xFA, 0x5F, 0xA7, 0x66, 0xFF, 0xF7, 0xB5, 0xFD, 0x15, 0x8C, 0xD3, 0x4F, 0x62, 0x5D, 0x48, 0x91, 0x20, 0x0E, 0x05, 0x85, 0x0E, 0xF1, 0x25, 0xF6, 0xDE, 0xE7, 0x56, 0x54, 0xF9, 0x97, 0x36, 0x02, 0x20, 0x23, 0xB5, 0x1B, 0x6E, 0x42, 0x53, 0x28, 0x28, 0xDB, 0x09, 0x92, 0x03, 0x37, 0x05, 0x0D, 0x70, 0xF0, 0xB6, - 0xB7, 0x2C, 0xCD, 0x3C, 0xB7, 0x81, 0xE6, 0x71, 0xAC, 0x22, 0x5D, 0xF5, 0x47, 0x2B }, - { 0xEF, 0x18, 0xE0, 0xEC, 0xD4, 0x66, 0x04, 0x34, 0xDF, 0x0D, - 0xBC, 0x91, 0x1E, 0xD4, 0x52, 0x16, 0x99, 0x66, 0x83, 0x9F } }, - { /* - credentials/test/attestation/Chip-Test-PAA-FFF2-Cert.pem - -----BEGIN CERTIFICATE----- - MIIBnTCCAUKgAwIBAgIIA5KnZVo+bHcwCgYIKoZIzj0EAwIwHzEdMBsGA1UEAwwU - TWF0dGVyIFRlc3QgUEFBIEZGRjIwIBcNMjEwNjI4MTQyMzQzWhgPOTk5OTEyMzEy - MzU5NTlaMB8xHTAbBgNVBAMMFE1hdHRlciBUZXN0IFBBQSBGRkYyMFkwEwYHKoZI - zj0CAQYIKoZIzj0DAQcDQgAEdW4YkvnpULAOlQqilfM1sEhLh20i4m+WZZLKweUQ - 1f6Zsx1cmIgWeorWUDd+dRD7dYI8fluYuMAG7F8Gz66FSqNmMGQwEgYDVR0TAQH/ - BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFOfv6sMzXF/Qw+Y0 - Up8WcEbEvKVcMB8GA1UdIwQYMBaAFOfv6sMzXF/Qw+Y0Up8WcEbEvKVcMAoGCCqG - SM49BAMCA0kAMEYCIQCSUQ0dYCFfARvaLqeV/ssklO+QppeHrQr8IGxhjAnMUgIh - AKA2sK+D40VcCTi5S/9HdRlyuNy+cZyfYbVW7LTqF8xX - -----END CERTIFICATE----- - */ - { 0x30, 0x82, 0x01, 0x9D, 0x30, 0x82, 0x01, 0x42, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x03, 0x92, 0xA7, 0x65, + 0xB7, 0x2C, 0xCD, 0x3C, 0xB7, 0x81, 0xE6, 0x71, 0xAC, 0x22, 0x5D, 0xF5, 0x47, 0x2B }; + +/* +credentials/test/attestation/Chip-Test-PAA-FFF2-Cert.pem +-----BEGIN CERTIFICATE----- +MIIBnTCCAUKgAwIBAgIIA5KnZVo+bHcwCgYIKoZIzj0EAwIwHzEdMBsGA1UEAwwU +TWF0dGVyIFRlc3QgUEFBIEZGRjIwIBcNMjEwNjI4MTQyMzQzWhgPOTk5OTEyMzEy +MzU5NTlaMB8xHTAbBgNVBAMMFE1hdHRlciBUZXN0IFBBQSBGRkYyMFkwEwYHKoZI +zj0CAQYIKoZIzj0DAQcDQgAEdW4YkvnpULAOlQqilfM1sEhLh20i4m+WZZLKweUQ +1f6Zsx1cmIgWeorWUDd+dRD7dYI8fluYuMAG7F8Gz66FSqNmMGQwEgYDVR0TAQH/ +BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFOfv6sMzXF/Qw+Y0 +Up8WcEbEvKVcMB8GA1UdIwQYMBaAFOfv6sMzXF/Qw+Y0Up8WcEbEvKVcMAoGCCqG +SM49BAMCA0kAMEYCIQCSUQ0dYCFfARvaLqeV/ssklO+QppeHrQr8IGxhjAnMUgIh +AKA2sK+D40VcCTi5S/9HdRlyuNy+cZyfYbVW7LTqF8xX +-----END CERTIFICATE----- +*/ +const uint8_t kChipTestPaaFff2[] = { 0x30, 0x82, 0x01, 0x9D, 0x30, 0x82, 0x01, 0x42, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x03, 0x92, 0xA7, 0x65, 0x5A, 0x3E, 0x6C, 0x77, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30, 0x1F, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x14, 0x4D, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x41, 0x41, 0x20, 0x46, 0x46, 0x46, 0x32, 0x30, 0x20, 0x17, 0x0D, 0x32, 0x31, 0x30, 0x36, @@ -117,31 +106,26 @@ CHIP_ERROR GetProductAttestationAuthorityCert(const ByteSpan & skid, MutableByte 0x03, 0x49, 0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0x92, 0x51, 0x0D, 0x1D, 0x60, 0x21, 0x5F, 0x01, 0x1B, 0xDA, 0x2E, 0xA7, 0x95, 0xFE, 0xCB, 0x24, 0x94, 0xEF, 0x90, 0xA6, 0x97, 0x87, 0xAD, 0x0A, 0xFC, 0x20, 0x6C, 0x61, 0x8C, 0x09, 0xCC, 0x52, 0x02, 0x21, 0x00, 0xA0, 0x36, 0xB0, 0xAF, 0x83, 0xE3, 0x45, 0x5C, 0x09, 0x38, 0xB9, 0x4B, 0xFF, 0x47, - 0x75, 0x19, 0x72, 0xB8, 0xDC, 0xBE, 0x71, 0x9C, 0x9F, 0x61, 0xB5, 0x56, 0xEC, 0xB4, 0xEA, 0x17, 0xCC, 0x57 }, - { 0xE7, 0xEF, 0xEA, 0xC3, 0x33, 0x5C, 0x5F, 0xD0, 0xC3, 0xE6, - 0x34, 0x52, 0x9F, 0x16, 0x70, 0x46, 0xC4, 0xBC, 0xA5, 0x5C } }, - }; - - size_t paaLookupTableIdx; - for (paaLookupTableIdx = 0; paaLookupTableIdx < ArraySize(sPAALookupTable); ++paaLookupTableIdx) - { - if (skid.data_equal(ByteSpan(sPAALookupTable[paaLookupTableIdx].mSKID))) - { - break; - } - } + 0x75, 0x19, 0x72, 0xB8, 0xDC, 0xBE, 0x71, 0x9C, 0x9F, 0x61, 0xB5, 0x56, 0xEC, 0xB4, 0xEA, 0x17, 0xCC, 0x57 }; - VerifyOrReturnError(paaLookupTableIdx < ArraySize(sPAALookupTable), CHIP_ERROR_INVALID_ARGUMENT); +const ByteSpan kTestPaaRoots[] = { + ByteSpan{kChipTestPaaFff1}, + ByteSpan{kChipTestPaaFff2}, +}; - return CopySpanToMutableSpan(ByteSpan{ sPAALookupTable[paaLookupTableIdx].mPAACertificate }, outDacBuffer); -} +const ArrayPaaRootStore kTestPaaRootStore{&kTestPaaRoots[0], ArraySize(kTestPaaRoots)}; +/** + * @brief Look-up of well-known keys used for CD signing by CSA. + * + * Current version uses only test key/cert provided in spec. + */ CHIP_ERROR GetCertificationDeclarationCertificate(const ByteSpan & skid, MutableByteSpan & outCertificate) { struct CertChainLookupTable { const uint8_t mCertificate[kMax_x509_Certificate_Length]; - const uint8_t mSKID[kKeyIdentifierLength]; + const uint8_t mSKID[Crypto::kSubjectKeyIdentifierLength]; }; static CertChainLookupTable @@ -191,6 +175,8 @@ CHIP_ERROR GetCertificationDeclarationCertificate(const ByteSpan & skid, Mutable class DefaultDACVerifier : public DeviceAttestationVerifier { public: + DefaultDACVerifier(const PaaRootStore *paaRootStore) : mPaaRootStore(paaRootStore) {} + AttestationVerificationResult VerifyAttestationInformation(const ByteSpan & attestationInfoBuffer, const ByteSpan & attestationChallengeBuffer, const ByteSpan & attestationSignatureBuffer, @@ -203,6 +189,11 @@ class DefaultDACVerifier : public DeviceAttestationVerifier AttestationVerificationResult ValidateCertificateDeclarationPayload(const ByteSpan & certDeclBuffer, const ByteSpan & firmwareInfo, const DeviceInfoForAttestation & deviceInfo) override; + +protected: + DefaultDACVerifier() {} + + const PaaRootStore * mPaaRootStore; }; AttestationVerificationResult DefaultDACVerifier::VerifyAttestationInformation(const ByteSpan & attestationInfoBuffer, @@ -246,7 +237,7 @@ AttestationVerificationResult DefaultDACVerifier::VerifyAttestationInformation(c deviceSignature) == CHIP_NO_ERROR, AttestationVerificationResult::kAttestationSignatureInvalid); - uint8_t akidBuf[Credentials::kKeyIdentifierLength]; + uint8_t akidBuf[Crypto::kAuthorityKeyIdentifierLength]; MutableByteSpan akid(akidBuf); ExtractAKIDFromX509Cert(paiCertDerBuffer, akid); @@ -254,7 +245,7 @@ AttestationVerificationResult DefaultDACVerifier::VerifyAttestationInformation(c chip::Platform::ScopedMemoryBuffer paaCert; VerifyOrReturnError(paaCert.Alloc(paaCertAllocatedLen), AttestationVerificationResult::kNoMemory); MutableByteSpan paa(paaCert.Get(), paaCertAllocatedLen); - VerifyOrReturnError(GetProductAttestationAuthorityCert(akid, paa) == CHIP_NO_ERROR, + VerifyOrReturnError(mPaaRootStore->GetProductAttestationAuthorityCert(akid, paa) == CHIP_NO_ERROR, AttestationVerificationResult::kPaaNotFound); VerifyOrReturnError(ValidateCertificateChain(paa.data(), paa.size(), paiCertDerBuffer.data(), paiCertDerBuffer.size(), @@ -397,9 +388,14 @@ AttestationVerificationResult DefaultDACVerifier::ValidateCertificateDeclaration } // namespace -DeviceAttestationVerifier * GetDefaultDACVerifier() +const PaaRootStore * GetTestPaaRootStore() +{ + return &kTestPaaRootStore; +} + +DeviceAttestationVerifier * GetDefaultDACVerifier(const PaaRootStore * paaRootStore) { - static DefaultDACVerifier defaultDACVerifier; + static DefaultDACVerifier defaultDACVerifier{paaRootStore}; return &defaultDACVerifier; } diff --git a/src/credentials/examples/DefaultDeviceAttestationVerifier.h b/src/credentials/examples/DefaultDeviceAttestationVerifier.h index aad200fdd3e434..cbcbee82f50d79 100644 --- a/src/credentials/examples/DefaultDeviceAttestationVerifier.h +++ b/src/credentials/examples/DefaultDeviceAttestationVerifier.h @@ -21,14 +21,30 @@ namespace chip { namespace Credentials { +/** + * @brief Get implementation of a PAA root store containing a basic set of static PAA roots + * sufficient for *testing* only. + * + * WARNING: The PAA list known to this PAA root store is a reduced subset that will likely + * cause users of it to fail attestation procedure in some cases. This is provided + * to support tests and examples, not to be used by real commissioners, as it + * contains several test roots which are not trustworthy for certified product usage. + * + * @returns a singleton PaaRootStore that contains some well-known PAA test root certs. + */ +const PaaRootStore * GetTestPaaRootStore(); + /** * @brief Get implementation of a sample DAC verifier to validate device * attestation procedure. * - * @returns a singleton DeviceAttestationVerifier that relies on no - * storage abstractions. + * @param[in] paaRootStore Pointer to the PaaRootStore instance to be used by implementation + * of default DeviceAttestationVerifier. Caller must ensure storage is + * always available while the DeviceAttestationVerifier could be used. + * + * @returns a singleton DeviceAttestationVerifier that satisfies basic device attestation procedure requirements. */ -DeviceAttestationVerifier * GetDefaultDACVerifier(); +DeviceAttestationVerifier * GetDefaultDACVerifier(const PaaRootStore * paaRootStore); } // namespace Credentials } // namespace chip diff --git a/src/credentials/tests/TestCertificationDeclaration.cpp b/src/credentials/tests/TestCertificationDeclaration.cpp index 12e49518de3e8f..3d15f39f2ea02e 100644 --- a/src/credentials/tests/TestCertificationDeclaration.cpp +++ b/src/credentials/tests/TestCertificationDeclaration.cpp @@ -247,7 +247,7 @@ static void TestCD_CMSSignAndVerify(nlTestSuite * inSuite, void * inContext) { ByteSpan cdContentIn(sTestCMS_CDContent01); ByteSpan cdContentOut; - uint8_t signerKeyIdBuf[kKeyIdentifierLength]; + uint8_t signerKeyIdBuf[Crypto::kSubjectKeyIdentifierLength]; MutableByteSpan signerKeyId(signerKeyIdBuf); uint8_t signedMessageBuf[kMaxCMSSignedCDMessage]; MutableByteSpan signedMessage(signedMessageBuf); @@ -297,7 +297,7 @@ static void TestCD_CMSVerifyAndExtract(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, testCase.cdContent.data_equal(cdContentOut)); // Test CMS_ExtractKeyId() - uint8_t signerKeyIdBuf[kKeyIdentifierLength]; + uint8_t signerKeyIdBuf[Crypto::kSubjectKeyIdentifierLength]; MutableByteSpan signerKeyId(signerKeyIdBuf); NL_TEST_ASSERT(inSuite, ExtractSKIDFromX509Cert(testCase.signerCert, signerKeyId) == CHIP_NO_ERROR); diff --git a/src/credentials/tests/TestDeviceAttestationCredentials.cpp b/src/credentials/tests/TestDeviceAttestationCredentials.cpp index f706582ddc087e..21a3dd68c0fe6a 100644 --- a/src/credentials/tests/TestDeviceAttestationCredentials.cpp +++ b/src/credentials/tests/TestDeviceAttestationCredentials.cpp @@ -195,8 +195,7 @@ static void TestDACVerifierExample_AttestationInfoVerification(nlTestSuite * inS default_verifier->VerifyAttestationInformation(ByteSpan(), ByteSpan(), ByteSpan(), ByteSpan(), ByteSpan(), ByteSpan()); NL_TEST_ASSERT(inSuite, attestation_result == AttestationVerificationResult::kNotImplemented); - // Replace default verifier with example verifier - DeviceAttestationVerifier * example_dac_verifier = GetDefaultDACVerifier(); + DeviceAttestationVerifier * example_dac_verifier = GetDefaultDACVerifier(GetTestPaaRootStore()); NL_TEST_ASSERT(inSuite, example_dac_verifier != nullptr); NL_TEST_ASSERT(inSuite, default_verifier != example_dac_verifier); @@ -252,7 +251,7 @@ static void TestDACVerifierExample_CertDeclarationVerification(nlTestSuite * inS CHIP_ERROR err = CHIP_NO_ERROR; // Replace default verifier with example verifier - DeviceAttestationVerifier * example_dac_verifier = GetDefaultDACVerifier(); + DeviceAttestationVerifier * example_dac_verifier = GetDefaultDACVerifier(GetTestPaaRootStore()); NL_TEST_ASSERT(inSuite, example_dac_verifier != nullptr); SetDeviceAttestationVerifier(example_dac_verifier); @@ -295,6 +294,73 @@ static void TestDACVerifierExample_CertDeclarationVerification(nlTestSuite * inS NL_TEST_ASSERT(inSuite, attestation_result == AttestationVerificationResult::kSuccess); } +static void TestPaaRootStore(nlTestSuite * inSuite, void * inContext) +{ + uint8_t kPaaFff1Start[] = { 0x30, 0x82, 0x01, 0x99, 0x30, 0x82, 0x01, 0x3F, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x68, 0x38, 0x4F, 0xAB, + 0xB9, 0x19, 0xFC, 0xDF, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30, 0x1F, 0x31 }; + uint8_t kPaaFff1Skid[] = { 0xEF, 0x18, 0xE0, 0xEC, 0xD4, 0x66, 0x04, 0x34, 0xDF, 0x0D, 0xBC, 0x91, 0x1E, 0xD4, 0x52, 0x16, 0x99, 0x66, 0x83, 0x9F }; + + uint8_t kPaaFff2Start[] = { 0x30, 0x82, 0x01, 0x9D, 0x30, 0x82, 0x01, 0x42, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x03, 0x92, 0xA7, 0x65, + 0x5A, 0x3E, 0x6C, 0x77, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30, 0x1F, 0x31 }; + uint8_t kPaaFff2Skid[] = { 0xE7, 0xEF, 0xEA, 0xC3, 0x33, 0x5C, 0x5F, 0xD0, 0xC3, 0xE6, 0x34, 0x52, 0x9F, 0x16, 0x70, 0x46, 0xC4, 0xBC, 0xA5, 0x5C }; + + // SKID to trigger CHIP_ERROR_INVALID_ARGUMENT + uint8_t kPaaBadSkid1[] = { 0xE7, 0xEF, 0xEA, 0xC3, 0x33, 0x5C, 0xD0, 0xC3, 0xE6, 0x34, 0x52, 0x9F, 0x16, 0x70, 0x46, 0xC4, 0xBC, 0xA5, 0x5C }; + ByteSpan kPaaBadSkidSpan1{kPaaBadSkid1}; + + // SKID to trigger CHIP_ERROR_INVALID_ARGUMENT + ByteSpan kPaaBadSkidSpan2{nullptr, sizeof(kPaaFff2Skid)}; + + // SKID to trigger CHIP_ERROR_CA_CERT_NOT_FOUND + uint8_t kPaaGoodSkidNotPresent[] = { 0xE7, 0xEF, 0xEA, 0xC3, 0x33, 0x5C, 0x5F, 0xD0, 0xC3, 0xE6, 0x34, 0x52, 0x9F, 0x16, 0x70, 0xFF, 0xFF, 0xBC, 0xA5, 0x5C }; + + struct TestCase + { + ByteSpan skidSpan; + ByteSpan startSpan; + CHIP_ERROR expectedResult; + }; + + const TestCase kTestCases[] = + { + {.skidSpan = ByteSpan{kPaaFff1Skid}, .startSpan = ByteSpan{kPaaFff1Start}, .expectedResult = CHIP_NO_ERROR}, + {.skidSpan = ByteSpan{kPaaFff2Skid}, .startSpan = ByteSpan{kPaaFff2Start}, .expectedResult = CHIP_NO_ERROR}, + {.skidSpan = ByteSpan{kPaaFff2Skid}, .startSpan = ByteSpan{kPaaFff2Start}, .expectedResult = CHIP_ERROR_BUFFER_TOO_SMALL}, + {.skidSpan = kPaaBadSkidSpan1, .startSpan = ByteSpan{}, .expectedResult = CHIP_ERROR_INVALID_ARGUMENT}, + {.skidSpan = kPaaBadSkidSpan2, .startSpan = ByteSpan{}, .expectedResult = CHIP_ERROR_INVALID_ARGUMENT}, + {.skidSpan = ByteSpan{kPaaGoodSkidNotPresent}, .startSpan = ByteSpan{}, .expectedResult = CHIP_ERROR_CA_CERT_NOT_FOUND}, + }; + + const PaaRootStore * testPaaRootStore = GetTestPaaRootStore(); + NL_TEST_ASSERT(inSuite, testPaaRootStore != nullptr); + + size_t testCaseIdx = 0; + for (const auto & testCase : kTestCases) + { + uint8_t buf[kMaxDERCertLength]; + MutableByteSpan paaCertSpan{buf}; + if (testCase.expectedResult == CHIP_ERROR_BUFFER_TOO_SMALL) + { + // Make the output much too small if checking for size handling + paaCertSpan = paaCertSpan.SubSpan(0, 16); + } + + // Try to obtain cert + CHIP_ERROR result = testPaaRootStore->GetProductAttestationAuthorityCert(testCase.skidSpan, paaCertSpan); + NL_TEST_ASSERT(inSuite, result == testCase.expectedResult); + + // In success cases, make sure the start of the cert matches expectation. Not using full certs + // to avoid repeating the known constants here. + if (testCase.expectedResult == CHIP_NO_ERROR) + { + NL_TEST_ASSERT(inSuite, paaCertSpan.size() > testCase.startSpan.size()); + paaCertSpan = paaCertSpan.SubSpan(0, testCase.startSpan.size()); + NL_TEST_ASSERT(inSuite, paaCertSpan.data_equal(testCase.startSpan) == true); + } + ++testCaseIdx; + } +} + /** * Set up the test suite. */ @@ -326,6 +392,7 @@ int TestDeviceAttestation_Teardown(void * inContext) static const nlTest sTests[] = { NL_TEST_DEF("Test Example Device Attestation Credentials Providers", TestDACProvidersExample_Providers), NL_TEST_DEF("Test Example Device Attestation Signature", TestDACProvidersExample_Signature), + NL_TEST_DEF("Test the 'for testing' Paa Root Store", TestPaaRootStore), NL_TEST_DEF("Test Example Device Attestation Information Verification", TestDACVerifierExample_AttestationInfoVerification), NL_TEST_DEF("Test Example Device Attestation Certification Declaration Verification", TestDACVerifierExample_CertDeclarationVerification), NL_TEST_SENTINEL() diff --git a/src/crypto/CHIPCryptoPAL.h b/src/crypto/CHIPCryptoPAL.h index 1d55e72a060cbd..78a58be47eb604 100644 --- a/src/crypto/CHIPCryptoPAL.h +++ b/src/crypto/CHIPCryptoPAL.h @@ -46,6 +46,8 @@ constexpr size_t kP256_ECDSA_Signature_Length_Raw = (2 * kP256_FE_Length); constexpr size_t kP256_Point_Length = (2 * kP256_FE_Length + 1); constexpr size_t kSHA256_Hash_Length = 32; constexpr size_t kSHA1_Hash_Length = 20; +constexpr size_t kSubjectKeyIdentifierLength = kSHA1_Hash_Length; +constexpr size_t kAuthorityKeyIdentifierLength = kSHA1_Hash_Length; constexpr size_t CHIP_CRYPTO_GROUP_SIZE_BYTES = kP256_FE_Length; constexpr size_t CHIP_CRYPTO_PUBLIC_KEY_SIZE_BYTES = kP256_Point_Length; diff --git a/src/crypto/tests/CHIPCryptoPALTest.cpp b/src/crypto/tests/CHIPCryptoPALTest.cpp index df2a737913afd6..dc3989bec15880 100644 --- a/src/crypto/tests/CHIPCryptoPALTest.cpp +++ b/src/crypto/tests/CHIPCryptoPALTest.cpp @@ -1874,7 +1874,7 @@ static void TestSKID_x509Extraction(nlTestSuite * inSuite, void * inContext) HeapChecker heapChecker(inSuite); CHIP_ERROR err = CHIP_NO_ERROR; - uint8_t skidBuf[Credentials::kKeyIdentifierLength]; + uint8_t skidBuf[kSubjectKeyIdentifierLength]; MutableByteSpan skidOut(skidBuf); ByteSpan cert; @@ -1901,7 +1901,7 @@ static void TestAKID_x509Extraction(nlTestSuite * inSuite, void * inContext) HeapChecker heapChecker(inSuite); CHIP_ERROR err = CHIP_NO_ERROR; - uint8_t akidBuf[Credentials::kKeyIdentifierLength]; + uint8_t akidBuf[kAuthorityKeyIdentifierLength]; MutableByteSpan akidOut(akidBuf); ByteSpan cert; diff --git a/src/darwin/Framework/CHIP/CHIPDeviceController.mm b/src/darwin/Framework/CHIP/CHIPDeviceController.mm index 794d6ed7ccd24f..6bb7d7a4d9fdaf 100644 --- a/src/darwin/Framework/CHIP/CHIPDeviceController.mm +++ b/src/darwin/Framework/CHIP/CHIPDeviceController.mm @@ -190,7 +190,9 @@ - (BOOL)startup:(_Nullable id)storageDelegate } // Initialize device attestation verifier - chip::Credentials::SetDeviceAttestationVerifier(chip::Credentials::GetDefaultDACVerifier()); + // TODO: Replace testingRootStore with a PaaRootStore that has the necessary official PAA roots available + const chip::Credentials::PaaRootStore * testingRootStore = chip::Credentials::GetTestPaaRootStore(); + chip::Credentials::SetDeviceAttestationVerifier(chip::Credentials::GetDefaultDACVerifier(testingRootStore)); params.fabricStorage = _fabricStorage; commissionerParams.storageDelegate = _persistentStorageDelegateBridge; diff --git a/src/protocols/secure_channel/CASESession.h b/src/protocols/secure_channel/CASESession.h index a8bbadd3cf1b75..71cda76e5eabd7 100644 --- a/src/protocols/secure_channel/CASESession.h +++ b/src/protocols/secure_channel/CASESession.h @@ -47,7 +47,7 @@ namespace chip { constexpr uint16_t kSigmaParamRandomNumberSize = 32; -constexpr uint16_t kTrustedRootIdSize = Credentials::kKeyIdentifierLength; +constexpr uint16_t kTrustedRootIdSize = Crypto::kSubjectKeyIdentifierLength; constexpr uint16_t kMaxTrustedRootIds = 5; constexpr uint16_t kIPKSize = 16;