LCOV - code coverage report
Current view: top level - lib/core - OTAImageHeader.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 72 72 100.0 %
Date: 2024-02-15 08:20:41 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2022 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 <lib/core/OTAImageHeader.h>
      18             : 
      19             : #include <lib/core/CHIPError.h>
      20             : #include <lib/core/Optional.h>
      21             : #include <lib/core/TLVReader.h>
      22             : #include <lib/core/TLVTags.h>
      23             : #include <lib/core/TLVTypes.h>
      24             : #include <lib/support/BufferReader.h>
      25             : #include <lib/support/CodeUtils.h>
      26             : #include <lib/support/ScopedBuffer.h>
      27             : #include <lib/support/Span.h>
      28             : 
      29             : #include <string.h>
      30             : 
      31             : namespace chip {
      32             : 
      33             : namespace {
      34             : 
      35             : enum class Tag : uint8_t
      36             : {
      37             :     kVendorId              = 0,
      38             :     kProductId             = 1,
      39             :     kSoftwareVersion       = 2,
      40             :     kSoftwareVersionString = 3,
      41             :     kPayloadSize           = 4,
      42             :     kMinApplicableVersion  = 5,
      43             :     kMaxApplicableVersion  = 6,
      44             :     kReleaseNotesURL       = 7,
      45             :     kImageDigestType       = 8,
      46             :     kImageDigest           = 9,
      47             : };
      48             : 
      49             : /// Length of the fixed portion of the Matter OTA image header: FileIdentifier (4B), TotalSize (8B) and HeaderSize (4B)
      50             : constexpr uint32_t kFixedHeaderSize = 16;
      51             : 
      52             : /// Maximum supported Matter OTA image header size
      53             : constexpr uint32_t kMaxHeaderSize = 1024;
      54             : 
      55             : /// Maximum size of the software version string
      56             : constexpr size_t kMaxSoftwareVersionStringSize = 64;
      57             : 
      58             : /// Maximum size of the release notes URL
      59             : constexpr size_t kMaxReleaseNotesURLSize = 256;
      60             : 
      61             : } // namespace
      62             : 
      63           9 : void OTAImageHeaderParser::Init()
      64             : {
      65           9 :     mState         = State::kInitialized;
      66           9 :     mBufferOffset  = 0;
      67           9 :     mHeaderTlvSize = 0;
      68           9 :     mBuffer.Alloc(kFixedHeaderSize);
      69           9 : }
      70             : 
      71           2 : void OTAImageHeaderParser::Clear()
      72             : {
      73           2 :     mState         = State::kNotInitialized;
      74           2 :     mBufferOffset  = 0;
      75           2 :     mHeaderTlvSize = 0;
      76           2 :     mBuffer.Free();
      77           2 : }
      78             : 
      79         112 : CHIP_ERROR OTAImageHeaderParser::AccumulateAndDecode(ByteSpan & buffer, OTAImageHeader & header)
      80             : {
      81         112 :     CHIP_ERROR error = CHIP_NO_ERROR;
      82             : 
      83         112 :     if (mState == State::kInitialized)
      84             :     {
      85          24 :         Append(buffer, kFixedHeaderSize - mBufferOffset);
      86          24 :         error = DecodeFixed();
      87             :     }
      88             : 
      89         112 :     if (mState == State::kTlv)
      90             :     {
      91          95 :         Append(buffer, mHeaderTlvSize - mBufferOffset);
      92          95 :         error = DecodeTlv(header);
      93             :     }
      94             : 
      95         112 :     if (error != CHIP_NO_ERROR && error != CHIP_ERROR_BUFFER_TOO_SMALL)
      96             :     {
      97           2 :         Clear();
      98             :     }
      99             : 
     100         112 :     return error;
     101             : }
     102             : 
     103         119 : void OTAImageHeaderParser::Append(ByteSpan & buffer, uint32_t numBytes)
     104             : {
     105         119 :     numBytes = chip::min(numBytes, static_cast<uint32_t>(buffer.size()));
     106         119 :     memcpy(&mBuffer[mBufferOffset], buffer.data(), numBytes);
     107         119 :     mBufferOffset += numBytes;
     108         119 :     buffer = buffer.SubSpan(numBytes);
     109         119 : }
     110             : 
     111          24 : CHIP_ERROR OTAImageHeaderParser::DecodeFixed()
     112             : {
     113          24 :     ReturnErrorCodeIf(mBufferOffset < kFixedHeaderSize, CHIP_ERROR_BUFFER_TOO_SMALL);
     114             : 
     115           8 :     Encoding::LittleEndian::Reader reader(mBuffer.Get(), mBufferOffset);
     116             :     uint32_t fileIdentifier;
     117             :     uint64_t totalSize;
     118           8 :     ReturnErrorOnFailure(reader.Read32(&fileIdentifier).Read64(&totalSize).Read32(&mHeaderTlvSize).StatusCode());
     119           8 :     ReturnErrorCodeIf(fileIdentifier != kOTAImageFileIdentifier, CHIP_ERROR_INVALID_FILE_IDENTIFIER);
     120             :     // Safety check against malicious headers.
     121           7 :     ReturnErrorCodeIf(mHeaderTlvSize > kMaxHeaderSize, CHIP_ERROR_NO_MEMORY);
     122           7 :     ReturnErrorCodeIf(!mBuffer.Alloc(mHeaderTlvSize), CHIP_ERROR_NO_MEMORY);
     123             : 
     124           7 :     mState        = State::kTlv;
     125           7 :     mBufferOffset = 0;
     126             : 
     127           7 :     return CHIP_NO_ERROR;
     128             : }
     129             : 
     130          95 : CHIP_ERROR OTAImageHeaderParser::DecodeTlv(OTAImageHeader & header)
     131             : {
     132          95 :     ReturnErrorCodeIf(mBufferOffset < mHeaderTlvSize, CHIP_ERROR_BUFFER_TOO_SMALL);
     133             : 
     134             :     TLV::TLVReader tlvReader;
     135           6 :     tlvReader.Init(mBuffer.Get(), mBufferOffset);
     136           6 :     ReturnErrorOnFailure(tlvReader.Next(TLV::TLVType::kTLVType_Structure, TLV::AnonymousTag()));
     137             : 
     138             :     TLV::TLVType outerType;
     139           6 :     ReturnErrorOnFailure(tlvReader.EnterContainer(outerType));
     140             : 
     141           6 :     ReturnErrorOnFailure(tlvReader.Next(TLV::ContextTag(Tag::kVendorId)));
     142           5 :     ReturnErrorOnFailure(tlvReader.Get(header.mVendorId));
     143           5 :     ReturnErrorOnFailure(tlvReader.Next(TLV::ContextTag(Tag::kProductId)));
     144           5 :     ReturnErrorOnFailure(tlvReader.Get(header.mProductId));
     145           5 :     ReturnErrorOnFailure(tlvReader.Next(TLV::ContextTag(Tag::kSoftwareVersion)));
     146           5 :     ReturnErrorOnFailure(tlvReader.Get(header.mSoftwareVersion));
     147           5 :     ReturnErrorOnFailure(tlvReader.Next(TLV::ContextTag(Tag::kSoftwareVersionString)));
     148           5 :     ReturnErrorOnFailure(tlvReader.Get(header.mSoftwareVersionString));
     149           5 :     ReturnErrorCodeIf(header.mSoftwareVersionString.size() > kMaxSoftwareVersionStringSize, CHIP_ERROR_INVALID_STRING_LENGTH);
     150           5 :     ReturnErrorOnFailure(tlvReader.Next(TLV::ContextTag(Tag::kPayloadSize)));
     151           5 :     ReturnErrorOnFailure(tlvReader.Get(header.mPayloadSize));
     152           5 :     ReturnErrorOnFailure(tlvReader.Next());
     153             : 
     154           5 :     if (tlvReader.GetTag() == TLV::ContextTag(Tag::kMinApplicableVersion))
     155             :     {
     156           4 :         ReturnErrorOnFailure(tlvReader.Get(header.mMinApplicableVersion.Emplace()));
     157           4 :         ReturnErrorOnFailure(tlvReader.Next());
     158             :     }
     159             : 
     160           5 :     if (tlvReader.GetTag() == TLV::ContextTag(Tag::kMaxApplicableVersion))
     161             :     {
     162           4 :         ReturnErrorOnFailure(tlvReader.Get(header.mMaxApplicableVersion.Emplace()));
     163           4 :         ReturnErrorOnFailure(tlvReader.Next());
     164             :     }
     165             : 
     166           5 :     if (tlvReader.GetTag() == TLV::ContextTag(Tag::kReleaseNotesURL))
     167             :     {
     168           4 :         ReturnErrorOnFailure(tlvReader.Get(header.mReleaseNotesURL));
     169           4 :         ReturnErrorCodeIf(header.mReleaseNotesURL.size() > kMaxReleaseNotesURLSize, CHIP_ERROR_INVALID_STRING_LENGTH);
     170           4 :         ReturnErrorOnFailure(tlvReader.Next());
     171             :     }
     172             : 
     173           5 :     ReturnErrorOnFailure(tlvReader.Expect(TLV::ContextTag(Tag::kImageDigestType)));
     174           5 :     ReturnErrorOnFailure(tlvReader.Get(header.mImageDigestType));
     175           5 :     ReturnErrorOnFailure(tlvReader.Next(TLV::ContextTag(Tag::kImageDigest)));
     176           5 :     ReturnErrorOnFailure(tlvReader.Get(header.mImageDigest));
     177             : 
     178           5 :     ReturnErrorOnFailure(tlvReader.ExitContainer(outerType));
     179             : 
     180           5 :     return CHIP_NO_ERROR;
     181             : }
     182             : 
     183             : } // namespace chip

Generated by: LCOV version 1.14