2 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures
3 # Copyright (C) 2017-2020 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 unittest import TestCase
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
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
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"),
71 stroid2name = {str(oid): name for name, oid in name2oid.items()}
74 class Version(Integer):
82 class CertificateSerialNumber(Integer):
86 class AlgorithmIdentifier(Sequence):
88 ("algorithm", ObjectIdentifier()),
89 ("parameters", Any(optional=True)),
93 class AttributeType(ObjectIdentifier):
97 class AttributeValue(Any):
101 class OrganizationName(Choice):
103 ("printableString", PrintableString()),
104 ("teletexString", TeletexString()),
108 class CommonName(Choice):
110 ("printableString", PrintableString()),
111 ("utf8String", UTF8String()),
115 class AttributeTypeAndValue(Sequence):
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(),
124 ("value", AttributeValue()),
128 class RelativeDistinguishedName(SetOf):
129 schema = AttributeTypeAndValue()
130 bounds = (1, float("+inf"))
133 class RDNSequence(SequenceOf):
134 schema = RelativeDistinguishedName()
139 ("rdnSequence", RDNSequence()),
145 ("utcTime", UTCTime()),
146 ("generalTime", GeneralizedTime()),
150 class Validity(Sequence):
152 ("notBefore", Time()),
153 ("notAfter", Time()),
157 class SubjectPublicKeyInfo(Sequence):
159 ("algorithm", AlgorithmIdentifier()),
160 ("subjectPublicKey", BitString()),
164 class UniqueIdentifier(BitString):
168 class KeyIdentifier(OctetString):
172 class SubjectKeyIdentifier(KeyIdentifier):
177 class Extension(Sequence):
179 ("extnID", ObjectIdentifier()),
180 ("critical", Boolean(default=False)),
181 ("extnValue", OctetString()),
185 class Extensions(SequenceOf):
187 bounds = (1, float("+inf"))
190 class TBSCertificate(Sequence):
192 ("version", Version(expl=tag_ctxc(0), default="v1")),
193 ("serialNumber", CertificateSerialNumber()),
194 ("signature", AlgorithmIdentifier()),
196 ("validity", Validity()),
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)),
205 class Certificate(Sequence):
207 ("tbsCertificate", TBSCertificate()),
208 ("signatureAlgorithm", AlgorithmIdentifier()),
209 ("signatureValue", BitString()),
214 class TestGoSelfSignedVector(TestCase):
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",
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)
242 def assert_raw_equals(obj, expect):
243 self.assertTrue(obj.decoded)
244 self.assertSequenceEqual(
245 raw[obj.offset:obj.offset + obj.tlvlen],
248 assert_raw_equals(tbs["serialNumber"], Integer(10143011886257155224))
249 algo_id = AlgorithmIdentifier((
250 ("algorithm", name2oid["id-sha1WithRSAEncryption"]),
251 ("parameters", Any(Null())),
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"),
265 RelativeDistinguishedName((
266 AttributeTypeAndValue((
267 ("type", AttributeType(oid)),
268 ("value", AttributeValue(klass(text))),
272 issuer = Name(("rdnSequence", rdnSeq))
273 self.assertEqual(tbs["issuer"], issuer)
274 assert_raw_equals(tbs["issuer"], issuer)
275 validity = Validity((
277 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53)))
280 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53)))
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",
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",
306 self.assertSequenceEqual(crt.encode(), raw)
309 pickle_loads(pickle_dumps(crt, pickle_proto))
311 tbs = TBSCertificate()
312 tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
314 sign_algo_id = AlgorithmIdentifier((
315 ("algorithm", name2oid["id-sha1WithRSAEncryption"]),
316 ("parameters", Any(Null())),
318 tbs["signature"] = sign_algo_id
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"),
330 RelativeDistinguishedName((
331 AttributeTypeAndValue((
332 ("type", AttributeType(oid)),
333 ("value", AttributeValue(klass(text))),
338 issuer["rdnSequence"] = rdnSeq
339 tbs["issuer"] = issuer
340 tbs["subject"] = issuer
342 validity = Validity((
344 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53)),),
347 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53)),),
350 tbs["validity"] = validity
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",
361 tbs["subjectPublicKeyInfo"] = spki
364 crt["tbsCertificate"] = tbs
365 crt["signatureAlgorithm"] = sign_algo_id
366 crt["signatureValue"] = BitString(hexdec("".join((
367 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
368 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
370 self.assertSequenceEqual(crt.encode(), raw)
372 Certificate().decod(encode_cer(crt), ctx={"bered": True}),
377 class TestGoPayPalVector(TestCase):
378 """PayPal certificate with "www.paypal.com\x00ssl.secureconnection.cc" name
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",
433 with assertRaisesRegex(self, DecodeError, "alphabet value"):
434 crt = Certificate().decod(raw)