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