1 /* $OpenBSD: tasn_prn.c,v 1.22 2021/12/03 17:10:49 jsing Exp $ */
2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3  * project 2000.
4  */
5 /* ====================================================================
6  * Copyright (c) 2000,2005 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58 
59 #include <stddef.h>
60 
61 #include <openssl/asn1.h>
62 #include <openssl/asn1t.h>
63 #include <openssl/buffer.h>
64 #include <openssl/err.h>
65 #include <openssl/objects.h>
66 #include <openssl/x509v3.h>
67 
68 #include "asn1_locl.h"
69 
70 /* Print routines.
71  */
72 
73 /* ASN1_PCTX routines */
74 
75 ASN1_PCTX default_pctx = {
76 	ASN1_PCTX_FLAGS_SHOW_ABSENT,	/* flags */
77 	0,				/* nm_flags */
78 	0,				/* cert_flags */
79 	0,				/* oid_flags */
80 	0				/* str_flags */
81 };
82 
83 
84 ASN1_PCTX *
85 ASN1_PCTX_new(void)
86 {
87 	ASN1_PCTX *p;
88 
89 	if ((p = calloc(1, sizeof(ASN1_PCTX))) == NULL) {
90 		ASN1error(ERR_R_MALLOC_FAILURE);
91 		return NULL;
92 	}
93 
94 	return p;
95 }
96 
97 void
98 ASN1_PCTX_free(ASN1_PCTX *p)
99 {
100 	free(p);
101 }
102 
103 unsigned long
104 ASN1_PCTX_get_flags(const ASN1_PCTX *p)
105 {
106 	return p->flags;
107 }
108 
109 void
110 ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags)
111 {
112 	p->flags = flags;
113 }
114 
115 unsigned long
116 ASN1_PCTX_get_nm_flags(const ASN1_PCTX *p)
117 {
118 	return p->nm_flags;
119 }
120 
121 void
122 ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags)
123 {
124 	p->nm_flags = flags;
125 }
126 
127 unsigned long
128 ASN1_PCTX_get_cert_flags(const ASN1_PCTX *p)
129 {
130 	return p->cert_flags;
131 }
132 
133 void
134 ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags)
135 {
136 	p->cert_flags = flags;
137 }
138 
139 unsigned long
140 ASN1_PCTX_get_oid_flags(const ASN1_PCTX *p)
141 {
142 	return p->oid_flags;
143 }
144 
145 void
146 ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags)
147 {
148 	p->oid_flags = flags;
149 }
150 
151 unsigned long
152 ASN1_PCTX_get_str_flags(const ASN1_PCTX *p)
153 {
154 	return p->str_flags;
155 }
156 
157 void
158 ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags)
159 {
160 	p->str_flags = flags;
161 }
162 
163 /* Main print routines */
164 
165 static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
166     const ASN1_ITEM *it, const char *fname, const char *sname, int nohdr,
167     const ASN1_PCTX *pctx);
168 
169 int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
170     const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx);
171 
172 static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld,
173     const ASN1_ITEM *it, int indent, const char *fname, const char *sname,
174     const ASN1_PCTX *pctx);
175 
176 static int asn1_print_fsname(BIO *out, int indent, const char *fname,
177     const char *sname, const ASN1_PCTX *pctx);
178 
179 int
180 ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent, const ASN1_ITEM *it,
181     const ASN1_PCTX *pctx)
182 {
183 	const char *sname;
184 
185 	if (pctx == NULL)
186 		pctx = &default_pctx;
187 	if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME)
188 		sname = NULL;
189 	else
190 		sname = it->sname;
191 	return asn1_item_print_ctx(out, &ifld, indent, it, NULL, sname,
192 	    0, pctx);
193 }
194 
195 static int
196 asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent, const ASN1_ITEM *it,
197     const char *fname, const char *sname, int nohdr, const ASN1_PCTX *pctx)
198 {
199 	const ASN1_TEMPLATE *tt;
200 	const ASN1_EXTERN_FUNCS *ef;
201 	ASN1_VALUE **tmpfld;
202 	const ASN1_AUX *aux = it->funcs;
203 	ASN1_aux_cb *asn1_cb;
204 	ASN1_PRINT_ARG parg;
205 	int i;
206 
207 	if (aux && aux->asn1_cb) {
208 		parg.out = out;
209 		parg.indent = indent;
210 		parg.pctx = pctx;
211 		asn1_cb = aux->asn1_cb;
212 	} else
213 		asn1_cb = NULL;
214 
215 	if ((it->itype != ASN1_ITYPE_PRIMITIVE ||
216 	    it->utype != V_ASN1_BOOLEAN) && *fld == NULL) {
217 		if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_ABSENT) {
218 			if (!nohdr &&
219 			    !asn1_print_fsname(out, indent, fname, sname, pctx))
220 				return 0;
221 			if (BIO_puts(out, "<ABSENT>\n") <= 0)
222 				return 0;
223 		}
224 		return 1;
225 	}
226 
227 	switch (it->itype) {
228 	case ASN1_ITYPE_PRIMITIVE:
229 		if (it->templates) {
230 			if (!asn1_template_print_ctx(out, fld, indent,
231 			    it->templates, pctx))
232 				return 0;
233 		}
234 		/* fall thru */
235 	case ASN1_ITYPE_MSTRING:
236 		if (!asn1_primitive_print(out, fld, it,
237 		    indent, fname, sname, pctx))
238 			return 0;
239 		break;
240 
241 	case ASN1_ITYPE_EXTERN:
242 		if (!nohdr &&
243 		    !asn1_print_fsname(out, indent, fname, sname, pctx))
244 			return 0;
245 		/* Use new style print routine if possible */
246 		ef = it->funcs;
247 		if (ef && ef->asn1_ex_print) {
248 			i = ef->asn1_ex_print(out, fld, indent, "", pctx);
249 			if (!i)
250 				return 0;
251 			if ((i == 2) && (BIO_puts(out, "\n") <= 0))
252 				return 0;
253 			return 1;
254 		} else if (sname &&
255 		    BIO_printf(out, ":EXTERNAL TYPE %s\n", sname) <= 0)
256 			return 0;
257 		break;
258 
259 	case ASN1_ITYPE_CHOICE:
260 		/* CHOICE type, get selector */
261 		i = asn1_get_choice_selector(fld, it);
262 		/* This should never happen... */
263 		if ((i < 0) || (i >= it->tcount)) {
264 			if (BIO_printf(out,
265 			    "ERROR: selector [%d] invalid\n", i) <= 0)
266 				return 0;
267 			return 1;
268 		}
269 		tt = it->templates + i;
270 		tmpfld = asn1_get_field_ptr(fld, tt);
271 		if (!asn1_template_print_ctx(out, tmpfld, indent, tt, pctx))
272 			return 0;
273 		break;
274 
275 	case ASN1_ITYPE_SEQUENCE:
276 	case ASN1_ITYPE_NDEF_SEQUENCE:
277 		if (!nohdr &&
278 		    !asn1_print_fsname(out, indent, fname, sname, pctx))
279 			return 0;
280 		if (fname || sname) {
281 			if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) {
282 				if (BIO_puts(out, " {\n") <= 0)
283 					return 0;
284 			} else {
285 				if (BIO_puts(out, "\n") <= 0)
286 					return 0;
287 			}
288 		}
289 
290 		if (asn1_cb) {
291 			i = asn1_cb(ASN1_OP_PRINT_PRE, fld, it, &parg);
292 			if (i == 0)
293 				return 0;
294 			if (i == 2)
295 				return 1;
296 		}
297 
298 		/* Print each field entry */
299 		for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) {
300 			const ASN1_TEMPLATE *seqtt;
301 
302 			seqtt = asn1_do_adb(fld, tt, 1);
303 			if (seqtt == NULL)
304 				return 0;
305 			tmpfld = asn1_get_field_ptr(fld, seqtt);
306 			if (!asn1_template_print_ctx(out, tmpfld, indent + 2,
307 			    seqtt, pctx))
308 				return 0;
309 		}
310 		if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) {
311 			if (BIO_printf(out, "%*s}\n", indent, "") < 0)
312 				return 0;
313 		}
314 
315 		if (asn1_cb) {
316 			i = asn1_cb(ASN1_OP_PRINT_POST, fld, it, &parg);
317 			if (i == 0)
318 				return 0;
319 		}
320 		break;
321 
322 	default:
323 		BIO_printf(out, "Unprocessed type %d\n", it->itype);
324 		return 0;
325 	}
326 
327 	return 1;
328 }
329 
330 int
331 asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
332     const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx)
333 {
334 	int i, flags;
335 	const char *sname, *fname;
336 
337 	flags = tt->flags;
338 	if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME)
339 		sname = tt->item->sname;
340 	else
341 		sname = NULL;
342 	if (pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME)
343 		fname = NULL;
344 	else
345 		fname = tt->field_name;
346 	if (flags & ASN1_TFLG_SK_MASK) {
347 		char *tname;
348 		ASN1_VALUE *skitem;
349 		STACK_OF(ASN1_VALUE) *stack;
350 
351 		/* SET OF, SEQUENCE OF */
352 		if (fname) {
353 			if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SSOF) {
354 				if (flags & ASN1_TFLG_SET_OF)
355 					tname = "SET";
356 				else
357 					tname = "SEQUENCE";
358 				if (BIO_printf(out, "%*s%s OF %s {\n",
359 				    indent, "", tname, tt->field_name) <= 0)
360 					return 0;
361 			} else if (BIO_printf(out, "%*s%s:\n", indent, "",
362 			    fname) <= 0)
363 				return 0;
364 		}
365 		stack = (STACK_OF(ASN1_VALUE) *)*fld;
366 		for (i = 0; i < sk_ASN1_VALUE_num(stack); i++) {
367 			if ((i > 0) && (BIO_puts(out, "\n") <= 0))
368 				return 0;
369 			skitem = sk_ASN1_VALUE_value(stack, i);
370 			if (!asn1_item_print_ctx(out, &skitem, indent + 2,
371 			    tt->item, NULL, NULL, 1, pctx))
372 				return 0;
373 		}
374 		if (!i && BIO_printf(out, "%*s<EMPTY>\n", indent + 2, "") <= 0)
375 			return 0;
376 		if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) {
377 			if (BIO_printf(out, "%*s}\n", indent, "") <= 0)
378 				return 0;
379 		}
380 		return 1;
381 	}
382 	return asn1_item_print_ctx(out, fld, indent, tt->item,
383 	    fname, sname, 0, pctx);
384 }
385 
386 static int
387 asn1_print_fsname(BIO *out, int indent, const char *fname, const char *sname,
388     const ASN1_PCTX *pctx)
389 {
390 	static char spaces[] = "                    ";
391 	const int nspaces = sizeof(spaces) - 1;
392 
393 	while (indent > nspaces) {
394 		if (BIO_write(out, spaces, nspaces) != nspaces)
395 			return 0;
396 		indent -= nspaces;
397 	}
398 	if (BIO_write(out, spaces, indent) != indent)
399 		return 0;
400 	if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME)
401 		sname = NULL;
402 	if (pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME)
403 		fname = NULL;
404 	if (!sname && !fname)
405 		return 1;
406 	if (fname) {
407 		if (BIO_puts(out, fname) <= 0)
408 			return 0;
409 	}
410 	if (sname) {
411 		if (fname) {
412 			if (BIO_printf(out, " (%s)", sname) <= 0)
413 				return 0;
414 		} else {
415 			if (BIO_puts(out, sname) <= 0)
416 				return 0;
417 		}
418 	}
419 	if (BIO_write(out, ": ", 2) != 2)
420 		return 0;
421 	return 1;
422 }
423 
424 static int
425 asn1_print_boolean_ctx(BIO *out, int boolval, const ASN1_PCTX *pctx)
426 {
427 	const char *str;
428 	switch (boolval) {
429 	case -1:
430 		str = "BOOL ABSENT";
431 		break;
432 
433 	case 0:
434 		str = "FALSE";
435 		break;
436 
437 	default:
438 		str = "TRUE";
439 		break;
440 
441 	}
442 
443 	if (BIO_puts(out, str) <= 0)
444 		return 0;
445 	return 1;
446 
447 }
448 
449 static int
450 asn1_print_integer_ctx(BIO *out, ASN1_INTEGER *str, const ASN1_PCTX *pctx)
451 {
452 	char *s;
453 	int ret = 1;
454 	if ((s = i2s_ASN1_INTEGER(NULL, str)) == NULL)
455 		return 0;
456 	if (BIO_puts(out, s) <= 0)
457 		ret = 0;
458 	free(s);
459 	return ret;
460 }
461 
462 static int
463 asn1_print_oid_ctx(BIO *out, const ASN1_OBJECT *oid, const ASN1_PCTX *pctx)
464 {
465 	char objbuf[80];
466 	const char *ln;
467 	ln = OBJ_nid2ln(OBJ_obj2nid(oid));
468 	if (!ln)
469 		ln = "";
470 	OBJ_obj2txt(objbuf, sizeof objbuf, oid, 1);
471 	if (BIO_printf(out, "%s (%s)", ln, objbuf) <= 0)
472 		return 0;
473 	return 1;
474 }
475 
476 static int
477 asn1_print_obstring_ctx(BIO *out, ASN1_STRING *str, int indent,
478     const ASN1_PCTX *pctx)
479 {
480 	if (str->type == V_ASN1_BIT_STRING) {
481 		if (BIO_printf(out, " (%ld unused bits)\n",
482 		    str->flags & 0x7) <= 0)
483 			return 0;
484 	} else if (BIO_puts(out, "\n") <= 0)
485 		return 0;
486 	if ((str->length > 0) &&
487 	    BIO_dump_indent(out, (char *)str->data, str->length,
488 	    indent + 2) <= 0)
489 		return 0;
490 	return 1;
491 }
492 
493 static int
494 asn1_primitive_print(BIO *out, ASN1_VALUE **fld, const ASN1_ITEM *it,
495     int indent, const char *fname, const char *sname, const ASN1_PCTX *pctx)
496 {
497 	long utype;
498 	ASN1_STRING *str;
499 	int ret = 1, needlf = 1;
500 	const char *pname;
501 
502 	if (!asn1_print_fsname(out, indent, fname, sname, pctx))
503 		return 0;
504 
505 	if (it != NULL && it->funcs != NULL) {
506 		const ASN1_PRIMITIVE_FUNCS *pf = it->funcs;
507 
508 		if (pf->prim_print == NULL)
509 			return 0;
510 
511 		return pf->prim_print(out, fld, it, indent, pctx);
512 	}
513 	if (it->itype == ASN1_ITYPE_MSTRING) {
514 		str = (ASN1_STRING *)*fld;
515 		utype = str->type & ~V_ASN1_NEG;
516 	} else {
517 		utype = it->utype;
518 		if (utype == V_ASN1_BOOLEAN)
519 			str = NULL;
520 		else
521 			str = (ASN1_STRING *)*fld;
522 	}
523 	if (utype == V_ASN1_ANY) {
524 		ASN1_TYPE *atype = (ASN1_TYPE *)*fld;
525 		utype = atype->type;
526 		fld = &atype->value.asn1_value;
527 		str = (ASN1_STRING *)*fld;
528 		if (pctx->flags & ASN1_PCTX_FLAGS_NO_ANY_TYPE)
529 			pname = NULL;
530 		else
531 			pname = ASN1_tag2str(utype);
532 	} else {
533 		if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_TYPE)
534 			pname = ASN1_tag2str(utype);
535 		else
536 			pname = NULL;
537 	}
538 
539 	if (utype == V_ASN1_NULL) {
540 		if (BIO_puts(out, "NULL\n") <= 0)
541 			return 0;
542 		return 1;
543 	}
544 
545 	if (pname) {
546 		if (BIO_puts(out, pname) <= 0)
547 			return 0;
548 		if (BIO_puts(out, ":") <= 0)
549 			return 0;
550 	}
551 
552 	switch (utype) {
553 	case V_ASN1_BOOLEAN:
554 		{
555 			int boolval = *(int *)fld;
556 			if (boolval == -1)
557 				boolval = it->size;
558 			ret = asn1_print_boolean_ctx(out, boolval, pctx);
559 		}
560 		break;
561 
562 	case V_ASN1_INTEGER:
563 	case V_ASN1_ENUMERATED:
564 		ret = asn1_print_integer_ctx(out, str, pctx);
565 		break;
566 
567 	case V_ASN1_UTCTIME:
568 		ret = ASN1_UTCTIME_print(out, str);
569 		break;
570 
571 	case V_ASN1_GENERALIZEDTIME:
572 		ret = ASN1_GENERALIZEDTIME_print(out, str);
573 		break;
574 
575 	case V_ASN1_OBJECT:
576 		ret = asn1_print_oid_ctx(out, (const ASN1_OBJECT *)*fld, pctx);
577 		break;
578 
579 	case V_ASN1_OCTET_STRING:
580 	case V_ASN1_BIT_STRING:
581 		ret = asn1_print_obstring_ctx(out, str, indent, pctx);
582 		needlf = 0;
583 		break;
584 
585 	case V_ASN1_SEQUENCE:
586 	case V_ASN1_SET:
587 	case V_ASN1_OTHER:
588 		if (BIO_puts(out, "\n") <= 0)
589 			return 0;
590 		if (ASN1_parse_dump(out, str->data, str->length,
591 		    indent, 0) <= 0)
592 			ret = 0;
593 		needlf = 0;
594 		break;
595 
596 	default:
597 		ret = ASN1_STRING_print_ex(out, str, pctx->str_flags);
598 	}
599 	if (!ret)
600 		return 0;
601 	if (needlf && BIO_puts(out, "\n") <= 0)
602 		return 0;
603 	return 1;
604 }
605