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

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2021 Project CHIP Authors
       4             :  *
       5             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6             :  *    you may not use this file except in compliance with the License.
       7             :  *    You may obtain a copy of the License at
       8             :  *
       9             :  *        http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  *    Unless required by applicable law or agreed to in writing, software
      12             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  *    See the License for the specific language governing permissions and
      15             :  *    limitations under the License.
      16             :  */
      17             : #include "DeviceAttestationConstructor.h"
      18             : #include "DeviceAttestationVendorReserved.h"
      19             : 
      20             : #include <lib/core/TLV.h>
      21             : #include <lib/support/CodeUtils.h>
      22             : #include <lib/support/logging/CHIPLogging.h>
      23             : 
      24             : #include <cstdint>
      25             : 
      26             : namespace chip {
      27             : namespace Credentials {
      28             : 
      29             : // context tag positions
      30             : enum AttestationInfoId : uint32_t
      31             : {
      32             :     kCertificationDeclarationTagId = 1,
      33             :     kAttestationNonceTagId         = 2,
      34             :     kTimestampTagId                = 3,
      35             :     kFirmwareInfoTagId             = 4,
      36             : };
      37             : 
      38             : enum OperationalCSRInfoId : uint32_t
      39             : {
      40             :     kCsr             = 1,
      41             :     kCsrNonce        = 2,
      42             :     kVendorReserved1 = 3,
      43             :     kVendorReserved2 = 4,
      44             :     kVendorReserved3 = 5,
      45             : };
      46             : 
      47             : // utility to determine number of Vendor Reserved elements in a bytespan
      48          90 : CHIP_ERROR CountVendorReservedElementsInDA(const ByteSpan & attestationElements, size_t & numOfElements)
      49             : {
      50          90 :     TLV::ContiguousBufferTLVReader tlvReader;
      51          90 :     TLV::TLVType containerType = TLV::kTLVType_Structure;
      52             : 
      53          90 :     tlvReader.Init(attestationElements);
      54          90 :     ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag()));
      55          90 :     ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));
      56             : 
      57          90 :     size_t count = 0;
      58             :     CHIP_ERROR error;
      59         372 :     while ((error = tlvReader.Next()) == CHIP_NO_ERROR)
      60             :     {
      61         282 :         TLV::Tag tag = tlvReader.GetTag();
      62         282 :         if (TLV::IsProfileTag(tag))
      63             :         {
      64          10 :             count++;
      65             :         }
      66             :     }
      67          90 :     VerifyOrReturnError(error == CHIP_NO_ERROR || error == CHIP_END_OF_TLV, error);
      68             : 
      69          90 :     numOfElements = count;
      70          90 :     return CHIP_NO_ERROR;
      71             : }
      72             : 
      73          91 : CHIP_ERROR DeconstructAttestationElements(const ByteSpan & attestationElements, ByteSpan & certificationDeclaration,
      74             :                                           ByteSpan & attestationNonce, uint32_t & timestamp, ByteSpan & firmwareInfo,
      75             :                                           DeviceAttestationVendorReservedDeconstructor & vendorReserved)
      76             : {
      77          91 :     bool certificationDeclarationExists = false;
      78          91 :     bool attestationNonceExists         = false;
      79          91 :     bool timestampExists                = false;
      80          91 :     bool gotFirstContextTag             = false;
      81          91 :     uint32_t lastContextTagId           = 0;
      82             : 
      83          91 :     TLV::ContiguousBufferTLVReader tlvReader;
      84          91 :     TLV::TLVType containerType = TLV::kTLVType_Structure;
      85             : 
      86          91 :     firmwareInfo = ByteSpan();
      87             : 
      88          91 :     tlvReader.Init(attestationElements);
      89          91 :     ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag()));
      90          91 :     ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));
      91             : 
      92             :     CHIP_ERROR error;
      93             : 
      94             :     // process context tags first (should be in sorted order)
      95         363 :     while ((error = tlvReader.Next()) == CHIP_NO_ERROR)
      96             :     {
      97         278 :         TLV::Tag tag = tlvReader.GetTag();
      98         278 :         if (!TLV::IsContextTag(tag))
      99             :         {
     100           5 :             break;
     101             :         }
     102             : 
     103             :         // Ensure tag-order and correct first expected tag
     104         273 :         uint32_t contextTagId = TLV::TagNumFromTag(tag);
     105         273 :         if (!gotFirstContextTag)
     106             :         {
     107             :             // First tag must always be Certification Declaration
     108          91 :             VerifyOrReturnError(contextTagId == kCertificationDeclarationTagId, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
     109          90 :             gotFirstContextTag = true;
     110             :         }
     111             :         else
     112             :         {
     113             :             // Subsequent tags must always be in order
     114         182 :             VerifyOrReturnError(contextTagId > lastContextTagId, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
     115             :         }
     116         272 :         lastContextTagId = contextTagId;
     117             : 
     118         272 :         switch (contextTagId)
     119             :         {
     120          90 :         case kCertificationDeclarationTagId:
     121          90 :             ReturnErrorOnFailure(tlvReader.GetByteView(certificationDeclaration));
     122          90 :             certificationDeclarationExists = true;
     123          90 :             break;
     124          90 :         case kAttestationNonceTagId:
     125          90 :             ReturnErrorOnFailure(tlvReader.GetByteView(attestationNonce));
     126          90 :             attestationNonceExists = true;
     127          90 :             break;
     128          90 :         case kTimestampTagId:
     129          90 :             ReturnErrorOnFailure(tlvReader.Get(timestamp));
     130          90 :             timestampExists = true;
     131          90 :             break;
     132           1 :         case kFirmwareInfoTagId:
     133           1 :             ReturnErrorOnFailure(tlvReader.GetByteView(firmwareInfo));
     134           1 :             break;
     135           1 :         default:
     136             :             // It's OK to have future context tags before vendor specific tags.
     137             :             // We already checked that the tags are in order.
     138           1 :             break;
     139             :         }
     140             :     }
     141             : 
     142          90 :     VerifyOrReturnError(error == CHIP_NO_ERROR || error == CHIP_END_OF_TLV, error);
     143             : 
     144          90 :     const bool allTagsNeededPresent = certificationDeclarationExists && attestationNonceExists && timestampExists;
     145          90 :     VerifyOrReturnError(allTagsNeededPresent, CHIP_ERROR_MISSING_TLV_ELEMENT);
     146             : 
     147          90 :     size_t count = 0;
     148          90 :     ReturnErrorOnFailure(CountVendorReservedElementsInDA(attestationElements, count));
     149          90 :     ReturnErrorOnFailure(vendorReserved.PrepareToReadVendorReservedElements(attestationElements, count));
     150          90 :     return CHIP_NO_ERROR;
     151             : }
     152             : 
     153         153 : CHIP_ERROR ConstructAttestationElements(const ByteSpan & certificationDeclaration, const ByteSpan & attestationNonce,
     154             :                                         uint32_t timestamp, const ByteSpan & firmwareInfo,
     155             :                                         DeviceAttestationVendorReservedConstructor & vendorReserved,
     156             :                                         MutableByteSpan & attestationElements)
     157             : {
     158         153 :     TLV::TLVWriter tlvWriter;
     159         153 :     TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
     160             : 
     161         153 :     VerifyOrReturnError(!certificationDeclaration.empty() && !attestationNonce.empty(), CHIP_ERROR_INVALID_ARGUMENT);
     162         151 :     VerifyOrReturnError(attestationNonce.size() == kExpectedAttestationNonceSize, CHIP_ERROR_INVALID_ARGUMENT);
     163             : 
     164         150 :     tlvWriter.Init(attestationElements.data(), static_cast<uint32_t>(attestationElements.size()));
     165         150 :     outerContainerType = TLV::kTLVType_NotSpecified;
     166         150 :     ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
     167         150 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), certificationDeclaration));
     168         150 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), attestationNonce));
     169         150 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), timestamp));
     170         150 :     if (!firmwareInfo.empty())
     171             :     {
     172           0 :         ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(4), firmwareInfo));
     173             :     }
     174             : 
     175         150 :     const VendorReservedElement * element = vendorReserved.cbegin();
     176         154 :     while ((element = vendorReserved.Next()) != nullptr)
     177             :     {
     178           4 :         ReturnErrorOnFailure(
     179             :             tlvWriter.Put(TLV::ProfileTag(element->vendorId, element->profileNum, element->tagNum), element->vendorReservedData));
     180             :     }
     181             : 
     182         150 :     ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
     183         150 :     ReturnErrorOnFailure(tlvWriter.Finalize());
     184         150 :     attestationElements = attestationElements.SubSpan(0, tlvWriter.GetLengthWritten());
     185             : 
     186         150 :     VerifyOrReturnError(attestationElements.size() <= Credentials::kMaxRspLen, CHIP_ERROR_MESSAGE_TOO_LONG);
     187             : 
     188         150 :     return CHIP_NO_ERROR;
     189             : }
     190             : 
     191           1 : CHIP_ERROR ConstructNOCSRElements(const ByteSpan & csr, const ByteSpan & csrNonce, const ByteSpan & vendor_reserved1,
     192             :                                   const ByteSpan & vendor_reserved2, const ByteSpan & vendor_reserved3,
     193             :                                   MutableByteSpan & nocsrElements)
     194             : {
     195           1 :     TLV::TLVWriter tlvWriter;
     196           1 :     TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
     197             : 
     198           1 :     VerifyOrReturnError(!csr.empty() && !csrNonce.empty(), CHIP_ERROR_INVALID_ARGUMENT);
     199           1 :     VerifyOrReturnError(csrNonce.size() == kExpectedAttestationNonceSize, CHIP_ERROR_INVALID_ARGUMENT);
     200             : 
     201           1 :     tlvWriter.Init(nocsrElements.data(), static_cast<uint32_t>(nocsrElements.size()));
     202           1 :     outerContainerType = TLV::kTLVType_NotSpecified;
     203           1 :     ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
     204           1 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), csr));
     205           1 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), csrNonce));
     206           1 :     if (!vendor_reserved1.empty())
     207             :     {
     208           1 :         ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), vendor_reserved1));
     209             :     }
     210           1 :     if (!vendor_reserved2.empty())
     211             :     {
     212           0 :         ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(4), vendor_reserved2));
     213             :     }
     214           1 :     if (!vendor_reserved3.empty())
     215             :     {
     216           1 :         ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(5), vendor_reserved3));
     217             :     }
     218             : 
     219           1 :     ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
     220           1 :     ReturnErrorOnFailure(tlvWriter.Finalize());
     221           1 :     nocsrElements = nocsrElements.SubSpan(0, tlvWriter.GetLengthWritten());
     222             : 
     223           1 :     VerifyOrReturnError(nocsrElements.size() <= Credentials::kMaxRspLen, CHIP_ERROR_MESSAGE_TOO_LONG);
     224             : 
     225           1 :     return CHIP_NO_ERROR;
     226             : }
     227             : 
     228           3 : CHIP_ERROR DeconstructNOCSRElements(const ByteSpan & nocsrElements, ByteSpan & csr, ByteSpan & csrNonce,
     229             :                                     ByteSpan & vendor_reserved1, ByteSpan & vendor_reserved2, ByteSpan & vendor_reserved3)
     230             : {
     231           3 :     bool csrExists            = false;
     232           3 :     bool csrNonceExists       = false;
     233           3 :     bool gotFirstContextTag   = false;
     234           3 :     uint32_t lastContextTagId = 0;
     235             : 
     236           3 :     TLV::ContiguousBufferTLVReader tlvReader;
     237           3 :     TLV::TLVType containerType = TLV::kTLVType_Structure;
     238             : 
     239             :     // empty out the optional items initially
     240           3 :     vendor_reserved1 = vendor_reserved2 = vendor_reserved3 = ByteSpan();
     241             : 
     242           3 :     tlvReader.Init(nocsrElements);
     243           3 :     ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag()));
     244           3 :     ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));
     245             : 
     246             :     CHIP_ERROR error;
     247             : 
     248             :     // process context tags first (should be in sorted order)
     249          15 :     while ((error = tlvReader.Next()) == CHIP_NO_ERROR)
     250             :     {
     251          12 :         TLV::Tag tag = tlvReader.GetTag();
     252          12 :         if (!TLV::IsContextTag(tag))
     253             :         {
     254           0 :             break;
     255             :         }
     256             : 
     257             :         // Ensure tag-order and correct first expected tag
     258          12 :         uint32_t contextTagId = TLV::TagNumFromTag(tag);
     259          12 :         if (!gotFirstContextTag)
     260             :         {
     261             :             // First tag must always be CSR
     262           3 :             VerifyOrReturnError(contextTagId == kCsr, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
     263           3 :             gotFirstContextTag = true;
     264             :         }
     265             :         else
     266             :         {
     267             :             // Subsequent tags must always be in order
     268           9 :             VerifyOrReturnError(contextTagId > lastContextTagId, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
     269             :         }
     270          12 :         lastContextTagId = contextTagId;
     271             : 
     272          12 :         switch (contextTagId)
     273             :         {
     274           3 :         case kCsr:
     275           3 :             ReturnErrorOnFailure(tlvReader.GetByteView(csr));
     276           3 :             csrExists = true;
     277           3 :             break;
     278           3 :         case kCsrNonce:
     279           3 :             ReturnErrorOnFailure(tlvReader.GetByteView(csrNonce));
     280           3 :             csrNonceExists = true;
     281           3 :             break;
     282           3 :         case kVendorReserved1:
     283           3 :             ReturnErrorOnFailure(tlvReader.Get(vendor_reserved1));
     284           3 :             break;
     285           0 :         case kVendorReserved2:
     286           0 :             ReturnErrorOnFailure(tlvReader.Get(vendor_reserved2));
     287           0 :             break;
     288           3 :         case kVendorReserved3:
     289           3 :             ReturnErrorOnFailure(tlvReader.Get(vendor_reserved3));
     290           3 :             break;
     291           0 :         default:
     292             :             // unrecognized TLV element
     293           0 :             return CHIP_ERROR_INVALID_TLV_ELEMENT;
     294             :         }
     295             :     }
     296             : 
     297           3 :     VerifyOrReturnError(error == CHIP_NO_ERROR || error == CHIP_END_OF_TLV, error);
     298             : 
     299           3 :     const bool allTagsNeededPresent = csrExists && csrNonceExists;
     300           3 :     VerifyOrReturnError(allTagsNeededPresent, CHIP_ERROR_MISSING_TLV_ELEMENT);
     301             : 
     302           3 :     return CHIP_NO_ERROR;
     303             : }
     304             : 
     305             : } // namespace Credentials
     306             : 
     307             : } // namespace chip

Generated by: LCOV version 1.14