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 1612429 : TLVReader::TLVReader() :
53 1612429 : ImplicitProfileId(kProfileIdNotSpecified), AppData(nullptr), mElemLenOrVal(0), mBackingStore(nullptr), mReadPoint(nullptr),
54 1612429 : mBufEnd(nullptr), mLenRead(0), mMaxLen(0), mContainerType(kTLVType_NotSpecified), mControlByte(kTLVControlByte_NotSpecified),
55 1612429 : mContainerOpen(false)
56 1612429 : {}
57 :
58 1010129 : 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 1010129 : uint32_t actualDataLen = dataLen > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(dataLen);
62 1010129 : mBackingStore = nullptr;
63 1010129 : mReadPoint = data;
64 1010129 : mBufEnd = data + actualDataLen;
65 1010129 : mLenRead = 0;
66 1010129 : mMaxLen = actualDataLen;
67 1010129 : ClearElementState();
68 1010129 : mContainerType = kTLVType_NotSpecified;
69 1010129 : SetContainerOpen(false);
70 :
71 1010129 : ImplicitProfileId = kProfileIdNotSpecified;
72 1010129 : }
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 561824 : void TLVReader::Init(const TLVReader & aReader)
96 : {
97 : // Initialize private data members
98 :
99 561824 : mElemTag = aReader.mElemTag;
100 561824 : mElemLenOrVal = aReader.mElemLenOrVal;
101 561824 : mBackingStore = aReader.mBackingStore;
102 561824 : mReadPoint = aReader.mReadPoint;
103 561824 : mBufEnd = aReader.mBufEnd;
104 561824 : mLenRead = aReader.mLenRead;
105 561824 : mMaxLen = aReader.mMaxLen;
106 561824 : mControlByte = aReader.mControlByte;
107 561824 : mContainerType = aReader.mContainerType;
108 561824 : SetContainerOpen(aReader.IsContainerOpen());
109 :
110 : // Initialize public data members
111 :
112 561824 : ImplicitProfileId = aReader.ImplicitProfileId;
113 561824 : AppData = aReader.AppData;
114 561824 : }
115 :
116 5710226 : TLVType TLVReader::GetType() const
117 : {
118 5710226 : TLVElementType elemType = ElementType();
119 5710226 : if (elemType == TLVElementType::EndOfContainer)
120 4 : return kTLVType_NotSpecified;
121 5710222 : if (elemType == TLVElementType::FloatingPointNumber32 || elemType == TLVElementType::FloatingPointNumber64)
122 11634 : return kTLVType_FloatingPointNumber;
123 5698588 : if (elemType == TLVElementType::NotSpecified || elemType >= TLVElementType::Null)
124 2276604 : return static_cast<TLVType>(elemType);
125 3421984 : return static_cast<TLVType>(static_cast<uint8_t>(elemType) & ~kTLVTypeSizeMask);
126 : }
127 :
128 109582 : uint32_t TLVReader::GetLength() const
129 : {
130 109582 : if (TLVTypeHasLength(ElementType()))
131 96443 : return static_cast<uint32_t>(mElemLenOrVal);
132 13139 : return 0;
133 : }
134 :
135 1912961 : CHIP_ERROR TLVReader::Get(bool & v) const
136 : {
137 1912961 : TLVElementType elemType = ElementType();
138 1912961 : if (elemType == TLVElementType::BooleanFalse)
139 949164 : v = false;
140 963797 : else if (elemType == TLVElementType::BooleanTrue)
141 963796 : v = true;
142 : else
143 1 : return CHIP_ERROR_WRONG_TLV_TYPE;
144 1912960 : return CHIP_NO_ERROR;
145 : }
146 :
147 928741 : CHIP_ERROR TLVReader::Get(int8_t & v) const
148 : {
149 928741 : int64_t v64 = 0;
150 928741 : CHIP_ERROR err = Get(v64);
151 928741 : if (!CanCastTo<int8_t>(v64))
152 : {
153 25 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
154 : }
155 928716 : v = static_cast<int8_t>(v64);
156 928716 : return err;
157 : }
158 :
159 926173 : CHIP_ERROR TLVReader::Get(int16_t & v) const
160 : {
161 926173 : int64_t v64 = 0;
162 926173 : CHIP_ERROR err = Get(v64);
163 926173 : if (!CanCastTo<int16_t>(v64))
164 : {
165 4 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
166 : }
167 926169 : v = static_cast<int16_t>(v64);
168 926169 : return err;
169 : }
170 :
171 926552 : CHIP_ERROR TLVReader::Get(int32_t & v) const
172 : {
173 926552 : int64_t v64 = 0;
174 926552 : CHIP_ERROR err = Get(v64);
175 926552 : if (!CanCastTo<int32_t>(v64))
176 : {
177 2 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
178 : }
179 926550 : v = static_cast<int32_t>(v64);
180 926550 : return err;
181 : }
182 :
183 3708724 : CHIP_ERROR TLVReader::Get(int64_t & v) const
184 : {
185 : // Internal callers of this method depend on it not modifying "v" on failure.
186 3708724 : switch (ElementType())
187 : {
188 3707316 : case TLVElementType::Int8:
189 3707316 : v = CastToSigned(static_cast<uint8_t>(mElemLenOrVal));
190 3707316 : break;
191 125 : case TLVElementType::Int16:
192 125 : v = CastToSigned(static_cast<uint16_t>(mElemLenOrVal));
193 125 : break;
194 821 : case TLVElementType::Int32:
195 821 : v = CastToSigned(static_cast<uint32_t>(mElemLenOrVal));
196 821 : break;
197 61 : case TLVElementType::Int64:
198 61 : v = CastToSigned(mElemLenOrVal);
199 61 : break;
200 401 : default:
201 401 : return CHIP_ERROR_WRONG_TLV_TYPE;
202 : }
203 :
204 3708323 : return CHIP_NO_ERROR;
205 : }
206 :
207 967201 : CHIP_ERROR TLVReader::Get(uint8_t & v) const
208 : {
209 967201 : uint64_t v64 = 0;
210 967201 : CHIP_ERROR err = Get(v64);
211 967201 : if (!CanCastTo<uint8_t>(v64))
212 : {
213 3 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
214 : }
215 967198 : v = static_cast<uint8_t>(v64);
216 967198 : return err;
217 : }
218 :
219 76271 : CHIP_ERROR TLVReader::Get(uint16_t & v) const
220 : {
221 76271 : uint64_t v64 = 0;
222 76271 : CHIP_ERROR err = Get(v64);
223 76271 : if (!CanCastTo<uint16_t>(v64))
224 : {
225 4 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
226 : }
227 76267 : v = static_cast<uint16_t>(v64);
228 76267 : return err;
229 : }
230 :
231 88151 : CHIP_ERROR TLVReader::Get(uint32_t & v) const
232 : {
233 88151 : uint64_t v64 = 0;
234 88151 : CHIP_ERROR err = Get(v64);
235 88151 : if (!CanCastTo<uint32_t>(v64))
236 : {
237 1 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
238 : }
239 88150 : v = static_cast<uint32_t>(v64);
240 88150 : return err;
241 : }
242 :
243 1185954 : CHIP_ERROR TLVReader::Get(uint64_t & v) const
244 : {
245 : // Internal callers of this method depend on it not modifying "v" on failure.
246 1185954 : switch (ElementType())
247 : {
248 258642 : case TLVElementType::UInt8:
249 : case TLVElementType::UInt16:
250 : case TLVElementType::UInt32:
251 : case TLVElementType::UInt64:
252 258642 : v = mElemLenOrVal;
253 258642 : break;
254 927312 : default:
255 927312 : return CHIP_ERROR_WRONG_TLV_TYPE;
256 : }
257 258642 : 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 10885 : CHIP_ERROR TLVReader::Get(ByteSpan & v) const
309 : {
310 : const uint8_t * val;
311 10885 : ReturnErrorOnFailure(GetDataPtr(val));
312 10881 : v = ByteSpan(val, GetLength());
313 :
314 10881 : 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 10132 : CHIP_ERROR TLVReader::GetBytes(uint8_t * buf, size_t bufSize)
419 : {
420 10132 : if (!TLVTypeIsString(ElementType()))
421 2 : return CHIP_ERROR_WRONG_TLV_TYPE;
422 :
423 10130 : if (mElemLenOrVal > bufSize)
424 0 : return CHIP_ERROR_BUFFER_TOO_SMALL;
425 :
426 10130 : CHIP_ERROR err = ReadData(buf, static_cast<uint32_t>(mElemLenOrVal));
427 10130 : if (err != CHIP_NO_ERROR)
428 0 : return err;
429 :
430 10130 : mElemLenOrVal = 0;
431 :
432 10130 : return CHIP_NO_ERROR;
433 : }
434 :
435 3183 : CHIP_ERROR TLVReader::GetString(char * buf, size_t bufSize)
436 : {
437 3183 : if (!TLVTypeIsString(ElementType()))
438 1 : return CHIP_ERROR_WRONG_TLV_TYPE;
439 :
440 3182 : if ((mElemLenOrVal + 1) > bufSize)
441 1 : return CHIP_ERROR_BUFFER_TOO_SMALL;
442 :
443 3181 : buf[mElemLenOrVal] = 0;
444 :
445 3181 : 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 22538 : CHIP_ERROR TLVReader::GetDataPtr(const uint8_t *& data) const
498 : {
499 22538 : VerifyOrReturnError(TLVTypeIsString(ElementType()), CHIP_ERROR_WRONG_TLV_TYPE);
500 :
501 22535 : if (GetLength() == 0)
502 : {
503 3846 : data = nullptr;
504 3846 : return CHIP_NO_ERROR;
505 : }
506 :
507 18689 : 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 18689 : VerifyOrReturnError(remainingLen >= static_cast<uint32_t>(mElemLenOrVal), CHIP_ERROR_TLV_UNDERRUN);
512 18685 : data = mReadPoint;
513 18685 : 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 2267239 : CHIP_ERROR TLVReader::EnterContainer(TLVType & outerContainerType)
563 : {
564 2267239 : TLVElementType elemType = ElementType();
565 2267239 : if (!TLVTypeIsContainer(elemType))
566 1 : return CHIP_ERROR_INCORRECT_STATE;
567 :
568 2267238 : outerContainerType = mContainerType;
569 2267238 : mContainerType = static_cast<TLVType>(elemType);
570 :
571 2267238 : ClearElementState();
572 2267238 : SetContainerOpen(false);
573 :
574 2267238 : return CHIP_NO_ERROR;
575 : }
576 :
577 371725 : CHIP_ERROR TLVReader::ExitContainer(TLVType outerContainerType)
578 : {
579 : CHIP_ERROR err;
580 :
581 371725 : err = SkipToEndOfContainer();
582 371725 : if (err != CHIP_NO_ERROR)
583 26 : return err;
584 :
585 371699 : mContainerType = outerContainerType;
586 371699 : ClearElementState();
587 :
588 371699 : return CHIP_NO_ERROR;
589 : }
590 :
591 6428 : CHIP_ERROR TLVReader::VerifyEndOfContainer()
592 : {
593 6428 : CHIP_ERROR err = Next();
594 6428 : if (err == CHIP_END_OF_TLV)
595 6427 : 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 5830767 : CHIP_ERROR TLVReader::Next()
602 : {
603 5830767 : ReturnErrorOnFailure(Skip());
604 5827982 : ReturnErrorOnFailure(ReadElement());
605 :
606 5810676 : TLVElementType elemType = ElementType();
607 :
608 5810676 : 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 5620754 : if (TLVTypeIsString(elemType) && (GetLength() != 0))
613 : {
614 29361 : ReturnErrorOnFailure(EnsureData(CHIP_ERROR_TLV_UNDERRUN));
615 : }
616 :
617 5620754 : return CHIP_NO_ERROR;
618 : }
619 :
620 82766 : CHIP_ERROR TLVReader::Expect(Tag expectedTag)
621 : {
622 82766 : VerifyOrReturnError(GetType() != kTLVType_NotSpecified, CHIP_ERROR_WRONG_TLV_TYPE);
623 82762 : VerifyOrReturnError(GetTag() == expectedTag, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
624 82724 : return CHIP_NO_ERROR;
625 : }
626 :
627 82025 : CHIP_ERROR TLVReader::Next(Tag expectedTag)
628 : {
629 82025 : ReturnErrorOnFailure(Next());
630 79971 : ReturnErrorOnFailure(Expect(expectedTag));
631 79936 : return CHIP_NO_ERROR;
632 : }
633 :
634 4792977 : CHIP_ERROR TLVReader::Expect(TLVType expectedType, Tag expectedTag)
635 : {
636 4792977 : VerifyOrReturnError(GetType() == expectedType, CHIP_ERROR_WRONG_TLV_TYPE);
637 4787058 : VerifyOrReturnError(GetTag() == expectedTag, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
638 4748105 : return CHIP_NO_ERROR;
639 : }
640 :
641 4784308 : CHIP_ERROR TLVReader::Next(TLVType expectedType, Tag expectedTag)
642 : {
643 4784308 : ReturnErrorOnFailure(Next());
644 4776410 : ReturnErrorOnFailure(Expect(expectedType, expectedTag));
645 4732521 : return CHIP_NO_ERROR;
646 : }
647 :
648 5857441 : CHIP_ERROR TLVReader::Skip()
649 : {
650 5857441 : const TLVElementType elemType = ElementType();
651 5857441 : VerifyOrReturnError(elemType != TLVElementType::EndOfContainer, CHIP_END_OF_TLV);
652 :
653 5854658 : if (TLVTypeIsContainer(elemType))
654 : {
655 : TLVType outerContainerType;
656 204087 : ReturnErrorOnFailure(EnterContainer(outerContainerType));
657 204087 : return ExitContainer(outerContainerType);
658 : }
659 :
660 5650571 : ReturnErrorOnFailure(SkipData());
661 5650571 : ClearElementState();
662 :
663 5650571 : 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 9306977 : void TLVReader::ClearElementState()
672 : {
673 9306977 : mElemTag = AnonymousTag();
674 9306977 : mControlByte = kTLVControlByte_NotSpecified;
675 9306977 : mElemLenOrVal = 0;
676 9306977 : }
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 8650848 : CHIP_ERROR TLVReader::SkipData()
688 : {
689 8650848 : CHIP_ERROR err = CHIP_NO_ERROR;
690 8650848 : TLVElementType elemType = ElementType();
691 :
692 8650848 : if (TLVTypeHasLength(elemType))
693 : {
694 250106 : err = ReadData(nullptr, static_cast<uint32_t>(mElemLenOrVal));
695 : }
696 :
697 8650848 : return err;
698 : }
699 :
700 373290 : CHIP_ERROR TLVReader::SkipToEndOfContainer()
701 : {
702 : CHIP_ERROR err;
703 373290 : TLVType outerContainerType = mContainerType;
704 373290 : 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 373290 : SetContainerOpen(false);
711 :
712 : while (true)
713 : {
714 3373541 : TLVElementType elemType = ElementType();
715 :
716 3373541 : if (elemType == TLVElementType::EndOfContainer)
717 : {
718 946796 : if (nestLevel == 0)
719 373264 : return CHIP_NO_ERROR;
720 :
721 573532 : nestLevel--;
722 573532 : mContainerType = (nestLevel == 0) ? outerContainerType : kTLVType_UnknownContainer;
723 : }
724 :
725 2426745 : else if (TLVTypeIsContainer(elemType))
726 : {
727 573533 : nestLevel++;
728 573533 : mContainerType = static_cast<TLVType>(elemType);
729 : }
730 :
731 3000277 : err = SkipData();
732 3000277 : if (err != CHIP_NO_ERROR)
733 0 : return err;
734 :
735 3000277 : err = ReadElement();
736 3000277 : if (err != CHIP_NO_ERROR)
737 26 : return err;
738 3000251 : }
739 : }
740 :
741 8828259 : CHIP_ERROR TLVReader::ReadElement()
742 : {
743 : // Make sure we have input data. Return CHIP_END_OF_TLV if no more data is available.
744 8828259 : ReturnErrorOnFailure(EnsureData(CHIP_END_OF_TLV));
745 8818373 : VerifyOrReturnError(mReadPoint != nullptr, CHIP_ERROR_INVALID_TLV_ELEMENT);
746 :
747 : // Get the element's control byte.
748 8818373 : mControlByte = *mReadPoint;
749 :
750 : // Extract the element type from the control byte. Fail if it's invalid.
751 8818373 : TLVElementType elemType = ElementType();
752 8818373 : VerifyOrReturnError(IsValidTLVType(elemType), CHIP_ERROR_INVALID_TLV_ELEMENT);
753 :
754 : // Extract the tag control from the control byte.
755 8815522 : TLVTagControl tagControl = static_cast<TLVTagControl>(mControlByte & kTLVTagControlMask);
756 :
757 : // Determine the number of bytes in the element's tag, if any.
758 8815522 : uint8_t tagBytes = sTagSizes[tagControl >> kTLVTagControlShift];
759 :
760 : // Extract the size of length/value field from the control byte.
761 8815522 : TLVFieldSize lenOrValFieldSize = GetTLVFieldSize(elemType);
762 :
763 : // Determine the number of bytes in the length/value field.
764 8815522 : 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 8815522 : 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 8815522 : 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 8815522 : ReturnErrorOnFailure(ReadData(stagingBuf, elemHeadBytes));
781 :
782 : // +1 to skip over the control byte
783 8815522 : const uint8_t * p = stagingBuf + 1;
784 :
785 : // Read the tag field, if present.
786 8815522 : mElemTag = ReadTag(tagControl, p);
787 8815522 : 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 8815522 : memcpy(&mElemLenOrVal, p, valOrLenBytes);
795 8815522 : LittleEndian::HostSwap(mElemLenOrVal);
796 :
797 8815522 : VerifyOrReturnError(!TLVTypeHasLength(elemType) || (mElemLenOrVal <= UINT32_MAX), CHIP_ERROR_NOT_IMPLEMENTED);
798 :
799 8814748 : return VerifyElement();
800 : }
801 :
802 8814748 : CHIP_ERROR TLVReader::VerifyElement()
803 : {
804 8814748 : if (ElementType() == TLVElementType::EndOfContainer)
805 : {
806 994290 : if (mContainerType == kTLVType_NotSpecified)
807 100 : return CHIP_ERROR_INVALID_TLV_ELEMENT;
808 994190 : if (mElemTag != AnonymousTag())
809 250 : return CHIP_ERROR_INVALID_TLV_TAG;
810 : }
811 : else
812 : {
813 7820458 : if (mElemTag == UnknownImplicitTag())
814 0 : return CHIP_ERROR_UNKNOWN_IMPLICIT_TLV_TAG;
815 7820458 : switch (mContainerType)
816 : {
817 1024397 : case kTLVType_NotSpecified:
818 1024397 : if (IsContextTag(mElemTag))
819 232 : return CHIP_ERROR_INVALID_TLV_TAG;
820 1024165 : break;
821 4419937 : case kTLVType_Structure:
822 4419937 : if (mElemTag == AnonymousTag())
823 673 : return CHIP_ERROR_INVALID_TLV_TAG;
824 4419264 : break;
825 1240792 : case kTLVType_Array:
826 1240792 : if (mElemTag != AnonymousTag())
827 1532 : return CHIP_ERROR_INVALID_TLV_TAG;
828 1239260 : break;
829 1135332 : case kTLVType_UnknownContainer:
830 : case kTLVType_List:
831 1135332 : 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 8811961 : if (TLVTypeHasLength(ElementType()))
846 : {
847 254166 : uint32_t overallLenRemaining = mMaxLen - mLenRead;
848 254166 : if (overallLenRemaining < static_cast<uint32_t>(mElemLenOrVal))
849 1034 : return CHIP_ERROR_TLV_UNDERRUN;
850 : }
851 :
852 8810927 : return CHIP_NO_ERROR;
853 : }
854 :
855 8815522 : Tag TLVReader::ReadTag(TLVTagControl tagControl, const uint8_t *& p) const
856 : {
857 : uint16_t vendorId;
858 : uint16_t profileNum;
859 :
860 8815522 : switch (tagControl)
861 : {
862 3613320 : case TLVTagControl::ContextSpecific:
863 3613320 : return ContextTag(Read8(p));
864 1250 : case TLVTagControl::CommonProfile_2Bytes:
865 1250 : return CommonTag(LittleEndian::Read16(p));
866 1639 : case TLVTagControl::CommonProfile_4Bytes:
867 1639 : return CommonTag(LittleEndian::Read32(p));
868 942891 : case TLVTagControl::ImplicitProfile_2Bytes:
869 942891 : if (ImplicitProfileId == kProfileIdNotSpecified)
870 0 : return UnknownImplicitTag();
871 942891 : return ProfileTag(ImplicitProfileId, LittleEndian::Read16(p));
872 2445 : case TLVTagControl::ImplicitProfile_4Bytes:
873 2445 : if (ImplicitProfileId == kProfileIdNotSpecified)
874 0 : return UnknownImplicitTag();
875 2445 : return ProfileTag(ImplicitProfileId, LittleEndian::Read32(p));
876 1938744 : case TLVTagControl::FullyQualified_6Bytes:
877 1938744 : vendorId = LittleEndian::Read16(p);
878 1938744 : profileNum = LittleEndian::Read16(p);
879 1938744 : return ProfileTag(vendorId, profileNum, LittleEndian::Read16(p));
880 1208 : case TLVTagControl::FullyQualified_8Bytes:
881 1208 : vendorId = LittleEndian::Read16(p);
882 1208 : profileNum = LittleEndian::Read16(p);
883 1208 : return ProfileTag(vendorId, profileNum, LittleEndian::Read32(p));
884 2314025 : case TLVTagControl::Anonymous:
885 : default:
886 2314025 : return AnonymousTag();
887 : }
888 : }
889 :
890 9096913 : CHIP_ERROR TLVReader::ReadData(uint8_t * buf, uint32_t len)
891 : {
892 17978602 : while (len > 0)
893 : {
894 8881689 : ReturnErrorOnFailure(EnsureData(CHIP_ERROR_TLV_UNDERRUN));
895 :
896 8881689 : uint32_t remainingLen = static_cast<decltype(mMaxLen)>(mBufEnd - mReadPoint);
897 :
898 8881689 : uint32_t readLen = len;
899 8881689 : if (readLen > remainingLen)
900 156 : readLen = remainingLen;
901 :
902 8881689 : if (buf != nullptr)
903 : {
904 8840341 : memcpy(buf, mReadPoint, readLen);
905 8840341 : buf += readLen;
906 : }
907 8881689 : mReadPoint += readLen;
908 8881689 : mLenRead += readLen;
909 8881689 : len -= readLen;
910 : }
911 :
912 9096913 : return CHIP_NO_ERROR;
913 : }
914 :
915 17739309 : CHIP_ERROR TLVReader::EnsureData(CHIP_ERROR noDataErr)
916 : {
917 17739309 : if (mReadPoint == mBufEnd)
918 : {
919 10172 : 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 17729423 : 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 65101345 : TLVElementType TLVReader::ElementType() const
974 : {
975 65101345 : if (mControlByte == static_cast<uint16_t>(kTLVControlByte_NotSpecified))
976 7036760 : return TLVElementType::NotSpecified;
977 58064585 : return static_cast<TLVElementType>(mControlByte & kTLVTypeMask);
978 : }
979 :
980 150443 : CHIP_ERROR TLVReader::FindElementWithTag(Tag tag, TLVReader & destReader) const
981 : {
982 150443 : CHIP_ERROR err = CHIP_NO_ERROR;
983 :
984 150443 : chip::TLV::TLVReader reader;
985 150443 : reader.Init(*this);
986 :
987 354478 : while (CHIP_NO_ERROR == (err = reader.Next()))
988 : {
989 327239 : VerifyOrExit(chip::TLV::kTLVType_NotSpecified != reader.GetType(), err = CHIP_ERROR_INVALID_TLV_ELEMENT);
990 :
991 327239 : if (tag == reader.GetTag())
992 : {
993 123204 : destReader.Init(reader);
994 123204 : break;
995 : }
996 : }
997 :
998 27239 : exit:
999 150443 : ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
1000 :
1001 150443 : 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 305 : CHIP_ERROR ContiguousBufferTLVReader::GetByteView(ByteSpan & data)
1043 : {
1044 305 : if (!TLVTypeIsByteString(ElementType()))
1045 : {
1046 2 : return CHIP_ERROR_WRONG_TLV_TYPE;
1047 : }
1048 :
1049 303 : return Get(data);
1050 : }
1051 :
1052 : } // namespace TLV
1053 : } // namespace chip
|