• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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