Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2023 Project CHIP Authors
4 : * Copyright (c) 2013-2017 Nest Labs, Inc.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 : #include <lib/core/TLVReader.h>
19 :
20 : #include <stdint.h>
21 : #include <string.h>
22 :
23 : #include <lib/core/CHIPConfig.h>
24 : #include <lib/core/CHIPEncoding.h>
25 : #include <lib/core/CHIPError.h>
26 : #include <lib/core/CHIPSafeCasts.h>
27 : #include <lib/core/DataModelTypes.h>
28 : #include <lib/core/Optional.h>
29 : #include <lib/core/TLVBackingStore.h>
30 : #include <lib/core/TLVCommon.h>
31 : #include <lib/core/TLVTags.h>
32 : #include <lib/core/TLVTypes.h>
33 : #include <lib/support/BufferWriter.h>
34 : #include <lib/support/BytesToHex.h>
35 : #include <lib/support/CHIPMem.h>
36 : #include <lib/support/CodeUtils.h>
37 : #include <lib/support/SafeInt.h>
38 : #include <lib/support/Span.h>
39 : #include <lib/support/logging/TextOnlyLogging.h>
40 :
41 : #if CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_READ
42 : #include <lib/support/utf8.h>
43 : #endif
44 :
45 : namespace chip {
46 : namespace TLV {
47 :
48 : using namespace chip::Encoding;
49 :
50 : static const uint8_t sTagSizes[] = { 0, 1, 2, 4, 2, 4, 6, 8 };
51 :
52 1603972 : TLVReader::TLVReader() :
53 1603972 : ImplicitProfileId(kProfileIdNotSpecified), AppData(nullptr), mElemLenOrVal(0), mBackingStore(nullptr), mReadPoint(nullptr),
54 1603972 : mBufEnd(nullptr), mLenRead(0), mMaxLen(0), mContainerType(kTLVType_NotSpecified), mControlByte(kTLVControlByte_NotSpecified),
55 1603972 : mContainerOpen(false)
56 1603972 : {}
57 :
58 993836 : void TLVReader::Init(const uint8_t * data, size_t dataLen)
59 : {
60 : // TODO: Maybe we can just make mMaxLen and mLenRead size_t instead?
61 993836 : uint32_t actualDataLen = dataLen > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(dataLen);
62 993836 : mBackingStore = nullptr;
63 993836 : mReadPoint = data;
64 993836 : mBufEnd = data + actualDataLen;
65 993836 : mLenRead = 0;
66 993836 : mMaxLen = actualDataLen;
67 993836 : ClearElementState();
68 993836 : mContainerType = kTLVType_NotSpecified;
69 993836 : SetContainerOpen(false);
70 :
71 993836 : ImplicitProfileId = kProfileIdNotSpecified;
72 993836 : }
73 :
74 4137 : CHIP_ERROR TLVReader::Init(TLVBackingStore & backingStore, uint32_t maxLen)
75 : {
76 4137 : mBackingStore = &backingStore;
77 4137 : mReadPoint = nullptr;
78 4137 : uint32_t bufLen = 0;
79 4137 : CHIP_ERROR err = mBackingStore->OnInit(*this, mReadPoint, bufLen);
80 4137 : if (err != CHIP_NO_ERROR)
81 0 : return err;
82 :
83 4137 : mBufEnd = mReadPoint + bufLen;
84 4137 : mLenRead = 0;
85 4137 : mMaxLen = maxLen;
86 4137 : ClearElementState();
87 4137 : mContainerType = kTLVType_NotSpecified;
88 4137 : SetContainerOpen(false);
89 :
90 4137 : ImplicitProfileId = kProfileIdNotSpecified;
91 4137 : AppData = nullptr;
92 4137 : return CHIP_NO_ERROR;
93 : }
94 :
95 568633 : void TLVReader::Init(const TLVReader & aReader)
96 : {
97 : // Initialize private data members
98 :
99 568633 : mElemTag = aReader.mElemTag;
100 568633 : mElemLenOrVal = aReader.mElemLenOrVal;
101 568633 : mBackingStore = aReader.mBackingStore;
102 568633 : mReadPoint = aReader.mReadPoint;
103 568633 : mBufEnd = aReader.mBufEnd;
104 568633 : mLenRead = aReader.mLenRead;
105 568633 : mMaxLen = aReader.mMaxLen;
106 568633 : mControlByte = aReader.mControlByte;
107 568633 : mContainerType = aReader.mContainerType;
108 568633 : SetContainerOpen(aReader.IsContainerOpen());
109 :
110 : // Initialize public data members
111 :
112 568633 : ImplicitProfileId = aReader.ImplicitProfileId;
113 568633 : AppData = aReader.AppData;
114 568633 : }
115 :
116 5638716 : TLVType TLVReader::GetType() const
117 : {
118 5638716 : TLVElementType elemType = ElementType();
119 5638716 : if (elemType == TLVElementType::EndOfContainer)
120 4 : return kTLVType_NotSpecified;
121 5638712 : if (elemType == TLVElementType::FloatingPointNumber32 || elemType == TLVElementType::FloatingPointNumber64)
122 11669 : return kTLVType_FloatingPointNumber;
123 5627043 : if (elemType == TLVElementType::NotSpecified || elemType >= TLVElementType::Null)
124 2245911 : return static_cast<TLVType>(elemType);
125 3381132 : return static_cast<TLVType>(static_cast<uint8_t>(elemType) & ~kTLVTypeSizeMask);
126 : }
127 :
128 109374 : uint32_t TLVReader::GetLength() const
129 : {
130 109374 : if (TLVTypeHasLength(ElementType()))
131 96235 : return static_cast<uint32_t>(mElemLenOrVal);
132 13139 : return 0;
133 : }
134 :
135 1879997 : CHIP_ERROR TLVReader::Get(bool & v) const
136 : {
137 1879997 : TLVElementType elemType = ElementType();
138 1879997 : if (elemType == TLVElementType::BooleanFalse)
139 932751 : v = false;
140 947246 : else if (elemType == TLVElementType::BooleanTrue)
141 947245 : v = true;
142 : else
143 1 : return CHIP_ERROR_WRONG_TLV_TYPE;
144 1879996 : return CHIP_NO_ERROR;
145 : }
146 :
147 912301 : CHIP_ERROR TLVReader::Get(int8_t & v) const
148 : {
149 912301 : int64_t v64 = 0;
150 912301 : CHIP_ERROR err = Get(v64);
151 912301 : if (!CanCastTo<int8_t>(v64))
152 : {
153 30 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
154 : }
155 912271 : v = static_cast<int8_t>(v64);
156 912271 : return err;
157 : }
158 :
159 909773 : CHIP_ERROR TLVReader::Get(int16_t & v) const
160 : {
161 909773 : int64_t v64 = 0;
162 909773 : CHIP_ERROR err = Get(v64);
163 909773 : if (!CanCastTo<int16_t>(v64))
164 : {
165 4 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
166 : }
167 909769 : v = static_cast<int16_t>(v64);
168 909769 : return err;
169 : }
170 :
171 910152 : CHIP_ERROR TLVReader::Get(int32_t & v) const
172 : {
173 910152 : int64_t v64 = 0;
174 910152 : CHIP_ERROR err = Get(v64);
175 910152 : if (!CanCastTo<int32_t>(v64))
176 : {
177 2 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
178 : }
179 910150 : v = static_cast<int32_t>(v64);
180 910150 : return err;
181 : }
182 :
183 3643082 : CHIP_ERROR TLVReader::Get(int64_t & v) const
184 : {
185 : // Internal callers of this method depend on it not modifying "v" on failure.
186 3643082 : switch (ElementType())
187 : {
188 3641711 : case TLVElementType::Int8:
189 3641711 : v = CastToSigned(static_cast<uint8_t>(mElemLenOrVal));
190 3641711 : break;
191 83 : case TLVElementType::Int16:
192 83 : v = CastToSigned(static_cast<uint16_t>(mElemLenOrVal));
193 83 : break;
194 824 : case TLVElementType::Int32:
195 824 : v = CastToSigned(static_cast<uint32_t>(mElemLenOrVal));
196 824 : break;
197 63 : case TLVElementType::Int64:
198 63 : v = CastToSigned(mElemLenOrVal);
199 63 : break;
200 401 : default:
201 401 : return CHIP_ERROR_WRONG_TLV_TYPE;
202 : }
203 :
204 3642681 : return CHIP_NO_ERROR;
205 : }
206 :
207 950805 : CHIP_ERROR TLVReader::Get(uint8_t & v) const
208 : {
209 950805 : uint64_t v64 = 0;
210 950805 : CHIP_ERROR err = Get(v64);
211 950805 : if (!CanCastTo<uint8_t>(v64))
212 : {
213 3 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
214 : }
215 950802 : v = static_cast<uint8_t>(v64);
216 950802 : return err;
217 : }
218 :
219 77380 : CHIP_ERROR TLVReader::Get(uint16_t & v) const
220 : {
221 77380 : uint64_t v64 = 0;
222 77380 : CHIP_ERROR err = Get(v64);
223 77380 : if (!CanCastTo<uint16_t>(v64))
224 : {
225 6 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
226 : }
227 77374 : v = static_cast<uint16_t>(v64);
228 77374 : return err;
229 : }
230 :
231 89826 : CHIP_ERROR TLVReader::Get(uint32_t & v) const
232 : {
233 89826 : uint64_t v64 = 0;
234 89826 : CHIP_ERROR err = Get(v64);
235 89826 : if (!CanCastTo<uint32_t>(v64))
236 : {
237 1 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
238 : }
239 89825 : v = static_cast<uint32_t>(v64);
240 89825 : return err;
241 : }
242 :
243 1173041 : CHIP_ERROR TLVReader::Get(uint64_t & v) const
244 : {
245 : // Internal callers of this method depend on it not modifying "v" on failure.
246 1173041 : switch (ElementType())
247 : {
248 262129 : case TLVElementType::UInt8:
249 : case TLVElementType::UInt16:
250 : case TLVElementType::UInt32:
251 : case TLVElementType::UInt64:
252 262129 : v = mElemLenOrVal;
253 262129 : break;
254 910912 : default:
255 910912 : return CHIP_ERROR_WRONG_TLV_TYPE;
256 : }
257 262129 : return CHIP_NO_ERROR;
258 : }
259 :
260 : namespace {
261 2559 : float BitCastToFloat(const uint64_t elemLenOrVal)
262 : {
263 : float f;
264 2559 : auto unsigned32 = static_cast<uint32_t>(elemLenOrVal);
265 2559 : memcpy(&f, &unsigned32, sizeof(f));
266 2559 : return f;
267 : }
268 : } // namespace
269 :
270 : // Note: Unlike the integer Get functions, this code avoids doing conversions
271 : // between float and double wherever possible, because these conversions are
272 : // relatively expensive on platforms that use soft-float instruction sets.
273 :
274 527 : CHIP_ERROR TLVReader::Get(float & v) const
275 : {
276 527 : switch (ElementType())
277 : {
278 525 : case TLVElementType::FloatingPointNumber32: {
279 525 : v = BitCastToFloat(mElemLenOrVal);
280 525 : break;
281 : }
282 2 : default:
283 2 : return CHIP_ERROR_WRONG_TLV_TYPE;
284 : }
285 525 : return CHIP_NO_ERROR;
286 : }
287 :
288 4216 : CHIP_ERROR TLVReader::Get(double & v) const
289 : {
290 4216 : switch (ElementType())
291 : {
292 2034 : case TLVElementType::FloatingPointNumber32: {
293 2034 : v = BitCastToFloat(mElemLenOrVal);
294 2034 : break;
295 : }
296 2181 : case TLVElementType::FloatingPointNumber64: {
297 : double d;
298 2181 : memcpy(&d, &mElemLenOrVal, sizeof(d));
299 2181 : v = d;
300 2181 : break;
301 : }
302 1 : default:
303 1 : return CHIP_ERROR_WRONG_TLV_TYPE;
304 : }
305 4215 : return CHIP_NO_ERROR;
306 : }
307 :
308 11058 : CHIP_ERROR TLVReader::Get(ByteSpan & v) const
309 : {
310 : const uint8_t * val;
311 11058 : ReturnErrorOnFailure(GetDataPtr(val));
312 11054 : v = ByteSpan(val, GetLength());
313 :
314 11054 : return CHIP_NO_ERROR;
315 : }
316 :
317 : namespace {
318 : constexpr int kUnicodeInformationSeparator1 = 0x1F;
319 : constexpr size_t kMaxLocalizedStringIdentifierLen = 2 * sizeof(LocalizedStringIdentifier);
320 : } // namespace
321 :
322 477 : CHIP_ERROR TLVReader::Get(CharSpan & v) const
323 : {
324 477 : if (!TLVTypeIsUTF8String(ElementType()))
325 : {
326 2 : return CHIP_ERROR_WRONG_TLV_TYPE;
327 : }
328 :
329 : const uint8_t * bytes;
330 475 : ReturnErrorOnFailure(GetDataPtr(bytes)); // Does length sanity checks
331 473 : if (bytes == nullptr)
332 : {
333 : // Calling memchr further down with bytes == nullptr would have undefined behaviour, exiting early.
334 101 : return CHIP_NO_ERROR;
335 : }
336 :
337 372 : uint32_t len = GetLength();
338 :
339 : // If Unicode Information Separator 1 (0x1f) is present in the string then method returns
340 : // string ending at first appearance of the Information Separator 1.
341 372 : const uint8_t * infoSeparator = reinterpret_cast<const uint8_t *>(memchr(bytes, kUnicodeInformationSeparator1, len));
342 372 : if (infoSeparator != nullptr)
343 : {
344 5 : len = static_cast<uint32_t>(infoSeparator - bytes);
345 : }
346 :
347 372 : v = CharSpan(Uint8::to_const_char(bytes), len);
348 : #if CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_READ
349 : // Spec requirement: A.11.2. UTF-8 and Octet Strings
350 : //
351 : // For UTF-8 strings, the value octets SHALL encode a valid
352 : // UTF-8 character (code points) sequence.
353 : //
354 : // Senders SHALL NOT include a terminating null character to
355 : // mark the end of a string.
356 :
357 : if (!Utf8::IsValid(v))
358 : {
359 : return CHIP_ERROR_INVALID_UTF8;
360 : }
361 :
362 : if (!v.empty() && (v.back() == 0))
363 : {
364 : return CHIP_ERROR_INVALID_TLV_CHAR_STRING;
365 : }
366 : #endif // CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_READ
367 372 : return CHIP_NO_ERROR;
368 : }
369 :
370 15 : CHIP_ERROR TLVReader::Get(Optional<LocalizedStringIdentifier> & lsid)
371 : {
372 15 : lsid.ClearValue();
373 15 : VerifyOrReturnError(TLVTypeIsUTF8String(ElementType()), CHIP_ERROR_WRONG_TLV_TYPE);
374 :
375 : const uint8_t * bytes;
376 14 : ReturnErrorOnFailure(GetDataPtr(bytes)); // Does length sanity checks
377 14 : if (bytes == nullptr)
378 : {
379 : // Calling memchr further down with bytes == nullptr would have undefined behaviour, exiting early.
380 0 : return CHIP_NO_ERROR;
381 : }
382 :
383 14 : uint32_t len = GetLength();
384 :
385 14 : const uint8_t * infoSeparator1 = static_cast<const uint8_t *>(memchr(bytes, kUnicodeInformationSeparator1, len));
386 14 : if (infoSeparator1 == nullptr)
387 : {
388 1 : return CHIP_NO_ERROR;
389 : }
390 :
391 13 : const uint8_t * lsidPtr = infoSeparator1 + 1;
392 13 : len -= static_cast<uint32_t>(lsidPtr - bytes);
393 :
394 13 : const uint8_t * infoSeparator2 = static_cast<const uint8_t *>(memchr(lsidPtr, kUnicodeInformationSeparator1, len));
395 13 : if (infoSeparator2 != nullptr)
396 : {
397 3 : len = static_cast<uint32_t>(infoSeparator2 - lsidPtr);
398 : }
399 13 : if (len == 0)
400 : {
401 1 : return CHIP_NO_ERROR;
402 : }
403 12 : VerifyOrReturnError(len <= kMaxLocalizedStringIdentifierLen, CHIP_ERROR_INVALID_TLV_ELEMENT);
404 : // Leading zeroes are not allowed.
405 11 : VerifyOrReturnError(static_cast<char>(lsidPtr[0]) != '0', CHIP_ERROR_INVALID_TLV_ELEMENT);
406 :
407 9 : char idStr[kMaxLocalizedStringIdentifierLen] = { '0', '0', '0', '0' };
408 9 : memcpy(&idStr[kMaxLocalizedStringIdentifierLen - len], lsidPtr, len);
409 :
410 : LocalizedStringIdentifier id;
411 9 : VerifyOrReturnError(Encoding::UppercaseHexToUint16(idStr, sizeof(idStr), id) == sizeof(LocalizedStringIdentifier),
412 : CHIP_ERROR_INVALID_TLV_ELEMENT);
413 :
414 8 : lsid.SetValue(id);
415 8 : return CHIP_NO_ERROR;
416 : }
417 :
418 9527 : CHIP_ERROR TLVReader::GetBytes(uint8_t * buf, size_t bufSize)
419 : {
420 9527 : if (!TLVTypeIsString(ElementType()))
421 2 : return CHIP_ERROR_WRONG_TLV_TYPE;
422 :
423 9525 : if (mElemLenOrVal > bufSize)
424 0 : return CHIP_ERROR_BUFFER_TOO_SMALL;
425 :
426 9525 : CHIP_ERROR err = ReadData(buf, static_cast<uint32_t>(mElemLenOrVal));
427 9525 : if (err != CHIP_NO_ERROR)
428 0 : return err;
429 :
430 9525 : mElemLenOrVal = 0;
431 :
432 9525 : return CHIP_NO_ERROR;
433 : }
434 :
435 3197 : CHIP_ERROR TLVReader::GetString(char * buf, size_t bufSize)
436 : {
437 3197 : if (!TLVTypeIsString(ElementType()))
438 1 : return CHIP_ERROR_WRONG_TLV_TYPE;
439 :
440 3196 : if ((mElemLenOrVal + 1) > bufSize)
441 1 : return CHIP_ERROR_BUFFER_TOO_SMALL;
442 :
443 3195 : buf[mElemLenOrVal] = 0;
444 :
445 3195 : return GetBytes(reinterpret_cast<uint8_t *>(buf), bufSize - 1);
446 : }
447 :
448 1 : CHIP_ERROR TLVReader::DupBytes(uint8_t *& buf, uint32_t & dataLen)
449 : {
450 1 : if (!TLVTypeIsString(ElementType()))
451 0 : return CHIP_ERROR_WRONG_TLV_TYPE;
452 :
453 1 : buf = static_cast<uint8_t *>(chip::Platform::MemoryAlloc(static_cast<uint32_t>(mElemLenOrVal)));
454 1 : if (buf == nullptr)
455 0 : return CHIP_ERROR_NO_MEMORY;
456 :
457 1 : CHIP_ERROR err = ReadData(buf, static_cast<uint32_t>(mElemLenOrVal));
458 1 : if (err != CHIP_NO_ERROR)
459 : {
460 0 : chip::Platform::MemoryFree(buf);
461 0 : buf = nullptr;
462 0 : return err;
463 : }
464 :
465 1 : dataLen = static_cast<uint32_t>(mElemLenOrVal);
466 1 : mElemLenOrVal = 0;
467 :
468 1 : return CHIP_NO_ERROR;
469 : }
470 :
471 2 : CHIP_ERROR TLVReader::DupString(char *& buf)
472 : {
473 2 : if (!TLVTypeIsString(ElementType()))
474 1 : return CHIP_ERROR_WRONG_TLV_TYPE;
475 :
476 1 : if (mElemLenOrVal > UINT32_MAX - 1)
477 0 : return CHIP_ERROR_NO_MEMORY;
478 :
479 1 : buf = static_cast<char *>(chip::Platform::MemoryAlloc(static_cast<uint32_t>(mElemLenOrVal + 1)));
480 1 : if (buf == nullptr)
481 0 : return CHIP_ERROR_NO_MEMORY;
482 :
483 1 : CHIP_ERROR err = ReadData(reinterpret_cast<uint8_t *>(buf), static_cast<uint32_t>(mElemLenOrVal));
484 1 : if (err != CHIP_NO_ERROR)
485 : {
486 0 : chip::Platform::MemoryFree(buf);
487 0 : buf = nullptr;
488 0 : return err;
489 : }
490 :
491 1 : buf[mElemLenOrVal] = 0;
492 1 : mElemLenOrVal = 0;
493 :
494 1 : return err;
495 : }
496 :
497 22855 : CHIP_ERROR TLVReader::GetDataPtr(const uint8_t *& data) const
498 : {
499 22855 : VerifyOrReturnError(TLVTypeIsString(ElementType()), CHIP_ERROR_WRONG_TLV_TYPE);
500 :
501 22852 : if (GetLength() == 0)
502 : {
503 3846 : data = nullptr;
504 3846 : return CHIP_NO_ERROR;
505 : }
506 :
507 19006 : uint32_t remainingLen = static_cast<decltype(mMaxLen)>(mBufEnd - mReadPoint);
508 :
509 : // Verify that the entirety of the data is available in the buffer.
510 : // Note that this may not be possible if the reader is reading from a chain of buffers.
511 19006 : VerifyOrReturnError(remainingLen >= static_cast<uint32_t>(mElemLenOrVal), CHIP_ERROR_TLV_UNDERRUN);
512 19002 : data = mReadPoint;
513 19002 : return CHIP_NO_ERROR;
514 : }
515 :
516 1639 : CHIP_ERROR TLVReader::OpenContainer(TLVReader & containerReader)
517 : {
518 1639 : TLVElementType elemType = ElementType();
519 1639 : if (!TLVTypeIsContainer(elemType))
520 1 : return CHIP_ERROR_INCORRECT_STATE;
521 :
522 1638 : containerReader.mBackingStore = mBackingStore;
523 1638 : containerReader.mReadPoint = mReadPoint;
524 1638 : containerReader.mBufEnd = mBufEnd;
525 1638 : containerReader.mLenRead = mLenRead;
526 1638 : containerReader.mMaxLen = mMaxLen;
527 1638 : containerReader.ClearElementState();
528 1638 : containerReader.mContainerType = static_cast<TLVType>(elemType);
529 1638 : containerReader.SetContainerOpen(false);
530 1638 : containerReader.ImplicitProfileId = ImplicitProfileId;
531 1638 : containerReader.AppData = AppData;
532 :
533 1638 : SetContainerOpen(true);
534 :
535 1638 : return CHIP_NO_ERROR;
536 : }
537 :
538 1566 : CHIP_ERROR TLVReader::CloseContainer(TLVReader & containerReader)
539 : {
540 : CHIP_ERROR err;
541 :
542 1566 : if (!IsContainerOpen())
543 1 : return CHIP_ERROR_INCORRECT_STATE;
544 :
545 1565 : if (static_cast<TLVElementType>(containerReader.mContainerType) != ElementType())
546 0 : return CHIP_ERROR_INCORRECT_STATE;
547 :
548 1565 : err = containerReader.SkipToEndOfContainer();
549 1565 : if (err != CHIP_NO_ERROR)
550 0 : return err;
551 :
552 1565 : mBackingStore = containerReader.mBackingStore;
553 1565 : mReadPoint = containerReader.mReadPoint;
554 1565 : mBufEnd = containerReader.mBufEnd;
555 1565 : mLenRead = containerReader.mLenRead;
556 1565 : mMaxLen = containerReader.mMaxLen;
557 1565 : ClearElementState();
558 :
559 1565 : return CHIP_NO_ERROR;
560 : }
561 :
562 2237295 : CHIP_ERROR TLVReader::EnterContainer(TLVType & outerContainerType)
563 : {
564 2237295 : TLVElementType elemType = ElementType();
565 2237295 : if (!TLVTypeIsContainer(elemType))
566 1 : return CHIP_ERROR_INCORRECT_STATE;
567 :
568 2237294 : outerContainerType = mContainerType;
569 2237294 : mContainerType = static_cast<TLVType>(elemType);
570 :
571 2237294 : ClearElementState();
572 2237294 : SetContainerOpen(false);
573 :
574 2237294 : return CHIP_NO_ERROR;
575 : }
576 :
577 375166 : CHIP_ERROR TLVReader::ExitContainer(TLVType outerContainerType)
578 : {
579 : CHIP_ERROR err;
580 :
581 375166 : err = SkipToEndOfContainer();
582 375166 : if (err != CHIP_NO_ERROR)
583 40 : return err;
584 :
585 375126 : mContainerType = outerContainerType;
586 375126 : ClearElementState();
587 :
588 375126 : return CHIP_NO_ERROR;
589 : }
590 :
591 6500 : CHIP_ERROR TLVReader::VerifyEndOfContainer()
592 : {
593 6500 : CHIP_ERROR err = Next();
594 6500 : if (err == CHIP_END_OF_TLV)
595 6499 : return CHIP_NO_ERROR;
596 1 : if (err == CHIP_NO_ERROR)
597 0 : return CHIP_ERROR_UNEXPECTED_TLV_ELEMENT;
598 1 : return err;
599 : }
600 :
601 5761167 : CHIP_ERROR TLVReader::Next()
602 : {
603 5761167 : ReturnErrorOnFailure(Skip());
604 5758346 : ReturnErrorOnFailure(ReadElement());
605 :
606 5740904 : TLVElementType elemType = ElementType();
607 :
608 5740904 : VerifyOrReturnError(elemType != TLVElementType::EndOfContainer, CHIP_END_OF_TLV);
609 :
610 : // Ensure that GetDataPtr calls can be called immediately after Next, so
611 : // that `Get(ByteSpan&)` does not need to advance buffers and just works
612 5549405 : if (TLVTypeIsString(elemType) && (GetLength() != 0))
613 : {
614 29705 : ReturnErrorOnFailure(EnsureData(CHIP_ERROR_TLV_UNDERRUN));
615 : }
616 :
617 5549405 : return CHIP_NO_ERROR;
618 : }
619 :
620 83763 : CHIP_ERROR TLVReader::Expect(Tag expectedTag)
621 : {
622 83763 : VerifyOrReturnError(GetType() != kTLVType_NotSpecified, CHIP_ERROR_WRONG_TLV_TYPE);
623 83759 : VerifyOrReturnError(GetTag() == expectedTag, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
624 83716 : return CHIP_NO_ERROR;
625 : }
626 :
627 83063 : CHIP_ERROR TLVReader::Next(Tag expectedTag)
628 : {
629 83063 : ReturnErrorOnFailure(Next());
630 80932 : ReturnErrorOnFailure(Expect(expectedTag));
631 80892 : return CHIP_NO_ERROR;
632 : }
633 :
634 4709727 : CHIP_ERROR TLVReader::Expect(TLVType expectedType, Tag expectedTag)
635 : {
636 4709727 : VerifyOrReturnError(GetType() == expectedType, CHIP_ERROR_WRONG_TLV_TYPE);
637 4703889 : VerifyOrReturnError(GetTag() == expectedTag, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
638 4665633 : return CHIP_NO_ERROR;
639 : }
640 :
641 4700739 : CHIP_ERROR TLVReader::Next(TLVType expectedType, Tag expectedTag)
642 : {
643 4700739 : ReturnErrorOnFailure(Next());
644 4692968 : ReturnErrorOnFailure(Expect(expectedType, expectedTag));
645 4649857 : return CHIP_NO_ERROR;
646 : }
647 :
648 5788623 : CHIP_ERROR TLVReader::Skip()
649 : {
650 5788623 : const TLVElementType elemType = ElementType();
651 5788623 : VerifyOrReturnError(elemType != TLVElementType::EndOfContainer, CHIP_END_OF_TLV);
652 :
653 5785804 : if (TLVTypeIsContainer(elemType))
654 : {
655 : TLVType outerContainerType;
656 206503 : ReturnErrorOnFailure(EnterContainer(outerContainerType));
657 206503 : return ExitContainer(outerContainerType);
658 : }
659 :
660 5579301 : ReturnErrorOnFailure(SkipData());
661 5579301 : ClearElementState();
662 :
663 5579301 : return CHIP_NO_ERROR;
664 : }
665 :
666 : /**
667 : * Clear the state of the TLVReader.
668 : * This method is used to position the reader before the first TLV,
669 : * between TLVs or after the last TLV.
670 : */
671 9192897 : void TLVReader::ClearElementState()
672 : {
673 9192897 : mElemTag = AnonymousTag();
674 9192897 : mControlByte = kTLVControlByte_NotSpecified;
675 9192897 : mElemLenOrVal = 0;
676 9192897 : }
677 :
678 : /**
679 : * Skip any data contained in the current TLV by reading over it without
680 : * a destination buffer.
681 : *
682 : * @retval #CHIP_NO_ERROR If the reader was successfully positioned at the end of the
683 : * data.
684 : * @retval other Other CHIP or platform error codes returned by the configured
685 : * TLVBackingStore.
686 : */
687 8579072 : CHIP_ERROR TLVReader::SkipData()
688 : {
689 8579072 : CHIP_ERROR err = CHIP_NO_ERROR;
690 8579072 : TLVElementType elemType = ElementType();
691 :
692 8579072 : if (TLVTypeHasLength(elemType))
693 : {
694 241139 : err = ReadData(nullptr, static_cast<uint32_t>(mElemLenOrVal));
695 : }
696 :
697 8579072 : return err;
698 : }
699 :
700 376731 : CHIP_ERROR TLVReader::SkipToEndOfContainer()
701 : {
702 : CHIP_ERROR err;
703 376731 : TLVType outerContainerType = mContainerType;
704 376731 : uint32_t nestLevel = 0;
705 :
706 : // If the user calls Next() after having called OpenContainer() but before calling
707 : // CloseContainer() they're effectively doing a close container by skipping over
708 : // the container element. So reset the 'container open' flag here to prevent them
709 : // from calling CloseContainer() with the now orphaned container reader.
710 376731 : SetContainerOpen(false);
711 :
712 : while (true)
713 : {
714 3376462 : TLVElementType elemType = ElementType();
715 :
716 3376462 : if (elemType == TLVElementType::EndOfContainer)
717 : {
718 944702 : if (nestLevel == 0)
719 376691 : return CHIP_NO_ERROR;
720 :
721 568011 : nestLevel--;
722 568011 : mContainerType = (nestLevel == 0) ? outerContainerType : kTLVType_UnknownContainer;
723 : }
724 :
725 2431760 : else if (TLVTypeIsContainer(elemType))
726 : {
727 568012 : nestLevel++;
728 568012 : mContainerType = static_cast<TLVType>(elemType);
729 : }
730 :
731 2999771 : err = SkipData();
732 2999771 : if (err != CHIP_NO_ERROR)
733 0 : return err;
734 :
735 2999771 : err = ReadElement();
736 2999771 : if (err != CHIP_NO_ERROR)
737 40 : return err;
738 2999731 : }
739 : }
740 :
741 8758117 : CHIP_ERROR TLVReader::ReadElement()
742 : {
743 : // Make sure we have input data. Return CHIP_END_OF_TLV if no more data is available.
744 8758117 : ReturnErrorOnFailure(EnsureData(CHIP_END_OF_TLV));
745 8747948 : VerifyOrReturnError(mReadPoint != nullptr, CHIP_ERROR_INVALID_TLV_ELEMENT);
746 :
747 : // Get the element's control byte.
748 8747948 : mControlByte = *mReadPoint;
749 :
750 : // Extract the element type from the control byte. Fail if it's invalid.
751 8747948 : TLVElementType elemType = ElementType();
752 8747948 : VerifyOrReturnError(IsValidTLVType(elemType), CHIP_ERROR_INVALID_TLV_ELEMENT);
753 :
754 : // Extract the tag control from the control byte.
755 8745156 : TLVTagControl tagControl = static_cast<TLVTagControl>(mControlByte & kTLVTagControlMask);
756 :
757 : // Determine the number of bytes in the element's tag, if any.
758 8745156 : uint8_t tagBytes = sTagSizes[tagControl >> kTLVTagControlShift];
759 :
760 : // Extract the size of length/value field from the control byte.
761 8745156 : TLVFieldSize lenOrValFieldSize = GetTLVFieldSize(elemType);
762 :
763 : // Determine the number of bytes in the length/value field.
764 8745156 : const uint8_t valOrLenBytes = TLVFieldSizeToBytes(lenOrValFieldSize);
765 :
766 : // Determine the number of bytes in the element's 'head'. This includes: the control byte, the tag bytes (if present), the
767 : // length bytes (if present), and for elements that don't have a length (e.g. integers), the value bytes.
768 8745156 : const uint8_t elemHeadBytes = static_cast<uint8_t>(1 + tagBytes + valOrLenBytes);
769 :
770 : // 17 = 1 control byte + 8 tag bytes + 8 length/value bytes
771 : uint8_t stagingBuf[17];
772 :
773 : // Odd workaround: clang-tidy claims garbage value otherwise as it does not
774 : // understand that ReadData initializes stagingBuf
775 8745156 : stagingBuf[1] = 0;
776 :
777 : // If the head of the element goes past the end of the current input buffer,
778 : // we need to read it into the staging buffer to parse it. Just do that unconditionally,
779 : // even if the head does not go past end of current buffer, to save codesize.
780 8745156 : ReturnErrorOnFailure(ReadData(stagingBuf, elemHeadBytes));
781 :
782 : // +1 to skip over the control byte
783 8745156 : const uint8_t * p = stagingBuf + 1;
784 :
785 : // Read the tag field, if present.
786 8745156 : mElemTag = ReadTag(tagControl, p);
787 8745156 : mElemLenOrVal = 0;
788 :
789 : // Read the length/value field, if present.
790 : // NOTE: this is works because even though we only memcpy a subset of values and leave
791 : // the rest 0. Value looks like "<le-byte> <le-byte> ... <le-byte> 0 0 ... 0"
792 : // which is the TLV format. HostSwap ensures this becomes a real host value
793 : // (should be a NOOP on LE machines, will full-swap on big-endian machines)
794 8745156 : memcpy(&mElemLenOrVal, p, valOrLenBytes);
795 8745156 : LittleEndian::HostSwap(mElemLenOrVal);
796 :
797 8745156 : VerifyOrReturnError(!TLVTypeHasLength(elemType) || (mElemLenOrVal <= UINT32_MAX), CHIP_ERROR_NOT_IMPLEMENTED);
798 :
799 8744413 : return VerifyElement();
800 : }
801 :
802 8744413 : CHIP_ERROR TLVReader::VerifyElement()
803 : {
804 8744413 : if (ElementType() == TLVElementType::EndOfContainer)
805 : {
806 993225 : if (mContainerType == kTLVType_NotSpecified)
807 77 : return CHIP_ERROR_INVALID_TLV_ELEMENT;
808 993148 : if (mElemTag != AnonymousTag())
809 282 : return CHIP_ERROR_INVALID_TLV_TAG;
810 : }
811 : else
812 : {
813 7751188 : if (mElemTag == UnknownImplicitTag())
814 0 : return CHIP_ERROR_UNKNOWN_IMPLICIT_TLV_TAG;
815 7751188 : switch (mContainerType)
816 : {
817 1008034 : case kTLVType_NotSpecified:
818 1008034 : if (IsContextTag(mElemTag))
819 228 : return CHIP_ERROR_INVALID_TLV_TAG;
820 1007806 : break;
821 4363255 : case kTLVType_Structure:
822 4363255 : if (mElemTag == AnonymousTag())
823 672 : return CHIP_ERROR_INVALID_TLV_TAG;
824 4362583 : break;
825 1241491 : case kTLVType_Array:
826 1241491 : if (mElemTag != AnonymousTag())
827 1542 : return CHIP_ERROR_INVALID_TLV_TAG;
828 1239949 : break;
829 1138408 : case kTLVType_UnknownContainer:
830 : case kTLVType_List:
831 1138408 : break;
832 0 : default:
833 0 : return CHIP_ERROR_INCORRECT_STATE;
834 : }
835 : }
836 :
837 : // If the current element encodes a specific length (e.g. a UTF8 string or a byte string), verify
838 : // that the purported length fits within the remaining bytes of the encoding (as delineated by mMaxLen).
839 : //
840 : // Note that this check is not strictly necessary to prevent runtime errors, as any attempt to access
841 : // the data of an element with an invalid length will result in an error. However checking the length
842 : // here catches the error earlier, and ensures that the application will never see the erroneous length
843 : // value.
844 : //
845 8741612 : if (TLVTypeHasLength(ElementType()))
846 : {
847 245137 : uint32_t overallLenRemaining = mMaxLen - mLenRead;
848 245137 : if (overallLenRemaining < static_cast<uint32_t>(mElemLenOrVal))
849 977 : return CHIP_ERROR_TLV_UNDERRUN;
850 : }
851 :
852 8740635 : return CHIP_NO_ERROR;
853 : }
854 :
855 8745156 : Tag TLVReader::ReadTag(TLVTagControl tagControl, const uint8_t *& p) const
856 : {
857 : uint16_t vendorId;
858 : uint16_t profileNum;
859 :
860 8745156 : switch (tagControl)
861 : {
862 3599616 : case TLVTagControl::ContextSpecific:
863 3599616 : return ContextTag(Read8(p));
864 1288 : case TLVTagControl::CommonProfile_2Bytes:
865 1288 : return CommonTag(LittleEndian::Read16(p));
866 1610 : case TLVTagControl::CommonProfile_4Bytes:
867 1610 : return CommonTag(LittleEndian::Read32(p));
868 926202 : case TLVTagControl::ImplicitProfile_2Bytes:
869 926202 : if (ImplicitProfileId == kProfileIdNotSpecified)
870 0 : return UnknownImplicitTag();
871 926202 : return ProfileTag(ImplicitProfileId, LittleEndian::Read16(p));
872 2440 : case TLVTagControl::ImplicitProfile_4Bytes:
873 2440 : if (ImplicitProfileId == kProfileIdNotSpecified)
874 0 : return UnknownImplicitTag();
875 2440 : return ProfileTag(ImplicitProfileId, LittleEndian::Read32(p));
876 1904386 : case TLVTagControl::FullyQualified_6Bytes:
877 1904386 : vendorId = LittleEndian::Read16(p);
878 1904386 : profileNum = LittleEndian::Read16(p);
879 1904386 : return ProfileTag(vendorId, profileNum, LittleEndian::Read16(p));
880 1209 : case TLVTagControl::FullyQualified_8Bytes:
881 1209 : vendorId = LittleEndian::Read16(p);
882 1209 : profileNum = LittleEndian::Read16(p);
883 1209 : return ProfileTag(vendorId, profileNum, LittleEndian::Read32(p));
884 2308405 : case TLVTagControl::Anonymous:
885 : default:
886 2308405 : return AnonymousTag();
887 : }
888 : }
889 :
890 9017581 : CHIP_ERROR TLVReader::ReadData(uint8_t * buf, uint32_t len)
891 : {
892 17829858 : while (len > 0)
893 : {
894 8812277 : ReturnErrorOnFailure(EnsureData(CHIP_ERROR_TLV_UNDERRUN));
895 :
896 8812277 : uint32_t remainingLen = static_cast<decltype(mMaxLen)>(mBufEnd - mReadPoint);
897 :
898 8812277 : uint32_t readLen = len;
899 8812277 : if (readLen > remainingLen)
900 156 : readLen = remainingLen;
901 :
902 8812277 : if (buf != nullptr)
903 : {
904 8770592 : memcpy(buf, mReadPoint, readLen);
905 8770592 : buf += readLen;
906 : }
907 8812277 : mReadPoint += readLen;
908 8812277 : mLenRead += readLen;
909 8812277 : len -= readLen;
910 : }
911 :
912 9017581 : return CHIP_NO_ERROR;
913 : }
914 :
915 17600099 : CHIP_ERROR TLVReader::EnsureData(CHIP_ERROR noDataErr)
916 : {
917 17600099 : if (mReadPoint == mBufEnd)
918 : {
919 10455 : VerifyOrReturnError((mLenRead != mMaxLen) && (mBackingStore != nullptr), noDataErr);
920 :
921 : uint32_t bufLen;
922 286 : ReturnErrorOnFailure(mBackingStore->GetNextBuffer(*this, mReadPoint, bufLen));
923 286 : VerifyOrReturnError(bufLen > 0, noDataErr);
924 :
925 : // Cap mBufEnd so that we don't read beyond the user's specified maximum length, even
926 : // if the underlying buffer is larger.
927 286 : bufLen = std::min(bufLen, mMaxLen - mLenRead);
928 286 : mBufEnd = mReadPoint + bufLen;
929 : }
930 :
931 17589930 : return CHIP_NO_ERROR;
932 : }
933 :
934 : /**
935 : * This is a private method used to compute the length of a TLV element head.
936 : */
937 2 : CHIP_ERROR TLVReader::GetElementHeadLength(uint8_t & elemHeadBytes) const
938 : {
939 : uint8_t tagBytes;
940 : uint8_t valOrLenBytes;
941 : TLVTagControl tagControl;
942 : TLVFieldSize lenOrValFieldSize;
943 2 : TLVElementType elemType = ElementType();
944 :
945 : // Verify element is of valid TLVType.
946 2 : VerifyOrReturnError(IsValidTLVType(elemType), CHIP_ERROR_INVALID_TLV_ELEMENT);
947 :
948 : // Extract the tag control from the control byte.
949 2 : tagControl = static_cast<TLVTagControl>(mControlByte & kTLVTagControlMask);
950 :
951 : // Determine the number of bytes in the element's tag, if any.
952 2 : tagBytes = sTagSizes[tagControl >> kTLVTagControlShift];
953 :
954 : // Extract the size of length/value field from the control byte.
955 2 : lenOrValFieldSize = GetTLVFieldSize(elemType);
956 :
957 : // Determine the number of bytes in the length/value field.
958 2 : valOrLenBytes = TLVFieldSizeToBytes(lenOrValFieldSize);
959 :
960 : // Determine the number of bytes in the element's 'head'. This includes: the
961 : // control byte, the tag bytes (if present), the length bytes (if present),
962 : // and for elements that don't have a length (e.g. integers), the value
963 : // bytes.
964 2 : VerifyOrReturnError(CanCastTo<uint8_t>(1 + tagBytes + valOrLenBytes), CHIP_ERROR_INTERNAL);
965 2 : elemHeadBytes = static_cast<uint8_t>(1 + tagBytes + valOrLenBytes);
966 :
967 2 : return CHIP_NO_ERROR;
968 : }
969 :
970 : /**
971 : * This is a private method that returns the TLVElementType from mControlByte
972 : */
973 64470255 : TLVElementType TLVReader::ElementType() const
974 : {
975 64470255 : if (mControlByte == static_cast<uint16_t>(kTLVControlByte_NotSpecified))
976 6950808 : return TLVElementType::NotSpecified;
977 57519447 : return static_cast<TLVElementType>(mControlByte & kTLVTypeMask);
978 : }
979 :
980 153192 : CHIP_ERROR TLVReader::FindElementWithTag(Tag tag, TLVReader & destReader) const
981 : {
982 153192 : CHIP_ERROR err = CHIP_NO_ERROR;
983 :
984 153192 : chip::TLV::TLVReader reader;
985 153192 : reader.Init(*this);
986 :
987 362187 : while (CHIP_NO_ERROR == (err = reader.Next()))
988 : {
989 334042 : VerifyOrExit(chip::TLV::kTLVType_NotSpecified != reader.GetType(), err = CHIP_ERROR_INVALID_TLV_ELEMENT);
990 :
991 334042 : if (tag == reader.GetTag())
992 : {
993 125047 : destReader.Init(reader);
994 125047 : break;
995 : }
996 : }
997 :
998 28145 : exit:
999 153192 : ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
1000 :
1001 153192 : return err;
1002 : }
1003 :
1004 1394 : CHIP_ERROR TLVReader::CountRemainingInContainer(size_t * size) const
1005 : {
1006 1394 : if (mContainerType == kTLVType_NotSpecified)
1007 : {
1008 0 : return CHIP_ERROR_INCORRECT_STATE;
1009 : }
1010 :
1011 1394 : TLVReader tempReader(*this);
1012 1394 : size_t count = 0;
1013 : CHIP_ERROR err;
1014 4187 : while ((err = tempReader.Next()) == CHIP_NO_ERROR)
1015 : {
1016 2793 : ++count;
1017 : };
1018 1394 : if (err == CHIP_END_OF_TLV)
1019 : {
1020 1394 : *size = count;
1021 1394 : return CHIP_NO_ERROR;
1022 : }
1023 0 : return err;
1024 : }
1025 :
1026 10 : CHIP_ERROR ContiguousBufferTLVReader::OpenContainer(ContiguousBufferTLVReader & containerReader)
1027 : {
1028 : // We are going to initialize containerReader by calling our superclass
1029 : // OpenContainer method. The superclass only knows how to initialize
1030 : // members the superclass knows about, so we assert that we don't have any
1031 : // extra members that need initializing. If such members ever get added,
1032 : // they would need to be initialized in this method.
1033 : static_assert(sizeof(ContiguousBufferTLVReader) == sizeof(TLVReader), "We have state the superclass is not initializing?");
1034 10 : return TLVReader::OpenContainer(containerReader);
1035 : }
1036 :
1037 11 : CHIP_ERROR ContiguousBufferTLVReader::GetStringView(Span<const char> & data)
1038 : {
1039 11 : return Get(data);
1040 : }
1041 :
1042 475 : CHIP_ERROR ContiguousBufferTLVReader::GetByteView(ByteSpan & data)
1043 : {
1044 475 : if (!TLVTypeIsByteString(ElementType()))
1045 : {
1046 2 : return CHIP_ERROR_WRONG_TLV_TYPE;
1047 : }
1048 :
1049 473 : return Get(data);
1050 : }
1051 :
1052 : } // namespace TLV
1053 : } // namespace chip
|