LCOV - code coverage report
Current view: top level - credentials - CertificationDeclaration.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 323 323 100.0 %
Date: 2024-02-15 08:20:41 Functions: 17 17 100.0 %

          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             :     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          81 : CHIP_ERROR DecodeCertificationElements(const ByteSpan & encodedCertElements, CertificationElementsWithoutPIDs & certDeclContent)
     218             : {
     219             :     CHIP_ERROR err;
     220             :     TLVReader reader;
     221             :     TLVType outerContainer;
     222             :     TLVType outerContainer2;
     223             : 
     224          81 :     VerifyOrReturnError(encodedCertElements.size() <= kMaxCMSSignedCDMessage, CHIP_ERROR_INVALID_ARGUMENT);
     225             : 
     226          81 :     reader.Init(encodedCertElements);
     227             : 
     228          81 :     ReturnErrorOnFailure(reader.Next(kTLVType_Structure, AnonymousTag()));
     229             : 
     230          81 :     ReturnErrorOnFailure(reader.EnterContainer(outerContainer));
     231             : 
     232          81 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_FormatVersion)));
     233          80 :     ReturnErrorOnFailure(reader.Get(certDeclContent.formatVersion));
     234             : 
     235          80 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_VendorId)));
     236          79 :     ReturnErrorOnFailure(reader.Get(certDeclContent.vendorId));
     237             : 
     238          79 :     ReturnErrorOnFailure(reader.Next(kTLVType_Array, ContextTag(kTag_ProductIdArray)));
     239          78 :     ReturnErrorOnFailure(reader.EnterContainer(outerContainer2));
     240             : 
     241         471 :     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          78 :     VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
     247          78 :     ReturnErrorOnFailure(reader.ExitContainer(outerContainer2));
     248             : 
     249          78 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_DeviceTypeId)));
     250          77 :     ReturnErrorOnFailure(reader.Get(certDeclContent.deviceTypeId));
     251             : 
     252          77 :     ReturnErrorOnFailure(reader.Next(kTLVType_UTF8String, ContextTag(kTag_CertificateId)));
     253          76 :     ReturnErrorOnFailure(reader.GetString(certDeclContent.certificateId, sizeof(certDeclContent.certificateId)));
     254          75 :     VerifyOrReturnError(strlen(certDeclContent.certificateId) == kCertificateIdLength, CHIP_ERROR_INVALID_TLV_ELEMENT);
     255             : 
     256          75 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_SecurityLevel)));
     257          74 :     ReturnErrorOnFailure(reader.Get(certDeclContent.securityLevel));
     258             : 
     259          74 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_SecurityInformation)));
     260          73 :     ReturnErrorOnFailure(reader.Get(certDeclContent.securityInformation));
     261             : 
     262          73 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_VersionNumber)));
     263          72 :     ReturnErrorOnFailure(reader.Get(certDeclContent.versionNumber));
     264             : 
     265          72 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_CertificationType)));
     266          71 :     ReturnErrorOnFailure(reader.Get(certDeclContent.certificationType));
     267             : 
     268          71 :     certDeclContent.dacOriginVIDandPIDPresent = false;
     269             : 
     270             :     // If kTag_DACOriginVendorId present then kTag_DACOriginProductId must be present.
     271          71 :     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          70 :     VerifyOrReturnError(err == CHIP_END_OF_TLV || err == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT || err == CHIP_NO_ERROR, err);
     283          70 :     VerifyOrReturnError(reader.GetTag() != TLV::ContextTag(kTag_DACOriginProductId), CHIP_ERROR_INVALID_TLV_ELEMENT);
     284             : 
     285          69 :     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          69 :     VerifyOrReturnError(err == CHIP_END_OF_TLV || err == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT || err == CHIP_NO_ERROR, err);
     306             : 
     307          69 :     ReturnErrorOnFailure(reader.ExitContainer(outerContainer));
     308             : 
     309          69 :     ReturnErrorOnFailure(reader.VerifyEndOfContainer());
     310             : 
     311          69 :     return CHIP_NO_ERROR;
     312             : }
     313             : 
     314         362 : bool CertificationElementsDecoder::IsProductIdIn(const ByteSpan & encodedCertElements, uint16_t productId)
     315             : {
     316         362 :     VerifyOrReturnError(FindAndEnterArray(encodedCertElements, ContextTag(kTag_ProductIdArray)) == CHIP_NO_ERROR, false);
     317             : 
     318         362 :     uint16_t cdProductId = 0;
     319       15431 :     while (GetNextProductId(cdProductId) == CHIP_NO_ERROR)
     320             :     {
     321       15322 :         if (productId == cdProductId)
     322             :         {
     323         253 :             return true;
     324             :         }
     325             :     }
     326         109 :     return false;
     327             : }
     328             : 
     329         388 : CHIP_ERROR CertificationElementsDecoder::FindAndEnterArray(const ByteSpan & encodedCertElements, Tag arrayTag)
     330             : {
     331             :     TLVType outerContainerType1;
     332             :     TLVType outerContainerType2;
     333             : 
     334         388 :     mReader.Init(encodedCertElements);
     335         388 :     ReturnErrorOnFailure(mReader.Next(kTLVType_Structure, AnonymousTag()));
     336         388 :     ReturnErrorOnFailure(mReader.EnterContainer(outerContainerType1));
     337             : 
     338             :     // position to arrayTag Array
     339             :     do
     340             :     {
     341        1346 :         ReturnErrorOnFailure(mReader.Next());
     342        1346 :     } while (mReader.Expect(kTLVType_Array, arrayTag) != CHIP_NO_ERROR);
     343             : 
     344         388 :     ReturnErrorOnFailure(mReader.EnterContainer(outerContainerType2));
     345             : 
     346         388 :     return CHIP_NO_ERROR;
     347             : }
     348             : 
     349       15431 : CHIP_ERROR CertificationElementsDecoder::GetNextProductId(uint16_t & productId)
     350             : {
     351       15431 :     ReturnErrorOnFailure(mReader.Next(AnonymousTag()));
     352       15322 :     ReturnErrorOnFailure(mReader.Get(productId));
     353       15322 :     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          90 : 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          90 :     CHIP_ERROR err = CHIP_NO_ERROR;
     416             : 
     417          90 :     ASN1_PARSE_ENTER_SEQUENCE
     418             :     {
     419             :         // eContentType OBJECT IDENTIFIER pkcs7-data (1.2.840.113549.1.7.1)
     420          90 :         ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
     421          90 :         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          89 :         ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
     426             :         {
     427             :             // OCTET STRING cd_content
     428          89 :             ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_OctetString);
     429          89 :             cdContent = ByteSpan(reader.GetValue(), reader.GetValueLen());
     430             :         }
     431          89 :         ASN1_EXIT_CONSTRUCTED;
     432             :     }
     433          89 :     ASN1_EXIT_SEQUENCE;
     434             : 
     435          89 : exit:
     436          89 :     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         178 : 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         178 :     CHIP_ERROR err = CHIP_NO_ERROR;
     502             : 
     503         178 :     ASN1_PARSE_ENTER_SET
     504             :     {
     505         178 :         ASN1_PARSE_ENTER_SEQUENCE
     506             :         {
     507             :             // version INTEGER ( v3(3) )
     508             :             {
     509             :                 int64_t version;
     510         179 :                 ASN1_PARSE_INTEGER(version);
     511             : 
     512             :                 // Verify that the CMS version is v3
     513         178 :                 VerifyOrExit(version == 3, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
     514             :             }
     515             : 
     516             :             // subjectKeyIdentifier OCTET STRING
     517         177 :             ASN1_PARSE_ELEMENT(kASN1TagClass_ContextSpecific, 0);
     518         177 :             signerKeyId = ByteSpan(reader.GetValue(), reader.GetValueLen());
     519             : 
     520             :             // digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
     521         177 :             ASN1_PARSE_ENTER_SEQUENCE
     522             :             {
     523         177 :                 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
     524         178 :                 VerifyOrReturnError(ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_DigestAlgo_SHA256)),
     525             :                                     ASN1_ERROR_UNSUPPORTED_ENCODING);
     526             :             }
     527         176 :             ASN1_EXIT_SEQUENCE;
     528             : 
     529             :             // signatureAlgorithm OBJECT IDENTIFIER ecdsa-with-SHA256 (1.2.840.10045.4.3.2)
     530         176 :             ASN1_PARSE_ENTER_SEQUENCE
     531             :             {
     532         176 :                 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
     533         176 :                 VerifyOrReturnError(
     534             :                     ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_SigAlgo_ECDSAWithSHA256)),
     535             :                     ASN1_ERROR_UNSUPPORTED_ENCODING);
     536             :             }
     537         175 :             ASN1_EXIT_SEQUENCE;
     538             : 
     539             :             // signature OCTET STRING
     540         175 :             ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_OctetString);
     541             : 
     542         175 :             MutableByteSpan signatureSpan(signature.Bytes(), signature.Capacity());
     543         175 :             ReturnErrorOnFailure(
     544             :                 EcdsaAsn1SignatureToRaw(kP256_FE_Length, ByteSpan(reader.GetValue(), reader.GetValueLen()), signatureSpan));
     545         175 :             ReturnErrorOnFailure(signature.SetLength(signatureSpan.size()));
     546             :         }
     547         175 :         ASN1_EXIT_SEQUENCE;
     548             :     }
     549         175 :     ASN1_EXIT_SET;
     550             : 
     551         176 : exit:
     552         176 :     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          90 : CHIP_ERROR CMS_Verify(const ByteSpan & signedMessage, const Crypto::P256PublicKey & signerPubkey, ByteSpan & cdContent)
     627             : {
     628          90 :     CHIP_ERROR err = CHIP_NO_ERROR;
     629             :     ASN1Reader reader;
     630          90 :     uint32_t size = signedMessage.size() > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(signedMessage.size());
     631             : 
     632          90 :     reader.Init(signedMessage.data(), size);
     633             : 
     634             :     // SignedData ::= SEQUENCE
     635          90 :     ASN1_PARSE_ENTER_SEQUENCE
     636             :     {
     637          90 :         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          90 :         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          90 :         ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
     647             :         {
     648          90 :             ASN1_PARSE_ENTER_SEQUENCE
     649             :             {
     650             :                 // Version ::= INTEGER { v3(3) }
     651             :                 int64_t version;
     652          91 :                 ASN1_PARSE_INTEGER(version);
     653             : 
     654             :                 // Verify that the CMS version is v3
     655          90 :                 VerifyOrExit(version == 3, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
     656             : 
     657             :                 // digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
     658          89 :                 ASN1_PARSE_ENTER_SET
     659             :                 {
     660          89 :                     ASN1_PARSE_ENTER_SEQUENCE
     661             :                     {
     662          89 :                         ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
     663          91 :                         VerifyOrReturnError(
     664             :                             ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_DigestAlgo_SHA256)),
     665             :                             ASN1_ERROR_UNSUPPORTED_ENCODING);
     666             :                     }
     667          88 :                     ASN1_EXIT_SEQUENCE;
     668             :                 }
     669          88 :                 ASN1_EXIT_SET;
     670             : 
     671             :                 // encapContentInfo EncapsulatedContentInfo
     672          88 :                 ReturnErrorOnFailure(DecodeEncapsulatedContent(reader, cdContent));
     673             : 
     674             :                 // signerInfo SignerInfo
     675          87 :                 ByteSpan signerKeyId;
     676          87 :                 P256ECDSASignature signature;
     677          87 :                 ReturnErrorOnFailure(DecodeSignerInfo(reader, signerKeyId, signature));
     678             : 
     679             :                 // Validate CD Signature
     680          87 :                 ReturnErrorOnFailure(signerPubkey.ECDSA_validate_msg_signature(cdContent.data(), cdContent.size(), signature));
     681          87 :             }
     682          86 :             ASN1_EXIT_SEQUENCE;
     683             :         }
     684          86 :         ASN1_EXIT_CONSTRUCTED;
     685             :     }
     686          86 :     ASN1_EXIT_SEQUENCE;
     687             : 
     688          87 : exit:
     689          87 :     return err;
     690             : }
     691             : 
     692          91 : CHIP_ERROR CMS_ExtractKeyId(const ByteSpan & signedMessage, ByteSpan & signerKeyId)
     693             : {
     694          91 :     CHIP_ERROR err = CHIP_NO_ERROR;
     695             :     ASN1Reader reader;
     696          91 :     uint32_t size = signedMessage.size() > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(signedMessage.size());
     697             : 
     698          91 :     reader.Init(signedMessage.data(), size);
     699             : 
     700             :     // SignedData ::= SEQUENCE
     701          91 :     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          91 :         ASN1_PARSE_ANY;
     706             : 
     707             :         // version [0] EXPLICIT Version DEFAULT v3
     708          91 :         ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
     709             :         {
     710          91 :             ASN1_PARSE_ENTER_SEQUENCE
     711             :             {
     712             :                 // Version ::= INTEGER { v3(3) }
     713          91 :                 ASN1_PARSE_ANY;
     714             : 
     715             :                 // digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
     716          91 :                 ASN1_PARSE_ANY;
     717             : 
     718             :                 // encapContentInfo EncapsulatedContentInfo
     719          91 :                 ASN1_PARSE_ANY;
     720             : 
     721             :                 // signerInfo SignerInfo
     722          91 :                 P256ECDSASignature signature;
     723          91 :                 ReturnErrorOnFailure(DecodeSignerInfo(reader, signerKeyId, signature));
     724          91 :             }
     725          88 :             ASN1_EXIT_SEQUENCE;
     726             :         }
     727          88 :         ASN1_EXIT_CONSTRUCTED;
     728             :     }
     729          88 :     ASN1_EXIT_SEQUENCE;
     730             : 
     731          88 : exit:
     732          88 :     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 1.14