]> Cypherpunks.ru repositories - pyderasn.git/blob - doc/examples.rst
Raise copyright years
[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 .. seealso:: :ref:`Better pretty printing <pprint_example>`
188
189 As command line utility
190 -----------------------
191
192 .. seealso:: :ref:`cmdline`
193
194 Descriptive errors
195 ------------------
196
197 If you have bad DER/BER, then errors will show you where error occurred::
198
199     $ python -m pyderasn --schema tests.test_crts:Certificate path/to/bad/file
200     Traceback (most recent call last):
201     [...]
202     pyderasn.DecodeError: UTCTime (tbsCertificate:validity:notAfter:utcTime) (at 328) invalid UTCTime format
203
204 ::
205
206     $ python -m pyderasn path/to/bad/file
207     [...]
208     pyderasn.DecodeError: UTCTime (0:SequenceOf:4:SequenceOf:1:UTCTime) (at 328) invalid UTCTime format
209
210 You can see, so called, decode path inside the structures:
211 ``tbsCertificate`` -> ``validity`` -> ``notAfter`` -> ``utcTime`` and
212 that object at byte 328 is invalid.
213
214 X.509 certificate creation
215 --------------------------
216
217 Let's create some simple self-signed X.509 certificate from the ground::
218
219     tbs = TBSCertificate()
220     tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
221
222     sign_algo_id = AlgorithmIdentifier((
223         ("algorithm", ObjectIdentifier("1.2.840.113549.1.1.5")),
224         ("parameters", Any(Null())),
225     ))
226     tbs["signature"] = sign_algo_id
227
228     rdnSeq = RDNSequence()
229     for oid, klass, text in (
230             ("2.5.4.6", PrintableString, "XX"),
231             ("2.5.4.8", PrintableString, "Some-State"),
232             ("2.5.4.7", PrintableString, "City"),
233             ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
234             ("2.5.4.3", PrintableString, "false.example.com"),
235             ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
236     ):
237         rdnSeq.append(
238             RelativeDistinguishedName((
239                 AttributeTypeAndValue((
240                     ("type", AttributeType(oid)),
241                     ("value", AttributeValue(klass(text))),
242                 )),
243             ))
244         )
245     issuer = Name(("rdnSequence", rdnSeq))
246     tbs["issuer"] = issuer
247     tbs["subject"] = issuer
248
249     validity = Validity((
250         ("notBefore", Time(
251             ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53))),
252         )),
253         ("notAfter", Time(
254             ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53))),
255         )),
256     ))
257     tbs["validity"] = validity
258
259     spki = SubjectPublicKeyInfo()
260     spki_algo_id = copy(sign_algo_id)
261     spki_algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
262     spki["algorithm"] = spki_algo_id
263     spki["subjectPublicKey"] = BitString(hexdec("".join((
264         "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
265         "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
266         "deec357d0203010001",
267     ))))
268     tbs["subjectPublicKeyInfo"] = spki
269
270     crt = Certificate()
271     crt["tbsCertificate"] = tbs
272     crt["signatureAlgorithm"] = sign_algo_id
273     crt["signatureValue"] = BitString(hexdec("".join((
274         "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
275         "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
276     ))))
277     crt.encode()
278
279 And we will get the same certificate used in Go's library tests.
280
281 DEFINED BY fields
282 -----------------
283
284 Here is only very simple example how you can define Any/OctetString
285 fields automatic decoding::
286
287     class AttributeTypeAndValue(Sequence):
288         schema = (
289             ((("type",), AttributeType(defines=((("value",), {
290                 id_at_countryName: PrintableString(),
291                 id_at_stateOrProvinceName: PrintableString(),
292                 id_at_localityName: PrintableString(),
293                 id_at_organizationName: PrintableString(),
294                 id_at_commonName: PrintableString(),
295             }),)))),
296             ("value", AttributeValue()),
297         )
298
299 And when you will try to decode X.509 certificate with it, your pretty
300 printer will show::
301
302        34   [0,0, 149]  . . issuer: Name CHOICE rdnSequence
303        34   [1,2, 146]  . . . rdnSequence: RDNSequence SEQUENCE OF
304        37   [1,1,  11]  . . . . 0: RelativeDistinguishedName SET OF
305        39   [1,1,   9]  . . . . . 0: AttributeTypeAndValue SEQUENCE
306        41   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
307        46   [0,0,   4]  . . . . . . value: [UNIV 19] AttributeValue ANY
308                         . . . . . . . 13:02:58:58
309        46   [1,1,   2]  . . . . . . . DEFINED BY (2.5.4.6): PrintableString PrintableString XX
310        50   [1,1,  19]  . . . . 1: RelativeDistinguishedName SET OF
311        52   [1,1,  17]  . . . . . 0: AttributeTypeAndValue SEQUENCE
312        54   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
313        59   [0,0,  12]  . . . . . . value: [UNIV 19] AttributeValue ANY
314                         . . . . . . . 13:0A:53:6F:6D:65:2D:53:74:61:74:65
315        59   [1,1,  10]  . . . . . . . DEFINED BY (2.5.4.8): PrintableString PrintableString Some-State
316        71   [1,1,  13]  . . . . 2: RelativeDistinguishedName SET OF
317        73   [1,1,  11]  . . . . . 0: AttributeTypeAndValue SEQUENCE
318        75   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
319        80   [0,0,   6]  . . . . . . value: [UNIV 19] AttributeValue ANY
320                         . . . . . . . 13:04:43:69:74:79
321        80   [1,1,   4]  . . . . . . . DEFINED BY (2.5.4.7): PrintableString PrintableString City
322        86   [1,1,  33]  . . . . 3: RelativeDistinguishedName SET OF
323        88   [1,1,  31]  . . . . . 0: AttributeTypeAndValue SEQUENCE
324        90   [1,1,   3]  . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-organizationName (2.5.4.10)
325        95   [0,0,  26]  . . . . . . value: [UNIV 19] AttributeValue ANY
326                         . . . . . . . 13:18:49:6E:74:65:72:6E:65:74:20:57:69:64:67:69
327                         . . . . . . . 74:73:20:50:74:79:20:4C:74:64
328        95   [1,1,  24]  . . . . . . . DEFINED BY (2.5.4.10): PrintableString PrintableString Internet Widgits Pty Ltd
329
330 .. seealso:: :ref:`definedby`
331
332 Streaming and dealing with huge structures
333 ------------------------------------------
334 .. seealso:: :ref:`streaming`