2 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures
3 # Copyright (C) 2017-2022 Sergey Matveev <stargrave@stargrave.org>
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.
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.
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/>.
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
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
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"),
69 stroid2name = {str(oid): name for name, oid in name2oid.items()}
72 class Version(Integer):
80 class CertificateSerialNumber(Integer):
84 class AlgorithmIdentifier(Sequence):
86 ("algorithm", ObjectIdentifier()),
87 ("parameters", Any(optional=True)),
91 class AttributeType(ObjectIdentifier):
95 class AttributeValue(Any):
99 class OrganizationName(Choice):
101 ("printableString", PrintableString()),
102 ("teletexString", TeletexString()),
106 class CommonName(Choice):
108 ("printableString", PrintableString()),
109 ("utf8String", UTF8String()),
113 class AttributeTypeAndValue(Sequence):
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(),
122 ("value", AttributeValue()),
126 class RelativeDistinguishedName(SetOf):
127 schema = AttributeTypeAndValue()
128 bounds = (1, float("+inf"))
131 class RDNSequence(SequenceOf):
132 schema = RelativeDistinguishedName()
137 ("rdnSequence", RDNSequence()),
143 ("utcTime", UTCTime()),
144 ("generalTime", GeneralizedTime()),
148 class Validity(Sequence):
150 ("notBefore", Time()),
151 ("notAfter", Time()),
155 class SubjectPublicKeyInfo(Sequence):
157 ("algorithm", AlgorithmIdentifier()),
158 ("subjectPublicKey", BitString()),
162 class UniqueIdentifier(BitString):
166 class KeyIdentifier(OctetString):
170 class SubjectKeyIdentifier(KeyIdentifier):
174 class Extension(Sequence):
176 ("extnID", ObjectIdentifier()),
177 ("critical", Boolean(default=False)),
178 ("extnValue", OctetString()),
182 class Extensions(SequenceOf):
184 bounds = (1, float("+inf"))
187 class TBSCertificate(Sequence):
189 ("version", Version(expl=tag_ctxc(0), default="v1")),
190 ("serialNumber", CertificateSerialNumber()),
191 ("signature", AlgorithmIdentifier()),
193 ("validity", Validity()),
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)),
202 class Certificate(Sequence):
204 ("tbsCertificate", TBSCertificate()),
205 ("signatureAlgorithm", AlgorithmIdentifier()),
206 ("signatureValue", BitString()),
211 class TestGoSelfSignedVector(TestCase):
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",
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)
239 def assert_raw_equals(obj, expect):
240 self.assertTrue(obj.decoded)
241 self.assertSequenceEqual(
242 raw[obj.offset:obj.offset + obj.tlvlen],
245 assert_raw_equals(tbs["serialNumber"], Integer(10143011886257155224))
246 algo_id = AlgorithmIdentifier((
247 ("algorithm", name2oid["id-sha1WithRSAEncryption"]),
248 ("parameters", Any(Null())),
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"),
262 RelativeDistinguishedName((
263 AttributeTypeAndValue((
264 ("type", AttributeType(oid)),
265 ("value", AttributeValue(klass(text))),
269 issuer = Name(("rdnSequence", rdnSeq))
270 self.assertEqual(tbs["issuer"], issuer)
271 assert_raw_equals(tbs["issuer"], issuer)
272 validity = Validity((
274 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53)))
277 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53)))
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",
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",
303 self.assertSequenceEqual(crt.encode(), raw)
304 crt = Certificate().decod(raw)
307 pickle_loads(pickle_dumps(crt, pickle_proto))
309 tbs = TBSCertificate()
310 tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
312 sign_algo_id = AlgorithmIdentifier((
313 ("algorithm", name2oid["id-sha1WithRSAEncryption"]),
314 ("parameters", Any(Null())),
316 tbs["signature"] = sign_algo_id
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"),
328 RelativeDistinguishedName((
329 AttributeTypeAndValue((
330 ("type", AttributeType(oid)),
331 ("value", AttributeValue(klass(text))),
336 issuer["rdnSequence"] = rdnSeq
337 tbs["issuer"] = issuer
338 tbs["subject"] = issuer
340 validity = Validity((
342 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53)),),
345 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53)),),
348 tbs["validity"] = validity
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",
359 tbs["subjectPublicKeyInfo"] = spki
362 crt["tbsCertificate"] = tbs
363 crt["signatureAlgorithm"] = sign_algo_id
364 crt["signatureValue"] = BitString(hexdec("".join((
365 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
366 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
368 self.assertSequenceEqual(crt.encode(), raw)
370 Certificate().decod(encode_cer(crt), ctx={"bered": True}),
375 class TestGoPayPalVector(TestCase):
376 """PayPal certificate with "www.paypal.com\x00ssl.secureconnection.cc" name
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",
431 with self.assertRaisesRegex(DecodeError, "alphabet value"):
432 crt = Certificate().decod(raw)