3 * Copyright (c) 2020 Project CHIP Authors
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * This file contains the implementation the chip message header
21 * encode/decode classes.
24 #include "MessageHeader.h"
30 #include <type_traits>
32 #include <core/CHIPError.h>
33 #include <support/BufferReader.h>
34 #include <support/CodeUtils.h>
35 #include <support/ReturnMacros.h>
37 /**********************************************
38 * Header format (little endian):
40 * -------- Unencrypted header -----------------------------------------------------
41 * 16 bit: | VERSION: 4 bit | FLAGS: 4 bit | ENCRYPTTYPE: 4 bit | RESERVED: 4 bit |
42 * 32 bit: | MESSAGE_ID |
43 * 64 bit: | SOURCE_NODE_ID (iff source node flag is set) |
44 * 64 bit: | DEST_NODE_ID (iff destination node flag is set) |
45 * 16 bit: | Encryption Key ID |
46 * 16 bit: | Payload Length |
47 * -------- Encrypted header -------------------------------------------------------
48 * 8 bit: | Exchange Header |
49 * 8 bit: | Message Type |
50 * 16 bit: | Exchange ID |
51 * 16 bit: | Optional Vendor ID |
52 * 16 bit: | Protocol ID |
53 * 32 bit: | Acknowledged Message Counter (if A flag in the Header is set) |
54 * -------- Encrypted Application Data Start ---------------------------------------
55 * <var>: | Encrypted Data |
56 * -------- Encrypted Application Data End -----------------------------------------
57 * <var>: | (Unencrypted) Message Authentication Tag |
59 **********************************************/
64 using namespace chip::Encoding;
66 /// size of the fixed portion of the header
67 constexpr size_t kFixedUnencryptedHeaderSizeBytes = 8;
69 /// size of the encrypted portion of the header
70 constexpr size_t kEncryptedHeaderSizeBytes = 6;
72 /// size of a serialized node id inside a header
73 constexpr size_t kNodeIdSizeBytes = 8;
75 /// size of a serialized vendor id inside a header
76 constexpr size_t kVendorIdSizeBytes = 2;
78 /// size of a serialized ack id inside a header
79 constexpr size_t kAckIdSizeBytes = 4;
81 /// Mask to extract just the version part from a 16bit header prefix.
82 constexpr uint16_t kVersionMask = 0xF000;
83 /// Shift to convert to/from a masked version 16bit value to a 4bit version.
84 constexpr int kVersionShift = 12;
86 /// Mask to extract just the encryption type part from a 16bit header prefix.
87 constexpr uint16_t kEncryptionTypeMask = 0xF0;
88 /// Shift to convert to/from a masked encryption type 16bit value to a 4bit encryption type.
89 constexpr int kEncryptionTypeShift = 4;
93 uint16_t PacketHeader::EncodeSizeBytes() const
95 size_t size = kFixedUnencryptedHeaderSizeBytes;
97 if (mSourceNodeId.HasValue())
99 size += kNodeIdSizeBytes;
102 if (mDestinationNodeId.HasValue())
104 size += kNodeIdSizeBytes;
107 static_assert(kFixedUnencryptedHeaderSizeBytes + kNodeIdSizeBytes + kNodeIdSizeBytes <= UINT16_MAX,
108 "Header size does not fit in uint16_t");
109 return static_cast<uint16_t>(size);
112 uint16_t PayloadHeader::EncodeSizeBytes() const
114 size_t size = kEncryptedHeaderSizeBytes;
116 if (mVendorId.HasValue())
118 size += kVendorIdSizeBytes;
121 if (mAckId.HasValue())
123 size += kAckIdSizeBytes;
126 static_assert(kEncryptedHeaderSizeBytes + kVendorIdSizeBytes + kAckIdSizeBytes <= UINT16_MAX,
127 "Header size does not fit in uint16_t");
128 return static_cast<uint16_t>(size);
131 uint16_t MessageAuthenticationCode::TagLenForEncryptionType(Header::EncryptionType encType)
135 case Header::EncryptionType::kAESCCMTagLen8:
138 case Header::EncryptionType::kAESCCMTagLen12:
141 case Header::EncryptionType::kAESCCMTagLen16:
149 CHIP_ERROR PacketHeader::Decode(const uint8_t * const data, uint16_t size, uint16_t * decode_len)
151 CHIP_ERROR err = CHIP_NO_ERROR;
152 LittleEndian::Reader reader(data, size);
154 uint16_t octets_read;
157 err = reader.Read16(&header).StatusCode();
159 version = ((header & kVersionMask) >> kVersionShift);
160 VerifyOrExit(version == kHeaderVersion, err = CHIP_ERROR_VERSION_MISMATCH);
162 mEncryptionType = static_cast<Header::EncryptionType>((header & kEncryptionTypeMask) >> kEncryptionTypeShift);
163 mFlags.SetRaw(header & Header::kFlagsMask);
165 err = reader.Read32(&mMessageId).StatusCode();
168 if (mFlags.Has(Header::FlagValues::kSourceNodeIdPresent))
170 uint64_t sourceNodeId;
171 err = reader.Read64(&sourceNodeId).StatusCode();
173 mSourceNodeId.SetValue(sourceNodeId);
177 mSourceNodeId.ClearValue();
180 if (mFlags.Has(Header::FlagValues::kDestinationNodeIdPresent))
182 uint64_t destinationNodeId;
183 err = reader.Read64(&destinationNodeId).StatusCode();
185 mDestinationNodeId.SetValue(destinationNodeId);
189 mDestinationNodeId.ClearValue();
192 err = reader.Read16(&mEncryptionKeyID).StatusCode();
195 octets_read = reader.OctetsRead();
196 VerifyOrExit(octets_read == EncodeSizeBytes(), err = CHIP_ERROR_INTERNAL);
197 *decode_len = octets_read;
204 CHIP_ERROR PacketHeader::DecodeAndConsume(const System::PacketBufferHandle & buf)
206 uint16_t headerSize = 0;
207 ReturnErrorOnFailure(Decode(buf->Start(), buf->DataLength(), &headerSize));
208 buf->ConsumeHead(headerSize);
209 return CHIP_NO_ERROR;
212 CHIP_ERROR PayloadHeader::Decode(const uint8_t * const data, uint16_t size, uint16_t * decode_len)
214 CHIP_ERROR err = CHIP_NO_ERROR;
215 LittleEndian::Reader reader(data, size);
217 uint16_t octets_read;
219 err = reader.Read8(&header).Read8(&mMessageType).Read16(&mExchangeID).StatusCode();
222 mExchangeFlags.SetRaw(header);
224 if (mExchangeFlags.Has(Header::ExFlagValues::kExchangeFlag_VendorIdPresent))
227 err = reader.Read16(&vendor_id).StatusCode();
229 mVendorId.SetValue(vendor_id);
233 mVendorId.ClearValue();
236 err = reader.Read16(&mProtocolID).StatusCode();
239 if (mExchangeFlags.Has(Header::ExFlagValues::kExchangeFlag_AckMsg))
242 err = reader.Read32(&ack_id).StatusCode();
244 mAckId.SetValue(ack_id);
251 octets_read = reader.OctetsRead();
252 VerifyOrExit(octets_read == EncodeSizeBytes(), err = CHIP_ERROR_INTERNAL);
253 *decode_len = octets_read;
260 CHIP_ERROR PayloadHeader::DecodeAndConsume(const System::PacketBufferHandle & buf)
262 uint16_t headerSize = 0;
263 ReturnErrorOnFailure(Decode(buf->Start(), buf->DataLength(), &headerSize));
264 buf->ConsumeHead(headerSize);
265 return CHIP_NO_ERROR;
268 CHIP_ERROR PacketHeader::Encode(uint8_t * data, uint16_t size, uint16_t * encode_size) const
270 CHIP_ERROR err = CHIP_NO_ERROR;
272 uint16_t header = kHeaderVersion << kVersionShift;
274 VerifyOrExit(size >= EncodeSizeBytes(), err = CHIP_ERROR_INVALID_ARGUMENT);
277 Header::Flags encodeFlags = mFlags;
278 encodeFlags.Set(Header::FlagValues::kSourceNodeIdPresent, mSourceNodeId.HasValue())
279 .Set(Header::FlagValues::kDestinationNodeIdPresent, mDestinationNodeId.HasValue());
281 header = header | encodeFlags.Raw();
284 header |= (static_cast<uint16_t>(static_cast<uint16_t>(mEncryptionType) << kEncryptionTypeShift) & kEncryptionTypeMask);
286 LittleEndian::Write16(p, header);
287 LittleEndian::Write32(p, mMessageId);
288 if (mSourceNodeId.HasValue())
290 LittleEndian::Write64(p, mSourceNodeId.Value());
292 if (mDestinationNodeId.HasValue())
294 LittleEndian::Write64(p, mDestinationNodeId.Value());
297 LittleEndian::Write16(p, mEncryptionKeyID);
299 // Written data size provided to caller on success
300 VerifyOrExit(p - data == EncodeSizeBytes(), err = CHIP_ERROR_INTERNAL);
301 *encode_size = static_cast<uint16_t>(p - data);
307 CHIP_ERROR PacketHeader::EncodeBeforeData(const System::PacketBufferHandle & buf) const
309 // Note: PayloadHeader::EncodeBeforeData probably needs changes if you
310 // change anything here.
311 uint16_t headerSize = EncodeSizeBytes();
312 VerifyOrReturnError(buf->EnsureReservedSize(headerSize), CHIP_ERROR_NO_MEMORY);
313 buf->SetStart(buf->Start() - headerSize);
314 uint16_t actualEncodedHeaderSize;
315 ReturnErrorOnFailure(EncodeAtStart(buf, &actualEncodedHeaderSize));
316 VerifyOrReturnError(actualEncodedHeaderSize == headerSize, CHIP_ERROR_INTERNAL);
317 return CHIP_NO_ERROR;
320 CHIP_ERROR PayloadHeader::Encode(uint8_t * data, uint16_t size, uint16_t * encode_size) const
322 CHIP_ERROR err = CHIP_NO_ERROR;
324 uint8_t header = mExchangeFlags.Raw();
326 VerifyOrExit(size >= EncodeSizeBytes(), err = CHIP_ERROR_INVALID_ARGUMENT);
329 Write8(p, mMessageType);
330 LittleEndian::Write16(p, mExchangeID);
331 if (mVendorId.HasValue())
333 LittleEndian::Write16(p, mVendorId.Value());
335 LittleEndian::Write16(p, mProtocolID);
336 if (mAckId.HasValue())
338 LittleEndian::Write32(p, mAckId.Value());
341 // Written data size provided to caller on success
342 VerifyOrExit(p - data == EncodeSizeBytes(), err = CHIP_ERROR_INTERNAL);
343 *encode_size = static_cast<uint16_t>(p - data);
349 CHIP_ERROR PayloadHeader::EncodeBeforeData(const System::PacketBufferHandle & buf) const
351 // Note: PacketHeader::EncodeBeforeData probably needs changes if you change
353 uint16_t headerSize = EncodeSizeBytes();
354 VerifyOrReturnError(buf->EnsureReservedSize(headerSize), CHIP_ERROR_NO_MEMORY);
355 buf->SetStart(buf->Start() - headerSize);
356 uint16_t actualEncodedHeaderSize;
357 ReturnErrorOnFailure(EncodeAtStart(buf, &actualEncodedHeaderSize));
358 VerifyOrReturnError(actualEncodedHeaderSize == headerSize, CHIP_ERROR_INTERNAL);
359 return CHIP_NO_ERROR;
362 CHIP_ERROR MessageAuthenticationCode::Decode(const PacketHeader & packetHeader, const uint8_t * const data, uint16_t size,
363 uint16_t * decode_len)
365 CHIP_ERROR err = CHIP_NO_ERROR;
366 const uint8_t * p = data;
367 const uint16_t taglen = TagLenForEncryptionType(packetHeader.GetEncryptionType());
369 VerifyOrExit(taglen != 0, err = CHIP_ERROR_WRONG_ENCRYPTION_TYPE_FROM_PEER);
370 VerifyOrExit(size >= taglen, err = CHIP_ERROR_INVALID_ARGUMENT);
372 memcpy(&mTag[0], p, taglen);
374 *decode_len = taglen;
381 CHIP_ERROR MessageAuthenticationCode::Encode(const PacketHeader & packetHeader, uint8_t * data, uint16_t size,
382 uint16_t * encode_size) const
384 CHIP_ERROR err = CHIP_NO_ERROR;
386 const uint16_t taglen = TagLenForEncryptionType(packetHeader.GetEncryptionType());
388 VerifyOrExit(taglen != 0, err = CHIP_ERROR_WRONG_ENCRYPTION_TYPE);
389 VerifyOrExit(size >= taglen, err = CHIP_ERROR_INVALID_ARGUMENT);
391 memcpy(p, &mTag[0], taglen);
393 // Written data size provided to caller on success
394 *encode_size = taglen;