Home | History | Annotate | Download | only in doc
      1 <html>
      2 <title>
      3 PyASN1 Constructed types
      4 </title>
      5 <head>
      6 </head>
      7 <body>
      8 <center>
      9 <table width=60%>
     10 <tr>
     11 <td>
     12 
     13 <h4>
     14 1.3 PyASN1 Constructed types
     15 </h4>
     16 
     17 <p>
     18 Besides scalar types, ASN.1 specifies so-called constructed ones - these
     19 are capable of holding one or more values of other types, both scalar
     20 and constructed.
     21 </p>
     22 
     23 <p>
     24 In pyasn1 implementation, constructed ASN.1 types behave like 
     25 Python sequences, and also support additional component addressing methods,
     26 specific to particular constructed type.
     27 </p>
     28 
     29 <a name="1.3.1"></a>
     30 <h4>
     31 1.3.1 Sequence and Set types
     32 </h4>
     33 
     34 <p>
     35 The Sequence and Set types have many similar properties:
     36 </p>
     37 <ul>
     38 <li>they can hold any number of inner components of different types
     39 <li>every component has a human-friendly identifier
     40 <li>any component can have a default value
     41 <li>some components can be absent.
     42 </ul>
     43 
     44 <p>
     45 However, Sequence type guarantees the ordering of Sequence value components
     46 to match their declaration order. By contrast, components of the
     47 Set type can be ordered to best suite application's needs.
     48 <p>
     49 
     50 <table bgcolor="lightgray" border=0 width=100%><TR><TD>
     51 <pre>
     52 Record ::= SEQUENCE {
     53   id        INTEGER,
     54   room  [0] INTEGER OPTIONAL,
     55   house [1] INTEGER DEFAULT 0
     56 }
     57 </pre>
     58 </td></tr></table>
     59 
     60 <p>
     61 Up to this moment, the only method we used for creating new pyasn1 types
     62 is Python sub-classing. With this method, a new, named Python class is created
     63 what mimics type derivation in ASN.1 grammar. However, ASN.1 also allows for
     64 defining anonymous subtypes (room and house components in the example above).
     65 To support anonymous subtyping in pyasn1, a cloning operation on an existing
     66 pyasn1 type object can be invoked what creates a new instance of original
     67 object with possibly modified properties.
     68 </p>
     69 
     70 <table bgcolor="lightgray" border=0 width=100%><TR><TD>
     71 <pre>
     72 >>> from pyasn1.type import univ, namedtype, tag
     73 >>> class Record(univ.Sequence):
     74 ...   componentType = namedtype.NamedTypes(
     75 ...     namedtype.NamedType('id', univ.Integer()),
     76 ...     namedtype.OptionalNamedType(
     77 ...       'room',
     78 ...       univ.Integer().subtype(
     79 ...         implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)
     80 ...       )
     81 ...     ),
     82 ...     namedtype.DefaultedNamedType(
     83 ...       'house', 
     84 ...       univ.Integer(0).subtype(
     85 ...         implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)
     86 ...       )
     87 ...     )
     88 ...   )
     89 >>>
     90 </pre>
     91 </td></tr></table>
     92 
     93 <p>
     94 All pyasn1 constructed type classes have a class attribute <b>componentType</b>
     95 that represent default type specification. Its value is a NamedTypes object.
     96 </p>
     97 
     98 <p>
     99 The NamedTypes class instance holds a sequence of NameType, OptionalNamedType
    100 or DefaultedNamedType objects which, in turn, refer to pyasn1 type objects that
    101 represent inner SEQUENCE components specification.
    102 </p>
    103 
    104 <p>
    105 Finally, invocation of a subtype() method of pyasn1 type objects in the code
    106 above returns an implicitly tagged copy of original object.
    107 </p>
    108 
    109 <p>
    110 Once a SEQUENCE or SET type is decleared with pyasn1, it can be instantiated
    111 and initialized (continuing the above code):
    112 </p>
    113 
    114 <table bgcolor="lightgray" border=0 width=100%><TR><TD>
    115 <pre>
    116 >>> record = Record()
    117 >>> record.setComponentByName('id', 123)
    118 >>> print(record.prettyPrint())
    119 Record:
    120  id=123
    121 >>> 
    122 >>> record.setComponentByPosition(1, 321)
    123 >>> print(record.prettyPrint())
    124 Record:
    125  id=123
    126  room=321
    127 >>>
    128 >>> record.setDefaultComponents()
    129 >>> print(record.prettyPrint())
    130 Record:
    131  id=123
    132  room=321
    133  house=0
    134 </pre>
    135 </td></tr></table>
    136 
    137 <p>
    138 Inner components of pyasn1 Sequence/Set objects could be accessed using the
    139 following methods:
    140 </p>
    141 
    142 <table bgcolor="lightgray" border=0 width=100%><TR><TD>
    143 <pre>
    144 >>> record.getComponentByName('id')
    145 Integer(123)
    146 >>> record.getComponentByPosition(1)
    147 Integer(321)
    148 >>> record[2]
    149 Integer(0)
    150 >>> for idx in range(len(record)):
    151 ...   print(record.getNameByPosition(idx), record.getComponentByPosition(idx))
    152 id 123
    153 room 321
    154 house 0
    155 >>>
    156 </pre>
    157 </td></tr></table>
    158 
    159 <p>
    160 The Set type share all the properties of Sequence type, and additionally
    161 support by-tag component addressing (as all Set components have distinct
    162 types).
    163 </p>
    164 
    165 <table bgcolor="lightgray" border=0 width=100%><TR><TD>
    166 <pre>
    167 >>> from pyasn1.type import univ, namedtype, tag
    168 >>> class Gamer(univ.Set):
    169 ...   componentType = namedtype.NamedTypes(
    170 ...     namedtype.NamedType('score', univ.Integer()),
    171 ...     namedtype.NamedType('player', univ.OctetString()),
    172 ...     namedtype.NamedType('id', univ.ObjectIdentifier())
    173 ...   )
    174 >>> gamer = Gamer()
    175 >>> gamer.setComponentByType(univ.Integer().getTagSet(), 121343)
    176 >>> gamer.setComponentByType(univ.OctetString().getTagSet(), 'Pascal')
    177 >>> gamer.setComponentByType(univ.ObjectIdentifier().getTagSet(), (1,3,7,2))
    178 >>> print(gamer.prettyPrint())
    179 Gamer:
    180  score=121343
    181  player=b'Pascal'
    182  id=1.3.7.2
    183 >>>
    184 </pre>
    185 </td></tr></table>
    186 
    187 <a name="1.3.2"></a>
    188 <h4>
    189 1.3.2 SequenceOf and SetOf types
    190 </h4>
    191 
    192 <p>
    193 Both, SequenceOf and SetOf types resemble an unlimited size list of components.
    194 All the components must be of the same type.
    195 </p>
    196 
    197 <table bgcolor="lightgray" border=0 width=100%><TR><TD>
    198 <pre>
    199 Progression ::= SEQUENCE OF INTEGER
    200 
    201 arithmeticProgression Progression ::= { 1, 3, 5, 7 }
    202 </pre>
    203 </td></tr></table>
    204 
    205 <p>
    206 SequenceOf and SetOf types are expressed by the very similar pyasn1 type 
    207 objects. Their components can only be addressed by position and they
    208 both have a property of automatic resize.
    209 </p>
    210 
    211 <p>
    212 To specify inner component type, the <b>componentType</b> class attribute
    213 should refer to another pyasn1 type object.
    214 </p>
    215 
    216 <table bgcolor="lightgray" border=0 width=100%><TR><TD>
    217 <pre>
    218 >>> from pyasn1.type import univ
    219 >>> class Progression(univ.SequenceOf):
    220 ...   componentType = univ.Integer()
    221 >>> arithmeticProgression = Progression()
    222 >>> arithmeticProgression.setComponentByPosition(1, 111)
    223 >>> print(arithmeticProgression.prettyPrint())
    224 Progression:
    225 -empty- 111
    226 >>> arithmeticProgression.setComponentByPosition(0, 100)
    227 >>> print(arithmeticProgression.prettyPrint())
    228 Progression:
    229 100 111
    230 >>>
    231 >>> for idx in range(len(arithmeticProgression)):
    232 ...    arithmeticProgression.getComponentByPosition(idx)
    233 Integer(100)
    234 Integer(111)
    235 >>>
    236 </pre>
    237 </td></tr></table>
    238 
    239 <p>
    240 Any scalar or constructed pyasn1 type object can serve as an inner component.
    241 Missing components are prohibited in SequenceOf/SetOf value objects.
    242 </p>
    243 
    244 <a name="1.3.3"></a>
    245 <h4>
    246 1.3.3 Choice type
    247 </h4>
    248 
    249 <p>
    250 Values of ASN.1 CHOICE type can contain only a single value of a type from a 
    251 list of possible alternatives. Alternatives must be ASN.1 types with
    252 distinct tags for the whole structure to remain unambiguous. Unlike most
    253 other types, CHOICE is an untagged one, e.g. it has no base tag of its own.
    254 </p>
    255 
    256 <table bgcolor="lightgray" border=0 width=100%><TR><TD>
    257 <pre>
    258 CodeOrMessage ::= CHOICE {
    259   code    INTEGER,
    260   message OCTET STRING
    261 }
    262 </pre>
    263 </td></tr></table>
    264 
    265 <p>
    266 In pyasn1 implementation, Choice object behaves like Set but accepts only
    267 a single inner component at a time. It also offers a few additional methods
    268 specific to its behaviour.
    269 </p>
    270 
    271 <table bgcolor="lightgray" border=0 width=100%><TR><TD>
    272 <pre>
    273 >>> from pyasn1.type import univ, namedtype
    274 >>> class CodeOrMessage(univ.Choice):
    275 ...   componentType = namedtype.NamedTypes(
    276 ...     namedtype.NamedType('code', univ.Integer()),
    277 ...     namedtype.NamedType('message', univ.OctetString())
    278 ...   )
    279 >>>
    280 >>> codeOrMessage = CodeOrMessage()
    281 >>> print(codeOrMessage.prettyPrint())
    282 CodeOrMessage:
    283 >>> codeOrMessage.setComponentByName('code', 123)
    284 >>> print(codeOrMessage.prettyPrint())
    285 CodeOrMessage:
    286  code=123
    287 >>> codeOrMessage.setComponentByName('message', 'my string value')
    288 >>> print(codeOrMessage.prettyPrint())
    289 CodeOrMessage:
    290  message=b'my string value'
    291 >>>
    292 </pre>
    293 </td></tr></table>
    294 
    295 <p>
    296 Since there could be only a single inner component value in the pyasn1 Choice
    297 value object, either of the following methods could be used for fetching it
    298 (continuing previous code):
    299 </p>
    300 
    301 <table bgcolor="lightgray" border=0 width=100%><TR><TD>
    302 <pre>
    303 >>> codeOrMessage.getName()
    304 'message'
    305 >>> codeOrMessage.getComponent()
    306 OctetString(b'my string value')
    307 >>>
    308 </pre>
    309 </td></tr></table>
    310 
    311 <a name="1.3.4"></a>
    312 <h4>
    313 1.3.4 Any type
    314 </h4>
    315 
    316 <p>
    317 The ASN.1 ANY type is a kind of wildcard or placeholder that matches
    318 any other type without knowing it in advance. Like CHOICE type, ANY
    319 has no base tag.
    320 </p>
    321 
    322 <table bgcolor="lightgray" border=0 width=100%><TR><TD>
    323 <pre>
    324 Error ::= SEQUENCE {
    325   code      INTEGER,
    326   parameter ANY DEFINED BY code
    327 }
    328 </pre>
    329 </td></tr></table>
    330 
    331 <p>
    332 The ANY type is frequently used in specifications, where exact type is not
    333 yet agreed upon between communicating parties or the number of possible
    334 alternatives of a type is infinite.
    335 Sometimes an auxiliary selector is kept around to help parties indicate
    336 the kind of ANY payload in effect ("code" in the example above).
    337 </p>
    338 
    339 <p>
    340 Values of the ANY type contain serialized ASN.1 value(s) in form of
    341 an octet string. Therefore pyasn1 Any value object share the properties of
    342 pyasn1 OctetString object.
    343 </p>
    344 
    345 <table bgcolor="lightgray" border=0 width=100%><TR><TD>
    346 <pre>
    347 >>> from pyasn1.type import univ
    348 >>> someValue = univ.Any(b'\x02\x01\x01')
    349 >>> someValue
    350 Any(b'\x02\x01\x01')
    351 >>> str(someValue)
    352 '\x02\x01\x01'
    353 >>> bytes(someValue)
    354 b'\x02\x01\x01'
    355 >>>
    356 </pre>
    357 </td></tr></table>
    358 
    359 <p>
    360 Receiving application is supposed to explicitly deserialize the content of Any
    361 value object, possibly using auxiliary selector for figuring out its ASN.1
    362 type to pick appropriate decoder.
    363 </p>
    364 
    365 <p>
    366 There will be some more talk and code snippets covering Any type in the codecs
    367 chapters that follow.
    368 </p>
    369 
    370 <hr>
    371 
    372 </td>
    373 </tr>
    374 </table>
    375 </center>
    376 </body>
    377 </html>
    378