]> Cypherpunks.ru repositories - pyderasn.git/blob - tests/test_crts.py
More decod() usage examples
[pyderasn.git] / tests / test_crts.py
1 # coding: utf-8
2 # PyDERASN -- Python ASN.1 DER codec with abstract structures
3 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, version 3 of the License.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this program.  If not, see
16 # <http://www.gnu.org/licenses/>.
17
18 from datetime import datetime
19 from unittest import TestCase
20
21 from pyderasn import Any
22 from pyderasn import BitString
23 from pyderasn import Boolean
24 from pyderasn import Choice
25 from pyderasn import GeneralizedTime
26 from pyderasn import hexdec
27 from pyderasn import IA5String
28 from pyderasn import Integer
29 from pyderasn import Null
30 from pyderasn import ObjectIdentifier
31 from pyderasn import OctetString
32 from pyderasn import pprint
33 from pyderasn import PrintableString
34 from pyderasn import Sequence
35 from pyderasn import SequenceOf
36 from pyderasn import SetOf
37 from pyderasn import tag_ctxc
38 from pyderasn import tag_ctxp
39 from pyderasn import TeletexString
40 from pyderasn import UTCTime
41
42
43 some_oids = {
44     "1.2.840.113549.1.1.1": "id-rsaEncryption",
45     "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
46     "1.2.840.113549.1.9.1": "id-emailAddress",
47     "2.5.29.14": "id-ce-subjectKeyIdentifier",
48     "2.5.29.15": "id-ce-keyUsage",
49     "2.5.29.17": "id-ce-subjectAltName",
50     "2.5.29.18": "id-ce-issuerAltName",
51     "2.5.29.19": "id-ce-basicConstraints",
52     "2.5.29.31": "id-ce-cRLDistributionPoints",
53     "2.5.29.35": "id-ce-authorityKeyIdentifier",
54     "2.5.29.37": "id-ce-extKeyUsage",
55     "2.5.4.3": "id-at-commonName",
56     "2.5.4.6": "id-at-countryName",
57     "2.5.4.7": "id-at-localityName",
58     "2.5.4.8": "id-at-stateOrProvinceName",
59     "2.5.4.10": "id-at-organizationName",
60     "2.5.4.11": "id-at-organizationalUnitName",
61 }
62
63
64 class Version(Integer):
65     schema = (
66         ("v1", 0),
67         ("v2", 1),
68         ("v3", 2),
69     )
70
71
72 class CertificateSerialNumber(Integer):
73     pass
74
75
76 class AlgorithmIdentifier(Sequence):
77     schema = (
78         ("algorithm", ObjectIdentifier()),
79         ("parameters", Any(optional=True)),
80     )
81
82
83 class AttributeType(ObjectIdentifier):
84     pass
85
86
87 class AttributeValue(Any):
88     pass
89
90
91 class OrganizationName(Choice):
92     schema = (
93         ("printableString", PrintableString()),
94         ("teletexString", TeletexString()),
95     )
96
97
98 class AttributeTypeAndValue(Sequence):
99     schema = (
100         ("type", AttributeType(defines=(((".", "value"), {
101             ObjectIdentifier("2.5.4.6"): PrintableString(),
102             ObjectIdentifier("2.5.4.8"): PrintableString(),
103             ObjectIdentifier("2.5.4.7"): PrintableString(),
104             ObjectIdentifier("2.5.4.10"): OrganizationName(),
105             ObjectIdentifier("2.5.4.3"): PrintableString(),
106         }),))),
107         ("value", AttributeValue()),
108     )
109
110
111 class RelativeDistinguishedName(SetOf):
112     schema = AttributeTypeAndValue()
113     bounds = (1, float("+inf"))
114
115
116 class RDNSequence(SequenceOf):
117     schema = RelativeDistinguishedName()
118
119
120 class Name(Choice):
121     schema = (
122         ("rdnSequence", RDNSequence()),
123     )
124
125
126 class Time(Choice):
127     schema = (
128         ("utcTime", UTCTime()),
129         ("generalTime", GeneralizedTime()),
130     )
131
132
133 class Validity(Sequence):
134     schema = (
135         ("notBefore", Time()),
136         ("notAfter", Time()),
137     )
138
139
140 class SubjectPublicKeyInfo(Sequence):
141     schema = (
142         ("algorithm", AlgorithmIdentifier()),
143         ("subjectPublicKey", BitString()),
144     )
145
146
147 class UniqueIdentifier(BitString):
148     pass
149
150
151 class Extension(Sequence):
152     schema = (
153         ("extnID", ObjectIdentifier()),
154         ("critical", Boolean(default=False)),
155         ("extnValue", OctetString()),
156     )
157
158
159 class Extensions(SequenceOf):
160     schema = Extension()
161     bounds = (1, float("+inf"))
162
163
164 class TBSCertificate(Sequence):
165     schema = (
166         ("version", Version(expl=tag_ctxc(0), default="v1")),
167         ("serialNumber", CertificateSerialNumber()),
168         ("signature", AlgorithmIdentifier()),
169         ("issuer", Name()),
170         ("validity", Validity()),
171         ("subject", Name()),
172         ("subjectPublicKeyInfo", SubjectPublicKeyInfo()),
173         ("issuerUniqueID", UniqueIdentifier(impl=tag_ctxp(1), optional=True)),
174         ("subjectUniqueID", UniqueIdentifier(impl=tag_ctxp(2), optional=True)),
175         ("extensions", Extensions(expl=tag_ctxc(3), optional=True)),
176     )
177
178
179 class Certificate(Sequence):
180     schema = (
181         ("tbsCertificate", TBSCertificate()),
182         ("signatureAlgorithm", AlgorithmIdentifier()),
183         ("signatureValue", BitString()),
184     )
185
186
187 class TestGoSelfSignedVector(TestCase):
188     def runTest(self):
189         raw = hexdec("".join((
190             "30820218308201c20209008cc3379210ec2c98300d06092a864886f70d0101050",
191             "500308192310b3009060355040613025858311330110603550408130a536f6d65",
192             "2d5374617465310d300b06035504071304436974793121301f060355040a13184",
193             "96e7465726e6574205769646769747320507479204c7464311a30180603550403",
194             "131166616c73652e6578616d706c652e636f6d3120301e06092a864886f70d010",
195             "901161166616c7365406578616d706c652e636f6d301e170d3039313030383030",
196             "323535335a170d3130313030383030323535335a308192310b300906035504061",
197             "3025858311330110603550408130a536f6d652d5374617465310d300b06035504",
198             "071304436974793121301f060355040a1318496e7465726e65742057696467697",
199             "47320507479204c7464311a30180603550403131166616c73652e6578616d706c",
200             "652e636f6d3120301e06092a864886f70d010901161166616c7365406578616d7",
201             "06c652e636f6d305c300d06092a864886f70d0101010500034b003048024100cd",
202             "b7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695a331b1deadea",
203             "dd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8fdeec357d0203",
204             "010001300d06092a864886f70d0101050500034100a67b06ec5ece92772ca413c",
205             "ba3ca12568fdc6c7b4511cd40a7f659980402df2b998bb9a4a8cbeb34c0f0a78c",
206             "f8d91ede14a5ed76bf116fe360aafa8821490435",
207         )))
208         crt = Certificate().decod(raw)
209         tbs = crt["tbsCertificate"]
210         self.assertEqual(tbs["version"], 0)
211         self.assertFalse(tbs["version"].decoded)
212         self.assertNotIn("version", tbs)
213         self.assertEqual(tbs["serialNumber"], 10143011886257155224)
214
215         def assert_raw_equals(obj, expect):
216             self.assertTrue(obj.decoded)
217             self.assertSequenceEqual(
218                 raw[obj.offset:obj.offset + obj.tlvlen],
219                 expect.encode(),
220             )
221         assert_raw_equals(tbs["serialNumber"], Integer(10143011886257155224))
222         algo_id = AlgorithmIdentifier((
223             ("algorithm", ObjectIdentifier("1.2.840.113549.1.1.5")),
224             ("parameters", Any(Null())),
225         ))
226         self.assertEqual(tbs["signature"], algo_id)
227         assert_raw_equals(tbs["signature"], algo_id)
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         self.assertEqual(tbs["issuer"], issuer)
247         assert_raw_equals(tbs["issuer"], issuer)
248         validity = Validity((
249             ("notBefore", Time(
250                 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53)))
251             )),
252             ("notAfter", Time(
253                 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53)))
254             )),
255         ))
256         self.assertEqual(tbs["validity"], validity)
257         assert_raw_equals(tbs["validity"], validity)
258         self.assertEqual(tbs["subject"], issuer)
259         assert_raw_equals(tbs["subject"], issuer)
260         spki = SubjectPublicKeyInfo()
261         algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
262         spki["algorithm"] = algo_id
263         spki["subjectPublicKey"] = BitString(hexdec("".join((
264             "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
265             "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
266             "deec357d0203010001",
267         ))))
268         self.assertEqual(tbs["subjectPublicKeyInfo"], spki)
269         assert_raw_equals(tbs["subjectPublicKeyInfo"], spki)
270         self.assertNotIn("issuerUniqueID", tbs)
271         self.assertNotIn("subjectUniqueID", tbs)
272         self.assertNotIn("extensions", tbs)
273         algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.5")
274         self.assertEqual(crt["signatureAlgorithm"], algo_id)
275         self.assertEqual(crt["signatureValue"], BitString(hexdec("".join((
276             "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
277             "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
278         )))))
279         self.assertSequenceEqual(crt.encode(), raw)
280         pprint(crt)
281         repr(crt)
282
283         tbs = TBSCertificate()
284         tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
285
286         sign_algo_id = AlgorithmIdentifier((
287             ("algorithm", ObjectIdentifier("1.2.840.113549.1.1.5")),
288             ("parameters", Any(Null())),
289         ))
290         tbs["signature"] = sign_algo_id
291
292         rdnSeq = RDNSequence()
293         for oid, klass, text in (
294                 ("2.5.4.6", PrintableString, "XX"),
295                 ("2.5.4.8", PrintableString, "Some-State"),
296                 ("2.5.4.7", PrintableString, "City"),
297                 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
298                 ("2.5.4.3", PrintableString, "false.example.com"),
299                 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
300         ):
301             rdnSeq.append(
302                 RelativeDistinguishedName((
303                     AttributeTypeAndValue((
304                         ("type", AttributeType(oid)),
305                         ("value", AttributeValue(klass(text))),
306                     )),
307                 ))
308             )
309         issuer = Name()
310         issuer["rdnSequence"] = rdnSeq
311         tbs["issuer"] = issuer
312         tbs["subject"] = issuer
313
314         validity = Validity((
315             ("notBefore", Time(
316                 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53)),),
317             )),
318             ("notAfter", Time(
319                 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53)),),
320             )),
321         ))
322         tbs["validity"] = validity
323
324         spki = SubjectPublicKeyInfo()
325         spki_algo_id = sign_algo_id.copy()
326         spki_algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
327         spki["algorithm"] = spki_algo_id
328         spki["subjectPublicKey"] = BitString(hexdec("".join((
329             "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
330             "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
331             "deec357d0203010001",
332         ))))
333         tbs["subjectPublicKeyInfo"] = spki
334
335         crt = Certificate()
336         crt["tbsCertificate"] = tbs
337         crt["signatureAlgorithm"] = sign_algo_id
338         crt["signatureValue"] = BitString(hexdec("".join((
339             "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
340             "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
341         ))))
342         self.assertSequenceEqual(crt.encode(), raw)
343
344
345 class TestGoPayPalVector(TestCase):
346     def runTest(self):
347         raw = hexdec("".join((
348             "30820644308205ada003020102020300f09b300d06092a864886f70d010105050",
349             "030820112310b3009060355040613024553311230100603550408130942617263",
350             "656c6f6e61311230100603550407130942617263656c6f6e61312930270603550",
351             "40a13204950532043657274696669636174696f6e20417574686f726974792073",
352             "2e6c2e312e302c060355040a142567656e6572616c4069707363612e636f6d204",
353             "32e492e462e2020422d423632323130363935312e302c060355040b1325697073",
354             "434120434c41534541312043657274696669636174696f6e20417574686f72697",
355             "479312e302c06035504031325697073434120434c415345413120436572746966",
356             "69636174696f6e20417574686f726974793120301e06092a864886f70d0109011",
357             "61167656e6572616c4069707363612e636f6d301e170d30393032323432333034",
358             "31375a170d3131303232343233303431375a308194310b3009060355040613025",
359             "553311330110603550408130a43616c69666f726e696131163014060355040713",
360             "0d53616e204672616e636973636f3111300f060355040a1308536563757269747",
361             "931143012060355040b130b53656375726520556e6974312f302d060355040313",
362             "267777772e70617970616c2e636f6d0073736c2e736563757265636f6e6e65637",
363             "4696f6e2e636330819f300d06092a864886f70d010101050003818d0030818902",
364             "818100d269fa6f3a00b4211bc8b102d73f19b2c46db454f88b8accdb72c29e3c6",
365             "0b9c6913d82b77d99ffd12984c173539c82ddfc248c77d541f3e81e42a1ad2d9e",
366             "ff5b1026ce9d571773162338c8d6f1baa3965b16674a4f73973a4d14a4f4e23f8",
367             "b058342d1d0dc2f7ae5b610b211c0dc212a90ffae97715a4981ac40f33bb859b2",
368             "4f0203010001a38203213082031d30090603551d1304023000301106096086480",
369             "186f8420101040403020640300b0603551d0f0404030203f830130603551d2504",
370             "0c300a06082b06010505070301301d0603551d0e04160414618f61344355147f2",
371             "709ce4c8bea9b7b1925bc6e301f0603551d230418301680140e0760d439c91b5b",
372             "5d907b23c8d2349d4a9a463930090603551d1104023000301c0603551d1204153",
373             "013811167656e6572616c4069707363612e636f6d307206096086480186f84201",
374             "0d046516634f7267616e697a6174696f6e20496e666f726d6174696f6e204e4f5",
375             "42056414c4944415445442e20434c415345413120536572766572204365727469",
376             "666963617465206973737565642062792068747470733a2f2f7777772e6970736",
377             "3612e636f6d2f302f06096086480186f84201020422162068747470733a2f2f77",
378             "77772e69707363612e636f6d2f6970736361323030322f304306096086480186f",
379             "84201040436163468747470733a2f2f7777772e69707363612e636f6d2f697073",
380             "6361323030322f697073636132303032434c41534541312e63726c30460609608",
381             "6480186f84201030439163768747470733a2f2f7777772e69707363612e636f6d",
382             "2f6970736361323030322f7265766f636174696f6e434c41534541312e68746d6",
383             "c3f304306096086480186f84201070436163468747470733a2f2f7777772e6970",
384             "7363612e636f6d2f6970736361323030322f72656e6577616c434c41534541312",
385             "e68746d6c3f304106096086480186f84201080434163268747470733a2f2f7777",
386             "772e69707363612e636f6d2f6970736361323030322f706f6c696379434c41534",
387             "541312e68746d6c3081830603551d1f047c307a3039a037a0358633687474703a",
388             "2f2f7777772e69707363612e636f6d2f6970736361323030322f6970736361323",
389             "03032434c41534541312e63726c303da03ba0398637687474703a2f2f77777762",
390             "61636b2e69707363612e636f6d2f6970736361323030322f69707363613230303",
391             "2434c41534541312e63726c303206082b0601050507010104263024302206082b",
392             "060105050730018616687474703a2f2f6f6373702e69707363612e636f6d2f300",
393             "d06092a864886f70d01010505000381810068ee799797dd3bef166a06f2149a6e",
394             "cd9e12f7aa8310bdd17c98fac7aed40e2c9e38059d5260a9990a81b498901daeb",
395             "b4ad7b9dc889e3778415bf782a5f2ba41255a901a1e4538a1525875942644fb20",
396             "07ba44cce54a2d723f9847f626dc054605076321ab469b9c78d5545b3d0c1ec86",
397             "48cb55023826fdbb8221c439607a8bb",
398         )))
399         crt = Certificate().decod(raw)
400         self.assertSequenceEqual(crt.encode(), raw)
401         pprint(crt)
402         repr(crt)