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