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