Matter SDK Coverage Report
Current view: top level - credentials/jcm - VendorIdVerificationClient.cpp (source / functions) Coverage Total Hit
Test: SHA:e98a48c2e59f85a25417956e1d105721433aa5d1 Lines: 97.2 % 71 69
Test Date: 2026-01-09 16:53:50 Functions: 100.0 % 5 5

            Line data    Source code
       1              : /*
       2              :  *    Copyright (c) 2025 Project CHIP Authors
       3              :  *    All rights reserved.
       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              : 
      18              : #include "VendorIdVerificationClient.h"
      19              : 
      20              : #include <controller/InvokeInteraction.h>
      21              : #include <credentials/CHIPCert.h>
      22              : #include <credentials/FabricTable.h>
      23              : 
      24              : namespace chip {
      25              : namespace Credentials {
      26              : namespace JCM {
      27              : 
      28            8 : CHIP_ERROR VendorIdVerificationClient::VerifyNOCCertificateChain(const ByteSpan & nocSpan, const ByteSpan & icacSpan,
      29              :                                                                  const ByteSpan & rcacSpan)
      30              : {
      31            8 :     ValidationContext validContext;
      32              : 
      33            8 :     validContext.Reset();
      34            8 :     validContext.mRequiredKeyUsages.Set(KeyUsageFlags::kDigitalSignature);
      35            8 :     validContext.mRequiredKeyPurposes.Set(KeyPurposeFlags::kClientAuth);
      36              : 
      37            8 :     ChipCertificateSet certificates;
      38            8 :     constexpr uint8_t kMaxNumCertsInOpCreds = 3;
      39           16 :     ReturnLogErrorOnFailure(certificates.Init(kMaxNumCertsInOpCreds));
      40           16 :     ReturnLogErrorOnFailure(certificates.LoadCert(rcacSpan, BitFlags<CertDecodeFlags>(CertDecodeFlags::kIsTrustAnchor)));
      41            7 :     if (!icacSpan.empty())
      42              :     {
      43           14 :         ReturnLogErrorOnFailure(certificates.LoadCert(icacSpan, BitFlags<CertDecodeFlags>(CertDecodeFlags::kGenerateTBSHash)));
      44              :     }
      45           12 :     ReturnLogErrorOnFailure(certificates.LoadCert(nocSpan, BitFlags<CertDecodeFlags>(CertDecodeFlags::kGenerateTBSHash)));
      46           12 :     ReturnLogErrorOnFailure(certificates.ValidateCert(certificates.GetLastCert(), validContext));
      47              : 
      48            6 :     return CHIP_NO_ERROR;
      49            8 : }
      50              : 
      51            9 : CHIP_ERROR VendorIdVerificationClient::Verify(
      52              :     TrustVerificationInfo * info, const ByteSpan clientChallengeSpan, const ByteSpan attestationChallengeSpan,
      53              :     const app::Clusters::OperationalCredentials::Commands::SignVIDVerificationResponse::DecodableType responseData)
      54              : {
      55              :     // Steps 1-9 have already been completed prior to the response callback
      56            9 :     const FabricIndex fabricIndex = info->adminFabricIndex;
      57            9 :     const VendorId vendorID       = info->adminVendorId;
      58            9 :     const FabricId fabricId       = info->adminFabricId;
      59            9 :     auto rcacSpan                 = info->adminRCAC.Span();
      60            9 :     auto icacSpan                 = info->adminICAC.Span();
      61            9 :     auto nocSpan                  = info->adminNOC.Span();
      62              : 
      63              :     // Extract the root public key
      64            9 :     P256PublicKeySpan rcacPublicKeySpan;
      65           18 :     ReturnLogErrorOnFailure(ExtractPublicKeyFromChipCert(rcacSpan, rcacPublicKeySpan));
      66            8 :     Crypto::P256PublicKey rcacPublicKey(rcacPublicKeySpan);
      67              : 
      68              :     // Locally generate the vendor_fabric_binding_message
      69              :     uint8_t vendorFabricBindingMessageBuffer[Crypto::kVendorFabricBindingMessageV1Size];
      70            8 :     MutableByteSpan vendorFabricBindingMessageSpan{ vendorFabricBindingMessageBuffer };
      71           16 :     ReturnLogErrorOnFailure(Crypto::GenerateVendorFabricBindingMessage(Crypto::FabricBindingVersion::kVersion1, rcacPublicKey,
      72              :                                                                        fabricId, vendorID, vendorFabricBindingMessageSpan));
      73              : 
      74              :     // Locally generate the vendor_id_verification_tbs message
      75            8 :     ByteSpan vidVerificationStatementSpan;
      76              :     uint8_t vidVerificationStatementBuffer[Crypto::kVendorIdVerificationTbsV1MaxSize];
      77            8 :     MutableByteSpan vidVerificationTbsSpan{ vidVerificationStatementBuffer };
      78              : 
      79              :     // Generate the ToBeSigned portion of the VID verification
      80           16 :     ReturnLogErrorOnFailure(Crypto::GenerateVendorIdVerificationToBeSigned(fabricIndex, clientChallengeSpan,
      81              :                                                                            attestationChallengeSpan, vendorFabricBindingMessageSpan,
      82              :                                                                            vidVerificationStatementSpan, vidVerificationTbsSpan));
      83              : 
      84              :     // Extract the operational public key
      85            8 :     P256PublicKeySpan nocPublicKeySpan;
      86           16 :     ReturnLogErrorOnFailure(ExtractPublicKeyFromChipCert(nocSpan, nocPublicKeySpan));
      87            7 :     Crypto::P256PublicKey nocPublicKey(nocPublicKeySpan);
      88              : 
      89              :     // 10. Given the subject public key associated with the fabric being verified, validate that Crypto_Verify(noc_public_key,
      90              :     // vendor_id_verification_tbs, signature) succeeds, otherwise the procedure terminates as failed.
      91            7 :     Crypto::P256ECDSASignature signature;
      92            7 :     ReturnValueOnFailure(signature.SetLength(responseData.signature.size()), CHIP_ERROR_BUFFER_TOO_SMALL);
      93            7 :     memcpy(signature.Bytes(), responseData.signature.data(), responseData.signature.size());
      94              : 
      95           14 :     ReturnLogErrorOnFailure(
      96              :         nocPublicKey.ECDSA_validate_msg_signature(vidVerificationTbsSpan.data(), vidVerificationTbsSpan.size(), signature));
      97              : 
      98              :     // 11. Verify that the NOC chain is valid using Crypto_VerifyChain() against the entire chain reconstructed from both the
      99              :     // NOCs and TrustedRootCertificates attribute entries whose FabricIndex field matches the fabric being verified.
     100              :     // If the chain is not valid, the procedure terminates as failed.
     101           10 :     ReturnLogErrorOnFailure(VerifyNOCCertificateChain(nocSpan, icacSpan, rcacSpan));
     102              : 
     103              :     // 12a If the VIDVerificationStatement field was present in the entry in Fabrics whose VendorID is being verified
     104              :     // (Not currently supported)
     105              :     // 12b. Otherwise (i.e VIDVerificationStatement not used):
     106              :     // 12bi. Look-up the entry in the Operational Trust Anchors Schema under the expected VendorID (VID field)
     107              :     // being verified whose IsRoot field is true and whose SubjectKeyID matches the SubjectKeyID field value of
     108              :     // the TrustedRootCertificates attribute entry whose FabricIndex field matches the fabric being verified
     109              :     // (i.e. the RCAC of the candidate fabric)
     110            4 :     ChipCertificateData certData;
     111              :     // Decode root cert with default (null) options
     112            8 :     ReturnLogErrorOnFailure(DecodeChipCert(rcacSpan, certData));
     113            4 :     ByteSpan globallyTrustedRootSpan;
     114            8 :     ReturnLogErrorOnFailure(OnLookupOperationalTrustAnchor(vendorID, certData.mSubjectKeyId, globallyTrustedRootSpan));
     115              : 
     116              :     // 12bii. Verify that the NOC chain is valid using Crypto_VerifyChain() against the entire chain reconstructed
     117              :     // from the NOCs attribute entry whose FabricIndex field matches the fabric being verified, but populating
     118              :     // the trusted root with the GloballyTrustedRoot certificate rather than the value in TrustedRootCertificates
     119              :     // associated with the candidate fabric. If the chain is not valid, the procedure terminates as failed.
     120            6 :     ReturnLogErrorOnFailure(VerifyNOCCertificateChain(nocSpan, icacSpan, globallyTrustedRootSpan));
     121              : 
     122              :     // 13. Given that all prior steps succeeded, the candidate fabric’s VendorID SHALL be deemed authentic and err should be
     123              :     // CHIP_NO_ERROR.
     124            2 :     return CHIP_NO_ERROR;
     125            8 : }
     126              : 
     127           11 : CHIP_ERROR VendorIdVerificationClient::VerifyVendorId(Messaging::ExchangeManager * exchangeMgr, const SessionGetterFunc getSession,
     128              :                                                       TrustVerificationInfo * info)
     129              : {
     130           11 :     ChipLogProgress(Controller, "Performing vendor ID verification for vendor ID: %u", info->adminVendorId);
     131              : 
     132              :     // Generate a 32-octet random challenge
     133              :     uint8_t kClientChallenge[32];
     134           11 :     TEMPORARY_RETURN_IGNORED Crypto::DRBG_get_bytes(kClientChallenge, sizeof(kClientChallenge));
     135           11 :     ByteSpan clientChallengeSpan{ kClientChallenge };
     136           11 :     chip::app::Clusters::OperationalCredentials::Commands::SignVIDVerificationRequest::Type request;
     137              : 
     138              :     // The selected fabric information that matches the Fabrics attribute whose VendorID field to be verified
     139              :     // is in the JCMTrustVerificationInfo info
     140           11 :     request.fabricIndex     = info->adminFabricIndex;
     141           11 :     request.clientChallenge = clientChallengeSpan;
     142              : 
     143            9 :     auto onSuccessCb = [&, getSession, info, kClientChallenge](const app::ConcreteCommandPath & aPath,
     144              :                                                                const app::StatusIB & aStatus,
     145            9 :                                                                const decltype(request)::ResponseType & responseData) {
     146            9 :         ChipLogProgress(Controller, "Successfully received SignVIDVerificationResponse");
     147            9 :         ByteSpan clientChallenge{ kClientChallenge };
     148            9 :         ByteSpan attestationChallenge = getSession().Value()->AsSecureSession()->GetCryptoContext().GetAttestationChallenge();
     149            9 :         CHIP_ERROR err                = Verify(info, clientChallenge, attestationChallenge, responseData);
     150            9 :         ChipLogProgress(Controller, "Vendor ID verification completed with result: %s", ErrorStr(err));
     151            9 :         OnVendorIdVerificationComplete(err);
     152           11 :     };
     153              : 
     154            2 :     auto onFailureCb = [&](CHIP_ERROR err) {
     155            2 :         ChipLogError(Controller, "Failed to receive SignVIDVerificationResponse: %s", ErrorStr(err));
     156            2 :         OnVendorIdVerificationComplete(err);
     157           13 :     };
     158              : 
     159              :     CHIP_ERROR err =
     160           11 :         Controller::InvokeCommandRequest(exchangeMgr, getSession().Value(), kRootEndpointId, request, onSuccessCb, onFailureCb);
     161           22 :     if (err != CHIP_NO_ERROR)
     162              :     {
     163            0 :         ChipLogError(Controller, "Failed to send SignVIDVerificationRequest: %s", ErrorStr(err));
     164            0 :         this->OnVendorIdVerificationComplete(err);
     165              :     }
     166              : 
     167           11 :     return CHIP_NO_ERROR;
     168           11 : }
     169              : 
     170              : } // namespace JCM
     171              : } // namespace Credentials
     172              : } // namespace chip
        

Generated by: LCOV version 2.0-1