]> Cypherpunks.ru repositories - pyderasn.git/blob - doc/examples.rst
Ability to set values during Sequence initialization
[pyderasn.git] / doc / examples.rst
1 Examples
2 ========
3
4 .. contents::
5
6 Schema definition
7 -----------------
8
9 Let's try to parse X.509 certificate. We have to define our structures
10 based on ASN.1 schema descriptions.
11
12 .. list-table::
13    :header-rows: 1
14
15    * - ASN.1 specification
16      - pyderasn's code
17    * - ::
18
19             Certificate  ::=  SEQUENCE  {
20                 tbsCertificate       TBSCertificate,
21                 signatureAlgorithm   AlgorithmIdentifier,
22                 signatureValue       BIT STRING  }
23      - ::
24
25             class Certificate(Sequence):
26                 schema = (
27                     ("tbsCertificate", TBSCertificate()),
28                     ("signatureAlgorithm", AlgorithmIdentifier()),
29                     ("signatureValue", BitString()),
30                 )
31    * - ::
32
33             AlgorithmIdentifier  ::=  SEQUENCE  {
34                 algorithm    OBJECT IDENTIFIER,
35                 parameters   ANY DEFINED BY algorithm OPTIONAL  }
36      - ::
37
38             class AlgorithmIdentifier(Sequence):
39                 schema = (
40                     ("algorithm", ObjectIdentifier()),
41                     ("parameters", Any(optional=True)),
42                 )
43    * - ::
44
45             TBSCertificate  ::=  SEQUENCE  {
46                 version         [0]  EXPLICIT Version DEFAULT v1,
47                 serialNumber         CertificateSerialNumber,
48                 signature            AlgorithmIdentifier,
49                 issuer               Name,
50                 validity             Validity,
51                 subject              Name,
52                 subjectPublicKeyInfo SubjectPublicKeyInfo,
53                 issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
54                 subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
55                 extensions      [3]  EXPLICIT Extensions OPTIONAL  }
56      - ::
57
58             class TBSCertificate(Sequence):
59                 schema = (
60                     ("version", Version(expl=tag_ctxc(0), default="v1")),
61                     ("serialNumber", CertificateSerialNumber()),
62                     ("signature", AlgorithmIdentifier()),
63                     ("issuer", Name()),
64                     ("validity", Validity()),
65                     ("subject", Name()),
66                     ("subjectPublicKeyInfo", SubjectPublicKeyInfo()),
67                     ("issuerUniqueID", UniqueIdentifier(impl=tag_ctxp(1), optional=True)),
68                     ("subjectUniqueID", UniqueIdentifier(impl=tag_ctxp(2), optional=True)),
69                     ("extensions", Extensions(expl=tag_ctxc(3), optional=True)),
70                 )
71    * - ::
72
73             Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
74      - ::
75
76             class Version(Integer):
77                 schema = (("v1", 0), ("v2", 1), ("v3", 2))
78    * - ::
79
80             CertificateSerialNumber  ::=  INTEGER
81      - ::
82
83             class CertificateSerialNumber(Integer):
84                 pass
85    * - ::
86
87             Validity ::= SEQUENCE {
88                 notBefore      Time,
89                 notAfter       Time }
90             Time ::= CHOICE {
91                 utcTime        UTCTime,
92                 generalTime    GeneralizedTime }
93      - ::
94
95             class Validity(Sequence):
96                 schema = (
97                     ("notBefore", Time()),
98                     ("notAfter", Time()),
99                 )
100             class Time(Choice):
101                 schema = (
102                     ("utcTime", UTCTime()),
103                     ("generalTime", GeneralizedTime()),
104                 )
105    * - ::
106
107             SubjectPublicKeyInfo  ::=  SEQUENCE  {
108                 algorithm            AlgorithmIdentifier,
109                 subjectPublicKey     BIT STRING  }
110      - ::
111
112             class SubjectPublicKeyInfo(Sequence):
113                 schema = (
114                     ("algorithm", AlgorithmIdentifier()),
115                     ("subjectPublicKey", BitString()),
116                 )
117    * - ::
118
119             UniqueIdentifier  ::=  BIT STRING
120      - ::
121
122             class UniqueIdentifier(BitString):
123                 pass
124    * - ::
125
126             Name ::= CHOICE { rdnSequence  RDNSequence }
127
128             RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
129
130             RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
131
132             AttributeTypeAndValue ::= SEQUENCE { type AttributeType, value AttributeValue }
133
134             AttributeType ::= OBJECT IDENTIFIER
135
136             AttributeValue ::= ANY -- DEFINED BY AttributeType
137      - ::
138
139             class Name(Choice):
140                 schema = (("rdnSequence", RDNSequence()),)
141             class RDNSequence(SequenceOf):
142                 schema = RelativeDistinguishedName()
143             class RelativeDistinguishedName(SetOf):
144                 schema = AttributeTypeAndValue()
145                 bounds = (1, float("+inf"))
146             class AttributeTypeAndValue(Sequence):
147                 schema = (
148                     ("type", AttributeType()),
149                     ("value", AttributeValue()),
150                 )
151             class AttributeType(ObjectIdentifier):
152                 pass
153             class AttributeValue(Any):
154                 pass
155    * - ::
156
157             Extensions ::=  SEQUENCE SIZE (1..MAX) OF Extension
158
159             Extension  ::=  SEQUENCE  {
160                 extnID      OBJECT IDENTIFIER,
161                 critical    BOOLEAN DEFAULT FALSE,
162                 extnValue   OCTET STRING
163                 }
164      - ::
165
166             class Extensions(SequenceOf):
167                 schema = Extension()
168                 bounds = (1, float("+inf"))
169             class Extension(Sequence):
170                 schema = (
171                     ("extnID", ObjectIdentifier()),
172                     ("critical", Boolean(default=False)),
173                     ("extnValue", OctetString()),
174                 )
175
176 We are ready to decode PayPal's certificate from Go `encoding/asn1
177 <https://golang.org/pkg/encoding/asn1/>`__ test suite (assuming that
178 it's DER encoded representation is already in ``raw`` variable)::
179
180     >>> crt, tail = Certificate().decode(raw)
181     >>> crt
182     Certificate SEQUENCE[TBSCertificate SEQUENCE[[0] EXPLICIT Version
183         INTEGER v3 OPTIONAL, CertificateSerialNumber INTEGER 61595,
184         AlgorithmIdentifier SEQUENCE[OBJECT IDENTIFIER 1.2.840.113549.1.1.5...
185
186 Pretty printing
187 ---------------
188
189 There is huge output. Let's pretty print it::
190
191     >>> print(pprint(crt))
192         0   [1,3,1604] Certificate SEQUENCE
193         4   [1,3,1453]  . tbsCertificate: TBSCertificate SEQUENCE
194        10-2 [1,1,   1]  . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
195        13   [1,1,   3]  . . serialNumber: CertificateSerialNumber INTEGER 61595
196        18   [1,1,  13]  . . signature: AlgorithmIdentifier SEQUENCE
197        20   [1,1,   9]  . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
198        31   [0,0,   2]  . . . parameters: [UNIV 5] ANY OPTIONAL
199                         . . . . 05:00
200        33   [0,0, 278]  . . issuer: Name CHOICE rdnSequence
201        33   [1,3, 274]  . . . rdnSequence: RDNSequence SEQUENCE OF
202        37   [1,1,  11]  . . . . 0: RelativeDistinguishedName SET OF
203        39   [1,1,   9]  . . . . . 0: AttributeTypeAndValue SEQUENCE
204        41   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
205        46   [0,0,   4]  . . . . . . value: [UNIV 19] AttributeValue ANY
206                         . . . . . . . 13:02:45:53
207     [...]
208      1461   [1,1,  13]  . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
209      1463   [1,1,   9]  . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
210      1474   [0,0,   2]  . . parameters: [UNIV 5] ANY OPTIONAL
211                         . . . 05:00
212      1476   [1,2, 129]  . signatureValue: BIT STRING 1024 bits
213                         . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
214                         . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
215      [...]
216
217     Trailing data: 0a
218
219 Let's parse that output, human::
220
221        10-2 [1,1,   1]  . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
222        ^  ^  ^ ^    ^   ^   ^        ^            ^       ^       ^  ^
223        0  1  2 3    4   5   6        7            8       9       10 11
224
225 ::
226
227        20   [1,1,   9]  . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
228        ^     ^ ^    ^   ^     ^          ^                 ^
229        0     2 3    4   5     6          9                 10
230
231 ::
232
233        33   [0,0, 278]  . . issuer: Name CHOICE rdnSequence
234        ^     ^ ^    ^   ^   ^       ^    ^      ^
235        0     2 3    4   5   6       8    9      10
236
237 :0:
238  Offset of the object, where its DER encoding begins.
239  Pay attention that it does **not** include explicit tag.
240 :1:
241  If explicit tag exists, then this is its length (tag + encoded length).
242 :2:
243  Length of object's tag. For example CHOICE does not have its own tag,
244  so it is zero.
245 :3:
246  Length of encoded length.
247 :4:
248  Length of encoded value.
249 :5:
250  Visual indentation to show the depth of object in the hierarchy.
251 :6:
252  Object's name inside SEQUENCE/CHOICE.
253 :7:
254  If either IMPLICIT or EXPLICIT tag is set, then it will be shown
255  here. "IMPLICIT" is omitted.
256 :8:
257  Object's class name, if set. Omitted if it is just an ordinary simple
258  value (like with ``algorithm`` in example above).
259 :9:
260  Object's ASN.1 type.
261 :10:
262  Object's value, if set. Can consist of multiple words (like OCTET/BIT
263  STRINGs above). We see ``v3`` value in Version, because it is named.
264  ``rdnSequence`` is the choice of CHOICE type.
265 :11:
266  Possible other flags like OPTIONAL and DEFAULT, if value equals to the
267  default one, specified in the schema.
268
269 As command line utility
270 -----------------------
271
272 You can decode DER files using command line abilities and get the same
273 picture as above by executing::
274
275     % python -m pyderasn --schema tests.test_crts:Certificate path/to/file
276
277 If there is no schema for you file, then you can try parsing it without,
278 but of course IMPLICIT tags will often make it impossible. But result is
279 good enough for the certificate above::
280
281     % python -m pyderasn path/to/file
282         0   [1,3,1604]  . >: SEQUENCE OF
283         4   [1,3,1453]  . . >: SEQUENCE OF
284         8   [0,0,   5]  . . . . >: [0] ANY
285                         . . . . . A0:03:02:01:02
286        13   [1,1,   3]  . . . . >: INTEGER 61595
287        18   [1,1,  13]  . . . . >: SEQUENCE OF
288        20   [1,1,   9]  . . . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
289        31   [1,1,   0]  . . . . . . >: NULL
290        33   [1,3, 274]  . . . . >: SEQUENCE OF
291        37   [1,1,  11]  . . . . . . >: SET OF
292        39   [1,1,   9]  . . . . . . . . >: SEQUENCE OF
293        41   [1,1,   3]  . . . . . . . . . . >: OBJECT IDENTIFIER 2.5.4.6
294        46   [1,1,   2]  . . . . . . . . . . >: PrintableString PrintableString ES
295     [...]
296      1409   [1,1,  50]  . . . . . . >: SEQUENCE OF
297      1411   [1,1,   8]  . . . . . . . . >: OBJECT IDENTIFIER 1.3.6.1.5.5.7.1.1
298      1421   [1,1,  38]  . . . . . . . . >: OCTET STRING 38 bytes
299                         . . . . . . . . . 30:24:30:22:06:08:2B:06:01:05:05:07:30:01:86:16
300                         . . . . . . . . . 68:74:74:70:3A:2F:2F:6F:63:73:70:2E:69:70:73:63
301                         . . . . . . . . . 61:2E:63:6F:6D:2F
302      1461   [1,1,  13]  . . >: SEQUENCE OF
303      1463   [1,1,   9]  . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
304      1474   [1,1,   0]  . . . . >: NULL
305      1476   [1,2, 129]  . . >: BIT STRING 1024 bits
306                         . . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
307                         . . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
308     [...]
309
310 If you have got dictionaries with ObjectIdentifiers, like example one
311 from ``tests/test_crts.py``::
312
313     some_oids = {
314         "1.2.840.113549.1.1.1": "id-rsaEncryption",
315         "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
316         [...]
317         "2.5.4.10": "id-at-organizationName",
318         "2.5.4.11": "id-at-organizationalUnitName",
319     }
320
321 then you can pass it to pretty printer to see human readable OIDs::
322
323     % python -m pyderasn --oids tests.test_crts:some_oids path/to/file
324     [...]
325        37   [1,1,  11]  . . . . . . >: SET OF
326        39   [1,1,   9]  . . . . . . . . >: SEQUENCE OF
327        41   [1,1,   3]  . . . . . . . . . . >: OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
328        46   [1,1,   2]  . . . . . . . . . . >: PrintableString PrintableString ES
329        50   [1,1,  18]  . . . . . . >: SET OF
330        52   [1,1,  16]  . . . . . . . . >: SEQUENCE OF
331        54   [1,1,   3]  . . . . . . . . . . >: OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
332        59   [1,1,   9]  . . . . . . . . . . >: PrintableString PrintableString Barcelona
333        70   [1,1,  18]  . . . . . . >: SET OF
334        72   [1,1,  16]  . . . . . . . . >: SEQUENCE OF
335        74   [1,1,   3]  . . . . . . . . . . >: OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
336        79   [1,1,   9]  . . . . . . . . . . >: PrintableString PrintableString Barcelona
337     [...]
338
339 Descriptive errors
340 ------------------
341
342 If you have bad DER, then errors will show you where error occurred::
343
344     % python -m pyderasn --schema tests.test_crts:Certificate path/to/bad/file
345     Traceback (most recent call last):
346     [...]
347     pyderasn.DecodeError: UTCTime (tbsCertificate.validity.notAfter.utcTime) (at 328) invalid UTCTime format
348
349 ::
350
351     % python -m pyderasn path/to/bad/file
352     [...]
353     pyderasn.DecodeError: UTCTime (0.SequenceOf.4.SequenceOf.1.UTCTime) (at 328) invalid UTCTime format
354
355 You can see, so called, decode path inside the structures:
356 ``tbsCertificate`` -> ``validity`` -> ``notAfter`` -> ``utcTime`` and
357 that object at byte 328 is invalid.
358
359 X.509 certificate creation
360 --------------------------
361
362 Let's create some simple self-signed X.509 certificate from the ground::
363
364     tbs = TBSCertificate()
365     tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
366
367     sign_algo_id = AlgorithmIdentifier((
368         ("algorithm", ObjectIdentifier("1.2.840.113549.1.1.5")),
369         ("parameters", Any(Null())),
370     ))
371     tbs["signature"] = sign_algo_id
372
373     rdnSeq = RDNSequence()
374     for oid, klass, text in (
375             ("2.5.4.6", PrintableString, "XX"),
376             ("2.5.4.8", PrintableString, "Some-State"),
377             ("2.5.4.7", PrintableString, "City"),
378             ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
379             ("2.5.4.3", PrintableString, "false.example.com"),
380             ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
381     ):
382         rdnSeq.append(
383             RelativeDistinguishedName((
384                 AttributeTypeAndValue((
385                     ("type", AttributeType(oid)),
386                     ("value", AttributeValue(klass(text))),
387                 )),
388             ))
389         )
390     issuer = Name(("rdnSequence", rdnSeq))
391     tbs["issuer"] = issuer
392     tbs["subject"] = issuer
393
394     validity = Validity((
395         ("notBefore", Time(
396             ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53))),
397         )),
398         ("notAfter", Time(
399             ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53))),
400         )),
401     ))
402     tbs["validity"] = validity
403
404     spki = SubjectPublicKeyInfo()
405     spki_algo_id = sign_algo_id.copy()
406     spki_algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
407     spki["algorithm"] = spki_algo_id
408     spki["subjectPublicKey"] = BitString(hexdec("".join((
409         "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
410         "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
411         "deec357d0203010001",
412     ))))
413     tbs["subjectPublicKeyInfo"] = spki
414
415     crt = Certificate()
416     crt["tbsCertificate"] = tbs
417     crt["signatureAlgorithm"] = sign_algo_id
418     crt["signatureValue"] = BitString(hexdec("".join((
419         "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
420         "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
421     ))))
422     crt.encode()
423
424 And we will get the same certificate used in Go's library tests.
425
426 DEFINED BY fields
427 -----------------
428
429 Here is only very simple example how you can define Any/OctetString
430 fields automatic decoding::
431
432     class AttributeTypeAndValue(Sequence):
433         schema = (
434             ((("type",), AttributeType(defines=("value", {
435                 id_at_countryName: PrintableString(),
436                 id_at_stateOrProvinceName: PrintableString(),
437                 id_at_localityName: PrintableString(),
438                 id_at_organizationName: PrintableString(),
439                 id_at_commonName: PrintableString(),
440             }))),),
441             ("value", AttributeValue()),
442         )
443
444 And when you will try to decode X.509 certificate with it, your pretty
445 printer will show::
446
447        34   [0,0, 149]  . . issuer: Name CHOICE rdnSequence
448        34   [1,2, 146]  . . . rdnSequence: RDNSequence SEQUENCE OF
449        37   [1,1,  11]  . . . . 0: RelativeDistinguishedName SET OF
450        39   [1,1,   9]  . . . . . 0: AttributeTypeAndValue SEQUENCE
451        41   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
452        46   [0,0,   4]  . . . . . . value: [UNIV 19] AttributeValue ANY
453                         . . . . . . . 13:02:58:58
454        46   [1,1,   2]  . . . . . . . DEFINED BY (2.5.4.6): PrintableString PrintableString XX
455        50   [1,1,  19]  . . . . 1: RelativeDistinguishedName SET OF
456        52   [1,1,  17]  . . . . . 0: AttributeTypeAndValue SEQUENCE
457        54   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
458        59   [0,0,  12]  . . . . . . value: [UNIV 19] AttributeValue ANY
459                         . . . . . . . 13:0A:53:6F:6D:65:2D:53:74:61:74:65
460        59   [1,1,  10]  . . . . . . . DEFINED BY (2.5.4.8): PrintableString PrintableString Some-State
461        71   [1,1,  13]  . . . . 2: RelativeDistinguishedName SET OF
462        73   [1,1,  11]  . . . . . 0: AttributeTypeAndValue SEQUENCE
463        75   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
464        80   [0,0,   6]  . . . . . . value: [UNIV 19] AttributeValue ANY
465                         . . . . . . . 13:04:43:69:74:79
466        80   [1,1,   4]  . . . . . . . DEFINED BY (2.5.4.7): PrintableString PrintableString City
467        86   [1,1,  33]  . . . . 3: RelativeDistinguishedName SET OF
468        88   [1,1,  31]  . . . . . 0: AttributeTypeAndValue SEQUENCE
469        90   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-organizationName (2.5.4.10)
470        95   [0,0,  26]  . . . . . . value: [UNIV 19] AttributeValue ANY
471                         . . . . . . . 13:18:49:6E:74:65:72:6E:65:74:20:57:69:64:67:69
472                         . . . . . . . 74:73:20:50:74:79:20:4C:74:64
473        95   [1,1,  24]  . . . . . . . DEFINED BY (2.5.4.10): PrintableString PrintableString Internet Widgits Pty Ltd
474
475 :ref:`Read more <definedby>` about that feature.