diff options
-rw-r--r-- | asn1c/enber.1 | 26 | ||||
-rw-r--r-- | asn1c/enber.c | 47 | ||||
-rw-r--r-- | asn1c/unber.1 | 16 | ||||
-rw-r--r-- | asn1c/unber.c | 52 |
4 files changed, 100 insertions, 41 deletions
diff --git a/asn1c/enber.1 b/asn1c/enber.1 index 8b1f42e1..4a9edfc2 100644 --- a/asn1c/enber.1 +++ b/asn1c/enber.1 @@ -12,16 +12,38 @@ .SH NAME enber \- Convert the unber XML output back into BER .SH SYNOPSIS -enber [\fB-\fR] \fIinfile\fR... +enber [\fB-n\fR] [\fB-\fR] \fIinfile\fR... .SH DESCRIPTION -enber takes the XML-encoded files produced by \fIunber\fR\|(1) and converts +enber takes the XML-formatted files produced by \fIunber\fR\|(1) and converts them back into the BER format. A single dash represents the standard input. +.SH OPTIONS +.TP +\fB\-n\fR +Disable input validation. By default, enber performs some basic validity checks +against the XML input. This option disables such checks. .SH EXAMPLES Decode the BER sequence and immediately encode it back .Vb \& unber \fB-p\fR \fIfilename.ber\fR | enber \fB-\fR > \fIreconstructed.ber\fR .Ve +.SH FOOTNOTES +This program does not attempt to perform full-fledged XML parsing. It is merely +compatible with \fIunber\fR\|(1)'s output. +In particular, the XML comments are not supported. +The following characters after the initial white space indicate +the start of a comment: "\fB#\fR" (a hash) and "\fB--\fR" (two dashes). +The whole comment line is ignored completely. Empty lines are ignored as well. +.P +The following example demostrates the use of comments: +.Vb +\& <C T="[1]" TL="2" V="2"> +\& <I T="[1]" TL="2" V="Indefinite"> +\& -- </I> +\& # Do not terminate: +\& # the absence of end-of-content octets is intentional! +\& </C> +.Ve .SH SEE ALSO .TP \&\fIunber\fR\|(1), \&\fIasn1c\fR\|(1) diff --git a/asn1c/enber.c b/asn1c/enber.c index 45fda434..c6cadf7b 100644 --- a/asn1c/enber.c +++ b/asn1c/enber.c @@ -45,7 +45,7 @@ #include <ber_tlv_tag.c> #include <ber_tlv_length.c> -static void usage(const char *av0); /* Print the Usage screen and exit */ +static void usage(const char *av0, int);/* Print the Usage screen and exit */ static int process(const char *fname); /* Perform the BER decoding */ static int process_line(const char *fname, char *line, int lineno); @@ -53,6 +53,8 @@ static int process_line(const char *fname, char *line, int lineno); #define COPYRIGHT \ "Copyright (c) 2004 Lev Walkin <vlm@lionet.info>\n" +static int no_validation; /* -n */ + int main(int ac, char **av) { int ch; /* Command line character */ @@ -61,15 +63,20 @@ main(int ac, char **av) { /* * Process command-line options. */ - while((ch = getopt(ac, av, "hv")) != -1) + while((ch = getopt(ac, av, "nhv")) != -1) switch(ch) { + case 'n': + no_validation++; + break; case 'v': - fprintf(stderr, "ASN.1 BER Decoder, v" VERSION "\n" COPYRIGHT); + usage(av[0], 1); + fprintf(stderr, "Convert unber(1)'s output back into BER, " + "v" VERSION "\n" COPYRIGHT); exit(0); break; case 'h': default: - usage(av[0]); + usage(av[0], 0); } /* @@ -101,11 +108,15 @@ main(int ac, char **av) { * Print the usage screen and exit(EX_USAGE). */ static void -usage(const char *av0) { +usage(const char *av0, int copyright_only) { + fprintf(stderr, + "Convert unber(1)'s output back into BER, " + "v" VERSION "\n" COPYRIGHT); + if(copyright_only) exit(0); fprintf(stderr, -"Convertor of under(1) output back into BER, v" VERSION "\n" COPYRIGHT -"Usage: %s [-] [file ...]\n" - , av0); + "Usage: %s [-n] [-] [file ...]\n" + "Options:\n" + " -n Disable XML input validation\n", av0); exit(EX_USAGE); } @@ -184,9 +195,18 @@ process_line(const char *fname, char *line, int lineno) { (void)fname; /* Find a tag opening angle bracket */ - for(; *line == ' '; line++); + for(; *line == ' ' || *line == '\t'; line++); op = line; - if(*op != '<') { + switch(*op) { + case '<': /* That's what we want! A tag opening */ + break; + case '-': /* This is a comment (dash-dash) */ + if(op[1] == *op) + case '\r': + case '\n': + case '#': /* This is a comment */ + return 0; + default: fprintf(stderr, "%s: Missing '<' after whitespace\n", fname); exit(EX_DATAERR); } @@ -240,10 +260,10 @@ process_line(const char *fname, char *line, int lineno) { tcl_pos = strstr(op, "T=\"["); tl_pos = strstr(op, "TL=\""); v_pos = strstr(op, "V=\""); - if(!tcl_pos || !tl_pos || !v_pos) { + if(!tcl_pos || !tl_pos || (!v_pos && constr != 2)) { fprintf(stderr, "%s: Mandatory attribute %s is not found at line %d\n", - fname, (!tcl_pos)?"T":(v_pos?"V":"TCL"), lineno); + fname, (!tcl_pos)?"T":((!v_pos)?"V":"TL"), lineno); exit(EX_DATAERR); } errno = 0; @@ -368,11 +388,12 @@ process_line(const char *fname, char *line, int lineno) { fputc(v, stdout); } if(len != tlv_len) { + if(no_validation) fprintf(stderr, "Warning: "); fprintf(stderr, "%s: Could not encode value of %d chars " "at line %d in %d bytes\n", fname, len, lineno, tlv_len); - exit(EX_DATAERR); + if(!no_validation) exit(EX_DATAERR); } } diff --git a/asn1c/unber.1 b/asn1c/unber.1 index bfedffa3..a31fabd1 100644 --- a/asn1c/unber.1 +++ b/asn1c/unber.1 @@ -29,7 +29,8 @@ By default, unber continues decoding until the end of file (input stream). Use the specified number of spaces for output indentation. Default is 4 spaces. .TP \fB\-p\fR -Do \fInot\fR attempt pretty-printing of known ASN.1 types (strings, INTEGER, BOOLEAN, etc). +Do \fInot\fR attempt pretty-printing of known ASN.1 types (OBJECT IDENTIFIER, INTEGER, BOOLEAN, etc). By default, some ASN.1 types are converted into +the text representation. This option is required for \&\fIenber\fR\|(1). .TP \fB\-t\fR \fIdata-string\fR Interpret the data-string as a sequence of hexadecimal values representing @@ -62,7 +63,7 @@ Likely name of the underlying ASN.1 type (for UNIVERSAL tags) [\fIF\fR] Indicates that the value was reformatted (pretty-printed) .P -Example: +Sample XML output: .Vb \& <I T="[UNIVERSAL 16]" TL="2" V="Indefinite" A="SEQUENCE"> \& <P T="[UNIVERSAL 19]" TL="2" V="2" A="PrintableString">US</P> @@ -84,10 +85,19 @@ Decode the binary stream taken from the standard input: .Vb \& cat \fI...\fR | unber \fB-\fR .Ve -Decode the binary stream into the same stream (see \fIenber\fR\|(1)): +Decode the binary stream into the same stream (see \&\fIenber\fR\|(1)): .Vb \& cat \fI...\fR | unber \fB-p\fR \fB-\fR | enber \fB-\fR > filename.ber\fI\fR .Ve +.SH FOOTNOTES +The constructed XML output is not necessarily well-formed. +.P +When indefinite length encoding is being used, the BER sequence, which is not +terminated with the end-of-content octets, will cause the terminating \fB</I>\fR +XML tag to disappear. +Thus, the invalid BER framing directly causes invalid XML output. +.P +The \&\fIenber\fR\|(1) utility understands this convention correctly. .SH SEE ALSO .TP \&\fIenber\fR\|(1), \&\fIasn1c\fR\|(1) diff --git a/asn1c/unber.c b/asn1c/unber.c index c9e7da12..c7ba71c8 100644 --- a/asn1c/unber.c +++ b/asn1c/unber.c @@ -158,7 +158,7 @@ typedef enum pd_code { 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 pd_code_e process_deeper(const char *fname, FILE *fp, int level, ssize_t limit, ssize_t *decoded, int expect_eoc); 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); @@ -169,6 +169,7 @@ static int process(const char *fname) { FILE *fp; pd_code_e pdc; + ssize_t decoded = 0; if(strcmp(fname, "-")) { fp = fopen(fname, "r"); @@ -184,7 +185,7 @@ process(const char *fname) { * Fetch out BER-encoded data until EOF or error. */ do { - pdc = process_deeper(fname, fp, 0, -1); + pdc = process_deeper(fname, fp, 0, -1, &decoded, 0); } while(pdc == PD_FINISHED && !single_type_decoding); if(fp != stdin) @@ -198,7 +199,7 @@ process(const char *fname) { /* * Process the TLV recursively. */ -static pd_code_e process_deeper(const char *fname, FILE *fp, int level, ssize_t limit) { +static pd_code_e process_deeper(const char *fname, FILE *fp, int level, ssize_t limit, ssize_t *decoded, int expect_eoc) { unsigned char tagbuf[32]; ssize_t tblen = 0; pd_code_e pdc = PD_FINISHED; @@ -266,52 +267,57 @@ static pd_code_e process_deeper(const char *fname, FILE *fp, int level, ssize_t continue; } - if(tagbuf[0] == '\0' && tagbuf[1] == '\0') { - /* End of content octets */ - return PD_FINISHED; - } - /* 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(!expect_eoc || tagbuf[0] || tagbuf[1]) + 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; } } + *decoded += t_len + l_len; + + if(expect_eoc && tagbuf[0] == '\0' && tagbuf[1] == '\0') { + /* End of content octets */ + print_TL(1, level - 1, 1, 2, 0, -1); + return PD_FINISHED; + } + if(constr) { + ssize_t dec = 0; /* * This is a constructed type. Process recursively. */ - - /* Get the new subframe limit from the structure tags */ - if(tlv_len == -1) - tlv_len = limit; - printf(">\n"); /* Close the opening tag */ - pdc = process_deeper(fname, fp, level + 1, tlv_len); + pdc = process_deeper(fname, fp, level + 1, + tlv_len == -1 ? limit : tlv_len, + &dec, tlv_len == -1); if(pdc == PD_FAILED) return pdc; + if(limit != -1) limit -= dec; + *decoded += dec; + if(tlv_len == -1) { + tblen = 0; + continue; + } } else { - assert(tlv_len >= 0); if(print_V(fname, fp, tlv_tag, tlv_len)) return PD_FAILED; + + limit -= tlv_len; + *decoded += tlv_len; } print_TL(1, level, constr, tblen, tlv_tag, tlv_len); @@ -339,9 +345,9 @@ print_TL(int fin, int level, int constr, ssize_t tlen, ber_tlv_tag_t tlv_tag, be ber_tlv_tag_fwrite(tlv_tag, stdout); printf("\""); - if(!fin) { + if(!fin || tlv_len == -1) printf(" TL=\"%ld\"", (long)tlen); - + if(!fin) { if(tlv_len == -1) printf(" V=\"Indefinite\""); else |