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