]> Cypherpunks.ru repositories - pyderasn.git/blob - doc/examples.rst
BER usage documentation
[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 ::
238
239        52-2 [1,1,1054]-4  . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
240                        ^                                 ^   ^            ^
241                       12                                13   9            10
242
243 :0:
244  Offset of the object, where its DER/BER encoding begins.
245  Pay attention that it does **not** include explicit tag.
246 :1:
247  If explicit tag exists, then this is its length (tag + encoded length).
248 :2:
249  Length of object's tag. For example CHOICE does not have its own tag,
250  so it is zero.
251 :3:
252  Length of encoded length.
253 :4:
254  Length of encoded value.
255 :5:
256  Visual indentation to show the depth of object in the hierarchy.
257 :6:
258  Object's name inside SEQUENCE/CHOICE.
259 :7:
260  If either IMPLICIT or EXPLICIT tag is set, then it will be shown
261  here. "IMPLICIT" is omitted.
262 :8:
263  Object's class name, if set. Omitted if it is just an ordinary simple
264  value (like with ``algorithm`` in example above).
265 :9:
266  Object's ASN.1 type.
267 :10:
268  Object's value, if set. Can consist of multiple words (like OCTET/BIT
269  STRINGs above). We see ``v3`` value in Version, because it is named.
270  ``rdnSequence`` is the choice of CHOICE type.
271 :11:
272  Possible other flags like OPTIONAL and DEFAULT, if value equals to the
273  default one, specified in the schema.
274 :12:
275  Only applicable to BER encoded data. If object has indefinite length
276  encoding, then subtract 2 bytes EOC from its length. If object has
277  explicit tag with indefinite length, then subtract another EOC bytes.
278  In example above, ``eContent`` field has both indefinite field encoding
279  and indefinite length explicit tag. ``BIT STRING``, ``OCTET STRING``
280  (and its derivatives), ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET
281  OF``, ``ANY`` could have indefinite length coding.
282 :13:
283  Only applicable to BER encoded data. If object has BER-specific
284  encoding, then ``BER`` will be shown. It does not depend on indefinite
285  length encoding. ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING`` (and its
286  derivatives) could be BERed.
287
288 As command line utility
289 -----------------------
290
291 You can decode DER/BER files using command line abilities and get the
292 same picture as above by executing::
293
294     % python -m pyderasn --schema tests.test_crts:Certificate path/to/file
295
296 If there is no schema for you file, then you can try parsing it without,
297 but of course IMPLICIT tags will often make it impossible. But result is
298 good enough for the certificate above::
299
300     % python -m pyderasn path/to/file
301         0   [1,3,1604]  . >: SEQUENCE OF
302         4   [1,3,1453]  . . >: SEQUENCE OF
303         8   [0,0,   5]  . . . . >: [0] ANY
304                         . . . . . A0:03:02:01:02
305        13   [1,1,   3]  . . . . >: INTEGER 61595
306        18   [1,1,  13]  . . . . >: SEQUENCE OF
307        20   [1,1,   9]  . . . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
308        31   [1,1,   0]  . . . . . . >: NULL
309        33   [1,3, 274]  . . . . >: SEQUENCE OF
310        37   [1,1,  11]  . . . . . . >: SET OF
311        39   [1,1,   9]  . . . . . . . . >: SEQUENCE OF
312        41   [1,1,   3]  . . . . . . . . . . >: OBJECT IDENTIFIER 2.5.4.6
313        46   [1,1,   2]  . . . . . . . . . . >: PrintableString PrintableString ES
314     [...]
315      1409   [1,1,  50]  . . . . . . >: SEQUENCE OF
316      1411   [1,1,   8]  . . . . . . . . >: OBJECT IDENTIFIER 1.3.6.1.5.5.7.1.1
317      1421   [1,1,  38]  . . . . . . . . >: OCTET STRING 38 bytes
318                         . . . . . . . . . 30:24:30:22:06:08:2B:06:01:05:05:07:30:01:86:16
319                         . . . . . . . . . 68:74:74:70:3A:2F:2F:6F:63:73:70:2E:69:70:73:63
320                         . . . . . . . . . 61:2E:63:6F:6D:2F
321      1461   [1,1,  13]  . . >: SEQUENCE OF
322      1463   [1,1,   9]  . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
323      1474   [1,1,   0]  . . . . >: NULL
324      1476   [1,2, 129]  . . >: BIT STRING 1024 bits
325                         . . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
326                         . . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
327     [...]
328
329 If you have got dictionaries with ObjectIdentifiers, like example one
330 from ``tests/test_crts.py``::
331
332     some_oids = {
333         "1.2.840.113549.1.1.1": "id-rsaEncryption",
334         "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
335         [...]
336         "2.5.4.10": "id-at-organizationName",
337         "2.5.4.11": "id-at-organizationalUnitName",
338     }
339
340 then you can pass it to pretty printer to see human readable OIDs::
341
342     % python -m pyderasn --oids tests.test_crts:some_oids path/to/file
343     [...]
344        37   [1,1,  11]  . . . . . . >: SET OF
345        39   [1,1,   9]  . . . . . . . . >: SEQUENCE OF
346        41   [1,1,   3]  . . . . . . . . . . >: OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
347        46   [1,1,   2]  . . . . . . . . . . >: PrintableString PrintableString ES
348        50   [1,1,  18]  . . . . . . >: SET OF
349        52   [1,1,  16]  . . . . . . . . >: SEQUENCE OF
350        54   [1,1,   3]  . . . . . . . . . . >: OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
351        59   [1,1,   9]  . . . . . . . . . . >: PrintableString PrintableString Barcelona
352        70   [1,1,  18]  . . . . . . >: SET OF
353        72   [1,1,  16]  . . . . . . . . >: SEQUENCE OF
354        74   [1,1,   3]  . . . . . . . . . . >: OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
355        79   [1,1,   9]  . . . . . . . . . . >: PrintableString PrintableString Barcelona
356     [...]
357
358 Descriptive errors
359 ------------------
360
361 If you have bad DER/BER, then errors will show you where error occurred::
362
363     % python -m pyderasn --schema tests.test_crts:Certificate path/to/bad/file
364     Traceback (most recent call last):
365     [...]
366     pyderasn.DecodeError: UTCTime (tbsCertificate.validity.notAfter.utcTime) (at 328) invalid UTCTime format
367
368 ::
369
370     % python -m pyderasn path/to/bad/file
371     [...]
372     pyderasn.DecodeError: UTCTime (0.SequenceOf.4.SequenceOf.1.UTCTime) (at 328) invalid UTCTime format
373
374 You can see, so called, decode path inside the structures:
375 ``tbsCertificate`` -> ``validity`` -> ``notAfter`` -> ``utcTime`` and
376 that object at byte 328 is invalid.
377
378 X.509 certificate creation
379 --------------------------
380
381 Let's create some simple self-signed X.509 certificate from the ground::
382
383     tbs = TBSCertificate()
384     tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
385
386     sign_algo_id = AlgorithmIdentifier((
387         ("algorithm", ObjectIdentifier("1.2.840.113549.1.1.5")),
388         ("parameters", Any(Null())),
389     ))
390     tbs["signature"] = sign_algo_id
391
392     rdnSeq = RDNSequence()
393     for oid, klass, text in (
394             ("2.5.4.6", PrintableString, "XX"),
395             ("2.5.4.8", PrintableString, "Some-State"),
396             ("2.5.4.7", PrintableString, "City"),
397             ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
398             ("2.5.4.3", PrintableString, "false.example.com"),
399             ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
400     ):
401         rdnSeq.append(
402             RelativeDistinguishedName((
403                 AttributeTypeAndValue((
404                     ("type", AttributeType(oid)),
405                     ("value", AttributeValue(klass(text))),
406                 )),
407             ))
408         )
409     issuer = Name(("rdnSequence", rdnSeq))
410     tbs["issuer"] = issuer
411     tbs["subject"] = issuer
412
413     validity = Validity((
414         ("notBefore", Time(
415             ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53))),
416         )),
417         ("notAfter", Time(
418             ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53))),
419         )),
420     ))
421     tbs["validity"] = validity
422
423     spki = SubjectPublicKeyInfo()
424     spki_algo_id = sign_algo_id.copy()
425     spki_algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
426     spki["algorithm"] = spki_algo_id
427     spki["subjectPublicKey"] = BitString(hexdec("".join((
428         "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
429         "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
430         "deec357d0203010001",
431     ))))
432     tbs["subjectPublicKeyInfo"] = spki
433
434     crt = Certificate()
435     crt["tbsCertificate"] = tbs
436     crt["signatureAlgorithm"] = sign_algo_id
437     crt["signatureValue"] = BitString(hexdec("".join((
438         "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
439         "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
440     ))))
441     crt.encode()
442
443 And we will get the same certificate used in Go's library tests.
444
445 DEFINED BY fields
446 -----------------
447
448 Here is only very simple example how you can define Any/OctetString
449 fields automatic decoding::
450
451     class AttributeTypeAndValue(Sequence):
452         schema = (
453             ((("type",), AttributeType(defines=("value", {
454                 id_at_countryName: PrintableString(),
455                 id_at_stateOrProvinceName: PrintableString(),
456                 id_at_localityName: PrintableString(),
457                 id_at_organizationName: PrintableString(),
458                 id_at_commonName: PrintableString(),
459             }))),),
460             ("value", AttributeValue()),
461         )
462
463 And when you will try to decode X.509 certificate with it, your pretty
464 printer will show::
465
466        34   [0,0, 149]  . . issuer: Name CHOICE rdnSequence
467        34   [1,2, 146]  . . . rdnSequence: RDNSequence SEQUENCE OF
468        37   [1,1,  11]  . . . . 0: RelativeDistinguishedName SET OF
469        39   [1,1,   9]  . . . . . 0: AttributeTypeAndValue SEQUENCE
470        41   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
471        46   [0,0,   4]  . . . . . . value: [UNIV 19] AttributeValue ANY
472                         . . . . . . . 13:02:58:58
473        46   [1,1,   2]  . . . . . . . DEFINED BY (2.5.4.6): PrintableString PrintableString XX
474        50   [1,1,  19]  . . . . 1: RelativeDistinguishedName SET OF
475        52   [1,1,  17]  . . . . . 0: AttributeTypeAndValue SEQUENCE
476        54   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
477        59   [0,0,  12]  . . . . . . value: [UNIV 19] AttributeValue ANY
478                         . . . . . . . 13:0A:53:6F:6D:65:2D:53:74:61:74:65
479        59   [1,1,  10]  . . . . . . . DEFINED BY (2.5.4.8): PrintableString PrintableString Some-State
480        71   [1,1,  13]  . . . . 2: RelativeDistinguishedName SET OF
481        73   [1,1,  11]  . . . . . 0: AttributeTypeAndValue SEQUENCE
482        75   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
483        80   [0,0,   6]  . . . . . . value: [UNIV 19] AttributeValue ANY
484                         . . . . . . . 13:04:43:69:74:79
485        80   [1,1,   4]  . . . . . . . DEFINED BY (2.5.4.7): PrintableString PrintableString City
486        86   [1,1,  33]  . . . . 3: RelativeDistinguishedName SET OF
487        88   [1,1,  31]  . . . . . 0: AttributeTypeAndValue SEQUENCE
488        90   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-organizationName (2.5.4.10)
489        95   [0,0,  26]  . . . . . . value: [UNIV 19] AttributeValue ANY
490                         . . . . . . . 13:18:49:6E:74:65:72:6E:65:74:20:57:69:64:67:69
491                         . . . . . . . 74:73:20:50:74:79:20:4C:74:64
492        95   [1,1,  24]  . . . . . . . DEFINED BY (2.5.4.10): PrintableString PrintableString Internet Widgits Pty Ltd
493
494 :ref:`Read more <definedby>` about that feature.