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