Matter SDK Coverage Report
Current view: top level - credentials/attestation_verifier - DeviceAttestationVerifier.h (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 66.7 % 30 20
Test Date: 2025-01-17 19:00:11 Functions: 52.9 % 17 9

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021 Project CHIP Authors
       4              :  *
       5              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6              :  *    you may not use this file except in compliance with the License.
       7              :  *    You may obtain a copy of the License at
       8              :  *
       9              :  *        http://www.apache.org/licenses/LICENSE-2.0
      10              :  *
      11              :  *    Unless required by applicable law or agreed to in writing, software
      12              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14              :  *    See the License for the specific language governing permissions and
      15              :  *    limitations under the License.
      16              :  */
      17              : #pragma once
      18              : 
      19              : #include <crypto/CHIPCryptoPAL.h>
      20              : #include <lib/core/CHIPCallback.h>
      21              : #include <lib/core/CHIPError.h>
      22              : #include <lib/core/CHIPVendorIdentifiers.hpp>
      23              : #include <lib/support/ScopedBuffer.h>
      24              : #include <lib/support/Span.h>
      25              : #include <stdlib.h>
      26              : 
      27              : namespace chip {
      28              : namespace Credentials {
      29              : 
      30              : enum class AttestationVerificationResult : uint16_t
      31              : {
      32              :     kSuccess = 0,
      33              : 
      34              :     kPaaUntrusted        = 100,
      35              :     kPaaNotFound         = 101,
      36              :     kPaaExpired          = 102,
      37              :     kPaaSignatureInvalid = 103,
      38              :     kPaaRevoked          = 104,
      39              :     kPaaFormatInvalid    = 105,
      40              :     kPaaArgumentInvalid  = 106,
      41              : 
      42              :     kPaiExpired           = 200,
      43              :     kPaiSignatureInvalid  = 201,
      44              :     kPaiRevoked           = 202,
      45              :     kPaiFormatInvalid     = 203,
      46              :     kPaiArgumentInvalid   = 204,
      47              :     kPaiVendorIdMismatch  = 205,
      48              :     kPaiAuthorityNotFound = 206,
      49              :     kPaiMissing           = 207,
      50              :     kPaiAndDacRevoked     = 208,
      51              : 
      52              :     kDacExpired           = 300,
      53              :     kDacSignatureInvalid  = 301,
      54              :     kDacRevoked           = 302,
      55              :     kDacFormatInvalid     = 303,
      56              :     kDacArgumentInvalid   = 304,
      57              :     kDacVendorIdMismatch  = 305,
      58              :     kDacProductIdMismatch = 306,
      59              :     kDacAuthorityNotFound = 307,
      60              : 
      61              :     kFirmwareInformationMismatch = 400,
      62              :     kFirmwareInformationMissing  = 401,
      63              : 
      64              :     kAttestationSignatureInvalid       = 500,
      65              :     kAttestationElementsMalformed      = 501,
      66              :     kAttestationNonceMismatch          = 502,
      67              :     kAttestationSignatureInvalidFormat = 503,
      68              : 
      69              :     kCertificationDeclarationNoKeyId            = 600,
      70              :     kCertificationDeclarationNoCertificateFound = 601,
      71              :     kCertificationDeclarationInvalidSignature   = 602,
      72              :     kCertificationDeclarationInvalidFormat      = 603,
      73              :     kCertificationDeclarationInvalidVendorId    = 604,
      74              :     kCertificationDeclarationInvalidProductId   = 605,
      75              :     kCertificationDeclarationInvalidPAA         = 606,
      76              : 
      77              :     kNoMemory = 700,
      78              : 
      79              :     kInvalidArgument = 800,
      80              : 
      81              :     kInternalError = 900,
      82              : 
      83              :     kNotImplemented = 0xFFFFU,
      84              : 
      85              :     // TODO: Add more attestation verification errors
      86              : };
      87              : 
      88              : enum CertificateType : uint8_t
      89              : {
      90              :     kUnknown = 0,
      91              :     kDAC     = 1,
      92              :     kPAI     = 2,
      93              : };
      94              : 
      95              : struct DeviceInfoForAttestation
      96              : {
      97              :     // Vendor ID reported by device in Basic Information cluster
      98              :     uint16_t vendorId = VendorId::NotSpecified;
      99              :     // Product ID reported by device in Basic Information cluster
     100              :     uint16_t productId = 0;
     101              :     // Vendor ID from DAC
     102              :     uint16_t dacVendorId = VendorId::NotSpecified;
     103              :     // Product ID from DAC
     104              :     uint16_t dacProductId = 0;
     105              :     // Vendor ID from PAI cert
     106              :     uint16_t paiVendorId = VendorId::NotSpecified;
     107              :     // Product ID from PAI cert (0 if absent)
     108              :     uint16_t paiProductId = 0;
     109              :     // Vendor ID from PAA cert
     110              :     uint16_t paaVendorId = VendorId::NotSpecified;
     111              :     // Subject Key Identifier (SKID) from PAA cert
     112              :     uint8_t paaSKID[Crypto::kSubjectKeyIdentifierLength] = { 0 };
     113              : };
     114              : 
     115              : /**
     116              :  * @brief Helper utility to model a basic trust store usable for device attestation verifiers.
     117              :  *
     118              :  * API is synchronous. Real commissioner implementations may entirely
     119              :  * hide Product Attestation Authority cert lookup behind the DeviceAttestationVerifier and
     120              :  * never use this interface at all. It is provided as a utility to help build DeviceAttestationVerifier
     121              :  * implementations suitable for testing or examples.
     122              :  */
     123              : class AttestationTrustStore
     124              : {
     125              : public:
     126            3 :     AttestationTrustStore()          = default;
     127            3 :     virtual ~AttestationTrustStore() = default;
     128              : 
     129              :     // Not copyable
     130              :     AttestationTrustStore(const AttestationTrustStore &)             = delete;
     131              :     AttestationTrustStore & operator=(const AttestationTrustStore &) = delete;
     132              : 
     133              :     /**
     134              :      * @brief Look-up a PAA cert by SKID
     135              :      *
     136              :      * The implementations of this interface must have access to a set of PAAs to trust.
     137              :      *
     138              :      * Interface is synchronous, and therefore this should not be used unless to expose a PAA
     139              :      * store that is both fully local and quick to access.
     140              :      *
     141              :      * @param[in] skid Buffer containing the subject key identifier (SKID) of the PAA to look-up
     142              :      * @param[in,out] outPaaDerBuffer Buffer to receive the contents of the PAA root cert, if found.
     143              :      *                                  Size will be updated to match actual size.
     144              :      *
     145              :      * @returns CHIP_NO_ERROR on success, CHIP_INVALID_ARGUMENT if `skid` or `outPaaDerBuffer` arguments
     146              :      *          are not usable, CHIP_BUFFER_TOO_SMALL if certificate doesn't fit in `outPaaDerBuffer`
     147              :      *          span, CHIP_ERROR_CA_CERT_NOT_FOUND if no PAA found that matches `skid.
     148              :      *
     149              :      */
     150              :     virtual CHIP_ERROR GetProductAttestationAuthorityCert(const ByteSpan & skid, MutableByteSpan & outPaaDerBuffer) const = 0;
     151              : };
     152              : 
     153              : /**
     154              :  * @brief Helper utility to model obtaining verifying keys by Key ID
     155              :  *
     156              :  * API is synchronous. Real commissioner implementations may entirely
     157              :  * hide key lookup behind the DeviceAttestationVerifier and never use this interface at all.
     158              :  * It is provided as a utility to help build DeviceAttestationVerifier
     159              :  * implementations suitable for testing or examples.
     160              :  */
     161              : class WellKnownKeysTrustStore
     162              : {
     163              : public:
     164            2 :     WellKnownKeysTrustStore()          = default;
     165            2 :     virtual ~WellKnownKeysTrustStore() = default;
     166              : 
     167              :     // Not copyable
     168              :     WellKnownKeysTrustStore(const WellKnownKeysTrustStore &)             = delete;
     169              :     WellKnownKeysTrustStore & operator=(const WellKnownKeysTrustStore &) = delete;
     170              : 
     171              :     /**
     172              :      * @brief Add a trusted key directly
     173              :      *
     174              :      * @param[in] kid - Key ID to use. Usually 20 bytes long, max 32 bytes.
     175              :      * @param[in] pubKey - Verifying public key to attach to the key ID.
     176              :      *
     177              :      * @return CHIP_NO_ERROR on success, CHIP_INVALID_ARGUMENT if `kid` or `pubKey` arguments
     178              :      *          are not usable. CHIP_ERROR_NO_MEMORY if the trust store is full.
     179              :      */
     180              :     virtual CHIP_ERROR AddTrustedKey(const ByteSpan & kid, const Crypto::P256PublicKey & pubKey) = 0;
     181              : 
     182              :     /**
     183              :      * @brief Add a trusted key via a public certificate.
     184              :      *
     185              :      * The subject public key of the certificate will be used.
     186              :      * The subject key ID extensions of the certificate will be the `kid`.
     187              :      *
     188              :      * Verification of trust chaining is at the discretion of the implementation.
     189              :      *
     190              :      * @param[in] derCertBytes - Certificate containing the X.509 DER certificate with the key.
     191              :      *
     192              :      * @return CHIP_NO_ERROR on success, CHIP_INVALID_ARGUMENT if derCertBytes is improperly
     193              :      *         formatted or not trusted. CHIP_ERROR_NO_MEMORY if the trust store is full.
     194              :      */
     195              :     virtual CHIP_ERROR AddTrustedKey(const ByteSpan & derCertBytes) = 0;
     196              : 
     197              :     /**
     198              :      * @brief Look-up a verifying key by Key ID
     199              :      *
     200              :      * Interface is synchronous.
     201              :      *
     202              :      * @param[in] kid Buffer containing the key identifier (KID) of the verifying key to look-up. Usually
     203              :      *                a SHA-1-sized buffer (20 bytes).
     204              :      * @param[out] outPubKey Reference to where the verifying key found will be stored on CHIP_NO_ERROR
     205              :      *
     206              :      * @returns CHIP_NO_ERROR on success, CHIP_INVALID_ARGUMENT if `kid` or `pubKey` arguments
     207              :      *          are not usable, CHIP_ERROR_KEY_NOT_FOUND if no key is found that matches `kid`.
     208              :      */
     209              :     virtual CHIP_ERROR LookupVerifyingKey(const ByteSpan & kid, Crypto::P256PublicKey & outPubKey) const = 0;
     210              : 
     211              :     /**
     212              :      * @brief Returns true if `kid` identifies a known test key.
     213              :      *
     214              :      * @param kid - Key ID to use. Usually 20 bytes long, max 32 bytes.
     215              :      * @return true if it's a test/development-only signing key identifier, false otherwise
     216              :      */
     217              :     virtual bool IsCdTestKey(const ByteSpan & kid) const = 0;
     218              : };
     219              : 
     220              : /**
     221              :  * @brief Basic AttestationTrustStore that holds all data within caller-owned memory.
     222              :  *
     223              :  * This is useful to wrap a fixed constant array of certificates into a trust store
     224              :  * implementation.
     225              :  */
     226              : 
     227              : class ArrayAttestationTrustStore : public AttestationTrustStore
     228              : {
     229              : public:
     230            3 :     ArrayAttestationTrustStore(const ByteSpan * derCerts, size_t numCerts) : mDerCerts(derCerts), mNumCerts(numCerts) {}
     231              : 
     232           99 :     CHIP_ERROR GetProductAttestationAuthorityCert(const ByteSpan & skid, MutableByteSpan & outPaaDerBuffer) const override
     233              :     {
     234           99 :         VerifyOrReturnError(!skid.empty() && (skid.data() != nullptr), CHIP_ERROR_INVALID_ARGUMENT);
     235           98 :         VerifyOrReturnError(skid.size() == Crypto::kSubjectKeyIdentifierLength, CHIP_ERROR_INVALID_ARGUMENT);
     236              : 
     237              :         size_t paaIdx;
     238           97 :         ByteSpan candidate;
     239              : 
     240          104 :         for (paaIdx = 0; paaIdx < mNumCerts; ++paaIdx)
     241              :         {
     242          102 :             uint8_t skidBuf[Crypto::kSubjectKeyIdentifierLength] = { 0 };
     243          102 :             candidate                                            = mDerCerts[paaIdx];
     244          102 :             MutableByteSpan candidateSkidSpan{ skidBuf };
     245          197 :             VerifyOrReturnError(CHIP_NO_ERROR == Crypto::ExtractSKIDFromX509Cert(candidate, candidateSkidSpan),
     246              :                                 CHIP_ERROR_INTERNAL);
     247              : 
     248          102 :             if (skid.data_equal(candidateSkidSpan))
     249              :             {
     250              :                 // Found a match
     251           95 :                 return CopySpanToMutableSpan(candidate, outPaaDerBuffer);
     252              :             }
     253              :         }
     254              : 
     255            2 :         return CHIP_ERROR_CA_CERT_NOT_FOUND;
     256              :     }
     257              : 
     258              : protected:
     259              :     const ByteSpan * mDerCerts;
     260              :     const size_t mNumCerts;
     261              : };
     262              : 
     263              : class DeviceAttestationVerifier
     264              : {
     265              : public:
     266            2 :     DeviceAttestationVerifier()          = default;
     267            6 :     virtual ~DeviceAttestationVerifier() = default;
     268              : 
     269              :     // Not copyable
     270              :     DeviceAttestationVerifier(const DeviceAttestationVerifier &)             = delete;
     271              :     DeviceAttestationVerifier & operator=(const DeviceAttestationVerifier &) = delete;
     272              : 
     273              :     struct AttestationInfo
     274              :     {
     275            0 :         AttestationInfo(const ByteSpan & attestationElements, const ByteSpan & attestationChallenge,
     276              :                         const ByteSpan & attestationSignature, const ByteSpan & paiDer, const ByteSpan & dacDer,
     277            0 :                         const ByteSpan & attestationNonce, VendorId remoteVendorId, uint16_t remoteProductId) :
     278            0 :             attestationElementsBuffer(attestationElements),
     279            0 :             attestationChallengeBuffer(attestationChallenge), attestationSignatureBuffer(attestationSignature),
     280            0 :             paiDerBuffer(paiDer), dacDerBuffer(dacDer), attestationNonceBuffer(attestationNonce), vendorId(remoteVendorId),
     281            0 :             productId(remoteProductId)
     282            0 :         {}
     283              :         const ByteSpan
     284              :             attestationElementsBuffer; // Buffer containing attestation elements portion of Attestation Response (raw TLV)
     285              :         const ByteSpan attestationChallengeBuffer; // Buffer containing the attestation challenge from the secure session
     286              :         const ByteSpan attestationSignatureBuffer; // Buffer the signature portion of Attestation Response
     287              :         const ByteSpan paiDerBuffer;               // Buffer containing the PAI certificate from device in DER format.
     288              :         const ByteSpan dacDerBuffer;               // Buffer containing the DAC certificate from device in DER format.
     289              :         const ByteSpan attestationNonceBuffer;     // Buffer containing attestation nonce.
     290              :         VendorId vendorId;
     291              :         uint16_t productId;
     292              :     };
     293              : 
     294              :     // Copies the bytes passed to it, and holds the PAI, DAC, and CD for additional verification step
     295              :     class AttestationDeviceInfo
     296              :     {
     297              :     public:
     298              :         AttestationDeviceInfo(const AttestationInfo & attestationInfo);
     299              : 
     300            0 :         ~AttestationDeviceInfo() = default;
     301              : 
     302              :         // Returns buffer containing the PAI certificate from device in DER format.
     303              :         const ByteSpan paiDerBuffer() const { return ByteSpan(mPaiDerBuffer.Get(), mPaiDerBuffer.AllocatedSize()); }
     304              : 
     305              :         // Returns buffer containing the DAC certificate from device in DER format.
     306              :         const ByteSpan dacDerBuffer() const { return ByteSpan(mDacDerBuffer.Get(), mDacDerBuffer.AllocatedSize()); }
     307              : 
     308              :         // Returns optional buffer containing the certificate declaration from device.
     309              :         const Optional<ByteSpan> cdBuffer() const
     310              :         {
     311              :             if (mCdBuffer.Get())
     312              :             {
     313              :                 return MakeOptional(ByteSpan(mDacDerBuffer.Get(), mDacDerBuffer.AllocatedSize()));
     314              :             }
     315              :             else
     316              :             {
     317              :                 return Optional<ByteSpan>();
     318              :             }
     319              :         }
     320              : 
     321              :         uint16_t BasicInformationVendorId() const { return mBasicInformationVendorId; }
     322              : 
     323              :         uint16_t BasicInformationProductId() const { return mBasicInformationProductId; }
     324              : 
     325              :     private:
     326              :         Platform::ScopedMemoryBufferWithSize<uint8_t> mPaiDerBuffer;
     327              :         Platform::ScopedMemoryBufferWithSize<uint8_t> mDacDerBuffer;
     328              :         Platform::ScopedMemoryBufferWithSize<uint8_t> mCdBuffer;
     329              :         uint16_t mBasicInformationVendorId;
     330              :         uint16_t mBasicInformationProductId;
     331              :     };
     332              : 
     333              :     typedef void (*OnAttestationInformationVerification)(void * context, const AttestationInfo & info,
     334              :                                                          AttestationVerificationResult result);
     335              : 
     336              :     /**
     337              :      * @brief Verify an attestation information payload against a DAC/PAI chain.
     338              :      *
     339              :      * @param[in] info All of the information required to verify the attestation.
     340              :      * @param[in] onCompletion Callback handler to provide Attestation Information Verification result to the caller of
     341              :      *                         VerifyAttestationInformation()
     342              :      */
     343              :     virtual void VerifyAttestationInformation(const AttestationInfo & info,
     344              :                                               Callback::Callback<OnAttestationInformationVerification> * onCompletion) = 0;
     345              : 
     346              :     /**
     347              :      * @brief Verify a CMS Signed Data signature against the CSA certificate of Subject Key Identifier that matches
     348              :      *        the subjectKeyIdentifier field of cmsEnvelopeBuffer.
     349              :      *
     350              :      * @param[in]  cmsEnvelopeBuffer A ByteSpan with a CMS signed message.
     351              :      * @param[out] certDeclBuffer    A ByteSpan to hold the CD content extracted from the CMS signed message.
     352              :      *
     353              :      * @returns AttestationVerificationResult::kSuccess on success or another specific
     354              :      *          value from AttestationVerificationResult enum on failure.
     355              :      */
     356              :     virtual AttestationVerificationResult ValidateCertificationDeclarationSignature(const ByteSpan & cmsEnvelopeBuffer,
     357              :                                                                                     ByteSpan & certDeclBuffer) = 0;
     358              : 
     359              :     /**
     360              :      * @brief Verify a CMS Signed Data Payload against the Basic Information Cluster and DAC/PAI's Vendor and Product IDs
     361              :      *
     362              :      * @param[in] certDeclBuffer   A ByteSpan with the Certification Declaration content.
     363              :      * @param[in] firmwareInfo     A ByteSpan with the Firmware Information content.
     364              :      * @param[in] deviceInfo       The device information
     365              :      *
     366              :      * @returns AttestationVerificationResult::kSuccess on success or another specific
     367              :      *          value from AttestationVerificationResult enum on failure.
     368              :      */
     369              :     virtual AttestationVerificationResult ValidateCertificateDeclarationPayload(const ByteSpan & certDeclBuffer,
     370              :                                                                                 const ByteSpan & firmwareInfo,
     371              :                                                                                 const DeviceInfoForAttestation & deviceInfo) = 0;
     372              : 
     373              :     // TODO: Validate Firmware Information
     374              : 
     375              :     /**
     376              :      * @brief Verify an operational certificate signing request payload against the DAC's public key.
     377              :      *
     378              :      * @param[in]  nocsrElementsBuffer Buffer containing CSR elements as per specifications section 11.22.5.6. NOCSR Elements.
     379              :      * @param[in]  attestationChallengeBuffer Buffer containing the attestation challenge from the secure session
     380              :      * @param[in]  attestationSignatureBuffer Buffer containing the signature portion of CSR Response
     381              :      * @param[in]  dacPublicKey Public Key from the DAC's certificate received from device.
     382              :      * @param[in]  csrNonce Buffer containing CSR nonce.
     383              :      */
     384              :     virtual CHIP_ERROR VerifyNodeOperationalCSRInformation(const ByteSpan & nocsrElementsBuffer,
     385              :                                                            const ByteSpan & attestationChallengeBuffer,
     386              :                                                            const ByteSpan & attestationSignatureBuffer,
     387              :                                                            const Crypto::P256PublicKey & dacPublicKey,
     388              :                                                            const ByteSpan & csrNonce) = 0;
     389              : 
     390              :     /**
     391              :      * @brief Verify whether or not the given DAC chain is revoked.
     392              :      *
     393              :      * @param[in] info All of the information required to check for revoked DAC chain.
     394              :      * @param[in] onCompletion Callback handler to provide Attestation Information Verification result to the caller of
     395              :      *                         CheckForRevokedDACChain()
     396              :      */
     397              :     virtual void CheckForRevokedDACChain(const AttestationInfo & info,
     398              :                                          Callback::Callback<OnAttestationInformationVerification> * onCompletion) = 0;
     399              : 
     400              :     /**
     401              :      * @brief Get the trust store used for the attestation verifier.
     402              :      *
     403              :      * Returns nullptr if not supported. Be careful not to hold-on to the trust store
     404              :      * for too long. It is only expected to have same lifetime as the DeviceAttestationVerifier.
     405              :      *
     406              :      * @return a pointer to the trust store or nullptr if none is directly accessible.
     407              :      */
     408            0 :     virtual WellKnownKeysTrustStore * GetCertificationDeclarationTrustStore() { return nullptr; }
     409              : 
     410              :     void EnableCdTestKeySupport(bool enabled) { mEnableCdTestKeySupport = enabled; }
     411           84 :     bool IsCdTestKeySupported() const { return mEnableCdTestKeySupport; }
     412              : 
     413              : protected:
     414              :     CHIP_ERROR ValidateAttestationSignature(const Crypto::P256PublicKey & pubkey, const ByteSpan & attestationElements,
     415              :                                             const ByteSpan & attestationChallenge, const Crypto::P256ECDSASignature & signature);
     416              : 
     417              :     // Default to support the "development" test key for legacy purposes (since the DefaultDACVerifier)
     418              :     // always supported development keys.
     419              :     bool mEnableCdTestKeySupport = true;
     420              : };
     421              : 
     422              : /**
     423              :  * @brief Interface for checking the device attestation revocation status
     424              :  *
     425              :  */
     426              : class DeviceAttestationRevocationDelegate
     427              : {
     428              : public:
     429              :     DeviceAttestationRevocationDelegate()          = default;
     430            0 :     virtual ~DeviceAttestationRevocationDelegate() = default;
     431              : 
     432              :     /**
     433              :      * @brief Verify whether or not the given DAC chain is revoked.
     434              :      *
     435              :      * @param[in] info All of the information required to check for revoked DAC chain.
     436              :      * @param[in] onCompletion Callback handler to provide Attestation Information Verification result to the caller of
     437              :      *                         CheckForRevokedDACChain().
     438              :      */
     439              :     virtual void
     440              :     CheckForRevokedDACChain(const DeviceAttestationVerifier::AttestationInfo & info,
     441              :                             Callback::Callback<DeviceAttestationVerifier::OnAttestationInformationVerification> * onCompletion) = 0;
     442              : };
     443              : 
     444              : /**
     445              :  * Instance getter for the global DeviceAttestationVerifier.
     446              :  *
     447              :  * Callers have to externally synchronize usage of this function.
     448              :  *
     449              :  * @return The global device attestation verifier. Assume never null.
     450              :  */
     451              : DeviceAttestationVerifier * GetDeviceAttestationVerifier();
     452              : 
     453              : /**
     454              :  * Instance setter for the global DeviceAttestationVerifier.
     455              :  *
     456              :  * Callers have to externally synchronize usage of this function.
     457              :  *
     458              :  * If the `verifier` is nullptr, no change is done.
     459              :  *
     460              :  * @param[in] verifier the DeviceAttestationVerifier to start returning with the getter
     461              :  */
     462              : void SetDeviceAttestationVerifier(DeviceAttestationVerifier * verifier);
     463              : 
     464              : } // namespace Credentials
     465              : } // namespace chip
        

Generated by: LCOV version 2.0-1