1<html> 2<title> 3PyASN1 Constructed types 4</title> 5<head> 6</head> 7<body> 8<center> 9<table width=60%> 10<tr> 11<td> 12 13<h4> 141.3 PyASN1 Constructed types 15</h4> 16 17<p> 18Besides scalar types, ASN.1 specifies so-called constructed ones - these 19are capable of holding one or more values of other types, both scalar 20and constructed. 21</p> 22 23<p> 24In pyasn1 implementation, constructed ASN.1 types behave like 25Python sequences, and also support additional component addressing methods, 26specific to particular constructed type. 27</p> 28 29<a name="1.3.1"></a> 30<h4> 311.3.1 Sequence and Set types 32</h4> 33 34<p> 35The 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> 45However, Sequence type guarantees the ordering of Sequence value components 46to match their declaration order. By contrast, components of the 47Set 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> 52Record ::= 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> 61Up to this moment, the only method we used for creating new pyasn1 types 62is Python sub-classing. With this method, a new, named Python class is created 63what mimics type derivation in ASN.1 grammar. However, ASN.1 also allows for 64defining anonymous subtypes (room and house components in the example above). 65To support anonymous subtyping in pyasn1, a cloning operation on an existing 66pyasn1 type object can be invoked what creates a new instance of original 67object 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> 94All pyasn1 constructed type classes have a class attribute <b>componentType</b> 95that represent default type specification. Its value is a NamedTypes object. 96</p> 97 98<p> 99The NamedTypes class instance holds a sequence of NameType, OptionalNamedType 100or DefaultedNamedType objects which, in turn, refer to pyasn1 type objects that 101represent inner SEQUENCE components specification. 102</p> 103 104<p> 105Finally, invocation of a subtype() method of pyasn1 type objects in the code 106above returns an implicitly tagged copy of original object. 107</p> 108 109<p> 110Once a SEQUENCE or SET type is decleared with pyasn1, it can be instantiated 111and 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()) 119Record: 120 id=123 121>>> 122>>> record.setComponentByPosition(1, 321) 123>>> print(record.prettyPrint()) 124Record: 125 id=123 126 room=321 127>>> 128>>> record.setDefaultComponents() 129>>> print(record.prettyPrint()) 130Record: 131 id=123 132 room=321 133 house=0 134</pre> 135</td></tr></table> 136 137<p> 138Inner components of pyasn1 Sequence/Set objects could be accessed using the 139following methods: 140</p> 141 142<table bgcolor="lightgray" border=0 width=100%><TR><TD> 143<pre> 144>>> record.getComponentByName('id') 145Integer(123) 146>>> record.getComponentByPosition(1) 147Integer(321) 148>>> record[2] 149Integer(0) 150>>> for idx in range(len(record)): 151... print(record.getNameByPosition(idx), record.getComponentByPosition(idx)) 152id 123 153room 321 154house 0 155>>> 156</pre> 157</td></tr></table> 158 159<p> 160The Set type share all the properties of Sequence type, and additionally 161support by-tag component addressing (as all Set components have distinct 162types). 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()) 179Gamer: 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> 1891.3.2 SequenceOf and SetOf types 190</h4> 191 192<p> 193Both, SequenceOf and SetOf types resemble an unlimited size list of components. 194All the components must be of the same type. 195</p> 196 197<table bgcolor="lightgray" border=0 width=100%><TR><TD> 198<pre> 199Progression ::= SEQUENCE OF INTEGER 200 201arithmeticProgression Progression ::= { 1, 3, 5, 7 } 202</pre> 203</td></tr></table> 204 205<p> 206SequenceOf and SetOf types are expressed by the very similar pyasn1 type 207objects. Their components can only be addressed by position and they 208both have a property of automatic resize. 209</p> 210 211<p> 212To specify inner component type, the <b>componentType</b> class attribute 213should 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()) 224Progression: 225-empty- 111 226>>> arithmeticProgression.setComponentByPosition(0, 100) 227>>> print(arithmeticProgression.prettyPrint()) 228Progression: 229100 111 230>>> 231>>> for idx in range(len(arithmeticProgression)): 232... arithmeticProgression.getComponentByPosition(idx) 233Integer(100) 234Integer(111) 235>>> 236</pre> 237</td></tr></table> 238 239<p> 240Any scalar or constructed pyasn1 type object can serve as an inner component. 241Missing components are prohibited in SequenceOf/SetOf value objects. 242</p> 243 244<a name="1.3.3"></a> 245<h4> 2461.3.3 Choice type 247</h4> 248 249<p> 250Values of ASN.1 CHOICE type can contain only a single value of a type from a 251list of possible alternatives. Alternatives must be ASN.1 types with 252distinct tags for the whole structure to remain unambiguous. Unlike most 253other 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> 258CodeOrMessage ::= CHOICE { 259 code INTEGER, 260 message OCTET STRING 261} 262</pre> 263</td></tr></table> 264 265<p> 266In pyasn1 implementation, Choice object behaves like Set but accepts only 267a single inner component at a time. It also offers a few additional methods 268specific 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()) 282CodeOrMessage: 283>>> codeOrMessage.setComponentByName('code', 123) 284>>> print(codeOrMessage.prettyPrint()) 285CodeOrMessage: 286 code=123 287>>> codeOrMessage.setComponentByName('message', 'my string value') 288>>> print(codeOrMessage.prettyPrint()) 289CodeOrMessage: 290 message=b'my string value' 291>>> 292</pre> 293</td></tr></table> 294 295<p> 296Since there could be only a single inner component value in the pyasn1 Choice 297value 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() 306OctetString(b'my string value') 307>>> 308</pre> 309</td></tr></table> 310 311<a name="1.3.4"></a> 312<h4> 3131.3.4 Any type 314</h4> 315 316<p> 317The ASN.1 ANY type is a kind of wildcard or placeholder that matches 318any other type without knowing it in advance. Like CHOICE type, ANY 319has no base tag. 320</p> 321 322<table bgcolor="lightgray" border=0 width=100%><TR><TD> 323<pre> 324Error ::= SEQUENCE { 325 code INTEGER, 326 parameter ANY DEFINED BY code 327} 328</pre> 329</td></tr></table> 330 331<p> 332The ANY type is frequently used in specifications, where exact type is not 333yet agreed upon between communicating parties or the number of possible 334alternatives of a type is infinite. 335Sometimes an auxiliary selector is kept around to help parties indicate 336the kind of ANY payload in effect ("code" in the example above). 337</p> 338 339<p> 340Values of the ANY type contain serialized ASN.1 value(s) in form of 341an octet string. Therefore pyasn1 Any value object share the properties of 342pyasn1 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 350Any(b'\x02\x01\x01') 351>>> str(someValue) 352'\x02\x01\x01' 353>>> bytes(someValue) 354b'\x02\x01\x01' 355>>> 356</pre> 357</td></tr></table> 358 359<p> 360Receiving application is supposed to explicitly deserialize the content of Any 361value object, possibly using auxiliary selector for figuring out its ASN.1 362type to pick appropriate decoder. 363</p> 364 365<p> 366There will be some more talk and code snippets covering Any type in the codecs 367chapters that follow. 368</p> 369 370<hr> 371 372</td> 373</tr> 374</table> 375</center> 376</body> 377</html> 378