diff --git a/libasn1fix/asn1fix.c b/libasn1fix/asn1fix.c index 46a32727..4a279325 100644 --- a/libasn1fix/asn1fix.c +++ b/libasn1fix/asn1fix.c @@ -158,18 +158,24 @@ asn1f_fix_module(arg_t *arg) { ret = asn1f_recurse_expr(arg, asn1f_fix_simple); RET2RVAL(ret, rvalue); - /* - * 2.[234] Process SEQUENCE/SET/CHOICE types. - */ - ret = asn1f_recurse_expr(arg, asn1f_fix_constructed); - RET2RVAL(ret, rvalue); - /* * 2.5.4 */ ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_types); RET2RVAL(ret, rvalue); + /* + * Fix tagging of top-level types. + */ + ret = asn1f_fix_constr_tag(arg, 1); + RET2RVAL(ret, rvalue); + + /* + * 2.[234] Process SEQUENCE/SET/CHOICE types. + */ + ret = asn1f_recurse_expr(arg, asn1f_fix_constructed); + RET2RVAL(ret, rvalue); + /* * 2.5.5 */ @@ -239,6 +245,10 @@ asn1f_fix_module(arg_t *arg) { TQ_FOR(expr, &(arg->mod->members), next) { arg->expr = expr; + if(arg->expr->meta_type == AMT_PARAMTYPE) + /* Do not process the parametrized types here */ + continue; + ret = asn1f_recurse_expr(arg, asn1f_check_constraints); RET2RVAL(ret, rvalue); @@ -286,7 +296,7 @@ asn1f_fix_constructed(arg_t *arg) { RET2RVAL(ret, rvalue); /* Fix tagging */ - ret = asn1f_fix_constr_tag(arg); + ret = asn1f_fix_constr_tag(arg, 0); RET2RVAL(ret, rvalue); /* Import COMPONENTS OF stuff */ @@ -308,6 +318,8 @@ asn1f_resolve_constraints(arg_t *arg) { etype = top_parent->expr_type; else etype = A1TC_INVALID; + DEBUG("asn1f_resolve_constraints(%s)", arg->expr->Identifier); + ret = asn1constraint_resolve(arg, arg->expr->module, arg->expr->constraints, etype, 0); RET2RVAL(ret, rvalue); @@ -326,6 +338,10 @@ asn1f_check_constraints(arg_t *arg) { int rvalue = 0; int ret; + DEBUG("asn1f_check_constraints(%s{%d/%d})", + arg->expr->Identifier, + arg->expr->meta_type, arg->expr->expr_type); + top_parent = asn1f_find_terminal_type(arg, arg->expr); if(!top_parent) return 0; @@ -339,8 +355,13 @@ asn1f_check_constraints(arg_t *arg) { etype, arg->expr->combined_constraints, test_types[i], 0, 0, 0); - if(!range && errno == EPERM) + if(!range && errno == EPERM) { + FATAL("This error happened for %s (%d) at line %d", + arg->expr->Identifier, + arg->expr->meta_type, + arg->expr->_lineno); return -1; + } asn1constraint_range_free(range); } diff --git a/libasn1fix/asn1fix_constr.c b/libasn1fix/asn1fix_constr.c index fab78d37..8c9dd383 100644 --- a/libasn1fix/asn1fix_constr.c +++ b/libasn1fix/asn1fix_constr.c @@ -1,7 +1,10 @@ #include "asn1fix_internal.h" +#define AFT_IMAGINARY_ANY 1 /* _fetch_tag() flag */ + static int _asn1f_check_if_tag_must_be_explicit(arg_t *arg, asn1p_expr_t *v); static int _asn1f_compare_tags(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b); +static int _asn1f_fix_type_tag(arg_t *arg, asn1p_expr_t *expr); int asn1f_pull_components_of(arg_t *arg) { @@ -77,6 +80,9 @@ asn1f_pull_components_of(arg_t *arg) { return r_value; } +/* + * Fix extensibility parts inside constructed types (SEQUENCE, SET, CHOICE). + */ int asn1f_fix_constr_ext(arg_t *arg) { asn1p_expr_t *expr = arg->expr; @@ -103,6 +109,10 @@ asn1f_fix_constr_ext(arg_t *arg) { TQ_INIT(&ext_list); cur_list = (void *)&root_list; + /* + * Split the set of fields into two lists, the root list + * and the extensions list. + */ while((v = TQ_REMOVE(&(expr->members), next))) { if(v->expr_type == A1TC_EXTENSIBLE) { ext_count++; @@ -161,16 +171,30 @@ asn1f_fix_constr_ext(arg_t *arg) { int -asn1f_fix_constr_tag(arg_t *arg) { +asn1f_fix_constr_tag(arg_t *arg, int fix_top_level) { asn1p_expr_t *expr = arg->expr; asn1p_expr_t *v; - int fl_impl_tags = 0; - int fl_auto_tags = 0; int root_tagged = 0; /* The root component is manually tagged */ int ext_tagged = 0; /* The extensions are manually tagged */ int component_number = 0; int r_value = 0; + DEBUG("%s(%s) for line %d", __func__, + expr->Identifier, expr->_lineno); + + /* + * Fix the top-level type itself first. + */ + if(fix_top_level) { + if(expr->tag.tag_class == TC_NOCLASS) + return r_value; + + if(_asn1f_fix_type_tag(arg, expr)) + r_value = -1; + + return r_value; + } + switch(expr->expr_type) { case ASN_CONSTR_SEQUENCE: case ASN_CONSTR_SET: @@ -180,14 +204,7 @@ asn1f_fix_constr_tag(arg_t *arg) { return 0; } - fl_impl_tags = (arg->mod->module_flags & MSF_IMPLICIT_TAGS); - fl_auto_tags = (arg->mod->module_flags & MSF_AUTOMATIC_TAGS); - - DEBUG("%s(%s) {%d, %d} for line %d", __func__, - expr->Identifier, fl_impl_tags, fl_auto_tags, expr->_lineno); - TQ_FOR(v, &(expr->members), next) { - int must_explicit = 0; if(v->expr_type == A1TC_EXTENSIBLE) { component_number++; @@ -196,43 +213,18 @@ asn1f_fix_constr_tag(arg_t *arg) { if(v->tag.tag_class == TC_NOCLASS) { continue; - } else { - switch(component_number) { - case 0: case 2: - root_tagged = 1; break; - default: - ext_tagged = 1; break; - } } - must_explicit = _asn1f_check_if_tag_must_be_explicit(arg, v); - - if(fl_impl_tags) { - if(v->tag.tag_mode != TM_EXPLICIT) { - if(must_explicit) - v->tag.tag_mode = TM_EXPLICIT; - else - v->tag.tag_mode = TM_IMPLICIT; - } - } else { - if(v->tag.tag_mode == TM_DEFAULT) { - v->tag.tag_mode = TM_EXPLICIT; - } + switch(component_number) { + case 0: case 2: + root_tagged = 1; break; + default: + ext_tagged = 1; break; } - /* - * Perform a final sanity check. - */ - if(must_explicit) { - if(v->tag.tag_mode == TM_IMPLICIT) { - FATAL("%s tagged in IMPLICIT mode " - "but must be EXPLICIT at line %d", - v->Identifier, v->_lineno); - r_value = -1; - } else { - v->tag.tag_mode = TM_EXPLICIT; - } - } + if(_asn1f_fix_type_tag(arg, v)) + r_value = -1; + } if(ext_tagged && !root_tagged) { @@ -241,13 +233,51 @@ asn1f_fix_constr_tag(arg_t *arg) { "but root components are not", expr->Identifier, expr->_lineno); r_value = -1; - } else if(!root_tagged && !ext_tagged && fl_auto_tags) { + } else if(!root_tagged && !ext_tagged + && (arg->mod->module_flags & MSF_AUTOMATIC_TAGS)) { + /* Make a decision on automatic tagging */ expr->auto_tags_OK = 1; } return r_value; } +static int +_asn1f_fix_type_tag(arg_t *arg, asn1p_expr_t *expr) { + int must_explicit = _asn1f_check_if_tag_must_be_explicit(arg, expr); + int fl_impl_tags = (arg->mod->module_flags & MSF_IMPLICIT_TAGS); + int r_value = 0; + + if(fl_impl_tags) { + if(expr->tag.tag_mode != TM_EXPLICIT) { + if(must_explicit) + expr->tag.tag_mode = TM_EXPLICIT; + else + expr->tag.tag_mode = TM_IMPLICIT; + } + } else { + if(expr->tag.tag_mode == TM_DEFAULT) { + expr->tag.tag_mode = TM_EXPLICIT; + } + } + + /* + * Perform a final sanity check. + */ + if(must_explicit) { + if(expr->tag.tag_mode == TM_IMPLICIT) { + FATAL("%s tagged in IMPLICIT mode " + "but must be EXPLICIT at line %d", + expr->Identifier, expr->_lineno); + r_value = -1; + } else { + expr->tag.tag_mode = TM_EXPLICIT; + } + } + + return r_value; +} + int asn1f_fix_constr_autotag(arg_t *arg) { asn1p_expr_t *expr = arg->expr; @@ -333,11 +363,25 @@ asn1f_check_constr_tags_distinct(arg_t *arg) { static int _asn1f_check_if_tag_must_be_explicit(arg_t *arg, asn1p_expr_t *v) { + struct asn1p_type_tag_s tag; + struct asn1p_type_tag_s save_tag; asn1p_expr_t *reft; + int ret; + + /* + * Fetch the _next_ tag for this type. + */ + save_tag = v->tag; /* Save existing tag */ + memset(&v->tag, 0, sizeof(v->tag)); /* Remove it temporarily */ + ret = asn1f_fetch_tag(arg->asn, arg->mod, v, &tag, 0); + v->tag = save_tag; /* Restore the tag back */ + + if(ret == 0) return 0; /* If found tag, it's okay */ reft = asn1f_find_terminal_type(arg, v); if(reft) { switch(reft->expr_type) { + case ASN_TYPE_ANY: case ASN_CONSTR_CHOICE: return 1; default: @@ -357,8 +401,8 @@ _asn1f_compare_tags(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) { int ra, rb; int ret; - ra = asn1f_fetch_tag(arg->asn, arg->mod, a, &ta); - rb = asn1f_fetch_tag(arg->asn, arg->mod, b, &tb); + ra = asn1f_fetch_tag(arg->asn, arg->mod, a, &ta, AFT_IMAGINARY_ANY); + rb = asn1f_fetch_tag(arg->asn, arg->mod, b, &tb, AFT_IMAGINARY_ANY); /* * If both tags are explicitly or implicitly given, use them. @@ -367,8 +411,12 @@ _asn1f_compare_tags(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) { /* * Simple case: fetched both tags. */ - if(ta.tag_value == tb.tag_value - && ta.tag_class == tb.tag_class) { + + if((ta.tag_value == tb.tag_value + && ta.tag_class == tb.tag_class) + || ta.tag_value == -1 /* Spread IMAGINARY ANY tag... */ + || tb.tag_value == -1 /* ...it is an evil virus, fear it! */ + ) { char *p = (a->expr_type == A1TC_EXTENSIBLE) ?"potentially ":""; FATAL("Component \"%s\" at line %d %shas the same tag " diff --git a/libasn1fix/asn1fix_constr.h b/libasn1fix/asn1fix_constr.h index 59970adf..ffed1437 100644 --- a/libasn1fix/asn1fix_constr.h +++ b/libasn1fix/asn1fix_constr.h @@ -14,7 +14,7 @@ int asn1f_fix_constr_ext(arg_t *); /* * Fix tagging in constructed types. */ -int asn1f_fix_constr_tag(arg_t *); +int asn1f_fix_constr_tag(arg_t *, int fix_top_level); /* * Check distinctive tagging in constructed types. diff --git a/libasn1fix/asn1fix_constraint.c b/libasn1fix/asn1fix_constraint.c index 4a25faee..3f30009e 100644 --- a/libasn1fix/asn1fix_constraint.c +++ b/libasn1fix/asn1fix_constraint.c @@ -93,7 +93,7 @@ asn1constraint_pullup(arg_t *arg) { expr->combined_constraints = ct_parent; if(ct_expr->type == ACT_CA_SET) { - int i; + unsigned int i; for(i = 0; i < ct_expr->el_count; i++) { if(asn1p_constraint_insert( expr->combined_constraints, @@ -120,9 +120,9 @@ asn1constraint_pullup(arg_t *arg) { int asn1constraint_resolve(arg_t *arg, asn1p_module_t *mod, asn1p_constraint_t *ct, asn1p_expr_type_e etype, enum asn1p_constraint_type_e effective_type) { + unsigned int el; int rvalue = 0; int ret; - int el; if(!ct) return 0; @@ -208,7 +208,7 @@ asn1constraint_resolve(arg_t *arg, asn1p_module_t *mod, asn1p_constraint_t *ct, static void _remove_exceptions(arg_t *arg, asn1p_constraint_t *ct) { - int i; + unsigned int i; for(i = 0; i < ct->el_count; i++) { if(ct->elements[i]->type == ACT_EL_EXT) diff --git a/libasn1fix/asn1fix_crange.c b/libasn1fix/asn1fix_crange.c index 6ef8c8ac..53d46407 100644 --- a/libasn1fix/asn1fix_crange.c +++ b/libasn1fix/asn1fix_crange.c @@ -699,8 +699,8 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr asn1p_value_t *vmin; asn1p_value_t *vmax; int expectation_met; + unsigned int i; int ret; - int i; if(!exmet) { exmet = &expectation_met; diff --git a/libasn1fix/asn1fix_param.c b/libasn1fix/asn1fix_param.c index c399ae42..5ce6b933 100644 --- a/libasn1fix/asn1fix_param.c +++ b/libasn1fix/asn1fix_param.c @@ -2,7 +2,10 @@ static int asn1f_parametrize(arg_t *arg, asn1p_expr_t *ex, asn1p_expr_t *ptype); static int asn1f_param_process_recursive(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype, asn1p_expr_t *actargs); +static int asn1f_param_process_constraints(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype, asn1p_expr_t *actargs); + static asn1p_expr_t *_referenced_argument(asn1p_ref_t *ref, asn1p_expr_t *ptype, asn1p_expr_t *actargs); +static int _process_constraints(arg_t *arg, asn1p_constraint_t *ct, asn1p_expr_t *ptype, asn1p_expr_t *actargs); int asn1f_fix_parametrized_assignment(arg_t *arg) { @@ -79,6 +82,7 @@ asn1f_parametrize(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype) { * as a child of the expression, replacing all occurences of * symbols which are defined as parametrized type arguments * with the actual values. + * 3. Don't forget to parametrize the subtype constraints. */ nex = asn1p_expr_clone(ptype, 0); @@ -117,34 +121,40 @@ asn1f_param_process_recursive(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptyp TQ_FOR(child, &(expr->members), next) { asn1p_expr_t *ra; - asn1p_expr_t *ne; + asn1p_expr_t *ne; /* new expression (clone) */ + + if(asn1f_param_process_constraints(arg, child, ptype, actargs)) + return -1; ra = _referenced_argument(child->reference, ptype, actargs); - if(ra == NULL) continue; - - DEBUG("Substituting parameter for %s %s at line %d", - child->Identifier, - asn1f_printable_reference(child->reference), - child->_lineno - ); - - assert(child->meta_type == AMT_TYPEREF); - assert(child->expr_type == A1TC_REFERENCE); - - ne = asn1p_expr_clone(ra, 0); - if(ne == NULL) return -1; - assert(ne->Identifier == 0); - ne->Identifier = strdup(child->Identifier); - if(ne->Identifier == 0) { - asn1p_expr_free(ne); - return -1; + if(ra) { + DEBUG("Substituting parameter for %s %s at line %d", + child->Identifier, + asn1f_printable_reference(child->reference), + child->_lineno + ); + + assert(child->meta_type == AMT_TYPEREF); + assert(child->expr_type == A1TC_REFERENCE); + + ne = asn1p_expr_clone(ra, 0); + if(ne == NULL) return -1; + assert(ne->Identifier == 0); + ne->Identifier = strdup(child->Identifier); + if(ne->Identifier == 0) { + asn1p_expr_free(ne); + return -1; + } + SUBSTITUTE(child, ne); } - SUBSTITUTE(child, ne); } return 0; } +/* + * Check that the given ref looks like an argument of a parametrized type. + */ static asn1p_expr_t * _referenced_argument(asn1p_ref_t *ref, asn1p_expr_t *ptype, asn1p_expr_t *actargs) { asn1p_expr_t *aa; @@ -163,3 +173,84 @@ _referenced_argument(asn1p_ref_t *ref, asn1p_expr_t *ptype, asn1p_expr_t *actarg return NULL; } + +/* + * Search for parameters inside constraints. + */ +static int +asn1f_param_process_constraints(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype, asn1p_expr_t *actargs) { + asn1p_constraint_t *cts; + int ret; + + if(!expr->constraints) return 0; + + cts = asn1p_constraint_clone(expr->constraints); + assert(cts); + + ret = _process_constraints(arg, cts, ptype, actargs); + if(ret == 1) { + asn1p_constraint_free(expr->constraints); + expr->constraints = cts; + ret = 0; + } else { + asn1p_constraint_free(cts); + } + + return ret; +} + +static int +_process_constraints(arg_t *arg, asn1p_constraint_t *ct, asn1p_expr_t *ptype, asn1p_expr_t *actargs) { + asn1p_value_t *values[3]; + int rvalue = 0; + size_t i; + + values[0] = ct->value; + values[1] = ct->range_start; + values[2] = ct->range_stop; + + for(i = 0; i < sizeof(values)/sizeof(values[0]); i++) { + asn1p_value_t *v = values[i]; + asn1p_expr_t *ra; + asn1p_ref_t *ref; + char *str; + + if(!v || v->type != ATV_REFERENCED) continue; + + ref = v->value.reference; + ra = _referenced_argument(ref, ptype, actargs); + if(!ra) continue; + + DEBUG("_process_constraints(%s), ra=%s", + asn1f_printable_reference(ref), ra->Identifier); + + str = strdup(ra->Identifier); + if(!str) return -1; + + assert(ref->comp_count == 1); + ref = asn1p_ref_new(ref->_lineno); + if(!ref) { free(str); return -1; } + + if(asn1p_ref_add_component(ref, str, 0)) { + free(str); + return -1; + } + + asn1p_ref_free(v->value.reference); + v->value.reference = ref; + rvalue = 1; + } + + /* Process the rest of constraints recursively */ + for(i = 0; i < ct->el_count; i++) { + int ret = _process_constraints(arg, ct->elements[i], + ptype, actargs); + if(ret == -1) + rvalue = -1; + else if(ret == 1 && rvalue != -1) + rvalue = 1; + } + + return rvalue; +} + diff --git a/libasn1fix/asn1fix_tags.c b/libasn1fix/asn1fix_tags.c index de80fad5..22ba422c 100644 --- a/libasn1fix/asn1fix_tags.c +++ b/libasn1fix/asn1fix_tags.c @@ -1,7 +1,7 @@ #include "asn1fix_internal.h" int -asn1f_fetch_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag) { +asn1f_fetch_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag, int flags) { int ret; if(expr->tag.tag_class != TC_NOCLASS) { @@ -19,6 +19,11 @@ asn1f_fetch_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct as memset(tag, 0, sizeof(*tag)); tag->tag_class = TC_UNIVERSAL; tag->tag_value = expr_type2uclass_value[expr->expr_type]; + if(flags && expr->expr_type == ASN_TYPE_ANY) { + assert(tag->tag_value == 0); + tag->tag_value = -1; + return 0; + } return (tag->tag_value == 0) ? -1 : 0; } @@ -37,7 +42,8 @@ asn1f_fetch_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct as return -1; expr->_mark |= TM_RECURSION; - ret = asn1f_fetch_tag(asn, expr->module, expr, tag); + ret = asn1f_fetch_tag(asn, expr->module, expr, tag, + flags); expr->_mark &= ~TM_RECURSION; return ret; } diff --git a/libasn1fix/asn1fix_tags.h b/libasn1fix/asn1fix_tags.h index 9d3595b9..429e56d7 100644 --- a/libasn1fix/asn1fix_tags.h +++ b/libasn1fix/asn1fix_tags.h @@ -1,6 +1,6 @@ #ifndef _ASN1FIX_TAGS_H_ #define _ASN1FIX_TAGS_H_ -int asn1f_fetch_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag); +int asn1f_fetch_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag, int special_ANY_handling); #endif /* _ASN1FIX_TAGS_H_ */