8a95a74a04f51b37224e07dc79aad95e2af5b73d
[platform/upstream/connectedhomeip.git] / src / transport / raw / MessageHeader.cpp
1 /*
2  *
3  *    Copyright (c) 2020 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 <core/CHIPError.h>
33 #include <support/BufferReader.h>
34 #include <support/CodeUtils.h>
35 #include <support/ReturnMacros.h>
36
37 /**********************************************
38  * Header format (little endian):
39  *
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                             |
58  *
59  **********************************************/
60
61 namespace chip {
62 namespace {
63
64 using namespace chip::Encoding;
65
66 /// size of the fixed portion of the header
67 constexpr size_t kFixedUnencryptedHeaderSizeBytes = 8;
68
69 /// size of the encrypted portion of the header
70 constexpr size_t kEncryptedHeaderSizeBytes = 6;
71
72 /// size of a serialized node id inside a header
73 constexpr size_t kNodeIdSizeBytes = 8;
74
75 /// size of a serialized vendor id inside a header
76 constexpr size_t kVendorIdSizeBytes = 2;
77
78 /// size of a serialized ack id inside a header
79 constexpr size_t kAckIdSizeBytes = 4;
80
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;
85
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;
90
91 } // namespace
92
93 uint16_t PacketHeader::EncodeSizeBytes() const
94 {
95     size_t size = kFixedUnencryptedHeaderSizeBytes;
96
97     if (mSourceNodeId.HasValue())
98     {
99         size += kNodeIdSizeBytes;
100     }
101
102     if (mDestinationNodeId.HasValue())
103     {
104         size += kNodeIdSizeBytes;
105     }
106
107     static_assert(kFixedUnencryptedHeaderSizeBytes + kNodeIdSizeBytes + kNodeIdSizeBytes <= UINT16_MAX,
108                   "Header size does not fit in uint16_t");
109     return static_cast<uint16_t>(size);
110 }
111
112 uint16_t PayloadHeader::EncodeSizeBytes() const
113 {
114     size_t size = kEncryptedHeaderSizeBytes;
115
116     if (mVendorId.HasValue())
117     {
118         size += kVendorIdSizeBytes;
119     }
120
121     if (mAckId.HasValue())
122     {
123         size += kAckIdSizeBytes;
124     }
125
126     static_assert(kEncryptedHeaderSizeBytes + kVendorIdSizeBytes + kAckIdSizeBytes <= UINT16_MAX,
127                   "Header size does not fit in uint16_t");
128     return static_cast<uint16_t>(size);
129 }
130
131 uint16_t MessageAuthenticationCode::TagLenForEncryptionType(Header::EncryptionType encType)
132 {
133     switch (encType)
134     {
135     case Header::EncryptionType::kAESCCMTagLen8:
136         return 8;
137
138     case Header::EncryptionType::kAESCCMTagLen12:
139         return 12;
140
141     case Header::EncryptionType::kAESCCMTagLen16:
142         return 16;
143
144     default:
145         return 0;
146     }
147 }
148
149 CHIP_ERROR PacketHeader::Decode(const uint8_t * const data, uint16_t size, uint16_t * decode_len)
150 {
151     CHIP_ERROR err = CHIP_NO_ERROR;
152     LittleEndian::Reader reader(data, size);
153     int version;
154     uint16_t octets_read;
155
156     uint16_t header;
157     err = reader.Read16(&header).StatusCode();
158     SuccessOrExit(err);
159     version = ((header & kVersionMask) >> kVersionShift);
160     VerifyOrExit(version == kHeaderVersion, err = CHIP_ERROR_VERSION_MISMATCH);
161
162     mEncryptionType = static_cast<Header::EncryptionType>((header & kEncryptionTypeMask) >> kEncryptionTypeShift);
163     mFlags.SetRaw(header & Header::kFlagsMask);
164
165     err = reader.Read32(&mMessageId).StatusCode();
166     SuccessOrExit(err);
167
168     if (mFlags.Has(Header::FlagValues::kSourceNodeIdPresent))
169     {
170         uint64_t sourceNodeId;
171         err = reader.Read64(&sourceNodeId).StatusCode();
172         SuccessOrExit(err);
173         mSourceNodeId.SetValue(sourceNodeId);
174     }
175     else
176     {
177         mSourceNodeId.ClearValue();
178     }
179
180     if (mFlags.Has(Header::FlagValues::kDestinationNodeIdPresent))
181     {
182         uint64_t destinationNodeId;
183         err = reader.Read64(&destinationNodeId).StatusCode();
184         SuccessOrExit(err);
185         mDestinationNodeId.SetValue(destinationNodeId);
186     }
187     else
188     {
189         mDestinationNodeId.ClearValue();
190     }
191
192     err = reader.Read16(&mEncryptionKeyID).StatusCode();
193     SuccessOrExit(err);
194
195     octets_read = reader.OctetsRead();
196     VerifyOrExit(octets_read == EncodeSizeBytes(), err = CHIP_ERROR_INTERNAL);
197     *decode_len = octets_read;
198
199 exit:
200
201     return err;
202 }
203
204 CHIP_ERROR PacketHeader::DecodeAndConsume(const System::PacketBufferHandle & buf)
205 {
206     uint16_t headerSize = 0;
207     ReturnErrorOnFailure(Decode(buf->Start(), buf->DataLength(), &headerSize));
208     buf->ConsumeHead(headerSize);
209     return CHIP_NO_ERROR;
210 }
211
212 CHIP_ERROR PayloadHeader::Decode(const uint8_t * const data, uint16_t size, uint16_t * decode_len)
213 {
214     CHIP_ERROR err = CHIP_NO_ERROR;
215     LittleEndian::Reader reader(data, size);
216     uint8_t header;
217     uint16_t octets_read;
218
219     err = reader.Read8(&header).Read8(&mMessageType).Read16(&mExchangeID).StatusCode();
220     SuccessOrExit(err);
221
222     mExchangeFlags.SetRaw(header);
223
224     if (mExchangeFlags.Has(Header::ExFlagValues::kExchangeFlag_VendorIdPresent))
225     {
226         uint16_t vendor_id;
227         err = reader.Read16(&vendor_id).StatusCode();
228         SuccessOrExit(err);
229         mVendorId.SetValue(vendor_id);
230     }
231     else
232     {
233         mVendorId.ClearValue();
234     }
235
236     err = reader.Read16(&mProtocolID).StatusCode();
237     SuccessOrExit(err);
238
239     if (mExchangeFlags.Has(Header::ExFlagValues::kExchangeFlag_AckMsg))
240     {
241         uint32_t ack_id;
242         err = reader.Read32(&ack_id).StatusCode();
243         SuccessOrExit(err);
244         mAckId.SetValue(ack_id);
245     }
246     else
247     {
248         mAckId.ClearValue();
249     }
250
251     octets_read = reader.OctetsRead();
252     VerifyOrExit(octets_read == EncodeSizeBytes(), err = CHIP_ERROR_INTERNAL);
253     *decode_len = octets_read;
254
255 exit:
256
257     return err;
258 }
259
260 CHIP_ERROR PayloadHeader::DecodeAndConsume(const System::PacketBufferHandle & buf)
261 {
262     uint16_t headerSize = 0;
263     ReturnErrorOnFailure(Decode(buf->Start(), buf->DataLength(), &headerSize));
264     buf->ConsumeHead(headerSize);
265     return CHIP_NO_ERROR;
266 }
267
268 CHIP_ERROR PacketHeader::Encode(uint8_t * data, uint16_t size, uint16_t * encode_size) const
269 {
270     CHIP_ERROR err  = CHIP_NO_ERROR;
271     uint8_t * p     = data;
272     uint16_t header = kHeaderVersion << kVersionShift;
273
274     VerifyOrExit(size >= EncodeSizeBytes(), err = CHIP_ERROR_INVALID_ARGUMENT);
275
276     {
277         Header::Flags encodeFlags = mFlags;
278         encodeFlags.Set(Header::FlagValues::kSourceNodeIdPresent, mSourceNodeId.HasValue())
279             .Set(Header::FlagValues::kDestinationNodeIdPresent, mDestinationNodeId.HasValue());
280
281         header = header | encodeFlags.Raw();
282     }
283
284     header |= (static_cast<uint16_t>(static_cast<uint16_t>(mEncryptionType) << kEncryptionTypeShift) & kEncryptionTypeMask);
285
286     LittleEndian::Write16(p, header);
287     LittleEndian::Write32(p, mMessageId);
288     if (mSourceNodeId.HasValue())
289     {
290         LittleEndian::Write64(p, mSourceNodeId.Value());
291     }
292     if (mDestinationNodeId.HasValue())
293     {
294         LittleEndian::Write64(p, mDestinationNodeId.Value());
295     }
296
297     LittleEndian::Write16(p, mEncryptionKeyID);
298
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);
302
303 exit:
304     return err;
305 }
306
307 CHIP_ERROR PacketHeader::EncodeBeforeData(const System::PacketBufferHandle & buf) const
308 {
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;
318 }
319
320 CHIP_ERROR PayloadHeader::Encode(uint8_t * data, uint16_t size, uint16_t * encode_size) const
321 {
322     CHIP_ERROR err = CHIP_NO_ERROR;
323     uint8_t * p    = data;
324     uint8_t header = mExchangeFlags.Raw();
325
326     VerifyOrExit(size >= EncodeSizeBytes(), err = CHIP_ERROR_INVALID_ARGUMENT);
327
328     Write8(p, header);
329     Write8(p, mMessageType);
330     LittleEndian::Write16(p, mExchangeID);
331     if (mVendorId.HasValue())
332     {
333         LittleEndian::Write16(p, mVendorId.Value());
334     }
335     LittleEndian::Write16(p, mProtocolID);
336     if (mAckId.HasValue())
337     {
338         LittleEndian::Write32(p, mAckId.Value());
339     }
340
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);
344
345 exit:
346     return err;
347 }
348
349 CHIP_ERROR PayloadHeader::EncodeBeforeData(const System::PacketBufferHandle & buf) const
350 {
351     // Note: PacketHeader::EncodeBeforeData probably needs changes if you change
352     // anything here.
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;
360 }
361
362 CHIP_ERROR MessageAuthenticationCode::Decode(const PacketHeader & packetHeader, const uint8_t * const data, uint16_t size,
363                                              uint16_t * decode_len)
364 {
365     CHIP_ERROR err        = CHIP_NO_ERROR;
366     const uint8_t * p     = data;
367     const uint16_t taglen = TagLenForEncryptionType(packetHeader.GetEncryptionType());
368
369     VerifyOrExit(taglen != 0, err = CHIP_ERROR_WRONG_ENCRYPTION_TYPE_FROM_PEER);
370     VerifyOrExit(size >= taglen, err = CHIP_ERROR_INVALID_ARGUMENT);
371
372     memcpy(&mTag[0], p, taglen);
373
374     *decode_len = taglen;
375
376 exit:
377
378     return err;
379 }
380
381 CHIP_ERROR MessageAuthenticationCode::Encode(const PacketHeader & packetHeader, uint8_t * data, uint16_t size,
382                                              uint16_t * encode_size) const
383 {
384     CHIP_ERROR err        = CHIP_NO_ERROR;
385     uint8_t * p           = data;
386     const uint16_t taglen = TagLenForEncryptionType(packetHeader.GetEncryptionType());
387
388     VerifyOrExit(taglen != 0, err = CHIP_ERROR_WRONG_ENCRYPTION_TYPE);
389     VerifyOrExit(size >= taglen, err = CHIP_ERROR_INVALID_ARGUMENT);
390
391     memcpy(p, &mTag[0], taglen);
392
393     // Written data size provided to caller on success
394     *encode_size = taglen;
395
396 exit:
397     return err;
398 }
399
400 } // namespace chip