| <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> |