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
|