Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / transport / raw / MessageHeader.cpp
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 <core/CHIPError.h>
33 #include <support/BufferReader.h>
34 #include <support/CodeUtils.h>
35
36 /**********************************************
37  * Header format (little endian):
38  *
39  * -------- Unencrypted header -----------------------------------------------------
40  *  16 bit: | VERSION: 4 bit | FLAGS: 4 bit | ENCRYPTTYPE: 4 bit | RESERVED: 4 bit |
41  *  32 bit: | MESSAGE_ID                                                           |
42  *  64 bit: | SOURCE_NODE_ID (iff source node flag is set)                         |
43  *  64 bit: | DEST_NODE_ID (iff destination node flag is set)                      |
44  *  16 bit: | Encryption Key ID                                                    |
45  *  16 bit: | Payload Length                                                       |
46  * -------- Encrypted header -------------------------------------------------------
47  *  8 bit:  | Exchange Header                                                      |
48  *  8 bit:  | Message Type                                                         |
49  *  16 bit: | Exchange ID                                                          |
50  *  16 bit: | Optional Vendor ID                                                   |
51  *  16 bit: | Protocol 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 vendor id inside a header
75 constexpr size_t kVendorIdSizeBytes = 2;
76
77 /// size of a serialized ack id inside a header
78 constexpr size_t kAckIdSizeBytes = 4;
79
80 /// Mask to extract just the version part from a 16bit header prefix.
81 constexpr uint16_t kVersionMask = 0xF000;
82 /// Shift to convert to/from a masked version 16bit value to a 4bit version.
83 constexpr int kVersionShift = 12;
84
85 /// Mask to extract just the encryption type part from a 16bit header prefix.
86 constexpr uint16_t kEncryptionTypeMask = 0xF0;
87 /// Shift to convert to/from a masked encryption type 16bit value to a 4bit encryption type.
88 constexpr int kEncryptionTypeShift = 4;
89
90 } // namespace
91
92 uint16_t PacketHeader::EncodeSizeBytes() const
93 {
94     size_t size = kFixedUnencryptedHeaderSizeBytes;
95
96     if (mSourceNodeId.HasValue())
97     {
98         size += kNodeIdSizeBytes;
99     }
100
101     if (mDestinationNodeId.HasValue())
102     {
103         size += kNodeIdSizeBytes;
104     }
105
106     static_assert(kFixedUnencryptedHeaderSizeBytes + kNodeIdSizeBytes + kNodeIdSizeBytes <= UINT16_MAX,
107                   "Header size does not fit in uint16_t");
108     return static_cast<uint16_t>(size);
109 }
110
111 uint16_t PayloadHeader::EncodeSizeBytes() const
112 {
113     size_t size = kEncryptedHeaderSizeBytes;
114
115     if (HaveVendorId())
116     {
117         size += kVendorIdSizeBytes;
118     }
119
120     if (mAckId.HasValue())
121     {
122         size += kAckIdSizeBytes;
123     }
124
125     static_assert(kEncryptedHeaderSizeBytes + kVendorIdSizeBytes + kAckIdSizeBytes <= UINT16_MAX,
126                   "Header size does not fit in uint16_t");
127     return static_cast<uint16_t>(size);
128 }
129
130 uint16_t MessageAuthenticationCode::TagLenForEncryptionType(Header::EncryptionType encType)
131 {
132     switch (encType)
133     {
134     case Header::EncryptionType::kAESCCMTagLen8:
135         return 8;
136
137     case Header::EncryptionType::kAESCCMTagLen12:
138         return 12;
139
140     case Header::EncryptionType::kAESCCMTagLen16:
141         return 16;
142
143     default:
144         return 0;
145     }
146 }
147
148 CHIP_ERROR PacketHeader::Decode(const uint8_t * const data, uint16_t size, uint16_t * decode_len)
149 {
150     CHIP_ERROR err = CHIP_NO_ERROR;
151     LittleEndian::Reader reader(data, size);
152     int version;
153     uint16_t octets_read;
154
155     uint16_t header;
156     err = reader.Read16(&header).StatusCode();
157     SuccessOrExit(err);
158     version = ((header & kVersionMask) >> kVersionShift);
159     VerifyOrExit(version == kHeaderVersion, err = CHIP_ERROR_VERSION_MISMATCH);
160
161     mEncryptionType = static_cast<Header::EncryptionType>((header & kEncryptionTypeMask) >> kEncryptionTypeShift);
162     mFlags.SetRaw(header & Header::kFlagsMask);
163
164     err = reader.Read32(&mMessageId).StatusCode();
165     SuccessOrExit(err);
166
167     if (mFlags.Has(Header::FlagValues::kSourceNodeIdPresent))
168     {
169         uint64_t sourceNodeId;
170         err = reader.Read64(&sourceNodeId).StatusCode();
171         SuccessOrExit(err);
172         mSourceNodeId.SetValue(sourceNodeId);
173     }
174     else
175     {
176         mSourceNodeId.ClearValue();
177     }
178
179     if (mFlags.Has(Header::FlagValues::kDestinationNodeIdPresent))
180     {
181         uint64_t destinationNodeId;
182         err = reader.Read64(&destinationNodeId).StatusCode();
183         SuccessOrExit(err);
184         mDestinationNodeId.SetValue(destinationNodeId);
185     }
186     else
187     {
188         mDestinationNodeId.ClearValue();
189     }
190
191     err = reader.Read16(&mEncryptionKeyID).StatusCode();
192     SuccessOrExit(err);
193
194     octets_read = reader.OctetsRead();
195     VerifyOrExit(octets_read == EncodeSizeBytes(), err = CHIP_ERROR_INTERNAL);
196     *decode_len = octets_read;
197
198 exit:
199
200     return err;
201 }
202
203 CHIP_ERROR PacketHeader::DecodeAndConsume(const System::PacketBufferHandle & buf)
204 {
205     uint16_t headerSize = 0;
206     ReturnErrorOnFailure(Decode(buf->Start(), buf->DataLength(), &headerSize));
207     buf->ConsumeHead(headerSize);
208     return CHIP_NO_ERROR;
209 }
210
211 CHIP_ERROR PayloadHeader::Decode(const uint8_t * const data, uint16_t size, uint16_t * decode_len)
212 {
213     CHIP_ERROR err = CHIP_NO_ERROR;
214     LittleEndian::Reader reader(data, size);
215     uint8_t header;
216     uint16_t octets_read;
217
218     err = reader.Read8(&header).Read8(&mMessageType).Read16(&mExchangeID).StatusCode();
219     SuccessOrExit(err);
220
221     mExchangeFlags.SetRaw(header);
222
223     VendorId vendor_id;
224     if (HaveVendorId())
225     {
226         uint16_t vendor_id_raw;
227         err = reader.Read16(&vendor_id_raw).StatusCode();
228         SuccessOrExit(err);
229         vendor_id = static_cast<VendorId>(vendor_id_raw);
230     }
231     else
232     {
233         vendor_id = VendorId::Common;
234     }
235
236     uint16_t protocol_id;
237     err = reader.Read16(&protocol_id).StatusCode();
238     SuccessOrExit(err);
239
240     mProtocolID = Protocols::Id(vendor_id, protocol_id);
241
242     if (mExchangeFlags.Has(Header::ExFlagValues::kExchangeFlag_AckMsg))
243     {
244         uint32_t ack_id;
245         err = reader.Read32(&ack_id).StatusCode();
246         SuccessOrExit(err);
247         mAckId.SetValue(ack_id);
248     }
249     else
250     {
251         mAckId.ClearValue();
252     }
253
254     octets_read = reader.OctetsRead();
255     VerifyOrExit(octets_read == EncodeSizeBytes(), err = CHIP_ERROR_INTERNAL);
256     *decode_len = octets_read;
257
258 exit:
259
260     return err;
261 }
262
263 CHIP_ERROR PayloadHeader::DecodeAndConsume(const System::PacketBufferHandle & buf)
264 {
265     uint16_t headerSize = 0;
266     ReturnErrorOnFailure(Decode(buf->Start(), buf->DataLength(), &headerSize));
267     buf->ConsumeHead(headerSize);
268     return CHIP_NO_ERROR;
269 }
270
271 CHIP_ERROR PacketHeader::Encode(uint8_t * data, uint16_t size, uint16_t * encode_size) const
272 {
273     CHIP_ERROR err  = CHIP_NO_ERROR;
274     uint8_t * p     = data;
275     uint16_t header = kHeaderVersion << kVersionShift;
276
277     VerifyOrExit(size >= EncodeSizeBytes(), err = CHIP_ERROR_INVALID_ARGUMENT);
278
279     {
280         Header::Flags encodeFlags = mFlags;
281         encodeFlags.Set(Header::FlagValues::kSourceNodeIdPresent, mSourceNodeId.HasValue())
282             .Set(Header::FlagValues::kDestinationNodeIdPresent, mDestinationNodeId.HasValue());
283
284         header = header | encodeFlags.Raw();
285     }
286
287     header |= (static_cast<uint16_t>(static_cast<uint16_t>(mEncryptionType) << kEncryptionTypeShift) & kEncryptionTypeMask);
288
289     LittleEndian::Write16(p, header);
290     LittleEndian::Write32(p, mMessageId);
291     if (mSourceNodeId.HasValue())
292     {
293         LittleEndian::Write64(p, mSourceNodeId.Value());
294     }
295     if (mDestinationNodeId.HasValue())
296     {
297         LittleEndian::Write64(p, mDestinationNodeId.Value());
298     }
299
300     LittleEndian::Write16(p, mEncryptionKeyID);
301
302     // Written data size provided to caller on success
303     VerifyOrExit(p - data == EncodeSizeBytes(), err = CHIP_ERROR_INTERNAL);
304     *encode_size = static_cast<uint16_t>(p - data);
305
306 exit:
307     return err;
308 }
309
310 CHIP_ERROR PacketHeader::EncodeBeforeData(const System::PacketBufferHandle & buf) const
311 {
312     // Note: PayloadHeader::EncodeBeforeData probably needs changes if you
313     // change anything here.
314     uint16_t headerSize = EncodeSizeBytes();
315     VerifyOrReturnError(buf->EnsureReservedSize(headerSize), CHIP_ERROR_NO_MEMORY);
316     buf->SetStart(buf->Start() - headerSize);
317     uint16_t actualEncodedHeaderSize;
318     ReturnErrorOnFailure(EncodeAtStart(buf, &actualEncodedHeaderSize));
319     VerifyOrReturnError(actualEncodedHeaderSize == headerSize, CHIP_ERROR_INTERNAL);
320     return CHIP_NO_ERROR;
321 }
322
323 CHIP_ERROR PayloadHeader::Encode(uint8_t * data, uint16_t size, uint16_t * encode_size) const
324 {
325     CHIP_ERROR err       = CHIP_NO_ERROR;
326     uint8_t * p          = data;
327     const uint8_t header = mExchangeFlags.Raw();
328
329     VerifyOrExit(size >= EncodeSizeBytes(), err = CHIP_ERROR_INVALID_ARGUMENT);
330
331     Write8(p, header);
332     Write8(p, mMessageType);
333     LittleEndian::Write16(p, mExchangeID);
334     if (HaveVendorId())
335     {
336         LittleEndian::Write16(p, static_cast<std::underlying_type_t<VendorId>>(mProtocolID.GetVendorId()));
337     }
338     LittleEndian::Write16(p, mProtocolID.GetProtocolId());
339     if (mAckId.HasValue())
340     {
341         LittleEndian::Write32(p, mAckId.Value());
342     }
343
344     // Written data size provided to caller on success
345     VerifyOrExit(p - data == EncodeSizeBytes(), err = CHIP_ERROR_INTERNAL);
346     *encode_size = static_cast<uint16_t>(p - data);
347
348 exit:
349     return err;
350 }
351
352 CHIP_ERROR PayloadHeader::EncodeBeforeData(const System::PacketBufferHandle & buf) const
353 {
354     // Note: PacketHeader::EncodeBeforeData probably needs changes if you change
355     // anything here.
356     uint16_t headerSize = EncodeSizeBytes();
357     VerifyOrReturnError(buf->EnsureReservedSize(headerSize), CHIP_ERROR_NO_MEMORY);
358     buf->SetStart(buf->Start() - headerSize);
359     uint16_t actualEncodedHeaderSize;
360     ReturnErrorOnFailure(EncodeAtStart(buf, &actualEncodedHeaderSize));
361     VerifyOrReturnError(actualEncodedHeaderSize == headerSize, CHIP_ERROR_INTERNAL);
362     return CHIP_NO_ERROR;
363 }
364
365 CHIP_ERROR MessageAuthenticationCode::Decode(const PacketHeader & packetHeader, const uint8_t * const data, uint16_t size,
366                                              uint16_t * decode_len)
367 {
368     CHIP_ERROR err        = CHIP_NO_ERROR;
369     const uint8_t * p     = data;
370     const uint16_t taglen = TagLenForEncryptionType(packetHeader.GetEncryptionType());
371
372     VerifyOrExit(taglen != 0, err = CHIP_ERROR_WRONG_ENCRYPTION_TYPE_FROM_PEER);
373     VerifyOrExit(size >= taglen, err = CHIP_ERROR_INVALID_ARGUMENT);
374
375     memcpy(&mTag[0], p, taglen);
376
377     *decode_len = taglen;
378
379 exit:
380
381     return err;
382 }
383
384 CHIP_ERROR MessageAuthenticationCode::Encode(const PacketHeader & packetHeader, uint8_t * data, uint16_t size,
385                                              uint16_t * encode_size) const
386 {
387     CHIP_ERROR err        = CHIP_NO_ERROR;
388     uint8_t * p           = data;
389     const uint16_t taglen = TagLenForEncryptionType(packetHeader.GetEncryptionType());
390
391     VerifyOrExit(taglen != 0, err = CHIP_ERROR_WRONG_ENCRYPTION_TYPE);
392     VerifyOrExit(size >= taglen, err = CHIP_ERROR_INVALID_ARGUMENT);
393
394     memcpy(p, &mTag[0], taglen);
395
396     // Written data size provided to caller on success
397     *encode_size = taglen;
398
399 exit:
400     return err;
401 }
402
403 } // namespace chip