]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/asn1/asn1_parse.c
ASN1: rename asn1_par.c to asn1_parse.c for clarity; simplify asn1_parse2()
[thirdparty/openssl.git] / crypto / asn1 / asn1_parse.c
1 /*
2 * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <stdio.h>
11 #include "internal/cryptlib.h"
12 #include <openssl/buffer.h>
13 #include <openssl/objects.h>
14 #include <openssl/asn1.h>
15
16 #ifndef ASN1_PARSE_MAXDEPTH
17 #define ASN1_PARSE_MAXDEPTH 128
18 #endif
19
20 static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
21 int offset, int depth, int indent, int dump);
22 static int asn1_print_info(BIO *bp, long offset, int depth, int hl, long len,
23 int tag, int xclass, int constructed, int indent)
24 {
25 char str[128];
26 const char *p;
27 int pop_f_prefix = 0;
28 long saved_indent = -1;
29 int i = 0;
30
31 if (constructed & V_ASN1_CONSTRUCTED)
32 p = "cons: ";
33 else
34 p = "prim: ";
35 if (constructed != (V_ASN1_CONSTRUCTED | 1)) {
36 if (BIO_snprintf(str, sizeof(str), "%5ld:d=%-2d hl=%ld l=%4ld %s",
37 offset, depth, (long)hl, len, p) <= 0)
38 goto err;
39 } else {
40 if (BIO_snprintf(str, sizeof(str), "%5ld:d=%-2d hl=%ld l=inf %s",
41 offset, depth, (long)hl, p) <= 0)
42 goto err;
43 }
44 if (BIO_set_prefix(bp, str) <= 0) {
45 if ((bp = BIO_push(BIO_new(BIO_f_prefix()), bp)) == NULL)
46 goto err;
47 pop_f_prefix = 1;
48 }
49 saved_indent = BIO_get_indent(bp);
50 if (BIO_set_prefix(bp, str) <= 0
51 || BIO_set_indent(bp, indent) < 0)
52 goto err;
53
54 /*
55 * BIO_set_prefix made a copy of |str|, so we can safely use it for
56 * something else, ASN.1 tag printout.
57 */
58 p = str;
59 if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
60 BIO_snprintf(str, sizeof(str), "priv [ %d ] ", tag);
61 else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
62 BIO_snprintf(str, sizeof(str), "cont [ %d ]", tag);
63 else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
64 BIO_snprintf(str, sizeof(str), "appl [ %d ]", tag);
65 else if (tag > 30)
66 BIO_snprintf(str, sizeof(str), "<ASN1 %d>", tag);
67 else
68 p = ASN1_tag2str(tag);
69
70 i = (BIO_printf(bp, "%-18s", p) > 0);
71 err:
72 if (saved_indent >= 0)
73 BIO_set_indent(bp, saved_indent);
74 if (pop_f_prefix) {
75 BIO_pop(bp);
76 BIO_free(bp);
77 }
78 return i;
79 }
80
81 int ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent)
82 {
83 return asn1_parse2(bp, &pp, len, 0, 0, indent, 0);
84 }
85
86 int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent,
87 int dump)
88 {
89 return asn1_parse2(bp, &pp, len, 0, 0, indent, dump);
90 }
91
92 static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
93 int offset, int depth, int indent, int dump)
94 {
95 const unsigned char *p, *ep, *tot, *op, *opp;
96 long len;
97 int tag, xclass, ret = 0;
98 int nl, hl, j, r;
99 ASN1_OBJECT *o = NULL;
100 ASN1_OCTET_STRING *os = NULL;
101 ASN1_INTEGER *ai = NULL;
102 ASN1_ENUMERATED *ae = NULL;
103 /* ASN1_BMPSTRING *bmp=NULL; */
104 int dump_indent, dump_cont = 0;
105
106 if (depth > ASN1_PARSE_MAXDEPTH) {
107 BIO_puts(bp, "BAD RECURSION DEPTH\n");
108 return 0;
109 }
110
111 dump_indent = 6; /* Because we know BIO_dump_indent() */
112 p = *pp;
113 tot = p + length;
114 while (length > 0) {
115 op = p;
116 j = ASN1_get_object(&p, &len, &tag, &xclass, length);
117 if (j & 0x80) {
118 BIO_puts(bp, "Error in encoding\n");
119 goto end;
120 }
121 hl = (p - op);
122 length -= hl;
123 /*
124 * if j == 0x21 it is a constructed indefinite length object
125 */
126 if (!asn1_print_info(bp, (long)offset + (long)(op - *pp), depth,
127 hl, len, tag, xclass, j, (indent) ? depth : 0))
128 goto end;
129 if (j & V_ASN1_CONSTRUCTED) {
130 const unsigned char *sp = p;
131
132 ep = p + len;
133 if (BIO_write(bp, "\n", 1) <= 0)
134 goto end;
135 if (len > length) {
136 BIO_printf(bp, "length is greater than %ld\n", length);
137 goto end;
138 }
139 if ((j == 0x21) && (len == 0)) {
140 for (;;) {
141 r = asn1_parse2(bp, &p, (long)(tot - p),
142 offset + (p - *pp), depth + 1,
143 indent, dump);
144 if (r == 0)
145 goto end;
146 if ((r == 2) || (p >= tot)) {
147 len = p - sp;
148 break;
149 }
150 }
151 } else {
152 long tmp = len;
153
154 while (p < ep) {
155 sp = p;
156 r = asn1_parse2(bp, &p, tmp,
157 offset + (p - *pp), depth + 1,
158 indent, dump);
159 if (r == 0)
160 goto end;
161 tmp -= p - sp;
162 }
163 }
164 } else if (xclass != 0) {
165 p += len;
166 if (BIO_write(bp, "\n", 1) <= 0)
167 goto end;
168 } else {
169 nl = 0;
170 if ((tag == V_ASN1_PRINTABLESTRING) ||
171 (tag == V_ASN1_T61STRING) ||
172 (tag == V_ASN1_IA5STRING) ||
173 (tag == V_ASN1_VISIBLESTRING) ||
174 (tag == V_ASN1_NUMERICSTRING) ||
175 (tag == V_ASN1_UTF8STRING) ||
176 (tag == V_ASN1_UTCTIME) || (tag == V_ASN1_GENERALIZEDTIME)) {
177 if (BIO_write(bp, ":", 1) <= 0)
178 goto end;
179 if ((len > 0) && BIO_write(bp, (const char *)p, (int)len)
180 != (int)len)
181 goto end;
182 } else if (tag == V_ASN1_OBJECT) {
183 opp = op;
184 if (d2i_ASN1_OBJECT(&o, &opp, len + hl) != NULL) {
185 if (BIO_write(bp, ":", 1) <= 0)
186 goto end;
187 i2a_ASN1_OBJECT(bp, o);
188 } else {
189 if (BIO_puts(bp, ":BAD OBJECT") <= 0)
190 goto end;
191 dump_cont = 1;
192 }
193 } else if (tag == V_ASN1_BOOLEAN) {
194 if (len != 1) {
195 if (BIO_puts(bp, ":BAD BOOLEAN") <= 0)
196 goto end;
197 dump_cont = 1;
198 }
199 if (len > 0)
200 BIO_printf(bp, ":%u", p[0]);
201 } else if (tag == V_ASN1_BMPSTRING) {
202 /* do the BMP thang */
203 } else if (tag == V_ASN1_OCTET_STRING) {
204 int i, printable = 1;
205
206 opp = op;
207 os = d2i_ASN1_OCTET_STRING(NULL, &opp, len + hl);
208 if (os != NULL && os->length > 0) {
209 opp = os->data;
210 /*
211 * testing whether the octet string is printable
212 */
213 for (i = 0; i < os->length; i++) {
214 if (((opp[i] < ' ') &&
215 (opp[i] != '\n') &&
216 (opp[i] != '\r') &&
217 (opp[i] != '\t')) || (opp[i] > '~')) {
218 printable = 0;
219 break;
220 }
221 }
222 if (printable)
223 /* printable string */
224 {
225 if (BIO_write(bp, ":", 1) <= 0)
226 goto end;
227 if (BIO_write(bp, (const char *)opp, os->length) <= 0)
228 goto end;
229 } else if (!dump)
230 /*
231 * not printable => print octet string as hex dump
232 */
233 {
234 if (BIO_write(bp, "[HEX DUMP]:", 11) <= 0)
235 goto end;
236 for (i = 0; i < os->length; i++) {
237 if (BIO_printf(bp, "%02X", opp[i]) <= 0)
238 goto end;
239 }
240 } else
241 /* print the normal dump */
242 {
243 if (!nl) {
244 if (BIO_write(bp, "\n", 1) <= 0)
245 goto end;
246 }
247 if (BIO_dump_indent(bp,
248 (const char *)opp,
249 ((dump == -1 || dump >
250 os->
251 length) ? os->length : dump),
252 dump_indent) <= 0)
253 goto end;
254 nl = 1;
255 }
256 }
257 ASN1_OCTET_STRING_free(os);
258 os = NULL;
259 } else if (tag == V_ASN1_INTEGER) {
260 int i;
261
262 opp = op;
263 ai = d2i_ASN1_INTEGER(NULL, &opp, len + hl);
264 if (ai != NULL) {
265 if (BIO_write(bp, ":", 1) <= 0)
266 goto end;
267 if (ai->type == V_ASN1_NEG_INTEGER)
268 if (BIO_write(bp, "-", 1) <= 0)
269 goto end;
270 for (i = 0; i < ai->length; i++) {
271 if (BIO_printf(bp, "%02X", ai->data[i]) <= 0)
272 goto end;
273 }
274 if (ai->length == 0) {
275 if (BIO_write(bp, "00", 2) <= 0)
276 goto end;
277 }
278 } else {
279 if (BIO_puts(bp, ":BAD INTEGER") <= 0)
280 goto end;
281 dump_cont = 1;
282 }
283 ASN1_INTEGER_free(ai);
284 ai = NULL;
285 } else if (tag == V_ASN1_ENUMERATED) {
286 int i;
287
288 opp = op;
289 ae = d2i_ASN1_ENUMERATED(NULL, &opp, len + hl);
290 if (ae != NULL) {
291 if (BIO_write(bp, ":", 1) <= 0)
292 goto end;
293 if (ae->type == V_ASN1_NEG_ENUMERATED)
294 if (BIO_write(bp, "-", 1) <= 0)
295 goto end;
296 for (i = 0; i < ae->length; i++) {
297 if (BIO_printf(bp, "%02X", ae->data[i]) <= 0)
298 goto end;
299 }
300 if (ae->length == 0) {
301 if (BIO_write(bp, "00", 2) <= 0)
302 goto end;
303 }
304 } else {
305 if (BIO_puts(bp, ":BAD ENUMERATED") <= 0)
306 goto end;
307 dump_cont = 1;
308 }
309 ASN1_ENUMERATED_free(ae);
310 ae = NULL;
311 } else if (len > 0 && dump) {
312 if (!nl) {
313 if (BIO_write(bp, "\n", 1) <= 0)
314 goto end;
315 }
316 if (BIO_dump_indent(bp, (const char *)p,
317 ((dump == -1 || dump > len) ? len : dump),
318 dump_indent) <= 0)
319 goto end;
320 nl = 1;
321 }
322 if (dump_cont) {
323 int i;
324 const unsigned char *tmp = op + hl;
325 if (BIO_puts(bp, ":[") <= 0)
326 goto end;
327 for (i = 0; i < len; i++) {
328 if (BIO_printf(bp, "%02X", tmp[i]) <= 0)
329 goto end;
330 }
331 if (BIO_puts(bp, "]") <= 0)
332 goto end;
333 dump_cont = 0;
334 }
335
336 if (!nl) {
337 if (BIO_write(bp, "\n", 1) <= 0)
338 goto end;
339 }
340 p += len;
341 if ((tag == V_ASN1_EOC) && (xclass == 0)) {
342 ret = 2; /* End of sequence */
343 goto end;
344 }
345 }
346 length -= len;
347 }
348 ret = 1;
349 end:
350 ASN1_OBJECT_free(o);
351 ASN1_OCTET_STRING_free(os);
352 ASN1_INTEGER_free(ai);
353 ASN1_ENUMERATED_free(ae);
354 *pp = p;
355 return ret;
356 }
357
358 const char *ASN1_tag2str(int tag)
359 {
360 static const char *const tag2str[] = {
361 /* 0-4 */
362 "EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING",
363 /* 5-9 */
364 "NULL", "OBJECT", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL",
365 /* 10-13 */
366 "ENUMERATED", "<ASN1 11>", "UTF8STRING", "<ASN1 13>",
367 /* 15-17 */
368 "<ASN1 14>", "<ASN1 15>", "SEQUENCE", "SET",
369 /* 18-20 */
370 "NUMERICSTRING", "PRINTABLESTRING", "T61STRING",
371 /* 21-24 */
372 "VIDEOTEXSTRING", "IA5STRING", "UTCTIME", "GENERALIZEDTIME",
373 /* 25-27 */
374 "GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING",
375 /* 28-30 */
376 "UNIVERSALSTRING", "<ASN1 29>", "BMPSTRING"
377 };
378
379 if ((tag == V_ASN1_NEG_INTEGER) || (tag == V_ASN1_NEG_ENUMERATED))
380 tag &= ~0x100;
381
382 if (tag < 0 || tag > 30)
383 return "(unknown)";
384 return tag2str[tag];
385 }