LCOV - code coverage report
Current view: top level - transport/raw - MessageHeader.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 164 166 98.8 %
Date: 2024-02-15 08:20:41 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2020-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             : 
      18             : /**
      19             :  * @file
      20             :  *   This file contains the implementation the chip message header
      21             :  *   encode/decode classes.
      22             :  */
      23             : 
      24             : #include "MessageHeader.h"
      25             : 
      26             : #include <assert.h>
      27             : #include <limits.h>
      28             : #include <stdint.h>
      29             : 
      30             : #include <type_traits>
      31             : 
      32             : #include <lib/core/CHIPError.h>
      33             : #include <lib/support/BufferReader.h>
      34             : #include <lib/support/CodeUtils.h>
      35             : 
      36             : /**********************************************
      37             :  * Header format (little endian):
      38             :  *
      39             :  * -------- Unencrypted header -----------------------------------------------------
      40             :  *  8 bit:  | Message Flags: VERSION: 4 bit | S: 1 bit | RESERVED: 1 bit | DSIZ: 2 bit |
      41             :  *  8 bit:  | Security Flags: P: 1 bit | C: 1 bit | MX: 1 bit | RESERVED: 3 bit | Session Type: 2 bit |
      42             :  *  16 bit: | Session ID                                                           |
      43             :  *  32 bit: | Message Counter                                                      |
      44             :  *  64 bit: | SOURCE_NODE_ID (iff source node flag is set)                         |
      45             :  *  64 bit: | DEST_NODE_ID (iff destination node flag is set)                      |
      46             :  * -------- Encrypted header -------------------------------------------------------
      47             :  *  8 bit:  | Exchange Flags: RESERVED: 3 bit | V: 1 bit | SX: 1 bit | R: 1 bit | A: 1 bit | I: 1 bit |
      48             :  *  8 bit:  | Protocol Opcode                                                      |
      49             :  * 16 bit:  | Exchange ID                                                          |
      50             :  * 16 bit:  | Protocol ID                                                          |
      51             :  * 16 bit:  | Optional Vendor ID                                                   |
      52             :  * 32 bit:  | Acknowledged Message Counter (if A flag in the Header is set)        |
      53             :  * -------- Encrypted Application Data Start ---------------------------------------
      54             :  *  <var>:  | Encrypted Data                                                       |
      55             :  * -------- Encrypted Application Data End -----------------------------------------
      56             :  *  <var>:  | (Unencrypted) Message Authentication Tag                             |
      57             :  *
      58             :  **********************************************/
      59             : 
      60             : namespace chip {
      61             : namespace {
      62             : 
      63             : using namespace chip::Encoding;
      64             : 
      65             : /// size of the fixed portion of the header
      66             : constexpr size_t kFixedUnencryptedHeaderSizeBytes = 8;
      67             : 
      68             : /// size of the encrypted portion of the header
      69             : constexpr size_t kEncryptedHeaderSizeBytes = 6;
      70             : 
      71             : /// size of a serialized node id inside a header
      72             : constexpr size_t kNodeIdSizeBytes = 8;
      73             : 
      74             : /// size of a serialized group id inside a header
      75             : constexpr size_t kGroupIdSizeBytes = 2;
      76             : 
      77             : /// size of a serialized vendor id inside a header
      78             : constexpr size_t kVendorIdSizeBytes = 2;
      79             : 
      80             : /// size of a serialized ack message counter inside a header
      81             : constexpr size_t kAckMessageCounterSizeBytes = 4;
      82             : 
      83             : /// Mask to extract just the version part from a 8bits header prefix.
      84             : constexpr uint8_t kVersionMask = 0xF0;
      85             : 
      86             : constexpr uint8_t kMsgFlagsMask = 0x07;
      87             : /// Shift to convert to/from a masked version 8bit value to a 4bit version.
      88             : constexpr int kVersionShift = 4;
      89             : 
      90             : } // namespace
      91             : 
      92       85548 : uint16_t PacketHeader::EncodeSizeBytes() const
      93             : {
      94       85548 :     size_t size = kFixedUnencryptedHeaderSizeBytes;
      95             : 
      96       85548 :     if (mSourceNodeId.HasValue())
      97             :     {
      98         286 :         size += kNodeIdSizeBytes;
      99             :     }
     100             : 
     101       85548 :     if (mDestinationNodeId.HasValue())
     102             :     {
     103         187 :         size += kNodeIdSizeBytes;
     104             :     }
     105       85361 :     else if (mDestinationGroupId.HasValue())
     106             :     {
     107          37 :         size += kGroupIdSizeBytes;
     108             :     }
     109             : 
     110             :     static_assert(kFixedUnencryptedHeaderSizeBytes + kNodeIdSizeBytes + kNodeIdSizeBytes <= UINT16_MAX,
     111             :                   "Header size does not fit in uint16_t");
     112       85548 :     return static_cast<uint16_t>(size);
     113             : }
     114             : 
     115       28768 : uint16_t PayloadHeader::EncodeSizeBytes() const
     116             : {
     117       28768 :     size_t size = kEncryptedHeaderSizeBytes;
     118             : 
     119       28768 :     if (HaveVendorId())
     120             :     {
     121          68 :         size += kVendorIdSizeBytes;
     122             :     }
     123             : 
     124       28768 :     if (mAckMessageCounter.HasValue())
     125             :     {
     126       23631 :         size += kAckMessageCounterSizeBytes;
     127             :     }
     128             : 
     129             :     static_assert(kEncryptedHeaderSizeBytes + kVendorIdSizeBytes + kAckMessageCounterSizeBytes <= UINT16_MAX,
     130             :                   "Header size does not fit in uint16_t");
     131       28768 :     return static_cast<uint16_t>(size);
     132             : }
     133             : 
     134       27005 : CHIP_ERROR PacketHeader::DecodeFixedCommon(Encoding::LittleEndian::Reader & reader)
     135             : {
     136       27005 :     CHIP_ERROR err = CHIP_NO_ERROR;
     137             :     int version;
     138             : 
     139             :     uint8_t msgFlags;
     140       27005 :     SuccessOrExit(err = reader.Read8(&msgFlags).StatusCode());
     141       27000 :     version = ((msgFlags & kVersionMask) >> kVersionShift);
     142       27000 :     VerifyOrExit(version == kMsgHeaderVersion, err = CHIP_ERROR_VERSION_MISMATCH);
     143       27000 :     SetMessageFlags(msgFlags);
     144             : 
     145       27000 :     SuccessOrExit(err = reader.Read16(&mSessionId).StatusCode());
     146             : 
     147             :     uint8_t securityFlags;
     148       26990 :     SuccessOrExit(err = reader.Read8(&securityFlags).StatusCode());
     149       26985 :     SetSecurityFlags(securityFlags);
     150             : 
     151       27005 : exit:
     152             : 
     153       27005 :     return err;
     154             : }
     155             : 
     156        9507 : CHIP_ERROR PacketHeader::DecodeFixed(const System::PacketBufferHandle & buf)
     157             : {
     158        9507 :     const uint8_t * const data = buf->Start();
     159        9507 :     uint16_t size              = buf->DataLength();
     160        9507 :     LittleEndian::Reader reader(data, size);
     161        9507 :     return DecodeFixedCommon(reader);
     162             : }
     163             : 
     164       17498 : CHIP_ERROR PacketHeader::Decode(const uint8_t * const data, uint16_t size, uint16_t * decode_len)
     165             : {
     166       17498 :     CHIP_ERROR err = CHIP_NO_ERROR;
     167       17498 :     LittleEndian::Reader reader(data, size);
     168             :     // TODO: De-uint16-ify everything related to this library
     169             :     uint16_t octets_read;
     170             : 
     171       17498 :     SuccessOrExit(err = DecodeFixedCommon(reader));
     172             : 
     173       17478 :     SuccessOrExit(err = reader.Read32(&mMessageCounter).StatusCode());
     174             : 
     175       17458 :     if (mMsgFlags.Has(Header::MsgFlagValues::kSourceNodeIdPresent))
     176             :     {
     177             :         uint64_t sourceNodeId;
     178         166 :         SuccessOrExit(err = reader.Read64(&sourceNodeId).StatusCode());
     179         142 :         mSourceNodeId.SetValue(sourceNodeId);
     180             :     }
     181             :     else
     182             :     {
     183       17292 :         mSourceNodeId.ClearValue();
     184             :     }
     185             : 
     186       17434 :     if (!IsSessionTypeValid())
     187             :     {
     188             :         // Reserved.
     189           0 :         SuccessOrExit(err = CHIP_ERROR_INTERNAL);
     190             :     }
     191             : 
     192       17434 :     if (mMsgFlags.HasAll(Header::MsgFlagValues::kDestinationNodeIdPresent, Header::MsgFlagValues::kDestinationGroupIdPresent))
     193             :     {
     194             :         // Reserved.
     195           0 :         SuccessOrExit(err = CHIP_ERROR_INTERNAL);
     196             :     }
     197       17434 :     else if (mMsgFlags.Has(Header::MsgFlagValues::kDestinationNodeIdPresent))
     198             :     {
     199             :         // No need to check if session is Unicast because for MCSP
     200             :         // a destination node ID is present with a group session ID.
     201             :         // Spec 4.9.2.4
     202             :         uint64_t destinationNodeId;
     203         104 :         SuccessOrExit(err = reader.Read64(&destinationNodeId).StatusCode());
     204          96 :         mDestinationNodeId.SetValue(destinationNodeId);
     205          96 :         mDestinationGroupId.ClearValue();
     206             :     }
     207       17330 :     else if (mMsgFlags.Has(Header::MsgFlagValues::kDestinationGroupIdPresent))
     208             :     {
     209          15 :         if (mSessionType != Header::SessionType::kGroupSession)
     210             :         {
     211           2 :             SuccessOrExit(err = CHIP_ERROR_INTERNAL);
     212             :         }
     213             :         uint16_t destinationGroupId;
     214          15 :         SuccessOrExit(err = reader.Read16(&destinationGroupId).StatusCode());
     215          13 :         mDestinationGroupId.SetValue(destinationGroupId);
     216          13 :         mDestinationNodeId.ClearValue();
     217             :     }
     218             :     else
     219             :     {
     220       17315 :         mDestinationNodeId.ClearValue();
     221       17315 :         mDestinationGroupId.ClearValue();
     222             :     }
     223             : 
     224       17424 :     if (mSecFlags.Has(Header::SecFlagValues::kMsgExtensionFlag))
     225             :     {
     226             :         // If present, skip over Message Extension block.
     227             :         // Spec 4.4.1.8. Message Extensions (variable)
     228             :         uint16_t mxLength;
     229           8 :         SuccessOrExit(err = reader.Read16(&mxLength).StatusCode());
     230           8 :         VerifyOrExit(mxLength <= reader.Remaining(), err = CHIP_ERROR_INTERNAL);
     231           8 :         reader.Skip(mxLength);
     232             :     }
     233             : 
     234       17424 :     octets_read = static_cast<uint16_t>(reader.OctetsRead());
     235       17424 :     *decode_len = octets_read;
     236             : 
     237       17498 : exit:
     238             : 
     239       17498 :     return err;
     240             : }
     241             : 
     242        9522 : CHIP_ERROR PacketHeader::DecodeAndConsume(const System::PacketBufferHandle & buf)
     243             : {
     244        9522 :     uint16_t headerSize = 0;
     245        9522 :     ReturnErrorOnFailure(Decode(buf->Start(), buf->DataLength(), &headerSize));
     246        9522 :     buf->ConsumeHead(headerSize);
     247        9522 :     return CHIP_NO_ERROR;
     248             : }
     249             : 
     250        9512 : CHIP_ERROR PayloadHeader::Decode(const uint8_t * const data, uint16_t size, uint16_t * decode_len)
     251             : {
     252        9512 :     CHIP_ERROR err = CHIP_NO_ERROR;
     253        9512 :     LittleEndian::Reader reader(data, size);
     254             :     uint8_t header;
     255             :     uint16_t octets_read;
     256             : 
     257        9512 :     SuccessOrExit(err = reader.Read8(&header).Read8(&mMessageType).Read16(&mExchangeID).StatusCode());
     258             : 
     259        9508 :     mExchangeFlags.SetRaw(header);
     260             : 
     261             :     VendorId vendor_id;
     262        9508 :     if (HaveVendorId())
     263             :     {
     264             :         uint16_t vendor_id_raw;
     265          22 :         SuccessOrExit(err = reader.Read16(&vendor_id_raw).StatusCode());
     266          22 :         vendor_id = static_cast<VendorId>(vendor_id_raw);
     267             :     }
     268             :     else
     269             :     {
     270        9486 :         vendor_id = VendorId::Common;
     271             :     }
     272             : 
     273             :     uint16_t protocol_id;
     274        9508 :     SuccessOrExit(err = reader.Read16(&protocol_id).StatusCode());
     275             : 
     276        9506 :     mProtocolID = Protocols::Id(vendor_id, protocol_id);
     277             : 
     278        9506 :     if (mExchangeFlags.Has(Header::ExFlagValues::kExchangeFlag_AckMsg))
     279             :     {
     280             :         uint32_t ack_message_counter;
     281        7836 :         SuccessOrExit(err = reader.Read32(&ack_message_counter).StatusCode());
     282        7836 :         mAckMessageCounter.SetValue(ack_message_counter);
     283             :     }
     284             :     else
     285             :     {
     286        1670 :         mAckMessageCounter.ClearValue();
     287             :     }
     288             : 
     289        9506 :     if (mExchangeFlags.Has(Header::ExFlagValues::kExchangeFlag_SecuredExtension))
     290             :     {
     291             :         // If present, skip over Secured Extension block.
     292             :         // Spec 4.4.3.7. Secured Extensions (variable)
     293             :         uint16_t sxLength;
     294           3 :         SuccessOrExit(err = reader.Read16(&sxLength).StatusCode());
     295           3 :         VerifyOrExit(sxLength <= reader.Remaining(), err = CHIP_ERROR_INTERNAL);
     296           3 :         reader.Skip(sxLength);
     297             :     }
     298             : 
     299        9506 :     octets_read = static_cast<uint16_t>(reader.OctetsRead());
     300        9506 :     *decode_len = octets_read;
     301             : 
     302        9512 : exit:
     303             : 
     304        9512 :     return err;
     305             : }
     306             : 
     307        9493 : CHIP_ERROR PayloadHeader::DecodeAndConsume(const System::PacketBufferHandle & buf)
     308             : {
     309        9493 :     uint16_t headerSize = 0;
     310        9493 :     ReturnErrorOnFailure(Decode(buf->Start(), buf->DataLength(), &headerSize));
     311        9493 :     buf->ConsumeHead(headerSize);
     312        9493 :     return CHIP_NO_ERROR;
     313             : }
     314             : 
     315       28550 : CHIP_ERROR PacketHeader::Encode(uint8_t * data, uint16_t size, uint16_t * encode_size) const
     316             : {
     317       28550 :     VerifyOrReturnError(size >= EncodeSizeBytes(), CHIP_ERROR_INVALID_ARGUMENT);
     318       28508 :     VerifyOrReturnError(!(mDestinationNodeId.HasValue() && mDestinationGroupId.HasValue()), CHIP_ERROR_INTERNAL);
     319       28507 :     VerifyOrReturnError(encode_size != nullptr, CHIP_ERROR_INTERNAL);
     320       28507 :     VerifyOrReturnError(IsSessionTypeValid(), CHIP_ERROR_INTERNAL);
     321             : 
     322       28507 :     Header::MsgFlags messageFlags = mMsgFlags;
     323       28507 :     messageFlags.Set(Header::MsgFlagValues::kSourceNodeIdPresent, mSourceNodeId.HasValue())
     324       28507 :         .Set(Header::MsgFlagValues::kDestinationNodeIdPresent, mDestinationNodeId.HasValue())
     325       28507 :         .Set(Header::MsgFlagValues::kDestinationGroupIdPresent, mDestinationGroupId.HasValue());
     326             : 
     327       28507 :     uint8_t msgFlags = (kMsgHeaderVersion << kVersionShift) | (messageFlags.Raw() & kMsgFlagsMask);
     328             : 
     329       28507 :     uint8_t * p = data;
     330       28507 :     Write8(p, msgFlags);
     331       28507 :     LittleEndian::Write16(p, mSessionId);
     332       28507 :     Write8(p, mSecFlags.Raw());
     333       28507 :     LittleEndian::Write32(p, mMessageCounter);
     334       28507 :     if (mSourceNodeId.HasValue())
     335             :     {
     336          87 :         LittleEndian::Write64(p, mSourceNodeId.Value());
     337             :     }
     338       28507 :     if (mDestinationNodeId.HasValue())
     339             :     {
     340          59 :         LittleEndian::Write64(p, mDestinationNodeId.Value());
     341             :     }
     342       28448 :     else if (mDestinationGroupId.HasValue())
     343             :     {
     344          10 :         LittleEndian::Write16(p, mDestinationGroupId.Value());
     345             :     }
     346             : 
     347             :     // Written data size provided to caller on success
     348       28507 :     VerifyOrReturnError(p - data == EncodeSizeBytes(), CHIP_ERROR_INTERNAL);
     349       28507 :     *encode_size = static_cast<uint16_t>(p - data);
     350             : 
     351       28507 :     return CHIP_NO_ERROR;
     352             : }
     353             : 
     354        9593 : CHIP_ERROR PacketHeader::EncodeBeforeData(const System::PacketBufferHandle & buf) const
     355             : {
     356             :     // Note: PayloadHeader::EncodeBeforeData probably needs changes if you
     357             :     // change anything here.
     358        9593 :     uint16_t headerSize = EncodeSizeBytes();
     359        9593 :     VerifyOrReturnError(buf->EnsureReservedSize(headerSize), CHIP_ERROR_NO_MEMORY);
     360        9593 :     buf->SetStart(buf->Start() - headerSize);
     361             :     uint16_t actualEncodedHeaderSize;
     362        9593 :     ReturnErrorOnFailure(EncodeAtStart(buf, &actualEncodedHeaderSize));
     363        9593 :     VerifyOrReturnError(actualEncodedHeaderSize == headerSize, CHIP_ERROR_INTERNAL);
     364        9593 :     return CHIP_NO_ERROR;
     365             : }
     366             : 
     367        9594 : CHIP_ERROR PayloadHeader::Encode(uint8_t * data, uint16_t size, uint16_t * encode_size) const
     368             : {
     369        9594 :     VerifyOrReturnError(size >= EncodeSizeBytes(), CHIP_ERROR_INVALID_ARGUMENT);
     370             : 
     371        9588 :     uint8_t * p          = data;
     372        9588 :     const uint8_t header = mExchangeFlags.Raw();
     373             : 
     374        9588 :     Write8(p, header);
     375        9588 :     Write8(p, mMessageType);
     376        9588 :     LittleEndian::Write16(p, mExchangeID);
     377        9588 :     if (HaveVendorId())
     378             :     {
     379          21 :         LittleEndian::Write16(p, to_underlying(mProtocolID.GetVendorId()));
     380             :     }
     381        9588 :     LittleEndian::Write16(p, mProtocolID.GetProtocolId());
     382        9588 :     if (mAckMessageCounter.HasValue())
     383             :     {
     384        7877 :         LittleEndian::Write32(p, mAckMessageCounter.Value());
     385             :     }
     386             : 
     387             :     // Written data size provided to caller on success
     388        9588 :     VerifyOrReturnError(p - data == EncodeSizeBytes(), CHIP_ERROR_INTERNAL);
     389        9588 :     *encode_size = static_cast<uint16_t>(p - data);
     390             : 
     391        9588 :     return CHIP_NO_ERROR;
     392             : }
     393             : 
     394        9586 : CHIP_ERROR PayloadHeader::EncodeBeforeData(const System::PacketBufferHandle & buf) const
     395             : {
     396             :     // Note: PacketHeader::EncodeBeforeData probably needs changes if you change
     397             :     // anything here.
     398        9586 :     uint16_t headerSize = EncodeSizeBytes();
     399        9586 :     VerifyOrReturnError(buf->EnsureReservedSize(headerSize), CHIP_ERROR_NO_MEMORY);
     400        9586 :     buf->SetStart(buf->Start() - headerSize);
     401             :     uint16_t actualEncodedHeaderSize;
     402        9586 :     ReturnErrorOnFailure(EncodeAtStart(buf, &actualEncodedHeaderSize));
     403        9586 :     VerifyOrReturnError(actualEncodedHeaderSize == headerSize, CHIP_ERROR_INTERNAL);
     404        9586 :     return CHIP_NO_ERROR;
     405             : }
     406             : 
     407        9405 : CHIP_ERROR MessageAuthenticationCode::Decode(const PacketHeader & packetHeader, const uint8_t * const data, uint16_t size,
     408             :                                              uint16_t * decode_len)
     409             : {
     410        9405 :     const uint16_t taglen = packetHeader.MICTagLength();
     411             : 
     412        9405 :     VerifyOrReturnError(taglen != 0, CHIP_ERROR_WRONG_ENCRYPTION_TYPE_FROM_PEER);
     413        9405 :     VerifyOrReturnError(size >= taglen, CHIP_ERROR_INVALID_ARGUMENT);
     414             : 
     415        9405 :     memcpy(&mTag[0], data, taglen);
     416             : 
     417        9405 :     *decode_len = taglen;
     418             : 
     419        9405 :     return CHIP_NO_ERROR;
     420             : }
     421             : 
     422        9487 : CHIP_ERROR MessageAuthenticationCode::Encode(const PacketHeader & packetHeader, uint8_t * data, uint16_t size,
     423             :                                              uint16_t * encode_size) const
     424             : {
     425        9487 :     uint8_t * p           = data;
     426        9487 :     const uint16_t taglen = packetHeader.MICTagLength();
     427             : 
     428        9487 :     VerifyOrReturnError(taglen != 0, CHIP_ERROR_WRONG_ENCRYPTION_TYPE);
     429        9487 :     VerifyOrReturnError(size >= taglen, CHIP_ERROR_INVALID_ARGUMENT);
     430             : 
     431        9487 :     memcpy(p, &mTag[0], taglen);
     432             : 
     433             :     // Written data size provided to caller on success
     434        9487 :     *encode_size = taglen;
     435             : 
     436        9487 :     return CHIP_NO_ERROR;
     437             : }
     438             : 
     439             : } // namespace chip

Generated by: LCOV version 1.14