| OLD | NEW |
| (Empty) |
| 1 <html> | |
| 2 <title> | |
| 3 PyASN1 programmer's manual | |
| 4 </title> | |
| 5 <head> | |
| 6 </head> | |
| 7 <body> | |
| 8 <center> | |
| 9 <table width=60%> | |
| 10 <tr> | |
| 11 <td> | |
| 12 | |
| 13 <h3> | |
| 14 PyASN1 programmer's manual | |
| 15 </h3> | |
| 16 | |
| 17 <p align=right> | |
| 18 <i>written by <a href=mailto:ilya@glas.net>Ilya Etingof</a>, 2011-2012</i> | |
| 19 </p> | |
| 20 | |
| 21 <p> | |
| 22 Free and open-source pyasn1 library makes it easier for programmers and | |
| 23 network engineers to develop, debug and experiment with ASN.1-based protocols | |
| 24 using Python programming language as a tool. | |
| 25 </p> | |
| 26 | |
| 27 <p> | |
| 28 Abstract Syntax Notation One | |
| 29 (<a href=http://en.wikipedia.org/wiki/Abstract_Syntax_Notation_1x>ASN.1</a>) | |
| 30 is a set of | |
| 31 <a href=http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-X.693-0207w.z
ip> | |
| 32 ITU standards</a> concered with provisioning instrumentation for developing | |
| 33 data exchange protocols in a robust, clear and interoperabable way for | |
| 34 various IT systems and applications. Most of the efforts are targeting the | |
| 35 following areas: | |
| 36 <ul> | |
| 37 <li>Data structures: the standard introduces a collection of basic data types | |
| 38 (similar to integers, bits, strings, arrays and records in a programming | |
| 39 language) that can be used for defining complex, possibly nested data | |
| 40 structures representing domain-specific data units. | |
| 41 <li>Serialization protocols: domain-specific data units expressed in ASN.1 | |
| 42 types could be converted into a series of octets for storage or transmission | |
| 43 over the wire and then recovered back into their structured form on the | |
| 44 receiving end. This process is immune to various hardware and software | |
| 45 related dependencies. | |
| 46 <li>Data description language: could be used to describe particular set of | |
| 47 domain-specific data structures and their relationships. Such a description | |
| 48 could be passed to an ASN.1 compiler for automated generation of program | |
| 49 code that represents ASN.1 data structures in language-native environment | |
| 50 and handles data serialization issues. | |
| 51 </ul> | |
| 52 </p> | |
| 53 | |
| 54 <p> | |
| 55 This tutorial and algorithms, implemented by pyasn1 library, are | |
| 56 largely based on the information read in the book | |
| 57 <a href="http://www.oss.com/asn1/dubuisson.html"> | |
| 58 ASN.1 - Communication between heterogeneous systems</a> | |
| 59 by Olivier Dubuisson. Another relevant resource is | |
| 60 <a href=ftp://ftp.rsasecurity.com/pub/pkcs/ascii/layman.asc> | |
| 61 A Layman's Guide to a Subset of ASN.1, BER, and DER</a> by Burton S. Kaliski. | |
| 62 It's advised to refer to these books for more in-depth knowledge on the | |
| 63 subject of ASN.1. | |
| 64 </p> | |
| 65 | |
| 66 <p> | |
| 67 As of this writing, pyasn1 library implements most of standard ASN.1 data | |
| 68 structures in a rather detailed and feature-rich manner. Another highly | |
| 69 important capability of the library is its data serialization facilities. | |
| 70 The last component of the standard - ASN.1 compiler is planned for | |
| 71 implementation in the future. | |
| 72 </p> | |
| 73 | |
| 74 </p> | |
| 75 The pyasn1 library was designed to follow the pre-1995 ASN.1 specification | |
| 76 (also known as X.208). Later, post 1995, revision (X.680) introduced | |
| 77 significant changes most of which have not yet been supported by pyasn1. | |
| 78 </p> | |
| 79 | |
| 80 <h3> | |
| 81 Table of contents | |
| 82 </h3> | |
| 83 | |
| 84 <p> | |
| 85 <ul> | |
| 86 <li><a href="#1">1. Data model for ASN.1 types</a> | |
| 87 <li><a href="#1.1">1.1 Scalar types</a> | |
| 88 <li><a href="#1.1.1">1.1.1 Boolean type</a> | |
| 89 <li><a href="#1.1.2">1.1.2 Null type</a> | |
| 90 <li><a href="#1.1.3">1.1.3 Integer type</a> | |
| 91 <li><a href="#1.1.4">1.1.4 Enumerated type</a> | |
| 92 <li><a href="#1.1.5">1.1.5 Real type</a> | |
| 93 <li><a href="#1.1.6">1.1.6 Bit string type</a> | |
| 94 <li><a href="#1.1.7">1.1.7 OctetString type</a> | |
| 95 <li><a href="#1.1.8">1.1.8 ObjectIdentifier type</a> | |
| 96 <li><a href="#1.1.9">1.1.9 Character string types</a> | |
| 97 <li><a href="#1.1.10">1.1.10 Useful types</a> | |
| 98 <li><a href="#1.2">1.2 Tagging</a> | |
| 99 <li><a href="#1.3">1.3 Constructed types</a> | |
| 100 <li><a href="#1.3.1">1.3.1 Sequence and Set types</a> | |
| 101 <li><a href="#1.3.2">1.3.2 SequenceOf and SetOf types</a> | |
| 102 <li><a href="#1.3.3">1.3.3 Choice type</a> | |
| 103 <li><a href="#1.3.4">1.3.4 Any type</a> | |
| 104 <li><a href="#1.4">1.4 Subtype constraints</a> | |
| 105 <li><a href="#1.4.1">1.4.1 Single value constraint</a> | |
| 106 <li><a href="#1.4.2">1.4.2 Value range constraint</a> | |
| 107 <li><a href="#1.4.3">1.4.3 Size constraint</a> | |
| 108 <li><a href="#1.4.4">1.4.4 Alphabet constraint</a> | |
| 109 <li><a href="#1.4.5">1.4.5 Constraint combinations</a> | |
| 110 <li><a href="#1.5">1.5 Types relationships</a> | |
| 111 <li><a href="#2">2. Codecs</a> | |
| 112 <li><a href="#2.1">2.1 Encoders</a> | |
| 113 <li><a href="#2.2">2.2 Decoders</a> | |
| 114 <li><a href="#2.2.1">2.2.1 Decoding untagged types</a> | |
| 115 <li><a href="#2.2.2">2.2.2 Ignoring unknown types</a> | |
| 116 <li><a href="#3">3. Feedback and getting help</a> | |
| 117 </ul> | |
| 118 | |
| 119 | |
| 120 <a name="1"></a> | |
| 121 <h3> | |
| 122 1. Data model for ASN.1 types | |
| 123 </h3> | |
| 124 | |
| 125 <p> | |
| 126 All ASN.1 types could be categorized into two groups: scalar (also called | |
| 127 simple or primitive) and constructed. The first group is populated by | |
| 128 well-known types like Integer or String. Members of constructed group | |
| 129 hold other types (simple or constructed) as their inner components, thus | |
| 130 they are semantically close to a programming language records or lists. | |
| 131 </p> | |
| 132 | |
| 133 <p> | |
| 134 In pyasn1, all ASN.1 types and values are implemented as Python objects. | |
| 135 The same pyasn1 object can represent either ASN.1 type and/or value | |
| 136 depending of the presense of value initializer on object instantiation. | |
| 137 We will further refer to these as <i>pyasn1 type object</i> versus <i>pyasn1 | |
| 138 value object</i>. | |
| 139 </p> | |
| 140 | |
| 141 <p> | |
| 142 Primitive ASN.1 types are implemented as immutable scalar objects. There values | |
| 143 could be used just like corresponding native Python values (integers, | |
| 144 strings/bytes etc) and freely mixed with them in expressions. | |
| 145 </p> | |
| 146 | |
| 147 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 148 <pre> | |
| 149 >>> from pyasn1.type import univ | |
| 150 >>> asn1IntegerValue = univ.Integer(12) | |
| 151 >>> asn1IntegerValue - 2 | |
| 152 10 | |
| 153 >>> univ.OctetString('abc') == 'abc' | |
| 154 True # Python 2 | |
| 155 >>> univ.OctetString(b'abc') == b'abc' | |
| 156 True # Python 3 | |
| 157 </pre> | |
| 158 </td></tr></table> | |
| 159 | |
| 160 <p> | |
| 161 It would be an error to perform an operation on a pyasn1 type object | |
| 162 as it holds no value to deal with: | |
| 163 </p> | |
| 164 | |
| 165 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 166 <pre> | |
| 167 >>> from pyasn1.type import univ | |
| 168 >>> asn1IntegerType = univ.Integer() | |
| 169 >>> asn1IntegerType - 2 | |
| 170 ... | |
| 171 pyasn1.error.PyAsn1Error: No value for __coerce__() | |
| 172 </pre> | |
| 173 </td></tr></table> | |
| 174 | |
| 175 <a name="1.1"></a> | |
| 176 <h4> | |
| 177 1.1 Scalar types | |
| 178 </h4> | |
| 179 | |
| 180 <p> | |
| 181 In the sub-sections that follow we will explain pyasn1 mapping to those | |
| 182 primitive ASN.1 types. Both, ASN.1 notation and corresponding pyasn1 | |
| 183 syntax will be given in each case. | |
| 184 </p> | |
| 185 | |
| 186 <a name="1.1.1"></a> | |
| 187 <h4> | |
| 188 1.1.1 Boolean type | |
| 189 </h4> | |
| 190 | |
| 191 <p> | |
| 192 This is the simplest type those values could be either True or False. | |
| 193 </p> | |
| 194 | |
| 195 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 196 <pre> | |
| 197 ;; type specification | |
| 198 FunFactorPresent ::= BOOLEAN | |
| 199 | |
| 200 ;; values declaration and assignment | |
| 201 pythonFunFactor FunFactorPresent ::= TRUE | |
| 202 cobolFunFactor FunFactorPresent :: FALSE | |
| 203 </pre> | |
| 204 </td></tr></table> | |
| 205 | |
| 206 <p> | |
| 207 And here's pyasn1 version of it: | |
| 208 </p> | |
| 209 | |
| 210 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 211 <pre> | |
| 212 >>> from pyasn1.type import univ | |
| 213 >>> class FunFactorPresent(univ.Boolean): pass | |
| 214 ... | |
| 215 >>> pythonFunFactor = FunFactorPresent(True) | |
| 216 >>> cobolFunFactor = FunFactorPresent(False) | |
| 217 >>> pythonFunFactor | |
| 218 FunFactorPresent('True(1)') | |
| 219 >>> cobolFunFactor | |
| 220 FunFactorPresent('False(0)') | |
| 221 >>> pythonFunFactor == cobolFunFactor | |
| 222 False | |
| 223 >>> | |
| 224 </pre> | |
| 225 </td></tr></table> | |
| 226 | |
| 227 <a name="1.1.2"></a> | |
| 228 <h4> | |
| 229 1.1.2 Null type | |
| 230 </h4> | |
| 231 | |
| 232 <p> | |
| 233 The NULL type is sometimes used to express the absense of any information. | |
| 234 </p> | |
| 235 | |
| 236 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 237 <pre> | |
| 238 ;; type specification | |
| 239 Vote ::= CHOICE { | |
| 240 agreed BOOLEAN, | |
| 241 skip NULL | |
| 242 } | |
| 243 </td></tr></table> | |
| 244 | |
| 245 ;; value declaration and assignment | |
| 246 myVote Vote ::= skip:NULL | |
| 247 </pre> | |
| 248 | |
| 249 <p> | |
| 250 We will explain the CHOICE type later in this paper, meanwhile the NULL | |
| 251 type: | |
| 252 </p> | |
| 253 | |
| 254 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 255 <pre> | |
| 256 >>> from pyasn1.type import univ | |
| 257 >>> skip = univ.Null() | |
| 258 >>> skip | |
| 259 Null('') | |
| 260 >>> | |
| 261 </pre> | |
| 262 </td></tr></table> | |
| 263 | |
| 264 <a name="1.1.3"></a> | |
| 265 <h4> | |
| 266 1.1.3 Integer type | |
| 267 </h4> | |
| 268 | |
| 269 <p> | |
| 270 ASN.1 defines the values of Integer type as negative or positive of whatever | |
| 271 length. This definition plays nicely with Python as the latter places no | |
| 272 limit on Integers. However, some ASN.1 implementations may impose certain | |
| 273 limits of integer value ranges. Keep that in mind when designing new | |
| 274 data structures. | |
| 275 </p> | |
| 276 | |
| 277 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 278 <pre> | |
| 279 ;; values specification | |
| 280 age-of-universe INTEGER ::= 13750000000 | |
| 281 mean-martian-surface-temperature INTEGER ::= -63 | |
| 282 </pre> | |
| 283 </td></tr></table> | |
| 284 | |
| 285 <p> | |
| 286 A rather strigntforward mapping into pyasn1: | |
| 287 </p> | |
| 288 | |
| 289 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 290 <pre> | |
| 291 >>> from pyasn1.type import univ | |
| 292 >>> ageOfUniverse = univ.Integer(13750000000) | |
| 293 >>> ageOfUniverse | |
| 294 Integer(13750000000) | |
| 295 >>> | |
| 296 >>> meanMartianSurfaceTemperature = univ.Integer(-63) | |
| 297 >>> meanMartianSurfaceTemperature | |
| 298 Integer(-63) | |
| 299 >>> | |
| 300 </pre> | |
| 301 </td></tr></table> | |
| 302 | |
| 303 <p> | |
| 304 ASN.1 allows to assign human-friendly names to particular values of | |
| 305 an INTEGER type. | |
| 306 </p> | |
| 307 | |
| 308 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 309 <pre> | |
| 310 Temperature ::= INTEGER { | |
| 311 freezing(0), | |
| 312 boiling(100) | |
| 313 } | |
| 314 </pre> | |
| 315 </td></tr></table> | |
| 316 | |
| 317 <p> | |
| 318 The Temperature type expressed in pyasn1: | |
| 319 </p> | |
| 320 | |
| 321 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 322 <pre> | |
| 323 >>> from pyasn1.type import univ, namedval | |
| 324 >>> class Temperature(univ.Integer): | |
| 325 ... namedValues = namedval.NamedValues(('freezing', 0), ('boiling', 100)) | |
| 326 ... | |
| 327 >>> t = Temperature(0) | |
| 328 >>> t | |
| 329 Temperature('freezing(0)') | |
| 330 >>> t + 1 | |
| 331 Temperature(1) | |
| 332 >>> t + 100 | |
| 333 Temperature('boiling(100)') | |
| 334 >>> t = Temperature('boiling') | |
| 335 >>> t | |
| 336 Temperature('boiling(100)') | |
| 337 >>> Temperature('boiling') / 2 | |
| 338 Temperature(50) | |
| 339 >>> -1 < Temperature('freezing') | |
| 340 True | |
| 341 >>> 47 > Temperature('boiling') | |
| 342 False | |
| 343 >>> | |
| 344 </pre> | |
| 345 </td></tr></table> | |
| 346 | |
| 347 <p> | |
| 348 These values labels have no effect on Integer type operations, any value | |
| 349 still could be assigned to a type (information on value constraints will | |
| 350 follow further in this paper). | |
| 351 </p> | |
| 352 | |
| 353 <a name="1.1.4"></a> | |
| 354 <h4> | |
| 355 1.1.4 Enumerated type | |
| 356 </h4> | |
| 357 | |
| 358 <p> | |
| 359 ASN.1 Enumerated type differs from an Integer type in a number of ways. | |
| 360 Most important is that its instance can only hold a value that belongs | |
| 361 to a set of values specified on type declaration. | |
| 362 </p> | |
| 363 | |
| 364 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 365 <pre> | |
| 366 error-status ::= ENUMERATED { | |
| 367 no-error(0), | |
| 368 authentication-error(10), | |
| 369 authorization-error(20), | |
| 370 general-failure(51) | |
| 371 } | |
| 372 </pre> | |
| 373 </td></tr></table> | |
| 374 | |
| 375 <p> | |
| 376 When constructing Enumerated type we will use two pyasn1 features: values | |
| 377 labels (as mentioned above) and value constraint (will be described in | |
| 378 more details later on). | |
| 379 </p> | |
| 380 | |
| 381 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 382 <pre> | |
| 383 >>> from pyasn1.type import univ, namedval, constraint | |
| 384 >>> class ErrorStatus(univ.Enumerated): | |
| 385 ... namedValues = namedval.NamedValues( | |
| 386 ... ('no-error', 0), | |
| 387 ... ('authentication-error', 10), | |
| 388 ... ('authorization-error', 20), | |
| 389 ... ('general-failure', 51) | |
| 390 ... ) | |
| 391 ... subtypeSpec = univ.Enumerated.subtypeSpec + \ | |
| 392 ... constraint.SingleValueConstraint(0, 10, 20, 51) | |
| 393 ... | |
| 394 >>> errorStatus = univ.ErrorStatus('no-error') | |
| 395 >>> errorStatus | |
| 396 ErrorStatus('no-error(0)') | |
| 397 >>> errorStatus == univ.ErrorStatus('general-failure') | |
| 398 False | |
| 399 >>> univ.ErrorStatus('non-existing-state') | |
| 400 Traceback (most recent call last): | |
| 401 ... | |
| 402 pyasn1.error.PyAsn1Error: Can't coerce non-existing-state into integer | |
| 403 >>> | |
| 404 </pre> | |
| 405 </td></tr></table> | |
| 406 | |
| 407 <p> | |
| 408 Particular integer values associated with Enumerated value states | |
| 409 have no meaning. They should not be used as such or in any kind of | |
| 410 math operation. Those integer values are only used by codecs to | |
| 411 transfer state from one entity to another. | |
| 412 </p> | |
| 413 | |
| 414 <a name="1.1.5"></a> | |
| 415 <h4> | |
| 416 1.1.5 Real type | |
| 417 </h4> | |
| 418 | |
| 419 <p> | |
| 420 Values of the Real type are a three-component tuple of mantissa, base and | |
| 421 exponent. All three are integers. | |
| 422 </p> | |
| 423 | |
| 424 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 425 <pre> | |
| 426 pi ::= REAL { mantissa 314159, base 10, exponent -5 } | |
| 427 </pre> | |
| 428 </td></tr></table> | |
| 429 | |
| 430 <p> | |
| 431 Corresponding pyasn1 objects can be initialized with either a three-component | |
| 432 tuple or a Python float. Infinite values could be expressed in a way, | |
| 433 compatible with Python float type. | |
| 434 | |
| 435 </p> | |
| 436 | |
| 437 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 438 <pre> | |
| 439 >>> from pyasn1.type import univ | |
| 440 >>> pi = univ.Real((314159, 10, -5)) | |
| 441 >>> pi | |
| 442 Real((314159, 10,-5)) | |
| 443 >>> float(pi) | |
| 444 3.14159 | |
| 445 >>> pi == univ.Real(3.14159) | |
| 446 True | |
| 447 >>> univ.Real('inf') | |
| 448 Real('inf') | |
| 449 >>> univ.Real('-inf') == float('-inf') | |
| 450 True | |
| 451 >>> | |
| 452 </pre> | |
| 453 </td></tr></table> | |
| 454 | |
| 455 <p> | |
| 456 If a Real object is initialized from a Python float or yielded by a math | |
| 457 operation, the base is set to decimal 10 (what affects encoding). | |
| 458 </p> | |
| 459 | |
| 460 <a name="1.1.6"></a> | |
| 461 <h4> | |
| 462 1.1.6 Bit string type | |
| 463 </h4> | |
| 464 | |
| 465 <p> | |
| 466 ASN.1 BIT STRING type holds opaque binary data of an arbitrarily length. | |
| 467 A BIT STRING value could be initialized by either a binary (base 2) or | |
| 468 hex (base 16) value. | |
| 469 </p> | |
| 470 | |
| 471 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 472 <pre> | |
| 473 public-key BIT STRING ::= '1010111011110001010110101101101 | |
| 474 1011000101010000010110101100010 | |
| 475 0110101010000111101010111111110'B | |
| 476 | |
| 477 signature BIT STRING ::= 'AF01330CD932093392100B39FF00DE0'H | |
| 478 </pre> | |
| 479 </td></tr></table> | |
| 480 | |
| 481 <p> | |
| 482 The pyasn1 BitString objects can initialize from native ASN.1 notation | |
| 483 (base 2 or base 16 strings) or from a Python tuple of binary components. | |
| 484 </p> | |
| 485 | |
| 486 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 487 <pre> | |
| 488 >>> from pyasn1.type import univ | |
| 489 >>> publicKey = univ.BitString( | |
| 490 ... "'1010111011110001010110101101101" | |
| 491 ... "1011000101010000010110101100010" | |
| 492 ... "0110101010000111101010111111110'B" | |
| 493 ) | |
| 494 >>> publicKey | |
| 495 BitString("'10101110111100010101101011011011011000101010000010110101100010\ | |
| 496 0110101010000111101010111111110'B") | |
| 497 >>> signature = univ.BitString( | |
| 498 ... "'AF01330CD932093392100B39FF00DE0'H" | |
| 499 ... ) | |
| 500 >>> signature | |
| 501 BitString("'101011110000000100110011000011001101100100110010000010010011001\ | |
| 502 1100100100001000000001011001110011111111100000000110111100000'B") | |
| 503 >>> fingerprint = univ.BitString( | |
| 504 ... (1, 0, 1, 1 ,0, 1, 1, 1, 0, 1, 0, 1) | |
| 505 ... ) | |
| 506 >>> fingerprint | |
| 507 BitString("'101101110101'B") | |
| 508 >>> | |
| 509 </pre> | |
| 510 </td></tr></table> | |
| 511 | |
| 512 <p> | |
| 513 Another BIT STRING initialization method supported by ASN.1 notation | |
| 514 is to specify only 1-th bits along with their human-friendly label | |
| 515 and bit offset relative to the beginning of the bit string. With this | |
| 516 method, all not explicitly mentioned bits are doomed to be zeros. | |
| 517 </p> | |
| 518 | |
| 519 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 520 <pre> | |
| 521 bit-mask BIT STRING ::= { | |
| 522 read-flag(0), | |
| 523 write-flag(2), | |
| 524 run-flag(4) | |
| 525 } | |
| 526 </pre> | |
| 527 </td></tr></table> | |
| 528 | |
| 529 <p> | |
| 530 To express this in pyasn1, we will employ the named values feature (as with | |
| 531 Enumeration type). | |
| 532 </p> | |
| 533 | |
| 534 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 535 <pre> | |
| 536 >>> from pyasn1.type import univ, namedval | |
| 537 >>> class BitMask(univ.BitString): | |
| 538 ... namedValues = namedval.NamedValues( | |
| 539 ... ('read-flag', 0), | |
| 540 ... ('write-flag', 2), | |
| 541 ... ('run-flag', 4) | |
| 542 ... ) | |
| 543 >>> bitMask = BitMask('read-flag,run-flag') | |
| 544 >>> bitMask | |
| 545 BitMask("'10001'B") | |
| 546 >>> tuple(bitMask) | |
| 547 (1, 0, 0, 0, 1) | |
| 548 >>> bitMask[4] | |
| 549 1 | |
| 550 >>> | |
| 551 </pre> | |
| 552 </td></tr></table> | |
| 553 | |
| 554 <p> | |
| 555 The BitString objects mimic the properties of Python tuple type in part | |
| 556 of immutable sequence object protocol support. | |
| 557 </p> | |
| 558 | |
| 559 <a name="1.1.7"></a> | |
| 560 <h4> | |
| 561 1.1.7 OctetString type | |
| 562 </h4> | |
| 563 | |
| 564 <p> | |
| 565 The OCTET STRING type is a confusing subject. According to ASN.1 | |
| 566 specification, this type is similar to BIT STRING, the major difference | |
| 567 is that the former operates in 8-bit chunks of data. What is important | |
| 568 to note, is that OCTET STRING was NOT designed to handle text strings - the | |
| 569 standard provides many other types specialized for text content. For that | |
| 570 reason, ASN.1 forbids to initialize OCTET STRING values with "quoted text | |
| 571 strings", only binary or hex initializers, similar to BIT STRING ones, | |
| 572 are allowed. | |
| 573 </p> | |
| 574 | |
| 575 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 576 <pre> | |
| 577 thumbnail OCTET STRING ::= '1000010111101110101111000000111011'B | |
| 578 thumbnail OCTET STRING ::= 'FA9823C43E43510DE3422'H | |
| 579 </pre> | |
| 580 </td></tr></table> | |
| 581 | |
| 582 <p> | |
| 583 However, ASN.1 users (e.g. protocols designers) seem to ignore the original | |
| 584 purpose of the OCTET STRING type - they used it for handling all kinds of | |
| 585 data, including text strings. | |
| 586 </p> | |
| 587 | |
| 588 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 589 <pre> | |
| 590 welcome-message OCTET STRING ::= "Welcome to ASN.1 wilderness!" | |
| 591 </pre> | |
| 592 </td></tr></table> | |
| 593 | |
| 594 <p> | |
| 595 In pyasn1, we have taken a liberal approach and allowed both BIT STRING | |
| 596 style and quoted text initializers for the OctetString objects. To avoid | |
| 597 possible collisions, quoted text is the default initialization syntax. | |
| 598 </p> | |
| 599 | |
| 600 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 601 <pre> | |
| 602 >>> from pyasn1.type import univ | |
| 603 >>> thumbnail = univ.OctetString( | |
| 604 ... binValue='1000010111101110101111000000111011' | |
| 605 ... ) | |
| 606 >>> thumbnail | |
| 607 OctetString(hexValue='85eebcec0') | |
| 608 >>> thumbnail = univ.OctetString( | |
| 609 ... hexValue='FA9823C43E43510DE3422' | |
| 610 ... ) | |
| 611 >>> thumbnail | |
| 612 OctetString(hexValue='fa9823c43e4351de34220') | |
| 613 >>> | |
| 614 </pre> | |
| 615 </td></tr></table> | |
| 616 | |
| 617 <p> | |
| 618 Most frequent usage of the OctetString class is to instantiate it with | |
| 619 a text string. | |
| 620 </p> | |
| 621 | |
| 622 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 623 <pre> | |
| 624 >>> from pyasn1.type import univ | |
| 625 >>> welcomeMessage = univ.OctetString('Welcome to ASN.1 wilderness!') | |
| 626 >>> welcomeMessage | |
| 627 OctetString(b'Welcome to ASN.1 wilderness!') | |
| 628 >>> print('%s' % welcomeMessage) | |
| 629 Welcome to ASN.1 wilderness! | |
| 630 >>> welcomeMessage[11:16] | |
| 631 OctetString(b'ASN.1') | |
| 632 >>> | |
| 633 </pre> | |
| 634 </td></tr></table> | |
| 635 | |
| 636 <p> | |
| 637 OctetString objects support the immutable sequence object protocol. | |
| 638 In other words, they behave like Python 3 bytes (or Python 2 strings). | |
| 639 </p> | |
| 640 | |
| 641 <p> | |
| 642 When running pyasn1 on Python 3, it's better to use the bytes objects for | |
| 643 OctetString instantiation, as it's more reliable and efficient. | |
| 644 </p> | |
| 645 | |
| 646 <p> | |
| 647 Additionally, OctetString's can also be instantiated with a sequence of | |
| 648 8-bit integers (ASCII codes). | |
| 649 </p> | |
| 650 | |
| 651 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 652 <pre> | |
| 653 >>> univ.OctetString((77, 101, 101, 103, 111)) | |
| 654 OctetString(b'Meego') | |
| 655 </pre> | |
| 656 </td></tr></table> | |
| 657 | |
| 658 <p> | |
| 659 It is sometimes convenient to express OctetString instances as 8-bit | |
| 660 characters (Python 3 bytes or Python 2 strings) or 8-bit integers. | |
| 661 </p> | |
| 662 | |
| 663 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 664 <pre> | |
| 665 >>> octetString = univ.OctetString('ABCDEF') | |
| 666 >>> octetString.asNumbers() | |
| 667 (65, 66, 67, 68, 69, 70) | |
| 668 >>> octetString.asOctets() | |
| 669 b'ABCDEF' | |
| 670 </pre> | |
| 671 </td></tr></table> | |
| 672 | |
| 673 <a name="1.1.8"></a> | |
| 674 <h4> | |
| 675 1.1.8 ObjectIdentifier type | |
| 676 </h4> | |
| 677 | |
| 678 <p> | |
| 679 Values of the OBJECT IDENTIFIER type are sequences of integers that could | |
| 680 be used to identify virtually anything in the world. Various ASN.1-based | |
| 681 protocols employ OBJECT IDENTIFIERs for their own identification needs. | |
| 682 </p> | |
| 683 | |
| 684 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 685 <pre> | |
| 686 internet-id OBJECT IDENTIFIER ::= { | |
| 687 iso(1) identified-organization(3) dod(6) internet(1) | |
| 688 } | |
| 689 </pre> | |
| 690 </td></tr></table> | |
| 691 | |
| 692 <p> | |
| 693 One of the natural ways to map OBJECT IDENTIFIER type into a Python | |
| 694 one is to use Python tuples of integers. So this approach is taken by | |
| 695 pyasn1. | |
| 696 </p> | |
| 697 | |
| 698 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 699 <pre> | |
| 700 >>> from pyasn1.type import univ | |
| 701 >>> internetId = univ.ObjectIdentifier((1, 3, 6, 1)) | |
| 702 >>> internetId | |
| 703 ObjectIdentifier('1.3.6.1') | |
| 704 >>> internetId[2] | |
| 705 6 | |
| 706 >>> internetId[1:3] | |
| 707 ObjectIdentifier('3.6') | |
| 708 </pre> | |
| 709 </td></tr></table> | |
| 710 | |
| 711 <p> | |
| 712 A more human-friendly "dotted" notation is also supported. | |
| 713 </p> | |
| 714 | |
| 715 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 716 <pre> | |
| 717 >>> from pyasn1.type import univ | |
| 718 >>> univ.ObjectIdentifier('1.3.6.1') | |
| 719 ObjectIdentifier('1.3.6.1') | |
| 720 </pre> | |
| 721 </td></tr></table> | |
| 722 | |
| 723 <p> | |
| 724 Symbolic names of the arcs of object identifier, sometimes present in | |
| 725 ASN.1 specifications, are not preserved and used in pyasn1 objects. | |
| 726 </p> | |
| 727 | |
| 728 <p> | |
| 729 The ObjectIdentifier objects mimic the properties of Python tuple type in | |
| 730 part of immutable sequence object protocol support. | |
| 731 </p> | |
| 732 | |
| 733 <a name="1.1.9"></a> | |
| 734 <h4> | |
| 735 1.1.9 Character string types | |
| 736 </h4> | |
| 737 | |
| 738 <p> | |
| 739 ASN.1 standard introduces a diverse set of text-specific types. All of them | |
| 740 were designed to handle various types of characters. Some of these types seem | |
| 741 be obsolete nowdays, as their target technologies are gone. Another issue | |
| 742 to be aware of is that raw OCTET STRING type is sometimes used in practice | |
| 743 by ASN.1 users instead of specialized character string types, despite | |
| 744 explicit prohibition imposed by ASN.1 specification. | |
| 745 </p> | |
| 746 | |
| 747 <p> | |
| 748 The two types are specific to ASN.1 are NumericString and PrintableString. | |
| 749 </p> | |
| 750 | |
| 751 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 752 <pre> | |
| 753 welcome-message ::= PrintableString { | |
| 754 "Welcome to ASN.1 text types" | |
| 755 } | |
| 756 | |
| 757 dial-pad-numbers ::= NumericString { | |
| 758 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" | |
| 759 } | |
| 760 </pre> | |
| 761 </td></tr></table> | |
| 762 | |
| 763 <p> | |
| 764 Their pyasn1 implementations are: | |
| 765 </p> | |
| 766 | |
| 767 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 768 <pre> | |
| 769 >>> from pyasn1.type import char | |
| 770 >>> '%s' % char.PrintableString("Welcome to ASN.1 text types") | |
| 771 'Welcome to ASN.1 text types' | |
| 772 >>> dialPadNumbers = char.NumericString( | |
| 773 "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" | |
| 774 ) | |
| 775 >>> dialPadNumbers | |
| 776 NumericString(b'0123456789') | |
| 777 >>> | |
| 778 </pre> | |
| 779 </td></tr></table> | |
| 780 | |
| 781 <p> | |
| 782 The following types came to ASN.1 from ISO standards on character sets. | |
| 783 </p> | |
| 784 | |
| 785 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 786 <pre> | |
| 787 >>> from pyasn1.type import char | |
| 788 >>> char.VisibleString("abc") | |
| 789 VisibleString(b'abc') | |
| 790 >>> char.IA5String('abc') | |
| 791 IA5String(b'abc') | |
| 792 >>> char.TeletexString('abc') | |
| 793 TeletexString(b'abc') | |
| 794 >>> char.VideotexString('abc') | |
| 795 VideotexString(b'abc') | |
| 796 >>> char.GraphicString('abc') | |
| 797 GraphicString(b'abc') | |
| 798 >>> char.GeneralString('abc') | |
| 799 GeneralString(b'abc') | |
| 800 >>> | |
| 801 </pre> | |
| 802 </td></tr></table> | |
| 803 | |
| 804 <p> | |
| 805 The last three types are relatively recent addition to the family of | |
| 806 character string types: UniversalString, BMPString, UTF8String. | |
| 807 </p> | |
| 808 | |
| 809 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 810 <pre> | |
| 811 >>> from pyasn1.type import char | |
| 812 >>> char.UniversalString("abc") | |
| 813 UniversalString(b'abc') | |
| 814 >>> char.BMPString('abc') | |
| 815 BMPString(b'abc') | |
| 816 >>> char.UTF8String('abc') | |
| 817 UTF8String(b'abc') | |
| 818 >>> utf8String = char.UTF8String('У попа была собака') | |
| 819 >>> utf8String | |
| 820 UTF8String(b'\xd0\xa3 \xd0\xbf\xd0\xbe\xd0\xbf\xd0\xb0 \xd0\xb1\xd1\x8b\xd0\xbb\
xd0\xb0 \ | |
| 821 \xd1\x81\xd0\xbe\xd0\xb1\xd0\xb0\xd0\xba\xd0\xb0') | |
| 822 >>> print(utf8String) | |
| 823 У попа была собака | |
| 824 >>> | |
| 825 </pre> | |
| 826 </td></tr></table> | |
| 827 | |
| 828 <p> | |
| 829 In pyasn1, all character type objects behave like Python strings. None of | |
| 830 them is currently constrained in terms of valid alphabet so it's up to | |
| 831 the data source to keep an eye on data validation for these types. | |
| 832 </p> | |
| 833 | |
| 834 <a name="1.1.10"></a> | |
| 835 <h4> | |
| 836 1.1.10 Useful types | |
| 837 </h4> | |
| 838 | |
| 839 <p> | |
| 840 There are three so-called useful types defined in the standard: | |
| 841 ObjectDescriptor, GeneralizedTime, UTCTime. They all are subtypes | |
| 842 of GraphicString or VisibleString types therefore useful types are | |
| 843 character string types. | |
| 844 </p> | |
| 845 | |
| 846 <p> | |
| 847 It's advised by the ASN.1 standard to have an instance of ObjectDescriptor | |
| 848 type holding a human-readable description of corresponding instance of | |
| 849 OBJECT IDENTIFIER type. There are no formal linkage between these instances | |
| 850 and provision for ObjectDescriptor uniqueness in the standard. | |
| 851 </p> | |
| 852 | |
| 853 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 854 <pre> | |
| 855 >>> from pyasn1.type import useful | |
| 856 >>> descrBER = useful.ObjectDescriptor( | |
| 857 "Basic encoding of a single ASN.1 type" | |
| 858 ) | |
| 859 >>> | |
| 860 </pre> | |
| 861 </td></tr></table> | |
| 862 | |
| 863 <p> | |
| 864 GeneralizedTime and UTCTime types are designed to hold a human-readable | |
| 865 timestamp in a universal and unambiguous form. The former provides | |
| 866 more flexibility in notation while the latter is more strict but has | |
| 867 Y2K issues. | |
| 868 </p> | |
| 869 | |
| 870 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 871 <pre> | |
| 872 ;; Mar 8 2010 12:00:00 MSK | |
| 873 moscow-time GeneralizedTime ::= "20110308120000.0" | |
| 874 ;; Mar 8 2010 12:00:00 UTC | |
| 875 utc-time GeneralizedTime ::= "201103081200Z" | |
| 876 ;; Mar 8 1999 12:00:00 UTC | |
| 877 utc-time UTCTime ::= "9803081200Z" | |
| 878 </pre> | |
| 879 </td></tr></table> | |
| 880 | |
| 881 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 882 <pre> | |
| 883 >>> from pyasn1.type import useful | |
| 884 >>> moscowTime = useful.GeneralizedTime("20110308120000.0") | |
| 885 >>> utcTime = useful.UTCTime("9803081200Z") | |
| 886 >>> | |
| 887 </pre> | |
| 888 </td></tr></table> | |
| 889 | |
| 890 <p> | |
| 891 Despite their intended use, these types possess no special, time-related, | |
| 892 handling in pyasn1. They are just printable strings. | |
| 893 </p> | |
| 894 | |
| 895 <a name="1.2"></a> | |
| 896 <h4> | |
| 897 1.2 Tagging | |
| 898 </h4> | |
| 899 | |
| 900 <p> | |
| 901 In order to continue with the Constructed ASN.1 types, we will first have | |
| 902 to introduce the concept of tagging (and its pyasn1 implementation), as | |
| 903 some of the Constructed types rely upon the tagging feature. | |
| 904 </p> | |
| 905 | |
| 906 <p> | |
| 907 When a value is coming into an ASN.1-based system (received from a network | |
| 908 or read from some storage), the receiving entity has to determine the | |
| 909 type of the value to interpret and verify it accordingly. | |
| 910 </p> | |
| 911 | |
| 912 <p> | |
| 913 Historically, the first data serialization protocol introduced in | |
| 914 ASN.1 was BER (Basic Encoding Rules). According to BER, any serialized | |
| 915 value is packed into a triplet of (Type, Length, Value) where Type is a | |
| 916 code that identifies the value (which is called <i>tag</i> in ASN.1), | |
| 917 length is the number of bytes occupied by the value in its serialized form | |
| 918 and value is ASN.1 value in a form suitable for serial transmission or storage. | |
| 919 </p> | |
| 920 | |
| 921 <p> | |
| 922 For that reason almost every ASN.1 type has a tag (which is actually a | |
| 923 BER type) associated with it by default. | |
| 924 </p> | |
| 925 | |
| 926 <p> | |
| 927 An ASN.1 tag could be viewed as a tuple of three numbers: | |
| 928 (Class, Format, Number). While Number identifies a tag, Class component | |
| 929 is used to create scopes for Numbers. Four scopes are currently defined: | |
| 930 UNIVERSAL, context-specific, APPLICATION and PRIVATE. The Format component | |
| 931 is actually a one-bit flag - zero for tags associated with scalar types, | |
| 932 and one for constructed types (will be discussed later on). | |
| 933 </p> | |
| 934 | |
| 935 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 936 <pre> | |
| 937 MyIntegerType ::= [12] INTEGER | |
| 938 MyOctetString ::= [APPLICATION 0] OCTET STRING | |
| 939 </pre> | |
| 940 </td></tr></table> | |
| 941 | |
| 942 <p> | |
| 943 In pyasn1, tags are implemented as immutable, tuple-like objects: | |
| 944 </p> | |
| 945 | |
| 946 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 947 <pre> | |
| 948 >>> from pyasn1.type import tag | |
| 949 >>> myTag = tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10) | |
| 950 >>> myTag | |
| 951 Tag(tagClass=128, tagFormat=0, tagId=10) | |
| 952 >>> tuple(myTag) | |
| 953 (128, 0, 10) | |
| 954 >>> myTag[2] | |
| 955 10 | |
| 956 >>> myTag == tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 10) | |
| 957 False | |
| 958 >>> | |
| 959 </pre> | |
| 960 </td></tr></table> | |
| 961 | |
| 962 <p> | |
| 963 Default tag, associated with any ASN.1 type, could be extended or replaced | |
| 964 to make new type distinguishable from its ancestor. The standard provides | |
| 965 two modes of tag mangling - IMPLICIT and EXPLICIT. | |
| 966 </p> | |
| 967 | |
| 968 <p> | |
| 969 EXPLICIT mode works by appending new tag to the existing ones thus creating | |
| 970 an ordered set of tags. This set will be considered as a whole for type | |
| 971 identification and encoding purposes. Important property of EXPLICIT tagging | |
| 972 mode is that it preserves base type information in encoding what makes it | |
| 973 possible to completely recover type information from encoding. | |
| 974 </p> | |
| 975 | |
| 976 <p> | |
| 977 When tagging in IMPLICIT mode, the outermost existing tag is dropped and | |
| 978 replaced with a new one. | |
| 979 </p> | |
| 980 | |
| 981 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 982 <pre> | |
| 983 MyIntegerType ::= [12] IMPLICIT INTEGER | |
| 984 MyOctetString ::= [APPLICATION 0] EXPLICIT OCTET STRING | |
| 985 </pre> | |
| 986 </td></tr></table> | |
| 987 | |
| 988 <p> | |
| 989 To model both modes of tagging, a specialized container TagSet object (holding | |
| 990 zero, one or more Tag objects) is used in pyasn1. | |
| 991 </p> | |
| 992 | |
| 993 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 994 <pre> | |
| 995 >>> from pyasn1.type import tag | |
| 996 >>> tagSet = tag.TagSet( | |
| 997 ... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10), # base tag | |
| 998 ... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10) # effective tag | |
| 999 ... ) | |
| 1000 >>> tagSet | |
| 1001 TagSet(Tag(tagClass=128, tagFormat=0, tagId=10)) | |
| 1002 >>> tagSet.getBaseTag() | |
| 1003 Tag(tagClass=128, tagFormat=0, tagId=10) | |
| 1004 >>> tagSet = tagSet.tagExplicitly( | |
| 1005 ... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 20) | |
| 1006 ... ) | |
| 1007 >>> tagSet | |
| 1008 TagSet(Tag(tagClass=128, tagFormat=0, tagId=10), | |
| 1009 Tag(tagClass=128, tagFormat=32, tagId=20)) | |
| 1010 >>> tagSet = tagSet.tagExplicitly( | |
| 1011 ... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 30) | |
| 1012 ... ) | |
| 1013 >>> tagSet | |
| 1014 TagSet(Tag(tagClass=128, tagFormat=0, tagId=10), | |
| 1015 Tag(tagClass=128, tagFormat=32, tagId=20), | |
| 1016 Tag(tagClass=128, tagFormat=32, tagId=30)) | |
| 1017 >>> tagSet = tagSet.tagImplicitly( | |
| 1018 ... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 40) | |
| 1019 ... ) | |
| 1020 >>> tagSet | |
| 1021 TagSet(Tag(tagClass=128, tagFormat=0, tagId=10), | |
| 1022 Tag(tagClass=128, tagFormat=32, tagId=20), | |
| 1023 Tag(tagClass=128, tagFormat=32, tagId=40)) | |
| 1024 >>> | |
| 1025 </pre> | |
| 1026 </td></tr></table> | |
| 1027 | |
| 1028 <p> | |
| 1029 As a side note: the "base tag" concept (accessible through the getBaseTag() | |
| 1030 method) is specific to pyasn1 -- the base tag is used to identify the original | |
| 1031 ASN.1 type of an object in question. Base tag is never occurs in encoding | |
| 1032 and is mostly used internally by pyasn1 for choosing type-specific data | |
| 1033 processing algorithms. The "effective tag" is the one that always appears in | |
| 1034 encoding and is used on tagSets comparation. | |
| 1035 </p> | |
| 1036 | |
| 1037 <p> | |
| 1038 Any two TagSet objects could be compared to see if one is a derivative | |
| 1039 of the other. Figuring this out is also useful in cases when a type-specific | |
| 1040 data processing algorithms are to be chosen. | |
| 1041 </p> | |
| 1042 | |
| 1043 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1044 <pre> | |
| 1045 >>> from pyasn1.type import tag | |
| 1046 >>> tagSet1 = tag.TagSet( | |
| 1047 ... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10) # base tag | |
| 1048 ... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10) # effective tag | |
| 1049 ... ) | |
| 1050 >>> tagSet2 = tagSet1.tagExplicitly( | |
| 1051 ... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 20) | |
| 1052 ... ) | |
| 1053 >>> tagSet1.isSuperTagSetOf(tagSet2) | |
| 1054 True | |
| 1055 >>> tagSet2.isSuperTagSetOf(tagSet1) | |
| 1056 False | |
| 1057 >>> | |
| 1058 </pre> | |
| 1059 </td></tr></table> | |
| 1060 | |
| 1061 <p> | |
| 1062 We will complete this discussion on tagging with a real-world example. The | |
| 1063 following ASN.1 tagged type: | |
| 1064 </p> | |
| 1065 | |
| 1066 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1067 <pre> | |
| 1068 MyIntegerType ::= [12] EXPLICIT INTEGER | |
| 1069 </pre> | |
| 1070 </td></tr></table> | |
| 1071 | |
| 1072 <p> | |
| 1073 could be expressed in pyasn1 like this: | |
| 1074 </p> | |
| 1075 | |
| 1076 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1077 <pre> | |
| 1078 >>> from pyasn1.type import univ, tag | |
| 1079 >>> class MyIntegerType(univ.Integer): | |
| 1080 ... tagSet = univ.Integer.tagSet.tagExplicitly( | |
| 1081 ... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 12) | |
| 1082 ... ) | |
| 1083 >>> myInteger = MyIntegerType(12345) | |
| 1084 >>> myInteger.getTagSet() | |
| 1085 TagSet(Tag(tagClass=0, tagFormat=0, tagId=2), | |
| 1086 Tag(tagClass=128, tagFormat=32, tagId=12)) | |
| 1087 >>> | |
| 1088 </pre> | |
| 1089 </td></tr></table> | |
| 1090 | |
| 1091 <p> | |
| 1092 Referring to the above code, the tagSet class attribute is a property of any | |
| 1093 pyasn1 type object that assigns default tagSet to a pyasn1 value object. This | |
| 1094 default tagSet specification can be ignored and effectively replaced by some | |
| 1095 other tagSet value passed on object instantiation. | |
| 1096 </p> | |
| 1097 | |
| 1098 <p> | |
| 1099 It's important to understand that the tag set property of pyasn1 type/value | |
| 1100 object can never be modifed in place. In other words, a pyasn1 type/value | |
| 1101 object can never change its tags. The only way is to create a new pyasn1 | |
| 1102 type/value object and associate different tag set with it. | |
| 1103 </p> | |
| 1104 | |
| 1105 | |
| 1106 <a name="1.3"></a> | |
| 1107 <h4> | |
| 1108 1.3 Constructed types | |
| 1109 </h4> | |
| 1110 | |
| 1111 <p> | |
| 1112 Besides scalar types, ASN.1 specifies so-called constructed ones - these | |
| 1113 are capable of holding one or more values of other types, both scalar | |
| 1114 and constructed. | |
| 1115 </p> | |
| 1116 | |
| 1117 <p> | |
| 1118 In pyasn1 implementation, constructed ASN.1 types behave like | |
| 1119 Python sequences, and also support additional component addressing methods, | |
| 1120 specific to particular constructed type. | |
| 1121 </p> | |
| 1122 | |
| 1123 <a name="1.3.1"></a> | |
| 1124 <h4> | |
| 1125 1.3.1 Sequence and Set types | |
| 1126 </h4> | |
| 1127 | |
| 1128 <p> | |
| 1129 The Sequence and Set types have many similar properties: | |
| 1130 </p> | |
| 1131 <ul> | |
| 1132 <li>they can hold any number of inner components of different types | |
| 1133 <li>every component has a human-friendly identifier | |
| 1134 <li>any component can have a default value | |
| 1135 <li>some components can be absent. | |
| 1136 </ul> | |
| 1137 | |
| 1138 <p> | |
| 1139 However, Sequence type guarantees the ordering of Sequence value components | |
| 1140 to match their declaration order. By contrast, components of the | |
| 1141 Set type can be ordered to best suite application's needs. | |
| 1142 <p> | |
| 1143 | |
| 1144 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1145 <pre> | |
| 1146 Record ::= SEQUENCE { | |
| 1147 id INTEGER, | |
| 1148 room [0] INTEGER OPTIONAL, | |
| 1149 house [1] INTEGER DEFAULT 0 | |
| 1150 } | |
| 1151 </pre> | |
| 1152 </td></tr></table> | |
| 1153 | |
| 1154 <p> | |
| 1155 Up to this moment, the only method we used for creating new pyasn1 types | |
| 1156 is Python sub-classing. With this method, a new, named Python class is created | |
| 1157 what mimics type derivation in ASN.1 grammar. However, ASN.1 also allows for | |
| 1158 defining anonymous subtypes (room and house components in the example above). | |
| 1159 To support anonymous subtyping in pyasn1, a cloning operation on an existing | |
| 1160 pyasn1 type object can be invoked what creates a new instance of original | |
| 1161 object with possibly modified properties. | |
| 1162 </p> | |
| 1163 | |
| 1164 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1165 <pre> | |
| 1166 >>> from pyasn1.type import univ, namedtype, tag | |
| 1167 >>> class Record(univ.Sequence): | |
| 1168 ... componentType = namedtype.NamedTypes( | |
| 1169 ... namedtype.NamedType('id', univ.Integer()), | |
| 1170 ... namedtype.OptionalNamedType( | |
| 1171 ... 'room', | |
| 1172 ... univ.Integer().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.ta
gFormatSimple, 0)) | |
| 1173 ... ), | |
| 1174 ... namedtype.DefaultedNamedType( | |
| 1175 ... 'house', | |
| 1176 ... univ.Integer(0).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.t
agFormatSimple, 1)) | |
| 1177 ... ) | |
| 1178 ... ) | |
| 1179 >>> | |
| 1180 </pre> | |
| 1181 </td></tr></table> | |
| 1182 | |
| 1183 <p> | |
| 1184 All pyasn1 constructed type classes have a class attribute <b>componentType</b> | |
| 1185 that represent default type specification. Its value is a NamedTypes object. | |
| 1186 </p> | |
| 1187 | |
| 1188 <p> | |
| 1189 The NamedTypes class instance holds a sequence of NameType, OptionalNamedType | |
| 1190 or DefaultedNamedType objects which, in turn, refer to pyasn1 type objects that | |
| 1191 represent inner SEQUENCE components specification. | |
| 1192 </p> | |
| 1193 | |
| 1194 <p> | |
| 1195 Finally, invocation of a subtype() method of pyasn1 type objects in the code | |
| 1196 above returns an implicitly tagged copy of original object. | |
| 1197 </p> | |
| 1198 | |
| 1199 <p> | |
| 1200 Once a SEQUENCE or SET type is decleared with pyasn1, it can be instantiated | |
| 1201 and initialized (continuing the above code): | |
| 1202 </p> | |
| 1203 | |
| 1204 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1205 <pre> | |
| 1206 >>> record = Record() | |
| 1207 >>> record.setComponentByName('id', 123) | |
| 1208 >>> print(record.prettyPrint()) | |
| 1209 Record: | |
| 1210 id=123 | |
| 1211 >>> | |
| 1212 >>> record.setComponentByPosition(1, 321) | |
| 1213 >>> print(record.prettyPrint()) | |
| 1214 Record: | |
| 1215 id=123 | |
| 1216 room=321 | |
| 1217 >>> | |
| 1218 >>> record.setDefaultComponents() | |
| 1219 >>> print(record.prettyPrint()) | |
| 1220 Record: | |
| 1221 id=123 | |
| 1222 room=321 | |
| 1223 house=0 | |
| 1224 </pre> | |
| 1225 </td></tr></table> | |
| 1226 | |
| 1227 <p> | |
| 1228 Inner components of pyasn1 Sequence/Set objects could be accessed using the | |
| 1229 following methods: | |
| 1230 </p> | |
| 1231 | |
| 1232 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1233 <pre> | |
| 1234 >>> record.getComponentByName('id') | |
| 1235 Integer(123) | |
| 1236 >>> record.getComponentByPosition(1) | |
| 1237 Integer(321) | |
| 1238 >>> record[2] | |
| 1239 Integer(0) | |
| 1240 >>> for idx in range(len(record)): | |
| 1241 ... print(record.getNameByPosition(idx), record.getComponentByPosition(idx)) | |
| 1242 id 123 | |
| 1243 room 321 | |
| 1244 house 0 | |
| 1245 >>> | |
| 1246 </pre> | |
| 1247 </td></tr></table> | |
| 1248 | |
| 1249 <p> | |
| 1250 The Set type share all the properties of Sequence type, and additionally | |
| 1251 support by-tag component addressing (as all Set components have distinct | |
| 1252 types). | |
| 1253 </p> | |
| 1254 | |
| 1255 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1256 <pre> | |
| 1257 >>> from pyasn1.type import univ, namedtype, tag | |
| 1258 >>> class Gamer(univ.Set): | |
| 1259 ... componentType = namedtype.NamedTypes( | |
| 1260 ... namedtype.NamedType('score', univ.Integer()), | |
| 1261 ... namedtype.NamedType('player', univ.OctetString()), | |
| 1262 ... namedtype.NamedType('id', univ.ObjectIdentifier()) | |
| 1263 ... ) | |
| 1264 >>> gamer = Gamer() | |
| 1265 >>> gamer.setComponentByType(univ.Integer().getTagSet(), 121343) | |
| 1266 >>> gamer.setComponentByType(univ.OctetString().getTagSet(), 'Pascal') | |
| 1267 >>> gamer.setComponentByType(univ.ObjectIdentifier().getTagSet(), (1,3,7,2)) | |
| 1268 >>> print(gamer.prettyPrint()) | |
| 1269 Gamer: | |
| 1270 score=121343 | |
| 1271 player=b'Pascal' | |
| 1272 id=1.3.7.2 | |
| 1273 >>> | |
| 1274 </pre> | |
| 1275 </td></tr></table> | |
| 1276 | |
| 1277 <a name="1.3.2"></a> | |
| 1278 <h4> | |
| 1279 1.3.2 SequenceOf and SetOf types | |
| 1280 </h4> | |
| 1281 | |
| 1282 <p> | |
| 1283 Both, SequenceOf and SetOf types resemble an unlimited size list of components. | |
| 1284 All the components must be of the same type. | |
| 1285 </p> | |
| 1286 | |
| 1287 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1288 <pre> | |
| 1289 Progression ::= SEQUENCE OF INTEGER | |
| 1290 | |
| 1291 arithmeticProgression Progression ::= { 1, 3, 5, 7 } | |
| 1292 </pre> | |
| 1293 </td></tr></table> | |
| 1294 | |
| 1295 <p> | |
| 1296 SequenceOf and SetOf types are expressed by the very similar pyasn1 type | |
| 1297 objects. Their components can only be addressed by position and they | |
| 1298 both have a property of automatic resize. | |
| 1299 </p> | |
| 1300 | |
| 1301 <p> | |
| 1302 To specify inner component type, the <b>componentType</b> class attribute | |
| 1303 should refer to another pyasn1 type object. | |
| 1304 </p> | |
| 1305 | |
| 1306 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1307 <pre> | |
| 1308 >>> from pyasn1.type import univ | |
| 1309 >>> class Progression(univ.SequenceOf): | |
| 1310 ... componentType = univ.Integer() | |
| 1311 >>> arithmeticProgression = Progression() | |
| 1312 >>> arithmeticProgression.setComponentByPosition(1, 111) | |
| 1313 >>> print(arithmeticProgression.prettyPrint()) | |
| 1314 Progression: | |
| 1315 -empty- 111 | |
| 1316 >>> arithmeticProgression.setComponentByPosition(0, 100) | |
| 1317 >>> print(arithmeticProgression.prettyPrint()) | |
| 1318 Progression: | |
| 1319 100 111 | |
| 1320 >>> | |
| 1321 >>> for idx in range(len(arithmeticProgression)): | |
| 1322 ... arithmeticProgression.getComponentByPosition(idx) | |
| 1323 Integer(100) | |
| 1324 Integer(111) | |
| 1325 >>> | |
| 1326 </pre> | |
| 1327 </td></tr></table> | |
| 1328 | |
| 1329 <p> | |
| 1330 Any scalar or constructed pyasn1 type object can serve as an inner component. | |
| 1331 Missing components are prohibited in SequenceOf/SetOf value objects. | |
| 1332 </p> | |
| 1333 | |
| 1334 <a name="1.3.3"></a> | |
| 1335 <h4> | |
| 1336 1.3.3 Choice type | |
| 1337 </h4> | |
| 1338 | |
| 1339 <p> | |
| 1340 Values of ASN.1 CHOICE type can contain only a single value of a type from a | |
| 1341 list of possible alternatives. Alternatives must be ASN.1 types with | |
| 1342 distinct tags for the whole structure to remain unambiguous. Unlike most | |
| 1343 other types, CHOICE is an untagged one, e.g. it has no base tag of its own. | |
| 1344 </p> | |
| 1345 | |
| 1346 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1347 <pre> | |
| 1348 CodeOrMessage ::= CHOICE { | |
| 1349 code INTEGER, | |
| 1350 message OCTET STRING | |
| 1351 } | |
| 1352 </pre> | |
| 1353 </td></tr></table> | |
| 1354 | |
| 1355 <p> | |
| 1356 In pyasn1 implementation, Choice object behaves like Set but accepts only | |
| 1357 a single inner component at a time. It also offers a few additional methods | |
| 1358 specific to its behaviour. | |
| 1359 </p> | |
| 1360 | |
| 1361 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1362 <pre> | |
| 1363 >>> from pyasn1.type import univ, namedtype | |
| 1364 >>> class CodeOrMessage(univ.Choice): | |
| 1365 ... componentType = namedtype.NamedTypes( | |
| 1366 ... namedtype.NamedType('code', univ.Integer()), | |
| 1367 ... namedtype.NamedType('message', univ.OctetString()) | |
| 1368 ... ) | |
| 1369 >>> | |
| 1370 >>> codeOrMessage = CodeOrMessage() | |
| 1371 >>> print(codeOrMessage.prettyPrint()) | |
| 1372 CodeOrMessage: | |
| 1373 >>> codeOrMessage.setComponentByName('code', 123) | |
| 1374 >>> print(codeOrMessage.prettyPrint()) | |
| 1375 CodeOrMessage: | |
| 1376 code=123 | |
| 1377 >>> codeOrMessage.setComponentByName('message', 'my string value') | |
| 1378 >>> print(codeOrMessage.prettyPrint()) | |
| 1379 CodeOrMessage: | |
| 1380 message=b'my string value' | |
| 1381 >>> | |
| 1382 </pre> | |
| 1383 </td></tr></table> | |
| 1384 | |
| 1385 <p> | |
| 1386 Since there could be only a single inner component value in the pyasn1 Choice | |
| 1387 value object, either of the following methods could be used for fetching it | |
| 1388 (continuing previous code): | |
| 1389 </p> | |
| 1390 | |
| 1391 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1392 <pre> | |
| 1393 >>> codeOrMessage.getName() | |
| 1394 'message' | |
| 1395 >>> codeOrMessage.getComponent() | |
| 1396 OctetString(b'my string value') | |
| 1397 >>> | |
| 1398 </pre> | |
| 1399 </td></tr></table> | |
| 1400 | |
| 1401 <a name="1.3.4"></a> | |
| 1402 <h4> | |
| 1403 1.3.4 Any type | |
| 1404 </h4> | |
| 1405 | |
| 1406 <p> | |
| 1407 The ASN.1 ANY type is a kind of wildcard or placeholder that matches | |
| 1408 any other type without knowing it in advance. Like CHOICE type, ANY | |
| 1409 has no base tag. | |
| 1410 </p> | |
| 1411 | |
| 1412 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1413 <pre> | |
| 1414 Error ::= SEQUENCE { | |
| 1415 code INTEGER, | |
| 1416 parameter ANY DEFINED BY code | |
| 1417 } | |
| 1418 </pre> | |
| 1419 </td></tr></table> | |
| 1420 | |
| 1421 <p> | |
| 1422 The ANY type is frequently used in specifications, where exact type is not | |
| 1423 yet agreed upon between communicating parties or the number of possible | |
| 1424 alternatives of a type is infinite. | |
| 1425 Sometimes an auxiliary selector is kept around to help parties indicate | |
| 1426 the kind of ANY payload in effect ("code" in the example above). | |
| 1427 </p> | |
| 1428 | |
| 1429 <p> | |
| 1430 Values of the ANY type contain serialized ASN.1 value(s) in form of | |
| 1431 an octet string. Therefore pyasn1 Any value object share the properties of | |
| 1432 pyasn1 OctetString object. | |
| 1433 </p> | |
| 1434 | |
| 1435 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1436 <pre> | |
| 1437 >>> from pyasn1.type import univ | |
| 1438 >>> someValue = univ.Any(b'\x02\x01\x01') | |
| 1439 >>> someValue | |
| 1440 Any(b'\x02\x01\x01') | |
| 1441 >>> str(someValue) | |
| 1442 '\x02\x01\x01' | |
| 1443 >>> bytes(someValue) | |
| 1444 b'\x02\x01\x01' | |
| 1445 >>> | |
| 1446 </pre> | |
| 1447 </td></tr></table> | |
| 1448 | |
| 1449 <p> | |
| 1450 Receiving application is supposed to explicitly deserialize the content of Any | |
| 1451 value object, possibly using auxiliary selector for figuring out its ASN.1 | |
| 1452 type to pick appropriate decoder. | |
| 1453 </p> | |
| 1454 | |
| 1455 <p> | |
| 1456 There will be some more talk and code snippets covering Any type in the codecs | |
| 1457 chapters that follow. | |
| 1458 </p> | |
| 1459 | |
| 1460 <a name="1.4"></a> | |
| 1461 <h4> | |
| 1462 1.4 Subtype constraints | |
| 1463 </h4> | |
| 1464 | |
| 1465 <p> | |
| 1466 Most ASN.1 types can correspond to an infinite set of values. To adapt to | |
| 1467 particular application's data model and needs, ASN.1 provides a mechanism | |
| 1468 for limiting the infinite set to values, that make sense in particular case. | |
| 1469 </p> | |
| 1470 | |
| 1471 <p> | |
| 1472 Imposing value constraints on an ASN.1 type can also be seen as creating | |
| 1473 a subtype from its base type. | |
| 1474 </p> | |
| 1475 | |
| 1476 <p> | |
| 1477 In pyasn1, constraints take shape of immutable objects capable | |
| 1478 of evaluating given value against constraint-specific requirements. | |
| 1479 Constraint object is a property of pyasn1 type. Like TagSet property, | |
| 1480 associated with every pyasn1 type, constraints can never be modified | |
| 1481 in place. The only way to modify pyasn1 type constraint is to associate | |
| 1482 new constraint object to a new pyasn1 type object. | |
| 1483 </p> | |
| 1484 | |
| 1485 <p> | |
| 1486 A handful of different flavors of <i>constraints</i> are defined in ASN.1. | |
| 1487 We will discuss them one by one in the following chapters and also explain | |
| 1488 how to combine and apply them to types. | |
| 1489 </p> | |
| 1490 | |
| 1491 <a name="1.4.1"></a> | |
| 1492 <h4> | |
| 1493 1.4.1 Single value constraint | |
| 1494 </h4> | |
| 1495 | |
| 1496 <p> | |
| 1497 This kind of constraint allows for limiting type to a finite, specified set | |
| 1498 of values. | |
| 1499 </p> | |
| 1500 | |
| 1501 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1502 <pre> | |
| 1503 DialButton ::= OCTET STRING ( | |
| 1504 "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | |
| 1505 ) | |
| 1506 </pre> | |
| 1507 </td></tr></table> | |
| 1508 | |
| 1509 <p> | |
| 1510 Its pyasn1 implementation would look like: | |
| 1511 </p> | |
| 1512 | |
| 1513 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1514 <pre> | |
| 1515 >>> from pyasn1.type import constraint | |
| 1516 >>> c = constraint.SingleValueConstraint( | |
| 1517 '0','1','2','3','4','5','6','7','8','9' | |
| 1518 ) | |
| 1519 >>> c | |
| 1520 SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) | |
| 1521 >>> c('0') | |
| 1522 >>> c('A') | |
| 1523 Traceback (most recent call last): | |
| 1524 ... | |
| 1525 pyasn1.type.error.ValueConstraintError: | |
| 1526 SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A | |
| 1527 >>> | |
| 1528 </pre> | |
| 1529 </td></tr></table> | |
| 1530 | |
| 1531 <p> | |
| 1532 As can be seen in the snippet above, if a value violates the constraint, an | |
| 1533 exception will be thrown. A constrainted pyasn1 type object holds a | |
| 1534 reference to a constraint object (or their combination, as will be explained | |
| 1535 later) and calls it for value verification. | |
| 1536 </p> | |
| 1537 | |
| 1538 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1539 <pre> | |
| 1540 >>> from pyasn1.type import univ, constraint | |
| 1541 >>> class DialButton(univ.OctetString): | |
| 1542 ... subtypeSpec = constraint.SingleValueConstraint( | |
| 1543 ... '0','1','2','3','4','5','6','7','8','9' | |
| 1544 ... ) | |
| 1545 >>> DialButton('0') | |
| 1546 DialButton(b'0') | |
| 1547 >>> DialButton('A') | |
| 1548 Traceback (most recent call last): | |
| 1549 ... | |
| 1550 pyasn1.type.error.ValueConstraintError: | |
| 1551 SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A | |
| 1552 >>> | |
| 1553 </pre> | |
| 1554 </td></tr></table> | |
| 1555 | |
| 1556 <p> | |
| 1557 Constrained pyasn1 value object can never hold a violating value. | |
| 1558 </p> | |
| 1559 | |
| 1560 <a name="1.4.2"></a> | |
| 1561 <h4> | |
| 1562 1.4.2 Value range constraint | |
| 1563 </h4> | |
| 1564 | |
| 1565 <p> | |
| 1566 A pair of values, compliant to a type to be constrained, denote low and upper | |
| 1567 bounds of allowed range of values of a type. | |
| 1568 </p> | |
| 1569 | |
| 1570 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1571 <pre> | |
| 1572 Teenagers ::= INTEGER (13..19) | |
| 1573 </pre> | |
| 1574 </td></tr></table> | |
| 1575 | |
| 1576 <p> | |
| 1577 And in pyasn1 terms: | |
| 1578 </p> | |
| 1579 | |
| 1580 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1581 <pre> | |
| 1582 >>> from pyasn1.type import univ, constraint | |
| 1583 >>> class Teenagers(univ.Integer): | |
| 1584 ... subtypeSpec = constraint.ValueRangeConstraint(13, 19) | |
| 1585 >>> Teenagers(14) | |
| 1586 Teenagers(14) | |
| 1587 >>> Teenagers(20) | |
| 1588 Traceback (most recent call last): | |
| 1589 ... | |
| 1590 pyasn1.type.error.ValueConstraintError: | |
| 1591 ValueRangeConstraint(13, 19) failed at: 20 | |
| 1592 >>> | |
| 1593 </pre> | |
| 1594 </td></tr></table> | |
| 1595 | |
| 1596 <p> | |
| 1597 Value range constraint usually applies numeric types. | |
| 1598 </p> | |
| 1599 | |
| 1600 <a name="1.4.3"></a> | |
| 1601 <h4> | |
| 1602 1.4.3 Size constraint | |
| 1603 </h4> | |
| 1604 | |
| 1605 <p> | |
| 1606 It is sometimes convenient to set or limit the allowed size of a data item | |
| 1607 to be sent from one application to another to manage bandwidth and memory | |
| 1608 consumption issues. Size constraint specifies the lower and upper bounds | |
| 1609 of the size of a valid value. | |
| 1610 </p> | |
| 1611 | |
| 1612 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1613 <pre> | |
| 1614 TwoBits ::= BIT STRING (SIZE (2)) | |
| 1615 </pre> | |
| 1616 </td></tr></table> | |
| 1617 | |
| 1618 <p> | |
| 1619 Express the same grammar in pyasn1: | |
| 1620 </p> | |
| 1621 | |
| 1622 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1623 <pre> | |
| 1624 >>> from pyasn1.type import univ, constraint | |
| 1625 >>> class TwoBits(univ.BitString): | |
| 1626 ... subtypeSpec = constraint.ValueSizeConstraint(2, 2) | |
| 1627 >>> TwoBits((1,1)) | |
| 1628 TwoBits("'11'B") | |
| 1629 >>> TwoBits((1,1,0)) | |
| 1630 Traceback (most recent call last): | |
| 1631 ... | |
| 1632 pyasn1.type.error.ValueConstraintError: | |
| 1633 ValueSizeConstraint(2, 2) failed at: (1, 1, 0) | |
| 1634 >>> | |
| 1635 </pre> | |
| 1636 </td></tr></table> | |
| 1637 | |
| 1638 <p> | |
| 1639 Size constraint can be applied to potentially massive values - bit or octet | |
| 1640 strings, SEQUENCE OF/SET OF values. | |
| 1641 </p> | |
| 1642 | |
| 1643 <a name="1.4.4"></a> | |
| 1644 <h4> | |
| 1645 1.4.4 Alphabet constraint | |
| 1646 </h4> | |
| 1647 | |
| 1648 <p> | |
| 1649 The permitted alphabet constraint is similar to Single value constraint | |
| 1650 but constraint applies to individual characters of a value. | |
| 1651 </p> | |
| 1652 | |
| 1653 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1654 <pre> | |
| 1655 MorseCode ::= PrintableString (FROM ("."|"-"|" ")) | |
| 1656 </pre> | |
| 1657 </td></tr></table> | |
| 1658 | |
| 1659 <p> | |
| 1660 And in pyasn1: | |
| 1661 </p> | |
| 1662 | |
| 1663 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1664 <pre> | |
| 1665 >>> from pyasn1.type import char, constraint | |
| 1666 >>> class MorseCode(char.PrintableString): | |
| 1667 ... subtypeSpec = constraint.PermittedAlphabetConstraint(".", "-", " ") | |
| 1668 >>> MorseCode("...---...") | |
| 1669 MorseCode('...---...') | |
| 1670 >>> MorseCode("?") | |
| 1671 Traceback (most recent call last): | |
| 1672 ... | |
| 1673 pyasn1.type.error.ValueConstraintError: | |
| 1674 PermittedAlphabetConstraint(".", "-", " ") failed at: "?" | |
| 1675 >>> | |
| 1676 </pre> | |
| 1677 </td></tr></table> | |
| 1678 | |
| 1679 <p> | |
| 1680 Current implementation does not handle ranges of characters in constraint | |
| 1681 (FROM "A".."Z" syntax), one has to list the whole set in a range. | |
| 1682 </p> | |
| 1683 | |
| 1684 <a name="1.4.5"></a> | |
| 1685 <h4> | |
| 1686 1.4.5 Constraint combinations | |
| 1687 </h4> | |
| 1688 | |
| 1689 <p> | |
| 1690 Up to this moment, we used a single constraint per ASN.1 type. The standard, | |
| 1691 however, allows for combining multiple individual constraints into | |
| 1692 intersections, unions and exclusions. | |
| 1693 </p> | |
| 1694 | |
| 1695 <p> | |
| 1696 In pyasn1 data model, all of these methods of constraint combinations are | |
| 1697 implemented as constraint-like objects holding individual constraint (or | |
| 1698 combination) objects. Like terminal constraint objects, combination objects | |
| 1699 are capable to perform value verification at its set of enclosed constraints | |
| 1700 according to the logic of particular combination. | |
| 1701 </p> | |
| 1702 | |
| 1703 <p> | |
| 1704 Constraints intersection verification succeeds only if a value is | |
| 1705 compliant to each constraint in a set. To begin with, the following | |
| 1706 specification will constitute a valid telephone number: | |
| 1707 </p> | |
| 1708 | |
| 1709 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1710 <pre> | |
| 1711 PhoneNumber ::= NumericString (FROM ("0".."9")) (SIZE 11) | |
| 1712 </pre> | |
| 1713 </td></tr></table> | |
| 1714 | |
| 1715 <p> | |
| 1716 Constraint intersection object serves the logic above: | |
| 1717 </p> | |
| 1718 | |
| 1719 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1720 <pre> | |
| 1721 >>> from pyasn1.type import char, constraint | |
| 1722 >>> class PhoneNumber(char.NumericString): | |
| 1723 ... subtypeSpec = constraint.ConstraintsIntersection( | |
| 1724 ... constraint.PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','
8','9'), | |
| 1725 ... constraint.ValueSizeConstraint(11, 11) | |
| 1726 ... ) | |
| 1727 >>> PhoneNumber('79039343212') | |
| 1728 PhoneNumber('79039343212') | |
| 1729 >>> PhoneNumber('?9039343212') | |
| 1730 Traceback (most recent call last): | |
| 1731 ... | |
| 1732 pyasn1.type.error.ValueConstraintError: | |
| 1733 ConstraintsIntersection( | |
| 1734 PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'), | |
| 1735 ValueSizeConstraint(11, 11)) failed at: | |
| 1736 PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9') failed a
t: "?039343212" | |
| 1737 >>> PhoneNumber('9343212') | |
| 1738 Traceback (most recent call last): | |
| 1739 ... | |
| 1740 pyasn1.type.error.ValueConstraintError: | |
| 1741 ConstraintsIntersection( | |
| 1742 PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'), | |
| 1743 ValueSizeConstraint(11, 11)) failed at: | |
| 1744 ValueSizeConstraint(10, 10) failed at: "9343212" | |
| 1745 >>> | |
| 1746 </pre> | |
| 1747 </td></tr></table> | |
| 1748 | |
| 1749 <p> | |
| 1750 Union of constraints works by making sure that a value is compliant | |
| 1751 to any of the constraint in a set. For instance: | |
| 1752 </p> | |
| 1753 | |
| 1754 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1755 <pre> | |
| 1756 CapitalOrSmall ::= IA5String (FROM ('A','B','C') | FROM ('a','b','c')) | |
| 1757 </pre> | |
| 1758 </td></tr></table> | |
| 1759 | |
| 1760 <p> | |
| 1761 It's important to note, that a value must fully comply to any single | |
| 1762 constraint in a set. In the specification above, a value of all small or | |
| 1763 all capital letters is compliant, but a mix of small&capitals is not. | |
| 1764 Here's its pyasn1 analogue: | |
| 1765 </p> | |
| 1766 | |
| 1767 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1768 <pre> | |
| 1769 >>> from pyasn1.type import char, constraint | |
| 1770 >>> class CapitalOrSmall(char.IA5String): | |
| 1771 ... subtypeSpec = constraint.ConstraintsUnion( | |
| 1772 ... constraint.PermittedAlphabetConstraint('A','B','C'), | |
| 1773 ... constraint.PermittedAlphabetConstraint('a','b','c') | |
| 1774 ... ) | |
| 1775 >>> CapitalOrSmall('ABBA') | |
| 1776 CapitalOrSmall('ABBA') | |
| 1777 >>> CapitalOrSmall('abba') | |
| 1778 CapitalOrSmall('abba') | |
| 1779 >>> CapitalOrSmall('Abba') | |
| 1780 Traceback (most recent call last): | |
| 1781 ... | |
| 1782 pyasn1.type.error.ValueConstraintError: | |
| 1783 ConstraintsUnion(PermittedAlphabetConstraint('A', 'B', 'C'), | |
| 1784 PermittedAlphabetConstraint('a', 'b', 'c')) failed at: failed for "Abba" | |
| 1785 >>> | |
| 1786 </pre> | |
| 1787 </td></tr></table> | |
| 1788 | |
| 1789 <p> | |
| 1790 Finally, the exclusion constraint simply negates the logic of value | |
| 1791 verification at a constraint. In the following example, any integer value | |
| 1792 is allowed in a type but not zero. | |
| 1793 </p> | |
| 1794 | |
| 1795 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1796 <pre> | |
| 1797 NoZero ::= INTEGER (ALL EXCEPT 0) | |
| 1798 </pre> | |
| 1799 </td></tr></table> | |
| 1800 | |
| 1801 <p> | |
| 1802 In pyasn1 the above definition would read: | |
| 1803 </p> | |
| 1804 | |
| 1805 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1806 <pre> | |
| 1807 >>> from pyasn1.type import univ, constraint | |
| 1808 >>> class NoZero(univ.Integer): | |
| 1809 ... subtypeSpec = constraint.ConstraintsExclusion( | |
| 1810 ... constraint.SingleValueConstraint(0) | |
| 1811 ... ) | |
| 1812 >>> NoZero(1) | |
| 1813 NoZero(1) | |
| 1814 >>> NoZero(0) | |
| 1815 Traceback (most recent call last): | |
| 1816 ... | |
| 1817 pyasn1.type.error.ValueConstraintError: | |
| 1818 ConstraintsExclusion(SingleValueConstraint(0)) failed at: 0 | |
| 1819 >>> | |
| 1820 </pre> | |
| 1821 </td></tr></table> | |
| 1822 | |
| 1823 <p> | |
| 1824 The depth of such a constraints tree, built with constraint combination objects | |
| 1825 at its nodes, has not explicit limit. Value verification is performed in a | |
| 1826 recursive manner till a definite solution is found. | |
| 1827 </p> | |
| 1828 | |
| 1829 <a name="1.5"></a> | |
| 1830 <h4> | |
| 1831 1.5 Types relationships | |
| 1832 </h4> | |
| 1833 | |
| 1834 <p> | |
| 1835 In the course of data processing in an application, it is sometimes | |
| 1836 convenient to figure out the type relationships between pyasn1 type or | |
| 1837 value objects. Formally, two things influence pyasn1 types relationship: | |
| 1838 <i>tag set</i> and <i>subtype constraints</i>. One pyasn1 type is considered | |
| 1839 to be a derivative of another if their TagSet and Constraint objects are | |
| 1840 a derivation of one another. | |
| 1841 </p> | |
| 1842 | |
| 1843 <p> | |
| 1844 The following example illustrates the concept (we use the same tagset but | |
| 1845 different constraints for simplicity): | |
| 1846 </p> | |
| 1847 | |
| 1848 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1849 <pre> | |
| 1850 >>> from pyasn1.type import univ, constraint | |
| 1851 >>> i1 = univ.Integer(subtypeSpec=constraint.ValueRangeConstraint(3,8)) | |
| 1852 >>> i2 = univ.Integer(subtypeSpec=constraint.ConstraintsIntersection( | |
| 1853 ... constraint.ValueRangeConstraint(3,8), | |
| 1854 ... constraint.ValueRangeConstraint(4,7) | |
| 1855 ... ) ) | |
| 1856 >>> i1.isSameTypeWith(i2) | |
| 1857 False | |
| 1858 >>> i1.isSuperTypeOf(i2) | |
| 1859 True | |
| 1860 >>> i1.isSuperTypeOf(i1) | |
| 1861 True | |
| 1862 >>> i2.isSuperTypeOf(i1) | |
| 1863 False | |
| 1864 >>> | |
| 1865 </pre> | |
| 1866 </td></tr></table> | |
| 1867 | |
| 1868 <p> | |
| 1869 As can be seen in the above code snippet, there are two methods of any pyasn1 | |
| 1870 type/value object that test types for their relationship: | |
| 1871 <b>isSameTypeWith</b>() and <b>isSuperTypeOf</b>(). The former is | |
| 1872 self-descriptive while the latter yields true if the argument appears | |
| 1873 to be a pyasn1 object which has tagset and constraints derived from those | |
| 1874 of the object being called. | |
| 1875 </p> | |
| 1876 | |
| 1877 <a name="2"></a> | |
| 1878 <h3> | |
| 1879 2. Codecs | |
| 1880 </h3> | |
| 1881 | |
| 1882 <p> | |
| 1883 In ASN.1 context, | |
| 1884 <a href=http://en.wikipedia.org/wiki/Codec>codec</a> | |
| 1885 is a program that transforms between concrete data structures and a stream | |
| 1886 of octets, suitable for transmission over the wire. This serialized form of | |
| 1887 data is sometimes called <i>substrate</i> or <i>essence</i>. | |
| 1888 </p> | |
| 1889 | |
| 1890 <p> | |
| 1891 In pyasn1 implementation, substrate takes shape of Python 3 bytes or | |
| 1892 Python 2 string objects. | |
| 1893 </p> | |
| 1894 | |
| 1895 <p> | |
| 1896 One of the properties of a codec is its ability to cope with incomplete | |
| 1897 data and/or substrate what implies codec to be stateful. In other words, | |
| 1898 when decoder runs out of substrate and data item being recovered is still | |
| 1899 incomplete, stateful codec would suspend and complete data item recovery | |
| 1900 whenever the rest of substrate becomes available. Similarly, stateful encoder | |
| 1901 would encode data items in multiple steps waiting for source data to | |
| 1902 arrive. Codec restartability is especially important when application deals | |
| 1903 with large volumes of data and/or runs on low RAM. For an interesting | |
| 1904 discussion on codecs options and design choices, refer to | |
| 1905 <a href=http://directory.apache.org/subprojects/asn1/>Apache ASN.1 project</a> | |
| 1906 . | |
| 1907 </p> | |
| 1908 | |
| 1909 <p> | |
| 1910 As of this writing, codecs implemented in pyasn1 are all stateless, mostly | |
| 1911 to keep the code simple. | |
| 1912 </p> | |
| 1913 | |
| 1914 <p> | |
| 1915 The pyasn1 package currently supports | |
| 1916 <a href=http://en.wikipedia.org/wiki/Basic_encoding_rules>BER</a> codec and | |
| 1917 its variations -- | |
| 1918 <a href=http://en.wikipedia.org/wiki/Canonical_encoding_rules>CER</a> and | |
| 1919 <a href=http://en.wikipedia.org/wiki/Distinguished_encoding_rules>DER</a>. | |
| 1920 More ASN.1 codecs are planned for implementation in the future. | |
| 1921 </p> | |
| 1922 | |
| 1923 <a name="2.1"></a> | |
| 1924 <h4> | |
| 1925 2.1 Encoders | |
| 1926 </h4> | |
| 1927 | |
| 1928 <p> | |
| 1929 Encoder is used for transforming pyasn1 value objects into substrate. Only | |
| 1930 pyasn1 value objects could be serialized, attempts to process pyasn1 type | |
| 1931 objects will cause encoder failure. | |
| 1932 </p> | |
| 1933 | |
| 1934 <p> | |
| 1935 The following code will create a pyasn1 Integer object and serialize it with | |
| 1936 BER encoder: | |
| 1937 </p> | |
| 1938 | |
| 1939 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1940 <pre> | |
| 1941 >>> from pyasn1.type import univ | |
| 1942 >>> from pyasn1.codec.ber import encoder | |
| 1943 >>> encoder.encode(univ.Integer(123456)) | |
| 1944 b'\x02\x03\x01\xe2@' | |
| 1945 >>> | |
| 1946 </pre> | |
| 1947 </td></tr></table> | |
| 1948 | |
| 1949 <p> | |
| 1950 BER standard also defines a so-called <i>indefinite length</i> encoding form | |
| 1951 which makes large data items processing more memory efficient. It is mostly | |
| 1952 useful when encoder does not have the whole value all at once and the | |
| 1953 length of the value can not be determined at the beginning of encoding. | |
| 1954 </p> | |
| 1955 | |
| 1956 <p> | |
| 1957 <i>Constructed encoding</i> is another feature of BER closely related to the | |
| 1958 indefinite length form. In essence, a large scalar value (such as ASN.1 | |
| 1959 character BitString type) could be chopped into smaller chunks by encoder | |
| 1960 and transmitted incrementally to limit memory consumption. Unlike indefinite | |
| 1961 length case, the length of the whole value must be known in advance when | |
| 1962 using constructed, definite length encoding form. | |
| 1963 </p> | |
| 1964 | |
| 1965 <p> | |
| 1966 Since pyasn1 codecs are not restartable, pyasn1 encoder may only encode data | |
| 1967 item all at once. However, even in this case, generating indefinite length | |
| 1968 encoding may help a low-memory receiver, running a restartable decoder, | |
| 1969 to process a large data item. | |
| 1970 </p> | |
| 1971 | |
| 1972 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 1973 <pre> | |
| 1974 >>> from pyasn1.type import univ | |
| 1975 >>> from pyasn1.codec.ber import encoder | |
| 1976 >>> encoder.encode( | |
| 1977 ... univ.OctetString('The quick brown fox jumps over the lazy dog'), | |
| 1978 ... defMode=False, | |
| 1979 ... maxChunkSize=8 | |
| 1980 ... ) | |
| 1981 b'$\x80\x04\x08The quic\x04\x08k brown \x04\x08fox jump\x04\x08s over \ | |
| 1982 t\x04\x08he lazy \x04\x03dog\x00\x00' | |
| 1983 >>> | |
| 1984 >>> encoder.encode( | |
| 1985 ... univ.OctetString('The quick brown fox jumps over the lazy dog'), | |
| 1986 ... maxChunkSize=8 | |
| 1987 ... ) | |
| 1988 b'$7\x04\x08The quic\x04\x08k brown \x04\x08fox jump\x04\x08s over \ | |
| 1989 t\x04\x08he lazy \x04\x03dog' | |
| 1990 </pre> | |
| 1991 </td></tr></table> | |
| 1992 | |
| 1993 <p> | |
| 1994 The <b>defMode</b> encoder parameter disables definite length encoding mode, | |
| 1995 while the optional <b>maxChunkSize</b> parameter specifies desired | |
| 1996 substrate chunk size that influences memory requirements at the decoder's end. | |
| 1997 </p> | |
| 1998 | |
| 1999 <p> | |
| 2000 To use CER or DER encoders one needs to explicitly import and call them - the | |
| 2001 APIs are all compatible. | |
| 2002 </p> | |
| 2003 | |
| 2004 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 2005 <pre> | |
| 2006 >>> from pyasn1.type import univ | |
| 2007 >>> from pyasn1.codec.ber import encoder as ber_encoder | |
| 2008 >>> from pyasn1.codec.cer import encoder as cer_encoder | |
| 2009 >>> from pyasn1.codec.der import encoder as der_encoder | |
| 2010 >>> ber_encoder.encode(univ.Boolean(True)) | |
| 2011 b'\x01\x01\x01' | |
| 2012 >>> cer_encoder.encode(univ.Boolean(True)) | |
| 2013 b'\x01\x01\xff' | |
| 2014 >>> der_encoder.encode(univ.Boolean(True)) | |
| 2015 b'\x01\x01\xff' | |
| 2016 >>> | |
| 2017 </pre> | |
| 2018 </td></tr></table> | |
| 2019 | |
| 2020 <a name="2.2"></a> | |
| 2021 <h4> | |
| 2022 2.2 Decoders | |
| 2023 </h4> | |
| 2024 | |
| 2025 <p> | |
| 2026 In the process of decoding, pyasn1 value objects are created and linked to | |
| 2027 each other, based on the information containted in the substrate. Thus, | |
| 2028 the original pyasn1 value object(s) are recovered. | |
| 2029 </p> | |
| 2030 | |
| 2031 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 2032 <pre> | |
| 2033 >>> from pyasn1.type import univ | |
| 2034 >>> from pyasn1.codec.ber import encoder, decoder | |
| 2035 >>> substrate = encoder.encode(univ.Boolean(True)) | |
| 2036 >>> decoder.decode(substrate) | |
| 2037 (Boolean('True(1)'), b'') | |
| 2038 >>> | |
| 2039 </pre> | |
| 2040 </td></tr></table> | |
| 2041 | |
| 2042 <p> | |
| 2043 Commenting on the code snippet above, pyasn1 decoder accepts substrate | |
| 2044 as an argument and returns a tuple of pyasn1 value object (possibly | |
| 2045 a top-level one in case of constructed object) and unprocessed part | |
| 2046 of input substrate. | |
| 2047 </p> | |
| 2048 | |
| 2049 <p> | |
| 2050 All pyasn1 decoders can handle both definite and indefinite length | |
| 2051 encoding modes automatically, explicit switching into one mode | |
| 2052 to another is not required. | |
| 2053 </p> | |
| 2054 | |
| 2055 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 2056 <pre> | |
| 2057 >>> from pyasn1.type import univ | |
| 2058 >>> from pyasn1.codec.ber import encoder, decoder | |
| 2059 >>> substrate = encoder.encode( | |
| 2060 ... univ.OctetString('The quick brown fox jumps over the lazy dog'), | |
| 2061 ... defMode=False, | |
| 2062 ... maxChunkSize=8 | |
| 2063 ... ) | |
| 2064 >>> decoder.decode(substrate) | |
| 2065 (OctetString(b'The quick brown fox jumps over the lazy dog'), b'') | |
| 2066 >>> | |
| 2067 </pre> | |
| 2068 </td></tr></table> | |
| 2069 | |
| 2070 <p> | |
| 2071 Speaking of BER/CER/DER encoding, in many situations substrate may not contain | |
| 2072 all necessary information needed for complete and accurate ASN.1 values | |
| 2073 recovery. The most obvious cases include implicitly tagged ASN.1 types | |
| 2074 and constrained types. | |
| 2075 </p> | |
| 2076 | |
| 2077 <p> | |
| 2078 As discussed earlier in this handbook, when an ASN.1 type is implicitly | |
| 2079 tagged, previous outermost tag is lost and never appears in substrate. | |
| 2080 If it is the base tag that gets lost, decoder is unable to pick type-specific | |
| 2081 value decoder at its table of built-in types, and therefore recover | |
| 2082 the value part, based only on the information contained in substrate. The | |
| 2083 approach taken by pyasn1 decoder is to use a prototype pyasn1 type object (or | |
| 2084 a set of them) to <i>guide</i> the decoding process by matching [possibly | |
| 2085 incomplete] tags recovered from substrate with those found in prototype pyasn1 | |
| 2086 type objects (also called pyasn1 specification object further in this paper). | |
| 2087 </p> | |
| 2088 | |
| 2089 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 2090 <pre> | |
| 2091 >>> from pyasn1.codec.ber import decoder | |
| 2092 >>> decoder.decode(b'\x02\x01\x0c', asn1Spec=univ.Integer()) | |
| 2093 Integer(12), b'' | |
| 2094 >>> | |
| 2095 </pre> | |
| 2096 </td></tr></table> | |
| 2097 | |
| 2098 <p> | |
| 2099 Decoder would neither modify pyasn1 specification object nor use | |
| 2100 its current values (if it's a pyasn1 value object), but rather use it as | |
| 2101 a hint for choosing proper decoder and as a pattern for creating new objects: | |
| 2102 </p> | |
| 2103 | |
| 2104 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 2105 <pre> | |
| 2106 >>> from pyasn1.type import univ, tag | |
| 2107 >>> from pyasn1.codec.ber import encoder, decoder | |
| 2108 >>> i = univ.Integer(12345).subtype( | |
| 2109 ... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 40) | |
| 2110 ... ) | |
| 2111 >>> substrate = encoder.encode(i) | |
| 2112 >>> substrate | |
| 2113 b'\x9f(\x0209' | |
| 2114 >>> decoder.decode(substrate) | |
| 2115 Traceback (most recent call last): | |
| 2116 ... | |
| 2117 pyasn1.error.PyAsn1Error: | |
| 2118 TagSet(Tag(tagClass=128, tagFormat=0, tagId=40)) not in asn1Spec | |
| 2119 >>> decoder.decode(substrate, asn1Spec=i) | |
| 2120 (Integer(12345), b'') | |
| 2121 >>> | |
| 2122 </pre> | |
| 2123 </td></tr></table> | |
| 2124 | |
| 2125 <p> | |
| 2126 Notice in the example above, that an attempt to run decoder without passing | |
| 2127 pyasn1 specification object fails because recovered tag does not belong | |
| 2128 to any of the built-in types. | |
| 2129 </p> | |
| 2130 | |
| 2131 <p> | |
| 2132 Another important feature of guided decoder operation is the use of | |
| 2133 values constraints possibly present in pyasn1 specification object. | |
| 2134 To explain this, we will decode a random integer object into generic Integer | |
| 2135 and the constrained one. | |
| 2136 </p> | |
| 2137 | |
| 2138 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 2139 <pre> | |
| 2140 >>> from pyasn1.type import univ, constraint | |
| 2141 >>> from pyasn1.codec.ber import encoder, decoder | |
| 2142 >>> class DialDigit(univ.Integer): | |
| 2143 ... subtypeSpec = constraint.ValueRangeConstraint(0,9) | |
| 2144 >>> substrate = encoder.encode(univ.Integer(13)) | |
| 2145 >>> decoder.decode(substrate) | |
| 2146 (Integer(13), b'') | |
| 2147 >>> decoder.decode(substrate, asn1Spec=DialDigit()) | |
| 2148 Traceback (most recent call last): | |
| 2149 ... | |
| 2150 pyasn1.type.error.ValueConstraintError: | |
| 2151 ValueRangeConstraint(0, 9) failed at: 13 | |
| 2152 >>> | |
| 2153 </pre> | |
| 2154 </td></tr></table> | |
| 2155 | |
| 2156 <p> | |
| 2157 Similarily to encoders, to use CER or DER decoders application has to | |
| 2158 explicitly import and call them - all APIs are compatible. | |
| 2159 </p> | |
| 2160 | |
| 2161 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 2162 <pre> | |
| 2163 >>> from pyasn1.type import univ | |
| 2164 >>> from pyasn1.codec.ber import encoder as ber_encoder | |
| 2165 >>> substrate = ber_encoder.encode(univ.OctetString('http://pyasn1.sf.net')) | |
| 2166 >>> | |
| 2167 >>> from pyasn1.codec.ber import decoder as ber_decoder | |
| 2168 >>> from pyasn1.codec.cer import decoder as cer_decoder | |
| 2169 >>> from pyasn1.codec.der import decoder as der_decoder | |
| 2170 >>> | |
| 2171 >>> ber_decoder.decode(substrate) | |
| 2172 (OctetString(b'http://pyasn1.sf.net'), b'') | |
| 2173 >>> cer_decoder.decode(substrate) | |
| 2174 (OctetString(b'http://pyasn1.sf.net'), b'') | |
| 2175 >>> der_decoder.decode(substrate) | |
| 2176 (OctetString(b'http://pyasn1.sf.net'), b'') | |
| 2177 >>> | |
| 2178 </pre> | |
| 2179 </td></tr></table> | |
| 2180 | |
| 2181 <a name="2.2.1"></a> | |
| 2182 <h4> | |
| 2183 2.2.1 Decoding untagged types | |
| 2184 </h4> | |
| 2185 | |
| 2186 <p> | |
| 2187 It has already been mentioned, that ASN.1 has two "special case" types: | |
| 2188 CHOICE and ANY. They are different from other types in part of | |
| 2189 tagging - unless these two are additionally tagged, neither of them will | |
| 2190 have their own tag. Therefore these types become invisible in substrate | |
| 2191 and can not be recovered without passing pyasn1 specification object to | |
| 2192 decoder. | |
| 2193 </p> | |
| 2194 | |
| 2195 <p> | |
| 2196 To explain the issue, we will first prepare a Choice object to deal with: | |
| 2197 </p> | |
| 2198 | |
| 2199 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 2200 <pre> | |
| 2201 >>> from pyasn1.type import univ, namedtype | |
| 2202 >>> class CodeOrMessage(univ.Choice): | |
| 2203 ... componentType = namedtype.NamedTypes( | |
| 2204 ... namedtype.NamedType('code', univ.Integer()), | |
| 2205 ... namedtype.NamedType('message', univ.OctetString()) | |
| 2206 ... ) | |
| 2207 >>> | |
| 2208 >>> codeOrMessage = CodeOrMessage() | |
| 2209 >>> codeOrMessage.setComponentByName('message', 'my string value') | |
| 2210 >>> print(codeOrMessage.prettyPrint()) | |
| 2211 CodeOrMessage: | |
| 2212 message=b'my string value' | |
| 2213 >>> | |
| 2214 </pre> | |
| 2215 </td></tr></table> | |
| 2216 | |
| 2217 <p> | |
| 2218 Let's now encode this Choice object and then decode its substrate | |
| 2219 with and without pyasn1 specification object: | |
| 2220 </p> | |
| 2221 | |
| 2222 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 2223 <pre> | |
| 2224 >>> from pyasn1.codec.ber import encoder, decoder | |
| 2225 >>> substrate = encoder.encode(codeOrMessage) | |
| 2226 >>> substrate | |
| 2227 b'\x04\x0fmy string value' | |
| 2228 >>> encoder.encode(univ.OctetString('my string value')) | |
| 2229 b'\x04\x0fmy string value' | |
| 2230 >>> | |
| 2231 >>> decoder.decode(substrate) | |
| 2232 (OctetString(b'my string value'), b'') | |
| 2233 >>> codeOrMessage, substrate = decoder.decode(substrate, asn1Spec=CodeOrMessage(
)) | |
| 2234 >>> print(codeOrMessage.prettyPrint()) | |
| 2235 CodeOrMessage: | |
| 2236 message=b'my string value' | |
| 2237 >>> | |
| 2238 </pre> | |
| 2239 </td></tr></table> | |
| 2240 | |
| 2241 <p> | |
| 2242 First thing to notice in the listing above is that the substrate produced | |
| 2243 for our Choice value object is equivalent to the substrate for an OctetString | |
| 2244 object initialized to the same value. In other words, any information about | |
| 2245 the Choice component is absent in encoding. | |
| 2246 </p> | |
| 2247 | |
| 2248 <p> | |
| 2249 Sure enough, that kind of substrate will decode into an OctetString object, | |
| 2250 unless original Choice type object is passed to decoder to guide the decoding | |
| 2251 process. | |
| 2252 </p> | |
| 2253 | |
| 2254 <p> | |
| 2255 Similarily untagged ANY type behaves differently on decoding phase - when | |
| 2256 decoder bumps into an Any object in pyasn1 specification, it stops decoding | |
| 2257 and puts all the substrate into a new Any value object in form of an octet | |
| 2258 string. Concerned application could then re-run decoder with an additional, | |
| 2259 more exact pyasn1 specification object to recover the contents of Any | |
| 2260 object. | |
| 2261 </p> | |
| 2262 | |
| 2263 <p> | |
| 2264 As it was mentioned elsewhere in this paper, Any type allows for incomplete | |
| 2265 or changing ASN.1 specification to be handled gracefully by decoder and | |
| 2266 applications. | |
| 2267 </p> | |
| 2268 | |
| 2269 <p> | |
| 2270 To illustrate the working of Any type, we'll have to make the stage | |
| 2271 by encoding a pyasn1 object and then putting its substrate into an any | |
| 2272 object. | |
| 2273 </p> | |
| 2274 | |
| 2275 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 2276 <pre> | |
| 2277 >>> from pyasn1.type import univ | |
| 2278 >>> from pyasn1.codec.ber import encoder, decoder | |
| 2279 >>> innerSubstrate = encoder.encode(univ.Integer(1234)) | |
| 2280 >>> innerSubstrate | |
| 2281 b'\x02\x02\x04\xd2' | |
| 2282 >>> any = univ.Any(innerSubstrate) | |
| 2283 >>> any | |
| 2284 Any(b'\x02\x02\x04\xd2') | |
| 2285 >>> substrate = encoder.encode(any) | |
| 2286 >>> substrate | |
| 2287 b'\x02\x02\x04\xd2' | |
| 2288 >>> | |
| 2289 </pre> | |
| 2290 </td></tr></table> | |
| 2291 | |
| 2292 <p> | |
| 2293 As with Choice type encoding, there is no traces of Any type in substrate. | |
| 2294 Obviously, the substrate we are dealing with, will decode into the inner | |
| 2295 [Integer] component, unless pyasn1 specification is given to guide the | |
| 2296 decoder. Continuing previous code: | |
| 2297 </p> | |
| 2298 | |
| 2299 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 2300 <pre> | |
| 2301 >>> from pyasn1.type import univ | |
| 2302 >>> from pyasn1.codec.ber import encoder, decoder | |
| 2303 | |
| 2304 >>> decoder.decode(substrate) | |
| 2305 (Integer(1234), b'') | |
| 2306 >>> any, substrate = decoder.decode(substrate, asn1Spec=univ.Any()) | |
| 2307 >>> any | |
| 2308 Any(b'\x02\x02\x04\xd2') | |
| 2309 >>> decoder.decode(str(any)) | |
| 2310 (Integer(1234), b'') | |
| 2311 >>> | |
| 2312 </pre> | |
| 2313 </td></tr></table> | |
| 2314 | |
| 2315 <p> | |
| 2316 Both CHOICE and ANY types are widely used in practice. Reader is welcome to | |
| 2317 take a look at | |
| 2318 <a href=http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt> | |
| 2319 ASN.1 specifications of X.509 applications</a> for more information. | |
| 2320 </p> | |
| 2321 | |
| 2322 <a name="2.2.2"></a> | |
| 2323 <h4> | |
| 2324 2.2.2 Ignoring unknown types | |
| 2325 </h4> | |
| 2326 | |
| 2327 <p> | |
| 2328 When dealing with a loosely specified ASN.1 structure, the receiving | |
| 2329 end may not be aware of some types present in the substrate. It may be | |
| 2330 convenient then to turn decoder into a recovery mode. Whilst there, decoder | |
| 2331 will not bail out when hit an unknown tag but rather treat it as an Any | |
| 2332 type. | |
| 2333 </p> | |
| 2334 | |
| 2335 <table bgcolor="lightgray" border=0 width=100%><TR><TD> | |
| 2336 <pre> | |
| 2337 >>> from pyasn1.type import univ, tag | |
| 2338 >>> from pyasn1.codec.ber import encoder, decoder | |
| 2339 >>> taggedInt = univ.Integer(12345).subtype( | |
| 2340 ... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 40) | |
| 2341 ... ) | |
| 2342 >>> substrate = encoder.encode(taggedInt) | |
| 2343 >>> decoder.decode(substrate) | |
| 2344 Traceback (most recent call last): | |
| 2345 ... | |
| 2346 pyasn1.error.PyAsn1Error: TagSet(Tag(tagClass=128, tagFormat=0, tagId=40)) not i
n asn1Spec | |
| 2347 >>> | |
| 2348 >>> decoder.decode.defaultErrorState = decoder.stDumpRawValue | |
| 2349 >>> decoder.decode(substrate) | |
| 2350 (Any(b'\x9f(\x0209'), '') | |
| 2351 >>> | |
| 2352 </pre> | |
| 2353 </td></tr></table> | |
| 2354 | |
| 2355 <p> | |
| 2356 It's also possible to configure a custom decoder, to handle unknown tags | |
| 2357 found in substrate. This can be done by means of <b>defaultRawDecoder</b> | |
| 2358 attribute holding a reference to type decoder object. Refer to the source | |
| 2359 for API details. | |
| 2360 </p> | |
| 2361 | |
| 2362 <a name="3"></a> | |
| 2363 <h3> | |
| 2364 3. Feedback and getting help | |
| 2365 </h3> | |
| 2366 | |
| 2367 <p> | |
| 2368 Although pyasn1 software is almost a decade old and used in many production | |
| 2369 environments, it still may have bugs and non-implemented pieces. Anyone | |
| 2370 who happens to run into such defect is welcome to complain to | |
| 2371 <a href=mailto:pyasn1-users@lists.sourceforge.net>pyasn1 mailing list</a> | |
| 2372 or better yet fix the issue and send | |
| 2373 <a href=mailto:ilya@glas.net>me</a> the patch. | |
| 2374 </p> | |
| 2375 | |
| 2376 <p> | |
| 2377 Typically, pyasn1 is used for building arbitrary protocol support into | |
| 2378 various applications. This involves manual translation of ASN.1 data | |
| 2379 structures into their pyasn1 implementations. To save time and effort, | |
| 2380 data structures for some of the popular protocols are pre-programmed | |
| 2381 and kept for further re-use in form of the | |
| 2382 <a href=http://sourceforge.net/projects/pyasn1/files/pyasn1-modules/> | |
| 2383 pyasn1-modules package</a>. For instance, many structures for PKI (X.509, | |
| 2384 PKCS#*, CRMF, OCSP), LDAP and SNMP are present. | |
| 2385 Applications authors are advised to import and use relevant modules | |
| 2386 from that package whenever needed protocol structures are already | |
| 2387 there. New protocol modules contributions are welcome. | |
| 2388 </p> | |
| 2389 | |
| 2390 <p> | |
| 2391 And finally, the latest pyasn1 package revision is available for free | |
| 2392 download from | |
| 2393 <a href=http://sourceforge.net/projects/pyasn1/>project home</a> and | |
| 2394 also from the | |
| 2395 <a href=http://pypi.python.org/pypi>Python package repository</a>. | |
| 2396 </p> | |
| 2397 | |
| 2398 <hr> | |
| 2399 | |
| 2400 </td> | |
| 2401 </tr> | |
| 2402 </table> | |
| 2403 </center> | |
| 2404 </body> | |
| 2405 </html> | |
| OLD | NEW |