Commit b74ac57b authored by Lev Walkin's avatar Lev Walkin

introducing less strict semantics

parent b9fa780e
...@@ -88,17 +88,21 @@ asn1constraint_compatible(asn1p_expr_type_e expr_type, ...@@ -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 = { \ static asn1cnst_range_t range_ ## foo = { \
{ ARE_VALUE, 0, val1 }, \ { ARE_VALUE, 0, val1 }, \
{ ARE_VALUE, 0, val2 }, \ { 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 * asn1cnst_range_t *
asn1constraint_default_alphabet(asn1p_expr_type_e expr_type) { 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(uint7, 0x00, 0x7f);
DECL(uint8, 0x00, 0xff);
DECL(uint16, 0x00, 0xffff);
DECL(uint31, 0x00, 0x7fffffff); DECL(uint31, 0x00, 0x7fffffff);
DECL(Space, 0x20, 0x20); DECL(Space, 0x20, 0x20);
DECL(ApostropheAndParens, 0x27, 0x29); DECL(ApostropheAndParens, 0x27, 0x29);
...@@ -127,38 +131,43 @@ asn1constraint_default_alphabet(asn1p_expr_type_e expr_type) { ...@@ -127,38 +131,43 @@ asn1constraint_default_alphabet(asn1p_expr_type_e expr_type) {
&range_Plus, &range_MinusDot, &range_Digits, &range_Z }; &range_Plus, &range_MinusDot, &range_Digits, &range_Z };
static asn1cnst_range_t *range_GeneralizedTime_array[] = { static asn1cnst_range_t *range_GeneralizedTime_array[] = {
&range_PlusCommaMinusDot, &range_Digits, &range_Z }; &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 = { static asn1cnst_range_t range_NumericString = {
{ ARE_VALUE, 0, 0x20 }, { ARE_VALUE, 0, 0x20 },
{ ARE_VALUE, 0, 0x39 }, { ARE_VALUE, 0, 0x39 },
range_NumericString_array, range_NumericString_array,
sizeof(range_NumericString_array) sizeof(range_NumericString_array)
/sizeof(range_NumericString_array[0]), /sizeof(range_NumericString_array[0]),
0, 0, 0, 0 }; 0, 0, 0, 0, 0 };
static asn1cnst_range_t range_PrintableString = { static asn1cnst_range_t range_PrintableString = {
{ ARE_VALUE, 0, 0x20 }, { ARE_VALUE, 0, 0x20 },
{ ARE_VALUE, 0, 0x7a }, { ARE_VALUE, 0, 0x7a },
range_PrintableString_array, range_PrintableString_array,
sizeof(range_PrintableString_array) sizeof(range_PrintableString_array)
/sizeof(range_PrintableString_array[0]), /sizeof(range_PrintableString_array[0]),
0, 0, 0, 0 }; 0, 0, 0, 0, 0 };
static asn1cnst_range_t range_VisibleString = { static asn1cnst_range_t range_VisibleString = {
{ ARE_VALUE, 0, 0x20 }, { ARE_VALUE, 0, 0x20 },
{ ARE_VALUE, 0, 0x7e }, { ARE_VALUE, 0, 0x7e },
0, 0, 0, 0, 0, 0 }; 0, 0, 0, 0, 0, 0, 0 };
static asn1cnst_range_t range_UTCTime = { static asn1cnst_range_t range_UTCTime = {
{ ARE_VALUE, 0, 0x2b }, { ARE_VALUE, 0, 0x2b },
{ ARE_VALUE, 0, 0x5a }, { ARE_VALUE, 0, 0x5a },
range_UTCTime_array, range_UTCTime_array,
sizeof(range_UTCTime_array) sizeof(range_UTCTime_array)
/sizeof(range_UTCTime_array[0]), /sizeof(range_UTCTime_array[0]),
0, 0, 0, 0 }; 0, 0, 0, 0, 1 };
static asn1cnst_range_t range_GeneralizedTime = { static asn1cnst_range_t range_GeneralizedTime = {
{ ARE_VALUE, 0, 0x2b }, { ARE_VALUE, 0, 0x2b },
{ ARE_VALUE, 0, 0x5a }, { ARE_VALUE, 0, 0x5a },
range_GeneralizedTime_array, range_GeneralizedTime_array,
sizeof(range_GeneralizedTime_array) sizeof(range_GeneralizedTime_array)
/sizeof(range_GeneralizedTime_array[0]), /sizeof(range_GeneralizedTime_array[0]),
0, 0, 0, 0 }; 0, 0, 0, 0, 1 };
switch(expr_type) { switch(expr_type) {
case ASN_STRING_NumericString: case ASN_STRING_NumericString:
...@@ -169,19 +178,42 @@ asn1constraint_default_alphabet(asn1p_expr_type_e expr_type) { ...@@ -169,19 +178,42 @@ asn1constraint_default_alphabet(asn1p_expr_type_e expr_type) {
return &range_VisibleString; return &range_VisibleString;
case ASN_STRING_IA5String: case ASN_STRING_IA5String:
return &range_uint7; return &range_uint7;
case ASN_BASIC_OCTET_STRING:
return &range_uint8;
case ASN_STRING_BMPString: case ASN_STRING_BMPString:
return &range_uint16; return &range_bmp;
case ASN_STRING_UniversalString:
case ASN_STRING_UTF8String: 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; return &range_uint31;
case ASN_BASIC_UTCTime: case ASN_BASIC_UTCTime:
/* Permitted alphabet constraint is not applicable */
assert(range_UTCTime.not_PER_visible);
return &range_UTCTime; return &range_UTCTime;
case ASN_BASIC_GeneralizedTime: case ASN_BASIC_GeneralizedTime:
/* Permitted alphabet constraint is not applicable */
assert(range_GeneralizedTime.not_PER_visible);
return &range_GeneralizedTime; 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: 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; return NULL;
......
...@@ -167,11 +167,20 @@ _range_print(const asn1cnst_range_t *range) { ...@@ -167,11 +167,20 @@ _range_print(const asn1cnst_range_t *range) {
if(_edge_compare(&range->left, &range->right)) { if(_edge_compare(&range->left, &range->right)) {
printf("(%s.", _edge_value(&range->left)); printf("(%s.", _edge_value(&range->left));
printf(".%s)", _edge_value(&range->right)); printf(".%s", _edge_value(&range->right));
} else { } 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) { if(range->el_count) {
int i; int i;
printf("-=>"); printf("-=>");
...@@ -232,6 +241,9 @@ static int _range_merge_in(asn1cnst_range_t *into, asn1cnst_range_t *cr) { ...@@ -232,6 +241,9 @@ static int _range_merge_in(asn1cnst_range_t *into, asn1cnst_range_t *cr) {
int prev_count = into->el_count; int prev_count = into->el_count;
int i; int i;
into->not_PER_visible |= cr->not_PER_visible;
into->extensible |= cr->extensible;
/* /*
* Add the element OR all its children "into". * 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 ...@@ -481,8 +493,15 @@ _range_intersection(asn1cnst_range_t *range, const asn1cnst_range_t *with, int s
int ret; int ret;
int i, j; int i, j;
if(with->empty_constraint || range->empty_constraint) { assert(!range->incompatible);
range->empty_constraint = 1; /* Propagate error */
/* 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; return 0;
} }
...@@ -609,7 +628,7 @@ _range_union(asn1cnst_range_t *range) { ...@@ -609,7 +628,7 @@ _range_union(asn1cnst_range_t *range) {
* Still, range may be joined: (1..4)(5..10). * Still, range may be joined: (1..4)(5..10).
* This logic is valid only for whole numbers * This logic is valid only for whole numbers
* (i.e., not REAL type, but REAL constraints * (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 if(ra->right.type == ARE_VALUE
&& rb->left.type == ARE_VALUE && rb->left.type == ARE_VALUE
...@@ -674,7 +693,7 @@ _range_canonicalize(asn1cnst_range_t *range) { ...@@ -674,7 +693,7 @@ _range_canonicalize(asn1cnst_range_t *range) {
} }
asn1cnst_range_t * 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 *range;
asn1cnst_range_t *tmp; asn1cnst_range_t *tmp;
asn1p_value_t *vmin; asn1p_value_t *vmin;
...@@ -689,7 +708,8 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr ...@@ -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) { if(asn1constraint_compatible(expr_type, type) != 1) {
errno = EINVAL; errno = EINVAL;
...@@ -730,7 +750,15 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr ...@@ -730,7 +750,15 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr
range = _range_new(); 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; return range;
switch(ct->type) { switch(ct->type) {
...@@ -746,9 +774,11 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr ...@@ -746,9 +774,11 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr
break; break;
case ACT_EL_EXT: case ACT_EL_EXT:
if(!*exmet) { if(!*exmet) {
range->not_PER_visible = 1; range->incompatible = 1;
} else { } else {
range->extensible = 1; _range_free(range);
errno = ERANGE;
range = 0;
} }
return range; return range;
case ACT_CT_SIZE: case ACT_CT_SIZE:
...@@ -756,12 +786,24 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr ...@@ -756,12 +786,24 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr
if(type == ct->type) { if(type == ct->type) {
*exmet = 1; *exmet = 1;
} else { } else {
range->not_PER_visible = 1; range->incompatible = 1;
return range; return range;
} }
assert(ct->el_count == 1); assert(ct->el_count == 1);
return asn1constraint_compute_PER_range(expr_type, tmp = asn1constraint_compute_PER_range(expr_type,
ct->elements[0], type, minmax, exmet); 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_SET: /* (10..20)(15..17) */
case ACT_CA_INT: /* SIZE(1..2) ^ FROM("ABCD") */ 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 ...@@ -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++) { for(i = 0; i < ct->el_count; i++) {
tmp = asn1constraint_compute_PER_range(expr_type, tmp = asn1constraint_compute_PER_range(expr_type,
ct->elements[i], 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) { if(!tmp) {
_range_free(range); if(errno == ERANGE) {
return NULL; 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) { if(ct->type == ACT_CA_SET) {
/* /*
* X.691, #9.3.18: * X.691, #9.3.18:
...@@ -791,17 +849,6 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr ...@@ -791,17 +849,6 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr
continue; 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, ret = _range_intersection(range, tmp,
ct->type == ACT_CA_SET); ct->type == ACT_CA_SET);
_range_free(tmp); _range_free(tmp);
...@@ -817,40 +864,100 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr ...@@ -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_CSV: /* SIZE(1..2, 3..4) */
case ACT_CA_UNI: /* SIZE(1..2) | FROM("ABCD") */ 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++) { for(i = 0; i < ct->el_count; i++) {
tmp = asn1constraint_compute_PER_range(expr_type, tmp = asn1constraint_compute_PER_range(expr_type,
ct->elements[i], type, minmax, exmet); ct->elements[i], type, minmax, exmet,
strict_PV);
if(!tmp) { if(!tmp) {
_range_free(range); if(errno == ERANGE) {
return NULL; 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) { if(tmp->empty_constraint) {
/* Ignore empty constraints */ /*
* Ignore empty constraints in OR logic.
*/
range->extensible |= tmp->extensible;
_range_free(tmp); _range_free(tmp);
continue; continue;
} }
range->not_PER_visible |= tmp->not_PER_visible;
range->extensible |= tmp->extensible;
_range_merge_in(range, tmp); _range_merge_in(range, tmp);
} }
_range_canonicalize(range); _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: * X.691, #9.3.19:
* If not PER-visible constraint is part of UNION, * 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); _range_free(range);
if(minmax) if(minmax)
range = _range_clone(minmax); range = _range_clone(minmax);
else else
range = _range_new(); range = _range_new();
range->not_PER_visible = 1;
range->incompatible = 1;
} }
return range; return range;
...@@ -862,10 +969,10 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr ...@@ -862,10 +969,10 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr
assert(ct->el_count >= 1); assert(ct->el_count >= 1);
_range_free(range); _range_free(range);
range = asn1constraint_compute_PER_range(expr_type, range = asn1constraint_compute_PER_range(expr_type,
ct->elements[0], type, minmax, exmet); ct->elements[0], type, minmax, exmet, strict_PV);
return range; return range;
default: default:
range->not_PER_visible = 1; range->incompatible = 1;
return range; return range;
} }
...@@ -874,7 +981,7 @@ asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constr ...@@ -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. * Expectation is not met. Return the default range.
*/ */
range->not_PER_visible = 1; range->incompatible = 1;
return range; return range;
} }
......
...@@ -21,13 +21,14 @@ typedef struct asn1cnst_range_s { ...@@ -21,13 +21,14 @@ typedef struct asn1cnst_range_s {
int el_size; int el_size;
int empty_constraint; /* If yes, too bad. */ 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; } 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. * (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. * (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, ...@@ -41,7 +42,8 @@ asn1cnst_range_t *asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type,
const asn1p_constraint_t *ct, const asn1p_constraint_t *ct,
enum asn1p_constraint_type_e required_type, enum asn1p_constraint_type_e required_type,
const asn1cnst_range_t *minmax, const asn1cnst_range_t *minmax,
int *expectation_met); int *expectation_met,
int strict_PER_visibility);
void asn1constraint_range_free(asn1cnst_range_t *); void asn1constraint_range_free(asn1cnst_range_t *);
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment