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