Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2022 Project CHIP Authors
4 : * Copyright (c) 2013-2017 Nest Labs, Inc.
5 : * All rights reserved.
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : /**
21 : * @file
22 : * This file implements an object for reading Abstract Syntax
23 : * Notation One (ASN.1) encoded data.
24 : *
25 : */
26 :
27 : #include <ctype.h>
28 : #include <stdint.h>
29 : #include <stdio.h>
30 : #include <stdlib.h>
31 :
32 : #include <lib/asn1/ASN1.h>
33 : #include <lib/core/CHIPEncoding.h>
34 : #include <lib/support/SafeInt.h>
35 :
36 : namespace chip {
37 : namespace ASN1 {
38 :
39 : using namespace chip::Encoding;
40 :
41 598 : void ASN1Reader::Init(const uint8_t * buf, size_t len)
42 : {
43 598 : ResetElementState();
44 598 : mBuf = buf;
45 598 : mBufEnd = buf + len;
46 598 : mElemStart = buf;
47 598 : mContainerEnd = mBufEnd;
48 598 : mNumSavedContexts = 0;
49 598 : }
50 :
51 28393 : CHIP_ERROR ASN1Reader::Next()
52 : {
53 28393 : VerifyOrReturnError(!EndOfContents, ASN1_END);
54 28393 : VerifyOrReturnError(!IndefiniteLen, ASN1_ERROR_UNSUPPORTED_ENCODING);
55 :
56 : // Defense-in-depth against integer overflow: mHeadLen + ValueLen are both uint32_t and
57 : // their sum could in principle wrap around, advancing mElemStart to an unintended
58 : // location. DecodeHead already caps ValueLen at the remaining buffer, so this cannot
59 : // wrap from any input reaching Next() through the public API; the guard hardens against
60 : // a future caller or a regression in those upstream bounds checks.
61 28392 : VerifyOrReturnError(mHeadLen <= UINT32_MAX - ValueLen, ASN1_ERROR_LENGTH_OVERFLOW);
62 : // Defend against an inconsistent reader state where mElemStart has advanced past
63 : // mContainerEnd (e.g. a prior failed unwind left stale pointers). Without this
64 : // check the pointer subtraction below would underflow when cast to size_t and the
65 : // bounds comparison would silently pass.
66 28392 : VerifyOrReturnError(mContainerEnd >= mElemStart, ASN1_ERROR_INVALID_STATE);
67 : // Compare in integer space rather than pointer space. On 32-bit targets size_t == uint32_t,
68 : // so the size_t cast provides no additional width; the preceding LENGTH_OVERFLOW guard is
69 : // what prevents wrap there. The size_t widening eliminates pointer-arithmetic UB on 64-bit
70 : // targets where computing `mElemStart + mHeadLen + ValueLen` could otherwise wrap past the
71 : // end of the address space before the comparison runs.
72 : //
73 : // BEHAVIOR CHANGE: a bounds-exceeded result here means a child element claims more bytes
74 : // than its parent container holds (malformed encoding). Previously this advanced mElemStart
75 : // past mContainerEnd and the subsequent `mElemStart != mContainerEnd` check returned ASN1_END,
76 : // which callers (and the ASN1_EXIT_* macros) treat as a clean end of container -- silently
77 : // swallowing the malformed input. It now surfaces as ASN1_ERROR_INVALID_ENCODING. A child
78 : // ending exactly at mContainerEnd still passes this `<=` check and reports ASN1_END as before,
79 : // so well-formed certificates are unaffected.
80 28392 : VerifyOrReturnError(static_cast<size_t>(mHeadLen) + ValueLen <= static_cast<size_t>(mContainerEnd - mElemStart),
81 : ASN1_ERROR_INVALID_ENCODING);
82 :
83 28390 : mElemStart = mElemStart + mHeadLen + ValueLen;
84 :
85 28390 : ResetElementState();
86 :
87 28390 : VerifyOrReturnError(mElemStart != mContainerEnd, ASN1_END);
88 :
89 17723 : return DecodeHead();
90 : }
91 :
92 7960 : CHIP_ERROR ASN1Reader::EnterConstructedType()
93 : {
94 7960 : VerifyOrReturnError(Constructed, ASN1_ERROR_INVALID_STATE);
95 :
96 7960 : return EnterContainer(0);
97 : }
98 :
99 7689 : CHIP_ERROR ASN1Reader::ExitConstructedType()
100 : {
101 7689 : return ExitContainer();
102 : }
103 :
104 856 : CHIP_ERROR ASN1Reader::GetConstructedType(const uint8_t *& val, uint32_t & valLen)
105 : {
106 856 : VerifyOrReturnError(Constructed, ASN1_ERROR_INVALID_STATE);
107 :
108 : // Defend against an inconsistent reader state where mElemStart has advanced past
109 : // mContainerEnd. Required ahead of any size_t-widened subtraction so the result
110 : // cannot underflow.
111 855 : VerifyOrReturnError(mContainerEnd >= mElemStart, ASN1_ERROR_INVALID_STATE);
112 : // Guard against integer overflow: mHeadLen + ValueLen are both uint32_t and their sum
113 : // could wrap around, producing a bogus length for the caller.
114 855 : VerifyOrReturnError(mHeadLen <= UINT32_MAX - ValueLen, ASN1_ERROR_LENGTH_OVERFLOW);
115 :
116 855 : val = mElemStart;
117 855 : valLen = mHeadLen + ValueLen;
118 :
119 855 : return CHIP_NO_ERROR;
120 : }
121 1033 : CHIP_ERROR ASN1Reader::EnterEncapsulatedType()
122 : {
123 1033 : VerifyOrReturnError(Class == kASN1TagClass_Universal &&
124 : (Tag == kASN1UniversalTag_OctetString || Tag == kASN1UniversalTag_BitString),
125 : ASN1_ERROR_INVALID_STATE);
126 :
127 1033 : VerifyOrReturnError(!Constructed, ASN1_ERROR_UNSUPPORTED_ENCODING);
128 :
129 1033 : return EnterContainer((Tag == kASN1UniversalTag_BitString) ? 1 : 0);
130 : }
131 :
132 1010 : CHIP_ERROR ASN1Reader::ExitEncapsulatedType()
133 : {
134 1010 : return ExitContainer();
135 : }
136 :
137 8993 : CHIP_ERROR ASN1Reader::EnterContainer(uint32_t offset)
138 : {
139 8993 : VerifyOrReturnError(mNumSavedContexts != kMaxContextDepth, ASN1_ERROR_MAX_DEPTH_EXCEEDED);
140 :
141 : // Peek-then-commit: validate all preconditions BEFORE mutating reader
142 : // state. If any guard fires the saved-context stack, mElemStart, and
143 : // mContainerEnd are all left untouched so the reader stays in a
144 : // consistent state.
145 8993 : if (!IndefiniteLen)
146 : {
147 8993 : VerifyOrReturnError(CanCastTo<uint32_t>(mBufEnd - Value), ASN1_ERROR_VALUE_OVERFLOW);
148 8993 : VerifyOrReturnError(static_cast<uint32_t>(mBufEnd - Value) >= ValueLen, ASN1_ERROR_VALUE_OVERFLOW);
149 : }
150 :
151 : // All checks passed - now commit by pushing the saved context and updating reader state.
152 8993 : mSavedContexts[mNumSavedContexts].ElemStart = mElemStart;
153 8993 : mSavedContexts[mNumSavedContexts].HeadLen = mHeadLen;
154 8993 : mSavedContexts[mNumSavedContexts].ValueLen = ValueLen;
155 8993 : mSavedContexts[mNumSavedContexts].IndefiniteLen = IndefiniteLen;
156 8993 : mSavedContexts[mNumSavedContexts].ContainerEnd = mContainerEnd;
157 8993 : mNumSavedContexts++;
158 :
159 8993 : mElemStart = Value + offset;
160 8993 : if (!IndefiniteLen)
161 : {
162 8993 : mContainerEnd = Value + ValueLen;
163 : }
164 :
165 8993 : ResetElementState();
166 :
167 8993 : return CHIP_NO_ERROR;
168 : }
169 :
170 8699 : CHIP_ERROR ASN1Reader::ExitContainer()
171 : {
172 8699 : VerifyOrReturnError(mNumSavedContexts != 0, ASN1_ERROR_INVALID_STATE);
173 :
174 : // Peek-then-commit: validate the saved context BEFORE mutating any reader
175 : // state. On any error the saved-context stack is left untouched so the
176 : // reader stays in a consistent state and a follow-up call sees the same
177 : // failure (rather than silently operating on a half-popped stack).
178 8699 : const ASN1ParseContext & prevContext = mSavedContexts[mNumSavedContexts - 1];
179 :
180 8699 : VerifyOrReturnError(!prevContext.IndefiniteLen, ASN1_ERROR_UNSUPPORTED_ENCODING);
181 :
182 : // Guard against integer overflow: HeadLen + ValueLen are both uint32_t and their sum
183 : // could wrap around, potentially advancing mElemStart to an unintended location.
184 8699 : VerifyOrReturnError(prevContext.HeadLen <= UINT32_MAX - prevContext.ValueLen, ASN1_ERROR_LENGTH_OVERFLOW);
185 : // Defend against a saved context with ContainerEnd < ElemStart so the pointer
186 : // subtraction below cannot underflow when widened to size_t.
187 8699 : VerifyOrReturnError(prevContext.ContainerEnd >= prevContext.ElemStart, ASN1_ERROR_INVALID_STATE);
188 : // Compare in integer space rather than pointer space. On 32-bit targets size_t == uint32_t
189 : // and the LENGTH_OVERFLOW guard above is what prevents wrap; the size_t widening eliminates
190 : // pointer-arithmetic UB on 64-bit targets where `prevContext.ElemStart + prevContext.HeadLen
191 : // + prevContext.ValueLen` could otherwise wrap past the end of the address space. A
192 : // bounds-exceeded result here means the saved container declared more bytes than its parent
193 : // holds (malformed encoding), NOT a clean end of container, so it must surface as
194 : // INVALID_ENCODING rather than ASN1_END.
195 8699 : VerifyOrReturnError(static_cast<size_t>(prevContext.HeadLen) + prevContext.ValueLen <=
196 : static_cast<size_t>(prevContext.ContainerEnd - prevContext.ElemStart),
197 : ASN1_ERROR_INVALID_ENCODING);
198 :
199 : // All checks passed - now commit by popping the saved context and updating reader state.
200 8699 : --mNumSavedContexts;
201 8699 : mElemStart = prevContext.ElemStart + prevContext.HeadLen + prevContext.ValueLen;
202 :
203 8699 : mContainerEnd = prevContext.ContainerEnd;
204 :
205 8699 : ResetElementState();
206 :
207 8699 : return CHIP_NO_ERROR;
208 : }
209 :
210 0 : bool ASN1Reader::IsContained() const
211 : {
212 0 : return mNumSavedContexts > 0;
213 : }
214 :
215 618 : CHIP_ERROR ASN1Reader::GetInteger(int64_t & val)
216 : {
217 618 : uint8_t encodedVal[sizeof(int64_t)] = { 0 };
218 618 : size_t valPaddingLen = sizeof(int64_t) - ValueLen;
219 :
220 618 : VerifyOrReturnError(Value != nullptr, ASN1_ERROR_INVALID_STATE);
221 618 : VerifyOrReturnError(ValueLen >= 1, ASN1_ERROR_INVALID_ENCODING);
222 618 : VerifyOrReturnError(ValueLen <= sizeof(int64_t), ASN1_ERROR_VALUE_OVERFLOW);
223 : // Mirrors the guard sequence in Next(): (1) reject inconsistent state where
224 : // mContainerEnd < mElemStart (without this the size_t-widened subtraction below would
225 : // underflow to a huge value and the bounds compare would trivially pass), (2) reject
226 : // mHeadLen + ValueLen wrap on 32-bit targets where size_t == uint32_t, (3) bounds-check
227 : // via the size_t-widened comparison.
228 618 : VerifyOrReturnError(mContainerEnd >= mElemStart, ASN1_ERROR_INVALID_STATE);
229 618 : VerifyOrReturnError(mHeadLen <= UINT32_MAX - ValueLen, ASN1_ERROR_LENGTH_OVERFLOW);
230 618 : VerifyOrReturnError(static_cast<size_t>(mHeadLen) + ValueLen <= static_cast<size_t>(mContainerEnd - mElemStart),
231 : ASN1_ERROR_UNDERRUN);
232 :
233 618 : if ((*Value & 0x80) == 0x80)
234 : {
235 19 : for (size_t i = 0; i < valPaddingLen; i++)
236 : {
237 15 : encodedVal[i] = 0xFF;
238 : }
239 : }
240 618 : memcpy(&encodedVal[valPaddingLen], Value, ValueLen);
241 :
242 618 : val = static_cast<int64_t>(BigEndian::Get64(encodedVal));
243 :
244 618 : return CHIP_NO_ERROR;
245 : }
246 :
247 582 : CHIP_ERROR ASN1Reader::GetBoolean(bool & val)
248 : {
249 582 : VerifyOrReturnError(Value != nullptr, ASN1_ERROR_INVALID_STATE);
250 582 : VerifyOrReturnError(ValueLen == 1, ASN1_ERROR_INVALID_ENCODING);
251 : // Mirrors the guard sequence in Next(): (1) reject inconsistent state where
252 : // mContainerEnd < mElemStart, (2) reject mHeadLen + ValueLen wrap on 32-bit
253 : // (size_t == uint32_t), (3) bounds-check via size_t-widened comparison.
254 582 : VerifyOrReturnError(mContainerEnd >= mElemStart, ASN1_ERROR_INVALID_STATE);
255 582 : VerifyOrReturnError(mHeadLen <= UINT32_MAX - ValueLen, ASN1_ERROR_LENGTH_OVERFLOW);
256 582 : VerifyOrReturnError(static_cast<size_t>(mHeadLen) + ValueLen <= static_cast<size_t>(mContainerEnd - mElemStart),
257 : ASN1_ERROR_UNDERRUN);
258 582 : VerifyOrReturnError(Value[0] == 0 || Value[0] == 0xFF, ASN1_ERROR_INVALID_ENCODING);
259 :
260 582 : val = (Value[0] != 0);
261 :
262 582 : return CHIP_NO_ERROR;
263 : }
264 :
265 369 : CHIP_ERROR ASN1Reader::GetUTCTime(ASN1UniversalTime & outTime)
266 : {
267 : // Supported Encoding: YYMMDDHHMMSSZ
268 369 : VerifyOrReturnError(Value != nullptr, ASN1_ERROR_INVALID_STATE);
269 369 : VerifyOrReturnError(ValueLen >= 1, ASN1_ERROR_INVALID_ENCODING);
270 : // Mirrors the guard sequence in Next(): (1) reject inconsistent state where
271 : // mContainerEnd < mElemStart, (2) reject mHeadLen + ValueLen wrap on 32-bit
272 : // (size_t == uint32_t), (3) bounds-check via size_t-widened comparison.
273 369 : VerifyOrReturnError(mContainerEnd >= mElemStart, ASN1_ERROR_INVALID_STATE);
274 369 : VerifyOrReturnError(mHeadLen <= UINT32_MAX - ValueLen, ASN1_ERROR_LENGTH_OVERFLOW);
275 369 : VerifyOrReturnError(static_cast<size_t>(mHeadLen) + ValueLen <= static_cast<size_t>(mContainerEnd - mElemStart),
276 : ASN1_ERROR_UNDERRUN);
277 369 : VerifyOrReturnError(ValueLen == 13 && Value[12] == 'Z', ASN1_ERROR_UNSUPPORTED_ENCODING);
278 :
279 369 : return outTime.ImportFrom_ASN1_TIME_string(CharSpan(reinterpret_cast<const char *>(Value), ValueLen));
280 : }
281 :
282 60 : CHIP_ERROR ASN1Reader::GetGeneralizedTime(ASN1UniversalTime & outTime)
283 : {
284 : // Supported Encoding: YYYYMMDDHHMMSSZ
285 60 : VerifyOrReturnError(Value != nullptr, ASN1_ERROR_INVALID_STATE);
286 60 : VerifyOrReturnError(ValueLen >= 1, ASN1_ERROR_INVALID_ENCODING);
287 : // Mirrors the guard sequence in Next(): (1) reject inconsistent state where
288 : // mContainerEnd < mElemStart, (2) reject mHeadLen + ValueLen wrap on 32-bit
289 : // (size_t == uint32_t), (3) bounds-check via size_t-widened comparison.
290 60 : VerifyOrReturnError(mContainerEnd >= mElemStart, ASN1_ERROR_INVALID_STATE);
291 60 : VerifyOrReturnError(mHeadLen <= UINT32_MAX - ValueLen, ASN1_ERROR_LENGTH_OVERFLOW);
292 60 : VerifyOrReturnError(static_cast<size_t>(mHeadLen) + ValueLen <= static_cast<size_t>(mContainerEnd - mElemStart),
293 : ASN1_ERROR_UNDERRUN);
294 60 : VerifyOrReturnError(ValueLen == 15 && Value[14] == 'Z', ASN1_ERROR_UNSUPPORTED_ENCODING);
295 :
296 60 : return outTime.ImportFrom_ASN1_TIME_string(CharSpan(reinterpret_cast<const char *>(Value), ValueLen));
297 : }
298 :
299 203 : static uint8_t ReverseBits(uint8_t v)
300 : {
301 : // swap adjacent bits
302 203 : v = static_cast<uint8_t>(static_cast<uint8_t>((v >> 1) & 0x55) | static_cast<uint8_t>((v & 0x55) << 1));
303 : // swap adjacent bit pairs
304 203 : v = static_cast<uint8_t>(static_cast<uint8_t>((v >> 2) & 0x33) | static_cast<uint8_t>((v & 0x33) << 2));
305 : // swap nibbles
306 203 : v = static_cast<uint8_t>(static_cast<uint8_t>(v >> 4) | static_cast<uint8_t>(v << 4));
307 203 : return v;
308 : }
309 :
310 196 : CHIP_ERROR ASN1Reader::GetBitString(uint32_t & outVal)
311 : {
312 : // NOTE: only supports DER encoding.
313 196 : VerifyOrReturnError(Value != nullptr, ASN1_ERROR_INVALID_STATE);
314 196 : VerifyOrReturnError(ValueLen >= 1, ASN1_ERROR_INVALID_ENCODING);
315 196 : VerifyOrReturnError(ValueLen <= 5, ASN1_ERROR_UNSUPPORTED_ENCODING);
316 : // Mirrors the guard sequence in Next(): (1) reject inconsistent state where
317 : // mContainerEnd < mElemStart, (2) reject mHeadLen + ValueLen wrap on 32-bit
318 : // (size_t == uint32_t), (3) bounds-check via size_t-widened comparison.
319 196 : VerifyOrReturnError(mContainerEnd >= mElemStart, ASN1_ERROR_INVALID_STATE);
320 196 : VerifyOrReturnError(mHeadLen <= UINT32_MAX - ValueLen, ASN1_ERROR_LENGTH_OVERFLOW);
321 196 : VerifyOrReturnError(static_cast<size_t>(mHeadLen) + ValueLen <= static_cast<size_t>(mContainerEnd - mElemStart),
322 : ASN1_ERROR_UNDERRUN);
323 :
324 196 : if (ValueLen == 1)
325 : {
326 2 : outVal = 0;
327 : }
328 : else
329 : {
330 194 : outVal = ReverseBits(Value[1]);
331 194 : unsigned int shift = 8;
332 203 : for (uint32_t i = 2; i < ValueLen; i++, shift += 8)
333 : {
334 : // Cast to uint32_t before shifting: ReverseBits returns uint8_t which
335 : // would be promoted to (signed) int, and shifts of 24+ on a value with
336 : // the high bit set are undefined behavior on signed integers.
337 9 : outVal |= (static_cast<uint32_t>(ReverseBits(Value[i])) << shift);
338 : }
339 : }
340 :
341 196 : return CHIP_NO_ERROR;
342 : }
343 :
344 17723 : CHIP_ERROR ASN1Reader::DecodeHead()
345 : {
346 17723 : const uint8_t * p = mElemStart;
347 17723 : VerifyOrReturnError(p < mBufEnd, ASN1_ERROR_UNDERRUN);
348 :
349 17723 : Class = *p & 0xC0;
350 17723 : Constructed = (*p & 0x20) != 0;
351 17723 : Tag = *p & 0x1F;
352 :
353 : // Only tags < 31 supported. The implication of this is that encoded tags are exactly 1 byte long.
354 17723 : VerifyOrReturnError(Tag < 0x1F, ASN1_ERROR_UNSUPPORTED_ENCODING);
355 :
356 17717 : p++;
357 17717 : VerifyOrReturnError(p < mBufEnd, ASN1_ERROR_UNDERRUN);
358 :
359 17717 : if ((*p & 0x80) == 0)
360 : {
361 16192 : ValueLen = *p & 0x7F;
362 16192 : IndefiniteLen = false;
363 16192 : p++;
364 : }
365 1525 : else if (*p == 0x80)
366 : {
367 1 : ValueLen = 0;
368 1 : IndefiniteLen = true;
369 1 : p++;
370 : }
371 : else
372 : {
373 1524 : ValueLen = 0;
374 1524 : uint8_t lenLen = *p & 0x7F;
375 1524 : p++;
376 3619 : for (; lenLen > 0; lenLen--, p++)
377 : {
378 2095 : VerifyOrReturnError(p < mBufEnd, ASN1_ERROR_UNDERRUN);
379 2095 : VerifyOrReturnError((ValueLen & 0xFF000000) == 0, ASN1_ERROR_LENGTH_OVERFLOW);
380 2095 : ValueLen = (ValueLen << 8) | *p;
381 : }
382 1524 : IndefiniteLen = false;
383 : }
384 :
385 17717 : VerifyOrReturnError(CanCastTo<uint32_t>(mBufEnd - p), ASN1_ERROR_VALUE_OVERFLOW);
386 17717 : VerifyOrReturnError(static_cast<uint32_t>(mBufEnd - p) >= ValueLen, ASN1_ERROR_VALUE_OVERFLOW);
387 17715 : VerifyOrReturnError(CanCastTo<uint32_t>(p - mElemStart), ASN1_ERROR_VALUE_OVERFLOW);
388 17715 : mHeadLen = static_cast<uint32_t>(p - mElemStart);
389 :
390 17715 : EndOfContents = (Class == kASN1TagClass_Universal && Tag == 0 && !Constructed && ValueLen == 0);
391 :
392 17715 : Value = p;
393 :
394 17715 : return CHIP_NO_ERROR;
395 : }
396 :
397 46680 : void ASN1Reader::ResetElementState()
398 : {
399 46680 : Class = 0;
400 46680 : Tag = 0;
401 46680 : Value = nullptr;
402 46680 : ValueLen = 0;
403 46680 : Constructed = false;
404 46680 : IndefiniteLen = false;
405 46680 : EndOfContents = false;
406 46680 : mHeadLen = 0;
407 46680 : }
408 :
409 0 : CHIP_ERROR DumpASN1(ASN1Reader & asn1Parser, const char * prefix, const char * indent)
410 : {
411 0 : CHIP_ERROR err = CHIP_NO_ERROR;
412 :
413 0 : if (indent == nullptr)
414 0 : indent = " ";
415 :
416 0 : int nestLevel = 0;
417 : while (true)
418 : {
419 0 : err = asn1Parser.Next();
420 0 : if (err != CHIP_NO_ERROR)
421 : {
422 0 : if (err == ASN1_END)
423 : {
424 0 : if (asn1Parser.IsContained())
425 : {
426 0 : err = asn1Parser.ExitConstructedType();
427 0 : if (err != CHIP_NO_ERROR)
428 : {
429 0 : printf("ASN1Reader::ExitConstructedType() failed: %" CHIP_ERROR_FORMAT "\n", err.Format());
430 0 : return err;
431 : }
432 0 : nestLevel--;
433 0 : continue;
434 : }
435 0 : break;
436 : }
437 0 : printf("ASN1Reader::Next() failed: %" CHIP_ERROR_FORMAT "\n", err.Format());
438 0 : return err;
439 : }
440 0 : if (prefix != nullptr)
441 0 : printf("%s", prefix);
442 0 : for (int i = nestLevel; i; i--)
443 0 : printf("%s", indent);
444 0 : if (asn1Parser.IsEndOfContents())
445 0 : printf("END-OF-CONTENTS ");
446 0 : else if (asn1Parser.GetClass() == kASN1TagClass_Universal)
447 0 : switch (asn1Parser.GetTag())
448 : {
449 0 : case kASN1UniversalTag_Boolean:
450 0 : printf("BOOLEAN ");
451 0 : break;
452 0 : case kASN1UniversalTag_Integer:
453 0 : printf("INTEGER ");
454 0 : break;
455 0 : case kASN1UniversalTag_BitString:
456 0 : printf("BIT STRING ");
457 0 : break;
458 0 : case kASN1UniversalTag_OctetString:
459 0 : printf("OCTET STRING ");
460 0 : break;
461 0 : case kASN1UniversalTag_Null:
462 0 : printf("NULL ");
463 0 : break;
464 0 : case kASN1UniversalTag_ObjectId:
465 0 : printf("OBJECT IDENTIFIER ");
466 0 : break;
467 0 : case kASN1UniversalTag_ObjectDesc:
468 0 : printf("OBJECT DESCRIPTOR ");
469 0 : break;
470 0 : case kASN1UniversalTag_External:
471 0 : printf("EXTERNAL ");
472 0 : break;
473 0 : case kASN1UniversalTag_Real:
474 0 : printf("REAL ");
475 0 : break;
476 0 : case kASN1UniversalTag_Enumerated:
477 0 : printf("ENUMERATED ");
478 0 : break;
479 0 : case kASN1UniversalTag_Sequence:
480 0 : printf("SEQUENCE ");
481 0 : break;
482 0 : case kASN1UniversalTag_Set:
483 0 : printf("SET ");
484 0 : break;
485 0 : case kASN1UniversalTag_UTF8String:
486 : case kASN1UniversalTag_NumericString:
487 : case kASN1UniversalTag_PrintableString:
488 : case kASN1UniversalTag_T61String:
489 : case kASN1UniversalTag_VideotexString:
490 : case kASN1UniversalTag_IA5String:
491 : case kASN1UniversalTag_GraphicString:
492 : case kASN1UniversalTag_VisibleString:
493 : case kASN1UniversalTag_GeneralString:
494 : case kASN1UniversalTag_UniversalString:
495 0 : printf("STRING ");
496 0 : break;
497 0 : case kASN1UniversalTag_UTCTime:
498 : case kASN1UniversalTag_GeneralizedTime:
499 0 : printf("TIME ");
500 0 : break;
501 0 : default:
502 0 : printf("[UNIVERSAL %lu] ", static_cast<unsigned long>(asn1Parser.GetTag()));
503 0 : break;
504 : }
505 0 : else if (asn1Parser.GetClass() == kASN1TagClass_Application)
506 0 : printf("[APPLICATION %lu] ", static_cast<unsigned long>(asn1Parser.GetTag()));
507 0 : else if (asn1Parser.GetClass() == kASN1TagClass_ContextSpecific)
508 0 : printf("[%lu] ", static_cast<unsigned long>(asn1Parser.GetTag()));
509 0 : else if (asn1Parser.GetClass() == kASN1TagClass_Private)
510 0 : printf("[PRIVATE %lu] ", static_cast<unsigned long>(asn1Parser.GetTag()));
511 :
512 0 : if (asn1Parser.IsConstructed())
513 0 : printf("(constructed) ");
514 :
515 0 : if (asn1Parser.IsIndefiniteLen())
516 0 : printf("Length = indefinite\n");
517 : else
518 0 : printf("Length = %ld\n", static_cast<long>(asn1Parser.GetValueLen()));
519 :
520 0 : if (asn1Parser.IsConstructed())
521 : {
522 0 : err = asn1Parser.EnterConstructedType();
523 0 : if (err != CHIP_NO_ERROR)
524 : {
525 0 : printf("ASN1Reader::EnterConstructedType() failed: %" CHIP_ERROR_FORMAT "\n", err.Format());
526 0 : return err;
527 : }
528 0 : nestLevel++;
529 : }
530 0 : }
531 :
532 0 : return err;
533 : }
534 :
535 : } // namespace ASN1
536 : } // namespace chip
|