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,
}
#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;
......
......@@ -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;
}
......
......@@ -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 *);
/*
......
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