aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLev Walkin <vlm@lionet.info>2004-09-23 22:06:02 +0000
committerLev Walkin <vlm@lionet.info>2004-09-23 22:06:02 +0000
commit06b8d7aa3355121c8810850972955374f884dc20 (patch)
tree646778c9f26c6077dc3d577d64d6f0ddbf3aaf11
parent60a1403aa733f2a86c4837708bc8fd53be5870e4 (diff)
implemented unber - the ASN.1 BER Decoder
-rw-r--r--asn1c/Makefile.am9
-rw-r--r--asn1c/Makefile.in31
-rw-r--r--asn1c/README3
-rw-r--r--asn1c/asn1c.111
-rw-r--r--asn1c/asn1c.c20
-rw-r--r--asn1c/unber.c481
6 files changed, 511 insertions, 44 deletions
diff --git a/asn1c/Makefile.am b/asn1c/Makefile.am
index 63bb31c2..a5caec37 100644
--- a/asn1c/Makefile.am
+++ b/asn1c/Makefile.am
@@ -10,18 +10,15 @@ AM_CPPFLAGS = \
-I${top_srcdir}/skeletons \
-DDATADIR=\"$(pkgdatadir)\"
-LDADD = \
+asn1c_LDADD = \
$(top_builddir)/libasn1parser/libasn1parser.la \
$(top_builddir)/libasn1print/libasn1print.la \
$(top_builddir)/libasn1fix/libasn1fix.la \
$(top_builddir)/libasn1compiler/libasn1compiler.la
-asn1c_SOURCES = asn1c.c \
- tlv_decoder.c tlv_decoder.h
+bin_PROGRAMS = asn1c unber
-bin_PROGRAMS = asn1c
-
-dist_man1_MANS = asn1c.1
+dist_man1_MANS = asn1c.1 unber.1
check_SCRIPTS = check-parsing.sh
TESTS = check-parsing.sh
diff --git a/asn1c/Makefile.in b/asn1c/Makefile.in
index 431b38ab..73c25f35 100644
--- a/asn1c/Makefile.in
+++ b/asn1c/Makefile.in
@@ -14,7 +14,7 @@
@SET_MAKE@
-SOURCES = $(asn1c_SOURCES)
+SOURCES = asn1c.c unber.c
srcdir = @srcdir@
top_srcdir = @top_srcdir@
@@ -37,7 +37,7 @@ NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
host_triplet = @host@
-bin_PROGRAMS = asn1c$(EXEEXT)
+bin_PROGRAMS = asn1c$(EXEEXT) unber$(EXEEXT)
subdir = asn1c
DIST_COMMON = README $(dist_man1_MANS) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in
@@ -51,18 +51,19 @@ CONFIG_CLEAN_FILES =
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS)
-am_asn1c_OBJECTS = asn1c.$(OBJEXT) tlv_decoder.$(OBJEXT)
-asn1c_OBJECTS = $(am_asn1c_OBJECTS)
-asn1c_LDADD = $(LDADD)
+asn1c_SOURCES = asn1c.c
+asn1c_OBJECTS = asn1c.$(OBJEXT)
asn1c_DEPENDENCIES = $(top_builddir)/libasn1parser/libasn1parser.la \
$(top_builddir)/libasn1print/libasn1print.la \
$(top_builddir)/libasn1fix/libasn1fix.la \
$(top_builddir)/libasn1compiler/libasn1compiler.la
+unber_SOURCES = unber.c
+unber_OBJECTS = unber.$(OBJEXT)
+unber_LDADD = $(LDADD)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
-@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/asn1c.Po \
-@AMDEP_TRUE@ ./$(DEPDIR)/tlv_decoder.Po
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/asn1c.Po ./$(DEPDIR)/unber.Po
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) \
@@ -71,8 +72,8 @@ LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) \
CCLD = $(CC)
LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
-SOURCES = $(asn1c_SOURCES)
-DIST_SOURCES = $(asn1c_SOURCES)
+SOURCES = asn1c.c unber.c
+DIST_SOURCES = asn1c.c unber.c
RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
html-recursive info-recursive install-data-recursive \
install-exec-recursive install-info-recursive \
@@ -205,16 +206,13 @@ AM_CPPFLAGS = \
-I${top_srcdir}/skeletons \
-DDATADIR=\"$(pkgdatadir)\"
-LDADD = \
+asn1c_LDADD = \
$(top_builddir)/libasn1parser/libasn1parser.la \
$(top_builddir)/libasn1print/libasn1print.la \
$(top_builddir)/libasn1fix/libasn1fix.la \
$(top_builddir)/libasn1compiler/libasn1compiler.la
-asn1c_SOURCES = asn1c.c \
- tlv_decoder.c tlv_decoder.h
-
-dist_man1_MANS = asn1c.1
+dist_man1_MANS = asn1c.1 unber.1
check_SCRIPTS = check-parsing.sh
TESTS = check-parsing.sh
EXTRA_DIST = check-parsing.sh
@@ -283,6 +281,9 @@ clean-binPROGRAMS:
asn1c$(EXEEXT): $(asn1c_OBJECTS) $(asn1c_DEPENDENCIES)
@rm -f asn1c$(EXEEXT)
$(LINK) $(asn1c_LDFLAGS) $(asn1c_OBJECTS) $(asn1c_LDADD) $(LIBS)
+unber$(EXEEXT): $(unber_OBJECTS) $(unber_DEPENDENCIES)
+ @rm -f unber$(EXEEXT)
+ $(LINK) $(unber_LDFLAGS) $(unber_OBJECTS) $(unber_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -291,7 +292,7 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1c.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tlv_decoder.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unber.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
diff --git a/asn1c/README b/asn1c/README
index 158cd115..8bec7b9e 100644
--- a/asn1c/README
+++ b/asn1c/README
@@ -1 +1,2 @@
-The ASN.1 Compiler
+asn1c - The ASN.1 Compiler
+unber - The ASN.1 BER Decoder
diff --git a/asn1c/asn1c.1 b/asn1c/asn1c.1
index 8d7cf061..d6be9458 100644
--- a/asn1c/asn1c.1
+++ b/asn1c/asn1c.1
@@ -4,9 +4,8 @@
.TH ASN1C 1 "\*(Dt" "ASN.1 Compiler" "ASN.1 Compiler"
.SH NAME
asn1c \- ASN.1 Compiler
-.ND ASN.1 compiler
.SH SYNOPSIS
-asn1c [\fB\-E\fR [\fB-F\fR] | \fB\-P\fR | \fB\-R\fR | \fB\-t\fR\fIdata-string\fR]
+asn1c [\fB\-E\fR [\fB-F\fR] | \fB\-P\fR | \fB\-R\fR]
[\fB\-S\fR\fIdir\fR]
[\fB\-W\fR\fIdebug-\fR...] [\fB\-f\fR\fIoption\fR...] [\fB\-p\fR\fIrint-\fR...]
\fIinfile\fR...
@@ -19,7 +18,6 @@ and other encoding standards.
\fIOverall Options\fR
\fB\-E \-F \-P \-R\fR
.BI "\-S " directory
-.BI "\-t " data-string
.TP
\fIWarning Options\fR
.br
@@ -55,10 +53,6 @@ omitting the usual support code.
.TP
\fB\-S\fR \fIdirectory\fR
Use the specified directory with ASN.1 skeleton files.
-.TP
-\fB\-t\fR \fIdata-string\fR
-Interpret the data-string as a sequence of hexadecimal values representing
-the start of BER TLV encoding. Print the human readable explanation.
.SH WARNING OPTIONS
.TP
.B \-Werror
@@ -104,5 +98,8 @@ its internal understanding of subtype constraints.
.TP
.B \-print-lines
Generate "-- #line" comments in \fB-E\fR output.
+.SH SEE ALSO
+.TP
+\&\fIunber\fR\|(1)
.SH AUTHORS
Lev Walkin <vlm@lionet.info>
diff --git a/asn1c/asn1c.c b/asn1c/asn1c.c
index 9dd5dde3..e3097bd5 100644
--- a/asn1c/asn1c.c
+++ b/asn1c/asn1c.c
@@ -19,9 +19,7 @@
#include <asn1c_compat.h> /* Portable basename(3) and dirname(3) */
-#include "tlv_decoder.h" /* -t: decode TL[V?] string */
-
-static void usage(char *av0); /* Print the Usage screen and exit(EX_USAGE) */
+static void usage(const char *av0); /* Print the Usage screen and exit */
#undef COPYRIGHT
#define COPYRIGHT \
@@ -45,7 +43,7 @@ main(int ac, char **av) {
/*
* Process command-line options.
*/
- while((ch = getopt(ac, av, "EFf:hLPp:RS:t:vW:")) != -1)
+ while((ch = getopt(ac, av, "EFf:hLPp:RS:vW:")) != -1)
switch(ch) {
case 'E':
print_arg__print_out = 1;
@@ -97,10 +95,6 @@ main(int ac, char **av) {
case 'S':
skeletons_dir = optarg;
break;
- case 't':
- if(decode_tlv_from_string(optarg))
- exit(EX_DATAERR);
- exit(0);
case 'v':
fprintf(stderr, "ASN.1 Compiler, v" VERSION "\n" COPYRIGHT);
exit(0);
@@ -264,11 +258,11 @@ main(int ac, char **av) {
* Print the usage screen and exit(EX_USAGE).
*/
static void
-usage(char *av0) {
+usage(const char *av0) {
fprintf(stderr,
"ASN.1 Compiler, v" VERSION "\n" COPYRIGHT
-"Usage: %s [options] infile...\n"
-"Where [options] are:\n"
+"Usage: %s [options] file ...\n"
+"Options:\n"
" -E Run only the ASN.1 parser and print out the tree\n"
" -F During -E operation, also perform tree fixing\n"
"\n"
@@ -278,10 +272,6 @@ usage(char *av0) {
" (Default is \"%s\")\n"
"\n"
-" -t <data-string> Decode the given tag[/length] sequence\n"
-" (e.g. -t \"bf 20\")\n"
-"\n"
-
" -Werror Treat warnings as errors; abort if any warning\n"
" -Wdebug-lexer Enable verbose debugging output from lexer\n"
" -Wdebug-fixer --//-- semantics processor\n"
diff --git a/asn1c/unber.c b/asn1c/unber.c
new file mode 100644
index 00000000..a954ece1
--- /dev/null
+++ b/asn1c/unber.c
@@ -0,0 +1,481 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sysexits.h> /* for EX_USAGE */
+#include <assert.h>
+#include <errno.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <asn1parser.h> /* For static string tables */
+
+#include <asn_types.h>
+#include <ber_tlv_tag.h>
+#include <ber_tlv_length.h>
+#include <ber_tlv_tag.c>
+#include <ber_tlv_length.c>
+
+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);
+
+#undef COPYRIGHT
+#define COPYRIGHT \
+ "Copyright (c) 2004 Lev Walkin <vlm@lionet.info>\n"
+
+static char *indent_buffer = " ";
+
+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, "i:t:v")) != -1)
+ switch(ch) {
+ case 't':
+ if(decode_tlv_from_string(optarg))
+ exit(EX_DATAERR);
+ exit(0);
+ case 'i':
+ i = atoi(optarg);
+ if(i >= 0 && i < 16) {
+ indent_buffer = alloca(i + 1);
+ memset(indent_buffer, ' ', i);
+ indent_buffer[i] = '\0';
+ } else {
+ fprintf(stderr, "-i %s: Invalid indent value\n",optarg);
+ exit(EX_USAGE);
+ }
+ break;
+ case 'v':
+ fprintf(stderr, "ASN.1 BER Decoder, v" VERSION "\n" COPYRIGHT);
+ exit(0);
+ break;
+ default:
+ usage(av[0]);
+ }
+
+ /*
+ * Ensure that there are some input files present.
+ */
+ if(ac > optind) {
+ ac -= optind;
+ av += optind;
+ } else {
+ fprintf(stderr, "%s: No input files specified\n", av[0]);
+ exit(1);
+ }
+
+ setvbuf(stdout, 0, _IOLBF, 0);
+
+ /*
+ * 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);
+ }
+
+ return 0;
+}
+
+/*
+ * Print the usage screen and exit(EX_USAGE).
+ */
+static void
+usage(const char *av0) {
+ fprintf(stderr,
+"ASN.1 BER Decoder, v" VERSION "\n" COPYRIGHT
+"Usage: %s [options] [-] [file ...]\n"
+"Options:\n"
+" -i <indent> Amount of spaces for indentation (default is 4)\n"
+" -t <data-string> Decode the given tag[/length] sequence\n"
+" (e.g. -t \"bf 20\")\n"
+ , av0);
+ 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, int level, ssize_t limit);
+static void print_TL(int fin, int level, int constr, ssize_t tlen, ber_tlv_tag_t, ber_tlv_len_t);
+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;
+
+ if(strcmp(fname, "-")) {
+ fp = fopen(fname, "r");
+ if(!fp) {
+ perror(fname);
+ return -1;
+ }
+ } else {
+ fp = stdin;
+ }
+
+ /*
+ * Fetch out BER-encoded data until EOF or error.
+ */
+ do {
+ pdc = process_deeper(fname, fp, 0, -1);
+ } while(pdc == PD_FINISHED); /* Wait until PD_EOF */
+
+ 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, int level, ssize_t limit) {
+ 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;
+
+ do {
+ int constr;
+ int ch;
+
+ if(limit == 0)
+ return PD_FINISHED;
+
+ if(limit >= 0 && tblen >= limit) {
+ fprintf(stderr,
+ "%s: Too long TL sequence (%ld >= %ld). "
+ "Dangerous file\n",
+ fname, (long)tblen, (long)limit);
+ return PD_FAILED;
+ }
+
+ ch = fgetc(fp);
+ if(ch == -1) {
+ if(tblen) {
+ fprintf(stderr,
+ "%s: Unexpected end of file (TL)\n",
+ fname);
+ 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 deciphering tag\n",
+ fname);
+ 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 deciphering length\n",
+ fname);
+ 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);
+
+ print_TL(0, level, constr, tblen, tlv_tag, tlv_len);
+
+ if(limit != -1) {
+ /* If limit is set, account for the TL sequence */
+ limit -= (t_len + l_len);
+ assert(limit >= 0);
+ }
+
+ if(limit != -1) {
+ 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;
+ } else if(tlv_len != -1) {
+ /* Account for the V */
+ limit -= tlv_len;
+ }
+ }
+
+ if(constr) {
+ /*
+ * This is a constructed type. Process recursively.
+ */
+
+ /* Get the new subframe limit from the structure tags */
+ if(tlv_len == -1)
+ tlv_len = limit;
+
+ pdc = process_deeper(fname, fp, level + 1, tlv_len);
+ if(pdc == PD_FAILED) return pdc;
+ } else {
+
+ assert(tlv_len >= 0);
+ if(print_V(fname, fp, tlv_tag, tlv_len))
+ return PD_FAILED;
+ }
+
+ print_TL(1, level, constr, tblen, tlv_tag, tlv_len);
+
+ tblen = 0;
+ } while(1);
+
+ return pdc;
+}
+
+static void
+print_TL(int fin, int level, int constr, ssize_t tlen, ber_tlv_tag_t tlv_tag, ber_tlv_len_t tlv_len) {
+
+ if(fin && tlen == 2 && !constr && !tlv_tag && !tlv_len) {
+ /* end of content octets */
+ return;
+ }
+
+ if(fin && !constr) {
+ printf("</P>\n");
+ return;
+ }
+
+ while(level-- > 0) printf(indent_buffer); /* Print indent */
+ printf(fin ? "</" : "<");
+
+ printf(constr ? "C" : "P");
+
+ printf(" T=\"");
+ ber_tlv_tag_fwrite(tlv_tag, stdout);
+ printf("\"");
+
+ if(!fin) {
+ printf(" tL=\"%ld\"", (long)tlen);
+
+ if(tlv_len == -1)
+ printf(" L=\"Indefinite\"");
+ else
+ printf(" L=\"%ld\"", (long)tlv_len);
+ }
+
+ 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(" A=\"%s\"", str);
+ }
+
+ if(fin || constr)
+ printf(">\n");
+ else
+ printf(">");
+}
+
+static int
+print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag, ber_tlv_len_t tlv_len) {
+ asn1p_expr_type_e etype = 0;
+ long collector = 0;
+ ssize_t i;
+
+ /* Figure out what type is it */
+ if(BER_TAG_CLASS(tlv_tag) == ASN_TAG_CLASS_UNIVERSAL) {
+ ber_tlv_tag_t tvalue = BER_TAG_VALUE(tlv_tag);
+ etype = ASN_UNIVERSAL_TAG2TYPE(tvalue);
+ }
+
+ /*
+ * Print the value in binary or text form.
+ */
+ for(i = 0; i < tlv_len; i++) {
+ int ch = fgetc(fp);
+ if(ch == -1) {
+ fprintf(stderr,
+ "%s: Unexpected end of file (V)\n", fname);
+ 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_UTF8String:
+ switch(ch) {
+ default:
+ if(((etype == ASN_STRING_UTF8String)
+ || !(ch & 0x80))
+ && (ch >= 0x20)
+ ) {
+ printf("%c", ch);
+ break;
+ }
+ /* Fall through */
+ case '<': case '>': case '&':
+ printf("&x%02x;", ch);
+ }
+ break;
+ case ASN_BASIC_BOOLEAN:
+ if(tlv_len == 1) {
+ switch(ch) {
+ case 0: printf("<false/>"); break;
+ case 0xff: printf("<true/>"); break;
+ default: printf("<true value=\"&x%02x\"/>", ch);
+ }
+ break;
+ }
+ /* Fall through */
+ case ASN_BASIC_INTEGER:
+ case ASN_BASIC_ENUMERATED:
+ if((size_t)tlv_len <= sizeof(collector)) {
+ if(i) {
+ collector = collector * 256 + ch;
+ } else {
+ collector = (int)(signed char)ch;
+ }
+ if((i+1) == tlv_len)
+ printf("%ld", collector);
+ break;
+ }
+ /* Fall through */
+ default:
+ printf("&x%02x;", ch);
+ }
+ }
+
+ 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++) {
+ 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;
+ }
+ 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 deciphering 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 deciphering 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;
+}