1 /*-
2  * Copyright (c) 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $Id$
27  */
28 #include "sys-common.h"
29 
30 #define	ASN_DISABLE_PER_SUPPORT	1
31 
32 #include <asn1parser.h>		/* For static string tables */
33 
34 #include <asn_application.h>
35 #include <constraints.c>
36 #include <ber_tlv_tag.c>
37 #include <ber_tlv_length.c>
38 #include <INTEGER.c>
39 #include <OBJECT_IDENTIFIER.c>
40 #include <RELATIVE-OID.c>
41 #include <asn_codecs_prim.c>
42 
43 #undef  COPYRIGHT
44 #define COPYRIGHT       \
45 	"Copyright (c) 2004, 2005 Lev Walkin <vlm@lionet.info>\n"
46 
47 static void usage(const char *av0);	/* Print the Usage screen and exit */
48 static int process(const char *fname);	/* Perform the BER decoding */
49 static int decode_tlv_from_string(const char *datastring);
50 
51 static int single_type_decoding = 0;	/* -1 enables that */
52 static int minimalistic = 0;		/* -m enables that */
53 static int pretty_printing = 1;		/* -p disables that */
54 static int skip_bytes = 0;		/* -s controls that */
55 static char indent_bytes[16] = "    ";	/* -i controls that */
56 
57 int
main(int ac,char ** av)58 main(int ac, char **av) {
59 	int ch;				/* Command line character */
60 	int i;				/* Index in some loops */
61 
62 	/*
63 	 * Process command-line options.
64 	 */
65 	while((ch = getopt(ac, av, "1hi:mps:t:v")) != -1)
66 	switch(ch) {
67 	case '1':
68 		single_type_decoding = 1;
69 		break;
70 	case 'i':
71 		i = atoi(optarg);
72 		if(i >= 0 && i < (int)sizeof(indent_bytes)) {
73 			memset(indent_bytes, ' ', i);
74 			indent_bytes[i] = '\0';
75 		} else {
76 			fprintf(stderr, "-i %s: Invalid indent value\n",optarg);
77 			exit(EX_USAGE);
78 		}
79 		break;
80 	case 'm':
81 		minimalistic = 1;
82 		break;
83 	case 'p':
84 		pretty_printing = 0;
85 		break;
86 	case 's':
87 		skip_bytes = atoi(optarg);
88 		if(skip_bytes < 0) {
89 			fprintf(stderr, "-s %s: positive value expected\n",
90 				optarg);
91 			exit(EX_USAGE);
92 		}
93 		break;
94 	case 't':
95 		if(decode_tlv_from_string(optarg))
96 			exit(EX_DATAERR);
97 		exit(0);
98 	case 'v':
99 		fprintf(stderr, "ASN.1 BER Decoder, v" VERSION "\n" COPYRIGHT);
100 		exit(0);
101 		break;
102 	case 'h':
103 	default:
104 		usage(av[0]);
105 	}
106 
107 	/*
108 	 * Ensure that there are some input files present.
109 	 */
110 	if(ac > optind) {
111 		ac -= optind;
112 		av += optind;
113 	} else {
114 		fprintf(stderr, "%s: No input files specified\n", av[0]);
115 		exit(1);
116 	}
117 
118 	setvbuf(stdout, 0, _IOLBF, 0);
119 
120 	/*
121 	 * Iterate over input files and parse each.
122 	 * All syntax trees from all files will be bundled together.
123 	 */
124 	for(i = 0; i < ac; i++) {
125 		if(process(av[i]))
126 			exit(EX_DATAERR);
127 	}
128 
129 	return 0;
130 }
131 
132 /*
133  * Print the usage screen and exit(EX_USAGE).
134  */
135 static void
usage(const char * av0)136 usage(const char *av0) {
137 	fprintf(stderr,
138 "ASN.1 BER Decoder, v" VERSION "\n" COPYRIGHT
139 "Usage: %s [options] [-] [file ...]\n"
140 "Options:\n"
141 "  -1                Decode only the first BER structure (otherwise, until EOF)\n"
142 "  -i <indent>       Amount of spaces for output indentation (default is 4)\n"
143 "  -m                Minimalistic mode: print as little as possible\n"
144 "  -p                Do not attempt pretty-printing of known ASN.1 types\n"
145 "  -s <skip>         Ignore first <skip> bytes of input\n"
146 "  -t <hex-string>   Decode the given tag[/length] sequence (e.g. -t \"bf20\")\n"
147 "\n"
148 "The XML opening tag format is as follows:\n"
149 "  <tform O=\"off\" T=\"tag\" TL=\"tl_len\" V=\"{Indefinite|v_len}\" [A=\"type\"] [F]>\n"
150 "Where:\n"
151 "  tform    Which form the value is in: constructed (\"C\", \"I\") or primitive (\"P\")\n"
152 "  off      Offset of the encoded element in the unber input stream\n"
153 "  tag      The tag class and value in human readable form\n"
154 "  tl_len   The length of the TL (BER Tag and Length) encoding\n"
155 "  v_len    The length of the value (V, encoded by the L), may be \"Indefinite\"\n"
156 "  type     Likely name of the underlying ASN.1 type (for [UNIVERSAL n] tags)\n"
157 "  [F]      Indicates that the value was reformatted (pretty-printed)\n"
158 "See the manual page for details\n"
159 	, av0);
160 	exit(EX_USAGE);
161 }
162 
163 typedef enum pd_code {
164 	PD_FAILED	= -1,
165 	PD_FINISHED	= 0,
166 	PD_EOF		= 1,
167 } pd_code_e;
168 static pd_code_e process_deeper(const char *fname, FILE *fp, asn1c_integer_t *offset, int level, ssize_t limit, ber_tlv_len_t *frame_size, ber_tlv_len_t effective_size, int expect_eoc);
169 static void print_TL(int fin, asn1c_integer_t offset, int level, int constr, ssize_t tlen, ber_tlv_tag_t, ber_tlv_len_t, ber_tlv_len_t effective_frame_size);
170 static int print_V(const char *fname, FILE *fp, ber_tlv_tag_t, ber_tlv_len_t);
171 
172 /*
173  * Open the file and initiate recursive processing.
174  */
175 static int
process(const char * fname)176 process(const char *fname) {
177 	FILE *fp;
178 	pd_code_e pdc;
179 	asn1c_integer_t offset = 0;		/* Stream decoding position */
180 	ber_tlv_len_t frame_size = 0;		/* Single frame size */
181 
182 	if(strcmp(fname, "-")) {
183 		fp = fopen(fname, "rb");
184 		if(!fp) {
185 			perror(fname);
186 			return -1;
187 		}
188 	} else {
189 		fp = stdin;
190 	}
191 
192 	/*
193 	 * Skip the requested amount of bytes.
194 	 */
195 	for(; offset < skip_bytes; offset++) {
196 		if(fgetc(fp) == -1) {
197 			fprintf(stderr,
198 				"%s: input source (%" PRIdASN " bytes) "
199 				"has less data than \"-s %d\" switch "
200 				"wants to skip\n",
201 				fname, offset, skip_bytes);
202 			if(fp != stdin) fclose(fp);
203 			return -1;
204 		}
205 	}
206 
207 	/*
208 	 * Fetch out BER-encoded data until EOF or error.
209 	 */
210 	do {
211 		pdc = process_deeper(fname, fp, &offset,
212 				     0, -1, &frame_size, 0, 0);
213 	} while(pdc == PD_FINISHED && !single_type_decoding);
214 
215 	if(fp != stdin)
216 		fclose(fp);
217 
218 	if(pdc == PD_FAILED)
219 		return -1;
220 	return 0;
221 }
222 
223 /*
224  * Process the TLV recursively.
225  */
226 static pd_code_e
process_deeper(const char * fname,FILE * fp,asn1c_integer_t * offset,int level,ssize_t limit,ber_tlv_len_t * frame_size,ber_tlv_len_t effective_size,int expect_eoc)227 process_deeper(const char *fname, FILE *fp, asn1c_integer_t *offset, int level, ssize_t limit, ber_tlv_len_t *frame_size, ber_tlv_len_t effective_size, int expect_eoc) {
228 	unsigned char tagbuf[32];
229 	ssize_t tblen = 0;
230 	pd_code_e pdc = PD_FINISHED;
231 	ber_tlv_tag_t tlv_tag;
232 	ber_tlv_len_t tlv_len;
233 	ssize_t t_len;
234 	ssize_t l_len;
235 
236 	for(;;) {
237 		ber_tlv_len_t local_esize = 0;
238 		int constr;
239 		int ch;
240 
241 		if(limit == 0)
242 			return PD_FINISHED;
243 
244 		if(limit >= 0 && tblen >= limit) {
245 			fprintf(stderr,
246 				"%s: Too long TL sequence (%ld >= %ld)"
247 				" at %" PRIdASN ". "
248 				"Broken or maliciously constructed file\n",
249 				fname, (long)tblen, (long)limit, *offset);
250 			return PD_FAILED;
251 		}
252 
253 		/* Get the next byte from the input stream */
254 		ch = fgetc(fp);
255 		if(ch == -1) {
256 			if(limit > 0 || expect_eoc) {
257 				fprintf(stderr,
258 					"%s: Unexpected end of file (TL)"
259 					" at %" PRIdASN "\n",
260 					fname, *offset);
261 				return PD_FAILED;
262 			} else {
263 				return PD_EOF;
264 			}
265 		}
266 
267 		tagbuf[tblen++] = ch;
268 
269 		/*
270 		 * Decode the TLV tag.
271 		 */
272 		t_len = ber_fetch_tag(tagbuf, tblen, &tlv_tag);
273 		switch(t_len) {
274 		case -1:
275 			fprintf(stderr, "%s: Fatal error decoding tag"
276 				" at %" PRIdASN "+%ld\n",
277 				fname, *offset, (long)tblen);
278 			return PD_FAILED;
279 		case 0:
280 			/* More data expected */
281 			continue;
282 		}
283 
284 		/*
285 		 * Decode the TLV length.
286 		 */
287 		constr = BER_TLV_CONSTRUCTED(tagbuf);
288 		l_len = ber_fetch_length(constr,
289 				tagbuf + t_len, tblen - t_len, &tlv_len);
290 		switch(l_len) {
291 		case -1:
292 			fprintf(stderr,
293 				"%s: Fatal error decoding value length"
294 				" at %" PRIdASN "\n",
295 				fname, *offset + t_len);
296 			return PD_FAILED;
297 		case 0:
298 			/* More data expected */
299 			continue;
300 		}
301 
302 		/* Make sure the T & L decoders took exactly the whole buffer */
303 		assert((t_len + l_len) == tblen);
304 
305 		if(!expect_eoc || tagbuf[0] || tagbuf[1])
306 			print_TL(0, *offset, level, constr, tblen,
307 				 tlv_tag, tlv_len, effective_size);
308 
309 		if(limit != -1) {
310 			/* If limit is set, account for the TL sequence */
311 			limit -= (t_len + l_len);
312 			assert(limit >= 0);
313 
314 			if(tlv_len > limit) {
315 				fprintf(stderr,
316 				"%s: Structure advertizes length (%ld) "
317 				"greater than of a parent container (%ld)\n",
318 					fname, (long)tlv_len, (long)limit);
319 				return PD_FAILED;
320 			}
321 		}
322 
323 		*offset += t_len + l_len;
324 		*frame_size += t_len + l_len;
325 		effective_size += t_len + l_len;
326 		local_esize += t_len + l_len;
327 
328 		if(expect_eoc && !tagbuf[0] && !tagbuf[1]) {
329 			/* End of content octets */
330 			print_TL(1, *offset - 2, level - 1, 1, 2, 0, -1,
331 					effective_size);
332 			return PD_FINISHED;
333 		}
334 
335 		if(constr) {
336 			ber_tlv_len_t dec = 0;
337 			/*
338 			 * This is a constructed type. Process recursively.
339 			 */
340 			printf(">\n");	/* Close the opening tag */
341 			if(tlv_len != -1 && limit != -1) {
342 				assert(limit >= tlv_len);
343 			}
344 			pdc = process_deeper(fname, fp, offset, level + 1,
345 				tlv_len == -1 ? limit : tlv_len,
346 				&dec, t_len + l_len, tlv_len == -1);
347 			if(pdc == PD_FAILED) return pdc;
348 			if(limit != -1) {
349 				assert(limit >= dec);
350 				limit -= dec;
351 			}
352 			*frame_size += dec;
353 			effective_size += dec;
354 			local_esize += dec;
355 			if(tlv_len == -1) {
356 				tblen = 0;
357 				if(pdc == PD_FINISHED
358 					&& limit < 0 && !expect_eoc)
359 					return pdc;
360 				continue;
361 			}
362 		} else {
363 			assert(tlv_len >= 0);
364 			if(print_V(fname, fp, tlv_tag, tlv_len))
365 				return PD_FAILED;
366 
367 			if(limit != -1) {
368 				assert(limit >= tlv_len);
369 				limit -= tlv_len;
370 			}
371 			*offset += tlv_len;
372 			*frame_size += tlv_len;
373 			effective_size += tlv_len;
374 			local_esize += tlv_len;
375 		}
376 
377 		print_TL(1, *offset, level, constr, tblen,
378 			 tlv_tag, tlv_len, local_esize);
379 
380 		tblen = 0;
381 
382 		/* Report success for a single top level TLV */
383 		if(level == 0 && limit == -1 && !expect_eoc)
384 			break;
385 	} /* for(;;) */
386 
387 	return pdc;
388 }
389 
390 static void
print_TL(int fin,asn1c_integer_t offset,int level,int constr,ssize_t tlen,ber_tlv_tag_t tlv_tag,ber_tlv_len_t tlv_len,ber_tlv_len_t effective_size)391 print_TL(int fin, asn1c_integer_t offset, int level, int constr, ssize_t tlen, ber_tlv_tag_t tlv_tag, ber_tlv_len_t tlv_len, ber_tlv_len_t effective_size) {
392 
393 	if(fin && !constr) {
394 		printf("</P>\n");
395 		return;
396 	}
397 
398 	while(level-- > 0) fputs(indent_bytes, stdout);  /* Print indent */
399 	printf(fin ? "</" : "<");
400 
401 	printf(constr ? ((tlv_len == -1) ? "I" : "C") : "P");
402 
403 	/* Print out the offset of this boundary, even if closing tag */
404 	if(!minimalistic)
405 		printf(" O=\"%" PRIdASN "\"", offset);
406 
407 	printf(" T=\"");
408 	ber_tlv_tag_fwrite(tlv_tag, stdout);
409 	printf("\"");
410 
411 	if(!fin || (tlv_len == -1 && !minimalistic))
412 		printf(" TL=\"%ld\"", (long)tlen);
413 	if(!fin) {
414 		if(tlv_len == -1)
415 			printf(" V=\"Indefinite\"");
416 		else
417 			printf(" V=\"%ld\"", (long)tlv_len);
418 	}
419 
420 	if(!minimalistic
421 	&& BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL) {
422 		const char *str;
423 		ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
424 		str = ASN_UNIVERSAL_TAG2STR(tvalue);
425 		if(str) printf(" A=\"%s\"", str);
426 	}
427 
428 	if(fin) {
429 		if(constr && !minimalistic)
430 			printf(" L=\"%ld\"", (long)effective_size);
431 		printf(">\n");
432 	}
433 }
434 
435 /*
436  * Print the value in binary form, or reformat for pretty-printing.
437  */
438 static int
print_V(const char * fname,FILE * fp,ber_tlv_tag_t tlv_tag,ber_tlv_len_t tlv_len)439 print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag, ber_tlv_len_t tlv_len) {
440 	asn1c_integer_t *arcs = 0;	/* Object identifier arcs */
441 	unsigned char *vbuf = 0;
442 	asn1p_expr_type_e etype = 0;
443 	asn1c_integer_t collector = 0;
444 	int special_format = 0;
445 	ssize_t i;
446 
447 	/* Figure out what type is it */
448 	if(BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL
449 	&& pretty_printing) {
450 		ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
451 		etype = ASN_UNIVERSAL_TAG2TYPE(tvalue);
452 	}
453 
454 	/*
455 	 * Determine how to print the value, either in its native binary form,
456 	 * encoded with &xNN characters, or using pretty-printing.
457 	 * The basic string types (including "useful types", like UTCTime)
458 	 * are excempt from this determination logic, because their alphabets
459 	 * are subsets of the XML's native UTF-8 encoding.
460 	 */
461 	switch(etype) {
462 	case ASN_BASIC_BOOLEAN:
463 		if(tlv_len == 1)
464 			special_format = 1;
465 		else
466 			etype = 0;
467 		break;
468 	case ASN_BASIC_INTEGER:
469 	case ASN_BASIC_ENUMERATED:
470 		if((size_t)tlv_len <= sizeof(collector))
471 			special_format = 1;
472 		else
473 			etype = 0;
474 		break;
475 	case ASN_BASIC_OBJECT_IDENTIFIER:
476 	case ASN_BASIC_RELATIVE_OID:
477 		if(tlv_len > 0 && tlv_len < 128*1024 /* VERY long OID! */) {
478 			arcs = MALLOC(sizeof(*arcs) * (tlv_len + 1));
479 			if(arcs) {
480 				vbuf = MALLOC(tlv_len + 1);
481 				/* Not checking is intentional */
482 			}
483 		}
484 	case ASN_BASIC_UTCTime:
485 	case ASN_BASIC_GeneralizedTime:
486 	case ASN_STRING_NumericString:
487 	case ASN_STRING_PrintableString:
488 	case ASN_STRING_VisibleString:
489 	case ASN_STRING_IA5String:
490 	case ASN_STRING_UTF8String:
491 		break;	/* Directly compatible with UTF-8 */
492 	case ASN_STRING_BMPString:
493 	case ASN_STRING_UniversalString:
494 		break;	/* Not directly compatible with UTF-8 */
495 	default:
496 		/* Conditionally compatible with UTF-8 */
497 		if((
498 			(etype & ASN_STRING_MASK)
499 			||
500 			(etype == ASN_BASIC_OCTET_STRING)
501 			||
502 			/*
503 			 * AUTOMATIC TAGS or IMPLICIT TAGS in effect,
504 			 * Treat this primitive type as OCTET_STRING.
505 			 */
506 			(BER_TAG_CLASS(tlv_tag) != ASN_TAG_CLASS_UNIVERSAL
507 				&& pretty_printing)
508 		) && (tlv_len > 0 && tlv_len < 128 * 1024)) {
509 			vbuf = MALLOC(tlv_len + 1);
510 			/* Not checking is intentional */
511 		}
512 		break;
513 	}
514 
515 	/* If collection vbuf is present, defer printing the F flag. */
516 	if(!vbuf) printf(special_format ? " F>" : ">");
517 
518 	/*
519 	 * Print the value in binary or text form,
520 	 * or collect the bytes into vbuf.
521 	 */
522 	for(i = 0; i < tlv_len; i++) {
523 		int ch = fgetc(fp);
524 		if(ch == -1) {
525 			fprintf(stderr,
526 			"%s: Unexpected end of file (V)\n", fname);
527 			if(vbuf) FREEMEM(vbuf);
528 			if(arcs) FREEMEM(arcs);
529 			return -1;
530 		}
531 		switch(etype) {
532 		case ASN_BASIC_UTCTime:
533 		case ASN_BASIC_GeneralizedTime:
534 		case ASN_STRING_NumericString:
535 		case ASN_STRING_PrintableString:
536 		case ASN_STRING_VisibleString:
537 		case ASN_STRING_IA5String:
538 		case ASN_STRING_UTF8String:
539 			switch(ch) {
540 			default:
541 				if(((etype == ASN_STRING_UTF8String)
542 					|| !(ch & 0x80))
543 				&& (ch >= 0x20)
544 				) {
545 					printf("%c", ch);
546 					break;
547 				}
548 				/* Fall through */
549 			case 0x3c: case 0x3e: case 0x26:
550 				printf("&#x%02x;", ch);
551 			}
552 			break;
553 		case ASN_BASIC_BOOLEAN:
554 			switch(ch) {
555 			case 0: printf("<false/>"); break;
556 			case 0xff: printf("<true/>"); break;
557 			default: printf("<true value=\"&#x%02x\"/>", ch);
558 			}
559 			break;
560 		case ASN_BASIC_INTEGER:
561 		case ASN_BASIC_ENUMERATED:
562 			if(i)	collector = collector * 256 + ch;
563 			else	collector = (int)(signed char)ch;
564 			break;
565 		default:
566 			if(vbuf) {
567 				vbuf[i] = ch;
568 			} else {
569 				printf("&#x%02x;", ch);
570 			}
571 		}
572 	}
573 
574 	/* Do post-processing */
575 	switch(etype) {
576 	case ASN_BASIC_INTEGER:
577 	case ASN_BASIC_ENUMERATED:
578 		printf("%" PRIdASN, collector);
579 		break;
580 	case ASN_BASIC_OBJECT_IDENTIFIER:
581 		if(vbuf) {
582 			OBJECT_IDENTIFIER_t oid;
583 			int arcno;
584 
585 			oid.buf = vbuf;
586 			oid.size = tlv_len;
587 
588 			arcno = OBJECT_IDENTIFIER_get_arcs(&oid, arcs,
589 				sizeof(*arcs), tlv_len + 1);
590 			if(arcno >= 0) {
591 				assert(arcno <= (tlv_len + 1));
592 				printf(" F>");
593 				for(i = 0; i < arcno; i++) {
594 					if(i) printf(".");
595 					printf("%" PRIuASN, arcs[i]);
596 				}
597 				FREEMEM(vbuf);
598 				vbuf = 0;
599 			}
600 		}
601 		break;
602 	case ASN_BASIC_RELATIVE_OID:
603 		if(vbuf) {
604 			RELATIVE_OID_t oid;
605 			int arcno;
606 
607 			oid.buf = vbuf;
608 			oid.size = tlv_len;
609 
610 			arcno = RELATIVE_OID_get_arcs(&oid, arcs,
611 				sizeof(*arcs), tlv_len);
612 			if(arcno >= 0) {
613 				assert(arcno <= (tlv_len + 1));
614 				printf(" F>");
615 				for(i = 0; i < arcno; i++) {
616 					if(i) printf(".");
617 					printf("%" PRIuASN, arcs[i]);
618 				}
619 				FREEMEM(vbuf);
620 				vbuf = 0;
621 			}
622 		}
623 		break;
624 	default: break;
625 	}
626 
627 	/*
628 	 * If the buffer was not consumed, print it out.
629 	 * It might be an OCTET STRING or other primitive type,
630 	 * which might actually be printable, but we need to figure it out.
631 	 */
632 	if(vbuf) {
633 		int binary;
634 
635 		/*
636 		 * Check whether the data could be represented as text
637 		 */
638 		binary = -1 * (tlv_len >> 3); /* Threshold is 12.5% binary */
639 		for(i = 0; i < tlv_len; i++) {
640 			switch(vbuf[i]) {
641 			case 0x1b: binary = 1; break;
642 			case 0x09: case 0x0a: case 0x0d: continue;
643 			default:
644 				if(vbuf[i] < 0x20 || vbuf[i] >= 0x7f)
645 					if(++binary > 0)  /* Way too many */
646 						break;
647 				continue;
648 			}
649 			break;
650 		}
651 		printf(">");
652 		for(i = 0; i < tlv_len; i++) {
653 			if(binary > 0 || vbuf[i] < 0x20 || vbuf[i] >= 0x7f
654 				|| vbuf[i] == 0x26	/* '&' */
655 				|| vbuf[i] == 0x3c	/* '<' */
656 				|| vbuf[i] == 0x3e	/* '>' */
657 			)
658 				printf("&#x%02x;", vbuf[i]);
659 			else
660 				printf("%c", vbuf[i]);
661 		}
662 		FREEMEM(vbuf);
663 	}
664 
665 	if(arcs) FREEMEM(arcs);
666 	return 0;
667 }
668 
669 
670 static int
decode_tlv_from_string(const char * datastring)671 decode_tlv_from_string(const char *datastring) {
672 	unsigned char *data, *dp;
673 	size_t dsize;	/* Data size */
674 	ssize_t len;
675 	ber_tlv_tag_t tlv_tag;
676 	ber_tlv_len_t tlv_len;
677 	const char *p;
678 	int half;
679 
680 	dsize = strlen(datastring) + 1;
681 	dp = data = CALLOC(1, dsize);
682 	assert(data);
683 
684 	for(half = 0, p = datastring; *p; p++) {
685 		switch(*p) {
686 		case '0': case '1': case '2': case '3': case '4':
687 		case '5': case '6': case '7': case '8': case '9':
688 			*dp |= *p - '0'; break;
689 		case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
690 			*dp |= *p - 'A' + 10; break;
691 		case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
692 			*dp |= *p - 'a' + 10; break;
693 		case ' ': case '\t': case '\r': case '\n':
694 			continue;
695 		default:
696 			fprintf(stderr, "Unexpected symbols in data string:\n");
697 			fprintf(stderr, "%s\n", datastring);
698 			for(dp = data; datastring < p; datastring++, dp++)
699 				*dp = ' ';
700 			*dp = '\0';
701 			fprintf(stderr, "%s^ <- here\n", (char *)data);
702 			return -1;
703 		}
704 		if(half) dp++; else (*dp) <<= 4;
705 		half = !half;
706 	}
707 
708 	assert((size_t)(dp - data) <= dsize);
709 	dsize = dp - data;
710 
711 	printf("BER: ");
712 	for(dp = data; dp < data + dsize; dp++)
713 		printf("%02X", *dp);
714 	printf("\n");
715 
716 	len = ber_fetch_tag(data, dsize, &tlv_tag);
717 	switch(len) {
718 	case -1:
719 		fprintf(stderr, "TAG: Fatal error decoding tag\n");
720 		return -1;
721 	case 0:
722 		fprintf(stderr, "TAG: More data expected\n");
723 		return -1;
724 	default:
725 		printf("TAG: ");
726 		ber_tlv_tag_fwrite(tlv_tag, stdout);
727 		if(BER_TLV_CONSTRUCTED(data)) {
728 			printf(" (constructed)");
729 		} else if(dsize >= 2 && data[0] == 0 && data[1] == 0) {
730 			printf(" (end-of-content)");
731 		} else {
732 			printf(" (primitive)");
733 		}
734 		if(BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL) {
735 			const char *str;
736 			ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
737 			str = ASN_UNIVERSAL_TAG2STR(tvalue);
738 			if(str) printf(" \"%s\"", str);
739 		}
740 		printf("\n");
741 	}
742 
743 	if(dsize > (size_t)len) {
744 		len = ber_fetch_length(BER_TLV_CONSTRUCTED(data),
745 			data + len, dsize - len, &tlv_len);
746 		switch(len) {
747 		case -1:
748 			fprintf(stderr,
749 				"LEN: Fatal error decoding length\n");
750 			return -1;
751 		case 0:
752 			fprintf(stderr, "LEN: More data expected\n");
753 			return -1;
754 		default:
755 			if(tlv_len == (ber_tlv_len_t)-1)
756 				printf("LEN: Indefinite length encoding\n");
757 			else
758 				printf("LEN: %ld bytes\n", (long)tlv_len);
759 		}
760 	}
761 
762 	return 0;
763 }
764 
765 /*
766  * Dummy functions.
767  */
ber_check_tags(asn_codec_ctx_t * opt_codec_ctx,asn_TYPE_descriptor_t * td,asn_struct_ctx_t * opt_ctx,const void * ptr,size_t size,int tag_mode,int last_tag_form,ber_tlv_len_t * last_length,int * opt_tlv_form)768 asn_dec_rval_t ber_check_tags(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_struct_ctx_t *opt_ctx, const void *ptr, size_t size, int tag_mode, int last_tag_form, ber_tlv_len_t *last_length, int *opt_tlv_form) { asn_dec_rval_t rv = { 0, 0 }; (void)opt_codec_ctx; (void)td; (void)opt_ctx; (void)ptr; (void)size; (void)tag_mode; (void)last_tag_form; (void)last_length; (void)opt_tlv_form; return rv; }
769 
der_write_tags(asn_TYPE_descriptor_t * td,size_t slen,int tag_mode,int last_tag_form,ber_tlv_tag_t tag,asn_app_consume_bytes_f * cb,void * app_key)770 ssize_t der_write_tags(asn_TYPE_descriptor_t *td, size_t slen, int tag_mode, int last_tag_form, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb, void *app_key) { (void)td; (void)slen; (void)tag_mode; (void)last_tag_form; (void)tag; (void)cb; (void)app_key; return -1; }
771 
xer_decode_general(asn_codec_ctx_t * opt_codec_ctx,asn_struct_ctx_t * ctx,void * struct_key,const char * xml_tag,const void * buf_ptr,size_t size,int (* otd)(void * struct_key,const void * chunk_buf,size_t chunk_size),ssize_t (* br)(void * struct_key,const void * chunk_buf,size_t chunk_size,int have_more))772 asn_dec_rval_t xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, asn_struct_ctx_t *ctx, void *struct_key, const char *xml_tag, const void *buf_ptr, size_t size, int (*otd)(void *struct_key, const void *chunk_buf, size_t chunk_size), ssize_t (*br)(void *struct_key, const void *chunk_buf, size_t chunk_size, int have_more)) { asn_dec_rval_t rv = { 0, 0 }; (void)opt_codec_ctx; (void)ctx; (void)struct_key; (void)xml_tag; (void)buf_ptr; (void)size; (void)otd; (void)br; return rv; }
773 
OCTET_STRING_decode_uper(asn_codec_ctx_t * ctx,asn_TYPE_descriptor_t * td,asn_per_constraints_t * cts,void ** sptr,asn_per_data_t * pd)774 asn_dec_rval_t OCTET_STRING_decode_uper(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *cts, void **sptr, asn_per_data_t *pd) { asn_dec_rval_t rv = { 0, 0 }; (void)ctx; (void)td; (void)cts; (void)sptr; (void)pd; return rv; }
775 
OCTET_STRING_encode_uper(asn_TYPE_descriptor_t * td,asn_per_constraints_t * cts,void * sptr,asn_per_outp_t * po)776 asn_enc_rval_t OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *cts, void *sptr, asn_per_outp_t *po) { asn_enc_rval_t er = { 0, 0, 0 }; (void)td; (void)cts; (void)sptr; (void)po; return er; }
777 
xer_whitespace_span(const void * chunk_buf,size_t chunk_size)778 size_t xer_whitespace_span(const void *chunk_buf, size_t chunk_size) {  (void)chunk_buf; (void)chunk_size; return 0; }
779