diff --git a/ChangeLog b/ChangeLog index 54356670..6c6a4656 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,14 +3,14 @@ * skeletons/standard-modules directory is now used for standard types. * Fixed class field access problem (Test case 98) - (Severity: medim; Security impact: none) + (Severity: medium; Security impact: none) * Refactored Information Object Classes parsing. * Refactored Parameterization support. * [typedef enum foo {}] foo_e; is now e_foo, see #1287989 * Refactored ValueSetTypeAssignment parsing. - * First release of PER encoder (does not encode SETs yet). * asn-decoder-template.c renamed into converter-sample.c * MEGACO (Media Gateway Control Protocol) decoder sample added. + * First release of PER encoder (does not encode SETs yet). 0.9.20: 2006-Mar-06 diff --git a/examples/sample.makefile.regen b/examples/sample.makefile.regen index 134e1f24..0e28ab6a 100755 --- a/examples/sample.makefile.regen +++ b/examples/sample.makefile.regen @@ -35,6 +35,19 @@ cat Makefile.am.sample \ echo " @touch ${ASN1PDU}.c" echo " make" echo + echo 'check: ${TARGET}' + echo " @if test -f ./sample-${ASN1PDU}-1.[db]er ; then \\" + echo " for f in ./sample-${ASN1PDU}-*.[db]er; do \\" + echo ' echo "Recoding $$f into XER and back..."; \' + echo ' ./${TARGET} -iber -oxer $$f > ./.tmp.1.$$ || exit 2; \' + echo ' ./${TARGET} -ixer -oxer ./.tmp.1.$$ > ./.tmp.2.$$ || exit 2; \' + echo ' diff ./.tmp.1.$$ ./.tmp.2.$$ || exit 2; \' + echo ' rm -f ./.tmp.[12].$$; \' + echo ' done; fi' + echo ' @echo ================' + echo ' @echo All tests passed' + echo ' @echo ================' + echo echo "distclean: clean" echo ' rm -f $(ASN_MODULE_SOURCES) $(ASN_MODULE_HEADERS)' echo ' rm -f $(ASN_CONVERTER_SOURCES) $(ASN_CONVERTER_HEADERS)' diff --git a/examples/sample.source.LDAP3/Makefile b/examples/sample.source.LDAP3/Makefile index f7dfc64b..5483981c 100644 --- a/examples/sample.source.LDAP3/Makefile +++ b/examples/sample.source.LDAP3/Makefile @@ -196,6 +196,19 @@ LDAPMessage.c: ../sample.makefile.regen @touch LDAPMessage.c make +check: ${TARGET} + @if test -f ./sample-LDAPMessage-1.[db]er ; then \ + for f in ./sample-LDAPMessage-*.[db]er; do \ + echo "Recoding $$f into XER and back..."; \ + ./${TARGET} -iber -oxer $$f > ./.tmp.1.$$ || exit 2; \ + ./${TARGET} -ixer -oxer ./.tmp.1.$$ > ./.tmp.2.$$ || exit 2; \ + diff ./.tmp.1.$$ ./.tmp.2.$$ || exit 2; \ + rm -f ./.tmp.[12].$$; \ + done; fi + @echo ================ + @echo All tests passed + @echo ================ + distclean: clean rm -f $(ASN_MODULE_SOURCES) $(ASN_MODULE_HEADERS) rm -f $(ASN_CONVERTER_SOURCES) $(ASN_CONVERTER_HEADERS) diff --git a/examples/sample.source.MEGACO/Makefile b/examples/sample.source.MEGACO/Makefile index d922a9da..b1415a2d 100644 --- a/examples/sample.source.MEGACO/Makefile +++ b/examples/sample.source.MEGACO/Makefile @@ -318,6 +318,19 @@ MegacoMessage.c: ../sample.makefile.regen @touch MegacoMessage.c make +check: ${TARGET} + @if test -f ./sample-MegacoMessage-1.[db]er ; then \ + for f in ./sample-MegacoMessage-*.[db]er; do \ + echo "Recoding $$f into XER and back..."; \ + ./${TARGET} -iber -oxer $$f > ./.tmp.1.$$ || exit 2; \ + ./${TARGET} -ixer -oxer ./.tmp.1.$$ > ./.tmp.2.$$ || exit 2; \ + diff ./.tmp.1.$$ ./.tmp.2.$$ || exit 2; \ + rm -f ./.tmp.[12].$$; \ + done; fi + @echo ================ + @echo All tests passed + @echo ================ + distclean: clean rm -f $(ASN_MODULE_SOURCES) $(ASN_MODULE_HEADERS) rm -f $(ASN_CONVERTER_SOURCES) $(ASN_CONVERTER_HEADERS) diff --git a/examples/sample.source.PKIX1/Makefile b/examples/sample.source.PKIX1/Makefile index 30e89518..26ca7488 100644 --- a/examples/sample.source.PKIX1/Makefile +++ b/examples/sample.source.PKIX1/Makefile @@ -378,6 +378,19 @@ Certificate.c: ../sample.makefile.regen @touch Certificate.c make +check: ${TARGET} + @if test -f ./sample-Certificate-1.[db]er ; then \ + for f in ./sample-Certificate-*.[db]er; do \ + echo "Recoding $$f into XER and back..."; \ + ./${TARGET} -iber -oxer $$f > ./.tmp.1.$$ || exit 2; \ + ./${TARGET} -ixer -oxer ./.tmp.1.$$ > ./.tmp.2.$$ || exit 2; \ + diff ./.tmp.1.$$ ./.tmp.2.$$ || exit 2; \ + rm -f ./.tmp.[12].$$; \ + done; fi + @echo ================ + @echo All tests passed + @echo ================ + distclean: clean rm -f $(ASN_MODULE_SOURCES) $(ASN_MODULE_HEADERS) rm -f $(ASN_CONVERTER_SOURCES) $(ASN_CONVERTER_HEADERS) diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c index 3643465c..5a0eccee 100644 --- a/skeletons/INTEGER.c +++ b/skeletons/INTEGER.c @@ -297,6 +297,20 @@ INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value) { INTEGER__compar_value2enum); } +static int +INTEGER_st_prealloc(INTEGER_t *st, int min_size) { + void *p = MALLOC(min_size + 1); + if(p) { + void *b = st->buf; + st->size = 0; + st->buf = p; + FREEMEM(b); + return 0; + } else { + return -1; + } +} + /* * Decode the chunk of XML text encoding INTEGER. */ @@ -310,11 +324,19 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun const char *lstop = lstart + chunk_size; enum { ST_SKIPSPACE, + ST_SKIPSPHEX, ST_WAITDIGITS, ST_DIGITS, + ST_HEXDIGIT1, + ST_HEXDIGIT2, + ST_HEXCOLON, ST_EXTRASTUFF } state = ST_SKIPSPACE; + if(chunk_size) + ASN_DEBUG("INTEGER body %d 0x%2x..0x%2x", + chunk_size, *lstart, lstop[-1]); + /* * We may have received a tag here. It will be processed inline. * Use strtoul()-like code and serialize the result. @@ -323,7 +345,19 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun int lv = *lp; switch(lv) { case 0x09: case 0x0a: case 0x0d: case 0x20: - if(state == ST_SKIPSPACE) continue; + switch(state) { + case ST_SKIPSPACE: + case ST_SKIPSPHEX: + continue; + case ST_HEXCOLON: + if(xer_is_whitespace(lp, lstop - lp)) { + lp = lstop - 1; + continue; + } + break; + default: + break; + } break; case 0x2d: /* '-' */ if(state == ST_SKIPSPACE) { @@ -340,7 +374,24 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun break; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: - if(state != ST_DIGITS) state = ST_DIGITS; + switch(state) { + case ST_DIGITS: break; + case ST_SKIPSPHEX: /* Fall through */ + case ST_HEXDIGIT1: + value = (lv - 0x30) << 4; + state = ST_HEXDIGIT2; + continue; + case ST_HEXDIGIT2: + value += (lv - 0x30); + state = ST_HEXCOLON; + st->buf[st->size++] = value; + continue; + case ST_HEXCOLON: + return XPBD_BROKEN_ENCODING; + default: + state = ST_DIGITS; + break; + } { long new_value = value * 10; @@ -381,22 +432,86 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun ASN_DEBUG("Unknown identifier for INTEGER"); } return XPBD_BROKEN_ENCODING; + case 0x3a: /* ':' */ + if(state == ST_HEXCOLON) { + /* This colon is expected */ + state = ST_HEXDIGIT1; + continue; + } else if(state == ST_DIGITS) { + /* The colon here means that we have + * decoded the first two hexadecimal + * places as a decimal value. + * Switch decoding mode. */ + ASN_DEBUG("INTEGER re-evaluate as hex form"); + if(INTEGER_st_prealloc(st, (chunk_size/3) + 1)) + return XPBD_SYSTEM_FAILURE; + state = ST_SKIPSPHEX; + lp = lstart - 1; + continue; + } else { + ASN_DEBUG("state %d at %d", state, lp - lstart); + break; + } + /* [A-Fa-f] */ + case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46: + case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66: + switch(state) { + case ST_SKIPSPHEX: + case ST_SKIPSPACE: /* Fall through */ + case ST_HEXDIGIT1: + value = lv - ((lv < 0x61) ? 0x41 : 0x61); + value += 10; + value <<= 4; + state = ST_HEXDIGIT2; + continue; + case ST_HEXDIGIT2: + value += lv - ((lv < 0x61) ? 0x41 : 0x61); + value += 10; + st->buf[st->size++] = value; + state = ST_HEXCOLON; + continue; + case ST_DIGITS: + ASN_DEBUG("INTEGER re-evaluate as hex form"); + if(INTEGER_st_prealloc(st, (chunk_size/3) + 1)) + return XPBD_SYSTEM_FAILURE; + state = ST_SKIPSPHEX; + lp = lstart - 1; + continue; + default: + break; + } + break; } /* Found extra non-numeric stuff */ + ASN_DEBUG("Found non-numeric 0x%2x at %d", + lv, lp - lstart); state = ST_EXTRASTUFF; break; } - if(state != ST_DIGITS) { + switch(state) { + case ST_DIGITS: + /* Everything is cool */ + break; + case ST_HEXCOLON: + st->buf[st->size] = 0; /* Just in case termination */ + return XPBD_BODY_CONSUMED; + case ST_HEXDIGIT1: + case ST_HEXDIGIT2: + case ST_SKIPSPHEX: + return XPBD_BROKEN_ENCODING; + default: if(xer_is_whitespace(lp, lstop - lp)) { if(state != ST_EXTRASTUFF) return XPBD_NOT_BODY_IGNORE; - /* Fall through */ + break; } else { - ASN_DEBUG("No useful digits in output"); + ASN_DEBUG("INTEGER: No useful digits (state %d)", + state); return XPBD_BROKEN_ENCODING; /* No digits */ } + break; } value *= sign; /* Change sign, if needed */ diff --git a/skeletons/converter-sample.c b/skeletons/converter-sample.c index c8ee34f2..d146f326 100644 --- a/skeletons/converter-sample.c +++ b/skeletons/converter-sample.c @@ -35,8 +35,10 @@ extern asn_TYPE_descriptor_t *asn_pdu_collection[]; * Open file and parse its contens. */ static void *data_decode_from_file(asn_TYPE_descriptor_t *asnTypeOfPDU, - const char *fname, ssize_t suggested_bufsize); + FILE *f, const char *filename, ssize_t suggested_bufsize); static int write_out(const void *buffer, size_t size, void *key); +static FILE *argument_to_file(char *av[], int idx); +static char *argument_to_name(char *av[], int idx); int opt_debug; /* -d */ static int opt_check; /* -c */ @@ -71,7 +73,7 @@ DEBUG(const char *fmt, ...) { } int -main(int ac, char **av) { +main(int ac, char *av[]) { static asn_TYPE_descriptor_t *pduType = &PDU_Type; ssize_t suggested_bufsize = 8192; /* close or equal to stdio buffer */ int number_of_iterations = 1; @@ -206,15 +208,17 @@ main(int ac, char **av) { * Process all files in turn. */ for(ac_i = 0; ac_i < ac; ac_i++) { - char *fname = av[ac_i]; - void *structure; asn_enc_rval_t erv; + void *structure; /* Decoded structure */ + FILE *file = argument_to_file(av, ac_i); + char *name = argument_to_name(av, ac_i); /* * Decode the encoded structure from file. */ structure = data_decode_from_file(pduType, - fname, suggested_bufsize); + file, name, suggested_bufsize); + if(file && file != stdin) fclose(file); if(!structure) { /* Error message is already printed */ exit(EX_DATAERR); @@ -227,14 +231,14 @@ main(int ac, char **av) { if(asn_check_constraints(pduType, structure, errbuf, &errlen)) { fprintf(stderr, "%s: ASN.1 constraint " - "check failed: %s\n", fname, errbuf); + "check failed: %s\n", name, errbuf); exit(EX_DATAERR); } } switch(oform) { case OUT_NULL: - fprintf(stderr, "%s: decoded successfully\n", fname); + fprintf(stderr, "%s: decoded successfully\n", name); break; case OUT_TEXT: /* -otext */ asn_fprint(stdout, pduType, structure); @@ -242,7 +246,7 @@ main(int ac, char **av) { case OUT_XER: /* -oxer */ if(xer_fprint(stdout, pduType, structure)) { fprintf(stderr, "%s: Cannot convert into XML\n", - fname); + name); exit(EX_UNAVAILABLE); } break; @@ -250,7 +254,7 @@ main(int ac, char **av) { erv = der_encode(pduType, structure, write_out, stdout); if(erv.encoded < 0) { fprintf(stderr, "%s: Cannot convert into DER\n", - fname); + name); exit(EX_UNAVAILABLE); } break; @@ -258,7 +262,7 @@ main(int ac, char **av) { erv = uper_encode(pduType, structure, write_out, stdout); if(erv.encoded < 0) { fprintf(stderr, "%s: Cannot convert into Unaligned PER\n", - fname); + name); exit(EX_UNAVAILABLE); } break; @@ -325,7 +329,8 @@ static void add_bytes_to_buffer(const void *data2add, size_t bySize) { DynamicBuffer.length += bySize; } -static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *fname, ssize_t suggested_bufsize) { +static void * +data_decode_from_file(asn_TYPE_descriptor_t *pduType, FILE *file, const char *filename, ssize_t suggested_bufsize) { static char *fbuf; static ssize_t fbuf_size; static asn_codec_ctx_t s_codec_ctx; @@ -333,26 +338,18 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f void *structure = 0; asn_dec_rval_t rval; size_t rd; - FILE *fp; + + if(!file) { + fprintf(stderr, "%s: %s\n", filename, strerror(errno)); + return 0; + } if(opt_stack) { s_codec_ctx.max_stack_size = opt_stack; opt_codec_ctx = &s_codec_ctx; } - if(strcmp(fname, "-")) { - DEBUG("Processing file %s", fname); - fp = fopen(fname, "r"); - } else { - DEBUG("Processing %s", "standard input"); - fname = "stdin"; - fp = stdin; - } - - if(!fp) { - fprintf(stderr, "%s: %s\n", fname, strerror(errno)); - return 0; - } + DEBUG("Processing %s", filename); /* prepare the file buffer */ if(fbuf_size != suggested_bufsize) { @@ -374,7 +371,7 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f rval.code = RC_WMORE; rval.consumed = 0; - while((rd = fread(fbuf, 1, fbuf_size, fp)) || !feof(fp)) { + while((rd = fread(fbuf, 1, fbuf_size, file)) || !feof(file)) { char *i_bptr; size_t i_size; @@ -425,7 +422,6 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f case RC_OK: DEBUG("RC_OK, finishing up with %ld", (long)rval.consumed); - if(fp != stdin) fclose(fp); return structure; case RC_WMORE: /* @@ -448,14 +444,12 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f break; } - fclose(fp); - /* Clean up partially decoded structure */ ASN_STRUCT_FREE(*pduType, structure); fprintf(stderr, "%s: " "Decode failed past byte %ld: %s\n", - fname, (long)(DynamicBuffer.bytes_shifted + filename, (long)(DynamicBuffer.bytes_shifted + DynamicBuffer.offset + rval.consumed), (rval.code == RC_WMORE) ? "Unexpected end of input" @@ -469,3 +463,27 @@ static int write_out(const void *buffer, size_t size, void *key) { FILE *fp = (FILE *)key; return (fwrite(buffer, 1, size, fp) == size) ? 0 : -1; } + +static int argument_is_stdin(char *av[], int idx) { + if(strcmp(av[idx], "-")) { + return 0; /* Certainly not */ + } else { + /* This might be , unless `./program -- -` */ + if(strcmp(av[-1], "--")) + return 1; + else + return 0; + } +} + +static FILE *argument_to_file(char *av[], int idx) { + return argument_is_stdin(av, idx) + ? stdin + : fopen(av[idx], "r"); +} + +static char *argument_to_name(char *av[], int idx) { + return argument_is_stdin(av, idx) + ? "standard input" + : av[idx]; +}