Commit d1bfea65 authored by Lev Walkin's avatar Lev Walkin
Browse files

SET OF/SEQUENCE OF interaction with named and unnamed CHOICE

parent 5ab96cda
0.9.20: 2005-Nov-07
* SET OF CHOICE, SEQUENCE OF CHOICE and a certain named S/O types
are represented differently in XER. THIS IS AN ICOMPATIBLE CHANGE.
(Test case 70) (Severity: low; Security impact: low)
0.9.19: 2005-Oct-06
* A proper solution to circular references. No kludge flags
......
......@@ -64,7 +64,7 @@ check-succeeded: check-executable
check: check-succeeded
clean:
@rm -f *.o
@rm -f *.o check-executable
EOM
# Perform building and checking
......
<PDU>
<seqOfZuka>
<zuka/>
<NULL/>
</seqOfZuka>
</PDU>
<PDU>
<namedSetOfNULL>
<NULL/> <NULL/> <NULL/>
</namedSetOfNULL>
</PDU>
<PDU>
<setOfChoice>
<a></a>
<b>1</b>
</setOfChoice>
</PDU>
<PDU>
<setOfChoice>
<a/>
<b>1</b>
</setOfChoice>
</PDU>
<PDU>
<namedSetOfChoice>
<a></a>
<b>1</b>
</namedSetOfChoice>
</PDU>
<PDU>
<namedSetOfChoice>
<a/>
<b>1</b>
</namedSetOfChoice>
</PDU>
......@@ -734,11 +734,12 @@ asn1c_lang_C_type_SEx_OF_def(arg_t *arg, int seq_of) {
OUT("offsetof(struct ");
out_name_chain(arg, ONC_avoid_keywords);
OUT(", _asn_ctx),\n");
if(expr_as_xmlvaluelist(arg, v))
OUT("1,\t/* XER encoding is XMLValueList */\n");
else
OUT("0,\t/* XER encoding is XMLDelimitedItemList */\n");
{
int as_xvl = expr_as_xmlvaluelist(arg, v);
OUT("%d,\t/* XER encoding is %s */\n",
as_xvl,
as_xvl ? "XMLValueList" : "XMLDelimitedItemList");
}
);
OUT("};\n");
......@@ -1866,12 +1867,16 @@ expr_as_xmlvaluelist(arg_t *arg, asn1p_expr_t *expr) {
expr = asn1f_find_terminal_type_ex(arg->asn, expr);
if(!expr) return 0;
/* X.680, 25.5, Table 5 */
/*
* X.680, 25.5, Table 5
*/
switch(expr->expr_type) {
case ASN_BASIC_BOOLEAN:
case ASN_BASIC_ENUMERATED:
case ASN_BASIC_NULL:
return 1;
case ASN_CONSTR_CHOICE:
return 2;
default:
return 0;
}
......
......@@ -549,6 +549,8 @@ OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr,
if(!cb) {
er.encoded += (type_variant == _TT_BIT_STRING) + st->size;
er.structure_ptr = 0;
er.failed_type = 0;
return er;
}
......@@ -572,6 +574,8 @@ OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr,
}
er.encoded += st->size;
er.structure_ptr = 0;
er.failed_type = 0;
return er;
cb_failed:
_ASN_ENCODE_FAILED;
......
/*
* Generic BER decoder template for any defined ASN.1 type.
* Generic decoder template for a selected ASN.1 type.
* Copyright (c) 2005 Lev Walkin <vlm@lionet.info>. All rights reserved.
*
* To compile with your own ASN.1 type, please redefine the asn_DEF as shown:
......@@ -21,21 +21,32 @@
#include <asn_application.h>
extern asn_TYPE_descriptor_t asn_DEF; /* ASN.1 type to be decoded */
static asn_TYPE_descriptor_t *pduType = &asn_DEF;
/*
* Open file and parse its contens.
*/
static void *data_decode_from_file(asn_TYPE_descriptor_t *asnTypeOfPDU,
const char *fname, ssize_t suggested_bufsize);
static int write_out(const void *buffer, size_t size, void *key);
int opt_debug; /* -d */
static int opt_check; /* -c */
static int opt_stack; /* -s */
static enum output_method {
OUT_NONE, /* No pretty-printing */
OUT_PRINT, /* -p flag */
OUT_XML /* -x flag */
} opt_ometh; /* -p or -x */
/* Input data format selector */
static enum input_format {
INP_BER, /* -iber: BER input */
INP_XER /* -ixer: XER input */
} iform; /* -i<format> */
/* Output data format selector */
static enum output_format {
OUT_XER, /* -oxer: XER (XML) output */
OUT_DER, /* -oder: DER output */
OUT_TEXT, /* -otext: semi-structured text */
OUT_NULL /* -onull: No pretty-printing */
} oform; /* -o<format> */
#define DEBUG(fmt, args...) do { \
if(!opt_debug) break; \
......@@ -46,7 +57,6 @@ static enum output_method {
int
main(int ac, char **av) {
ssize_t suggested_bufsize = 8192; /* close or equal to stdio buffer */
asn_TYPE_descriptor_t *pduType = &asn_DEF;
int number_of_iterations = 1;
int num;
int ch;
......@@ -54,8 +64,22 @@ main(int ac, char **av) {
/*
* Pocess the command-line argments.
*/
while((ch = getopt(ac, av, "b:cdn:hps:x")) != -1)
while((ch = getopt(ac, av, "i:o:b:cdn:hs:")) != -1)
switch(ch) {
case 'i':
if(optarg[0] == 'b') { iform = INP_BER; break; }
if(optarg[0] == 'x') { iform = INP_XER; break; }
fprintf(stderr, "-i<format>: '%s': improper format selector",
optarg);
exit(EX_UNAVAILABLE);
case 'o':
if(optarg[0] == 'd') { oform = OUT_DER; break; }
if(optarg[0] == 'x') { oform = OUT_XER; break; }
if(optarg[0] == 't') { oform = OUT_TEXT; break; }
if(optarg[0] == 'n') { oform = OUT_NULL; break; }
fprintf(stderr, "-o<format>: '%s': improper format selector",
optarg);
exit(EX_UNAVAILABLE);
case 'b':
suggested_bufsize = atoi(optarg);
if(suggested_bufsize < 1
......@@ -80,9 +104,6 @@ main(int ac, char **av) {
exit(EX_UNAVAILABLE);
}
break;
case 'p':
opt_ometh = OUT_PRINT;
break;
case 's':
opt_stack = atoi(optarg);
if(opt_stack <= 0) {
......@@ -92,25 +113,22 @@ main(int ac, char **av) {
exit(EX_UNAVAILABLE);
}
break;
case 'x':
opt_ometh = OUT_XML;
break;
case 'h':
default:
fprintf(stderr,
"Usage: %s [options] <data.ber> ...\n"
"Where options are:\n"
" -iber (I) Input is in BER (Basic Encoding Rules)\n"
" -ixer Input is in XER (XML Encoding Rules)\n"
" -oder Output in DER (Distinguished Encoding Rules)\n"
" -oxer (O) Output in XER (XML Encoding Rules)\n"
" -otext Output in plain semi-structured text (dump)\n"
" -onull Verify (decode) input, but do not output\n"
" -b <size> Set the i/o buffer size (default is %ld)\n"
" -c Check ASN.1 constraints after decoding\n"
" -d Enable debugging (-dd is even better)\n"
" -n <num> Process files <num> times\n"
" -s <size> Set the stack usage limit\n"
" -p Print out the decoded contents\n"
" -x Print out as XML"
#ifdef ASN_DECODER_DEFAULT_OUTPUT_XML
" (default)"
#endif
"\n"
, av[0], (long)suggested_bufsize);
exit(EX_USAGE);
}
......@@ -119,14 +137,12 @@ main(int ac, char **av) {
av += optind;
if(ac < 1) {
fprintf(stderr, "Error: missing filename\n");
fprintf(stderr, "%s: No input files specified. "
"Try '-h' for more information\n",
av[-optind]);
exit(EX_USAGE);
}
#ifdef ASN_DECODER_DEFAULT_OUTPUT_XML
if(opt_ometh == OUT_NONE) opt_ometh = OUT_XML;
#endif
setvbuf(stdout, 0, _IOLBF, 0);
for(num = 0; num < number_of_iterations; num++) {
......@@ -137,6 +153,7 @@ main(int ac, char **av) {
for(ac_i = 0; ac_i < ac; ac_i++) {
char *fname = av[ac_i];
void *structure;
asn_enc_rval_t erv;
/*
* Decode the encoded structure from file.
......@@ -148,32 +165,40 @@ main(int ac, char **av) {
exit(EX_DATAERR);
}
switch(opt_ometh) {
case OUT_NONE:
/* Check ASN.1 constraints */
if(opt_check) {
char errbuf[128];
size_t errlen = sizeof(errbuf);
if(asn_check_constraints(pduType, structure,
errbuf, &errlen)) {
fprintf(stderr, "%s: ASN.1 constraint "
"check failed: %s\n", fname, errbuf);
exit(EX_DATAERR);
}
}
switch(oform) {
case OUT_NULL:
fprintf(stderr, "%s: decoded successfully\n", fname);
break;
case OUT_PRINT: /* -p */
case OUT_TEXT: /* -otext */
asn_fprint(stdout, pduType, structure);
break;
case OUT_XML: /* -x */
case OUT_XER: /* -oxer */
if(xer_fprint(stdout, pduType, structure)) {
fprintf(stderr, "%s: Cannot convert into XML\n",
fname);
exit(EX_UNAVAILABLE);
}
break;
}
/* Check ASN.1 constraints */
if(opt_check) {
char errbuf[128];
size_t errlen = sizeof(errbuf);
if(asn_check_constraints(pduType, structure,
errbuf, &errlen)) {
fprintf(stderr, "%s: ASN.1 constraint "
"check failed: %s\n", fname, errbuf);
exit(EX_DATAERR);
case OUT_DER:
erv = der_encode(pduType, structure, write_out, stdout);
if(erv.encoded < 0) {
fprintf(stderr, "%s: Cannot convert into DER\n",
fname);
exit(EX_UNAVAILABLE);
}
break;
}
pduType->free_struct(pduType, structure, 0);
......@@ -183,6 +208,10 @@ main(int ac, char **av) {
return 0;
}
/* Dump the buffer */
static int write_out(const void *buffer, size_t size, void *key) {
return (fwrite(buffer, 1, size, key) == size) ? 0 : -1;
}
static char *buffer;
static size_t buf_offset; /* Offset from the start */
......@@ -194,7 +223,7 @@ static off_t buf_shifted; /* Number of bytes ever shifted */
#define bufend (buffer + buf_offset + buf_len)
/*
* Ensure that the buffer contains at least this amoount of free space.
* Ensure that the buffer contains at least this amount of free space.
*/
static void buf_extend(size_t bySize) {
......@@ -231,6 +260,7 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f
static asn_codec_ctx_t s_codec_ctx;
asn_codec_ctx_t *opt_codec_ctx = 0;
void *structure = 0;
asn_dec_rval_t rval;
size_t rd;
FILE *fp;
......@@ -239,9 +269,14 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f
opt_codec_ctx = &s_codec_ctx;
}
DEBUG("Processing file %s", fname);
fp = fopen(fname, "r");
if(strcmp(fname, "-")) {
DEBUG("Processing file %s", fname);
fp = fopen(fname, "r");
} else {
DEBUG("Processing standard input");
fname = "stdin";
fp = stdin;
}
if(!fp) {
fprintf(stderr, "%s: %s\n", fname, strerror(errno));
......@@ -262,9 +297,13 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f
buf_offset = 0;
buf_len = 0;
/* Pretend immediate EOF */
rval.code = RC_WMORE;
rval.consumed = 0;
while((rd = fread(fbuf, 1, fbuf_size, fp)) || !feof(fp)) {
asn_dec_rval_t rval;
int using_local_buf;
char *i_bptr;
size_t i_size;
/*
* Copy the data over, or use the original buffer.
......@@ -275,26 +314,27 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f
memcpy(bufend, fbuf, rd);
buf_len += rd;
rval = ber_decode(opt_codec_ctx, pduType,
(void **)&structure, bufptr, buf_len);
DEBUG("ber_decode(%ld) consumed %ld, code %d",
(long)buf_len, (long)rval.consumed, rval.code);
/*
* Adjust position inside the source buffer.
*/
assert(rval.consumed <= buf_len);
buf_offset += rval.consumed;
buf_len -= rval.consumed;
i_bptr = bufptr;
i_size = buf_len;
} else {
using_local_buf = 1;
i_bptr = fbuf;
i_size = rd;
}
/* Feed the chunk of data into a decoder routine */
switch(iform) {
case INP_BER:
rval = ber_decode(opt_codec_ctx, pduType,
(void **)&structure, fbuf, rd);
DEBUG("ber_decode(%ld) consumed %ld, code %d",
(long)rd, (long)rval.consumed, rval.code);
(void **)&structure, i_bptr, i_size);
break;
case INP_XER:
rval = xer_decode(opt_codec_ctx, pduType,
(void **)&structure, i_bptr, i_size);
break;
}
DEBUG("decode(%ld) consumed %ld, code %d",
(long)buf_len, (long)rval.consumed, rval.code);
if(buf_len == 0) {
/*
* Switch the remainder into the intermediate buffer.
*/
......@@ -310,10 +350,16 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f
switch(rval.code) {
case RC_OK:
DEBUG("RC_OK, finishing up");
fclose(fp);
if(fp != stdin) fclose(fp);
return structure;
case RC_WMORE:
DEBUG("RC_WMORE, continuing...");
/*
* Adjust position inside the source buffer.
*/
buf_offset += rval.consumed;
buf_len -= rval.consumed;
rval.consumed = 0;
continue;
case RC_FAIL:
break;
......@@ -327,8 +373,11 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f
pduType->free_struct(pduType, structure, 0);
fprintf(stderr, "%s: "
"Decode failed past %lld byte\n",
fname, (long long)(buf_shifted + buf_offset));
"Decode failed past byte %ld: %s\n",
fname, (long)(buf_shifted + buf_offset + rval.consumed),
(rval.code == RC_WMORE)
? "Unexpected end of input"
: "Input processing error");
return 0;
}
......
......@@ -20,7 +20,7 @@ extern "C" {
#endif
/* Environment version might be used to avoid running with the old library */
#define ASN1C_ENVIRONMENT_VERSION 919 /* Compile-time version */
#define ASN1C_ENVIRONMENT_VERSION 920 /* Compile-time version */
int get_asn1c_environment_version(void); /* Run-time version */
#define CALLOC(nmemb, size) calloc(nmemb, size)
......
......@@ -572,7 +572,8 @@ CHOICE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
* Restore parsing context.
*/
ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
if(ctx->phase == 0 && !*xml_tag)
ctx->phase = 1; /* Skip the outer tag checking phase */
/*
* Phases of XER/XML processing:
......@@ -625,6 +626,12 @@ CHOICE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
/* Fall through */
}
/* No need to wait for closing tag; special mode. */
if(ctx->phase == 3 && !*xml_tag) {
ctx->phase = 5; /* Phase out */
RETURN(RC_OK);
}
/*
* Get the next part of the XML stream.
*/
......@@ -644,6 +651,12 @@ CHOICE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
}
tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
ASN_DEBUG("XER/CHOICE checked [%c%c%c%c] vs [%s], tcv=%d",
ch_size>0?((uint8_t *)buf_ptr)[0]:'?',
ch_size>1?((uint8_t *)buf_ptr)[1]:'?',
ch_size>2?((uint8_t *)buf_ptr)[2]:'?',
ch_size>3?((uint8_t *)buf_ptr)[3]:'?',
xml_tag, tcv);
/* Skip the extensions section */
if(ctx->phase == 4) {
......@@ -739,7 +752,8 @@ CHOICE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
break;
}
ASN_DEBUG("Unexpected XML tag in CHOICE");
ASN_DEBUG("Unexpected XML tag in CHOICE (ph=%d, tag=%s)",
ctx->phase, xml_tag);
break;
}
......
......@@ -51,6 +51,8 @@ SEQUENCE_OF_encode_der(asn_TYPE_descriptor_t *td, void *ptr,
computed_size += encoding_size;
if(!cb) {
erval.encoded = computed_size;
erval.structure_ptr = 0;
erval.failed_type = 0;
return erval;
}
......@@ -79,6 +81,8 @@ SEQUENCE_OF_encode_der(asn_TYPE_descriptor_t *td, void *ptr,
erval.structure_ptr = ptr;
} else {
erval.encoded = computed_size;
erval.structure_ptr = 0;
erval.failed_type = 0;
}
return erval;
......@@ -116,8 +120,7 @@ SEQUENCE_OF_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
ilevel + 1, flags, cb, app_key);
if(tmper.encoded == -1) return tmper;
if(tmper.encoded == 0 && specs->as_XMLValueList) {
const char *name = (*elm->name)
? elm->name : elm->type->xml_tag;
const char *name = elm->type->xml_tag;
size_t len = strlen(name);
if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel + 1);
_ASN_CALLBACK3("<", 1, name, len, "/>", 2);
......
......@@ -471,8 +471,7 @@ SET_OF_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
*/
asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics;
asn_TYPE_member_t *element = td->elements;
const char *elm_tag = ((*element->name)
? element->name : element->type->xml_tag);
const char *elm_tag;
const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
/*
......@@ -492,6 +491,14 @@ SET_OF_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
if(st == 0) RETURN(RC_FAIL);
}
/* Which tag is expected for the downstream */
if(specs->as_XMLValueList) {
elm_tag = (specs->as_XMLValueList == 1) ? 0 : "";
} else {
elm_tag = (*element->name)
? element->name : element->type->xml_tag;
}
/*
* Restore parsing context.
*/
......@@ -515,6 +522,7 @@ SET_OF_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
asn_dec_rval_t tmprval;
/* Invoke the inner type decoder, m.b. multiple times */
ASN_DEBUG("XER/SET OF element [%s]", elm_tag);
tmprval = element->type->xer_decoder(opt_codec_ctx,
element->type, &ctx->ptr, elm_tag,
buf_ptr, size);
......@@ -553,7 +561,8 @@ SET_OF_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
}
tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
ASN_DEBUG("XER/SET OF: tcv = %d, ph=%d", tcv, ctx->phase);
ASN_DEBUG("XER/SET OF: tcv = %d, ph=%d t=%s",
tcv, ctx->phase, xml_tag);
switch(tcv) {
case XCT_CLOSING:
if(ctx->phase == 0) break;
......@@ -682,18 +691,18 @@ SET_OF_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
_ASN_CALLBACK3("<", 1, mname, mlen, ">", 1);
}
if(!xcan && specs->as_XMLValueList)
if(!xcan && specs->as_XMLValueList == 1)
_i_ASN_TEXT_INDENT(1, ilevel + 1);
tmper = elm->type->xer_encoder(elm->type, memb_ptr,
ilevel + 1, flags, cb, app_key);
ilevel + (specs->as_XMLValueList != 2),
flags, cb, app_key);
if(tmper.encoded == -1) {
td = tmper.failed_type;
sptr = tmper.structure_ptr;
goto cb_failed;
}
if(tmper.encoded == 0 && specs->as_XMLValueList) {
const char *name = (*elm->name)
? elm->name : elm->type->xml_tag;
const char *name = elm->type->xml_tag;
size_t len = strlen(name);
_ASN_CALLBACK3("<", 1, name, len, "/>", 2);
}
......
......@@ -46,8 +46,8 @@ main() {
check("</", "", XCT_BROKEN);
check("/>", "", XCT_BROKEN);
check("<>", "", XCT_OPENING);
check("</>", "", XCT_CLOSING);
check("<>", "", XCT_UNKNOWN_OP);
check("</>", "", XCT_UNKNOWN_CL);
check("", "a", XCT_BROKEN);
check("<>", "a", XCT_UNKNOWN_OP);
......
......@@ -124,6 +124,10 @@ xer_check_tag(const void *buf_ptr, int size, const char *need_tag) {
}
}
/* Sometimes we don't care about the tag */
if(!need_tag || !*need_tag)
return (xer_check_tag_e)(XCT__UNK__MASK | ct);
/*