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