OLD | NEW |
(Empty) | |
| 1 <html> |
| 2 <title> |
| 3 PyASN1 subtype constraints |
| 4 </title> |
| 5 <head> |
| 6 </head> |
| 7 <body> |
| 8 <center> |
| 9 <table width=60%> |
| 10 <tr> |
| 11 <td> |
| 12 |
| 13 <h4> |
| 14 1.4 PyASN1 subtype constraints |
| 15 </h4> |
| 16 |
| 17 <p> |
| 18 Most ASN.1 types can correspond to an infinite set of values. To adapt to |
| 19 particular application's data model and needs, ASN.1 provides a mechanism |
| 20 for limiting the infinite set to values, that make sense in particular case. |
| 21 </p> |
| 22 |
| 23 <p> |
| 24 Imposing value constraints on an ASN.1 type can also be seen as creating |
| 25 a subtype from its base type. |
| 26 </p> |
| 27 |
| 28 <p> |
| 29 In pyasn1, constraints take shape of immutable objects capable |
| 30 of evaluating given value against constraint-specific requirements. |
| 31 Constraint object is a property of pyasn1 type. Like TagSet property, |
| 32 associated with every pyasn1 type, constraints can never be modified |
| 33 in place. The only way to modify pyasn1 type constraint is to associate |
| 34 new constraint object to a new pyasn1 type object. |
| 35 </p> |
| 36 |
| 37 <p> |
| 38 A handful of different flavors of <i>constraints</i> are defined in ASN.1. |
| 39 We will discuss them one by one in the following chapters and also explain |
| 40 how to combine and apply them to types. |
| 41 </p> |
| 42 |
| 43 <a name="1.4.1"></a> |
| 44 <h4> |
| 45 1.4.1 Single value constraint |
| 46 </h4> |
| 47 |
| 48 <p> |
| 49 This kind of constraint allows for limiting type to a finite, specified set |
| 50 of values. |
| 51 </p> |
| 52 |
| 53 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 54 <pre> |
| 55 DialButton ::= OCTET STRING ( |
| 56 "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" |
| 57 ) |
| 58 </pre> |
| 59 </td></tr></table> |
| 60 |
| 61 <p> |
| 62 Its pyasn1 implementation would look like: |
| 63 </p> |
| 64 |
| 65 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 66 <pre> |
| 67 >>> from pyasn1.type import constraint |
| 68 >>> c = constraint.SingleValueConstraint( |
| 69 '0','1','2','3','4','5','6','7','8','9' |
| 70 ) |
| 71 >>> c |
| 72 SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
| 73 >>> c('0') |
| 74 >>> c('A') |
| 75 Traceback (most recent call last): |
| 76 ... |
| 77 pyasn1.type.error.ValueConstraintError: |
| 78 SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A |
| 79 >>> |
| 80 </pre> |
| 81 </td></tr></table> |
| 82 |
| 83 <p> |
| 84 As can be seen in the snippet above, if a value violates the constraint, an |
| 85 exception will be thrown. A constrainted pyasn1 type object holds a |
| 86 reference to a constraint object (or their combination, as will be explained |
| 87 later) and calls it for value verification. |
| 88 </p> |
| 89 |
| 90 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 91 <pre> |
| 92 >>> from pyasn1.type import univ, constraint |
| 93 >>> class DialButton(univ.OctetString): |
| 94 ... subtypeSpec = constraint.SingleValueConstraint( |
| 95 ... '0','1','2','3','4','5','6','7','8','9' |
| 96 ... ) |
| 97 >>> DialButton('0') |
| 98 DialButton(b'0') |
| 99 >>> DialButton('A') |
| 100 Traceback (most recent call last): |
| 101 ... |
| 102 pyasn1.type.error.ValueConstraintError: |
| 103 SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A |
| 104 >>> |
| 105 </pre> |
| 106 </td></tr></table> |
| 107 |
| 108 <p> |
| 109 Constrained pyasn1 value object can never hold a violating value. |
| 110 </p> |
| 111 |
| 112 <a name="1.4.2"></a> |
| 113 <h4> |
| 114 1.4.2 Value range constraint |
| 115 </h4> |
| 116 |
| 117 <p> |
| 118 A pair of values, compliant to a type to be constrained, denote low and upper |
| 119 bounds of allowed range of values of a type. |
| 120 </p> |
| 121 |
| 122 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 123 <pre> |
| 124 Teenagers ::= INTEGER (13..19) |
| 125 </pre> |
| 126 </td></tr></table> |
| 127 |
| 128 <p> |
| 129 And in pyasn1 terms: |
| 130 </p> |
| 131 |
| 132 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 133 <pre> |
| 134 >>> from pyasn1.type import univ, constraint |
| 135 >>> class Teenagers(univ.Integer): |
| 136 ... subtypeSpec = constraint.ValueRangeConstraint(13, 19) |
| 137 >>> Teenagers(14) |
| 138 Teenagers(14) |
| 139 >>> Teenagers(20) |
| 140 Traceback (most recent call last): |
| 141 ... |
| 142 pyasn1.type.error.ValueConstraintError: |
| 143 ValueRangeConstraint(13, 19) failed at: 20 |
| 144 >>> |
| 145 </pre> |
| 146 </td></tr></table> |
| 147 |
| 148 <p> |
| 149 Value range constraint usually applies numeric types. |
| 150 </p> |
| 151 |
| 152 <a name="1.4.3"></a> |
| 153 <h4> |
| 154 1.4.3 Size constraint |
| 155 </h4> |
| 156 |
| 157 <p> |
| 158 It is sometimes convenient to set or limit the allowed size of a data item |
| 159 to be sent from one application to another to manage bandwidth and memory |
| 160 consumption issues. Size constraint specifies the lower and upper bounds |
| 161 of the size of a valid value. |
| 162 </p> |
| 163 |
| 164 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 165 <pre> |
| 166 TwoBits ::= BIT STRING (SIZE (2)) |
| 167 </pre> |
| 168 </td></tr></table> |
| 169 |
| 170 <p> |
| 171 Express the same grammar in pyasn1: |
| 172 </p> |
| 173 |
| 174 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 175 <pre> |
| 176 >>> from pyasn1.type import univ, constraint |
| 177 >>> class TwoBits(univ.BitString): |
| 178 ... subtypeSpec = constraint.ValueSizeConstraint(2, 2) |
| 179 >>> TwoBits((1,1)) |
| 180 TwoBits("'11'B") |
| 181 >>> TwoBits((1,1,0)) |
| 182 Traceback (most recent call last): |
| 183 ... |
| 184 pyasn1.type.error.ValueConstraintError: |
| 185 ValueSizeConstraint(2, 2) failed at: (1, 1, 0) |
| 186 >>> |
| 187 </pre> |
| 188 </td></tr></table> |
| 189 |
| 190 <p> |
| 191 Size constraint can be applied to potentially massive values - bit or octet |
| 192 strings, SEQUENCE OF/SET OF values. |
| 193 </p> |
| 194 |
| 195 <a name="1.4.4"></a> |
| 196 <h4> |
| 197 1.4.4 Alphabet constraint |
| 198 </h4> |
| 199 |
| 200 <p> |
| 201 The permitted alphabet constraint is similar to Single value constraint |
| 202 but constraint applies to individual characters of a value. |
| 203 </p> |
| 204 |
| 205 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 206 <pre> |
| 207 MorseCode ::= PrintableString (FROM ("."|"-"|" ")) |
| 208 </pre> |
| 209 </td></tr></table> |
| 210 |
| 211 <p> |
| 212 And in pyasn1: |
| 213 </p> |
| 214 |
| 215 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 216 <pre> |
| 217 >>> from pyasn1.type import char, constraint |
| 218 >>> class MorseCode(char.PrintableString): |
| 219 ... subtypeSpec = constraint.PermittedAlphabetConstraint(".", "-", " ") |
| 220 >>> MorseCode("...---...") |
| 221 MorseCode('...---...') |
| 222 >>> MorseCode("?") |
| 223 Traceback (most recent call last): |
| 224 ... |
| 225 pyasn1.type.error.ValueConstraintError: |
| 226 PermittedAlphabetConstraint(".", "-", " ") failed at: "?" |
| 227 >>> |
| 228 </pre> |
| 229 </td></tr></table> |
| 230 |
| 231 <p> |
| 232 Current implementation does not handle ranges of characters in constraint |
| 233 (FROM "A".."Z" syntax), one has to list the whole set in a range. |
| 234 </p> |
| 235 |
| 236 <a name="1.4.5"></a> |
| 237 <h4> |
| 238 1.4.5 Constraint combinations |
| 239 </h4> |
| 240 |
| 241 <p> |
| 242 Up to this moment, we used a single constraint per ASN.1 type. The standard, |
| 243 however, allows for combining multiple individual constraints into |
| 244 intersections, unions and exclusions. |
| 245 </p> |
| 246 |
| 247 <p> |
| 248 In pyasn1 data model, all of these methods of constraint combinations are |
| 249 implemented as constraint-like objects holding individual constraint (or |
| 250 combination) objects. Like terminal constraint objects, combination objects |
| 251 are capable to perform value verification at its set of enclosed constraints |
| 252 according to the logic of particular combination. |
| 253 </p> |
| 254 |
| 255 <p> |
| 256 Constraints intersection verification succeeds only if a value is |
| 257 compliant to each constraint in a set. To begin with, the following |
| 258 specification will constitute a valid telephone number: |
| 259 </p> |
| 260 |
| 261 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 262 <pre> |
| 263 PhoneNumber ::= NumericString (FROM ("0".."9")) (SIZE 11) |
| 264 </pre> |
| 265 </td></tr></table> |
| 266 |
| 267 <p> |
| 268 Constraint intersection object serves the logic above: |
| 269 </p> |
| 270 |
| 271 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 272 <pre> |
| 273 >>> from pyasn1.type import char, constraint |
| 274 >>> class PhoneNumber(char.NumericString): |
| 275 ... subtypeSpec = constraint.ConstraintsIntersection( |
| 276 ... constraint.PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','
8','9'), |
| 277 ... constraint.ValueSizeConstraint(11, 11) |
| 278 ... ) |
| 279 >>> PhoneNumber('79039343212') |
| 280 PhoneNumber('79039343212') |
| 281 >>> PhoneNumber('?9039343212') |
| 282 Traceback (most recent call last): |
| 283 ... |
| 284 pyasn1.type.error.ValueConstraintError: |
| 285 ConstraintsIntersection( |
| 286 PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'), |
| 287 ValueSizeConstraint(11, 11)) failed at: |
| 288 PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9') failed a
t: "?039343212" |
| 289 >>> PhoneNumber('9343212') |
| 290 Traceback (most recent call last): |
| 291 ... |
| 292 pyasn1.type.error.ValueConstraintError: |
| 293 ConstraintsIntersection( |
| 294 PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'), |
| 295 ValueSizeConstraint(11, 11)) failed at: |
| 296 ValueSizeConstraint(10, 10) failed at: "9343212" |
| 297 >>> |
| 298 </pre> |
| 299 </td></tr></table> |
| 300 |
| 301 <p> |
| 302 Union of constraints works by making sure that a value is compliant |
| 303 to any of the constraint in a set. For instance: |
| 304 </p> |
| 305 |
| 306 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 307 <pre> |
| 308 CapitalOrSmall ::= IA5String (FROM ('A','B','C') | FROM ('a','b','c')) |
| 309 </pre> |
| 310 </td></tr></table> |
| 311 |
| 312 <p> |
| 313 It's important to note, that a value must fully comply to any single |
| 314 constraint in a set. In the specification above, a value of all small or |
| 315 all capital letters is compliant, but a mix of small&capitals is not. |
| 316 Here's its pyasn1 analogue: |
| 317 </p> |
| 318 |
| 319 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 320 <pre> |
| 321 >>> from pyasn1.type import char, constraint |
| 322 >>> class CapitalOrSmall(char.IA5String): |
| 323 ... subtypeSpec = constraint.ConstraintsUnion( |
| 324 ... constraint.PermittedAlphabetConstraint('A','B','C'), |
| 325 ... constraint.PermittedAlphabetConstraint('a','b','c') |
| 326 ... ) |
| 327 >>> CapitalOrSmall('ABBA') |
| 328 CapitalOrSmall('ABBA') |
| 329 >>> CapitalOrSmall('abba') |
| 330 CapitalOrSmall('abba') |
| 331 >>> CapitalOrSmall('Abba') |
| 332 Traceback (most recent call last): |
| 333 ... |
| 334 pyasn1.type.error.ValueConstraintError: |
| 335 ConstraintsUnion(PermittedAlphabetConstraint('A', 'B', 'C'), |
| 336 PermittedAlphabetConstraint('a', 'b', 'c')) failed at: failed for "Abba" |
| 337 >>> |
| 338 </pre> |
| 339 </td></tr></table> |
| 340 |
| 341 <p> |
| 342 Finally, the exclusion constraint simply negates the logic of value |
| 343 verification at a constraint. In the following example, any integer value |
| 344 is allowed in a type but not zero. |
| 345 </p> |
| 346 |
| 347 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 348 <pre> |
| 349 NoZero ::= INTEGER (ALL EXCEPT 0) |
| 350 </pre> |
| 351 </td></tr></table> |
| 352 |
| 353 <p> |
| 354 In pyasn1 the above definition would read: |
| 355 </p> |
| 356 |
| 357 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 358 <pre> |
| 359 >>> from pyasn1.type import univ, constraint |
| 360 >>> class NoZero(univ.Integer): |
| 361 ... subtypeSpec = constraint.ConstraintsExclusion( |
| 362 ... constraint.SingleValueConstraint(0) |
| 363 ... ) |
| 364 >>> NoZero(1) |
| 365 NoZero(1) |
| 366 >>> NoZero(0) |
| 367 Traceback (most recent call last): |
| 368 ... |
| 369 pyasn1.type.error.ValueConstraintError: |
| 370 ConstraintsExclusion(SingleValueConstraint(0)) failed at: 0 |
| 371 >>> |
| 372 </pre> |
| 373 </td></tr></table> |
| 374 |
| 375 <p> |
| 376 The depth of such a constraints tree, built with constraint combination objects |
| 377 at its nodes, has not explicit limit. Value verification is performed in a |
| 378 recursive manner till a definite solution is found. |
| 379 </p> |
| 380 |
| 381 <a name="1.5"></a> |
| 382 <h4> |
| 383 1.5 Types relationships |
| 384 </h4> |
| 385 |
| 386 <p> |
| 387 In the course of data processing in an application, it is sometimes |
| 388 convenient to figure out the type relationships between pyasn1 type or |
| 389 value objects. Formally, two things influence pyasn1 types relationship: |
| 390 <i>tag set</i> and <i>subtype constraints</i>. One pyasn1 type is considered |
| 391 to be a derivative of another if their TagSet and Constraint objects are |
| 392 a derivation of one another. |
| 393 </p> |
| 394 |
| 395 <p> |
| 396 The following example illustrates the concept (we use the same tagset but |
| 397 different constraints for simplicity): |
| 398 </p> |
| 399 |
| 400 <table bgcolor="lightgray" border=0 width=100%><TR><TD> |
| 401 <pre> |
| 402 >>> from pyasn1.type import univ, constraint |
| 403 >>> i1 = univ.Integer(subtypeSpec=constraint.ValueRangeConstraint(3,8)) |
| 404 >>> i2 = univ.Integer(subtypeSpec=constraint.ConstraintsIntersection( |
| 405 ... constraint.ValueRangeConstraint(3,8), |
| 406 ... constraint.ValueRangeConstraint(4,7) |
| 407 ... ) ) |
| 408 >>> i1.isSameTypeWith(i2) |
| 409 False |
| 410 >>> i1.isSuperTypeOf(i2) |
| 411 True |
| 412 >>> i1.isSuperTypeOf(i1) |
| 413 True |
| 414 >>> i2.isSuperTypeOf(i1) |
| 415 False |
| 416 >>> |
| 417 </pre> |
| 418 </td></tr></table> |
| 419 |
| 420 <p> |
| 421 As can be seen in the above code snippet, there are two methods of any pyasn1 |
| 422 type/value object that test types for their relationship: |
| 423 <b>isSameTypeWith</b>() and <b>isSuperTypeOf</b>(). The former is |
| 424 self-descriptive while the latter yields true if the argument appears |
| 425 to be a pyasn1 object which has tagset and constraints derived from those |
| 426 of the object being called. |
| 427 </p> |
| 428 |
| 429 <hr> |
| 430 |
| 431 </td> |
| 432 </tr> |
| 433 </table> |
| 434 </center> |
| 435 </body> |
| 436 </html> |
OLD | NEW |