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