weeded the library out of unber program
diff --git a/asn1-tools/unber/Makefile.am b/asn1-tools/unber/Makefile.am
index 938bea1..465b169 100644
--- a/asn1-tools/unber/Makefile.am
+++ b/asn1-tools/unber/Makefile.am
@@ -6,6 +6,12 @@
-I${top_srcdir}/libasn1parser \
-I${top_srcdir}/skeletons
-unber_LDADD = $(top_builddir)/libasn1common/libasn1common.la
+noinst_LTLIBRARIES = libasn1-unber-tool.la
+
+libasn1_unber_tool_la_SOURCES = \
+ libasn1_unber_tool.c libasn1_unber_tool.h
+
+unber_LDADD = libasn1-unber-tool.la \
+ $(top_builddir)/libasn1common/libasn1common.la
bin_PROGRAMS = unber
diff --git a/asn1-tools/unber/libasn1_unber_tool.c b/asn1-tools/unber/libasn1_unber_tool.c
new file mode 100644
index 0000000..d956772
--- /dev/null
+++ b/asn1-tools/unber/libasn1_unber_tool.c
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include "asn1_common.h"
+#include "libasn1_unber_tool.h"
+
+#define ASN_DISABLE_PER_SUPPORT 1
+#define ASN_DISABLE_OER_SUPPORT 1
+
+#include <asn1parser.h> /* For static string tables */
+
+#include <asn_application.h>
+#include <constraints.c>
+#include <ber_tlv_tag.c>
+#include <ber_tlv_length.c>
+#include <INTEGER.c>
+#include <OBJECT_IDENTIFIER.c>
+#include <RELATIVE-OID.c>
+#include <asn_codecs_prim.c>
+#include <asn1p_integer.c>
+#include <asn_internal.c>
+
+static int single_type_decoding = 0; /* -1 enables that */
+static int minimalistic = 0; /* -m enables that */
+static int pretty_printing = 1; /* -p disables that */
+static long skip_bytes = 0; /* -s controls that */
+static char indent_bytes[16] = " "; /* -i controls that */
+
+void set_minimalistic_output(int v) { minimalistic = v; }
+void set_single_type_decoding(int v) { single_type_decoding = v; }
+void set_pretty_printing(int v) { pretty_printing = v; }
+int set_skip_bytes(long v) { if(v < 0) return -1; skip_bytes = v; return 0; }
+int set_indent_size(int indent_size) {
+ if(indent_size < 0 || indent_size >= (int)sizeof(indent_bytes)) {
+ return -1;
+ }
+ memset(indent_bytes, ' ', indent_size);
+ indent_bytes[indent_size] = '\0';
+ return 0;
+}
+
+typedef enum pd_code {
+ PD_FAILED = -1,
+ PD_FINISHED = 0,
+ PD_EOF = 1,
+} pd_code_e;
+static pd_code_e process_deeper(const char *fname, FILE *fp,
+ size_t *offset, int level,
+ ssize_t limit, ber_tlv_len_t *frame_size,
+ ber_tlv_len_t effective_size, int expect_eoc);
+static void print_TL(int fin, size_t offset, int level, int constr,
+ ssize_t tlen, ber_tlv_tag_t, ber_tlv_len_t,
+ ber_tlv_len_t effective_frame_size);
+static int print_V(const char *fname, FILE *fp, ber_tlv_tag_t, ber_tlv_len_t);
+
+/*
+ * Open the file and initiate recursive processing.
+ */
+static int
+unber_stream(const char *fname, FILE *fp) {
+ pd_code_e pdc;
+ size_t offset = 0; /* Stream decoding position */
+ ber_tlv_len_t frame_size = 0; /* Single frame size */
+
+ /*
+ * Skip the requested amount of bytes.
+ */
+ for(; offset < (size_t)skip_bytes; offset++) {
+ if(fgetc(fp) == -1) {
+ fprintf(stderr, "%s: input source (%zu bytes) "
+ "has less data than \"-s %ld\" switch "
+ "wants to skip\n",
+ fname, offset, skip_bytes);
+ return -1;
+ }
+ }
+
+ /*
+ * Fetch out BER-encoded data until EOF or error.
+ */
+ do {
+ pdc = process_deeper(fname, fp, &offset, 0, -1, &frame_size, 0, 0);
+ } while(pdc == PD_FINISHED && !single_type_decoding);
+
+ if(pdc == PD_FAILED) return -1;
+ return 0;
+}
+
+/*
+ * Process the TLV recursively.
+ */
+static pd_code_e
+process_deeper(const char *fname, FILE *fp, size_t *offset, int level,
+ ssize_t limit, ber_tlv_len_t *frame_size,
+ ber_tlv_len_t effective_size, int expect_eoc) {
+ unsigned char tagbuf[32];
+ ssize_t tblen = 0;
+ pd_code_e pdc = PD_FINISHED;
+ ber_tlv_tag_t tlv_tag;
+ ber_tlv_len_t tlv_len;
+ ssize_t t_len;
+ ssize_t l_len;
+
+ for(;;) {
+ ber_tlv_len_t local_esize = 0;
+ int constr;
+ int ch;
+
+ if(limit == 0) return PD_FINISHED;
+
+ if(limit >= 0 && tblen >= limit) {
+ fprintf(stderr,
+ "%s: Too long TL sequence (%ld >= %ld)"
+ " at %zu. "
+ "Broken or maliciously constructed file\n",
+ fname, (long)tblen, (long)limit, *offset);
+ return PD_FAILED;
+ }
+
+ /* Get the next byte from the input stream */
+ ch = fgetc(fp);
+ if(ch == -1) {
+ if(limit > 0 || expect_eoc) {
+ fprintf(stderr,
+ "%s: Unexpected end of file (TL)"
+ " at %zu\n",
+ fname, *offset);
+ return PD_FAILED;
+ } else {
+ return PD_EOF;
+ }
+ }
+
+ tagbuf[tblen++] = ch;
+
+ /*
+ * Decode the TLV tag.
+ */
+ t_len = ber_fetch_tag(tagbuf, tblen, &tlv_tag);
+ switch(t_len) {
+ case -1:
+ fprintf(stderr,
+ "%s: Fatal error decoding tag"
+ " at %zu+%ld\n",
+ fname, *offset, (long)tblen);
+ return PD_FAILED;
+ case 0:
+ /* More data expected */
+ continue;
+ }
+
+ /*
+ * Decode the TLV length.
+ */
+ constr = BER_TLV_CONSTRUCTED(tagbuf);
+ l_len =
+ ber_fetch_length(constr, tagbuf + t_len, tblen - t_len, &tlv_len);
+ switch(l_len) {
+ case -1:
+ fprintf(stderr,
+ "%s: Fatal error decoding value length"
+ " at %zu\n",
+ fname, *offset + t_len);
+ return PD_FAILED;
+ case 0:
+ /* More data expected */
+ continue;
+ }
+
+ /* Make sure the T & L decoders took exactly the whole buffer */
+ assert((t_len + l_len) == tblen);
+
+ if(!expect_eoc || tagbuf[0] || tagbuf[1])
+ print_TL(0, *offset, level, constr, tblen, tlv_tag, tlv_len,
+ effective_size);
+
+ if(limit != -1) {
+ /* If limit is set, account for the TL sequence */
+ limit -= (t_len + l_len);
+ assert(limit >= 0);
+
+ if(tlv_len > limit) {
+ fprintf(stderr,
+ "%s: Structure advertizes length (%ld) "
+ "greater than of a parent container (%ld)\n",
+ fname, (long)tlv_len, (long)limit);
+ return PD_FAILED;
+ }
+ }
+
+ *offset += t_len + l_len;
+ *frame_size += t_len + l_len;
+ effective_size += t_len + l_len;
+ local_esize += t_len + l_len;
+
+ if(expect_eoc && !tagbuf[0] && !tagbuf[1]) {
+ /* End of content octets */
+ print_TL(1, *offset - 2, level - 1, 1, 2, 0, -1, effective_size);
+ return PD_FINISHED;
+ }
+
+ if(constr) {
+ ber_tlv_len_t dec = 0;
+ /*
+ * This is a constructed type. Process recursively.
+ */
+ printf(">\n"); /* Close the opening tag */
+ if(tlv_len != -1 && limit != -1) {
+ assert(limit >= tlv_len);
+ }
+ pdc = process_deeper(fname, fp, offset, level + 1,
+ tlv_len == -1 ? limit : tlv_len, &dec,
+ t_len + l_len, tlv_len == -1);
+ if(pdc == PD_FAILED) return pdc;
+ if(limit != -1) {
+ assert(limit >= dec);
+ limit -= dec;
+ }
+ *frame_size += dec;
+ effective_size += dec;
+ local_esize += dec;
+ if(tlv_len == -1) {
+ tblen = 0;
+ if(pdc == PD_FINISHED && limit < 0 && !expect_eoc) return pdc;
+ continue;
+ }
+ } else {
+ assert(tlv_len >= 0);
+ if(print_V(fname, fp, tlv_tag, tlv_len)) return PD_FAILED;
+
+ if(limit != -1) {
+ assert(limit >= tlv_len);
+ limit -= tlv_len;
+ }
+ *offset += tlv_len;
+ *frame_size += tlv_len;
+ effective_size += tlv_len;
+ local_esize += tlv_len;
+ }
+
+ print_TL(1, *offset, level, constr, tblen, tlv_tag, tlv_len,
+ local_esize);
+
+ tblen = 0;
+
+ /* Report success for a single top level TLV */
+ if(level == 0 && limit == -1 && !expect_eoc) break;
+ } /* for(;;) */
+
+ return pdc;
+}
+
+static void
+print_TL(int fin, size_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) {
+ if(fin && !constr) {
+ printf("</P>\n");
+ return;
+ }
+
+ while(level-- > 0) fputs(indent_bytes, stdout); /* Print indent */
+ printf(fin ? "</" : "<");
+
+ printf(constr ? ((tlv_len == -1) ? "I" : "C") : "P");
+
+ /* Print out the offset of this boundary, even if closing tag */
+ if(!minimalistic) printf(" O=\"%zu\"", offset);
+
+ printf(" T=\"");
+ ber_tlv_tag_fwrite(tlv_tag, stdout);
+ printf("\"");
+
+ if(!fin || (tlv_len == -1 && !minimalistic))
+ printf(" TL=\"%ld\"", (long)tlen);
+ if(!fin) {
+ if(tlv_len == -1)
+ printf(" V=\"Indefinite\"");
+ else
+ printf(" V=\"%ld\"", (long)tlv_len);
+ }
+
+ if(!minimalistic && BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL) {
+ const char *str;
+ ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
+ str = ASN_UNIVERSAL_TAG2STR(tvalue);
+ if(str) printf(" A=\"%s\"", str);
+ }
+
+ if(fin) {
+ if(constr && !minimalistic) printf(" L=\"%ld\"", (long)effective_size);
+ printf(">\n");
+ }
+}
+
+/*
+ * Print the value in binary form, or reformat for pretty-printing.
+ */
+static int
+print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag,
+ ber_tlv_len_t tlv_len) {
+ asn_oid_arc_t *arcs = 0; /* Object identifier arcs */
+ unsigned char *vbuf = 0;
+ asn1p_expr_type_e etype = 0;
+ asn1c_integer_t collector = 0;
+ int special_format = 0;
+ ssize_t i;
+
+ /* Figure out what type is it */
+ if(BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL && pretty_printing) {
+ ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
+ etype = ASN_UNIVERSAL_TAG2TYPE(tvalue);
+ }
+
+ /*
+ * Determine how to print the value, either in its native binary form,
+ * encoded with &xNN characters, or using pretty-printing.
+ * The basic string types (including "useful types", like UTCTime)
+ * are excempt from this determination logic, because their alphabets
+ * are subsets of the XML's native UTF-8 encoding.
+ */
+ switch(etype) {
+ case ASN_BASIC_BOOLEAN:
+ if(tlv_len == 1)
+ special_format = 1;
+ else
+ etype = 0;
+ break;
+ case ASN_BASIC_INTEGER:
+ case ASN_BASIC_ENUMERATED:
+ if((size_t)tlv_len <= sizeof(collector))
+ special_format = 1;
+ else
+ etype = 0;
+ break;
+ case ASN_BASIC_OBJECT_IDENTIFIER:
+ case ASN_BASIC_RELATIVE_OID:
+ if(tlv_len > 0 && tlv_len < 128 * 1024 /* VERY long OID! */) {
+ arcs = MALLOC(sizeof(*arcs) * (tlv_len + 1));
+ if(arcs) {
+ vbuf = MALLOC(tlv_len + 1);
+ /* Not checking is intentional */
+ }
+ }
+ case ASN_BASIC_UTCTime:
+ case ASN_BASIC_GeneralizedTime:
+ case ASN_STRING_NumericString:
+ case ASN_STRING_PrintableString:
+ case ASN_STRING_VisibleString:
+ case ASN_STRING_IA5String:
+ case ASN_STRING_UTF8String:
+ break; /* Directly compatible with UTF-8 */
+ case ASN_STRING_BMPString:
+ case ASN_STRING_UniversalString:
+ break; /* Not directly compatible with UTF-8 */
+ default:
+ /* Conditionally compatible with UTF-8 */
+ if(((etype & ASN_STRING_MASK) || (etype == ASN_BASIC_OCTET_STRING) ||
+ /*
+ * AUTOMATIC TAGS or IMPLICIT TAGS in effect,
+ * Treat this primitive type as OCTET_STRING.
+ */
+ (BER_TAG_CLASS(tlv_tag) != ASN_TAG_CLASS_UNIVERSAL
+ && pretty_printing))
+ && (tlv_len > 0 && tlv_len < 128 * 1024)) {
+ vbuf = MALLOC(tlv_len + 1);
+ /* Not checking is intentional */
+ }
+ break;
+ }
+
+ /* If collection vbuf is present, defer printing the F flag. */
+ if(!vbuf) printf(special_format ? " F>" : ">");
+
+ /*
+ * Print the value in binary or text form,
+ * or collect the bytes into vbuf.
+ */
+ for(i = 0; i < tlv_len; i++) {
+ int ch = fgetc(fp);
+ if(ch == -1) {
+ fprintf(stderr, "%s: Unexpected end of file (V)\n", fname);
+ if(vbuf) FREEMEM(vbuf);
+ if(arcs) FREEMEM(arcs);
+ return -1;
+ }
+ switch(etype) {
+ case ASN_BASIC_UTCTime:
+ case ASN_BASIC_GeneralizedTime:
+ case ASN_STRING_NumericString:
+ case ASN_STRING_PrintableString:
+ case ASN_STRING_VisibleString:
+ case ASN_STRING_IA5String:
+ case ASN_STRING_UTF8String:
+ switch(ch) {
+ default:
+ if(((etype == ASN_STRING_UTF8String) || !(ch & 0x80))
+ && (ch >= 0x20)) {
+ printf("%c", ch);
+ break;
+ }
+ /* Fall through */
+ case 0x3c:
+ case 0x3e:
+ case 0x26:
+ printf("&#x%02x;", ch);
+ }
+ break;
+ case ASN_BASIC_BOOLEAN:
+ switch(ch) {
+ case 0:
+ printf("<false/>");
+ break;
+ case 0xff:
+ printf("<true/>");
+ break;
+ default:
+ printf("<true value=\"&#x%02x\"/>", ch);
+ }
+ break;
+ case ASN_BASIC_INTEGER:
+ case ASN_BASIC_ENUMERATED:
+ if(i)
+ collector = collector * 256 + ch;
+ else
+ collector = (int)(signed char)ch;
+ break;
+ default:
+ if(vbuf) {
+ vbuf[i] = ch;
+ } else {
+ printf("&#x%02x;", ch);
+ }
+ }
+ }
+
+ /* Do post-processing */
+ switch(etype) {
+ case ASN_BASIC_INTEGER:
+ case ASN_BASIC_ENUMERATED:
+ printf("%s", asn1p_itoa(collector));
+ break;
+ case ASN_BASIC_OBJECT_IDENTIFIER:
+ if(vbuf) {
+ OBJECT_IDENTIFIER_t oid = {0, 0};
+ ssize_t arcno;
+
+ oid.buf = vbuf;
+ oid.size = tlv_len;
+
+ arcno = OBJECT_IDENTIFIER_get_arcs(&oid, arcs, tlv_len + 1);
+ if(arcno >= 0) {
+ assert(arcno <= (tlv_len + 1));
+ printf(" F>");
+ for(i = 0; i < arcno; i++) {
+ if(i) printf(".");
+ printf("%" PRIu32, arcs[i]);
+ }
+ FREEMEM(vbuf);
+ vbuf = 0;
+ }
+ }
+ break;
+ case ASN_BASIC_RELATIVE_OID:
+ if(vbuf) {
+ RELATIVE_OID_t oid;
+ int arcno;
+
+ oid.buf = vbuf;
+ oid.size = tlv_len;
+
+ arcno = RELATIVE_OID_get_arcs(&oid, arcs, tlv_len);
+ if(arcno >= 0) {
+ assert(arcno <= tlv_len);
+ printf(" F>");
+ for(i = 0; i < arcno; i++) {
+ if(i) printf(".");
+ printf("%" PRIu32, arcs[i]);
+ }
+ FREEMEM(vbuf);
+ vbuf = 0;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * If the buffer was not consumed, print it out.
+ * It might be an OCTET STRING or other primitive type,
+ * which might actually be printable, but we need to figure it out.
+ */
+ if(vbuf) {
+ int binary;
+
+ /*
+ * Check whether the data could be represented as text
+ */
+ binary = -1 * (tlv_len >> 3); /* Threshold is 12.5% binary */
+ for(i = 0; i < tlv_len; i++) {
+ switch(vbuf[i]) {
+ case 0x1b:
+ binary = 1;
+ break;
+ case 0x09:
+ case 0x0a:
+ case 0x0d:
+ continue;
+ default:
+ if(vbuf[i] < 0x20 || vbuf[i] >= 0x7f)
+ if(++binary > 0) /* Way too many */
+ break;
+ continue;
+ }
+ break;
+ }
+ printf(">");
+ for(i = 0; i < tlv_len; i++) {
+ if(binary > 0 || vbuf[i] < 0x20 || vbuf[i] >= 0x7f
+ || vbuf[i] == 0x26 /* '&' */
+ || vbuf[i] == 0x3c /* '<' */
+ || vbuf[i] == 0x3e /* '>' */
+ )
+ printf("&#x%02x;", vbuf[i]);
+ else
+ printf("%c", vbuf[i]);
+ }
+ FREEMEM(vbuf);
+ }
+
+ if(arcs) FREEMEM(arcs);
+ return 0;
+}
+
+int
+unber_file(const char *fname) {
+ FILE *fp;
+
+ if(strcmp(fname, "-")) {
+ fp = fopen(fname, "rb");
+ if(!fp) {
+ perror(fname);
+ return -1;
+ }
+ } else {
+ fp = stdin;
+ }
+
+ int ret = unber_stream(fname, fp);
+
+ if(fp != stdin) fclose(fp);
+
+ return ret;
+}
+
+int
+decode_tlv_from_hex_string(const char *datastring) {
+ unsigned char *data, *dp;
+ size_t dsize; /* Data size */
+ ssize_t len;
+ ber_tlv_tag_t tlv_tag;
+ ber_tlv_len_t tlv_len;
+ const char *p;
+ int half;
+
+ dsize = strlen(datastring) + 1;
+ dp = data = CALLOC(1, dsize);
+ assert(data);
+
+ for(half = 0, p = datastring; *p; p++) {
+ /* clang-format off */
+ switch(*p) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ *dp |= *p - '0'; break;
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ *dp |= *p - 'A' + 10; break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ *dp |= *p - 'a' + 10; break;
+ case ' ': case '\t': case '\r': case '\n':
+ continue;
+ default:
+ fprintf(stderr, "Unexpected symbols in data string:\n");
+ fprintf(stderr, "%s\n", datastring);
+ for(dp = data; datastring < p; datastring++, dp++)
+ *dp = ' ';
+ *dp = '\0';
+ fprintf(stderr, "%s^ <- here\n", (char *)data);
+ return -1;
+ }
+ /* clang-format on */
+ if(half)
+ dp++;
+ else
+ (*dp) <<= 4;
+ half = !half;
+ }
+
+ assert((size_t)(dp - data) <= dsize);
+ dsize = dp - data;
+
+ printf("BER: ");
+ for(dp = data; dp < data + dsize; dp++) printf("%02X", *dp);
+ printf("\n");
+
+ len = ber_fetch_tag(data, dsize, &tlv_tag);
+ switch(len) {
+ case -1:
+ fprintf(stderr, "TAG: Fatal error decoding tag\n");
+ return -1;
+ case 0:
+ fprintf(stderr, "TAG: More data expected\n");
+ return -1;
+ default:
+ printf("TAG: ");
+ ber_tlv_tag_fwrite(tlv_tag, stdout);
+ if(BER_TLV_CONSTRUCTED(data)) {
+ printf(" (constructed)");
+ } else if(dsize >= 2 && data[0] == 0 && data[1] == 0) {
+ printf(" (end-of-content)");
+ } else {
+ printf(" (primitive)");
+ }
+ if(BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL) {
+ const char *str;
+ ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
+ str = ASN_UNIVERSAL_TAG2STR(tvalue);
+ if(str) printf(" \"%s\"", str);
+ }
+ printf("\n");
+ }
+
+ if(dsize > (size_t)len) {
+ len = ber_fetch_length(BER_TLV_CONSTRUCTED(data), data + len,
+ dsize - len, &tlv_len);
+ switch(len) {
+ case -1:
+ fprintf(stderr, "LEN: Fatal error decoding length\n");
+ return -1;
+ case 0:
+ fprintf(stderr, "LEN: More data expected\n");
+ return -1;
+ default:
+ if(tlv_len == (ber_tlv_len_t)-1)
+ printf("LEN: Indefinite length encoding\n");
+ else
+ printf("LEN: %ld bytes\n", (long)tlv_len);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Dummy functions.
+ */
+asn_dec_rval_t
+ber_check_tags(const asn_codec_ctx_t *opt_codec_ctx,
+ const 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;
+}
+
+ssize_t
+der_write_tags(const 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;
+}
+
+asn_dec_rval_t
+xer_decode_general(const 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;
+}
+
+size_t
+xer_whitespace_span(const void *chunk_buf, size_t chunk_size) {
+ (void)chunk_buf;
+ (void)chunk_size;
+ return 0;
+}
+
+int
+OCTET_STRING_compare(const asn_TYPE_descriptor_t *td, const void *a,
+ const void *b) {
+ (void)td;
+ (void)a;
+ (void)b;
+ return 0;
+}
+
+intmax_t
+asn_random_between(intmax_t a, intmax_t b) {
+ (void)b;
+ return a;
+};
+
diff --git a/asn1-tools/unber/libasn1_unber_tool.h b/asn1-tools/unber/libasn1_unber_tool.h
new file mode 100644
index 0000000..316db82
--- /dev/null
+++ b/asn1-tools/unber/libasn1_unber_tool.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2004-2019 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/* Set global options. */
+void set_minimalistic_output(int v);
+void set_single_type_decoding(int v);
+void set_pretty_printing(int v);
+int set_skip_bytes(long v);
+int set_indent_size(int indent_size);
+
+/*
+ * Convert BER-encoded file into the low level non-standard XML-like structure.
+ * Primarily used for manual debugging.
+ */
+int unber_file(const char *fname);
+
+/*
+ * Decode the TLV given by the given string.
+ */
+int decode_tlv_from_hex_string(const char *datastring);
+
diff --git a/asn1-tools/unber/unber.c b/asn1-tools/unber/unber.c
index c707c98..6126b15 100644
--- a/asn1-tools/unber/unber.c
+++ b/asn1-tools/unber/unber.c
@@ -25,73 +25,45 @@
*
*/
#include "asn1_common.h"
-
-#define ASN_DISABLE_PER_SUPPORT 1
-#define ASN_DISABLE_OER_SUPPORT 1
-
-#include <asn1parser.h> /* For static string tables */
-
-#include <asn_application.h>
-#include <constraints.c>
-#include <ber_tlv_tag.c>
-#include <ber_tlv_length.c>
-#include <INTEGER.c>
-#include <OBJECT_IDENTIFIER.c>
-#include <RELATIVE-OID.c>
-#include <asn_codecs_prim.c>
-#include <asn1p_integer.c>
-#include <asn_internal.c>
+#include "libasn1_unber_tool.h"
#undef COPYRIGHT
-#define COPYRIGHT "Copyright (c) 2004, 2005 Lev Walkin <vlm@lionet.info>\n"
+#define COPYRIGHT "Copyright (c) 2004-2019 Lev Walkin <vlm@lionet.info>\n"
static void usage(const char *av0); /* Print the Usage screen and exit */
-static int process(const char *fname); /* Perform the BER decoding */
-static int decode_tlv_from_string(const char *datastring);
-
-static int single_type_decoding = 0; /* -1 enables that */
-static int minimalistic = 0; /* -m enables that */
-static int pretty_printing = 1; /* -p disables that */
-static long skip_bytes = 0; /* -s controls that */
-static char indent_bytes[16] = " "; /* -i controls that */
int
main(int ac, char **av) {
int ch; /* Command line character */
- int i; /* Index in some loops */
/*
* Process command-line options.
*/
- while((ch = getopt(ac, av, "1hi:mps:t:v")) != -1) switch(ch) {
+ while((ch = getopt(ac, av, "1hi:mps:t:v")) != -1) {
+ switch(ch) {
case '1':
- single_type_decoding = 1;
+ set_single_type_decoding(1);
break;
case 'i':
- i = atoi(optarg);
- if(i >= 0 && i < (int)sizeof(indent_bytes)) {
- memset(indent_bytes, ' ', i);
- indent_bytes[i] = '\0';
- } else {
+ if(set_indent_size(atoi(optarg)) != 0) {
fprintf(stderr, "-i %s: Invalid indent value\n", optarg);
exit(EX_USAGE);
}
break;
case 'm':
- minimalistic = 1;
+ set_minimalistic_output(1);
break;
case 'p':
- pretty_printing = 0;
+ set_pretty_printing(0);
break;
case 's':
- skip_bytes = atol(optarg);
- if(skip_bytes < 0) {
+ if(set_skip_bytes(atol(optarg)) != 0) {
fprintf(stderr, "-s %s: positive value expected\n", optarg);
exit(EX_USAGE);
}
break;
case 't':
- if(decode_tlv_from_string(optarg)) exit(EX_DATAERR);
+ if(decode_tlv_from_hex_string(optarg)) exit(EX_DATAERR);
exit(0);
case 'v':
fprintf(stderr, "ASN.1 BER Decoder, v" VERSION "\n" COPYRIGHT);
@@ -101,6 +73,7 @@
default:
usage(av[0]);
}
+ }
/*
* Ensure that there are some input files present.
@@ -119,8 +92,8 @@
* Iterate over input files and parse each.
* All syntax trees from all files will be bundled together.
*/
- for(i = 0; i < ac; i++) {
- if(process(av[i])) exit(EX_DATAERR);
+ for(int i = 0; i < ac; i++) {
+ if(unber_file(av[i])) exit(EX_DATAERR);
}
return 0;
@@ -159,687 +132,3 @@
exit(EX_USAGE);
}
-typedef enum pd_code {
- PD_FAILED = -1,
- PD_FINISHED = 0,
- PD_EOF = 1,
-} pd_code_e;
-static pd_code_e process_deeper(const char *fname, FILE *fp,
- size_t *offset, int level,
- ssize_t limit, ber_tlv_len_t *frame_size,
- ber_tlv_len_t effective_size, int expect_eoc);
-static void print_TL(int fin, size_t offset, int level, int constr,
- ssize_t tlen, ber_tlv_tag_t, ber_tlv_len_t,
- ber_tlv_len_t effective_frame_size);
-static int print_V(const char *fname, FILE *fp, ber_tlv_tag_t, ber_tlv_len_t);
-
-/*
- * Open the file and initiate recursive processing.
- */
-static int
-process(const char *fname) {
- FILE *fp;
- pd_code_e pdc;
- size_t offset = 0; /* Stream decoding position */
- ber_tlv_len_t frame_size = 0; /* Single frame size */
-
- if(strcmp(fname, "-")) {
- fp = fopen(fname, "rb");
- if(!fp) {
- perror(fname);
- return -1;
- }
- } else {
- fp = stdin;
- }
-
- /*
- * Skip the requested amount of bytes.
- */
- for(; offset < (size_t)skip_bytes; offset++) {
- if(fgetc(fp) == -1) {
- fprintf(stderr, "%s: input source (%zu bytes) "
- "has less data than \"-s %ld\" switch "
- "wants to skip\n",
- fname, offset, skip_bytes);
- if(fp != stdin) fclose(fp);
- return -1;
- }
- }
-
- /*
- * Fetch out BER-encoded data until EOF or error.
- */
- do {
- pdc = process_deeper(fname, fp, &offset, 0, -1, &frame_size, 0, 0);
- } while(pdc == PD_FINISHED && !single_type_decoding);
-
- if(fp != stdin) fclose(fp);
-
- if(pdc == PD_FAILED) return -1;
- return 0;
-}
-
-/*
- * Process the TLV recursively.
- */
-static pd_code_e
-process_deeper(const char *fname, FILE *fp, size_t *offset, int level,
- ssize_t limit, ber_tlv_len_t *frame_size,
- ber_tlv_len_t effective_size, int expect_eoc) {
- unsigned char tagbuf[32];
- ssize_t tblen = 0;
- pd_code_e pdc = PD_FINISHED;
- ber_tlv_tag_t tlv_tag;
- ber_tlv_len_t tlv_len;
- ssize_t t_len;
- ssize_t l_len;
-
- for(;;) {
- ber_tlv_len_t local_esize = 0;
- int constr;
- int ch;
-
- if(limit == 0) return PD_FINISHED;
-
- if(limit >= 0 && tblen >= limit) {
- fprintf(stderr,
- "%s: Too long TL sequence (%ld >= %ld)"
- " at %zu. "
- "Broken or maliciously constructed file\n",
- fname, (long)tblen, (long)limit, *offset);
- return PD_FAILED;
- }
-
- /* Get the next byte from the input stream */
- ch = fgetc(fp);
- if(ch == -1) {
- if(limit > 0 || expect_eoc) {
- fprintf(stderr,
- "%s: Unexpected end of file (TL)"
- " at %zu\n",
- fname, *offset);
- return PD_FAILED;
- } else {
- return PD_EOF;
- }
- }
-
- tagbuf[tblen++] = ch;
-
- /*
- * Decode the TLV tag.
- */
- t_len = ber_fetch_tag(tagbuf, tblen, &tlv_tag);
- switch(t_len) {
- case -1:
- fprintf(stderr,
- "%s: Fatal error decoding tag"
- " at %zu+%ld\n",
- fname, *offset, (long)tblen);
- return PD_FAILED;
- case 0:
- /* More data expected */
- continue;
- }
-
- /*
- * Decode the TLV length.
- */
- constr = BER_TLV_CONSTRUCTED(tagbuf);
- l_len =
- ber_fetch_length(constr, tagbuf + t_len, tblen - t_len, &tlv_len);
- switch(l_len) {
- case -1:
- fprintf(stderr,
- "%s: Fatal error decoding value length"
- " at %zu\n",
- fname, *offset + t_len);
- return PD_FAILED;
- case 0:
- /* More data expected */
- continue;
- }
-
- /* Make sure the T & L decoders took exactly the whole buffer */
- assert((t_len + l_len) == tblen);
-
- if(!expect_eoc || tagbuf[0] || tagbuf[1])
- print_TL(0, *offset, level, constr, tblen, tlv_tag, tlv_len,
- effective_size);
-
- if(limit != -1) {
- /* If limit is set, account for the TL sequence */
- limit -= (t_len + l_len);
- assert(limit >= 0);
-
- if(tlv_len > limit) {
- fprintf(stderr,
- "%s: Structure advertizes length (%ld) "
- "greater than of a parent container (%ld)\n",
- fname, (long)tlv_len, (long)limit);
- return PD_FAILED;
- }
- }
-
- *offset += t_len + l_len;
- *frame_size += t_len + l_len;
- effective_size += t_len + l_len;
- local_esize += t_len + l_len;
-
- if(expect_eoc && !tagbuf[0] && !tagbuf[1]) {
- /* End of content octets */
- print_TL(1, *offset - 2, level - 1, 1, 2, 0, -1, effective_size);
- return PD_FINISHED;
- }
-
- if(constr) {
- ber_tlv_len_t dec = 0;
- /*
- * This is a constructed type. Process recursively.
- */
- printf(">\n"); /* Close the opening tag */
- if(tlv_len != -1 && limit != -1) {
- assert(limit >= tlv_len);
- }
- pdc = process_deeper(fname, fp, offset, level + 1,
- tlv_len == -1 ? limit : tlv_len, &dec,
- t_len + l_len, tlv_len == -1);
- if(pdc == PD_FAILED) return pdc;
- if(limit != -1) {
- assert(limit >= dec);
- limit -= dec;
- }
- *frame_size += dec;
- effective_size += dec;
- local_esize += dec;
- if(tlv_len == -1) {
- tblen = 0;
- if(pdc == PD_FINISHED && limit < 0 && !expect_eoc) return pdc;
- continue;
- }
- } else {
- assert(tlv_len >= 0);
- if(print_V(fname, fp, tlv_tag, tlv_len)) return PD_FAILED;
-
- if(limit != -1) {
- assert(limit >= tlv_len);
- limit -= tlv_len;
- }
- *offset += tlv_len;
- *frame_size += tlv_len;
- effective_size += tlv_len;
- local_esize += tlv_len;
- }
-
- print_TL(1, *offset, level, constr, tblen, tlv_tag, tlv_len,
- local_esize);
-
- tblen = 0;
-
- /* Report success for a single top level TLV */
- if(level == 0 && limit == -1 && !expect_eoc) break;
- } /* for(;;) */
-
- return pdc;
-}
-
-static void
-print_TL(int fin, size_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) {
- if(fin && !constr) {
- printf("</P>\n");
- return;
- }
-
- while(level-- > 0) fputs(indent_bytes, stdout); /* Print indent */
- printf(fin ? "</" : "<");
-
- printf(constr ? ((tlv_len == -1) ? "I" : "C") : "P");
-
- /* Print out the offset of this boundary, even if closing tag */
- if(!minimalistic) printf(" O=\"%zu\"", offset);
-
- printf(" T=\"");
- ber_tlv_tag_fwrite(tlv_tag, stdout);
- printf("\"");
-
- if(!fin || (tlv_len == -1 && !minimalistic))
- printf(" TL=\"%ld\"", (long)tlen);
- if(!fin) {
- if(tlv_len == -1)
- printf(" V=\"Indefinite\"");
- else
- printf(" V=\"%ld\"", (long)tlv_len);
- }
-
- if(!minimalistic && BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL) {
- const char *str;
- ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
- str = ASN_UNIVERSAL_TAG2STR(tvalue);
- if(str) printf(" A=\"%s\"", str);
- }
-
- if(fin) {
- if(constr && !minimalistic) printf(" L=\"%ld\"", (long)effective_size);
- printf(">\n");
- }
-}
-
-/*
- * Print the value in binary form, or reformat for pretty-printing.
- */
-static int
-print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag,
- ber_tlv_len_t tlv_len) {
- asn_oid_arc_t *arcs = 0; /* Object identifier arcs */
- unsigned char *vbuf = 0;
- asn1p_expr_type_e etype = 0;
- asn1c_integer_t collector = 0;
- int special_format = 0;
- ssize_t i;
-
- /* Figure out what type is it */
- if(BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL && pretty_printing) {
- ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
- etype = ASN_UNIVERSAL_TAG2TYPE(tvalue);
- }
-
- /*
- * Determine how to print the value, either in its native binary form,
- * encoded with &xNN characters, or using pretty-printing.
- * The basic string types (including "useful types", like UTCTime)
- * are excempt from this determination logic, because their alphabets
- * are subsets of the XML's native UTF-8 encoding.
- */
- switch(etype) {
- case ASN_BASIC_BOOLEAN:
- if(tlv_len == 1)
- special_format = 1;
- else
- etype = 0;
- break;
- case ASN_BASIC_INTEGER:
- case ASN_BASIC_ENUMERATED:
- if((size_t)tlv_len <= sizeof(collector))
- special_format = 1;
- else
- etype = 0;
- break;
- case ASN_BASIC_OBJECT_IDENTIFIER:
- case ASN_BASIC_RELATIVE_OID:
- if(tlv_len > 0 && tlv_len < 128 * 1024 /* VERY long OID! */) {
- arcs = MALLOC(sizeof(*arcs) * (tlv_len + 1));
- if(arcs) {
- vbuf = MALLOC(tlv_len + 1);
- /* Not checking is intentional */
- }
- }
- case ASN_BASIC_UTCTime:
- case ASN_BASIC_GeneralizedTime:
- case ASN_STRING_NumericString:
- case ASN_STRING_PrintableString:
- case ASN_STRING_VisibleString:
- case ASN_STRING_IA5String:
- case ASN_STRING_UTF8String:
- break; /* Directly compatible with UTF-8 */
- case ASN_STRING_BMPString:
- case ASN_STRING_UniversalString:
- break; /* Not directly compatible with UTF-8 */
- default:
- /* Conditionally compatible with UTF-8 */
- if(((etype & ASN_STRING_MASK) || (etype == ASN_BASIC_OCTET_STRING) ||
- /*
- * AUTOMATIC TAGS or IMPLICIT TAGS in effect,
- * Treat this primitive type as OCTET_STRING.
- */
- (BER_TAG_CLASS(tlv_tag) != ASN_TAG_CLASS_UNIVERSAL
- && pretty_printing))
- && (tlv_len > 0 && tlv_len < 128 * 1024)) {
- vbuf = MALLOC(tlv_len + 1);
- /* Not checking is intentional */
- }
- break;
- }
-
- /* If collection vbuf is present, defer printing the F flag. */
- if(!vbuf) printf(special_format ? " F>" : ">");
-
- /*
- * Print the value in binary or text form,
- * or collect the bytes into vbuf.
- */
- for(i = 0; i < tlv_len; i++) {
- int ch = fgetc(fp);
- if(ch == -1) {
- fprintf(stderr, "%s: Unexpected end of file (V)\n", fname);
- if(vbuf) FREEMEM(vbuf);
- if(arcs) FREEMEM(arcs);
- return -1;
- }
- switch(etype) {
- case ASN_BASIC_UTCTime:
- case ASN_BASIC_GeneralizedTime:
- case ASN_STRING_NumericString:
- case ASN_STRING_PrintableString:
- case ASN_STRING_VisibleString:
- case ASN_STRING_IA5String:
- case ASN_STRING_UTF8String:
- switch(ch) {
- default:
- if(((etype == ASN_STRING_UTF8String) || !(ch & 0x80))
- && (ch >= 0x20)) {
- printf("%c", ch);
- break;
- }
- /* Fall through */
- case 0x3c:
- case 0x3e:
- case 0x26:
- printf("&#x%02x;", ch);
- }
- break;
- case ASN_BASIC_BOOLEAN:
- switch(ch) {
- case 0:
- printf("<false/>");
- break;
- case 0xff:
- printf("<true/>");
- break;
- default:
- printf("<true value=\"&#x%02x\"/>", ch);
- }
- break;
- case ASN_BASIC_INTEGER:
- case ASN_BASIC_ENUMERATED:
- if(i)
- collector = collector * 256 + ch;
- else
- collector = (int)(signed char)ch;
- break;
- default:
- if(vbuf) {
- vbuf[i] = ch;
- } else {
- printf("&#x%02x;", ch);
- }
- }
- }
-
- /* Do post-processing */
- switch(etype) {
- case ASN_BASIC_INTEGER:
- case ASN_BASIC_ENUMERATED:
- printf("%s", asn1p_itoa(collector));
- break;
- case ASN_BASIC_OBJECT_IDENTIFIER:
- if(vbuf) {
- OBJECT_IDENTIFIER_t oid = {0, 0};
- ssize_t arcno;
-
- oid.buf = vbuf;
- oid.size = tlv_len;
-
- arcno = OBJECT_IDENTIFIER_get_arcs(&oid, arcs, tlv_len + 1);
- if(arcno >= 0) {
- assert(arcno <= (tlv_len + 1));
- printf(" F>");
- for(i = 0; i < arcno; i++) {
- if(i) printf(".");
- printf("%" PRIu32, arcs[i]);
- }
- FREEMEM(vbuf);
- vbuf = 0;
- }
- }
- break;
- case ASN_BASIC_RELATIVE_OID:
- if(vbuf) {
- RELATIVE_OID_t oid;
- int arcno;
-
- oid.buf = vbuf;
- oid.size = tlv_len;
-
- arcno = RELATIVE_OID_get_arcs(&oid, arcs, tlv_len);
- if(arcno >= 0) {
- assert(arcno <= tlv_len);
- printf(" F>");
- for(i = 0; i < arcno; i++) {
- if(i) printf(".");
- printf("%" PRIu32, arcs[i]);
- }
- FREEMEM(vbuf);
- vbuf = 0;
- }
- }
- break;
- default:
- break;
- }
-
- /*
- * If the buffer was not consumed, print it out.
- * It might be an OCTET STRING or other primitive type,
- * which might actually be printable, but we need to figure it out.
- */
- if(vbuf) {
- int binary;
-
- /*
- * Check whether the data could be represented as text
- */
- binary = -1 * (tlv_len >> 3); /* Threshold is 12.5% binary */
- for(i = 0; i < tlv_len; i++) {
- switch(vbuf[i]) {
- case 0x1b:
- binary = 1;
- break;
- case 0x09:
- case 0x0a:
- case 0x0d:
- continue;
- default:
- if(vbuf[i] < 0x20 || vbuf[i] >= 0x7f)
- if(++binary > 0) /* Way too many */
- break;
- continue;
- }
- break;
- }
- printf(">");
- for(i = 0; i < tlv_len; i++) {
- if(binary > 0 || vbuf[i] < 0x20 || vbuf[i] >= 0x7f
- || vbuf[i] == 0x26 /* '&' */
- || vbuf[i] == 0x3c /* '<' */
- || vbuf[i] == 0x3e /* '>' */
- )
- printf("&#x%02x;", vbuf[i]);
- else
- printf("%c", vbuf[i]);
- }
- FREEMEM(vbuf);
- }
-
- if(arcs) FREEMEM(arcs);
- return 0;
-}
-
-
-static int
-decode_tlv_from_string(const char *datastring) {
- unsigned char *data, *dp;
- size_t dsize; /* Data size */
- ssize_t len;
- ber_tlv_tag_t tlv_tag;
- ber_tlv_len_t tlv_len;
- const char *p;
- int half;
-
- dsize = strlen(datastring) + 1;
- dp = data = CALLOC(1, dsize);
- assert(data);
-
- for(half = 0, p = datastring; *p; p++) {
- /* clang-format off */
- switch(*p) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- *dp |= *p - '0'; break;
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- *dp |= *p - 'A' + 10; break;
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- *dp |= *p - 'a' + 10; break;
- case ' ': case '\t': case '\r': case '\n':
- continue;
- default:
- fprintf(stderr, "Unexpected symbols in data string:\n");
- fprintf(stderr, "%s\n", datastring);
- for(dp = data; datastring < p; datastring++, dp++)
- *dp = ' ';
- *dp = '\0';
- fprintf(stderr, "%s^ <- here\n", (char *)data);
- return -1;
- }
- /* clang-format on */
- if(half)
- dp++;
- else
- (*dp) <<= 4;
- half = !half;
- }
-
- assert((size_t)(dp - data) <= dsize);
- dsize = dp - data;
-
- printf("BER: ");
- for(dp = data; dp < data + dsize; dp++) printf("%02X", *dp);
- printf("\n");
-
- len = ber_fetch_tag(data, dsize, &tlv_tag);
- switch(len) {
- case -1:
- fprintf(stderr, "TAG: Fatal error decoding tag\n");
- return -1;
- case 0:
- fprintf(stderr, "TAG: More data expected\n");
- return -1;
- default:
- printf("TAG: ");
- ber_tlv_tag_fwrite(tlv_tag, stdout);
- if(BER_TLV_CONSTRUCTED(data)) {
- printf(" (constructed)");
- } else if(dsize >= 2 && data[0] == 0 && data[1] == 0) {
- printf(" (end-of-content)");
- } else {
- printf(" (primitive)");
- }
- if(BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL) {
- const char *str;
- ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
- str = ASN_UNIVERSAL_TAG2STR(tvalue);
- if(str) printf(" \"%s\"", str);
- }
- printf("\n");
- }
-
- if(dsize > (size_t)len) {
- len = ber_fetch_length(BER_TLV_CONSTRUCTED(data), data + len,
- dsize - len, &tlv_len);
- switch(len) {
- case -1:
- fprintf(stderr, "LEN: Fatal error decoding length\n");
- return -1;
- case 0:
- fprintf(stderr, "LEN: More data expected\n");
- return -1;
- default:
- if(tlv_len == (ber_tlv_len_t)-1)
- printf("LEN: Indefinite length encoding\n");
- else
- printf("LEN: %ld bytes\n", (long)tlv_len);
- }
- }
-
- return 0;
-}
-
-/*
- * Dummy functions.
- */
-asn_dec_rval_t
-ber_check_tags(const asn_codec_ctx_t *opt_codec_ctx,
- const 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;
-}
-
-ssize_t
-der_write_tags(const 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;
-}
-
-asn_dec_rval_t
-xer_decode_general(const 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;
-}
-
-size_t
-xer_whitespace_span(const void *chunk_buf, size_t chunk_size) {
- (void)chunk_buf;
- (void)chunk_size;
- return 0;
-}
-
-int
-OCTET_STRING_compare(const asn_TYPE_descriptor_t *td, const void *a,
- const void *b) {
- (void)td;
- (void)a;
- (void)b;
- return 0;
-}
-
-intmax_t
-asn_random_between(intmax_t a, intmax_t b) {
- (void)b;
- return a;
-};
-