LCOV - code coverage report
Current view: top level - credentials - DeviceAttestationVendorReserved.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 31 54 57.4 %
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             : #pragma once
      18             : 
      19             : #include <lib/core/CHIPError.h>
      20             : #include <lib/core/TLV.h>
      21             : #include <lib/support/Span.h>
      22             : 
      23             : #include <cstdint>
      24             : 
      25             : namespace chip {
      26             : namespace Credentials {
      27             : 
      28             : struct VendorReservedElement
      29             : {
      30             :     uint16_t vendorId;
      31             :     uint16_t profileNum;
      32             :     uint32_t tagNum;
      33             :     ByteSpan vendorReservedData;
      34             : };
      35             : 
      36             : // extract elements out of the device attestation bytespan
      37             : class DeviceAttestationVendorReservedDeconstructor
      38             : {
      39             : 
      40             : public:
      41          85 :     DeviceAttestationVendorReservedDeconstructor() {}
      42             : 
      43             :     // Read TLV until first profile tag
      44          85 :     CHIP_ERROR PrepareToReadVendorReservedElements(const ByteSpan & attestationElements, size_t count)
      45             :     {
      46          85 :         mIsInitialized         = false;
      47          85 :         mIsDone                = false;
      48          85 :         mNumVendorReservedData = count;
      49          85 :         mAttestationData       = attestationElements;
      50             : 
      51          85 :         mTlvReader.Init(mAttestationData);
      52          85 :         ReturnErrorOnFailure(mTlvReader.Next(containerType, TLV::AnonymousTag()));
      53          85 :         ReturnErrorOnFailure(mTlvReader.EnterContainer(containerType));
      54             : 
      55             :         // position to first ProfileTag
      56             :         while (true)
      57             :         {
      58         340 :             CHIP_ERROR err = mTlvReader.Next();
      59         340 :             if (err == CHIP_END_OF_TLV)
      60             :             {
      61          84 :                 mIsDone = true;
      62          84 :                 break;
      63             :             }
      64             : 
      65         256 :             ReturnErrorOnFailure(err);
      66             : 
      67         256 :             TLV::Tag tag = mTlvReader.GetTag();
      68         256 :             if (!TLV::IsContextTag(tag))
      69           1 :                 break;
      70         255 :         }
      71             :         // positioned to first non-context tag (vendor reserved data)
      72          85 :         mIsInitialized  = true;
      73          85 :         mIsAtFirstToken = true;
      74          85 :         return CHIP_NO_ERROR;
      75             :     }
      76             : 
      77             :     size_t GetNumberOfElements() const { return mNumVendorReservedData; }
      78             : 
      79             :     /**
      80             :      *  @brief Return next VendorReserved element. PrepareToReadVendorReservedElements must be called first.
      81             :      *
      82             :      *  @param[out] element  Next vendor Reserved element
      83             :      *
      84             :      *  @returns   CHIP_NO_ERROR on success
      85             :      *             CHIP_ERROR_INCORRECT_STATE if PrepareToReadVendorReservedElements hasn't been called first
      86             :      *             CHIP_ERROR_UNEXPECTED_TLV_ELEMENT if we reach non-profile-specific tags or vendorId is zero
      87             :      *             CHIP_END_OF_TLV if not further entries are present
      88             :      */
      89             :     CHIP_ERROR GetNextVendorReservedElement(struct VendorReservedElement & element)
      90             :     {
      91             :         VerifyOrReturnError(mIsInitialized, CHIP_ERROR_UNINITIALIZED);
      92             :         if (mIsDone)
      93             :         {
      94             :             return CHIP_END_OF_TLV;
      95             :         }
      96             : 
      97             :         if (mIsAtFirstToken)
      98             :         {
      99             :             // Already had a Next() done for us by PrepareToReadVendorReservedElements
     100             :             // so we don't Next() since we should be pointing at a vendor-reserved.
     101             :             mIsAtFirstToken = false;
     102             :         }
     103             :         else
     104             :         {
     105             :             CHIP_ERROR error = mTlvReader.Next();
     106             :             if (error == CHIP_END_OF_TLV)
     107             :             {
     108             :                 mIsDone = true;
     109             :             }
     110             :             ReturnErrorOnFailure(error);
     111             :         }
     112             : 
     113             :         TLV::Tag tag = mTlvReader.GetTag();
     114             :         if (!TLV::IsProfileTag(tag))
     115             :         {
     116             :             return CHIP_ERROR_UNEXPECTED_TLV_ELEMENT;
     117             :         }
     118             : 
     119             :         // tag is profile tag
     120             :         element.vendorId   = TLV::VendorIdFromTag(tag);
     121             :         element.profileNum = TLV::ProfileNumFromTag(tag);
     122             :         element.tagNum     = TLV::TagNumFromTag(tag);
     123             : 
     124             :         ReturnErrorOnFailure(mTlvReader.GetByteView(element.vendorReservedData));
     125             : 
     126             :         return CHIP_NO_ERROR;
     127             :     }
     128             : 
     129             : private:
     130             :     size_t mNumVendorReservedData; // number of VendorReserved entries (could be 0)
     131             :     ByteSpan mAttestationData;
     132             :     bool mIsInitialized  = false;
     133             :     bool mIsAtFirstToken = false;
     134             :     bool mIsDone         = false;
     135             :     TLV::ContiguousBufferTLVReader mTlvReader;
     136             :     TLV::TLVType containerType = TLV::kTLVType_Structure;
     137             : };
     138             : 
     139             : class DeviceAttestationVendorReservedConstructor
     140             : {
     141             : public:
     142             :     DeviceAttestationVendorReservedConstructor(struct VendorReservedElement * array, size_t size) : mElements(array), mMaxSize(size)
     143             :     {}
     144             : 
     145             :     typedef const struct VendorReservedElement * const_iterator;
     146             : 
     147         148 :     const_iterator Next()
     148             :     {
     149         148 :         VerifyOrReturnError(mCurrentIndex < mNumEntriesUsed, nullptr);
     150           0 :         return &mElements[mCurrentIndex++];
     151             :     }
     152             : 
     153         148 :     const_iterator cbegin()
     154             :     {
     155             :         // sort the array in place and return the head element.
     156         148 :         do_sorting();
     157         148 :         mCurrentIndex = 0;
     158         148 :         return mElements;
     159             :     }
     160             : 
     161             :     CHIP_ERROR addVendorReservedElement(uint16_t vendorId, uint16_t profileNum, uint32_t tagNum, ByteSpan span)
     162             :     {
     163             :         if (mNumEntriesUsed == mMaxSize)
     164             :             return CHIP_ERROR_NO_MEMORY;
     165             : 
     166             :         mElements[mNumEntriesUsed].tagNum             = tagNum;
     167             :         mElements[mNumEntriesUsed].profileNum         = profileNum;
     168             :         mElements[mNumEntriesUsed].vendorId           = vendorId;
     169             :         mElements[mNumEntriesUsed].vendorReservedData = span;
     170             :         mNumEntriesUsed++;
     171             :         return CHIP_NO_ERROR;
     172             :     }
     173             : 
     174             :     size_t GetNumberOfElements() const { return mNumEntriesUsed; }
     175             : 
     176             : private:
     177             :     /*
     178             :      * Sort according to A.2.4 in the spec.
     179             :      * Mark all sorted entries by setting used flag.
     180             :      * Order is head to tail, sorted by next
     181             :      * Executed when entries are about to be read
     182             :      */
     183         148 :     void do_sorting()
     184             :     {
     185         148 :         size_t starting = 0;
     186             : 
     187         148 :         while (starting < mNumEntriesUsed)
     188             :         {
     189           0 :             uint32_t minVendor = UINT32_MAX;
     190             : 
     191             :             // find lowest vendorId
     192             :             size_t i;
     193           0 :             for (i = starting; i < mNumEntriesUsed; i++)
     194             :             {
     195           0 :                 if (mElements[i].vendorId < minVendor)
     196             :                 {
     197           0 :                     minVendor = mElements[i].vendorId;
     198             :                 }
     199             :             }
     200             : 
     201           0 :             uint32_t minProfile = UINT32_MAX;
     202             :             // find lowest ProfileNum
     203           0 :             for (i = starting; i < mNumEntriesUsed; i++)
     204             :             {
     205           0 :                 if (mElements[i].vendorId == minVendor)
     206             :                 {
     207           0 :                     if (mElements[i].profileNum < minProfile)
     208           0 :                         minProfile = mElements[i].profileNum;
     209             :                 }
     210             :             }
     211             : 
     212             :             // first lowest tagNum for this vendorId/profileNum
     213           0 :             uint64_t minTagNum = UINT64_MAX;
     214           0 :             size_t lowestIndex = SIZE_MAX;
     215           0 :             for (i = starting; i < mNumEntriesUsed; i++)
     216             :             {
     217           0 :                 if (mElements[i].vendorId == minVendor && mElements[i].profileNum == minProfile)
     218             :                 {
     219           0 :                     if (mElements[i].tagNum < minTagNum)
     220             :                     {
     221           0 :                         minTagNum   = mElements[i].tagNum;
     222           0 :                         lowestIndex = i;
     223             :                     }
     224             :                 }
     225             :             }
     226             : 
     227             :             // lowestIndex is the element to move into elements[starting].
     228           0 :             if (lowestIndex != starting)
     229             :             {
     230             :                 //
     231           0 :                 VendorReservedElement tmpElement;
     232             : 
     233           0 :                 tmpElement             = mElements[starting];
     234           0 :                 mElements[starting]    = mElements[lowestIndex];
     235           0 :                 mElements[lowestIndex] = tmpElement;
     236             :             }
     237           0 :             starting++;
     238             :         }
     239         148 :     }
     240             : 
     241             :     VendorReservedElement * mElements;
     242             :     size_t mMaxSize;            // size of elements array
     243             :     size_t mNumEntriesUsed = 0; // elements used
     244             :     size_t mCurrentIndex;       // iterating from [0...maxSize -1]
     245             : };
     246             : 
     247             : } // namespace Credentials
     248             : } // namespace chip

Generated by: LCOV version 1.14