]> Cypherpunks.ru repositories - pyderasn.git/blob - doc/examples.rst
953001a36c9c6b98c16f1ff512595c9533da043e
[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 = Certificate().decod(raw)
181     >>> crt
182     Certificate SEQUENCE[tbsCertificate: TBSCertificate SEQUENCE[
183         version: [0] EXPLICIT Version INTEGER v3 OPTIONAL;
184         serialNumber: CertificateSerialNumber INTEGER 61595;
185         signature: AlgorithmIdentifier SEQUENCE[OBJECT IDENTIFIER 1.2.840.113549.1.1.5...
186
187 :ref:`Look here <pprint_example>` for better pretty printing.
188
189 .. _cmdline:
190
191 As command line utility
192 -----------------------
193
194 You can decode DER/BER files using command line abilities and get the
195 same picture as above by executing::
196
197     $ python -m pyderasn --schema tests.test_crts:Certificate path/to/file
198
199 If there is no schema for you file, then you can try parsing it without,
200 but of course IMPLICIT tags will often make it impossible. But result is
201 good enough for the certificate above::
202
203     $ python -m pyderasn path/to/file
204         0   [1,3,1604]  . >: SEQUENCE OF
205         4   [1,3,1453]  . . >: SEQUENCE OF
206         8   [0,0,   5]  . . . . >: [0] ANY
207                         . . . . . A0:03:02:01:02
208        13   [1,1,   3]  . . . . >: INTEGER 61595
209        18   [1,1,  13]  . . . . >: SEQUENCE OF
210        20   [1,1,   9]  . . . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
211        31   [1,1,   0]  . . . . . . >: NULL
212        33   [1,3, 274]  . . . . >: SEQUENCE OF
213        37   [1,1,  11]  . . . . . . >: SET OF
214        39   [1,1,   9]  . . . . . . . . >: SEQUENCE OF
215        41   [1,1,   3]  . . . . . . . . . . >: OBJECT IDENTIFIER 2.5.4.6
216        46   [1,1,   2]  . . . . . . . . . . >: PrintableString PrintableString ES
217     [...]
218      1409   [1,1,  50]  . . . . . . >: SEQUENCE OF
219      1411   [1,1,   8]  . . . . . . . . >: OBJECT IDENTIFIER 1.3.6.1.5.5.7.1.1
220      1421   [1,1,  38]  . . . . . . . . >: OCTET STRING 38 bytes
221                         . . . . . . . . . 30:24:30:22:06:08:2B:06:01:05:05:07:30:01:86:16
222                         . . . . . . . . . 68:74:74:70:3A:2F:2F:6F:63:73:70:2E:69:70:73:63
223                         . . . . . . . . . 61:2E:63:6F:6D:2F
224      1461   [1,1,  13]  . . >: SEQUENCE OF
225      1463   [1,1,   9]  . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
226      1474   [1,1,   0]  . . . . >: NULL
227      1476   [1,2, 129]  . . >: BIT STRING 1024 bits
228                         . . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
229                         . . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
230     [...]
231
232 Human readable OIDs
233 ___________________
234
235 If you have got dictionaries with ObjectIdentifiers, like example one
236 from ``tests/test_crts.py``::
237
238     stroid2name = {
239         "1.2.840.113549.1.1.1": "id-rsaEncryption",
240         "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
241         [...]
242         "2.5.4.10": "id-at-organizationName",
243         "2.5.4.11": "id-at-organizationalUnitName",
244     }
245
246 then you can pass it to pretty printer to see human readable OIDs::
247
248     $ python -m pyderasn --oids tests.test_crts:stroid2name path/to/file
249     [...]
250        37   [1,1,  11]  . . . . . . >: SET OF
251        39   [1,1,   9]  . . . . . . . . >: SEQUENCE OF
252        41   [1,1,   3]  . . . . . . . . . . >: OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
253        46   [1,1,   2]  . . . . . . . . . . >: PrintableString PrintableString ES
254        50   [1,1,  18]  . . . . . . >: SET OF
255        52   [1,1,  16]  . . . . . . . . >: SEQUENCE OF
256        54   [1,1,   3]  . . . . . . . . . . >: OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
257        59   [1,1,   9]  . . . . . . . . . . >: PrintableString PrintableString Barcelona
258        70   [1,1,  18]  . . . . . . >: SET OF
259        72   [1,1,  16]  . . . . . . . . >: SEQUENCE OF
260        74   [1,1,   3]  . . . . . . . . . . >: OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
261        79   [1,1,   9]  . . . . . . . . . . >: PrintableString PrintableString Barcelona
262     [...]
263
264 Decode paths
265 ____________
266
267 Each decoded element has so-called decode path: sequence of structure
268 names it is passing during the decode process. Each element has its own
269 unique path inside the whole ASN.1 tree. You can print it out with
270 ``--print-decode-path`` option::
271
272     $ python -m pyderasn --schema path.to:Certificate --print-decode-path path/to/file
273        0    [1,3,1604]  Certificate SEQUENCE []
274        4    [1,3,1453]   . tbsCertificate: TBSCertificate SEQUENCE [tbsCertificate]
275       10-2  [1,1,   1]   . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL [tbsCertificate:version]
276       13    [1,1,   3]   . . serialNumber: CertificateSerialNumber INTEGER 61595 [tbsCertificate:serialNumber]
277       18    [1,1,  13]   . . signature: AlgorithmIdentifier SEQUENCE [tbsCertificate:signature]
278       20    [1,1,   9]   . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5 [tbsCertificate:signature:algorithm]
279       31    [0,0,   2]   . . . parameters: [UNIV 5] ANY OPTIONAL [tbsCertificate:signature:parameters]
280                          . . . . 05:00
281       33    [0,0, 278]   . . issuer: Name CHOICE rdnSequence [tbsCertificate:issuer]
282       33    [1,3, 274]   . . . rdnSequence: RDNSequence SEQUENCE OF [tbsCertificate:issuer:rdnSequence]
283       37    [1,1,  11]   . . . . 0: RelativeDistinguishedName SET OF [tbsCertificate:issuer:rdnSequence:0]
284       39    [1,1,   9]   . . . . . 0: AttributeTypeAndValue SEQUENCE [tbsCertificate:issuer:rdnSequence:0:0]
285       41    [1,1,   3]   . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6 [tbsCertificate:issuer:rdnSequence:0:0:type]
286       46    [0,0,   4]   . . . . . . value: [UNIV 19] AttributeValue ANY [tbsCertificate:issuer:rdnSequence:0:0:value]
287                          . . . . . . . 13:02:45:53
288       46    [1,1,   2]   . . . . . . . DEFINED BY 2.5.4.6: CountryName PrintableString ES [tbsCertificate:issuer:rdnSequence:0:0:value:DEFINED BY 2.5.4.6]
289     [...]
290
291 Now you can print only the specified tree, for example signature algorithm::
292
293     $ python -m pyderasn --schema path.to:Certificate --decode-path-only tbsCertificate:signature path/to/file
294       18    [1,1,  13]  AlgorithmIdentifier SEQUENCE
295       20    [1,1,   9]   . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
296       31    [0,0,   2]   . parameters: [UNIV 5] ANY OPTIONAL
297                          . . 05:00
298
299 Descriptive errors
300 ------------------
301
302 If you have bad DER/BER, then errors will show you where error occurred::
303
304     $ python -m pyderasn --schema tests.test_crts:Certificate path/to/bad/file
305     Traceback (most recent call last):
306     [...]
307     pyderasn.DecodeError: UTCTime (tbsCertificate:validity:notAfter:utcTime) (at 328) invalid UTCTime format
308
309 ::
310
311     $ python -m pyderasn path/to/bad/file
312     [...]
313     pyderasn.DecodeError: UTCTime (0:SequenceOf:4:SequenceOf:1:UTCTime) (at 328) invalid UTCTime format
314
315 You can see, so called, decode path inside the structures:
316 ``tbsCertificate`` -> ``validity`` -> ``notAfter`` -> ``utcTime`` and
317 that object at byte 328 is invalid.
318
319 X.509 certificate creation
320 --------------------------
321
322 Let's create some simple self-signed X.509 certificate from the ground::
323
324     tbs = TBSCertificate()
325     tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
326
327     sign_algo_id = AlgorithmIdentifier((
328         ("algorithm", ObjectIdentifier("1.2.840.113549.1.1.5")),
329         ("parameters", Any(Null())),
330     ))
331     tbs["signature"] = sign_algo_id
332
333     rdnSeq = RDNSequence()
334     for oid, klass, text in (
335             ("2.5.4.6", PrintableString, "XX"),
336             ("2.5.4.8", PrintableString, "Some-State"),
337             ("2.5.4.7", PrintableString, "City"),
338             ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
339             ("2.5.4.3", PrintableString, "false.example.com"),
340             ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
341     ):
342         rdnSeq.append(
343             RelativeDistinguishedName((
344                 AttributeTypeAndValue((
345                     ("type", AttributeType(oid)),
346                     ("value", AttributeValue(klass(text))),
347                 )),
348             ))
349         )
350     issuer = Name(("rdnSequence", rdnSeq))
351     tbs["issuer"] = issuer
352     tbs["subject"] = issuer
353
354     validity = Validity((
355         ("notBefore", Time(
356             ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53))),
357         )),
358         ("notAfter", Time(
359             ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53))),
360         )),
361     ))
362     tbs["validity"] = validity
363
364     spki = SubjectPublicKeyInfo()
365     spki_algo_id = copy(sign_algo_id)
366     spki_algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
367     spki["algorithm"] = spki_algo_id
368     spki["subjectPublicKey"] = BitString(hexdec("".join((
369         "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
370         "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
371         "deec357d0203010001",
372     ))))
373     tbs["subjectPublicKeyInfo"] = spki
374
375     crt = Certificate()
376     crt["tbsCertificate"] = tbs
377     crt["signatureAlgorithm"] = sign_algo_id
378     crt["signatureValue"] = BitString(hexdec("".join((
379         "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
380         "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
381     ))))
382     crt.encode()
383
384 And we will get the same certificate used in Go's library tests.
385
386 DEFINED BY fields
387 -----------------
388
389 Here is only very simple example how you can define Any/OctetString
390 fields automatic decoding::
391
392     class AttributeTypeAndValue(Sequence):
393         schema = (
394             ((("type",), AttributeType(defines=((("value",), {
395                 id_at_countryName: PrintableString(),
396                 id_at_stateOrProvinceName: PrintableString(),
397                 id_at_localityName: PrintableString(),
398                 id_at_organizationName: PrintableString(),
399                 id_at_commonName: PrintableString(),
400             }),)))),
401             ("value", AttributeValue()),
402         )
403
404 And when you will try to decode X.509 certificate with it, your pretty
405 printer will show::
406
407        34   [0,0, 149]  . . issuer: Name CHOICE rdnSequence
408        34   [1,2, 146]  . . . rdnSequence: RDNSequence SEQUENCE OF
409        37   [1,1,  11]  . . . . 0: RelativeDistinguishedName SET OF
410        39   [1,1,   9]  . . . . . 0: AttributeTypeAndValue SEQUENCE
411        41   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
412        46   [0,0,   4]  . . . . . . value: [UNIV 19] AttributeValue ANY
413                         . . . . . . . 13:02:58:58
414        46   [1,1,   2]  . . . . . . . DEFINED BY (2.5.4.6): PrintableString PrintableString XX
415        50   [1,1,  19]  . . . . 1: RelativeDistinguishedName SET OF
416        52   [1,1,  17]  . . . . . 0: AttributeTypeAndValue SEQUENCE
417        54   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
418        59   [0,0,  12]  . . . . . . value: [UNIV 19] AttributeValue ANY
419                         . . . . . . . 13:0A:53:6F:6D:65:2D:53:74:61:74:65
420        59   [1,1,  10]  . . . . . . . DEFINED BY (2.5.4.8): PrintableString PrintableString Some-State
421        71   [1,1,  13]  . . . . 2: RelativeDistinguishedName SET OF
422        73   [1,1,  11]  . . . . . 0: AttributeTypeAndValue SEQUENCE
423        75   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
424        80   [0,0,   6]  . . . . . . value: [UNIV 19] AttributeValue ANY
425                         . . . . . . . 13:04:43:69:74:79
426        80   [1,1,   4]  . . . . . . . DEFINED BY (2.5.4.7): PrintableString PrintableString City
427        86   [1,1,  33]  . . . . 3: RelativeDistinguishedName SET OF
428        88   [1,1,  31]  . . . . . 0: AttributeTypeAndValue SEQUENCE
429        90   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-organizationName (2.5.4.10)
430        95   [0,0,  26]  . . . . . . value: [UNIV 19] AttributeValue ANY
431                         . . . . . . . 13:18:49:6E:74:65:72:6E:65:74:20:57:69:64:67:69
432                         . . . . . . . 74:73:20:50:74:79:20:4C:74:64
433        95   [1,1,  24]  . . . . . . . DEFINED BY (2.5.4.10): PrintableString PrintableString Internet Widgits Pty Ltd
434
435 :ref:`Read more <definedby>` about that feature.