diff --git a/libasn1fix/asn1fix_constraint_compat.c b/libasn1fix/asn1fix_constraint_compat.c index f2f47fd1be2d768f54215475f3c187bf98380014..effa0ad57947406d4a866ac50dcd4ec8f0e279ae 100644 --- a/libasn1fix/asn1fix_constraint_compat.c +++ b/libasn1fix/asn1fix_constraint_compat.c @@ -88,17 +88,21 @@ asn1constraint_compatible(asn1p_expr_type_e expr_type, } -#define DECL(foo, val1, val2) \ +#define DECL_RANGE(foo, val1, val2, pv) \ static asn1cnst_range_t range_ ## foo = { \ { ARE_VALUE, 0, val1 }, \ { ARE_VALUE, 0, val2 }, \ - 0, 0, 0, 0, 0, 0 } + 0, 0, 0, 0, 0, 0, pv } + +#define DECL(foo, val1, val2) DECL_RANGE(foo, val1, val2, 0) +#define DECL_notPV(foo, val1, val2) DECL_RANGE(foo, val1, val2, 1) asn1cnst_range_t * asn1constraint_default_alphabet(asn1p_expr_type_e expr_type) { + DECL_notPV(octstr, 0x00, 0xff); /* Not PER-visible */ + DECL_notPV(utf8, 0x00, 0x7fffffff); /* Not PER-visible */ + DECL(bmp, 0x00, 65533); /* 64K-2 cells */ DECL(uint7, 0x00, 0x7f); - DECL(uint8, 0x00, 0xff); - DECL(uint16, 0x00, 0xffff); DECL(uint31, 0x00, 0x7fffffff); DECL(Space, 0x20, 0x20); DECL(ApostropheAndParens, 0x27, 0x29); @@ -127,38 +131,43 @@ asn1constraint_default_alphabet(asn1p_expr_type_e expr_type) { &range_Plus, &range_MinusDot, &range_Digits, &range_Z }; static asn1cnst_range_t *range_GeneralizedTime_array[] = { &range_PlusCommaMinusDot, &range_Digits, &range_Z }; + + static asn1cnst_range_t range_notPERVisible = { + { ARE_MIN, 0, 0 }, + { ARE_MAX, 0, 0 }, + 0, 0, 0, 0, 0, 0, 1 }; static asn1cnst_range_t range_NumericString = { { ARE_VALUE, 0, 0x20 }, { ARE_VALUE, 0, 0x39 }, range_NumericString_array, sizeof(range_NumericString_array) /sizeof(range_NumericString_array[0]), - 0, 0, 0, 0 }; + 0, 0, 0, 0, 0 }; static asn1cnst_range_t range_PrintableString = { { ARE_VALUE, 0, 0x20 }, { ARE_VALUE, 0, 0x7a }, range_PrintableString_array, sizeof(range_PrintableString_array) /sizeof(range_PrintableString_array[0]), - 0, 0, 0, 0 }; + 0, 0, 0, 0, 0 }; static asn1cnst_range_t range_VisibleString = { { ARE_VALUE, 0, 0x20 }, { ARE_VALUE, 0, 0x7e }, - 0, 0, 0, 0, 0, 0 }; + 0, 0, 0, 0, 0, 0, 0 }; static asn1cnst_range_t range_UTCTime = { { ARE_VALUE, 0, 0x2b }, { ARE_VALUE, 0, 0x5a }, range_UTCTime_array, sizeof(range_UTCTime_array) /sizeof(range_UTCTime_array[0]), - 0, 0, 0, 0 }; + 0, 0, 0, 0, 1 }; static asn1cnst_range_t range_GeneralizedTime = { { ARE_VALUE, 0, 0x2b }, { ARE_VALUE, 0, 0x5a }, range_GeneralizedTime_array, sizeof(range_GeneralizedTime_array) /sizeof(range_GeneralizedTime_array[0]), - 0, 0, 0, 0 }; + 0, 0, 0, 0, 1 }; switch(expr_type) { case ASN_STRING_NumericString: @@ -169,19 +178,42 @@ asn1constraint_default_alphabet(asn1p_expr_type_e expr_type) { return &range_VisibleString; case ASN_STRING_IA5String: return &range_uint7; - case ASN_BASIC_OCTET_STRING: - return &range_uint8; case ASN_STRING_BMPString: - return &range_uint16; - case ASN_STRING_UniversalString: + return &range_bmp; case ASN_STRING_UTF8String: + /* + * X.691, #9.3.6 + * Not a known-multipler character string type. + */ + assert(range_utf8.not_PER_visible); + return &range_utf8; + case ASN_STRING_UniversalString: return &range_uint31; case ASN_BASIC_UTCTime: + /* Permitted alphabet constraint is not applicable */ + assert(range_UTCTime.not_PER_visible); return &range_UTCTime; case ASN_BASIC_GeneralizedTime: + /* Permitted alphabet constraint is not applicable */ + assert(range_GeneralizedTime.not_PER_visible); return &range_GeneralizedTime; + case ASN_BASIC_OCTET_STRING: + /* + * Permitted alphabet constraint is not applicable + * to this type. However, we support it, albeit not + * in a strict PER mode. + */ + assert(range_octstr.not_PER_visible); + return &range_octstr; default: - break; + if(!(expr_type & ASN_STRING_MASK)) + break; + assert(expr_type & ASN_STRING_NKM_MASK); + /* + * X.691, 9.3.6 + * Not a known-multiplier character string. + */ + return &range_notPERVisible; } return NULL; diff --git a/libasn1fix/asn1fix_crange.c b/libasn1fix/asn1fix_crange.c index 3032799b2963a2ddbff7113911a1e31feb88347c..6ef8c8ac2e014d81ad635f1908a12a45307050f5 100644 --- a/libasn1fix/asn1fix_crange.c +++ b/libasn1fix/asn1fix_crange.c @@ -167,11 +167,20 @@ _range_print(const asn1cnst_range_t *range) { if(_edge_compare(&range->left, &range->right)) { printf("(%s.", _edge_value(&range->left)); - printf(".%s)", _edge_value(&range->right)); + printf(".%s", _edge_value(&range->right)); } else { - printf("(%s)", _edge_value(&range->left)); + printf("(%s", _edge_value(&range->left)); } + if(range->extensible) { + printf(",...)"); + } else { + printf(")"); + } + + if(range->incompatible) printf("/I"); + if(range->not_PER_visible) printf("/!V"); + if(range->el_count) { int i; printf("-=>"); @@ -232,6 +241,9 @@ static int _range_merge_in(asn1cnst_range_t *into, asn1cnst_range_t *cr) { int prev_count = into->el_count; int i; + into->not_PER_visible |= cr->not_PER_visible; + into->extensible |= cr->extensible; + /* * Add the element OR all its children "into". */ @@ -481,8 +493,15 @@ _range_intersection(asn1cnst_range_t *range, const asn1cnst_range_t *with, int s int ret; int i, j; - if(with->empty_constraint || range->empty_constraint) { - range->empty_constraint = 1; /* Propagate error */ + assert(!range->incompatible); + + /* Propagate errors */ + range->extensible |= with->extensible; + range->not_PER_visible |= with->not_PER_visible; + range->empty_constraint |= with->empty_constraint; + + if(range->empty_constraint) { + /* No use in intersecting empty constraints */ return 0; } @@ -609,7 +628,7 @@ _range_union(asn1cnst_range_t *range) { * Still, range may be joined: (1..4)(5..10). * This logic is valid only for whole numbers * (i.e., not REAL type, but REAL constraints - * are not PER-visible (X.691, 9.3.12). + * are not PER-visible (X.691, #9.3.12). */ if(ra->right.type == ARE_VALUE && rb->left.type == ARE_VALUE @@ -674,7 +693,7 @@ _range_canonicalize(asn1cnst_range_t *range) { } asn1cnst_range_t * -asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constraint_t *ct, enum asn1p_constraint_type_e type, const asn1cnst_range_t *minmax, int *exmet) { +asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constraint_t *ct, enum asn1p_constraint_type_e type, const asn1cnst_range_t *minmax, int *exmet, int strict_PV) { asn1cnst_range_t *range; asn1cnst_range_t *tmp; asn1p_value_t *vmin; @@ -689,7 +708,8 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr } /* - * Check if the requested constraint is compatible with expression type. + * Check if the requested constraint is theoretically compatible + * with the given expression type. */ if(asn1constraint_compatible(expr_type, type) != 1) { errno = EINVAL; @@ -730,7 +750,15 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr range = _range_new(); } - if(!ct || range->not_PER_visible) + /* + * X.691, #9.3.6 + * Constraints on restricter character string types + * which are not known-multiplier are not PER-visible. + */ + if((expr_type & ASN_STRING_NKM_MASK)) + range->not_PER_visible = 1; + + if(!ct || (strict_PV && range->not_PER_visible)) return range; switch(ct->type) { @@ -746,9 +774,11 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr break; case ACT_EL_EXT: if(!*exmet) { - range->not_PER_visible = 1; + range->incompatible = 1; } else { - range->extensible = 1; + _range_free(range); + errno = ERANGE; + range = 0; } return range; case ACT_CT_SIZE: @@ -756,12 +786,24 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr if(type == ct->type) { *exmet = 1; } else { - range->not_PER_visible = 1; + range->incompatible = 1; return range; } assert(ct->el_count == 1); - return asn1constraint_compute_PER_range(expr_type, - ct->elements[0], type, minmax, exmet); + tmp = asn1constraint_compute_PER_range(expr_type, + ct->elements[0], type, minmax, exmet, strict_PV); + if(tmp) { + _range_free(range); + } else { + if(errno == ERANGE) { + range->empty_constraint = 1; + range->extensible = 1; + tmp = range; + } else { + _range_free(range); + } + } + return tmp; case ACT_CA_SET: /* (10..20)(15..17) */ case ACT_CA_INT: /* SIZE(1..2) ^ FROM("ABCD") */ @@ -769,13 +811,29 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr for(i = 0; i < ct->el_count; i++) { tmp = asn1constraint_compute_PER_range(expr_type, ct->elements[i], type, - ct->type==ACT_CA_SET?range:minmax, exmet); + ct->type==ACT_CA_SET?range:minmax, exmet, + strict_PV); if(!tmp) { - _range_free(range); - return NULL; + if(errno == ERANGE) { + continue; + } else { + _range_free(range); + return NULL; + } } - if(tmp->not_PER_visible) { + if(tmp->incompatible) { + /* + * Ignore constraints + * incompatible with arguments: + * SIZE(1..2) ^ FROM("ABCD") + * either SIZE or FROM will be ignored. + */ + _range_free(tmp); + continue; + } + + if(strict_PV && tmp->not_PER_visible) { if(ct->type == ACT_CA_SET) { /* * X.691, #9.3.18: @@ -791,17 +849,6 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr continue; } - range->extensible |= tmp->extensible; - - if(tmp->extensible && type == ACT_CT_FROM) { - /* - * X.691, #9.3.10: - * Extensible permitted alphabet constraints - * are not PER-visible. - */ - range->not_PER_visible = 1; - } - ret = _range_intersection(range, tmp, ct->type == ACT_CA_SET); _range_free(tmp); @@ -817,40 +864,100 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr case ACT_CA_CSV: /* SIZE(1..2, 3..4) */ case ACT_CA_UNI: /* SIZE(1..2) | FROM("ABCD") */ - /* Merge everything. Canonicalizator will do union magic */ + /* + * Grab the first valid constraint. + */ + tmp = 0; for(i = 0; i < ct->el_count; i++) { tmp = asn1constraint_compute_PER_range(expr_type, - ct->elements[i], type, minmax, exmet); + ct->elements[i], type, minmax, exmet, + strict_PV); if(!tmp) { - _range_free(range); - return NULL; + if(errno == ERANGE) { + range->extensible = 1; + continue; + } else { + _range_free(range); + return NULL; + } + } + if(tmp->incompatible) { + _range_free(tmp); + tmp = 0; + } + break; + } + if(tmp) { + tmp->extensible |= range->extensible; + tmp->empty_constraint |= range->empty_constraint; + _range_free(range); + range = tmp; + } else { + range->incompatible = 1; + return range; + } + + /* + * Merge with the rest of them. + * Canonicalizator will do the union magic. + */ + for(; i < ct->el_count; i++) { + tmp = asn1constraint_compute_PER_range(expr_type, + ct->elements[i], type, minmax, exmet, + strict_PV); + if(!tmp) { + if(errno == ERANGE) { + range->extensible = 1; + continue; + } else { + _range_free(range); + return NULL; + } + } + + if(tmp->incompatible) { + _range_free(tmp); + _range_canonicalize(range); + range->incompatible = 1; + return range; } if(tmp->empty_constraint) { - /* Ignore empty constraints */ + /* + * Ignore empty constraints in OR logic. + */ + range->extensible |= tmp->extensible; _range_free(tmp); continue; } - range->not_PER_visible |= tmp->not_PER_visible; - range->extensible |= tmp->extensible; - _range_merge_in(range, tmp); } _range_canonicalize(range); - if(range->not_PER_visible) { + if(range->extensible && type == ACT_CT_FROM) { + /* + * X.691, #9.3.10: + * Extensible permitted alphabet constraints + * are not PER-visible. + */ + range->not_PER_visible = 1; + } + + if(strict_PV && range->not_PER_visible) { /* * X.691, #9.3.19: * If not PER-visible constraint is part of UNION, - * the resulting constraint is not PER-visible. + * the whole resulting constraint is not PER-visible. */ _range_free(range); if(minmax) range = _range_clone(minmax); else range = _range_new(); + range->not_PER_visible = 1; + range->incompatible = 1; } return range; @@ -862,10 +969,10 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr assert(ct->el_count >= 1); _range_free(range); range = asn1constraint_compute_PER_range(expr_type, - ct->elements[0], type, minmax, exmet); + ct->elements[0], type, minmax, exmet, strict_PV); return range; default: - range->not_PER_visible = 1; + range->incompatible = 1; return range; } @@ -874,7 +981,7 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr /* * Expectation is not met. Return the default range. */ - range->not_PER_visible = 1; + range->incompatible = 1; return range; } diff --git a/libasn1fix/asn1fix_crange.h b/libasn1fix/asn1fix_crange.h index 9873e3b20cf103593797b98a84ae94c505bb92a1..9d4763acefede112c753c8cb4bdd457242de00bb 100644 --- a/libasn1fix/asn1fix_crange.h +++ b/libasn1fix/asn1fix_crange.h @@ -21,13 +21,14 @@ typedef struct asn1cnst_range_s { int el_size; int empty_constraint; /* If yes, too bad. */ - int extensible; /* Extension marker (...) present. */ + int extensible; /* Extension marker (...) is in effect. */ - int not_PER_visible; /* Contains non PER-visible components */ + int incompatible; /* Constraint incompatible with argument */ + int not_PER_visible; /* Contains not PER-visible components */ } asn1cnst_range_t; /* - * Compute the PER-visible constraint range. + * Compute the constraint range with variable PER visibility restrictions. * * (expr_type) must have the type of the top-level parent ASN.1 type. * (required_type) must be one of ACT_EL_RANGE, ACT_CT_SIZE or ACT_CT_FROM. @@ -41,7 +42,8 @@ asn1cnst_range_t *asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constraint_t *ct, enum asn1p_constraint_type_e required_type, const asn1cnst_range_t *minmax, - int *expectation_met); + int *expectation_met, + int strict_PER_visibility); void asn1constraint_range_free(asn1cnst_range_t *); /*