blob: 90468b43aaecd911cab74e22b2067b3adb7fab1e [file] [log] [blame]
Lev Walkin12984672004-09-24 21:00:15 +00001/*-
2 * Copyright (c) 2004 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 */
Lev Walkin06b8d7a2004-09-23 22:06:02 +000028#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <sys/types.h>
32#include <unistd.h>
33#include <sysexits.h> /* for EX_USAGE */
34#include <assert.h>
35#include <errno.h>
36
37#ifdef HAVE_CONFIG_H
38#include "config.h"
39#endif
40
41#include <asn1parser.h> /* For static string tables */
42
Lev Walkin12984672004-09-24 21:00:15 +000043#include <asn_application.h>
44#include <constraints.c>
Lev Walkin06b8d7a2004-09-23 22:06:02 +000045#include <ber_tlv_tag.c>
46#include <ber_tlv_length.c>
Lev Walkin12984672004-09-24 21:00:15 +000047#include <OBJECT_IDENTIFIER.c>
48#include <RELATIVE-OID.c>
Lev Walkina35f3ba2004-10-21 12:21:54 +000049#include <asn_codecs_prim.c>
Lev Walkin06b8d7a2004-09-23 22:06:02 +000050
51static void usage(const char *av0); /* Print the Usage screen and exit */
52static int process(const char *fname); /* Perform the BER decoding */
53static int decode_tlv_from_string(const char *datastring);
54
55#undef COPYRIGHT
56#define COPYRIGHT \
57 "Copyright (c) 2004 Lev Walkin <vlm@lionet.info>\n"
58
Lev Walkin12984672004-09-24 21:00:15 +000059static int single_type_decoding = 0; /* -1 enables that */
60static int pretty_printing = 1; /* -p disables that */
61static char *indent_buffer = " "; /* -i controls that */
Lev Walkin06b8d7a2004-09-23 22:06:02 +000062
63int
64main(int ac, char **av) {
65 int ch; /* Command line character */
66 int i; /* Index in some loops */
67
68 /*
69 * Process command-line options.
70 */
Lev Walkin12984672004-09-24 21:00:15 +000071 while((ch = getopt(ac, av, "1hi:pt:v")) != -1)
Lev Walkin06b8d7a2004-09-23 22:06:02 +000072 switch(ch) {
Lev Walkin12984672004-09-24 21:00:15 +000073 case '1':
74 single_type_decoding = 1;
75 break;
Lev Walkin06b8d7a2004-09-23 22:06:02 +000076 case 't':
77 if(decode_tlv_from_string(optarg))
78 exit(EX_DATAERR);
79 exit(0);
Lev Walkin12984672004-09-24 21:00:15 +000080 case 'p':
81 pretty_printing = 0;
82 break;
Lev Walkin06b8d7a2004-09-23 22:06:02 +000083 case 'i':
84 i = atoi(optarg);
85 if(i >= 0 && i < 16) {
86 indent_buffer = alloca(i + 1);
87 memset(indent_buffer, ' ', i);
88 indent_buffer[i] = '\0';
89 } else {
90 fprintf(stderr, "-i %s: Invalid indent value\n",optarg);
91 exit(EX_USAGE);
92 }
93 break;
94 case 'v':
95 fprintf(stderr, "ASN.1 BER Decoder, v" VERSION "\n" COPYRIGHT);
96 exit(0);
97 break;
Lev Walkin12984672004-09-24 21:00:15 +000098 case 'h':
Lev Walkin06b8d7a2004-09-23 22:06:02 +000099 default:
100 usage(av[0]);
101 }
102
103 /*
104 * Ensure that there are some input files present.
105 */
106 if(ac > optind) {
107 ac -= optind;
108 av += optind;
109 } else {
110 fprintf(stderr, "%s: No input files specified\n", av[0]);
111 exit(1);
112 }
113
114 setvbuf(stdout, 0, _IOLBF, 0);
115
116 /*
117 * Iterate over input files and parse each.
118 * All syntax trees from all files will be bundled together.
119 */
120 for(i = 0; i < ac; i++) {
121 if(process(av[i]))
122 exit(EX_DATAERR);
123 }
124
125 return 0;
126}
127
128/*
129 * Print the usage screen and exit(EX_USAGE).
130 */
131static void
132usage(const char *av0) {
133 fprintf(stderr,
134"ASN.1 BER Decoder, v" VERSION "\n" COPYRIGHT
135"Usage: %s [options] [-] [file ...]\n"
136"Options:\n"
Lev Walkin12984672004-09-24 21:00:15 +0000137" -1 Decode only the first BER structure (otherwise, until EOF)\n"
138" -i <indent> Amount of spaces for output indentation (default is 4)\n"
139" -p Do not attempt pretty-printing of known ASN.1 types\n"
140" -t <data-string> Decode the given tag[/length] sequence (e.g. -t \"bf20\")\n"
141"\n"
142"The XML opening tag format is as follows:\n"
143" <tform T=\"tag\" TL=\"tl_len\" V=\"{Indefinite|v_len}\" [A=\"type\"] [F]>\n"
144"Where:\n"
145" tform Which form the value is in: constructed (\"C\", \"I\") or primitive (\"P\")\n"
146" tag The tag class and value\n"
147" tl_len The length of the TL (BER Tag and Length) encoding\n"
148" v_len The length of the value (V, encoded by the L), may be \"Indefinite\"\n"
149" type Likely name of the underlying ASN.1 type (for [UNIVERSAL n] tags)\n"
150" [F] Indicates that the value was reformatted (pretty-printed)\n"
151"See the manual page for details\n"
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000152 , av0);
153 exit(EX_USAGE);
154}
155
156typedef enum pd_code {
157 PD_FAILED = -1,
158 PD_FINISHED = 0,
159 PD_EOF = 1,
160} pd_code_e;
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000161static pd_code_e process_deeper(const char *fname, FILE *fp, int level, ssize_t limit, ssize_t *decoded, int expect_eoc);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000162static void print_TL(int fin, int level, int constr, ssize_t tlen, ber_tlv_tag_t, ber_tlv_len_t);
163static int print_V(const char *fname, FILE *fp, ber_tlv_tag_t, ber_tlv_len_t);
164
165/*
166 * Open the file and initiate recursive processing.
167 */
168static int
169process(const char *fname) {
170 FILE *fp;
171 pd_code_e pdc;
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000172 ssize_t decoded = 0;
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000173
174 if(strcmp(fname, "-")) {
175 fp = fopen(fname, "r");
176 if(!fp) {
177 perror(fname);
178 return -1;
179 }
180 } else {
181 fp = stdin;
182 }
183
184 /*
185 * Fetch out BER-encoded data until EOF or error.
186 */
187 do {
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000188 pdc = process_deeper(fname, fp, 0, -1, &decoded, 0);
Lev Walkin12984672004-09-24 21:00:15 +0000189 } while(pdc == PD_FINISHED && !single_type_decoding);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000190
191 if(fp != stdin)
192 fclose(fp);
193
194 if(pdc == PD_FAILED)
195 return -1;
196 return 0;
197}
198
199/*
200 * Process the TLV recursively.
201 */
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000202static pd_code_e process_deeper(const char *fname, FILE *fp, int level, ssize_t limit, ssize_t *decoded, int expect_eoc) {
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000203 unsigned char tagbuf[32];
204 ssize_t tblen = 0;
205 pd_code_e pdc = PD_FINISHED;
206 ber_tlv_tag_t tlv_tag;
207 ber_tlv_len_t tlv_len;
208 ssize_t t_len;
209 ssize_t l_len;
210
211 do {
212 int constr;
213 int ch;
214
215 if(limit == 0)
216 return PD_FINISHED;
217
218 if(limit >= 0 && tblen >= limit) {
219 fprintf(stderr,
220 "%s: Too long TL sequence (%ld >= %ld). "
221 "Dangerous file\n",
222 fname, (long)tblen, (long)limit);
223 return PD_FAILED;
224 }
225
226 ch = fgetc(fp);
227 if(ch == -1) {
228 if(tblen) {
229 fprintf(stderr,
230 "%s: Unexpected end of file (TL)\n",
231 fname);
232 return PD_FAILED;
233 } else {
234 return PD_EOF;
235 }
236 }
237
238 tagbuf[tblen++] = ch;
239
240 /*
241 * Decode the TLV tag.
242 */
243 t_len = ber_fetch_tag(tagbuf, tblen, &tlv_tag);
244 switch(t_len) {
245 case -1:
246 fprintf(stderr, "%s: Fatal error deciphering tag\n",
247 fname);
248 return PD_FAILED;
249 case 0:
250 /* More data expected */
251 continue;
252 }
253
254 /*
255 * Decode the TLV length.
256 */
257 constr = BER_TLV_CONSTRUCTED(tagbuf);
258 l_len = ber_fetch_length(constr,
259 tagbuf + t_len, tblen - t_len, &tlv_len);
260 switch(l_len) {
261 case -1:
262 fprintf(stderr, "%s: Fatal error deciphering length\n",
263 fname);
264 return PD_FAILED;
265 case 0:
266 /* More data expected */
267 continue;
268 }
269
270 /* Make sure the T & L decoders took exactly the whole buffer */
271 assert((t_len + l_len) == tblen);
272
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000273 if(!expect_eoc || tagbuf[0] || tagbuf[1])
274 print_TL(0, level, constr, tblen, tlv_tag, tlv_len);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000275
276 if(limit != -1) {
277 /* If limit is set, account for the TL sequence */
278 limit -= (t_len + l_len);
279 assert(limit >= 0);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000280
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000281 if(tlv_len > limit) {
282 fprintf(stderr,
283 "%s: Structure advertizes length (%ld) "
284 "greater than of a parent container (%ld)\n",
285 fname, (long)tlv_len, (long)limit);
286 return PD_FAILED;
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000287 }
288 }
289
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000290 *decoded += t_len + l_len;
291
292 if(expect_eoc && tagbuf[0] == '\0' && tagbuf[1] == '\0') {
293 /* End of content octets */
294 print_TL(1, level - 1, 1, 2, 0, -1);
295 return PD_FINISHED;
296 }
297
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000298 if(constr) {
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000299 ssize_t dec = 0;
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000300 /*
301 * This is a constructed type. Process recursively.
302 */
Lev Walkin12984672004-09-24 21:00:15 +0000303 printf(">\n"); /* Close the opening tag */
Lev Walkin7c9e9232004-10-02 00:10:25 +0000304 if(tlv_len != -1 && limit != -1) {
305 assert(limit >= tlv_len);
306 }
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000307 pdc = process_deeper(fname, fp, level + 1,
308 tlv_len == -1 ? limit : tlv_len,
309 &dec, tlv_len == -1);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000310 if(pdc == PD_FAILED) return pdc;
Lev Walkin7c9e9232004-10-02 00:10:25 +0000311 if(limit != -1) {
312 assert(limit >= dec);
313 limit -= dec;
314 }
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000315 *decoded += dec;
316 if(tlv_len == -1) {
317 tblen = 0;
318 continue;
319 }
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000320 } else {
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000321 assert(tlv_len >= 0);
322 if(print_V(fname, fp, tlv_tag, tlv_len))
323 return PD_FAILED;
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000324
Lev Walkin7c9e9232004-10-02 00:10:25 +0000325 if(limit != -1) {
326 assert(limit >= tlv_len);
327 limit -= tlv_len;
328 }
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000329 *decoded += tlv_len;
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000330 }
331
332 print_TL(1, level, constr, tblen, tlv_tag, tlv_len);
333
334 tblen = 0;
335 } while(1);
336
337 return pdc;
338}
339
340static void
341print_TL(int fin, int level, int constr, ssize_t tlen, ber_tlv_tag_t tlv_tag, ber_tlv_len_t tlv_len) {
342
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000343 if(fin && !constr) {
344 printf("</P>\n");
345 return;
346 }
347
348 while(level-- > 0) printf(indent_buffer); /* Print indent */
349 printf(fin ? "</" : "<");
350
Lev Walkin12984672004-09-24 21:00:15 +0000351 printf(constr ? ((tlv_len == -1) ? "I" : "C") : "P");
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000352
353 printf(" T=\"");
354 ber_tlv_tag_fwrite(tlv_tag, stdout);
355 printf("\"");
356
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000357 if(!fin || tlv_len == -1)
Lev Walkin12984672004-09-24 21:00:15 +0000358 printf(" TL=\"%ld\"", (long)tlen);
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000359 if(!fin) {
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000360 if(tlv_len == -1)
Lev Walkin12984672004-09-24 21:00:15 +0000361 printf(" V=\"Indefinite\"");
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000362 else
Lev Walkin12984672004-09-24 21:00:15 +0000363 printf(" V=\"%ld\"", (long)tlv_len);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000364 }
365
366 if(BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL) {
367 const char *str;
368 ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
369 str = ASN_UNIVERSAL_TAG2STR(tvalue);
370 if(str) printf(" A=\"%s\"", str);
371 }
372
Lev Walkin12984672004-09-24 21:00:15 +0000373 if(fin) printf(">\n");
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000374}
375
Lev Walkin12984672004-09-24 21:00:15 +0000376/*
377 * Print the value in binary form, or reformat for pretty-printing.
378 */
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000379static int
380print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag, ber_tlv_len_t tlv_len) {
Lev Walkin77995ef2004-09-29 13:29:57 +0000381 asn1c_integer_t *arcs = 0; /* Object identifier arcs */
Lev Walkin12984672004-09-24 21:00:15 +0000382 unsigned char *vbuf = 0;
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000383 asn1p_expr_type_e etype = 0;
Lev Walkin77995ef2004-09-29 13:29:57 +0000384 asn1c_integer_t collector = 0;
Lev Walkin12984672004-09-24 21:00:15 +0000385 int special_format = 0;
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000386 ssize_t i;
387
388 /* Figure out what type is it */
Lev Walkin12984672004-09-24 21:00:15 +0000389 if(BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL
390 && pretty_printing) {
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000391 ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
392 etype = ASN_UNIVERSAL_TAG2TYPE(tvalue);
393 }
394
395 /*
Lev Walkin12984672004-09-24 21:00:15 +0000396 * Determine how to print the value, either in its native binary form,
397 * encoded with &xNN characters, or using pretty-printing.
398 * The basic string types (including "useful types", like UTCTime)
399 * are excempt from this determination logic, because their alphabets
400 * are subsets of the XML's native UTF-8 encoding.
401 */
402 switch(etype) {
403 case ASN_BASIC_BOOLEAN:
404 if(tlv_len == 1)
405 special_format = 1;
406 else
407 etype = 0;
408 break;
409 case ASN_BASIC_INTEGER:
410 case ASN_BASIC_ENUMERATED:
411 if((size_t)tlv_len <= sizeof(collector))
412 special_format = 1;
413 else
414 etype = 0;
415 break;
416 case ASN_BASIC_OBJECT_IDENTIFIER:
417 case ASN_BASIC_RELATIVE_OID:
418 if(tlv_len > 0 && tlv_len < 128*1024 /* VERY long OID! */) {
419 arcs = malloc(sizeof(*arcs) * (tlv_len + 1));
420 if(arcs) {
421 vbuf = malloc(tlv_len + 1);
422 /* Not checking is intentional */
423 }
424 }
425 case ASN_BASIC_UTCTime:
426 case ASN_BASIC_GeneralizedTime:
427 case ASN_STRING_NumericString:
428 case ASN_STRING_PrintableString:
429 case ASN_STRING_VisibleString:
430 case ASN_STRING_IA5String:
431 case ASN_STRING_UTF8String:
432 break; /* Directly compatible with UTF-8 */
433 case ASN_STRING_BMPString:
434 case ASN_STRING_UniversalString:
435 break; /* Not directly compatible with UTF-8 */
436 default:
437 /* Conditionally compatible with UTF-8 */
438 if((
439 (etype & ASN_STRING_MASK)
440 ||
441 (etype == ASN_BASIC_OCTET_STRING)
442 ) && (tlv_len > 0 && tlv_len < 128 * 1024)) {
443 vbuf = malloc(tlv_len + 1);
444 /* Not checking is intentional */
445 }
446 break;
447 }
448
449 /* If collection vbuf is present, defer printing the F flag. */
450 if(!vbuf) printf(special_format ? " F>" : ">");
451
452 /*
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000453 * Print the value in binary or text form.
454 */
455 for(i = 0; i < tlv_len; i++) {
456 int ch = fgetc(fp);
457 if(ch == -1) {
458 fprintf(stderr,
459 "%s: Unexpected end of file (V)\n", fname);
Lev Walkin12984672004-09-24 21:00:15 +0000460 if(vbuf) free(vbuf);
461 if(arcs) free(arcs);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000462 return -1;
463 }
464 switch(etype) {
465 case ASN_BASIC_UTCTime:
466 case ASN_BASIC_GeneralizedTime:
467 case ASN_STRING_NumericString:
468 case ASN_STRING_PrintableString:
469 case ASN_STRING_VisibleString:
Lev Walkin12984672004-09-24 21:00:15 +0000470 case ASN_STRING_IA5String:
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000471 case ASN_STRING_UTF8String:
472 switch(ch) {
473 default:
474 if(((etype == ASN_STRING_UTF8String)
475 || !(ch & 0x80))
476 && (ch >= 0x20)
477 ) {
478 printf("%c", ch);
479 break;
480 }
481 /* Fall through */
482 case '<': case '>': case '&':
483 printf("&x%02x;", ch);
484 }
485 break;
486 case ASN_BASIC_BOOLEAN:
Lev Walkin12984672004-09-24 21:00:15 +0000487 switch(ch) {
488 case 0: printf("<false/>"); break;
489 case 0xff: printf("<true/>"); break;
490 default: printf("<true value=\"&x%02x\"/>", ch);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000491 }
Lev Walkin12984672004-09-24 21:00:15 +0000492 break;
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000493 case ASN_BASIC_INTEGER:
494 case ASN_BASIC_ENUMERATED:
Lev Walkin12984672004-09-24 21:00:15 +0000495 if(i) collector = collector * 256 + ch;
496 else collector = (int)(signed char)ch;
497 break;
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000498 default:
Lev Walkin12984672004-09-24 21:00:15 +0000499 if(vbuf) {
500 vbuf[i] = ch;
501 } else {
502 printf("&x%02x;", ch);
503 }
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000504 }
505 }
506
Lev Walkin12984672004-09-24 21:00:15 +0000507 /* Do post-processing */
508 switch(etype) {
509 case ASN_BASIC_INTEGER:
510 case ASN_BASIC_ENUMERATED:
Lev Walkinfcf97b32004-09-24 23:46:19 +0000511 printf("%" PRIdASN, collector);
Lev Walkin12984672004-09-24 21:00:15 +0000512 break;
513 case ASN_BASIC_OBJECT_IDENTIFIER:
514 if(vbuf) {
515 OBJECT_IDENTIFIER_t oid;
516 int arcno;
517
518 oid.buf = vbuf;
519 oid.size = tlv_len;
520
521 arcno = OBJECT_IDENTIFIER_get_arcs(&oid, arcs,
522 sizeof(*arcs), tlv_len + 1);
523 if(arcno >= 0) {
524 assert(arcno <= (tlv_len + 1));
525 printf(" F>");
526 for(i = 0; i < arcno; i++) {
527 if(i) printf(".");
528 printf("%" PRIuASN, arcs[i]);
529 }
530 free(vbuf);
531 vbuf = 0;
532 }
533 }
534 break;
535 case ASN_BASIC_RELATIVE_OID:
536 if(vbuf) {
537 RELATIVE_OID_t oid;
538 int arcno;
539
540 oid.buf = vbuf;
541 oid.size = tlv_len;
542
543 arcno = RELATIVE_OID_get_arcs(&oid, arcs,
544 sizeof(*arcs), tlv_len);
545 if(arcno >= 0) {
546 assert(arcno <= (tlv_len + 1));
547 printf(" F>");
548 for(i = 0; i < arcno; i++) {
549 if(i) printf(".");
550 printf("%" PRIuASN, arcs[i]);
551 }
552 free(vbuf);
553 vbuf = 0;
554 }
555 }
556 break;
557 default: break;
558 }
559
560 /*
561 * If the buffer was not consumed, print it out.
562 */
563 if(vbuf) {
564 int binary;
565
566 /*
567 * Check whether the data could be represented as text
568 */
569 binary = -1 * (tlv_len >> 2); /* Threshold is 25% binary */
570 for(i = 0; i < tlv_len; i++) {
571 switch(vbuf[i]) {
572 case 0x1b: binary = 1; break;
573 case 0x09: case 0x0a: case 0x0d: continue;
574 default:
575 if(vbuf[i] < 0x20 || (vbuf[i] & 0x80))
576 if(++binary > 0) /* Way too many */
577 break;
578 continue;
579 }
580 break;
581 }
582 printf(">");
583 for(i = 0; i < tlv_len; i++) {
584 if(binary > 0 || vbuf[i] < 0x20 || (vbuf[i] & 0x80))
585 printf("&x%02x;", vbuf[i]);
586 else
587 printf("%c", vbuf[i]);
588 }
589 free(vbuf);
590 }
591
592 if(arcs) free(arcs);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000593 return 0;
594}
595
596
597static int
598decode_tlv_from_string(const char *datastring) {
599 unsigned char *data, *dp;
600 size_t dsize; /* Data size */
601 ssize_t len;
602 ber_tlv_tag_t tlv_tag;
603 ber_tlv_len_t tlv_len;
604 const char *p;
605 int half;
606
607 dsize = strlen(datastring) + 1;
608 dp = data = calloc(1, dsize);
609 assert(data);
610
611 for(half = 0, p = datastring; *p; p++) {
612 switch(*p) {
613 case '0': case '1': case '2': case '3': case '4':
614 case '5': case '6': case '7': case '8': case '9':
615 *dp |= *p - '0'; break;
616 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
617 *dp |= *p - 'A' + 10; break;
618 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
619 *dp |= *p - 'a' + 10; break;
620 case ' ': case '\t': case '\r': case '\n':
621 continue;
622 default:
623 fprintf(stderr, "Unexpected symbols in data string:\n");
624 fprintf(stderr, "%s\n", datastring);
625 for(dp = data; datastring < p; datastring++, dp++)
626 *dp = ' ';
627 *dp = '\0';
628 fprintf(stderr, "%s^ <- here\n", (char *)data);
629 return -1;
630 }
631 if(half) dp++; else (*dp) <<= 4;
632 half = !half;
633 }
634
635 assert((size_t)(dp - data) <= dsize);
636 dsize = dp - data;
637
638 printf("BER: ");
639 for(dp = data; dp < data + dsize; dp++)
640 printf("%02X", *dp);
641 printf("\n");
642
643 len = ber_fetch_tag(data, dsize, &tlv_tag);
644 switch(len) {
645 case -1:
646 fprintf(stderr, "TAG: Fatal error deciphering tag\n");
647 return -1;
648 case 0:
649 fprintf(stderr, "TAG: More data expected\n");
650 return -1;
651 default:
652 printf("TAG: ");
653 ber_tlv_tag_fwrite(tlv_tag, stdout);
654 if(BER_TLV_CONSTRUCTED(data)) {
655 printf(" (constructed)");
656 } else if(dsize >= 2 && data[0] == 0 && data[1] == 0) {
657 printf(" (end-of-content)");
658 } else {
659 printf(" (primitive)");
660 }
661 if(BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL) {
662 const char *str;
663 ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
664 str = ASN_UNIVERSAL_TAG2STR(tvalue);
665 if(str) printf(" \"%s\"", str);
666 }
667 printf("\n");
668 }
669
670 if(dsize > (size_t)len) {
671 len = ber_fetch_length(BER_TLV_CONSTRUCTED(data),
672 data + len, dsize - len, &tlv_len);
673 switch(len) {
674 case -1:
675 fprintf(stderr,
676 "LEN: Fatal error deciphering length\n");
677 return -1;
678 case 0:
679 fprintf(stderr, "LEN: More data expected\n");
680 return -1;
681 default:
682 if(tlv_len == (ber_tlv_len_t)-1)
683 printf("LEN: Indefinite length encoding\n");
684 else
685 printf("LEN: %ld bytes\n", (long)tlv_len);
686 }
687 }
688
689 return 0;
690}
Lev Walkin12984672004-09-24 21:00:15 +0000691
692/*
693 * Dummy functions.
694 */
Lev Walkin87534e02004-10-20 15:50:23 +0000695asn_dec_rval_t ber_check_tags(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_struct_ctx_t *opt_ctx, 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; (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; }
Lev Walkina35f3ba2004-10-21 12:21:54 +0000696
Lev Walkin77995ef2004-09-29 13:29:57 +0000697ssize_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; }
Lev Walkina35f3ba2004-10-21 12:21:54 +0000698
699asn_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, void *buf_ptr, size_t size, int (*otd)(void *struct_key, void *chunk_buf, size_t chunk_size), ssize_t (*br)(void *struct_key, void *chunk_buf, size_t chunk_size, int have_more)) { asn_dec_rval_t rv; (void)opt_codec_ctx; (void)ctx; (void)struct_key; (void)xml_tag; (void)buf_ptr; (void)size; (void)otd; (void)br; return rv; }
700