2 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures
3 # Copyright (C) 2017-2021 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)
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)
306 pickle_loads(pickle_dumps(crt, pickle_proto))
308 tbs = TBSCertificate()
309 tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
311 sign_algo_id = AlgorithmIdentifier((
312 ("algorithm", name2oid["id-sha1WithRSAEncryption"]),
313 ("parameters", Any(Null())),
315 tbs["signature"] = sign_algo_id
317 rdnSeq = RDNSequence()
318 for oid, klass, text in (
319 ("2.5.4.6", PrintableString, "XX"),
320 ("2.5.4.8", PrintableString, "Some-State"),
321 ("2.5.4.7", PrintableString, "City"),
322 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
323 ("2.5.4.3", PrintableString, "false.example.com"),
324 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
327 RelativeDistinguishedName((
328 AttributeTypeAndValue((
329 ("type", AttributeType(oid)),
330 ("value", AttributeValue(klass(text))),
335 issuer["rdnSequence"] = rdnSeq
336 tbs["issuer"] = issuer
337 tbs["subject"] = issuer
339 validity = Validity((
341 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53)),),
344 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53)),),
347 tbs["validity"] = validity
349 spki = SubjectPublicKeyInfo()
350 spki_algo_id = copy(sign_algo_id)
351 spki_algo_id["algorithm"] = name2oid["id-rsaEncryption"]
352 spki["algorithm"] = spki_algo_id
353 spki["subjectPublicKey"] = BitString(hexdec("".join((
354 "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
355 "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
356 "deec357d0203010001",
358 tbs["subjectPublicKeyInfo"] = spki
361 crt["tbsCertificate"] = tbs
362 crt["signatureAlgorithm"] = sign_algo_id
363 crt["signatureValue"] = BitString(hexdec("".join((
364 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
365 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
367 self.assertSequenceEqual(crt.encode(), raw)
369 Certificate().decod(encode_cer(crt), ctx={"bered": True}),
374 class TestGoPayPalVector(TestCase):
375 """PayPal certificate with "www.paypal.com\x00ssl.secureconnection.cc" name
378 raw = hexdec("".join((
379 "30820644308205ada003020102020300f09b300d06092a864886f70d010105050",
380 "030820112310b3009060355040613024553311230100603550408130942617263",
381 "656c6f6e61311230100603550407130942617263656c6f6e61312930270603550",
382 "40a13204950532043657274696669636174696f6e20417574686f726974792073",
383 "2e6c2e312e302c060355040a142567656e6572616c4069707363612e636f6d204",
384 "32e492e462e2020422d423632323130363935312e302c060355040b1325697073",
385 "434120434c41534541312043657274696669636174696f6e20417574686f72697",
386 "479312e302c06035504031325697073434120434c415345413120436572746966",
387 "69636174696f6e20417574686f726974793120301e06092a864886f70d0109011",
388 "61167656e6572616c4069707363612e636f6d301e170d30393032323432333034",
389 "31375a170d3131303232343233303431375a308194310b3009060355040613025",
390 "553311330110603550408130a43616c69666f726e696131163014060355040713",
391 "0d53616e204672616e636973636f3111300f060355040a1308536563757269747",
392 "931143012060355040b130b53656375726520556e6974312f302d060355040313",
393 "267777772e70617970616c2e636f6d0073736c2e736563757265636f6e6e65637",
394 "4696f6e2e636330819f300d06092a864886f70d010101050003818d0030818902",
395 "818100d269fa6f3a00b4211bc8b102d73f19b2c46db454f88b8accdb72c29e3c6",
396 "0b9c6913d82b77d99ffd12984c173539c82ddfc248c77d541f3e81e42a1ad2d9e",
397 "ff5b1026ce9d571773162338c8d6f1baa3965b16674a4f73973a4d14a4f4e23f8",
398 "b058342d1d0dc2f7ae5b610b211c0dc212a90ffae97715a4981ac40f33bb859b2",
399 "4f0203010001a38203213082031d30090603551d1304023000301106096086480",
400 "186f8420101040403020640300b0603551d0f0404030203f830130603551d2504",
401 "0c300a06082b06010505070301301d0603551d0e04160414618f61344355147f2",
402 "709ce4c8bea9b7b1925bc6e301f0603551d230418301680140e0760d439c91b5b",
403 "5d907b23c8d2349d4a9a463930090603551d1104023000301c0603551d1204153",
404 "013811167656e6572616c4069707363612e636f6d307206096086480186f84201",
405 "0d046516634f7267616e697a6174696f6e20496e666f726d6174696f6e204e4f5",
406 "42056414c4944415445442e20434c415345413120536572766572204365727469",
407 "666963617465206973737565642062792068747470733a2f2f7777772e6970736",
408 "3612e636f6d2f302f06096086480186f84201020422162068747470733a2f2f77",
409 "77772e69707363612e636f6d2f6970736361323030322f304306096086480186f",
410 "84201040436163468747470733a2f2f7777772e69707363612e636f6d2f697073",
411 "6361323030322f697073636132303032434c41534541312e63726c30460609608",
412 "6480186f84201030439163768747470733a2f2f7777772e69707363612e636f6d",
413 "2f6970736361323030322f7265766f636174696f6e434c41534541312e68746d6",
414 "c3f304306096086480186f84201070436163468747470733a2f2f7777772e6970",
415 "7363612e636f6d2f6970736361323030322f72656e6577616c434c41534541312",
416 "e68746d6c3f304106096086480186f84201080434163268747470733a2f2f7777",
417 "772e69707363612e636f6d2f6970736361323030322f706f6c696379434c41534",
418 "541312e68746d6c3081830603551d1f047c307a3039a037a0358633687474703a",
419 "2f2f7777772e69707363612e636f6d2f6970736361323030322f6970736361323",
420 "03032434c41534541312e63726c303da03ba0398637687474703a2f2f77777762",
421 "61636b2e69707363612e636f6d2f6970736361323030322f69707363613230303",
422 "2434c41534541312e63726c303206082b0601050507010104263024302206082b",
423 "060105050730018616687474703a2f2f6f6373702e69707363612e636f6d2f300",
424 "d06092a864886f70d01010505000381810068ee799797dd3bef166a06f2149a6e",
425 "cd9e12f7aa8310bdd17c98fac7aed40e2c9e38059d5260a9990a81b498901daeb",
426 "b4ad7b9dc889e3778415bf782a5f2ba41255a901a1e4538a1525875942644fb20",
427 "07ba44cce54a2d723f9847f626dc054605076321ab469b9c78d5545b3d0c1ec86",
428 "48cb55023826fdbb8221c439607a8bb",
430 with self.assertRaisesRegex(DecodeError, "alphabet value"):
431 crt = Certificate().decod(raw)