blob: 0733331d642c8bca911d5d7fb140a340600b608d [file] [log] [blame]
Lev Walkinccfaf2a2019-01-21 17:45:31 -08001/*
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 */
27#include "asn1_common.h"
28#include "libasn1_unber_tool.h"
29
30#define ASN_DISABLE_PER_SUPPORT 1
31#define ASN_DISABLE_OER_SUPPORT 1
32
33#include <asn1parser.h> /* For static string tables */
34
35#include <asn_application.h>
36#include <constraints.c>
37#include <ber_tlv_tag.c>
38#include <ber_tlv_length.c>
39#include <INTEGER.c>
40#include <OBJECT_IDENTIFIER.c>
41#include <RELATIVE-OID.c>
42#include <asn_codecs_prim.c>
43#include <asn1p_integer.c>
44#include <asn_internal.c>
45
46static int single_type_decoding = 0; /* -1 enables that */
47static int minimalistic = 0; /* -m enables that */
48static int pretty_printing = 1; /* -p disables that */
49static long skip_bytes = 0; /* -s controls that */
50static char indent_bytes[16] = " "; /* -i controls that */
51
52void set_minimalistic_output(int v) { minimalistic = v; }
53void set_single_type_decoding(int v) { single_type_decoding = v; }
54void set_pretty_printing(int v) { pretty_printing = v; }
55int set_skip_bytes(long v) { if(v < 0) return -1; skip_bytes = v; return 0; }
56int set_indent_size(int indent_size) {
57 if(indent_size < 0 || indent_size >= (int)sizeof(indent_bytes)) {
58 return -1;
59 }
60 memset(indent_bytes, ' ', indent_size);
61 indent_bytes[indent_size] = '\0';
62 return 0;
63}
64
65typedef enum pd_code {
66 PD_FAILED = -1,
67 PD_FINISHED = 0,
68 PD_EOF = 1,
69} pd_code_e;
Lev Walkin6ccf7432019-01-21 23:46:19 -080070static pd_code_e process_deeper(const char *fname, input_stream_t *,
71 output_stream_t *os, int level,
Lev Walkinccfaf2a2019-01-21 17:45:31 -080072 ssize_t limit, ber_tlv_len_t *frame_size,
73 ber_tlv_len_t effective_size, int expect_eoc);
Lev Walkin6ccf7432019-01-21 23:46:19 -080074static void print_TL(output_stream_t *, int fin, off_t offset, int level,
75 int constr, ssize_t tlen, ber_tlv_tag_t, ber_tlv_len_t,
Lev Walkinccfaf2a2019-01-21 17:45:31 -080076 ber_tlv_len_t effective_frame_size);
Lev Walkin6ccf7432019-01-21 23:46:19 -080077static int print_V(const char *fname, input_stream_t *, output_stream_t *,
78 ber_tlv_tag_t, ber_tlv_len_t);
79
80static int ibs_getc(input_stream_t *ibs) { return ibs->nextChar(ibs); }
81static int __attribute__((format(printf, 2, 3)))
82osprintf(output_stream_t *os, const char *fmt, ...) {
83 va_list ap;
84 va_start(ap, fmt);
85 int ret = os->vprintf(os, fmt, ap);
86 va_end(ap);
87 return ret;
88}
89static int __attribute__((format(printf, 2, 3)))
90osprintfError(output_stream_t *os, const char *fmt, ...) {
91 va_list ap;
92 va_start(ap, fmt);
93 int ret = os->vprintfError(os, fmt, ap);
94 va_end(ap);
95 return ret;
96}
Lev Walkinccfaf2a2019-01-21 17:45:31 -080097
98/*
99 * Open the file and initiate recursive processing.
100 */
Lev Walkin6ccf7432019-01-21 23:46:19 -0800101int
102unber_stream(const char *fname, input_stream_t *ibs, output_stream_t *os) {
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800103 pd_code_e pdc;
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800104 ber_tlv_len_t frame_size = 0; /* Single frame size */
105
106 /*
107 * Skip the requested amount of bytes.
108 */
Lev Walkin6ccf7432019-01-21 23:46:19 -0800109 for(size_t offset = 0; offset < (size_t)skip_bytes; offset++) {
110 if(ibs_getc(ibs) == -1) {
111 osprintfError(os,
112 "%s: input source has less data "
113 "than \"-s %ld\" switch wants to skip\n",
114 fname, skip_bytes);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800115 return -1;
116 }
117 }
118
119 /*
120 * Fetch out BER-encoded data until EOF or error.
121 */
122 do {
Lev Walkin6ccf7432019-01-21 23:46:19 -0800123 pdc = process_deeper(fname, ibs, os, 0, -1, &frame_size, 0, 0);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800124 } while(pdc == PD_FINISHED && !single_type_decoding);
125
126 if(pdc == PD_FAILED) return -1;
127 return 0;
128}
129
130/*
131 * Process the TLV recursively.
132 */
133static pd_code_e
Lev Walkin6ccf7432019-01-21 23:46:19 -0800134process_deeper(const char *fname, input_stream_t *ibs, output_stream_t *os,
135 int level, ssize_t limit, ber_tlv_len_t *frame_size,
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800136 ber_tlv_len_t effective_size, int expect_eoc) {
137 unsigned char tagbuf[32];
138 ssize_t tblen = 0;
139 pd_code_e pdc = PD_FINISHED;
140 ber_tlv_tag_t tlv_tag;
141 ber_tlv_len_t tlv_len;
142 ssize_t t_len;
143 ssize_t l_len;
144
145 for(;;) {
146 ber_tlv_len_t local_esize = 0;
147 int constr;
148 int ch;
149
150 if(limit == 0) return PD_FINISHED;
151
152 if(limit >= 0 && tblen >= limit) {
Lev Walkin6ccf7432019-01-21 23:46:19 -0800153 osprintfError(os,
154 "%s: Too long TL sequence (%zd >= %zd) at %lld. "
155 "Broken or maliciously constructed file\n",
156 fname, tblen, limit, ibs->bytesRead(ibs));
157 return PD_FAILED;
158 }
159
160 if(tblen >= (ssize_t)sizeof(tagbuf)) {
161 osprintfError(os,
162 "%s: Too long TL sequence (%zd bytes) at %lld. "
163 "Broken or maliciously constructed file\n",
164 fname, tblen, ibs->bytesRead(ibs));
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800165 return PD_FAILED;
166 }
167
168 /* Get the next byte from the input stream */
Lev Walkin6ccf7432019-01-21 23:46:19 -0800169 ch = ibs_getc(ibs);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800170 if(ch == -1) {
171 if(limit > 0 || expect_eoc) {
Lev Walkin6ccf7432019-01-21 23:46:19 -0800172 osprintfError(os,
173 "%s: Unexpected end of file (TL)"
174 " at %zu\n",
175 fname, (size_t)ibs->bytesRead(ibs));
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800176 return PD_FAILED;
177 } else {
178 return PD_EOF;
179 }
180 }
181
182 tagbuf[tblen++] = ch;
183
184 /*
185 * Decode the TLV tag.
186 */
187 t_len = ber_fetch_tag(tagbuf, tblen, &tlv_tag);
188 switch(t_len) {
189 case -1:
Lev Walkin6ccf7432019-01-21 23:46:19 -0800190 osprintfError(os,
191 "%s: Fatal error decoding tag"
192 " at %zu\n",
193 fname, (size_t)ibs->bytesRead(ibs));
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800194 return PD_FAILED;
195 case 0:
196 /* More data expected */
197 continue;
198 }
199
200 /*
201 * Decode the TLV length.
202 */
203 constr = BER_TLV_CONSTRUCTED(tagbuf);
204 l_len =
205 ber_fetch_length(constr, tagbuf + t_len, tblen - t_len, &tlv_len);
206 switch(l_len) {
207 case -1:
Lev Walkin6ccf7432019-01-21 23:46:19 -0800208 osprintfError(os,
209 "%s: Fatal error decoding value length"
210 " at %zu\n",
211 fname, (size_t)ibs->bytesRead(ibs));
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800212 return PD_FAILED;
213 case 0:
214 /* More data expected */
215 continue;
216 }
217
218 /* Make sure the T & L decoders took exactly the whole buffer */
Lev Walkin6ccf7432019-01-21 23:46:19 -0800219 if((t_len + l_len) != tblen) {
220 osprintfError(os,
221 "%s: Outer tag length doesn't match inner tag length"
222 " at %zu\n",
223 fname, (size_t)ibs->bytesRead(ibs));
224 return PD_FAILED;
225 }
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800226
227 if(!expect_eoc || tagbuf[0] || tagbuf[1])
Lev Walkin6ccf7432019-01-21 23:46:19 -0800228 print_TL(os, 0, ibs->bytesRead(ibs), level, constr, tblen,
229 tlv_tag, tlv_len, effective_size);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800230
231 if(limit != -1) {
232 /* If limit is set, account for the TL sequence */
233 limit -= (t_len + l_len);
234 assert(limit >= 0);
235
236 if(tlv_len > limit) {
Lev Walkin6ccf7432019-01-21 23:46:19 -0800237 osprintfError(os,
238 "%s: Structure advertizes length (%ld) "
239 "greater than of a parent container (%ld)\n",
240 fname, (long)tlv_len, (long)limit);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800241 return PD_FAILED;
242 }
243 }
244
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800245 *frame_size += t_len + l_len;
246 effective_size += t_len + l_len;
247 local_esize += t_len + l_len;
248
249 if(expect_eoc && !tagbuf[0] && !tagbuf[1]) {
250 /* End of content octets */
Lev Walkin6ccf7432019-01-21 23:46:19 -0800251 print_TL(os, 1, ibs->bytesRead(ibs), level - 1, 1, 2, 0, -1,
252 effective_size);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800253 return PD_FINISHED;
254 }
255
256 if(constr) {
257 ber_tlv_len_t dec = 0;
258 /*
259 * This is a constructed type. Process recursively.
260 */
Lev Walkin6ccf7432019-01-21 23:46:19 -0800261 osprintf(os, ">\n"); /* Close the opening tag */
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800262 if(tlv_len != -1 && limit != -1) {
263 assert(limit >= tlv_len);
264 }
Lev Walkin6ccf7432019-01-21 23:46:19 -0800265 pdc = process_deeper(fname, ibs, os, level + 1,
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800266 tlv_len == -1 ? limit : tlv_len, &dec,
267 t_len + l_len, tlv_len == -1);
268 if(pdc == PD_FAILED) return pdc;
269 if(limit != -1) {
270 assert(limit >= dec);
271 limit -= dec;
272 }
273 *frame_size += dec;
274 effective_size += dec;
275 local_esize += dec;
276 if(tlv_len == -1) {
277 tblen = 0;
278 if(pdc == PD_FINISHED && limit < 0 && !expect_eoc) return pdc;
279 continue;
280 }
281 } else {
282 assert(tlv_len >= 0);
Lev Walkin6ccf7432019-01-21 23:46:19 -0800283 if(print_V(fname, ibs, os, tlv_tag, tlv_len)) return PD_FAILED;
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800284
285 if(limit != -1) {
286 assert(limit >= tlv_len);
287 limit -= tlv_len;
288 }
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800289 *frame_size += tlv_len;
290 effective_size += tlv_len;
291 local_esize += tlv_len;
292 }
293
Lev Walkin6ccf7432019-01-21 23:46:19 -0800294 print_TL(os, 1, ibs->bytesRead(ibs), level, constr, tblen,
295 tlv_tag, tlv_len, local_esize);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800296
297 tblen = 0;
298
299 /* Report success for a single top level TLV */
300 if(level == 0 && limit == -1 && !expect_eoc) break;
301 } /* for(;;) */
302
303 return pdc;
304}
305
306static void
Lev Walkin6ccf7432019-01-21 23:46:19 -0800307print_TL(output_stream_t *os, int fin, off_t offset, int level, int constr,
308 ssize_t tlen, ber_tlv_tag_t tlv_tag, ber_tlv_len_t tlv_len,
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800309 ber_tlv_len_t effective_size) {
310 if(fin && !constr) {
Lev Walkin6ccf7432019-01-21 23:46:19 -0800311 osprintf(os, "</P>\n");
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800312 return;
313 }
314
Lev Walkin6ccf7432019-01-21 23:46:19 -0800315 while(level-- > 0) osprintf(os, "%s", indent_bytes); /* Print indent */
316 osprintf(os, fin ? "</" : "<");
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800317
Lev Walkin6ccf7432019-01-21 23:46:19 -0800318 osprintf(os, constr ? ((tlv_len == -1) ? "I" : "C") : "P");
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800319
320 /* Print out the offset of this boundary, even if closing tag */
Lev Walkin6ccf7432019-01-21 23:46:19 -0800321 if(!minimalistic) osprintf(os, " O=\"%lld\"", offset);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800322
Lev Walkin6ccf7432019-01-21 23:46:19 -0800323 osprintf(os, " T=\"%s\"", ber_tlv_tag_string(tlv_tag));
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800324
325 if(!fin || (tlv_len == -1 && !minimalistic))
Lev Walkin6ccf7432019-01-21 23:46:19 -0800326 osprintf(os, " TL=\"%ld\"", (long)tlen);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800327 if(!fin) {
328 if(tlv_len == -1)
Lev Walkin6ccf7432019-01-21 23:46:19 -0800329 osprintf(os, " V=\"Indefinite\"");
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800330 else
Lev Walkin6ccf7432019-01-21 23:46:19 -0800331 osprintf(os, " V=\"%ld\"", (long)tlv_len);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800332 }
333
334 if(!minimalistic && BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL) {
335 const char *str;
336 ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
337 str = ASN_UNIVERSAL_TAG2STR(tvalue);
Lev Walkin6ccf7432019-01-21 23:46:19 -0800338 if(str) osprintf(os, " A=\"%s\"", str);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800339 }
340
341 if(fin) {
Lev Walkin6ccf7432019-01-21 23:46:19 -0800342 if(constr && !minimalistic) {
343 osprintf(os, " L=\"%ld\"", (long)effective_size);
344 }
345 osprintf(os, ">\n");
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800346 }
347}
348
349/*
350 * Print the value in binary form, or reformat for pretty-printing.
351 */
352static int
Lev Walkin6ccf7432019-01-21 23:46:19 -0800353print_V(const char *fname, input_stream_t *ibs, output_stream_t *os,
354 ber_tlv_tag_t tlv_tag, ber_tlv_len_t tlv_len) {
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800355 asn_oid_arc_t *arcs = 0; /* Object identifier arcs */
356 unsigned char *vbuf = 0;
357 asn1p_expr_type_e etype = 0;
358 asn1c_integer_t collector = 0;
359 int special_format = 0;
360 ssize_t i;
361
362 /* Figure out what type is it */
363 if(BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL && pretty_printing) {
364 ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
365 etype = ASN_UNIVERSAL_TAG2TYPE(tvalue);
366 }
367
368 /*
369 * Determine how to print the value, either in its native binary form,
370 * encoded with &xNN characters, or using pretty-printing.
371 * The basic string types (including "useful types", like UTCTime)
372 * are excempt from this determination logic, because their alphabets
373 * are subsets of the XML's native UTF-8 encoding.
374 */
375 switch(etype) {
376 case ASN_BASIC_BOOLEAN:
377 if(tlv_len == 1)
378 special_format = 1;
379 else
380 etype = 0;
381 break;
382 case ASN_BASIC_INTEGER:
383 case ASN_BASIC_ENUMERATED:
384 if((size_t)tlv_len <= sizeof(collector))
385 special_format = 1;
386 else
387 etype = 0;
388 break;
389 case ASN_BASIC_OBJECT_IDENTIFIER:
390 case ASN_BASIC_RELATIVE_OID:
391 if(tlv_len > 0 && tlv_len < 128 * 1024 /* VERY long OID! */) {
392 arcs = MALLOC(sizeof(*arcs) * (tlv_len + 1));
393 if(arcs) {
394 vbuf = MALLOC(tlv_len + 1);
395 /* Not checking is intentional */
396 }
397 }
398 case ASN_BASIC_UTCTime:
399 case ASN_BASIC_GeneralizedTime:
400 case ASN_STRING_NumericString:
401 case ASN_STRING_PrintableString:
402 case ASN_STRING_VisibleString:
403 case ASN_STRING_IA5String:
404 case ASN_STRING_UTF8String:
405 break; /* Directly compatible with UTF-8 */
406 case ASN_STRING_BMPString:
407 case ASN_STRING_UniversalString:
408 break; /* Not directly compatible with UTF-8 */
409 default:
410 /* Conditionally compatible with UTF-8 */
411 if(((etype & ASN_STRING_MASK) || (etype == ASN_BASIC_OCTET_STRING) ||
412 /*
413 * AUTOMATIC TAGS or IMPLICIT TAGS in effect,
414 * Treat this primitive type as OCTET_STRING.
415 */
416 (BER_TAG_CLASS(tlv_tag) != ASN_TAG_CLASS_UNIVERSAL
417 && pretty_printing))
418 && (tlv_len > 0 && tlv_len < 128 * 1024)) {
419 vbuf = MALLOC(tlv_len + 1);
420 /* Not checking is intentional */
421 }
422 break;
423 }
424
425 /* If collection vbuf is present, defer printing the F flag. */
Lev Walkin6ccf7432019-01-21 23:46:19 -0800426 if(!vbuf) osprintf(os, special_format ? " F>" : ">");
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800427
428 /*
429 * Print the value in binary or text form,
430 * or collect the bytes into vbuf.
431 */
432 for(i = 0; i < tlv_len; i++) {
Lev Walkin6ccf7432019-01-21 23:46:19 -0800433 int ch = ibs_getc(ibs);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800434 if(ch == -1) {
Lev Walkin6ccf7432019-01-21 23:46:19 -0800435 osprintfError(os, "%s: Unexpected end of file (V)\n", fname);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800436 if(vbuf) FREEMEM(vbuf);
437 if(arcs) FREEMEM(arcs);
438 return -1;
439 }
440 switch(etype) {
441 case ASN_BASIC_UTCTime:
442 case ASN_BASIC_GeneralizedTime:
443 case ASN_STRING_NumericString:
444 case ASN_STRING_PrintableString:
445 case ASN_STRING_VisibleString:
446 case ASN_STRING_IA5String:
447 case ASN_STRING_UTF8String:
448 switch(ch) {
449 default:
450 if(((etype == ASN_STRING_UTF8String) || !(ch & 0x80))
451 && (ch >= 0x20)) {
Lev Walkin6ccf7432019-01-21 23:46:19 -0800452 osprintf(os, "%c", ch);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800453 break;
454 }
455 /* Fall through */
456 case 0x3c:
457 case 0x3e:
458 case 0x26:
Lev Walkin6ccf7432019-01-21 23:46:19 -0800459 osprintf(os, "&#x%02x;", ch);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800460 }
461 break;
462 case ASN_BASIC_BOOLEAN:
463 switch(ch) {
464 case 0:
Lev Walkin6ccf7432019-01-21 23:46:19 -0800465 osprintf(os, "<false/>");
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800466 break;
467 case 0xff:
Lev Walkin6ccf7432019-01-21 23:46:19 -0800468 osprintf(os, "<true/>");
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800469 break;
470 default:
Lev Walkin6ccf7432019-01-21 23:46:19 -0800471 osprintf(os, "<true value=\"&#x%02x\"/>", ch);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800472 }
473 break;
474 case ASN_BASIC_INTEGER:
475 case ASN_BASIC_ENUMERATED:
476 if(i)
477 collector = collector * 256 + ch;
478 else
479 collector = (int)(signed char)ch;
480 break;
481 default:
482 if(vbuf) {
483 vbuf[i] = ch;
484 } else {
Lev Walkin6ccf7432019-01-21 23:46:19 -0800485 osprintf(os, "&#x%02x;", ch);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800486 }
487 }
488 }
489
490 /* Do post-processing */
491 switch(etype) {
492 case ASN_BASIC_INTEGER:
493 case ASN_BASIC_ENUMERATED:
Lev Walkin6ccf7432019-01-21 23:46:19 -0800494 osprintf(os, "%s", asn1p_itoa(collector));
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800495 break;
496 case ASN_BASIC_OBJECT_IDENTIFIER:
497 if(vbuf) {
498 OBJECT_IDENTIFIER_t oid = {0, 0};
499 ssize_t arcno;
500
501 oid.buf = vbuf;
502 oid.size = tlv_len;
503
504 arcno = OBJECT_IDENTIFIER_get_arcs(&oid, arcs, tlv_len + 1);
505 if(arcno >= 0) {
506 assert(arcno <= (tlv_len + 1));
Lev Walkin6ccf7432019-01-21 23:46:19 -0800507 osprintf(os, " F>");
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800508 for(i = 0; i < arcno; i++) {
Lev Walkin6ccf7432019-01-21 23:46:19 -0800509 if(i) osprintf(os, ".");
510 osprintf(os, "%" PRIu32, arcs[i]);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800511 }
512 FREEMEM(vbuf);
513 vbuf = 0;
514 }
515 }
516 break;
517 case ASN_BASIC_RELATIVE_OID:
518 if(vbuf) {
519 RELATIVE_OID_t oid;
520 int arcno;
521
522 oid.buf = vbuf;
523 oid.size = tlv_len;
524
525 arcno = RELATIVE_OID_get_arcs(&oid, arcs, tlv_len);
526 if(arcno >= 0) {
527 assert(arcno <= tlv_len);
Lev Walkin6ccf7432019-01-21 23:46:19 -0800528 osprintf(os, " F>");
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800529 for(i = 0; i < arcno; i++) {
Lev Walkin6ccf7432019-01-21 23:46:19 -0800530 if(i) osprintf(os, ".");
531 osprintf(os, "%" PRIu32, arcs[i]);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800532 }
533 FREEMEM(vbuf);
534 vbuf = 0;
535 }
536 }
537 break;
538 default:
539 break;
540 }
541
542 /*
543 * If the buffer was not consumed, print it out.
544 * It might be an OCTET STRING or other primitive type,
545 * which might actually be printable, but we need to figure it out.
546 */
547 if(vbuf) {
548 int binary;
549
550 /*
551 * Check whether the data could be represented as text
552 */
553 binary = -1 * (tlv_len >> 3); /* Threshold is 12.5% binary */
554 for(i = 0; i < tlv_len; i++) {
555 switch(vbuf[i]) {
556 case 0x1b:
557 binary = 1;
558 break;
559 case 0x09:
560 case 0x0a:
561 case 0x0d:
562 continue;
563 default:
564 if(vbuf[i] < 0x20 || vbuf[i] >= 0x7f)
565 if(++binary > 0) /* Way too many */
566 break;
567 continue;
568 }
569 break;
570 }
Lev Walkin6ccf7432019-01-21 23:46:19 -0800571 osprintf(os, ">");
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800572 for(i = 0; i < tlv_len; i++) {
573 if(binary > 0 || vbuf[i] < 0x20 || vbuf[i] >= 0x7f
574 || vbuf[i] == 0x26 /* '&' */
575 || vbuf[i] == 0x3c /* '<' */
576 || vbuf[i] == 0x3e /* '>' */
577 )
Lev Walkin6ccf7432019-01-21 23:46:19 -0800578 osprintf(os, "&#x%02x;", vbuf[i]);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800579 else
Lev Walkin6ccf7432019-01-21 23:46:19 -0800580 osprintf(os, "%c", vbuf[i]);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800581 }
582 FREEMEM(vbuf);
583 }
584
585 if(arcs) FREEMEM(arcs);
586 return 0;
587}
588
Lev Walkin6ccf7432019-01-21 23:46:19 -0800589struct file_input_stream {
590 input_stream_t istream;
591 FILE *fp;
592 off_t offset;
593};
594
595static int file_input_stream_nextChar(input_stream_t *ibs) {
596 struct file_input_stream *fs = (struct file_input_stream *)ibs;
597 int ret = fgetc(fs->fp);
598 if(ret != -1) {
599 fs->offset++;
600 }
601 return ret;
602}
603
604static off_t file_input_stream_bytesRead(input_stream_t *ibs) {
605 struct file_input_stream *fs = (struct file_input_stream *)ibs;
606 return fs->offset;
607}
608
609struct file_output_stream {
610 output_stream_t ostream;
611 FILE *outputFile;
612 FILE *errorFile;
613};
614
615static int
616file_output_stream_vprintf(output_stream_t *os, const char *fmt, va_list ap) {
617 struct file_output_stream *fos = (struct file_output_stream *)os;
618 return vfprintf(fos->outputFile, fmt, ap);
619}
620
621static int
622file_output_stream_vprintfError(output_stream_t *os, const char *fmt, va_list ap) {
623 struct file_output_stream *fos = (struct file_output_stream *)os;
624 return vfprintf(fos->errorFile, fmt, ap);
625}
626
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800627int
628unber_file(const char *fname) {
629 FILE *fp;
630
631 if(strcmp(fname, "-")) {
632 fp = fopen(fname, "rb");
633 if(!fp) {
634 perror(fname);
635 return -1;
636 }
637 } else {
638 fp = stdin;
639 }
640
Lev Walkin6ccf7432019-01-21 23:46:19 -0800641 struct file_input_stream ifs;
642 ifs.istream.nextChar = file_input_stream_nextChar;
643 ifs.istream.bytesRead = file_input_stream_bytesRead;
644 ifs.fp = fp;
645
646 struct file_output_stream ofs;
647 ofs.ostream.vprintf = file_output_stream_vprintf;
648 ofs.ostream.vprintfError = file_output_stream_vprintfError;
649 ofs.outputFile = stdout;
650 ofs.errorFile = stderr;
651
652 int ret = unber_stream(fname, &ifs.istream, &ofs.ostream);
Lev Walkinccfaf2a2019-01-21 17:45:31 -0800653
654 if(fp != stdin) fclose(fp);
655
656 return ret;
657}
658
659int
660decode_tlv_from_hex_string(const char *datastring) {
661 unsigned char *data, *dp;
662 size_t dsize; /* Data size */
663 ssize_t len;
664 ber_tlv_tag_t tlv_tag;
665 ber_tlv_len_t tlv_len;
666 const char *p;
667 int half;
668
669 dsize = strlen(datastring) + 1;
670 dp = data = CALLOC(1, dsize);
671 assert(data);
672
673 for(half = 0, p = datastring; *p; p++) {
674 /* clang-format off */
675 switch(*p) {
676 case '0': case '1': case '2': case '3': case '4':
677 case '5': case '6': case '7': case '8': case '9':
678 *dp |= *p - '0'; break;
679 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
680 *dp |= *p - 'A' + 10; break;
681 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
682 *dp |= *p - 'a' + 10; break;
683 case ' ': case '\t': case '\r': case '\n':
684 continue;
685 default:
686 fprintf(stderr, "Unexpected symbols in data string:\n");
687 fprintf(stderr, "%s\n", datastring);
688 for(dp = data; datastring < p; datastring++, dp++)
689 *dp = ' ';
690 *dp = '\0';
691 fprintf(stderr, "%s^ <- here\n", (char *)data);
692 return -1;
693 }
694 /* clang-format on */
695 if(half)
696 dp++;
697 else
698 (*dp) <<= 4;
699 half = !half;
700 }
701
702 assert((size_t)(dp - data) <= dsize);
703 dsize = dp - data;
704
705 printf("BER: ");
706 for(dp = data; dp < data + dsize; dp++) printf("%02X", *dp);
707 printf("\n");
708
709 len = ber_fetch_tag(data, dsize, &tlv_tag);
710 switch(len) {
711 case -1:
712 fprintf(stderr, "TAG: Fatal error decoding tag\n");
713 return -1;
714 case 0:
715 fprintf(stderr, "TAG: More data expected\n");
716 return -1;
717 default:
718 printf("TAG: ");
719 ber_tlv_tag_fwrite(tlv_tag, stdout);
720 if(BER_TLV_CONSTRUCTED(data)) {
721 printf(" (constructed)");
722 } else if(dsize >= 2 && data[0] == 0 && data[1] == 0) {
723 printf(" (end-of-content)");
724 } else {
725 printf(" (primitive)");
726 }
727 if(BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL) {
728 const char *str;
729 ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
730 str = ASN_UNIVERSAL_TAG2STR(tvalue);
731 if(str) printf(" \"%s\"", str);
732 }
733 printf("\n");
734 }
735
736 if(dsize > (size_t)len) {
737 len = ber_fetch_length(BER_TLV_CONSTRUCTED(data), data + len,
738 dsize - len, &tlv_len);
739 switch(len) {
740 case -1:
741 fprintf(stderr, "LEN: Fatal error decoding length\n");
742 return -1;
743 case 0:
744 fprintf(stderr, "LEN: More data expected\n");
745 return -1;
746 default:
747 if(tlv_len == (ber_tlv_len_t)-1)
748 printf("LEN: Indefinite length encoding\n");
749 else
750 printf("LEN: %ld bytes\n", (long)tlv_len);
751 }
752 }
753
754 return 0;
755}
756
757/*
758 * Dummy functions.
759 */
760asn_dec_rval_t
761ber_check_tags(const asn_codec_ctx_t *opt_codec_ctx,
762 const asn_TYPE_descriptor_t *td, asn_struct_ctx_t *opt_ctx,
763 const void *ptr, size_t size, int tag_mode, int last_tag_form,
764 ber_tlv_len_t *last_length, int *opt_tlv_form) {
765 asn_dec_rval_t rv = {0, 0};
766 (void)opt_codec_ctx;
767 (void)td;
768 (void)opt_ctx;
769 (void)ptr;
770 (void)size;
771 (void)tag_mode;
772 (void)last_tag_form;
773 (void)last_length;
774 (void)opt_tlv_form;
775 return rv;
776}
777
778ssize_t
779der_write_tags(const asn_TYPE_descriptor_t *td, size_t slen, int tag_mode,
780 int last_tag_form, ber_tlv_tag_t tag,
781 asn_app_consume_bytes_f *cb, void *app_key) {
782 (void)td;
783 (void)slen;
784 (void)tag_mode;
785 (void)last_tag_form;
786 (void)tag;
787 (void)cb;
788 (void)app_key;
789 return -1;
790}
791
792asn_dec_rval_t
793xer_decode_general(const asn_codec_ctx_t *opt_codec_ctx, asn_struct_ctx_t *ctx,
794 void *struct_key, const char *xml_tag, const void *buf_ptr,
795 size_t size,
796 int (*otd)(void *struct_key, const void *chunk_buf,
797 size_t chunk_size),
798 ssize_t (*br)(void *struct_key, const void *chunk_buf,
799 size_t chunk_size, int have_more)) {
800 asn_dec_rval_t rv = {0, 0};
801 (void)opt_codec_ctx;
802 (void)ctx;
803 (void)struct_key;
804 (void)xml_tag;
805 (void)buf_ptr;
806 (void)size;
807 (void)otd;
808 (void)br;
809 return rv;
810}
811
812size_t
813xer_whitespace_span(const void *chunk_buf, size_t chunk_size) {
814 (void)chunk_buf;
815 (void)chunk_size;
816 return 0;
817}
818
819int
820OCTET_STRING_compare(const asn_TYPE_descriptor_t *td, const void *a,
821 const void *b) {
822 (void)td;
823 (void)a;
824 (void)b;
825 return 0;
826}
827
828intmax_t
829asn_random_between(intmax_t a, intmax_t b) {
830 (void)b;
831 return a;
832};
833