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