Matter SDK Coverage Report
Current view: top level - setup_payload - SetupPayload.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 96.1 % 154 148
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 21 21

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020 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              : 
      18              : /**
      19              :  *    @file
      20              :  *      The implementation of the Setup Payload. Currently only needed to
      21              :  *      verify the validity of a Setup Payload
      22              :  */
      23              : 
      24              : #include "SetupPayload.h"
      25              : 
      26              : #include <crypto/CHIPCryptoPAL.h>
      27              : #include <lib/core/CHIPCore.h>
      28              : #include <lib/core/CHIPVendorIdentifiers.hpp>
      29              : #include <lib/core/TLV.h>
      30              : #include <lib/core/TLVData.h>
      31              : #include <lib/core/TLVUtilities.h>
      32              : #include <lib/support/CodeUtils.h>
      33              : #include <utility>
      34              : 
      35              : namespace chip {
      36              : 
      37              : // Check the Setup Payload for validity
      38              : //
      39              : // `vendor_id` and `product_id` are allowed all of uint16_t
      40           51 : bool PayloadContents::isValidQRCodePayload(ValidationMode mode) const
      41              : {
      42              :     // 3-bit value specifying the QR code payload version.
      43           51 :     VerifyOrReturnValue(version < (1 << kVersionFieldLengthInBits), false);
      44              : 
      45           50 :     VerifyOrReturnValue(static_cast<uint8_t>(commissioningFlow) < (1 << kCommissioningFlowFieldLengthInBits), false);
      46              : 
      47              :     // Device Commissioning Flow
      48              :     // Even in ValidationMode::kConsume we can only handle modes that we understand.
      49              :     // 0: Standard commissioning flow: such a device, when uncommissioned, always enters commissioning mode upon power-up, subject
      50              :     // to the rules in [ref_Announcement_Commencement]. 1: User-intent commissioning flow: user action required to enter
      51              :     // commissioning mode. 2: Custom commissioning flow: interaction with a vendor-specified means is needed before commissioning.
      52              :     // 3: Reserved
      53           49 :     VerifyOrReturnValue(commissioningFlow == CommissioningFlow::kStandard ||
      54              :                             commissioningFlow == CommissioningFlow::kUserActionRequired ||
      55              :                             commissioningFlow == CommissioningFlow::kCustom,
      56              :                         false);
      57              : 
      58              :     // General discriminator validity is enforced by the SetupDiscriminator class, but it can't be short for QR a code.
      59           49 :     VerifyOrReturnValue(!discriminator.IsShortDiscriminator(), false);
      60              : 
      61              :     // RendevouzInformation must be present for a QR code.
      62           47 :     VerifyOrReturnValue(rendezvousInformation.HasValue(), false);
      63           42 :     if (mode == ValidationMode::kProduce)
      64              :     {
      65           40 :         chip::RendezvousInformationFlags valid(RendezvousInformationFlag::kBLE, RendezvousInformationFlag::kOnNetwork,
      66              :                                                RendezvousInformationFlag::kSoftAP, RendezvousInformationFlag::kWiFiPAF);
      67           40 :         VerifyOrReturnValue(rendezvousInformation.Value().HasOnly(valid), false);
      68              :     }
      69              : 
      70           41 :     return CheckPayloadCommonConstraints();
      71              : }
      72              : 
      73           12 : bool PayloadContents::isValidManualCode(ValidationMode mode) const
      74              : {
      75              :     // No additional constraints apply to Manual Pairing Codes.
      76              :     // (If the payload has a long discriminator it will be converted automatically.)
      77           12 :     return CheckPayloadCommonConstraints();
      78              : }
      79              : 
      80           56 : bool PayloadContents::IsValidSetupPIN(uint32_t setupPIN)
      81              : {
      82              :     // SHALL be restricted to the values 0x0000001 to 0x5F5E0FE (00000001 to 99999998 in decimal), excluding the invalid Passcode
      83              :     // values.
      84           56 :     if (setupPIN == kSetupPINCodeUndefinedValue || setupPIN > kSetupPINCodeMaximumValue || setupPIN == 11111111 ||
      85           54 :         setupPIN == 22222222 || setupPIN == 33333333 || setupPIN == 44444444 || setupPIN == 55555555 || setupPIN == 66666666 ||
      86           54 :         setupPIN == 77777777 || setupPIN == 88888888 || setupPIN == 12345678 || setupPIN == 87654321)
      87              :     {
      88            2 :         return false;
      89              :     }
      90              : 
      91           54 :     return true;
      92              : }
      93              : 
      94           53 : bool PayloadContents::CheckPayloadCommonConstraints() const
      95              : {
      96              :     // Validation rules in this method apply to all validation modes.
      97              : 
      98              :     // Even in ValidationMode::kConsume we don't understand how to handle any payload version other than 0.
      99           53 :     VerifyOrReturnValue(version == 0, false);
     100              : 
     101           53 :     VerifyOrReturnValue(IsValidSetupPIN(setUpPINCode), false);
     102              : 
     103              :     // VendorID must be unspecified (0) or in valid range expected.
     104           51 :     VerifyOrReturnValue((vendorID == VendorId::Unspecified) || IsVendorIdValidOperationally(vendorID), false);
     105              : 
     106              :     // A value of 0x0000 SHALL NOT be assigned to a product since Product ID = 0x0000 is used for these specific cases:
     107              :     //  * To announce an anonymized Product ID as part of device discovery
     108              :     //  * To indicate an OTA software update file applies to multiple Product IDs equally.
     109              :     //  * To avoid confusion when presenting the Onboarding Payload for ECM with multiple nodes
     110              :     // In these special cases the vendorID must be 0 (Unspecified)
     111           51 :     VerifyOrReturnValue(productID != 0 || vendorID == VendorId::Unspecified, false);
     112              : 
     113           51 :     return true;
     114              : }
     115              : 
     116           27 : bool PayloadContents::operator==(const PayloadContents & input) const
     117              : {
     118           27 :     return (this->version == input.version && this->vendorID == input.vendorID && this->productID == input.productID &&
     119           54 :             this->commissioningFlow == input.commissioningFlow && this->rendezvousInformation == input.rendezvousInformation &&
     120           81 :             this->discriminator == input.discriminator && this->setUpPINCode == input.setUpPINCode);
     121              : }
     122              : 
     123           11 : CHIP_ERROR SetupPayload::addOptionalVendorData(uint8_t tag, std::string data)
     124              : {
     125           11 :     OptionalQRCodeInfo info;
     126           11 :     info.tag  = tag;
     127           11 :     info.type = optionalQRCodeInfoTypeString;
     128           11 :     info.data = std::move(data);
     129              : 
     130           11 :     return addOptionalVendorData(info);
     131           11 : }
     132              : 
     133            6 : CHIP_ERROR SetupPayload::addOptionalVendorData(uint8_t tag, int32_t data)
     134              : {
     135            6 :     OptionalQRCodeInfo info;
     136            6 :     info.tag   = tag;
     137            6 :     info.type  = optionalQRCodeInfoTypeInt32;
     138            6 :     info.int32 = data;
     139              : 
     140            6 :     return addOptionalVendorData(info);
     141            6 : }
     142              : 
     143           70 : std::vector<OptionalQRCodeInfo> SetupPayload::getAllOptionalVendorData() const
     144              : {
     145           70 :     std::vector<OptionalQRCodeInfo> returnedOptionalInfo;
     146           92 :     for (auto & entry : optionalVendorData)
     147              :     {
     148           22 :         returnedOptionalInfo.push_back(entry.second);
     149              :     }
     150           70 :     return returnedOptionalInfo;
     151              : }
     152              : 
     153            4 : CHIP_ERROR SetupPayload::removeOptionalVendorData(uint8_t tag)
     154              : {
     155            4 :     VerifyOrReturnError(optionalVendorData.find(tag) != optionalVendorData.end(), CHIP_ERROR_KEY_NOT_FOUND);
     156            2 :     optionalVendorData.erase(tag);
     157              : 
     158            2 :     return CHIP_NO_ERROR;
     159              : }
     160              : 
     161            7 : CHIP_ERROR SetupPayload::addSerialNumber(std::string serialNumber)
     162              : {
     163            7 :     OptionalQRCodeInfoExtension info;
     164            7 :     info.tag  = kSerialNumberTag;
     165            7 :     info.type = optionalQRCodeInfoTypeString;
     166            7 :     info.data = std::move(serialNumber);
     167              : 
     168            7 :     return addOptionalExtensionData(info);
     169            7 : }
     170              : 
     171            2 : CHIP_ERROR SetupPayload::addSerialNumber(uint32_t serialNumber)
     172              : {
     173            2 :     OptionalQRCodeInfoExtension info;
     174            2 :     info.tag    = kSerialNumberTag;
     175            2 :     info.type   = optionalQRCodeInfoTypeUInt32;
     176            2 :     info.uint32 = serialNumber;
     177              : 
     178            2 :     return addOptionalExtensionData(info);
     179            2 : }
     180              : 
     181            4 : CHIP_ERROR SetupPayload::getSerialNumber(std::string & outSerialNumber) const
     182              : {
     183            4 :     CHIP_ERROR err = CHIP_NO_ERROR;
     184            4 :     OptionalQRCodeInfoExtension info;
     185            4 :     ReturnErrorOnFailure(getOptionalExtensionData(kSerialNumberTag, info));
     186              : 
     187            2 :     switch (info.type)
     188              :     {
     189            1 :     case (optionalQRCodeInfoTypeString):
     190            1 :         outSerialNumber = info.data;
     191            1 :         break;
     192            1 :     case (optionalQRCodeInfoTypeUInt32):
     193            1 :         outSerialNumber = std::to_string(info.uint32);
     194            1 :         break;
     195            0 :     default:
     196            0 :         err = CHIP_ERROR_INVALID_ARGUMENT;
     197            0 :         break;
     198              :     }
     199              : 
     200            2 :     return err;
     201            4 : }
     202              : 
     203            3 : CHIP_ERROR SetupPayload::removeSerialNumber()
     204              : {
     205            3 :     VerifyOrReturnError(optionalExtensionData.find(kSerialNumberTag) != optionalExtensionData.end(), CHIP_ERROR_KEY_NOT_FOUND);
     206            1 :     optionalExtensionData.erase(kSerialNumberTag);
     207              : 
     208            1 :     return CHIP_NO_ERROR;
     209              : }
     210              : 
     211            1 : CHIP_ERROR SetupPayload::generateRandomSetupPin(uint32_t & setupPINCode)
     212              : {
     213            1 :     uint8_t retries          = 0;
     214            1 :     const uint8_t maxRetries = 10;
     215              : 
     216              :     do
     217              :     {
     218            1 :         ReturnErrorOnFailure(Crypto::DRBG_get_bytes(reinterpret_cast<uint8_t *>(&setupPINCode), sizeof(setupPINCode)));
     219              : 
     220              :         // Passcodes shall be restricted to the values 00000001 to 99999998 in decimal, see 5.1.1.6
     221              :         // TODO: Consider revising this method to ensure uniform distribution of setup PIN codes
     222            1 :         setupPINCode = (setupPINCode % kSetupPINCodeMaximumValue) + 1;
     223              : 
     224              :         // Make sure that the Generated Setup Pin code is not one of the invalid passcodes/pin codes defined in the
     225              :         // specification.
     226            1 :         if (IsValidSetupPIN(setupPINCode))
     227              :         {
     228            1 :             return CHIP_NO_ERROR;
     229              :         }
     230              : 
     231            0 :         retries++;
     232              :         // We got pretty unlucky with the random number generator, Just try again.
     233              :         // This shouldn't take many retries assuming DRBG_get_bytes is not broken.
     234            0 :     } while (retries < maxRetries);
     235              : 
     236            0 :     return CHIP_ERROR_INTERNAL;
     237              : }
     238              : 
     239           21 : CHIP_ERROR SetupPayload::addOptionalVendorData(const OptionalQRCodeInfo & info)
     240              : {
     241           21 :     VerifyOrReturnError(IsVendorTag(info.tag), CHIP_ERROR_INVALID_ARGUMENT);
     242           19 :     optionalVendorData[info.tag] = info;
     243              : 
     244           19 :     return CHIP_NO_ERROR;
     245              : }
     246              : 
     247           12 : CHIP_ERROR SetupPayload::addOptionalExtensionData(const OptionalQRCodeInfoExtension & info)
     248              : {
     249           12 :     VerifyOrReturnError(IsCommonTag(info.tag), CHIP_ERROR_INVALID_ARGUMENT);
     250           12 :     optionalExtensionData[info.tag] = info;
     251              : 
     252           12 :     return CHIP_NO_ERROR;
     253              : }
     254              : 
     255            4 : CHIP_ERROR SetupPayload::getOptionalVendorData(uint8_t tag, OptionalQRCodeInfo & info) const
     256              : {
     257            4 :     const auto it = optionalVendorData.find(tag);
     258            4 :     VerifyOrReturnError(it != optionalVendorData.end(), CHIP_ERROR_KEY_NOT_FOUND);
     259            4 :     info = it->second;
     260              : 
     261            4 :     return CHIP_NO_ERROR;
     262              : }
     263              : 
     264            7 : CHIP_ERROR SetupPayload::getOptionalExtensionData(uint8_t tag, OptionalQRCodeInfoExtension & info) const
     265              : {
     266            7 :     const auto it = optionalExtensionData.find(tag);
     267            7 :     VerifyOrReturnError(it != optionalExtensionData.end(), CHIP_ERROR_KEY_NOT_FOUND);
     268            5 :     info = it->second;
     269            5 :     return CHIP_NO_ERROR;
     270              : }
     271              : 
     272            3 : optionalQRCodeInfoType SetupPayload::getNumericTypeFor(uint8_t tag) const
     273              : {
     274            3 :     optionalQRCodeInfoType elemType = optionalQRCodeInfoTypeUnknown;
     275              : 
     276            3 :     if (IsVendorTag(tag))
     277              :     {
     278            2 :         elemType = optionalQRCodeInfoTypeInt32;
     279              :     }
     280            1 :     else if (tag == kSerialNumberTag)
     281              :     {
     282            1 :         elemType = optionalQRCodeInfoTypeUInt32;
     283              :     }
     284              : 
     285            3 :     return elemType;
     286              : }
     287              : 
     288           63 : std::vector<OptionalQRCodeInfoExtension> SetupPayload::getAllOptionalExtensionData() const
     289              : {
     290           63 :     std::vector<OptionalQRCodeInfoExtension> returnedOptionalInfo;
     291           78 :     for (auto & entry : optionalExtensionData)
     292              :     {
     293           15 :         returnedOptionalInfo.push_back(entry.second);
     294              :     }
     295           63 :     return returnedOptionalInfo;
     296              : }
     297              : 
     298           25 : bool SetupPayload::operator==(const SetupPayload & input) const
     299              : {
     300           25 :     std::vector<OptionalQRCodeInfo> inputOptionalVendorData;
     301           25 :     std::vector<OptionalQRCodeInfoExtension> inputOptionalExtensionData;
     302              : 
     303           25 :     VerifyOrReturnError(PayloadContents::operator==(input), false);
     304              : 
     305           24 :     inputOptionalVendorData = input.getAllOptionalVendorData();
     306           24 :     VerifyOrReturnError(optionalVendorData.size() == inputOptionalVendorData.size(), false);
     307              : 
     308           28 :     for (const OptionalQRCodeInfo & inputInfo : inputOptionalVendorData)
     309              :     {
     310            4 :         OptionalQRCodeInfo info;
     311            4 :         CHIP_ERROR err = getOptionalVendorData(inputInfo.tag, info);
     312            4 :         VerifyOrReturnError(err == CHIP_NO_ERROR, false);
     313            4 :         VerifyOrReturnError(inputInfo.type == info.type, false);
     314            4 :         VerifyOrReturnError(inputInfo.data == info.data, false);
     315            4 :         VerifyOrReturnError(inputInfo.int32 == info.int32, false);
     316            4 :     }
     317              : 
     318           24 :     inputOptionalExtensionData = input.getAllOptionalExtensionData();
     319           24 :     VerifyOrReturnError(optionalExtensionData.size() == inputOptionalExtensionData.size(), false);
     320              : 
     321           27 :     for (const OptionalQRCodeInfoExtension & inputInfo : inputOptionalExtensionData)
     322              :     {
     323            3 :         OptionalQRCodeInfoExtension info;
     324            3 :         CHIP_ERROR err = getOptionalExtensionData(inputInfo.tag, info);
     325            3 :         VerifyOrReturnError(err == CHIP_NO_ERROR, false);
     326            3 :         VerifyOrReturnError(inputInfo.type == info.type, false);
     327            3 :         VerifyOrReturnError(inputInfo.data == info.data, false);
     328            3 :         VerifyOrReturnError(inputInfo.int32 == info.int32, false);
     329            3 :         VerifyOrReturnError(inputInfo.int64 == info.int64, false);
     330            3 :         VerifyOrReturnError(inputInfo.uint32 == info.uint32, false);
     331            3 :         VerifyOrReturnError(inputInfo.uint64 == info.uint64, false);
     332            3 :     }
     333              : 
     334           24 :     return true;
     335           25 : }
     336              : 
     337              : } // namespace chip
        

Generated by: LCOV version 2.0-1