| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- <html>
- <title>
- PyASN1 Constructed types
- </title>
- <head>
- </head>
- <body>
- <center>
- <table width=60%>
- <tr>
- <td>
- <h4>
- 1.3 PyASN1 Constructed types
- </h4>
- <p>
- Besides scalar types, ASN.1 specifies so-called constructed ones - these
- are capable of holding one or more values of other types, both scalar
- and constructed.
- </p>
- <p>
- In pyasn1 implementation, constructed ASN.1 types behave like
- Python sequences, and also support additional component addressing methods,
- specific to particular constructed type.
- </p>
- <a name="1.3.1"></a>
- <h4>
- 1.3.1 Sequence and Set types
- </h4>
- <p>
- The Sequence and Set types have many similar properties:
- </p>
- <ul>
- <li>they can hold any number of inner components of different types
- <li>every component has a human-friendly identifier
- <li>any component can have a default value
- <li>some components can be absent.
- </ul>
- <p>
- However, Sequence type guarantees the ordering of Sequence value components
- to match their declaration order. By contrast, components of the
- Set type can be ordered to best suite application's needs.
- <p>
- <table bgcolor="lightgray" border=0 width=100%><TR><TD>
- <pre>
- Record ::= SEQUENCE {
- id INTEGER,
- room [0] INTEGER OPTIONAL,
- house [1] INTEGER DEFAULT 0
- }
- </pre>
- </td></tr></table>
- <p>
- Up to this moment, the only method we used for creating new pyasn1 types
- is Python sub-classing. With this method, a new, named Python class is created
- what mimics type derivation in ASN.1 grammar. However, ASN.1 also allows for
- defining anonymous subtypes (room and house components in the example above).
- To support anonymous subtyping in pyasn1, a cloning operation on an existing
- pyasn1 type object can be invoked what creates a new instance of original
- object with possibly modified properties.
- </p>
- <table bgcolor="lightgray" border=0 width=100%><TR><TD>
- <pre>
- >>> from pyasn1.type import univ, namedtype, tag
- >>> class Record(univ.Sequence):
- ... componentType = namedtype.NamedTypes(
- ... namedtype.NamedType('id', univ.Integer()),
- ... namedtype.OptionalNamedType(
- ... 'room',
- ... univ.Integer().subtype(
- ... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)
- ... )
- ... ),
- ... namedtype.DefaultedNamedType(
- ... 'house',
- ... univ.Integer(0).subtype(
- ... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)
- ... )
- ... )
- ... )
- >>>
- </pre>
- </td></tr></table>
- <p>
- All pyasn1 constructed type classes have a class attribute <b>componentType</b>
- that represent default type specification. Its value is a NamedTypes object.
- </p>
- <p>
- The NamedTypes class instance holds a sequence of NameType, OptionalNamedType
- or DefaultedNamedType objects which, in turn, refer to pyasn1 type objects that
- represent inner SEQUENCE components specification.
- </p>
- <p>
- Finally, invocation of a subtype() method of pyasn1 type objects in the code
- above returns an implicitly tagged copy of original object.
- </p>
- <p>
- Once a SEQUENCE or SET type is decleared with pyasn1, it can be instantiated
- and initialized (continuing the above code):
- </p>
- <table bgcolor="lightgray" border=0 width=100%><TR><TD>
- <pre>
- >>> record = Record()
- >>> record.setComponentByName('id', 123)
- >>> print(record.prettyPrint())
- Record:
- id=123
- >>>
- >>> record.setComponentByPosition(1, 321)
- >>> print(record.prettyPrint())
- Record:
- id=123
- room=321
- >>>
- >>> record.setDefaultComponents()
- >>> print(record.prettyPrint())
- Record:
- id=123
- room=321
- house=0
- </pre>
- </td></tr></table>
- <p>
- Inner components of pyasn1 Sequence/Set objects could be accessed using the
- following methods:
- </p>
- <table bgcolor="lightgray" border=0 width=100%><TR><TD>
- <pre>
- >>> record.getComponentByName('id')
- Integer(123)
- >>> record.getComponentByPosition(1)
- Integer(321)
- >>> record[2]
- Integer(0)
- >>> for idx in range(len(record)):
- ... print(record.getNameByPosition(idx), record.getComponentByPosition(idx))
- id 123
- room 321
- house 0
- >>>
- </pre>
- </td></tr></table>
- <p>
- The Set type share all the properties of Sequence type, and additionally
- support by-tag component addressing (as all Set components have distinct
- types).
- </p>
- <table bgcolor="lightgray" border=0 width=100%><TR><TD>
- <pre>
- >>> from pyasn1.type import univ, namedtype, tag
- >>> class Gamer(univ.Set):
- ... componentType = namedtype.NamedTypes(
- ... namedtype.NamedType('score', univ.Integer()),
- ... namedtype.NamedType('player', univ.OctetString()),
- ... namedtype.NamedType('id', univ.ObjectIdentifier())
- ... )
- >>> gamer = Gamer()
- >>> gamer.setComponentByType(univ.Integer().getTagSet(), 121343)
- >>> gamer.setComponentByType(univ.OctetString().getTagSet(), 'Pascal')
- >>> gamer.setComponentByType(univ.ObjectIdentifier().getTagSet(), (1,3,7,2))
- >>> print(gamer.prettyPrint())
- Gamer:
- score=121343
- player=b'Pascal'
- id=1.3.7.2
- >>>
- </pre>
- </td></tr></table>
- <a name="1.3.2"></a>
- <h4>
- 1.3.2 SequenceOf and SetOf types
- </h4>
- <p>
- Both, SequenceOf and SetOf types resemble an unlimited size list of components.
- All the components must be of the same type.
- </p>
- <table bgcolor="lightgray" border=0 width=100%><TR><TD>
- <pre>
- Progression ::= SEQUENCE OF INTEGER
- arithmeticProgression Progression ::= { 1, 3, 5, 7 }
- </pre>
- </td></tr></table>
- <p>
- SequenceOf and SetOf types are expressed by the very similar pyasn1 type
- objects. Their components can only be addressed by position and they
- both have a property of automatic resize.
- </p>
- <p>
- To specify inner component type, the <b>componentType</b> class attribute
- should refer to another pyasn1 type object.
- </p>
- <table bgcolor="lightgray" border=0 width=100%><TR><TD>
- <pre>
- >>> from pyasn1.type import univ
- >>> class Progression(univ.SequenceOf):
- ... componentType = univ.Integer()
- >>> arithmeticProgression = Progression()
- >>> arithmeticProgression.setComponentByPosition(1, 111)
- >>> print(arithmeticProgression.prettyPrint())
- Progression:
- -empty- 111
- >>> arithmeticProgression.setComponentByPosition(0, 100)
- >>> print(arithmeticProgression.prettyPrint())
- Progression:
- 100 111
- >>>
- >>> for idx in range(len(arithmeticProgression)):
- ... arithmeticProgression.getComponentByPosition(idx)
- Integer(100)
- Integer(111)
- >>>
- </pre>
- </td></tr></table>
- <p>
- Any scalar or constructed pyasn1 type object can serve as an inner component.
- Missing components are prohibited in SequenceOf/SetOf value objects.
- </p>
- <a name="1.3.3"></a>
- <h4>
- 1.3.3 Choice type
- </h4>
- <p>
- Values of ASN.1 CHOICE type can contain only a single value of a type from a
- list of possible alternatives. Alternatives must be ASN.1 types with
- distinct tags for the whole structure to remain unambiguous. Unlike most
- other types, CHOICE is an untagged one, e.g. it has no base tag of its own.
- </p>
- <table bgcolor="lightgray" border=0 width=100%><TR><TD>
- <pre>
- CodeOrMessage ::= CHOICE {
- code INTEGER,
- message OCTET STRING
- }
- </pre>
- </td></tr></table>
- <p>
- In pyasn1 implementation, Choice object behaves like Set but accepts only
- a single inner component at a time. It also offers a few additional methods
- specific to its behaviour.
- </p>
- <table bgcolor="lightgray" border=0 width=100%><TR><TD>
- <pre>
- >>> from pyasn1.type import univ, namedtype
- >>> class CodeOrMessage(univ.Choice):
- ... componentType = namedtype.NamedTypes(
- ... namedtype.NamedType('code', univ.Integer()),
- ... namedtype.NamedType('message', univ.OctetString())
- ... )
- >>>
- >>> codeOrMessage = CodeOrMessage()
- >>> print(codeOrMessage.prettyPrint())
- CodeOrMessage:
- >>> codeOrMessage.setComponentByName('code', 123)
- >>> print(codeOrMessage.prettyPrint())
- CodeOrMessage:
- code=123
- >>> codeOrMessage.setComponentByName('message', 'my string value')
- >>> print(codeOrMessage.prettyPrint())
- CodeOrMessage:
- message=b'my string value'
- >>>
- </pre>
- </td></tr></table>
- <p>
- Since there could be only a single inner component value in the pyasn1 Choice
- value object, either of the following methods could be used for fetching it
- (continuing previous code):
- </p>
- <table bgcolor="lightgray" border=0 width=100%><TR><TD>
- <pre>
- >>> codeOrMessage.getName()
- 'message'
- >>> codeOrMessage.getComponent()
- OctetString(b'my string value')
- >>>
- </pre>
- </td></tr></table>
- <a name="1.3.4"></a>
- <h4>
- 1.3.4 Any type
- </h4>
- <p>
- The ASN.1 ANY type is a kind of wildcard or placeholder that matches
- any other type without knowing it in advance. Like CHOICE type, ANY
- has no base tag.
- </p>
- <table bgcolor="lightgray" border=0 width=100%><TR><TD>
- <pre>
- Error ::= SEQUENCE {
- code INTEGER,
- parameter ANY DEFINED BY code
- }
- </pre>
- </td></tr></table>
- <p>
- The ANY type is frequently used in specifications, where exact type is not
- yet agreed upon between communicating parties or the number of possible
- alternatives of a type is infinite.
- Sometimes an auxiliary selector is kept around to help parties indicate
- the kind of ANY payload in effect ("code" in the example above).
- </p>
- <p>
- Values of the ANY type contain serialized ASN.1 value(s) in form of
- an octet string. Therefore pyasn1 Any value object share the properties of
- pyasn1 OctetString object.
- </p>
- <table bgcolor="lightgray" border=0 width=100%><TR><TD>
- <pre>
- >>> from pyasn1.type import univ
- >>> someValue = univ.Any(b'\x02\x01\x01')
- >>> someValue
- Any(b'\x02\x01\x01')
- >>> str(someValue)
- '\x02\x01\x01'
- >>> bytes(someValue)
- b'\x02\x01\x01'
- >>>
- </pre>
- </td></tr></table>
- <p>
- Receiving application is supposed to explicitly deserialize the content of Any
- value object, possibly using auxiliary selector for figuring out its ASN.1
- type to pick appropriate decoder.
- </p>
- <p>
- There will be some more talk and code snippets covering Any type in the codecs
- chapters that follow.
- </p>
- <hr>
- </td>
- </tr>
- </table>
- </center>
- </body>
- </html>
|