blob: db00157f8ab27b13fba89c6fe6f4eb48f2971506 [file] [log] [blame]
Lev Walkin12984672004-09-24 21:00:15 +00001/*-
Lev Walkinf9854342005-06-08 00:06:59 +00002 * Copyright (c) 2004, 2005 Lev Walkin <vlm@lionet.info>. All rights reserved.
Lev Walkin12984672004-09-24 21:00:15 +00003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 * $Id$
26 */
Lev Walkinc0d04912005-02-25 12:52:27 +000027#include "sys-common.h"
Lev Walkin06b8d7a2004-09-23 22:06:02 +000028
29#include <asn1parser.h> /* For static string tables */
30
Lev Walkin12984672004-09-24 21:00:15 +000031#include <asn_application.h>
32#include <constraints.c>
Lev Walkin06b8d7a2004-09-23 22:06:02 +000033#include <ber_tlv_tag.c>
34#include <ber_tlv_length.c>
Lev Walkin12984672004-09-24 21:00:15 +000035#include <OBJECT_IDENTIFIER.c>
36#include <RELATIVE-OID.c>
Lev Walkina35f3ba2004-10-21 12:21:54 +000037#include <asn_codecs_prim.c>
Lev Walkin06b8d7a2004-09-23 22:06:02 +000038
Lev Walkinc0d04912005-02-25 12:52:27 +000039#undef COPYRIGHT
40#define COPYRIGHT \
Lev Walkinf9854342005-06-08 00:06:59 +000041 "Copyright (c) 2004, 2005 Lev Walkin <vlm@lionet.info>\n"
Lev Walkinc0d04912005-02-25 12:52:27 +000042
Lev Walkin06b8d7a2004-09-23 22:06:02 +000043static void usage(const char *av0); /* Print the Usage screen and exit */
44static int process(const char *fname); /* Perform the BER decoding */
45static int decode_tlv_from_string(const char *datastring);
46
Lev Walkin12984672004-09-24 21:00:15 +000047static int single_type_decoding = 0; /* -1 enables that */
48static int pretty_printing = 1; /* -p disables that */
49static char *indent_buffer = " "; /* -i controls that */
Lev Walkin06b8d7a2004-09-23 22:06:02 +000050
51int
52main(int ac, char **av) {
53 int ch; /* Command line character */
54 int i; /* Index in some loops */
55
56 /*
57 * Process command-line options.
58 */
Lev Walkin12984672004-09-24 21:00:15 +000059 while((ch = getopt(ac, av, "1hi:pt:v")) != -1)
Lev Walkin06b8d7a2004-09-23 22:06:02 +000060 switch(ch) {
Lev Walkin12984672004-09-24 21:00:15 +000061 case '1':
62 single_type_decoding = 1;
63 break;
Lev Walkin06b8d7a2004-09-23 22:06:02 +000064 case 't':
65 if(decode_tlv_from_string(optarg))
66 exit(EX_DATAERR);
67 exit(0);
Lev Walkin12984672004-09-24 21:00:15 +000068 case 'p':
69 pretty_printing = 0;
70 break;
Lev Walkin06b8d7a2004-09-23 22:06:02 +000071 case 'i':
72 i = atoi(optarg);
73 if(i >= 0 && i < 16) {
74 indent_buffer = alloca(i + 1);
75 memset(indent_buffer, ' ', i);
76 indent_buffer[i] = '\0';
77 } else {
78 fprintf(stderr, "-i %s: Invalid indent value\n",optarg);
79 exit(EX_USAGE);
80 }
81 break;
82 case 'v':
83 fprintf(stderr, "ASN.1 BER Decoder, v" VERSION "\n" COPYRIGHT);
84 exit(0);
85 break;
Lev Walkin12984672004-09-24 21:00:15 +000086 case 'h':
Lev Walkin06b8d7a2004-09-23 22:06:02 +000087 default:
88 usage(av[0]);
89 }
90
91 /*
92 * Ensure that there are some input files present.
93 */
94 if(ac > optind) {
95 ac -= optind;
96 av += optind;
97 } else {
98 fprintf(stderr, "%s: No input files specified\n", av[0]);
99 exit(1);
100 }
101
102 setvbuf(stdout, 0, _IOLBF, 0);
103
104 /*
105 * Iterate over input files and parse each.
106 * All syntax trees from all files will be bundled together.
107 */
108 for(i = 0; i < ac; i++) {
109 if(process(av[i]))
110 exit(EX_DATAERR);
111 }
112
113 return 0;
114}
115
116/*
117 * Print the usage screen and exit(EX_USAGE).
118 */
119static void
120usage(const char *av0) {
121 fprintf(stderr,
122"ASN.1 BER Decoder, v" VERSION "\n" COPYRIGHT
123"Usage: %s [options] [-] [file ...]\n"
124"Options:\n"
Lev Walkin12984672004-09-24 21:00:15 +0000125" -1 Decode only the first BER structure (otherwise, until EOF)\n"
126" -i <indent> Amount of spaces for output indentation (default is 4)\n"
127" -p Do not attempt pretty-printing of known ASN.1 types\n"
128" -t <data-string> Decode the given tag[/length] sequence (e.g. -t \"bf20\")\n"
129"\n"
130"The XML opening tag format is as follows:\n"
Lev Walkinf9854342005-06-08 00:06:59 +0000131" <tform O=\"off\" T=\"tag\" TL=\"tl_len\" V=\"{Indefinite|v_len}\" [A=\"type\"] [F]>\n"
Lev Walkin12984672004-09-24 21:00:15 +0000132"Where:\n"
133" tform Which form the value is in: constructed (\"C\", \"I\") or primitive (\"P\")\n"
Lev Walkinf9854342005-06-08 00:06:59 +0000134" off Offset of the encoded element in the unber input stream\n"
135" tag The tag class and value in human readable form\n"
Lev Walkin12984672004-09-24 21:00:15 +0000136" tl_len The length of the TL (BER Tag and Length) encoding\n"
137" v_len The length of the value (V, encoded by the L), may be \"Indefinite\"\n"
138" type Likely name of the underlying ASN.1 type (for [UNIVERSAL n] tags)\n"
139" [F] Indicates that the value was reformatted (pretty-printed)\n"
140"See the manual page for details\n"
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000141 , av0);
142 exit(EX_USAGE);
143}
144
145typedef enum pd_code {
146 PD_FAILED = -1,
147 PD_FINISHED = 0,
148 PD_EOF = 1,
149} pd_code_e;
Lev Walkinf9854342005-06-08 00:06:59 +0000150static pd_code_e process_deeper(const char *fname, FILE *fp, asn1c_integer_t *offset, int level, ssize_t limit, ssize_t *frame_size, int expect_eoc);
151static void print_TL(int fin, asn1c_integer_t offset, int level, int constr, ssize_t tlen, ber_tlv_tag_t, ber_tlv_len_t);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000152static int print_V(const char *fname, FILE *fp, ber_tlv_tag_t, ber_tlv_len_t);
153
154/*
155 * Open the file and initiate recursive processing.
156 */
157static int
158process(const char *fname) {
159 FILE *fp;
160 pd_code_e pdc;
Lev Walkinf9854342005-06-08 00:06:59 +0000161 asn1c_integer_t offset = 0; /* Stream decoding position */
162 ssize_t frame_size = 0; /* Single frame size */
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000163
164 if(strcmp(fname, "-")) {
165 fp = fopen(fname, "r");
166 if(!fp) {
167 perror(fname);
168 return -1;
169 }
170 } else {
171 fp = stdin;
172 }
173
174 /*
175 * Fetch out BER-encoded data until EOF or error.
176 */
177 do {
Lev Walkinf9854342005-06-08 00:06:59 +0000178 pdc = process_deeper(fname, fp, &offset, 0, -1, &frame_size, 0);
Lev Walkin12984672004-09-24 21:00:15 +0000179 } while(pdc == PD_FINISHED && !single_type_decoding);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000180
181 if(fp != stdin)
182 fclose(fp);
183
184 if(pdc == PD_FAILED)
185 return -1;
186 return 0;
187}
188
189/*
190 * Process the TLV recursively.
191 */
Lev Walkinf9854342005-06-08 00:06:59 +0000192static pd_code_e process_deeper(const char *fname, FILE *fp, asn1c_integer_t *offset, int level, ssize_t limit, ssize_t *frame_size, int expect_eoc) {
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000193 unsigned char tagbuf[32];
194 ssize_t tblen = 0;
195 pd_code_e pdc = PD_FINISHED;
196 ber_tlv_tag_t tlv_tag;
197 ber_tlv_len_t tlv_len;
198 ssize_t t_len;
199 ssize_t l_len;
200
201 do {
202 int constr;
203 int ch;
204
205 if(limit == 0)
206 return PD_FINISHED;
207
208 if(limit >= 0 && tblen >= limit) {
209 fprintf(stderr,
Lev Walkinf9854342005-06-08 00:06:59 +0000210 "%s: Too long TL sequence (%ld >= %ld)"
211 " at %" PRIdASN ". "
212 "Broken or maliciously constructed file\n",
213 fname, (long)tblen, (long)limit, *offset);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000214 return PD_FAILED;
215 }
216
Lev Walkinf9854342005-06-08 00:06:59 +0000217 /* Get the next byte from the input stream */
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000218 ch = fgetc(fp);
219 if(ch == -1) {
Lev Walkinf9854342005-06-08 00:06:59 +0000220 if(tblen || limit) {
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000221 fprintf(stderr,
Lev Walkinf9854342005-06-08 00:06:59 +0000222 "%s: Unexpected end of file (TL)"
223 " at %" PRIdASN "\n",
224 fname, *offset);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000225 return PD_FAILED;
226 } else {
227 return PD_EOF;
228 }
229 }
230
231 tagbuf[tblen++] = ch;
232
233 /*
234 * Decode the TLV tag.
235 */
236 t_len = ber_fetch_tag(tagbuf, tblen, &tlv_tag);
237 switch(t_len) {
238 case -1:
Lev Walkinf9854342005-06-08 00:06:59 +0000239 fprintf(stderr, "%s: Fatal error decoding tag"
240 " at %" PRIdASN "+%ld\n",
241 fname, *offset, (long)tblen);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000242 return PD_FAILED;
243 case 0:
244 /* More data expected */
245 continue;
246 }
247
248 /*
249 * Decode the TLV length.
250 */
251 constr = BER_TLV_CONSTRUCTED(tagbuf);
252 l_len = ber_fetch_length(constr,
253 tagbuf + t_len, tblen - t_len, &tlv_len);
254 switch(l_len) {
255 case -1:
Lev Walkinf9854342005-06-08 00:06:59 +0000256 fprintf(stderr,
257 "%s: Fatal error decoding value length"
258 " at %" PRIdASN "\n",
259 fname, *offset + t_len);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000260 return PD_FAILED;
261 case 0:
262 /* More data expected */
263 continue;
264 }
265
266 /* Make sure the T & L decoders took exactly the whole buffer */
267 assert((t_len + l_len) == tblen);
268
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000269 if(!expect_eoc || tagbuf[0] || tagbuf[1])
Lev Walkinf9854342005-06-08 00:06:59 +0000270 print_TL(0, *offset, level, constr, tblen, tlv_tag, tlv_len);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000271
272 if(limit != -1) {
273 /* If limit is set, account for the TL sequence */
274 limit -= (t_len + l_len);
275 assert(limit >= 0);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000276
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000277 if(tlv_len > limit) {
278 fprintf(stderr,
279 "%s: Structure advertizes length (%ld) "
280 "greater than of a parent container (%ld)\n",
281 fname, (long)tlv_len, (long)limit);
282 return PD_FAILED;
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000283 }
284 }
285
Lev Walkinf9854342005-06-08 00:06:59 +0000286 *offset += t_len + l_len;
287 *frame_size += t_len + l_len;
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000288
289 if(expect_eoc && tagbuf[0] == '\0' && tagbuf[1] == '\0') {
290 /* End of content octets */
Lev Walkinf9854342005-06-08 00:06:59 +0000291 print_TL(1, *offset, level - 1, 1, 2, 0, -1);
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000292 return PD_FINISHED;
293 }
294
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000295 if(constr) {
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000296 ssize_t dec = 0;
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000297 /*
298 * This is a constructed type. Process recursively.
299 */
Lev Walkin12984672004-09-24 21:00:15 +0000300 printf(">\n"); /* Close the opening tag */
Lev Walkin7c9e9232004-10-02 00:10:25 +0000301 if(tlv_len != -1 && limit != -1) {
302 assert(limit >= tlv_len);
303 }
Lev Walkinf9854342005-06-08 00:06:59 +0000304 pdc = process_deeper(fname, fp, offset, level + 1,
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000305 tlv_len == -1 ? limit : tlv_len,
306 &dec, tlv_len == -1);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000307 if(pdc == PD_FAILED) return pdc;
Lev Walkin7c9e9232004-10-02 00:10:25 +0000308 if(limit != -1) {
309 assert(limit >= dec);
310 limit -= dec;
311 }
Lev Walkinf9854342005-06-08 00:06:59 +0000312 *frame_size += dec;
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000313 if(tlv_len == -1) {
314 tblen = 0;
315 continue;
316 }
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000317 } else {
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000318 assert(tlv_len >= 0);
319 if(print_V(fname, fp, tlv_tag, tlv_len))
320 return PD_FAILED;
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000321
Lev Walkin7c9e9232004-10-02 00:10:25 +0000322 if(limit != -1) {
323 assert(limit >= tlv_len);
324 limit -= tlv_len;
325 }
Lev Walkinf9854342005-06-08 00:06:59 +0000326 *offset += tlv_len;
327 *frame_size += tlv_len;
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000328 }
329
Lev Walkinf9854342005-06-08 00:06:59 +0000330 print_TL(1, *offset, level, constr, tblen, tlv_tag, tlv_len);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000331
332 tblen = 0;
333 } while(1);
334
335 return pdc;
336}
337
338static void
Lev Walkinf9854342005-06-08 00:06:59 +0000339print_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) {
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000340
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000341 if(fin && !constr) {
342 printf("</P>\n");
343 return;
344 }
345
346 while(level-- > 0) printf(indent_buffer); /* Print indent */
347 printf(fin ? "</" : "<");
348
Lev Walkin12984672004-09-24 21:00:15 +0000349 printf(constr ? ((tlv_len == -1) ? "I" : "C") : "P");
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000350
Lev Walkinf9854342005-06-08 00:06:59 +0000351 /* In case of <P>, <C>, <I>, </I> print out the offset */
352 if(fin == 0 || tlv_len == -1)
353 printf(" O=\"%" PRIdASN "\"", offset);
354
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000355 printf(" T=\"");
356 ber_tlv_tag_fwrite(tlv_tag, stdout);
357 printf("\"");
358
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000359 if(!fin || tlv_len == -1)
Lev Walkin12984672004-09-24 21:00:15 +0000360 printf(" TL=\"%ld\"", (long)tlen);
Lev Walkin0cb0fc52004-09-27 20:31:19 +0000361 if(!fin) {
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000362 if(tlv_len == -1)
Lev Walkin12984672004-09-24 21:00:15 +0000363 printf(" V=\"Indefinite\"");
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000364 else
Lev Walkin12984672004-09-24 21:00:15 +0000365 printf(" V=\"%ld\"", (long)tlv_len);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000366 }
367
368 if(BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL) {
369 const char *str;
370 ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
371 str = ASN_UNIVERSAL_TAG2STR(tvalue);
372 if(str) printf(" A=\"%s\"", str);
373 }
374
Lev Walkin12984672004-09-24 21:00:15 +0000375 if(fin) printf(">\n");
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000376}
377
Lev Walkin12984672004-09-24 21:00:15 +0000378/*
379 * Print the value in binary form, or reformat for pretty-printing.
380 */
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000381static int
382print_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 +0000383 asn1c_integer_t *arcs = 0; /* Object identifier arcs */
Lev Walkin12984672004-09-24 21:00:15 +0000384 unsigned char *vbuf = 0;
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000385 asn1p_expr_type_e etype = 0;
Lev Walkin77995ef2004-09-29 13:29:57 +0000386 asn1c_integer_t collector = 0;
Lev Walkin12984672004-09-24 21:00:15 +0000387 int special_format = 0;
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000388 ssize_t i;
389
390 /* Figure out what type is it */
Lev Walkin12984672004-09-24 21:00:15 +0000391 if(BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL
392 && pretty_printing) {
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000393 ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
394 etype = ASN_UNIVERSAL_TAG2TYPE(tvalue);
395 }
396
397 /*
Lev Walkin12984672004-09-24 21:00:15 +0000398 * Determine how to print the value, either in its native binary form,
399 * encoded with &xNN characters, or using pretty-printing.
400 * The basic string types (including "useful types", like UTCTime)
401 * are excempt from this determination logic, because their alphabets
402 * are subsets of the XML's native UTF-8 encoding.
403 */
404 switch(etype) {
405 case ASN_BASIC_BOOLEAN:
406 if(tlv_len == 1)
407 special_format = 1;
408 else
409 etype = 0;
410 break;
411 case ASN_BASIC_INTEGER:
412 case ASN_BASIC_ENUMERATED:
413 if((size_t)tlv_len <= sizeof(collector))
414 special_format = 1;
415 else
416 etype = 0;
417 break;
418 case ASN_BASIC_OBJECT_IDENTIFIER:
419 case ASN_BASIC_RELATIVE_OID:
420 if(tlv_len > 0 && tlv_len < 128*1024 /* VERY long OID! */) {
421 arcs = malloc(sizeof(*arcs) * (tlv_len + 1));
422 if(arcs) {
423 vbuf = malloc(tlv_len + 1);
424 /* Not checking is intentional */
425 }
426 }
427 case ASN_BASIC_UTCTime:
428 case ASN_BASIC_GeneralizedTime:
429 case ASN_STRING_NumericString:
430 case ASN_STRING_PrintableString:
431 case ASN_STRING_VisibleString:
432 case ASN_STRING_IA5String:
433 case ASN_STRING_UTF8String:
434 break; /* Directly compatible with UTF-8 */
435 case ASN_STRING_BMPString:
436 case ASN_STRING_UniversalString:
437 break; /* Not directly compatible with UTF-8 */
438 default:
439 /* Conditionally compatible with UTF-8 */
440 if((
441 (etype & ASN_STRING_MASK)
442 ||
443 (etype == ASN_BASIC_OCTET_STRING)
Lev Walkin6550fd52004-10-26 13:47:34 +0000444 ||
445 /*
446 * AUTOMATIC TAGS or IMPLICIT TAGS in effect,
447 * Treat this primitive type as OCTET_STRING.
448 */
449 (BER_TAG_CLASS(tlv_tag) != ASN_TAG_CLASS_UNIVERSAL
450 && pretty_printing)
Lev Walkin12984672004-09-24 21:00:15 +0000451 ) && (tlv_len > 0 && tlv_len < 128 * 1024)) {
452 vbuf = malloc(tlv_len + 1);
453 /* Not checking is intentional */
454 }
455 break;
456 }
457
458 /* If collection vbuf is present, defer printing the F flag. */
459 if(!vbuf) printf(special_format ? " F>" : ">");
460
461 /*
Lev Walkin6550fd52004-10-26 13:47:34 +0000462 * Print the value in binary or text form,
463 * or collect the bytes into vbuf.
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000464 */
465 for(i = 0; i < tlv_len; i++) {
466 int ch = fgetc(fp);
467 if(ch == -1) {
468 fprintf(stderr,
469 "%s: Unexpected end of file (V)\n", fname);
Lev Walkin12984672004-09-24 21:00:15 +0000470 if(vbuf) free(vbuf);
471 if(arcs) free(arcs);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000472 return -1;
473 }
474 switch(etype) {
475 case ASN_BASIC_UTCTime:
476 case ASN_BASIC_GeneralizedTime:
477 case ASN_STRING_NumericString:
478 case ASN_STRING_PrintableString:
479 case ASN_STRING_VisibleString:
Lev Walkin12984672004-09-24 21:00:15 +0000480 case ASN_STRING_IA5String:
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000481 case ASN_STRING_UTF8String:
482 switch(ch) {
483 default:
484 if(((etype == ASN_STRING_UTF8String)
485 || !(ch & 0x80))
486 && (ch >= 0x20)
487 ) {
488 printf("%c", ch);
489 break;
490 }
491 /* Fall through */
Lev Walkin6550fd52004-10-26 13:47:34 +0000492 case 0x3c: case 0x3e: case 0x26:
Lev Walkin451af472004-10-25 22:58:49 +0000493 printf("&#x%02x;", ch);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000494 }
495 break;
496 case ASN_BASIC_BOOLEAN:
Lev Walkin12984672004-09-24 21:00:15 +0000497 switch(ch) {
498 case 0: printf("<false/>"); break;
499 case 0xff: printf("<true/>"); break;
Lev Walkin451af472004-10-25 22:58:49 +0000500 default: printf("<true value=\"&#x%02x\"/>", ch);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000501 }
Lev Walkin12984672004-09-24 21:00:15 +0000502 break;
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000503 case ASN_BASIC_INTEGER:
504 case ASN_BASIC_ENUMERATED:
Lev Walkin12984672004-09-24 21:00:15 +0000505 if(i) collector = collector * 256 + ch;
506 else collector = (int)(signed char)ch;
507 break;
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000508 default:
Lev Walkin12984672004-09-24 21:00:15 +0000509 if(vbuf) {
510 vbuf[i] = ch;
511 } else {
Lev Walkin451af472004-10-25 22:58:49 +0000512 printf("&#x%02x;", ch);
Lev Walkin12984672004-09-24 21:00:15 +0000513 }
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000514 }
515 }
516
Lev Walkin12984672004-09-24 21:00:15 +0000517 /* Do post-processing */
518 switch(etype) {
519 case ASN_BASIC_INTEGER:
520 case ASN_BASIC_ENUMERATED:
Lev Walkinfcf97b32004-09-24 23:46:19 +0000521 printf("%" PRIdASN, collector);
Lev Walkin12984672004-09-24 21:00:15 +0000522 break;
523 case ASN_BASIC_OBJECT_IDENTIFIER:
524 if(vbuf) {
525 OBJECT_IDENTIFIER_t oid;
526 int arcno;
527
528 oid.buf = vbuf;
529 oid.size = tlv_len;
530
531 arcno = OBJECT_IDENTIFIER_get_arcs(&oid, arcs,
532 sizeof(*arcs), tlv_len + 1);
533 if(arcno >= 0) {
534 assert(arcno <= (tlv_len + 1));
535 printf(" F>");
536 for(i = 0; i < arcno; i++) {
537 if(i) printf(".");
538 printf("%" PRIuASN, arcs[i]);
539 }
540 free(vbuf);
541 vbuf = 0;
542 }
543 }
544 break;
545 case ASN_BASIC_RELATIVE_OID:
546 if(vbuf) {
547 RELATIVE_OID_t oid;
548 int arcno;
549
550 oid.buf = vbuf;
551 oid.size = tlv_len;
552
553 arcno = RELATIVE_OID_get_arcs(&oid, arcs,
554 sizeof(*arcs), tlv_len);
555 if(arcno >= 0) {
556 assert(arcno <= (tlv_len + 1));
557 printf(" F>");
558 for(i = 0; i < arcno; i++) {
559 if(i) printf(".");
560 printf("%" PRIuASN, arcs[i]);
561 }
562 free(vbuf);
563 vbuf = 0;
564 }
565 }
566 break;
567 default: break;
568 }
569
570 /*
571 * If the buffer was not consumed, print it out.
Lev Walkin6550fd52004-10-26 13:47:34 +0000572 * It might be an OCTET STRING or other primitive type,
573 * which might actually be printable, but we need to figure it out.
Lev Walkin12984672004-09-24 21:00:15 +0000574 */
575 if(vbuf) {
576 int binary;
577
578 /*
579 * Check whether the data could be represented as text
580 */
Lev Walkin6550fd52004-10-26 13:47:34 +0000581 binary = -1 * (tlv_len >> 3); /* Threshold is 12.5% binary */
Lev Walkin12984672004-09-24 21:00:15 +0000582 for(i = 0; i < tlv_len; i++) {
583 switch(vbuf[i]) {
584 case 0x1b: binary = 1; break;
585 case 0x09: case 0x0a: case 0x0d: continue;
586 default:
Lev Walkin6550fd52004-10-26 13:47:34 +0000587 if(vbuf[i] < 0x20 || vbuf[i] >= 0x7f)
Lev Walkin12984672004-09-24 21:00:15 +0000588 if(++binary > 0) /* Way too many */
589 break;
590 continue;
591 }
592 break;
593 }
594 printf(">");
595 for(i = 0; i < tlv_len; i++) {
Lev Walkin6550fd52004-10-26 13:47:34 +0000596 if(binary > 0 || vbuf[i] < 0x20 || vbuf[i] >= 0x7f
597 || vbuf[i] == 0x26 /* '&' */
598 || vbuf[i] == 0x3c /* '<' */
599 || vbuf[i] == 0x3e /* '>' */
600 )
Lev Walkin451af472004-10-25 22:58:49 +0000601 printf("&#x%02x;", vbuf[i]);
Lev Walkin12984672004-09-24 21:00:15 +0000602 else
603 printf("%c", vbuf[i]);
604 }
605 free(vbuf);
606 }
607
608 if(arcs) free(arcs);
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000609 return 0;
610}
611
612
613static int
614decode_tlv_from_string(const char *datastring) {
615 unsigned char *data, *dp;
616 size_t dsize; /* Data size */
617 ssize_t len;
618 ber_tlv_tag_t tlv_tag;
619 ber_tlv_len_t tlv_len;
620 const char *p;
621 int half;
622
623 dsize = strlen(datastring) + 1;
624 dp = data = calloc(1, dsize);
625 assert(data);
626
627 for(half = 0, p = datastring; *p; p++) {
628 switch(*p) {
629 case '0': case '1': case '2': case '3': case '4':
630 case '5': case '6': case '7': case '8': case '9':
631 *dp |= *p - '0'; break;
632 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
633 *dp |= *p - 'A' + 10; break;
634 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
635 *dp |= *p - 'a' + 10; break;
636 case ' ': case '\t': case '\r': case '\n':
637 continue;
638 default:
639 fprintf(stderr, "Unexpected symbols in data string:\n");
640 fprintf(stderr, "%s\n", datastring);
641 for(dp = data; datastring < p; datastring++, dp++)
642 *dp = ' ';
643 *dp = '\0';
644 fprintf(stderr, "%s^ <- here\n", (char *)data);
645 return -1;
646 }
647 if(half) dp++; else (*dp) <<= 4;
648 half = !half;
649 }
650
651 assert((size_t)(dp - data) <= dsize);
652 dsize = dp - data;
653
654 printf("BER: ");
655 for(dp = data; dp < data + dsize; dp++)
656 printf("%02X", *dp);
657 printf("\n");
658
659 len = ber_fetch_tag(data, dsize, &tlv_tag);
660 switch(len) {
661 case -1:
Lev Walkinf9854342005-06-08 00:06:59 +0000662 fprintf(stderr, "TAG: Fatal error decoding tag\n");
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000663 return -1;
664 case 0:
665 fprintf(stderr, "TAG: More data expected\n");
666 return -1;
667 default:
668 printf("TAG: ");
669 ber_tlv_tag_fwrite(tlv_tag, stdout);
670 if(BER_TLV_CONSTRUCTED(data)) {
671 printf(" (constructed)");
672 } else if(dsize >= 2 && data[0] == 0 && data[1] == 0) {
673 printf(" (end-of-content)");
674 } else {
675 printf(" (primitive)");
676 }
677 if(BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL) {
678 const char *str;
679 ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
680 str = ASN_UNIVERSAL_TAG2STR(tvalue);
681 if(str) printf(" \"%s\"", str);
682 }
683 printf("\n");
684 }
685
686 if(dsize > (size_t)len) {
687 len = ber_fetch_length(BER_TLV_CONSTRUCTED(data),
688 data + len, dsize - len, &tlv_len);
689 switch(len) {
690 case -1:
691 fprintf(stderr,
Lev Walkinf9854342005-06-08 00:06:59 +0000692 "LEN: Fatal error decoding length\n");
Lev Walkin06b8d7a2004-09-23 22:06:02 +0000693 return -1;
694 case 0:
695 fprintf(stderr, "LEN: More data expected\n");
696 return -1;
697 default:
698 if(tlv_len == (ber_tlv_len_t)-1)
699 printf("LEN: Indefinite length encoding\n");
700 else
701 printf("LEN: %ld bytes\n", (long)tlv_len);
702 }
703 }
704
705 return 0;
706}
Lev Walkin12984672004-09-24 21:00:15 +0000707
708/*
709 * Dummy functions.
710 */
Lev Walkincbf5a7e2005-03-10 18:53:33 +0000711asn_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; (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 +0000712
Lev Walkin77995ef2004-09-29 13:29:57 +0000713ssize_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 +0000714
Lev Walkin51be70c2005-03-10 09:33:13 +0000715asn_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; (void)opt_codec_ctx; (void)ctx; (void)struct_key; (void)xml_tag; (void)buf_ptr; (void)size; (void)otd; (void)br; return rv; }
Lev Walkina35f3ba2004-10-21 12:21:54 +0000716
Lev Walkin51be70c2005-03-10 09:33:13 +0000717int xer_is_whitespace(const void *b, size_t s) { (void)b; (void)s; return 0; }