LCOV - code coverage report
Current view: top level - credentials/attestation_verifier - DeviceAttestationVerifier.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 20 29 69.0 %
Date: 2024-02-15 08:20:41 Functions: 9 15 60.0 %

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

Generated by: LCOV version 1.14