diff options
Diffstat (limited to 'python/pyasn1/doc/constraints.html')
-rw-r--r-- | python/pyasn1/doc/constraints.html | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/python/pyasn1/doc/constraints.html b/python/pyasn1/doc/constraints.html new file mode 100644 index 000000000..53da1addf --- /dev/null +++ b/python/pyasn1/doc/constraints.html @@ -0,0 +1,436 @@ +<html> +<title> +PyASN1 subtype constraints +</title> +<head> +</head> +<body> +<center> +<table width=60%> +<tr> +<td> + +<h4> +1.4 PyASN1 subtype constraints +</h4> + +<p> +Most ASN.1 types can correspond to an infinite set of values. To adapt to +particular application's data model and needs, ASN.1 provides a mechanism +for limiting the infinite set to values, that make sense in particular case. +</p> + +<p> +Imposing value constraints on an ASN.1 type can also be seen as creating +a subtype from its base type. +</p> + +<p> +In pyasn1, constraints take shape of immutable objects capable +of evaluating given value against constraint-specific requirements. +Constraint object is a property of pyasn1 type. Like TagSet property, +associated with every pyasn1 type, constraints can never be modified +in place. The only way to modify pyasn1 type constraint is to associate +new constraint object to a new pyasn1 type object. +</p> + +<p> +A handful of different flavors of <i>constraints</i> are defined in ASN.1. +We will discuss them one by one in the following chapters and also explain +how to combine and apply them to types. +</p> + +<a name="1.4.1"></a> +<h4> +1.4.1 Single value constraint +</h4> + +<p> +This kind of constraint allows for limiting type to a finite, specified set +of values. +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +DialButton ::= OCTET STRING ( + "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" +) +</pre> +</td></tr></table> + +<p> +Its pyasn1 implementation would look like: +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> from pyasn1.type import constraint +>>> c = constraint.SingleValueConstraint( + '0','1','2','3','4','5','6','7','8','9' +) +>>> c +SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) +>>> c('0') +>>> c('A') +Traceback (most recent call last): +... +pyasn1.type.error.ValueConstraintError: + SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A +>>> +</pre> +</td></tr></table> + +<p> +As can be seen in the snippet above, if a value violates the constraint, an +exception will be thrown. A constrainted pyasn1 type object holds a +reference to a constraint object (or their combination, as will be explained +later) and calls it for value verification. +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> from pyasn1.type import univ, constraint +>>> class DialButton(univ.OctetString): +... subtypeSpec = constraint.SingleValueConstraint( +... '0','1','2','3','4','5','6','7','8','9' +... ) +>>> DialButton('0') +DialButton(b'0') +>>> DialButton('A') +Traceback (most recent call last): +... +pyasn1.type.error.ValueConstraintError: + SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A +>>> +</pre> +</td></tr></table> + +<p> +Constrained pyasn1 value object can never hold a violating value. +</p> + +<a name="1.4.2"></a> +<h4> +1.4.2 Value range constraint +</h4> + +<p> +A pair of values, compliant to a type to be constrained, denote low and upper +bounds of allowed range of values of a type. +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +Teenagers ::= INTEGER (13..19) +</pre> +</td></tr></table> + +<p> +And in pyasn1 terms: +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> from pyasn1.type import univ, constraint +>>> class Teenagers(univ.Integer): +... subtypeSpec = constraint.ValueRangeConstraint(13, 19) +>>> Teenagers(14) +Teenagers(14) +>>> Teenagers(20) +Traceback (most recent call last): +... +pyasn1.type.error.ValueConstraintError: + ValueRangeConstraint(13, 19) failed at: 20 +>>> +</pre> +</td></tr></table> + +<p> +Value range constraint usually applies numeric types. +</p> + +<a name="1.4.3"></a> +<h4> +1.4.3 Size constraint +</h4> + +<p> +It is sometimes convenient to set or limit the allowed size of a data item +to be sent from one application to another to manage bandwidth and memory +consumption issues. Size constraint specifies the lower and upper bounds +of the size of a valid value. +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +TwoBits ::= BIT STRING (SIZE (2)) +</pre> +</td></tr></table> + +<p> +Express the same grammar in pyasn1: +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> from pyasn1.type import univ, constraint +>>> class TwoBits(univ.BitString): +... subtypeSpec = constraint.ValueSizeConstraint(2, 2) +>>> TwoBits((1,1)) +TwoBits("'11'B") +>>> TwoBits((1,1,0)) +Traceback (most recent call last): +... +pyasn1.type.error.ValueConstraintError: + ValueSizeConstraint(2, 2) failed at: (1, 1, 0) +>>> +</pre> +</td></tr></table> + +<p> +Size constraint can be applied to potentially massive values - bit or octet +strings, SEQUENCE OF/SET OF values. +</p> + +<a name="1.4.4"></a> +<h4> +1.4.4 Alphabet constraint +</h4> + +<p> +The permitted alphabet constraint is similar to Single value constraint +but constraint applies to individual characters of a value. +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +MorseCode ::= PrintableString (FROM ("."|"-"|" ")) +</pre> +</td></tr></table> + +<p> +And in pyasn1: +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> from pyasn1.type import char, constraint +>>> class MorseCode(char.PrintableString): +... subtypeSpec = constraint.PermittedAlphabetConstraint(".", "-", " ") +>>> MorseCode("...---...") +MorseCode('...---...') +>>> MorseCode("?") +Traceback (most recent call last): +... +pyasn1.type.error.ValueConstraintError: + PermittedAlphabetConstraint(".", "-", " ") failed at: "?" +>>> +</pre> +</td></tr></table> + +<p> +Current implementation does not handle ranges of characters in constraint +(FROM "A".."Z" syntax), one has to list the whole set in a range. +</p> + +<a name="1.4.5"></a> +<h4> +1.4.5 Constraint combinations +</h4> + +<p> +Up to this moment, we used a single constraint per ASN.1 type. The standard, +however, allows for combining multiple individual constraints into +intersections, unions and exclusions. +</p> + +<p> +In pyasn1 data model, all of these methods of constraint combinations are +implemented as constraint-like objects holding individual constraint (or +combination) objects. Like terminal constraint objects, combination objects +are capable to perform value verification at its set of enclosed constraints +according to the logic of particular combination. +</p> + +<p> +Constraints intersection verification succeeds only if a value is +compliant to each constraint in a set. To begin with, the following +specification will constitute a valid telephone number: +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +PhoneNumber ::= NumericString (FROM ("0".."9")) (SIZE 11) +</pre> +</td></tr></table> + +<p> +Constraint intersection object serves the logic above: +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> from pyasn1.type import char, constraint +>>> class PhoneNumber(char.NumericString): +... subtypeSpec = constraint.ConstraintsIntersection( +... constraint.PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'), +... constraint.ValueSizeConstraint(11, 11) +... ) +>>> PhoneNumber('79039343212') +PhoneNumber('79039343212') +>>> PhoneNumber('?9039343212') +Traceback (most recent call last): +... +pyasn1.type.error.ValueConstraintError: + ConstraintsIntersection( + PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'), + ValueSizeConstraint(11, 11)) failed at: + PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9') failed at: "?039343212" +>>> PhoneNumber('9343212') +Traceback (most recent call last): +... +pyasn1.type.error.ValueConstraintError: + ConstraintsIntersection( + PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'), + ValueSizeConstraint(11, 11)) failed at: + ValueSizeConstraint(10, 10) failed at: "9343212" +>>> +</pre> +</td></tr></table> + +<p> +Union of constraints works by making sure that a value is compliant +to any of the constraint in a set. For instance: +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +CapitalOrSmall ::= IA5String (FROM ('A','B','C') | FROM ('a','b','c')) +</pre> +</td></tr></table> + +<p> +It's important to note, that a value must fully comply to any single +constraint in a set. In the specification above, a value of all small or +all capital letters is compliant, but a mix of small&capitals is not. +Here's its pyasn1 analogue: +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> from pyasn1.type import char, constraint +>>> class CapitalOrSmall(char.IA5String): +... subtypeSpec = constraint.ConstraintsUnion( +... constraint.PermittedAlphabetConstraint('A','B','C'), +... constraint.PermittedAlphabetConstraint('a','b','c') +... ) +>>> CapitalOrSmall('ABBA') +CapitalOrSmall('ABBA') +>>> CapitalOrSmall('abba') +CapitalOrSmall('abba') +>>> CapitalOrSmall('Abba') +Traceback (most recent call last): +... +pyasn1.type.error.ValueConstraintError: + ConstraintsUnion(PermittedAlphabetConstraint('A', 'B', 'C'), + PermittedAlphabetConstraint('a', 'b', 'c')) failed at: failed for "Abba" +>>> +</pre> +</td></tr></table> + +<p> +Finally, the exclusion constraint simply negates the logic of value +verification at a constraint. In the following example, any integer value +is allowed in a type but not zero. +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +NoZero ::= INTEGER (ALL EXCEPT 0) +</pre> +</td></tr></table> + +<p> +In pyasn1 the above definition would read: +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> from pyasn1.type import univ, constraint +>>> class NoZero(univ.Integer): +... subtypeSpec = constraint.ConstraintsExclusion( +... constraint.SingleValueConstraint(0) +... ) +>>> NoZero(1) +NoZero(1) +>>> NoZero(0) +Traceback (most recent call last): +... +pyasn1.type.error.ValueConstraintError: + ConstraintsExclusion(SingleValueConstraint(0)) failed at: 0 +>>> +</pre> +</td></tr></table> + +<p> +The depth of such a constraints tree, built with constraint combination objects +at its nodes, has not explicit limit. Value verification is performed in a +recursive manner till a definite solution is found. +</p> + +<a name="1.5"></a> +<h4> +1.5 Types relationships +</h4> + +<p> +In the course of data processing in an application, it is sometimes +convenient to figure out the type relationships between pyasn1 type or +value objects. Formally, two things influence pyasn1 types relationship: +<i>tag set</i> and <i>subtype constraints</i>. One pyasn1 type is considered +to be a derivative of another if their TagSet and Constraint objects are +a derivation of one another. +</p> + +<p> +The following example illustrates the concept (we use the same tagset but +different constraints for simplicity): +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> from pyasn1.type import univ, constraint +>>> i1 = univ.Integer(subtypeSpec=constraint.ValueRangeConstraint(3,8)) +>>> i2 = univ.Integer(subtypeSpec=constraint.ConstraintsIntersection( +... constraint.ValueRangeConstraint(3,8), +... constraint.ValueRangeConstraint(4,7) +... ) ) +>>> i1.isSameTypeWith(i2) +False +>>> i1.isSuperTypeOf(i2) +True +>>> i1.isSuperTypeOf(i1) +True +>>> i2.isSuperTypeOf(i1) +False +>>> +</pre> +</td></tr></table> + +<p> +As can be seen in the above code snippet, there are two methods of any pyasn1 +type/value object that test types for their relationship: +<b>isSameTypeWith</b>() and <b>isSuperTypeOf</b>(). The former is +self-descriptive while the latter yields true if the argument appears +to be a pyasn1 object which has tagset and constraints derived from those +of the object being called. +</p> + +<hr> + +</td> +</tr> +</table> +</center> +</body> +</html> |