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