summaryrefslogtreecommitdiff
path: root/docs/source/pyasn1/contents.rst
blob: eaa78358f317e75f9e3010693142dcadc1e2540f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228

.. _pyasn1:

Library documentation
=====================

As of this moment, pyasn1 library implements all ASN.1 data
types as Python objects in accordance with X.208 standard. Later,
post-1995, revision (X.680) introduced some changes to the schema
language which may not be fully supported by pyasn1. Aside from data
types a collection of data transformation codecs comes with the
pyasn1 package.

As for ASN.1 schema language, pyasn1 package does
not ship any compiler for it. However, there's a tool called
`asn1late <https://github.com/kimgr/asn1ate>`_ which is an ASN.1
grammar parser paired to code generator capable of generating pyasn1
code. So this is an alternative (or at least a good start) to manual
implementation of pyasn1 classes from ASN.1 specification.

Both `pyasn1 <https://github.com/etingof/pyasn1>`_ and
`pyasn1-modules <https://github.com/etingof/pyasn1-modules>`_ libraries
can be used out-of-the-box with Python versions 2.4 through 3.7.
No external dependencies required.

.. _pyasn1-types:

ASN.1 types
-----------

The ASN.1 data description
`language <https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-X.208-198811-W!!PDF-E&type=items>`_
defines a handful of built-in data types. ASN.1 types exhibit different
semantics (e.g. number vs string) and can be distinguished from each other by
:ref:`tags <type.tag>`.

Subtypes can be created on top of base ASN.1 types by adding/overriding the
:ref:`tags <type.tag>` and/or imposing additional
:ref:`constraints <type.constraint>` on accepted values.

ASN.1 types in pyasn1 are Python objects. One or more ASN.1 types
comprise a *schema* describing data structures of unbounded complexity.

.. code-block:: python

   class RSAPublicKey(Sequence):
       """
       ASN.1 specification:

       RSAPublicKey ::= SEQUENCE {
           modulus           INTEGER,  -- n
           publicExponent    INTEGER   -- e
       }
       """
       componentType = NamedTypes(
           NamedType('modulus', Integer()),
           NamedType('publicExponent', Integer())
       )

ASN.1 schema can be "instantiated" by essentially putting some concrete value
into the type container. Such instantiated schema object can still be
used as a schema, but additionally it can play a role of a value in the
context of any applicable operator (e.g. arithmetic etc.).

.. code-block:: python

   rsaPublicKey = RSAPublicKey()

   # ASN.1 SEQUENCE type quacks like Python dict
   rsaPublicKey['modulus'] = 280789907761334970323210643584308373
   rsaPublicKey['publicExponent'] = 65537

Main use of ASN.1 schemas is to guide data transformation. Instantiated
ASN.1 schemas carry concrete data to/from data transformation services.

.. _isValue:

To tell instantiated schema object from just a schema, the *.isValue*
property can come in handy:

.. code-block:: python

   schema = RSAPublicKey()

   # non-instantiated schema
   assert schema.isValue == False

   rsaPublicKey['modulus'] = 280789907761334970323210643584308373

   # partially instantiated schema
   assert schema['modulus'].isValue == True
   assert schema.isValue == False

   rsaPublicKey['publicExponent'] = 65537

   # fully instantiated schema
   assert schema.isValue == True

Copies of existing ASN.1 types can be created with *.clone()* method.
All the existing properties of the prototype ASN.1 object get copied
over the new type unless the replacements are given. Main use-case
for *.clone()* is to instantiate a schema.

.. _clone:

.. code-block:: python

   instantiated_schema_A = Integer(1)

   # ASN.1 INTEGER type quacks like Python int
   assert instantiated_schema_A == 1

   instantiated_schema_B = instantiated_schema_A.clone(2)

   assert instantiated_schema_B == 2

.. _subtype:

New ASN.1 types can be created on top of existing ASN.1 types with
the *subtype()* method. Desired properties of the new type get
merged with the corresponding properties of the old type. Main use-case
for *.subtype()* is to assemble new ASN.1 types by :ref:`tagging <type.tag>`
or applying additional :ref:`constraints <type.constraint>` to accepted
type's values.

.. code-block:: python

   parent_type_schema = Integer()

   child_type_schema = parent_type_schema.subtype(
       explicitTag=Tag(tag.tagClassApplication, tag.tagFormatSimple, 0x06)
   )

   # test ASN.1 type relationships
   assert child_type_schema.isSubtypeOf(parent_type_schema) == True
   assert child_type_schema.isSameTypeWith(parent_type_schema) == False


.. toctree::
   :maxdepth: 2

   /pyasn1/type/base/contents
   /pyasn1/type/univ/contents
   /pyasn1/type/char/contents
   /pyasn1/type/useful/contents

ASN.1 type harness
++++++++++++++++++

The identification and behaviour of ASN.1 types is determined by
:ref:`tags <type.tag>` and :ref:`constraints <type.constraint>`.
The inner structure of *constructed* ASN.1 types is defined by
its :ref:`fields <type.namedtype>` specification.

.. toctree::
   :maxdepth: 2

   /pyasn1/type/tag/contents
   /pyasn1/type/constraint/contents
   /pyasn1/type/namedtype/contents
   /pyasn1/type/opentype/contents
   /pyasn1/type/namedval/contents

.. _pyasn1-codecs:

Serialisation codecs
--------------------

Common use-case for pyasn1 is to instantiate ASN.1 schema with
user-supplied values and pass instantiated schema to the encoder.
The encoder will then turn the data structure into serialised form
(stream of bytes) suitable for storing into a file or sending over
the network.

.. code-block:: python

    value = 1
    instantiated_schema = Integer(value)

    serialised = encode(instantiated_schema)

Alternatively, value and schema can be passed separately:

.. code-block:: python

    value = 1
    schema = Integer()

    serialised = encode(value, asn1Spec=schema)

At the receiving end, a decoder would be invoked and given the
serialised data as received from the network along with the ASN.1
schema describing the layout of the data structures. The outcome
would be an instance of ASN.1 schema filled with values as supplied
by the sender.

.. code-block:: python

    serialised = b'\x01\x01\x01'
    schema = Integer()

    value, _ = decode(serialised, asn1Spec=schema)

    assert value == 1

Many distinct serialisation protocols exist for ASN.1, some are
implemented in pyasn1.

.. toctree::
   :maxdepth: 2

   /pyasn1/codec/ber/contents
   /pyasn1/codec/cer/contents
   /pyasn1/codec/der/contents
   /pyasn1/codec/native/contents

Exceptions
----------

Operations on PyASN1 schema and value objects might cause errors. These
errors are manifested to the caller in form of Python exceptions.

The exception hierarchy is as follows (ordered from least specific).

.. toctree::
   :maxdepth: 2

   /pyasn1/error/contents