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