VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/asn1/asn1-dump.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.9 KB
Line 
1/* $Id: asn1-dump.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - ASN.1, Structure Dumper.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "internal/iprt.h"
42#include <iprt/asn1.h>
43
44#include <iprt/errcore.h>
45#include <iprt/log.h>
46#ifdef IN_RING3
47# include <iprt/stream.h>
48#endif
49#include <iprt/string.h>
50
51#include <iprt/formats/asn1.h>
52
53
54/*********************************************************************************************************************************
55* Structures and Typedefs *
56*********************************************************************************************************************************/
57/**
58 * Dump data structure.
59 */
60typedef struct RTASN1DUMPDATA
61{
62 /** RTASN1DUMP_F_XXX. */
63 uint32_t fFlags;
64 /** The printfv like output function. */
65 PFNRTDUMPPRINTFV pfnPrintfV;
66 /** PrintfV user argument. */
67 void *pvUser;
68} RTASN1DUMPDATA;
69/** Pointer to a dump data structure. */
70typedef RTASN1DUMPDATA *PRTASN1DUMPDATA;
71
72
73#ifndef IN_SUP_HARDENED_R3
74
75/*
76 * Since we're the only user of OIDs, this stuff lives here.
77 * Should that ever change, this code needs to move elsewhere and get it's own public API.
78 */
79# include "oiddb.h"
80
81
82/**
83 * Searches a range in the big table for a key.
84 *
85 * @returns Pointer to the matching entry. NULL if not found.
86 * @param iEntry The start of the range.
87 * @param cEntries The number of entries in the range.
88 * @param uKey The key to find.
89 */
90DECLINLINE(PCRTOIDENTRYBIG) rtOidDbLookupBig(uint32_t iEntry, uint32_t cEntries, uint32_t uKey)
91{
92 /* Not worth doing binary search here, too few entries. */
93 while (cEntries-- > 0)
94 {
95 uint32_t const uThisKey = g_aBigOidTable[iEntry].uKey;
96 if (uThisKey >= uKey)
97 {
98 if (uThisKey == uKey)
99 return &g_aBigOidTable[iEntry];
100 break;
101 }
102 iEntry++;
103 }
104 return NULL;
105}
106
107
108/**
109 * Searches a range in the small table for a key.
110 *
111 * @returns Pointer to the matching entry. NULL if not found.
112 * @param iEntry The start of the range.
113 * @param cEntries The number of entries in the range.
114 * @param uKey The key to find.
115 */
116DECLINLINE(PCRTOIDENTRYSMALL) rtOidDbLookupSmall(uint32_t iEntry, uint32_t cEntries, uint32_t uKey)
117{
118 if (cEntries < 6)
119 {
120 /* Linear search for small ranges. */
121 while (cEntries-- > 0)
122 {
123 uint32_t const uThisKey = g_aSmallOidTable[iEntry].uKey;
124 if (uThisKey >= uKey)
125 {
126 if (uThisKey == uKey)
127 return &g_aSmallOidTable[iEntry];
128 break;
129 }
130 iEntry++;
131 }
132 }
133 else
134 {
135 /* Binary search. */
136 uint32_t iEnd = iEntry + cEntries;
137 for (;;)
138 {
139 uint32_t const i = iEntry + (iEnd - iEntry) / 2;
140 uint32_t const uThisKey = g_aSmallOidTable[i].uKey;
141 if (uThisKey < uKey)
142 {
143 iEntry = i + 1;
144 if (iEntry >= iEnd)
145 break;
146 }
147 else if (uThisKey > uKey)
148 {
149 iEnd = i;
150 if (iEnd <= iEntry)
151 break;
152 }
153 else
154 return &g_aSmallOidTable[i];
155 }
156 }
157 return NULL;
158}
159
160
161/**
162 * Queries the name for an object identifier.
163 *
164 * @returns IPRT status code (VINF_SUCCESS, VERR_NOT_FOUND,
165 * VERR_BUFFER_OVERFLOW)
166 * @param pauComponents The components making up the object ID.
167 * @param cComponents The number of components.
168 * @param pszDst Where to store the name if found.
169 * @param cbDst The size of the destination buffer.
170 */
171static int rtOidDbQueryObjIdName(uint32_t const *pauComponents, uint8_t cComponents, char *pszDst, size_t cbDst)
172{
173 int rc = VERR_NOT_FOUND;
174 if (cComponents > 0)
175 {
176 /*
177 * The top level is always in the small table as the range is restricted to 0,1,2.
178 */
179 bool fBigTable = false;
180 uint32_t cEntries = RT_MIN(RT_ELEMENTS(g_aSmallOidTable), 3);
181 uint32_t iEntry = 0;
182 for (;;)
183 {
184 uint32_t const uKey = *pauComponents++;
185 if (!fBigTable)
186 {
187 PCRTOIDENTRYSMALL pSmallHit = rtOidDbLookupSmall(iEntry, cEntries, uKey);
188 if (pSmallHit)
189 {
190 if (--cComponents == 0)
191 {
192 if (RTBldProgStrTabQueryString(&g_OidDbStrTab, pSmallHit->offString,
193 pSmallHit->cchString, pszDst, cbDst) >= 0)
194 return VINF_SUCCESS;
195 rc = VERR_BUFFER_OVERFLOW;
196 break;
197 }
198 cEntries = pSmallHit->cChildren;
199 if (cEntries)
200 {
201 iEntry = pSmallHit->idxChildren;
202 fBigTable = pSmallHit->fBigTable;
203 continue;
204 }
205 }
206 }
207 else
208 {
209 PCRTOIDENTRYBIG pBigHit = rtOidDbLookupBig(iEntry, cEntries, uKey);
210 if (pBigHit)
211 {
212 if (--cComponents == 0)
213 {
214 if (RTBldProgStrTabQueryString(&g_OidDbStrTab, pBigHit->offString,
215 pBigHit->cchString, pszDst, cbDst) >= 0)
216 return VINF_SUCCESS;
217 rc = VERR_BUFFER_OVERFLOW;
218 break;
219 }
220 cEntries = pBigHit->cChildren;
221 if (cEntries)
222 {
223 iEntry = pBigHit->idxChildren;
224 fBigTable = pBigHit->fBigTable;
225 continue;
226 }
227 }
228 }
229 break;
230 }
231 }
232
233 return rc;
234}
235
236
237/**
238 * Queries the name for an object identifier.
239 *
240 * This API is simple and more or less requires a
241 *
242 * @returns IPRT status code.
243 * @retval VINF_SUCCESS on success.
244 * @retval VERR_NOT_FOUND if not found.
245 * @retval VERR_BUFFER_OVERFLOW if more buffer space is required.
246 *
247 * @param pauComponents The components making up the object ID.
248 * @param cComponents The number of components.
249 * @param pszDst Where to store the name if found.
250 * @param cbDst The size of the destination buffer.
251 */
252RTDECL(int) RTAsn1QueryObjIdName(PCRTASN1OBJID pObjId, char *pszDst, size_t cbDst)
253{
254 return rtOidDbQueryObjIdName(pObjId->pauComponents, pObjId->cComponents, pszDst, cbDst);
255}
256
257#endif /* !IN_SUP_HARDENED_R3 */
258
259
260
261/**
262 * Wrapper around FNRTASN1DUMPPRINTFV.
263 *
264 * @param pData The dump data structure.
265 * @param pszFormat Format string.
266 * @param ... Format arguments.
267 */
268static void rtAsn1DumpPrintf(PRTASN1DUMPDATA pData, const char *pszFormat, ...)
269{
270 va_list va;
271 va_start(va, pszFormat);
272 pData->pfnPrintfV(pData->pvUser, pszFormat, va);
273 va_end(va);
274}
275
276
277/**
278 * Prints indentation.
279 *
280 * @param pData The dump data structure.
281 * @param uDepth The indentation depth.
282 */
283static void rtAsn1DumpPrintIdent(PRTASN1DUMPDATA pData, uint32_t uDepth)
284{
285 uint32_t cchLeft = uDepth * 2;
286 while (cchLeft > 0)
287 {
288 static char const s_szSpaces[] = " ";
289 uint32_t cch = RT_MIN(cchLeft, sizeof(s_szSpaces) - 1);
290 rtAsn1DumpPrintf(pData, &s_szSpaces[sizeof(s_szSpaces) - 1 - cch]);
291 cchLeft -= cch;
292 }
293}
294
295
296/**
297 * Dumps UTC TIME and GENERALIZED TIME
298 *
299 * @param pData The dump data structure.
300 * @param pAsn1Core The ASN.1 core object representation.
301 * @param pszType The time type name.
302 */
303static void rtAsn1DumpTime(PRTASN1DUMPDATA pData, PCRTASN1CORE pAsn1Core, const char *pszType)
304{
305 if ((pAsn1Core->fFlags & RTASN1CORE_F_PRIMITE_TAG_STRUCT))
306 {
307 PCRTASN1TIME pTime = (PCRTASN1TIME)pAsn1Core;
308 rtAsn1DumpPrintf(pData, "%s -- %04u-%02u-%02u %02u:%02u:%02.%09Z\n",
309 pszType,
310 pTime->Time.i32Year, pTime->Time.u8Month, pTime->Time.u8MonthDay,
311 pTime->Time.u8Hour, pTime->Time.u8Minute, pTime->Time.u8Second,
312 pTime->Time.u32Nanosecond);
313 }
314 else if (pAsn1Core->cb > 0 && pAsn1Core->cb < 32 && pAsn1Core->uData.pch)
315 rtAsn1DumpPrintf(pData, "%s '%.*s'\n", pszType, (size_t)pAsn1Core->cb, pAsn1Core->uData.pch);
316 else
317 rtAsn1DumpPrintf(pData, "%s -- cb=%u\n", pszType, pAsn1Core->cb);
318}
319
320
321/**
322 * Dumps strings sharing the RTASN1STRING structure.
323 *
324 * @param pData The dump data structure.
325 * @param pAsn1Core The ASN.1 core object representation.
326 * @param pszType The string type name.
327 * @param uDepth The current identation level.
328 */
329static void rtAsn1DumpString(PRTASN1DUMPDATA pData, PCRTASN1CORE pAsn1Core, const char *pszType, uint32_t uDepth)
330{
331 rtAsn1DumpPrintf(pData, "%s", pszType);
332
333 const char *pszPostfix = "'\n";
334 bool fUtf8 = false;
335 const char *pch = pAsn1Core->uData.pch;
336 uint32_t cch = pAsn1Core->cb;
337 PCRTASN1STRING pString = (PCRTASN1STRING)pAsn1Core;
338 if ( (pAsn1Core->fFlags & RTASN1CORE_F_PRIMITE_TAG_STRUCT)
339 && pString->pszUtf8
340 && pString->cchUtf8)
341 {
342 fUtf8 = true;
343 pszPostfix = "' -- utf-8\n";
344 }
345
346 if (cch == 0 || !pch)
347 rtAsn1DumpPrintf(pData, "-- cb=%u\n", pszType, pAsn1Core->cb);
348 else
349 {
350 if (cch >= 48)
351 {
352 rtAsn1DumpPrintf(pData, "\n");
353 rtAsn1DumpPrintIdent(pData, uDepth + 1);
354 }
355 rtAsn1DumpPrintf(pData, " '");
356
357 /** @todo Handle BMP and UNIVERSIAL strings specially. */
358 do
359 {
360 const char *pchStart = pch;
361 while ( cch > 0
362 && (uint8_t)*pch >= 0x20
363 && (!fUtf8 ? (uint8_t)*pch < 0x7f : (uint8_t)*pch != 0x7f)
364 && *pch != '\'')
365 cch--, pch++;
366 if (pchStart != pch)
367 rtAsn1DumpPrintf(pData, "%.*s", pch - pchStart, pchStart);
368
369 while ( cch > 0
370 && ( (uint8_t)*pch < 0x20
371 || (!fUtf8 ? (uint8_t)*pch >= 0x7f : (uint8_t)*pch == 0x7f)
372 || (uint8_t)*pch == '\'') )
373 {
374 rtAsn1DumpPrintf(pData, "\\x%02x", *pch);
375 cch--;
376 pch++;
377 }
378 } while (cch > 0);
379
380 rtAsn1DumpPrintf(pData, pszPostfix);
381 }
382}
383
384
385/**
386 * Dumps the type and value of an universal ASN.1 type.
387 *
388 * @returns True if it opens a child, false if not.
389 * @param pData The dumper data.
390 * @param pAsn1Core The ASN.1 object to dump.
391 * @param uDepth The current depth (for indentation).
392 */
393static bool rtAsn1DumpUniversalTypeAndValue(PRTASN1DUMPDATA pData, PCRTASN1CORE pAsn1Core, uint32_t uDepth)
394{
395 const char *pszValuePrefix = "-- value:";
396 const char *pszDefault = "";
397 if (pAsn1Core->fFlags & RTASN1CORE_F_DEFAULT)
398 {
399 pszValuePrefix = "DEFAULT";
400 pszDefault = "DEFAULT ";
401 }
402
403 bool fOpen = false;
404 switch (pAsn1Core->uRealTag)
405 {
406 case ASN1_TAG_BOOLEAN:
407 if (pAsn1Core->fFlags & RTASN1CORE_F_PRIMITE_TAG_STRUCT)
408 rtAsn1DumpPrintf(pData, "BOOLEAN %s %RTbool\n", pszValuePrefix, ((PCRTASN1BOOLEAN)pAsn1Core)->fValue);
409 else if (pAsn1Core->cb == 1 && pAsn1Core->uData.pu8)
410 rtAsn1DumpPrintf(pData, "BOOLEAN %s %u\n", pszValuePrefix, *pAsn1Core->uData.pu8);
411 else
412 rtAsn1DumpPrintf(pData, "BOOLEAN -- cb=%u\n", pAsn1Core->cb);
413 break;
414
415 case ASN1_TAG_INTEGER:
416 if ((pAsn1Core->fFlags & RTASN1CORE_F_PRIMITE_TAG_STRUCT) && pAsn1Core->cb <= 8)
417 rtAsn1DumpPrintf(pData, "INTEGER %s %llu / %#llx\n", pszValuePrefix,
418 ((PCRTASN1INTEGER)pAsn1Core)->uValue, ((PCRTASN1INTEGER)pAsn1Core)->uValue);
419 else if (pAsn1Core->cb == 0 || pAsn1Core->cb >= 512 || !pAsn1Core->uData.pu8)
420 rtAsn1DumpPrintf(pData, "INTEGER -- cb=%u\n", pAsn1Core->cb);
421 else if (pAsn1Core->cb <= 32)
422 rtAsn1DumpPrintf(pData, "INTEGER %s %.*Rhxs\n", pszValuePrefix, (size_t)pAsn1Core->cb, pAsn1Core->uData.pu8);
423 else
424 rtAsn1DumpPrintf(pData, "INTEGER %s\n%.*Rhxd\n", pszValuePrefix, (size_t)pAsn1Core->cb, pAsn1Core->uData.pu8);
425 break;
426
427 case ASN1_TAG_BIT_STRING:
428 if ((pAsn1Core->fFlags & RTASN1CORE_F_PRIMITE_TAG_STRUCT))
429 {
430 PCRTASN1BITSTRING pBitString = (PCRTASN1BITSTRING)pAsn1Core;
431 rtAsn1DumpPrintf(pData, "BIT STRING %s-- cb=%u cBits=%#x cMaxBits=%#x",
432 pszDefault, pBitString->Asn1Core.cb, pBitString->cBits, pBitString->cMaxBits);
433 if (pBitString->cBits <= 64)
434 rtAsn1DumpPrintf(pData, " value=%#llx\n", RTAsn1BitString_GetAsUInt64(pBitString));
435 else
436 rtAsn1DumpPrintf(pData, "\n");
437 }
438 else
439 rtAsn1DumpPrintf(pData, "BIT STRING %s-- cb=%u\n", pszDefault, pAsn1Core->cb);
440 fOpen = pAsn1Core->pOps != NULL;
441 break;
442
443 case ASN1_TAG_OCTET_STRING:
444 rtAsn1DumpPrintf(pData, "OCTET STRING %s-- cb=%u\n", pszDefault, pAsn1Core->cb);
445 fOpen = pAsn1Core->pOps != NULL;
446 break;
447
448 case ASN1_TAG_NULL:
449 rtAsn1DumpPrintf(pData, "NULL\n");
450 break;
451
452 case ASN1_TAG_OID:
453 if ((pAsn1Core->fFlags & RTASN1CORE_F_PRIMITE_TAG_STRUCT))
454 {
455#ifndef IN_SUP_HARDENED_R3
456 PCRTASN1OBJID pObjId = (PCRTASN1OBJID)pAsn1Core;
457 char szName[64];
458 if (rtOidDbQueryObjIdName(pObjId->pauComponents, pObjId->cComponents, szName, sizeof(szName)) == VINF_SUCCESS)
459 rtAsn1DumpPrintf(pData, "OBJECT IDENTIFIER %s%s ('%s')\n",
460 pszDefault, szName, ((PCRTASN1OBJID)pAsn1Core)->szObjId);
461 else
462#endif
463 rtAsn1DumpPrintf(pData, "OBJECT IDENTIFIER %s'%s'\n", pszDefault, ((PCRTASN1OBJID)pAsn1Core)->szObjId);
464 }
465 else
466 rtAsn1DumpPrintf(pData, "OBJECT IDENTIFIER %s -- cb=%u\n", pszDefault, pAsn1Core->cb);
467 break;
468
469 case ASN1_TAG_OBJECT_DESCRIPTOR:
470 rtAsn1DumpPrintf(pData, "OBJECT DESCRIPTOR -- cb=%u TODO\n", pAsn1Core->cb);
471 break;
472
473 case ASN1_TAG_EXTERNAL:
474 rtAsn1DumpPrintf(pData, "EXTERNAL -- cb=%u TODO\n", pAsn1Core->cb);
475 break;
476
477 case ASN1_TAG_REAL:
478 rtAsn1DumpPrintf(pData, "REAL -- cb=%u TODO\n", pAsn1Core->cb);
479 break;
480
481 case ASN1_TAG_ENUMERATED:
482 rtAsn1DumpPrintf(pData, "ENUMERATED -- cb=%u TODO\n", pAsn1Core->cb);
483 break;
484
485 case ASN1_TAG_EMBEDDED_PDV:
486 rtAsn1DumpPrintf(pData, "EMBEDDED PDV -- cb=%u TODO\n", pAsn1Core->cb);
487 break;
488
489 case ASN1_TAG_UTF8_STRING:
490 rtAsn1DumpString(pData, pAsn1Core, "UTF8 STRING", uDepth);
491 break;
492
493 case ASN1_TAG_RELATIVE_OID:
494 rtAsn1DumpPrintf(pData, "RELATIVE OBJECT IDENTIFIER -- cb=%u TODO\n", pAsn1Core->cb);
495 break;
496
497 case ASN1_TAG_SEQUENCE:
498 rtAsn1DumpPrintf(pData, "SEQUENCE -- cb=%u\n", pAsn1Core->cb);
499 fOpen = true;
500 break;
501 case ASN1_TAG_SET:
502 rtAsn1DumpPrintf(pData, "SET -- cb=%u\n", pAsn1Core->cb);
503 fOpen = true;
504 break;
505
506 case ASN1_TAG_NUMERIC_STRING:
507 rtAsn1DumpString(pData, pAsn1Core, "NUMERIC STRING", uDepth);
508 break;
509
510 case ASN1_TAG_PRINTABLE_STRING:
511 rtAsn1DumpString(pData, pAsn1Core, "PRINTABLE STRING", uDepth);
512 break;
513
514 case ASN1_TAG_T61_STRING:
515 rtAsn1DumpString(pData, pAsn1Core, "T61 STRING", uDepth);
516 break;
517
518 case ASN1_TAG_VIDEOTEX_STRING:
519 rtAsn1DumpString(pData, pAsn1Core, "VIDEOTEX STRING", uDepth);
520 break;
521
522 case ASN1_TAG_IA5_STRING:
523 rtAsn1DumpString(pData, pAsn1Core, "IA5 STRING", uDepth);
524 break;
525
526 case ASN1_TAG_GRAPHIC_STRING:
527 rtAsn1DumpString(pData, pAsn1Core, "GRAPHIC STRING", uDepth);
528 break;
529
530 case ASN1_TAG_VISIBLE_STRING:
531 rtAsn1DumpString(pData, pAsn1Core, "VISIBLE STRING", uDepth);
532 break;
533
534 case ASN1_TAG_GENERAL_STRING:
535 rtAsn1DumpString(pData, pAsn1Core, "GENERAL STRING", uDepth);
536 break;
537
538 case ASN1_TAG_UNIVERSAL_STRING:
539 rtAsn1DumpString(pData, pAsn1Core, "UNIVERSAL STRING", uDepth);
540 break;
541
542 case ASN1_TAG_BMP_STRING:
543 rtAsn1DumpString(pData, pAsn1Core, "BMP STRING", uDepth);
544 break;
545
546 case ASN1_TAG_UTC_TIME:
547 rtAsn1DumpTime(pData, pAsn1Core, "UTC TIME");
548 break;
549
550 case ASN1_TAG_GENERALIZED_TIME:
551 rtAsn1DumpTime(pData, pAsn1Core, "GENERALIZED TIME");
552 break;
553
554 case ASN1_TAG_CHARACTER_STRING:
555 rtAsn1DumpPrintf(pData, "CHARACTER STRING -- cb=%u TODO\n", pAsn1Core->cb);
556 break;
557
558 default:
559 rtAsn1DumpPrintf(pData, "[UNIVERSAL %u]\n", pAsn1Core->uTag);
560 break;
561 }
562 return fOpen;
563}
564
565
566/** @callback_method_impl{FNRTASN1ENUMCALLBACK} */
567static DECLCALLBACK(int) rtAsn1DumpEnumCallback(PRTASN1CORE pAsn1Core, const char *pszName, uint32_t uDepth, void *pvUser)
568{
569 PRTASN1DUMPDATA pData = (PRTASN1DUMPDATA)pvUser;
570 if (!pAsn1Core->fFlags)
571 return VINF_SUCCESS;
572
573 bool fOpen = false;
574 rtAsn1DumpPrintIdent(pData, uDepth);
575 switch (pAsn1Core->fClass & ASN1_TAGCLASS_MASK)
576 {
577 case ASN1_TAGCLASS_UNIVERSAL:
578 rtAsn1DumpPrintf(pData, "%-16s ", pszName);
579 fOpen = rtAsn1DumpUniversalTypeAndValue(pData, pAsn1Core, uDepth);
580 break;
581
582 case ASN1_TAGCLASS_CONTEXT:
583 if ((pAsn1Core->fRealClass & ASN1_TAGCLASS_MASK) == ASN1_TAGCLASS_UNIVERSAL)
584 {
585 rtAsn1DumpPrintf(pData, "%-16s [%u] ", pszName, pAsn1Core->uTag);
586 fOpen = rtAsn1DumpUniversalTypeAndValue(pData, pAsn1Core, uDepth);
587 }
588 else
589 {
590 rtAsn1DumpPrintf(pData, "%-16s [%u]\n", pszName, pAsn1Core->uTag);
591 fOpen = true;
592 }
593 break;
594
595 case ASN1_TAGCLASS_APPLICATION:
596 if ((pAsn1Core->fRealClass & ASN1_TAGCLASS_MASK) == ASN1_TAGCLASS_UNIVERSAL)
597 {
598 rtAsn1DumpPrintf(pData, "%-16s [APPLICATION %u] ", pszName, pAsn1Core->uTag);
599 fOpen = rtAsn1DumpUniversalTypeAndValue(pData, pAsn1Core, uDepth);
600 }
601 else
602 {
603 rtAsn1DumpPrintf(pData, "%-16s [APPLICATION %u]\n", pszName, pAsn1Core->uTag);
604 fOpen = true;
605 }
606 break;
607
608 case ASN1_TAGCLASS_PRIVATE:
609 if (RTASN1CORE_IS_DUMMY(pAsn1Core))
610 rtAsn1DumpPrintf(pData, "%-16s DUMMY\n", pszName);
611 else
612 {
613 rtAsn1DumpPrintf(pData, "%-16s [PRIVATE %u]\n", pszName, pAsn1Core->uTag);
614 fOpen = true;
615 }
616 break;
617 }
618 /** @todo {} */
619
620 /*
621 * Recurse.
622 */
623 if ( pAsn1Core->pOps
624 && pAsn1Core->pOps->pfnEnum)
625 pAsn1Core->pOps->pfnEnum(pAsn1Core, rtAsn1DumpEnumCallback, uDepth, pData);
626 return VINF_SUCCESS;
627}
628
629
630RTDECL(int) RTAsn1Dump(PCRTASN1CORE pAsn1Core, uint32_t fFlags, uint32_t uLevel, PFNRTDUMPPRINTFV pfnPrintfV, void *pvUser)
631{
632 if ( pAsn1Core->pOps
633 && pAsn1Core->pOps->pfnEnum)
634 {
635 RTASN1DUMPDATA Data;
636 Data.fFlags = fFlags;
637 Data.pfnPrintfV = pfnPrintfV;
638 Data.pvUser = pvUser;
639
640 return pAsn1Core->pOps->pfnEnum((PRTASN1CORE)pAsn1Core, rtAsn1DumpEnumCallback, uLevel, &Data);
641 }
642 return VINF_SUCCESS;
643}
644
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use