Matter SDK Coverage Report
Current view: top level - credentials - CertificationDeclaration.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 100.0 % 325 325
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 17 17

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021-2022 Project CHIP Authors
       4              :  *    All rights reserved.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : 
      19              : /**
      20              :  *    @file
      21              :  *      This file implements data types, objects and APIs for
      22              :  *      working with Certification Declaration elements.
      23              :  */
      24              : 
      25              : #include <algorithm>
      26              : #include <cinttypes>
      27              : #include <cstddef>
      28              : 
      29              : #include <credentials/CertificationDeclaration.h>
      30              : #include <crypto/CHIPCryptoPAL.h>
      31              : #include <lib/core/CHIPCore.h>
      32              : #include <lib/core/CHIPSafeCasts.h>
      33              : #include <lib/core/TLV.h>
      34              : #include <lib/support/SafeInt.h>
      35              : 
      36              : namespace chip {
      37              : namespace Credentials {
      38              : 
      39              : using namespace chip::ASN1;
      40              : using namespace chip::TLV;
      41              : using namespace chip::Crypto;
      42              : 
      43              : static constexpr uint8_t sOID_ContentType_PKCS7Data[]       = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
      44              : static constexpr uint8_t sOID_ContentType_PKCS7SignedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 };
      45              : static constexpr uint8_t sOID_DigestAlgo_SHA256[]           = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 };
      46              : static constexpr uint8_t sOID_SigAlgo_ECDSAWithSHA256[]     = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02 };
      47              : 
      48              : /** Certification Declaration Element TLV Tags
      49              :  */
      50              : enum
      51              : {
      52              :     kTag_FormatVersion       = 0,  /**< [ unsigned int ] Format version. */
      53              :     kTag_VendorId            = 1,  /**< [ unsigned int ] Vedor identifier. */
      54              :     kTag_ProductIdArray      = 2,  /**< [ array ] Product identifiers (each is unsigned int). */
      55              :     kTag_DeviceTypeId        = 3,  /**< [ unsigned int ] Device Type identifier. */
      56              :     kTag_CertificateId       = 4,  /**< [ UTF-8 string, length 19 ] Certificate identifier. */
      57              :     kTag_SecurityLevel       = 5,  /**< [ unsigned int ] Security level. */
      58              :     kTag_SecurityInformation = 6,  /**< [ unsigned int ] Security information. */
      59              :     kTag_VersionNumber       = 7,  /**< [ unsigned int ] Version number. */
      60              :     kTag_CertificationType   = 8,  /**< [ unsigned int ] Certification Type. */
      61              :     kTag_DACOriginVendorId   = 9,  /**< [ unsigned int, optional ] DAC origin vendor identifier. */
      62              :     kTag_DACOriginProductId  = 10, /**< [ unsigned int, optional ] DAC origin product identifier. */
      63              :     kTag_AuthorizedPAAList   = 11, /**< [ array, optional ] Authorized PAA List. */
      64              : };
      65              : 
      66            7 : CHIP_ERROR EncodeCertificationElements(const CertificationElements & certElements, MutableByteSpan & encodedCertElements)
      67              : {
      68            7 :     TLVWriter writer;
      69              :     TLVType outerContainer1, outerContainer2;
      70              : 
      71            7 :     writer.Init(encodedCertElements);
      72              : 
      73            7 :     ReturnErrorOnFailure(writer.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainer1));
      74              : 
      75            7 :     ReturnErrorOnFailure(writer.Put(ContextTag(kTag_FormatVersion), certElements.FormatVersion));
      76            7 :     ReturnErrorOnFailure(writer.Put(ContextTag(kTag_VendorId), certElements.VendorId));
      77              : 
      78            7 :     VerifyOrReturnError(certElements.ProductIdsCount > 0, CHIP_ERROR_INVALID_ARGUMENT);
      79            7 :     VerifyOrReturnError(certElements.ProductIdsCount <= kMaxProductIdsCount, CHIP_ERROR_INVALID_ARGUMENT);
      80              : 
      81            7 :     ReturnErrorOnFailure(writer.StartContainer(ContextTag(kTag_ProductIdArray), kTLVType_Array, outerContainer2));
      82          115 :     for (uint8_t i = 0; i < certElements.ProductIdsCount; i++)
      83              :     {
      84          108 :         ReturnErrorOnFailure(writer.Put(AnonymousTag(), certElements.ProductIds[i]));
      85              :     }
      86            7 :     ReturnErrorOnFailure(writer.EndContainer(outerContainer2));
      87              : 
      88            7 :     ReturnErrorOnFailure(writer.Put(ContextTag(kTag_DeviceTypeId), certElements.DeviceTypeId));
      89            7 :     ReturnErrorOnFailure(writer.PutString(ContextTag(kTag_CertificateId), certElements.CertificateId));
      90            7 :     ReturnErrorOnFailure(writer.Put(ContextTag(kTag_SecurityLevel), certElements.SecurityLevel));
      91            7 :     ReturnErrorOnFailure(writer.Put(ContextTag(kTag_SecurityInformation), certElements.SecurityInformation));
      92            7 :     ReturnErrorOnFailure(writer.Put(ContextTag(kTag_VersionNumber), certElements.VersionNumber));
      93            6 :     ReturnErrorOnFailure(writer.Put(ContextTag(kTag_CertificationType), certElements.CertificationType));
      94            6 :     if (certElements.DACOriginVIDandPIDPresent)
      95              :     {
      96            2 :         ReturnErrorOnFailure(writer.Put(ContextTag(kTag_DACOriginVendorId), certElements.DACOriginVendorId));
      97            2 :         ReturnErrorOnFailure(writer.Put(ContextTag(kTag_DACOriginProductId), certElements.DACOriginProductId));
      98              :     }
      99            6 :     if (certElements.AuthorizedPAAListCount > 0)
     100              :     {
     101            1 :         VerifyOrReturnError(certElements.AuthorizedPAAListCount <= kMaxAuthorizedPAAListCount, CHIP_ERROR_INVALID_ARGUMENT);
     102              : 
     103            1 :         ReturnErrorOnFailure(writer.StartContainer(ContextTag(kTag_AuthorizedPAAList), kTLVType_Array, outerContainer2));
     104           11 :         for (uint8_t i = 0; i < certElements.AuthorizedPAAListCount; i++)
     105              :         {
     106           10 :             ReturnErrorOnFailure(writer.Put(AnonymousTag(), ByteSpan(certElements.AuthorizedPAAList[i])));
     107              :         }
     108            1 :         ReturnErrorOnFailure(writer.EndContainer(outerContainer2));
     109              :     }
     110              : 
     111            6 :     ReturnErrorOnFailure(writer.EndContainer(outerContainer1));
     112              : 
     113            6 :     ReturnErrorOnFailure(writer.Finalize());
     114              : 
     115            6 :     encodedCertElements.reduce_size(writer.GetLengthWritten());
     116              : 
     117            6 :     return CHIP_NO_ERROR;
     118              : }
     119              : 
     120            5 : CHIP_ERROR DecodeCertificationElements(const ByteSpan & encodedCertElements, CertificationElements & certElements)
     121              : {
     122              :     CHIP_ERROR err;
     123            5 :     TLVReader reader;
     124              :     TLVType outerContainer1, outerContainer2;
     125              : 
     126            5 :     VerifyOrReturnError(encodedCertElements.size() <= kMaxCMSSignedCDMessage, CHIP_ERROR_INVALID_ARGUMENT);
     127              : 
     128            5 :     reader.Init(encodedCertElements);
     129              : 
     130            5 :     ReturnErrorOnFailure(reader.Next(kTLVType_Structure, AnonymousTag()));
     131              : 
     132            5 :     ReturnErrorOnFailure(reader.EnterContainer(outerContainer1));
     133              : 
     134            5 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_FormatVersion)));
     135            5 :     ReturnErrorOnFailure(reader.Get(certElements.FormatVersion));
     136              : 
     137            5 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_VendorId)));
     138            5 :     ReturnErrorOnFailure(reader.Get(certElements.VendorId));
     139              : 
     140            4 :     ReturnErrorOnFailure(reader.Next(kTLVType_Array, ContextTag(kTag_ProductIdArray)));
     141            3 :     ReturnErrorOnFailure(reader.EnterContainer(outerContainer2));
     142              : 
     143            3 :     certElements.ProductIdsCount = 0;
     144          106 :     while ((err = reader.Next(AnonymousTag())) == CHIP_NO_ERROR)
     145              :     {
     146          103 :         VerifyOrReturnError(certElements.ProductIdsCount < kMaxProductIdsCount, CHIP_ERROR_INVALID_ARGUMENT);
     147          103 :         ReturnErrorOnFailure(reader.Get(certElements.ProductIds[certElements.ProductIdsCount++]));
     148              :     }
     149            3 :     VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
     150            3 :     ReturnErrorOnFailure(reader.ExitContainer(outerContainer2));
     151              : 
     152            3 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_DeviceTypeId)));
     153            3 :     ReturnErrorOnFailure(reader.Get(certElements.DeviceTypeId));
     154              : 
     155            3 :     ReturnErrorOnFailure(reader.Next(kTLVType_UTF8String, ContextTag(kTag_CertificateId)));
     156            3 :     ReturnErrorOnFailure(reader.GetString(certElements.CertificateId, sizeof(certElements.CertificateId)));
     157            3 :     VerifyOrReturnError(strlen(certElements.CertificateId) == kCertificateIdLength, CHIP_ERROR_INVALID_TLV_ELEMENT);
     158              : 
     159            3 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_SecurityLevel)));
     160            3 :     ReturnErrorOnFailure(reader.Get(certElements.SecurityLevel));
     161              : 
     162            3 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_SecurityInformation)));
     163            3 :     ReturnErrorOnFailure(reader.Get(certElements.SecurityInformation));
     164              : 
     165            3 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_VersionNumber)));
     166            3 :     ReturnErrorOnFailure(reader.Get(certElements.VersionNumber));
     167              : 
     168            3 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_CertificationType)));
     169            3 :     ReturnErrorOnFailure(reader.Get(certElements.CertificationType));
     170              : 
     171            3 :     certElements.DACOriginVIDandPIDPresent = false;
     172              : 
     173              :     // If kTag_DACOriginVendorId present then kTag_DACOriginProductId must be present.
     174            3 :     if ((err = reader.Next(ContextTag(kTag_DACOriginVendorId))) == CHIP_NO_ERROR)
     175              :     {
     176            1 :         ReturnErrorOnFailure(reader.Get(certElements.DACOriginVendorId));
     177              : 
     178            1 :         ReturnErrorOnFailure(reader.Next(ContextTag(kTag_DACOriginProductId)));
     179            1 :         ReturnErrorOnFailure(reader.Get(certElements.DACOriginProductId));
     180              : 
     181            1 :         certElements.DACOriginVIDandPIDPresent = true;
     182              : 
     183            1 :         err = reader.Next();
     184              :     }
     185            3 :     VerifyOrReturnError(err == CHIP_END_OF_TLV || err == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT || err == CHIP_NO_ERROR, err);
     186            3 :     VerifyOrReturnError(reader.GetTag() != TLV::ContextTag(kTag_DACOriginProductId), CHIP_ERROR_INVALID_TLV_ELEMENT);
     187              : 
     188            3 :     if (err != CHIP_END_OF_TLV && reader.GetTag() == ContextTag(kTag_AuthorizedPAAList))
     189              :     {
     190            1 :         VerifyOrReturnError(reader.GetType() == kTLVType_Array, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
     191              : 
     192            1 :         ReturnErrorOnFailure(reader.EnterContainer(outerContainer2));
     193              : 
     194            1 :         certElements.AuthorizedPAAListCount = 0;
     195           11 :         while ((err = reader.Next(kTLVType_ByteString, AnonymousTag())) == CHIP_NO_ERROR)
     196              :         {
     197           10 :             VerifyOrReturnError(reader.GetLength() == kKeyIdentifierLength, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
     198           10 :             VerifyOrReturnError(certElements.AuthorizedPAAListCount < kMaxAuthorizedPAAListCount, CHIP_ERROR_INVALID_ARGUMENT);
     199              : 
     200           10 :             ReturnErrorOnFailure(
     201              :                 reader.GetBytes(certElements.AuthorizedPAAList[certElements.AuthorizedPAAListCount++], kKeyIdentifierLength));
     202              :         }
     203            1 :         VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
     204            1 :         ReturnErrorOnFailure(reader.ExitContainer(outerContainer2));
     205              : 
     206            1 :         err = reader.Next();
     207              :     }
     208            3 :     VerifyOrReturnError(err == CHIP_END_OF_TLV || err == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT || err == CHIP_NO_ERROR, err);
     209              : 
     210            3 :     ReturnErrorOnFailure(reader.ExitContainer(outerContainer1));
     211              : 
     212            3 :     ReturnErrorOnFailure(reader.VerifyEndOfContainer());
     213              : 
     214            3 :     return CHIP_NO_ERROR;
     215              : }
     216              : 
     217           83 : CHIP_ERROR DecodeCertificationElements(const ByteSpan & encodedCertElements, CertificationElementsWithoutPIDs & certDeclContent)
     218              : {
     219              :     CHIP_ERROR err;
     220           83 :     TLVReader reader;
     221              :     TLVType outerContainer;
     222              :     TLVType outerContainer2;
     223              : 
     224           83 :     VerifyOrReturnError(encodedCertElements.size() <= kMaxCMSSignedCDMessage, CHIP_ERROR_INVALID_ARGUMENT);
     225              : 
     226           83 :     reader.Init(encodedCertElements);
     227              : 
     228           83 :     ReturnErrorOnFailure(reader.Next(kTLVType_Structure, AnonymousTag()));
     229              : 
     230           83 :     ReturnErrorOnFailure(reader.EnterContainer(outerContainer));
     231              : 
     232           83 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_FormatVersion)));
     233           82 :     ReturnErrorOnFailure(reader.Get(certDeclContent.formatVersion));
     234              : 
     235           82 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_VendorId)));
     236           81 :     ReturnErrorOnFailure(reader.Get(certDeclContent.vendorId));
     237              : 
     238           81 :     ReturnErrorOnFailure(reader.Next(kTLVType_Array, ContextTag(kTag_ProductIdArray)));
     239           80 :     ReturnErrorOnFailure(reader.EnterContainer(outerContainer2));
     240              : 
     241          475 :     while ((err = reader.Next(kTLVType_UnsignedInteger, AnonymousTag())) == CHIP_NO_ERROR)
     242              :     {
     243              :         // Verifies that the TLV structure of PID Array is correct
     244              :         // but skip the values
     245              :     }
     246           80 :     VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
     247           80 :     ReturnErrorOnFailure(reader.ExitContainer(outerContainer2));
     248              : 
     249           80 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_DeviceTypeId)));
     250           79 :     ReturnErrorOnFailure(reader.Get(certDeclContent.deviceTypeId));
     251              : 
     252           79 :     ReturnErrorOnFailure(reader.Next(kTLVType_UTF8String, ContextTag(kTag_CertificateId)));
     253           78 :     ReturnErrorOnFailure(reader.GetString(certDeclContent.certificateId, sizeof(certDeclContent.certificateId)));
     254           77 :     VerifyOrReturnError(strlen(certDeclContent.certificateId) == kCertificateIdLength, CHIP_ERROR_INVALID_TLV_ELEMENT);
     255              : 
     256           77 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_SecurityLevel)));
     257           76 :     ReturnErrorOnFailure(reader.Get(certDeclContent.securityLevel));
     258              : 
     259           76 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_SecurityInformation)));
     260           75 :     ReturnErrorOnFailure(reader.Get(certDeclContent.securityInformation));
     261              : 
     262           75 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_VersionNumber)));
     263           74 :     ReturnErrorOnFailure(reader.Get(certDeclContent.versionNumber));
     264              : 
     265           74 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_CertificationType)));
     266           73 :     ReturnErrorOnFailure(reader.Get(certDeclContent.certificationType));
     267              : 
     268           73 :     certDeclContent.dacOriginVIDandPIDPresent = false;
     269              : 
     270              :     // If kTag_DACOriginVendorId present then kTag_DACOriginProductId must be present.
     271           73 :     if ((err = reader.Next(ContextTag(kTag_DACOriginVendorId))) == CHIP_NO_ERROR)
     272              :     {
     273            6 :         ReturnErrorOnFailure(reader.Get(certDeclContent.dacOriginVendorId));
     274              : 
     275            6 :         ReturnErrorOnFailure(reader.Next(ContextTag(kTag_DACOriginProductId)));
     276            5 :         ReturnErrorOnFailure(reader.Get(certDeclContent.dacOriginProductId));
     277              : 
     278            5 :         certDeclContent.dacOriginVIDandPIDPresent = true;
     279              : 
     280            5 :         err = reader.Next();
     281              :     }
     282           72 :     VerifyOrReturnError(err == CHIP_END_OF_TLV || err == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT || err == CHIP_NO_ERROR, err);
     283           72 :     VerifyOrReturnError(reader.GetTag() != TLV::ContextTag(kTag_DACOriginProductId), CHIP_ERROR_INVALID_TLV_ELEMENT);
     284              : 
     285           71 :     if (err != CHIP_END_OF_TLV && reader.GetTag() == ContextTag(kTag_AuthorizedPAAList))
     286              :     {
     287            7 :         VerifyOrReturnError(reader.GetType() == kTLVType_Array, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
     288              : 
     289            7 :         ReturnErrorOnFailure(reader.EnterContainer(outerContainer2));
     290              : 
     291           43 :         while ((err = reader.Next(kTLVType_ByteString, AnonymousTag())) == CHIP_NO_ERROR)
     292              :         {
     293           36 :             VerifyOrReturnError(reader.GetLength() == kKeyIdentifierLength, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
     294              :             // Verifies that the TLV structure of the Authorized PAA List is correct
     295              :             // but skip the values
     296              :         }
     297            7 :         VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
     298              : 
     299            7 :         ReturnErrorOnFailure(reader.ExitContainer(outerContainer2));
     300              : 
     301            7 :         certDeclContent.authorizedPAAListPresent = true;
     302              : 
     303            7 :         err = reader.Next();
     304              :     }
     305           71 :     VerifyOrReturnError(err == CHIP_END_OF_TLV || err == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT || err == CHIP_NO_ERROR, err);
     306              : 
     307           71 :     ReturnErrorOnFailure(reader.ExitContainer(outerContainer));
     308              : 
     309           71 :     ReturnErrorOnFailure(reader.VerifyEndOfContainer());
     310              : 
     311           71 :     return CHIP_NO_ERROR;
     312              : }
     313              : 
     314          368 : bool CertificationElementsDecoder::IsProductIdIn(const ByteSpan & encodedCertElements, uint16_t productId)
     315              : {
     316          368 :     VerifyOrReturnError(FindAndEnterArray(encodedCertElements, ContextTag(kTag_ProductIdArray)) == CHIP_NO_ERROR, false);
     317              : 
     318          368 :     uint16_t cdProductId = 0;
     319        15437 :     while (GetNextProductId(cdProductId) == CHIP_NO_ERROR)
     320              :     {
     321        15328 :         if (productId == cdProductId)
     322              :         {
     323          259 :             return true;
     324              :         }
     325              :     }
     326          109 :     return false;
     327              : }
     328              : 
     329          394 : CHIP_ERROR CertificationElementsDecoder::FindAndEnterArray(const ByteSpan & encodedCertElements, Tag arrayTag)
     330              : {
     331              :     TLVType outerContainerType1;
     332              :     TLVType outerContainerType2;
     333              : 
     334          394 :     mReader.Init(encodedCertElements);
     335          394 :     ReturnErrorOnFailure(mReader.Next(kTLVType_Structure, AnonymousTag()));
     336          394 :     ReturnErrorOnFailure(mReader.EnterContainer(outerContainerType1));
     337              : 
     338              :     // position to arrayTag Array
     339              :     do
     340              :     {
     341         1364 :         ReturnErrorOnFailure(mReader.Next());
     342         1364 :     } while (mReader.Expect(kTLVType_Array, arrayTag) != CHIP_NO_ERROR);
     343              : 
     344          394 :     ReturnErrorOnFailure(mReader.EnterContainer(outerContainerType2));
     345              : 
     346          394 :     return CHIP_NO_ERROR;
     347              : }
     348              : 
     349        15437 : CHIP_ERROR CertificationElementsDecoder::GetNextProductId(uint16_t & productId)
     350              : {
     351        15437 :     ReturnErrorOnFailure(mReader.Next(AnonymousTag()));
     352        15328 :     ReturnErrorOnFailure(mReader.Get(productId));
     353        15328 :     return CHIP_NO_ERROR;
     354              : }
     355              : 
     356           26 : bool CertificationElementsDecoder::HasAuthorizedPAA(const ByteSpan & encodedCertElements, const ByteSpan & authorizedPAA)
     357              : {
     358           26 :     VerifyOrReturnError(FindAndEnterArray(encodedCertElements, ContextTag(kTag_AuthorizedPAAList)) == CHIP_NO_ERROR, false);
     359              : 
     360           26 :     ByteSpan cdAuthorizedPAA;
     361          184 :     while (GetNextAuthorizedPAA(cdAuthorizedPAA) == CHIP_NO_ERROR)
     362              :     {
     363          171 :         if (authorizedPAA.data_equal(cdAuthorizedPAA))
     364              :         {
     365           13 :             return true;
     366              :         }
     367              :     }
     368           13 :     return false;
     369              : }
     370              : 
     371          184 : CHIP_ERROR CertificationElementsDecoder::GetNextAuthorizedPAA(ByteSpan & authorizedPAA)
     372              : {
     373          184 :     ReturnErrorOnFailure(mReader.Next(AnonymousTag()));
     374          171 :     ReturnErrorOnFailure(mReader.Get(authorizedPAA));
     375          171 :     return CHIP_NO_ERROR;
     376              : }
     377              : 
     378              : namespace {
     379              : 
     380            2 : CHIP_ERROR EncodeEncapsulatedContent(const ByteSpan & cdContent, ASN1Writer & writer)
     381              : {
     382              :     /**
     383              :      * EncapsulatedContentInfo ::= SEQUENCE {
     384              :      *   eContentType OBJECT IDENTIFIER pkcs7-data (1.2.840.113549.1.7.1),
     385              :      *   eContent [0] EXPLICIT OCTET STRING cd_content }
     386              :      */
     387            2 :     CHIP_ERROR err = CHIP_NO_ERROR;
     388              : 
     389            2 :     ASN1_START_SEQUENCE
     390              :     {
     391              :         // eContentType OBJECT IDENTIFIER pkcs7-data (1.2.840.113549.1.7.1)
     392            2 :         ReturnErrorOnFailure(writer.PutObjectId(sOID_ContentType_PKCS7Data, sizeof(sOID_ContentType_PKCS7Data)));
     393              : 
     394              :         // eContent [0] EXPLICIT OCTET STRING cd_content
     395            2 :         ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
     396              :         {
     397              :             // OCTET STRING cd_content
     398            2 :             ReturnErrorOnFailure(writer.PutOctetString(cdContent.data(), static_cast<uint16_t>(cdContent.size())));
     399              :         }
     400            2 :         ASN1_END_CONSTRUCTED;
     401              :     }
     402            2 :     ASN1_END_SEQUENCE;
     403              : 
     404            2 : exit:
     405            2 :     return err;
     406              : }
     407              : 
     408           92 : CHIP_ERROR DecodeEncapsulatedContent(ASN1Reader & reader, ByteSpan & cdContent)
     409              : {
     410              :     /**
     411              :      * EncapsulatedContentInfo ::= SEQUENCE {
     412              :      *   eContentType OBJECT IDENTIFIER pkcs7-data (1.2.840.113549.1.7.1),
     413              :      *   eContent [0] EXPLICIT OCTET STRING cd_content }
     414              :      */
     415           92 :     CHIP_ERROR err = CHIP_NO_ERROR;
     416              : 
     417           92 :     ASN1_PARSE_ENTER_SEQUENCE
     418              :     {
     419              :         // eContentType OBJECT IDENTIFIER pkcs7-data (1.2.840.113549.1.7.1)
     420           92 :         ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
     421           92 :         VerifyOrReturnError(ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_ContentType_PKCS7Data)),
     422              :                             ASN1_ERROR_UNSUPPORTED_ENCODING);
     423              : 
     424              :         // eContent [0] EXPLICIT OCTET STRING cd_content
     425           91 :         ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
     426              :         {
     427              :             // OCTET STRING cd_content
     428           91 :             ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_OctetString);
     429           91 :             cdContent = ByteSpan(reader.GetValue(), reader.GetValueLen());
     430              :         }
     431           91 :         ASN1_EXIT_CONSTRUCTED;
     432              :     }
     433           91 :     ASN1_EXIT_SEQUENCE;
     434              : 
     435           91 : exit:
     436           91 :     return err;
     437              : }
     438              : 
     439            2 : CHIP_ERROR EncodeSignerInfo(const ByteSpan & signerKeyId, const P256ECDSASignature & signature, ASN1Writer & writer)
     440              : {
     441              :     /**
     442              :      * SignerInfo ::= SEQUENCE {
     443              :      *   version INTEGER ( v3(3) ),
     444              :      *   subjectKeyIdentifier OCTET STRING,
     445              :      *   digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1),
     446              :      *   signatureAlgorithm OBJECT IDENTIFIER ecdsa-with-SHA256 (1.2.840.10045.4.3.2),
     447              :      *   signature OCTET STRING }
     448              :      */
     449            2 :     CHIP_ERROR err = CHIP_NO_ERROR;
     450              : 
     451            2 :     ASN1_START_SET
     452              :     {
     453            2 :         ASN1_START_SEQUENCE
     454              :         {
     455              :             // version INTEGER ( v3(3) )
     456            2 :             ASN1_ENCODE_INTEGER(3);
     457              : 
     458              :             // subjectKeyIdentifier OCTET STRING
     459            2 :             ReturnErrorOnFailure(writer.PutOctetString(kASN1TagClass_ContextSpecific, 0, signerKeyId.data(),
     460              :                                                        static_cast<uint16_t>(signerKeyId.size())));
     461              : 
     462              :             // digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
     463            2 :             ASN1_START_SEQUENCE
     464              :             {
     465            2 :                 ReturnErrorOnFailure(writer.PutObjectId(sOID_DigestAlgo_SHA256, sizeof(sOID_DigestAlgo_SHA256)));
     466              :             }
     467            2 :             ASN1_END_SEQUENCE;
     468              : 
     469              :             // signatureAlgorithm OBJECT IDENTIFIER ecdsa-with-SHA256 (1.2.840.10045.4.3.2)
     470            2 :             ASN1_START_SEQUENCE
     471              :             {
     472            2 :                 ASN1_ENCODE_OBJECT_ID(kOID_SigAlgo_ECDSAWithSHA256);
     473              :             }
     474            2 :             ASN1_END_SEQUENCE;
     475              : 
     476              :             // signature OCTET STRING
     477            2 :             ASN1_START_OCTET_STRING_ENCAPSULATED
     478              :             {
     479            2 :                 ReturnErrorOnFailure(ConvertECDSASignatureRawToDER(P256ECDSASignatureSpan(signature.ConstBytes()), writer));
     480              :             }
     481            2 :             ASN1_END_ENCAPSULATED;
     482              :         }
     483            2 :         ASN1_END_SEQUENCE;
     484              :     }
     485            2 :     ASN1_END_SET;
     486              : 
     487            2 : exit:
     488            2 :     return err;
     489              : }
     490              : 
     491          182 : CHIP_ERROR DecodeSignerInfo(ASN1Reader & reader, ByteSpan & signerKeyId, P256ECDSASignature & signature)
     492              : {
     493              :     /**
     494              :      * SignerInfo ::= SEQUENCE {
     495              :      *   version INTEGER ( v3(3) ),
     496              :      *   subjectKeyIdentifier OCTET STRING,
     497              :      *   digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1),
     498              :      *   signatureAlgorithm OBJECT IDENTIFIER ecdsa-with-SHA256 (1.2.840.10045.4.3.2),
     499              :      *   signature OCTET STRING }
     500              :      */
     501          182 :     CHIP_ERROR err = CHIP_NO_ERROR;
     502              : 
     503          182 :     ASN1_PARSE_ENTER_SET
     504              :     {
     505          182 :         ASN1_PARSE_ENTER_SEQUENCE
     506              :         {
     507              :             // version INTEGER ( v3(3) )
     508              :             {
     509              :                 int64_t version;
     510          183 :                 ASN1_PARSE_INTEGER(version);
     511              : 
     512              :                 // Verify that the CMS version is v3
     513          182 :                 VerifyOrExit(version == 3, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
     514              :             }
     515              : 
     516              :             // subjectKeyIdentifier OCTET STRING
     517          181 :             ASN1_PARSE_ELEMENT(kASN1TagClass_ContextSpecific, 0);
     518          181 :             signerKeyId = ByteSpan(reader.GetValue(), reader.GetValueLen());
     519              : 
     520              :             // digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
     521          181 :             ASN1_PARSE_ENTER_SEQUENCE
     522              :             {
     523          181 :                 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
     524          182 :                 VerifyOrReturnError(ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_DigestAlgo_SHA256)),
     525              :                                     ASN1_ERROR_UNSUPPORTED_ENCODING);
     526              :             }
     527          180 :             ASN1_EXIT_SEQUENCE;
     528              : 
     529              :             // signatureAlgorithm OBJECT IDENTIFIER ecdsa-with-SHA256 (1.2.840.10045.4.3.2)
     530          180 :             ASN1_PARSE_ENTER_SEQUENCE
     531              :             {
     532          180 :                 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
     533          180 :                 VerifyOrReturnError(
     534              :                     ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_SigAlgo_ECDSAWithSHA256)),
     535              :                     ASN1_ERROR_UNSUPPORTED_ENCODING);
     536              :             }
     537          179 :             ASN1_EXIT_SEQUENCE;
     538              : 
     539              :             // signature OCTET STRING
     540          179 :             ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_OctetString);
     541              : 
     542          179 :             MutableByteSpan signatureSpan(signature.Bytes(), signature.Capacity());
     543          179 :             ReturnErrorOnFailure(
     544              :                 EcdsaAsn1SignatureToRaw(kP256_FE_Length, ByteSpan(reader.GetValue(), reader.GetValueLen()), signatureSpan));
     545          179 :             ReturnErrorOnFailure(signature.SetLength(signatureSpan.size()));
     546              :         }
     547          179 :         ASN1_EXIT_SEQUENCE;
     548              :     }
     549          179 :     ASN1_EXIT_SET;
     550              : 
     551          180 : exit:
     552          180 :     return err;
     553              : }
     554              : 
     555              : } // namespace
     556              : 
     557            2 : CHIP_ERROR CMS_Sign(const ByteSpan & cdContent, const ByteSpan & signerKeyId, Crypto::P256Keypair & signerKeypair,
     558              :                     MutableByteSpan & signedMessage)
     559              : {
     560              :     /**
     561              :      * CertificationDeclaration ::= SEQUENCE {
     562              :      *   version INTEGER ( v3(3) ),
     563              :      *   digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1),
     564              :      *   encapContentInfo EncapsulatedContentInfo,
     565              :      *   signerInfo SignerInfo }
     566              :      */
     567            2 :     CHIP_ERROR err = CHIP_NO_ERROR;
     568              :     ASN1Writer writer;
     569            2 :     uint32_t size = static_cast<uint32_t>(std::min(static_cast<size_t>(UINT32_MAX), signedMessage.size()));
     570              : 
     571            2 :     writer.Init(signedMessage.data(), size);
     572              : 
     573            2 :     ASN1_START_SEQUENCE
     574              :     {
     575              :         // OID identifies the CMS signed-data content type
     576            2 :         ReturnErrorOnFailure(writer.PutObjectId(sOID_ContentType_PKCS7SignedData, sizeof(sOID_ContentType_PKCS7SignedData)));
     577              : 
     578            2 :         ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
     579              :         {
     580            2 :             ASN1_START_SEQUENCE
     581              :             {
     582              :                 // version INTEGER ( v3(3) )
     583            2 :                 ASN1_ENCODE_INTEGER(3);
     584              : 
     585              :                 // digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
     586            2 :                 ASN1_START_SET
     587              :                 {
     588            2 :                     ASN1_START_SEQUENCE
     589              :                     {
     590            2 :                         ReturnErrorOnFailure(writer.PutObjectId(sOID_DigestAlgo_SHA256, sizeof(sOID_DigestAlgo_SHA256)));
     591              :                     }
     592            2 :                     ASN1_END_SEQUENCE;
     593              :                 }
     594            2 :                 ASN1_END_SET;
     595              : 
     596              :                 // encapContentInfo EncapsulatedContentInfo
     597            2 :                 ReturnErrorOnFailure(EncodeEncapsulatedContent(cdContent, writer));
     598              : 
     599            2 :                 Crypto::P256ECDSASignature signature;
     600            2 :                 ReturnErrorOnFailure(signerKeypair.ECDSA_sign_msg(cdContent.data(), cdContent.size(), signature));
     601              : 
     602              :                 // signerInfo SignerInfo
     603            2 :                 ReturnErrorOnFailure(EncodeSignerInfo(signerKeyId, signature, writer));
     604            2 :             }
     605            2 :             ASN1_END_SEQUENCE;
     606              :         }
     607            2 :         ASN1_END_CONSTRUCTED;
     608              :     }
     609            2 :     ASN1_END_SEQUENCE;
     610              : 
     611            2 :     signedMessage.reduce_size(writer.GetLengthWritten());
     612              : 
     613            2 : exit:
     614            2 :     return err;
     615              : }
     616              : 
     617            2 : CHIP_ERROR CMS_Verify(const ByteSpan & signedMessage, const ByteSpan & signerX509Cert, ByteSpan & cdContent)
     618              : {
     619            2 :     P256PublicKey signerPubkey;
     620              : 
     621            2 :     ReturnErrorOnFailure(ExtractPubkeyFromX509Cert(signerX509Cert, signerPubkey));
     622              : 
     623            2 :     return CMS_Verify(signedMessage, signerPubkey, cdContent);
     624            2 : }
     625              : 
     626           92 : CHIP_ERROR CMS_Verify(const ByteSpan & signedMessage, const Crypto::P256PublicKey & signerPubkey, ByteSpan & cdContent)
     627              : {
     628           92 :     CHIP_ERROR err = CHIP_NO_ERROR;
     629              :     ASN1Reader reader;
     630           92 :     uint32_t size = signedMessage.size() > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(signedMessage.size());
     631              : 
     632           92 :     reader.Init(signedMessage.data(), size);
     633              : 
     634              :     // SignedData ::= SEQUENCE
     635           92 :     ASN1_PARSE_ENTER_SEQUENCE
     636              :     {
     637           92 :         ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
     638              : 
     639              :         // id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
     640              :         // OID identifies the CMS signed-data content type
     641           92 :         VerifyOrReturnError(
     642              :             ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_ContentType_PKCS7SignedData)),
     643              :             ASN1_ERROR_UNSUPPORTED_ENCODING);
     644              : 
     645              :         // version [0] EXPLICIT Version DEFAULT v3
     646           92 :         ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
     647              :         {
     648           92 :             ASN1_PARSE_ENTER_SEQUENCE
     649              :             {
     650              :                 // Version ::= INTEGER { v3(3) }
     651              :                 int64_t version;
     652           93 :                 ASN1_PARSE_INTEGER(version);
     653              : 
     654              :                 // Verify that the CMS version is v3
     655           92 :                 VerifyOrExit(version == 3, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
     656              : 
     657              :                 // digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
     658           91 :                 ASN1_PARSE_ENTER_SET
     659              :                 {
     660           91 :                     ASN1_PARSE_ENTER_SEQUENCE
     661              :                     {
     662           91 :                         ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
     663           93 :                         VerifyOrReturnError(
     664              :                             ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_DigestAlgo_SHA256)),
     665              :                             ASN1_ERROR_UNSUPPORTED_ENCODING);
     666              :                     }
     667           90 :                     ASN1_EXIT_SEQUENCE;
     668              :                 }
     669           90 :                 ASN1_EXIT_SET;
     670              : 
     671              :                 // encapContentInfo EncapsulatedContentInfo
     672           90 :                 ReturnErrorOnFailure(DecodeEncapsulatedContent(reader, cdContent));
     673              : 
     674              :                 // signerInfo SignerInfo
     675           89 :                 ByteSpan signerKeyId;
     676           89 :                 P256ECDSASignature signature;
     677           89 :                 ReturnErrorOnFailure(DecodeSignerInfo(reader, signerKeyId, signature));
     678              : 
     679              :                 // Validate CD Signature
     680           89 :                 ReturnErrorOnFailure(signerPubkey.ECDSA_validate_msg_signature(cdContent.data(), cdContent.size(), signature));
     681           89 :             }
     682           88 :             ASN1_EXIT_SEQUENCE;
     683              :         }
     684           88 :         ASN1_EXIT_CONSTRUCTED;
     685              :     }
     686           88 :     ASN1_EXIT_SEQUENCE;
     687              : 
     688           89 : exit:
     689           89 :     return err;
     690              : }
     691              : 
     692           93 : CHIP_ERROR CMS_ExtractKeyId(const ByteSpan & signedMessage, ByteSpan & signerKeyId)
     693              : {
     694           93 :     CHIP_ERROR err = CHIP_NO_ERROR;
     695              :     ASN1Reader reader;
     696           93 :     uint32_t size = signedMessage.size() > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(signedMessage.size());
     697              : 
     698           93 :     reader.Init(signedMessage.data(), size);
     699              : 
     700              :     // SignedData ::= SEQUENCE
     701           93 :     ASN1_PARSE_ENTER_SEQUENCE
     702              :     {
     703              :         // id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
     704              :         // OID identifies the CMS signed-data content type
     705           93 :         ASN1_PARSE_ANY;
     706              : 
     707              :         // version [0] EXPLICIT Version DEFAULT v3
     708           93 :         ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
     709              :         {
     710           93 :             ASN1_PARSE_ENTER_SEQUENCE
     711              :             {
     712              :                 // Version ::= INTEGER { v3(3) }
     713           93 :                 ASN1_PARSE_ANY;
     714              : 
     715              :                 // digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
     716           93 :                 ASN1_PARSE_ANY;
     717              : 
     718              :                 // encapContentInfo EncapsulatedContentInfo
     719           93 :                 ASN1_PARSE_ANY;
     720              : 
     721              :                 // signerInfo SignerInfo
     722           93 :                 P256ECDSASignature signature;
     723           93 :                 ReturnErrorOnFailure(DecodeSignerInfo(reader, signerKeyId, signature));
     724           93 :             }
     725           90 :             ASN1_EXIT_SEQUENCE;
     726              :         }
     727           90 :         ASN1_EXIT_CONSTRUCTED;
     728              :     }
     729           90 :     ASN1_EXIT_SEQUENCE;
     730              : 
     731           90 : exit:
     732           90 :     return err;
     733              : }
     734              : 
     735            2 : CHIP_ERROR CMS_ExtractCDContent(const ByteSpan & signedMessage, ByteSpan & cdContent)
     736              : {
     737            2 :     CHIP_ERROR err = CHIP_NO_ERROR;
     738              :     ASN1Reader reader;
     739            2 :     uint32_t size = signedMessage.size() > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(signedMessage.size());
     740              : 
     741            2 :     reader.Init(signedMessage.data(), size);
     742              : 
     743              :     // SignedData ::= SEQUENCE
     744            2 :     ASN1_PARSE_ENTER_SEQUENCE
     745              :     {
     746              :         // id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
     747              :         // OID identifies the CMS signed-data content type
     748            2 :         ASN1_PARSE_ANY;
     749              : 
     750              :         // version [0] EXPLICIT Version DEFAULT v3
     751            2 :         ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
     752              :         {
     753            2 :             ASN1_PARSE_ENTER_SEQUENCE
     754              :             {
     755              :                 // Version ::= INTEGER { v3(3) }
     756            2 :                 ASN1_PARSE_ANY;
     757              : 
     758              :                 // digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
     759            2 :                 ASN1_PARSE_ANY;
     760              : 
     761              :                 // encapContentInfo EncapsulatedContentInfo
     762            2 :                 ReturnErrorOnFailure(DecodeEncapsulatedContent(reader, cdContent));
     763              : 
     764              :                 // signerInfo SignerInfo
     765            2 :                 ASN1_PARSE_ANY;
     766              :             }
     767            2 :             ASN1_EXIT_SEQUENCE;
     768              :         }
     769            2 :         ASN1_EXIT_CONSTRUCTED;
     770              :     }
     771            2 :     ASN1_EXIT_SEQUENCE;
     772              : 
     773            2 : exit:
     774            2 :     return err;
     775              : }
     776              : 
     777              : } // namespace Credentials
     778              : } // namespace chip
        

Generated by: LCOV version 2.0-1