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 600 : void ASN1Reader::Init(const uint8_t * buf, size_t len)
42 : {
43 600 : ResetElementState();
44 600 : mBuf = buf;
45 600 : mBufEnd = buf + len;
46 600 : mElemStart = buf;
47 600 : mContainerEnd = mBufEnd;
48 600 : mNumSavedContexts = 0;
49 600 : }
50 :
51 28609 : CHIP_ERROR ASN1Reader::Next()
52 : {
53 28609 : VerifyOrReturnError(!EndOfContents, ASN1_END);
54 28609 : 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 28608 : 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 28608 : 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 28608 : VerifyOrReturnError(static_cast<size_t>(mHeadLen) + ValueLen <= static_cast<size_t>(mContainerEnd - mElemStart),
81 : ASN1_ERROR_INVALID_ENCODING);
82 :
83 28606 : mElemStart = mElemStart + mHeadLen + ValueLen;
84 :
85 28606 : ResetElementState();
86 :
87 28606 : VerifyOrReturnError(mElemStart != mContainerEnd, ASN1_END);
88 :
89 17851 : return DecodeHead();
90 : }
91 :
92 8016 : CHIP_ERROR ASN1Reader::EnterConstructedType()
93 : {
94 8016 : VerifyOrReturnError(Constructed, ASN1_ERROR_INVALID_STATE);
95 :
96 8016 : return EnterContainer(0);
97 : }
98 :
99 7745 : CHIP_ERROR ASN1Reader::ExitConstructedType()
100 : {
101 7745 : return ExitContainer();
102 : }
103 :
104 865 : CHIP_ERROR ASN1Reader::GetConstructedType(const uint8_t *& val, uint32_t & valLen)
105 : {
106 865 : 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 864 : 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 864 : VerifyOrReturnError(mHeadLen <= UINT32_MAX - ValueLen, ASN1_ERROR_LENGTH_OVERFLOW);
115 :
116 864 : val = mElemStart;
117 864 : valLen = mHeadLen + ValueLen;
118 :
119 864 : return CHIP_NO_ERROR;
120 : }
121 1044 : CHIP_ERROR ASN1Reader::EnterEncapsulatedType()
122 : {
123 1044 : VerifyOrReturnError(Class == kASN1TagClass_Universal &&
124 : (Tag == kASN1UniversalTag_OctetString || Tag == kASN1UniversalTag_BitString),
125 : ASN1_ERROR_INVALID_STATE);
126 :
127 1044 : VerifyOrReturnError(!Constructed, ASN1_ERROR_UNSUPPORTED_ENCODING);
128 :
129 1044 : return EnterContainer((Tag == kASN1UniversalTag_BitString) ? 1 : 0);
130 : }
131 :
132 1021 : CHIP_ERROR ASN1Reader::ExitEncapsulatedType()
133 : {
134 1021 : return ExitContainer();
135 : }
136 :
137 9060 : CHIP_ERROR ASN1Reader::EnterContainer(uint32_t offset)
138 : {
139 9060 : 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 9060 : if (!IndefiniteLen)
146 : {
147 9060 : VerifyOrReturnError(CanCastTo<uint32_t>(mBufEnd - Value), ASN1_ERROR_VALUE_OVERFLOW);
148 9060 : 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 9060 : mSavedContexts[mNumSavedContexts].ElemStart = mElemStart;
153 9060 : mSavedContexts[mNumSavedContexts].HeadLen = mHeadLen;
154 9060 : mSavedContexts[mNumSavedContexts].ValueLen = ValueLen;
155 9060 : mSavedContexts[mNumSavedContexts].IndefiniteLen = IndefiniteLen;
156 9060 : mSavedContexts[mNumSavedContexts].ContainerEnd = mContainerEnd;
157 9060 : mNumSavedContexts++;
158 :
159 9060 : mElemStart = Value + offset;
160 9060 : if (!IndefiniteLen)
161 : {
162 9060 : mContainerEnd = Value + ValueLen;
163 : }
164 :
165 9060 : ResetElementState();
166 :
167 9060 : return CHIP_NO_ERROR;
168 : }
169 :
170 8766 : CHIP_ERROR ASN1Reader::ExitContainer()
171 : {
172 8766 : 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 8766 : const ASN1ParseContext & prevContext = mSavedContexts[mNumSavedContexts - 1];
179 :
180 8766 : 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 8766 : 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 8766 : 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 8766 : 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 8766 : --mNumSavedContexts;
201 8766 : mElemStart = prevContext.ElemStart + prevContext.HeadLen + prevContext.ValueLen;
202 :
203 8766 : mContainerEnd = prevContext.ContainerEnd;
204 :
205 8766 : ResetElementState();
206 :
207 8766 : return CHIP_NO_ERROR;
208 : }
209 :
210 0 : bool ASN1Reader::IsContained() const
211 : {
212 0 : return mNumSavedContexts > 0;
213 : }
214 :
215 620 : CHIP_ERROR ASN1Reader::GetInteger(int64_t & val)
216 : {
217 620 : uint8_t encodedVal[sizeof(int64_t)] = { 0 };
218 620 : size_t valPaddingLen = sizeof(int64_t) - ValueLen;
219 :
220 620 : VerifyOrReturnError(Value != nullptr, ASN1_ERROR_INVALID_STATE);
221 620 : VerifyOrReturnError(ValueLen >= 1, ASN1_ERROR_INVALID_ENCODING);
222 620 : 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 620 : VerifyOrReturnError(mContainerEnd >= mElemStart, ASN1_ERROR_INVALID_STATE);
229 620 : VerifyOrReturnError(mHeadLen <= UINT32_MAX - ValueLen, ASN1_ERROR_LENGTH_OVERFLOW);
230 620 : VerifyOrReturnError(static_cast<size_t>(mHeadLen) + ValueLen <= static_cast<size_t>(mContainerEnd - mElemStart),
231 : ASN1_ERROR_UNDERRUN);
232 :
233 620 : if ((*Value & 0x80) == 0x80)
234 : {
235 19 : for (size_t i = 0; i < valPaddingLen; i++)
236 : {
237 15 : encodedVal[i] = 0xFF;
238 : }
239 : }
240 620 : memcpy(&encodedVal[valPaddingLen], Value, ValueLen);
241 :
242 620 : val = static_cast<int64_t>(BigEndian::Get64(encodedVal));
243 :
244 620 : return CHIP_NO_ERROR;
245 : }
246 :
247 588 : CHIP_ERROR ASN1Reader::GetBoolean(bool & val)
248 : {
249 588 : VerifyOrReturnError(Value != nullptr, ASN1_ERROR_INVALID_STATE);
250 588 : 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 588 : VerifyOrReturnError(mContainerEnd >= mElemStart, ASN1_ERROR_INVALID_STATE);
255 588 : VerifyOrReturnError(mHeadLen <= UINT32_MAX - ValueLen, ASN1_ERROR_LENGTH_OVERFLOW);
256 588 : VerifyOrReturnError(static_cast<size_t>(mHeadLen) + ValueLen <= static_cast<size_t>(mContainerEnd - mElemStart),
257 : ASN1_ERROR_UNDERRUN);
258 588 : VerifyOrReturnError(Value[0] == 0 || Value[0] == 0xFF, ASN1_ERROR_INVALID_ENCODING);
259 :
260 588 : val = (Value[0] != 0);
261 :
262 588 : return CHIP_NO_ERROR;
263 : }
264 :
265 371 : CHIP_ERROR ASN1Reader::GetUTCTime(ASN1UniversalTime & outTime)
266 : {
267 : // Supported Encoding: YYMMDDHHMMSSZ
268 371 : VerifyOrReturnError(Value != nullptr, ASN1_ERROR_INVALID_STATE);
269 371 : 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 371 : VerifyOrReturnError(mContainerEnd >= mElemStart, ASN1_ERROR_INVALID_STATE);
274 371 : VerifyOrReturnError(mHeadLen <= UINT32_MAX - ValueLen, ASN1_ERROR_LENGTH_OVERFLOW);
275 371 : VerifyOrReturnError(static_cast<size_t>(mHeadLen) + ValueLen <= static_cast<size_t>(mContainerEnd - mElemStart),
276 : ASN1_ERROR_UNDERRUN);
277 371 : VerifyOrReturnError(ValueLen == 13 && Value[12] == 'Z', ASN1_ERROR_UNSUPPORTED_ENCODING);
278 :
279 371 : return outTime.ImportFrom_ASN1_TIME_string(CharSpan(reinterpret_cast<const char *>(Value), ValueLen));
280 : }
281 :
282 62 : CHIP_ERROR ASN1Reader::GetGeneralizedTime(ASN1UniversalTime & outTime)
283 : {
284 : // Supported Encoding: YYYYMMDDHHMMSSZ
285 62 : VerifyOrReturnError(Value != nullptr, ASN1_ERROR_INVALID_STATE);
286 62 : 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 62 : VerifyOrReturnError(mContainerEnd >= mElemStart, ASN1_ERROR_INVALID_STATE);
291 62 : VerifyOrReturnError(mHeadLen <= UINT32_MAX - ValueLen, ASN1_ERROR_LENGTH_OVERFLOW);
292 62 : VerifyOrReturnError(static_cast<size_t>(mHeadLen) + ValueLen <= static_cast<size_t>(mContainerEnd - mElemStart),
293 : ASN1_ERROR_UNDERRUN);
294 62 : VerifyOrReturnError(ValueLen == 15 && Value[14] == 'Z', ASN1_ERROR_UNSUPPORTED_ENCODING);
295 :
296 62 : return outTime.ImportFrom_ASN1_TIME_string(CharSpan(reinterpret_cast<const char *>(Value), ValueLen));
297 : }
298 :
299 205 : static uint8_t ReverseBits(uint8_t v)
300 : {
301 : // swap adjacent bits
302 205 : 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 205 : v = static_cast<uint8_t>(static_cast<uint8_t>((v >> 2) & 0x33) | static_cast<uint8_t>((v & 0x33) << 2));
305 : // swap nibbles
306 205 : v = static_cast<uint8_t>(static_cast<uint8_t>(v >> 4) | static_cast<uint8_t>(v << 4));
307 205 : return v;
308 : }
309 :
310 198 : CHIP_ERROR ASN1Reader::GetBitString(uint32_t & outVal)
311 : {
312 : // NOTE: only supports DER encoding.
313 198 : VerifyOrReturnError(Value != nullptr, ASN1_ERROR_INVALID_STATE);
314 198 : VerifyOrReturnError(ValueLen >= 1, ASN1_ERROR_INVALID_ENCODING);
315 198 : 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 198 : VerifyOrReturnError(mContainerEnd >= mElemStart, ASN1_ERROR_INVALID_STATE);
320 198 : VerifyOrReturnError(mHeadLen <= UINT32_MAX - ValueLen, ASN1_ERROR_LENGTH_OVERFLOW);
321 198 : VerifyOrReturnError(static_cast<size_t>(mHeadLen) + ValueLen <= static_cast<size_t>(mContainerEnd - mElemStart),
322 : ASN1_ERROR_UNDERRUN);
323 :
324 198 : if (ValueLen == 1)
325 : {
326 2 : outVal = 0;
327 : }
328 : else
329 : {
330 196 : outVal = ReverseBits(Value[1]);
331 196 : unsigned int shift = 8;
332 205 : 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 198 : return CHIP_NO_ERROR;
342 : }
343 :
344 17851 : CHIP_ERROR ASN1Reader::DecodeHead()
345 : {
346 17851 : const uint8_t * p = mElemStart;
347 17851 : VerifyOrReturnError(p < mBufEnd, ASN1_ERROR_UNDERRUN);
348 :
349 17851 : Class = *p & 0xC0;
350 17851 : Constructed = (*p & 0x20) != 0;
351 17851 : Tag = *p & 0x1F;
352 :
353 : // Only tags < 31 supported. The implication of this is that encoded tags are exactly 1 byte long.
354 17851 : VerifyOrReturnError(Tag < 0x1F, ASN1_ERROR_UNSUPPORTED_ENCODING);
355 :
356 17845 : p++;
357 17845 : VerifyOrReturnError(p < mBufEnd, ASN1_ERROR_UNDERRUN);
358 :
359 17845 : if ((*p & 0x80) == 0)
360 : {
361 16314 : ValueLen = *p & 0x7F;
362 16314 : IndefiniteLen = false;
363 16314 : p++;
364 : }
365 1531 : else if (*p == 0x80)
366 : {
367 1 : ValueLen = 0;
368 1 : IndefiniteLen = true;
369 1 : p++;
370 : }
371 : else
372 : {
373 1530 : ValueLen = 0;
374 1530 : uint8_t lenLen = *p & 0x7F;
375 1530 : p++;
376 3635 : for (; lenLen > 0; lenLen--, p++)
377 : {
378 2105 : VerifyOrReturnError(p < mBufEnd, ASN1_ERROR_UNDERRUN);
379 2105 : VerifyOrReturnError((ValueLen & 0xFF000000) == 0, ASN1_ERROR_LENGTH_OVERFLOW);
380 2105 : ValueLen = (ValueLen << 8) | *p;
381 : }
382 1530 : IndefiniteLen = false;
383 : }
384 :
385 17845 : VerifyOrReturnError(CanCastTo<uint32_t>(mBufEnd - p), ASN1_ERROR_VALUE_OVERFLOW);
386 17845 : VerifyOrReturnError(static_cast<uint32_t>(mBufEnd - p) >= ValueLen, ASN1_ERROR_VALUE_OVERFLOW);
387 17843 : VerifyOrReturnError(CanCastTo<uint32_t>(p - mElemStart), ASN1_ERROR_VALUE_OVERFLOW);
388 17843 : mHeadLen = static_cast<uint32_t>(p - mElemStart);
389 :
390 17843 : EndOfContents = (Class == kASN1TagClass_Universal && Tag == 0 && !Constructed && ValueLen == 0);
391 :
392 17843 : Value = p;
393 :
394 17843 : return CHIP_NO_ERROR;
395 : }
396 :
397 47032 : void ASN1Reader::ResetElementState()
398 : {
399 47032 : Class = 0;
400 47032 : Tag = 0;
401 47032 : Value = nullptr;
402 47032 : ValueLen = 0;
403 47032 : Constructed = false;
404 47032 : IndefiniteLen = false;
405 47032 : EndOfContents = false;
406 47032 : mHeadLen = 0;
407 47032 : }
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
|