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.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
26 from pyderasn import Any
27 from pyderasn import BitString
28 from pyderasn import Boolean
29 from pyderasn import Choice
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
50 "id-rsaEncryption": ObjectIdentifier("1.2.840.113549.1.1.1"),
51 "id-sha1WithRSAEncryption": ObjectIdentifier("1.2.840.113549.1.1.5"),
52 "id-emailAddress": ObjectIdentifier("1.2.840.113549.1.9.1"),
53 "id-ce-subjectKeyIdentifier": ObjectIdentifier("2.5.29.14"),
54 "id-ce-keyUsage": ObjectIdentifier("2.5.29.15"),
55 "id-ce-subjectAltName": ObjectIdentifier("2.5.29.17"),
56 "id-ce-issuerAltName": ObjectIdentifier("2.5.29.18"),
57 "id-ce-basicConstraints": ObjectIdentifier("2.5.29.19"),
58 "id-ce-cRLDistributionPoints": ObjectIdentifier("2.5.29.31"),
59 "id-ce-authorityKeyIdentifier": ObjectIdentifier("2.5.29.35"),
60 "id-ce-extKeyUsage": ObjectIdentifier("2.5.29.37"),
61 "id-at-commonName": ObjectIdentifier("2.5.4.3"),
62 "id-at-countryName": ObjectIdentifier("2.5.4.6"),
63 "id-at-localityName": ObjectIdentifier("2.5.4.7"),
64 "id-at-stateOrProvinceName": ObjectIdentifier("2.5.4.8"),
65 "id-at-organizationName": ObjectIdentifier("2.5.4.10"),
66 "id-at-organizationalUnitName": ObjectIdentifier("2.5.4.11"),
68 stroid2name = {str(oid): name for name, oid in name2oid.items()}
71 class Version(Integer):
79 class CertificateSerialNumber(Integer):
83 class AlgorithmIdentifier(Sequence):
85 ("algorithm", ObjectIdentifier()),
86 ("parameters", Any(optional=True)),
90 class AttributeType(ObjectIdentifier):
94 class AttributeValue(Any):
98 class OrganizationName(Choice):
100 ("printableString", PrintableString()),
101 ("teletexString", TeletexString()),
105 class AttributeTypeAndValue(Sequence):
107 ("type", AttributeType(defines=(((".", "value"), {
108 name2oid["id-at-countryName"]: PrintableString(),
109 name2oid["id-at-localityName"]: PrintableString(),
110 name2oid["id-at-stateOrProvinceName"]: PrintableString(),
111 name2oid["id-at-organizationName"]: OrganizationName(),
112 name2oid["id-at-commonName"]: PrintableString(),
114 ("value", AttributeValue()),
118 class RelativeDistinguishedName(SetOf):
119 schema = AttributeTypeAndValue()
120 bounds = (1, float("+inf"))
123 class RDNSequence(SequenceOf):
124 schema = RelativeDistinguishedName()
129 ("rdnSequence", RDNSequence()),
135 ("utcTime", UTCTime()),
136 ("generalTime", GeneralizedTime()),
140 class Validity(Sequence):
142 ("notBefore", Time()),
143 ("notAfter", Time()),
147 class SubjectPublicKeyInfo(Sequence):
149 ("algorithm", AlgorithmIdentifier()),
150 ("subjectPublicKey", BitString()),
154 class UniqueIdentifier(BitString):
158 class KeyIdentifier(OctetString):
162 class SubjectKeyIdentifier(KeyIdentifier):
167 class Extension(Sequence):
169 ("extnID", ObjectIdentifier()),
170 ("critical", Boolean(default=False)),
171 ("extnValue", OctetString()),
175 class Extensions(SequenceOf):
177 bounds = (1, float("+inf"))
180 class TBSCertificate(Sequence):
182 ("version", Version(expl=tag_ctxc(0), default="v1")),
183 ("serialNumber", CertificateSerialNumber()),
184 ("signature", AlgorithmIdentifier()),
186 ("validity", Validity()),
188 ("subjectPublicKeyInfo", SubjectPublicKeyInfo()),
189 ("issuerUniqueID", UniqueIdentifier(impl=tag_ctxp(1), optional=True)),
190 ("subjectUniqueID", UniqueIdentifier(impl=tag_ctxp(2), optional=True)),
191 ("extensions", Extensions(expl=tag_ctxc(3), optional=True)),
195 class Certificate(Sequence):
197 ("tbsCertificate", TBSCertificate()),
198 ("signatureAlgorithm", AlgorithmIdentifier()),
199 ("signatureValue", BitString()),
204 class TestGoSelfSignedVector(TestCase):
206 raw = hexdec("".join((
207 "30820218308201c20209008cc3379210ec2c98300d06092a864886f70d0101050",
208 "500308192310b3009060355040613025858311330110603550408130a536f6d65",
209 "2d5374617465310d300b06035504071304436974793121301f060355040a13184",
210 "96e7465726e6574205769646769747320507479204c7464311a30180603550403",
211 "131166616c73652e6578616d706c652e636f6d3120301e06092a864886f70d010",
212 "901161166616c7365406578616d706c652e636f6d301e170d3039313030383030",
213 "323535335a170d3130313030383030323535335a308192310b300906035504061",
214 "3025858311330110603550408130a536f6d652d5374617465310d300b06035504",
215 "071304436974793121301f060355040a1318496e7465726e65742057696467697",
216 "47320507479204c7464311a30180603550403131166616c73652e6578616d706c",
217 "652e636f6d3120301e06092a864886f70d010901161166616c7365406578616d7",
218 "06c652e636f6d305c300d06092a864886f70d0101010500034b003048024100cd",
219 "b7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695a331b1deadea",
220 "dd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8fdeec357d0203",
221 "010001300d06092a864886f70d0101050500034100a67b06ec5ece92772ca413c",
222 "ba3ca12568fdc6c7b4511cd40a7f659980402df2b998bb9a4a8cbeb34c0f0a78c",
223 "f8d91ede14a5ed76bf116fe360aafa8821490435",
225 crt = Certificate().decod(raw)
226 tbs = crt["tbsCertificate"]
227 self.assertEqual(tbs["version"], 0)
228 self.assertFalse(tbs["version"].decoded)
229 self.assertNotIn("version", tbs)
230 self.assertEqual(tbs["serialNumber"], 10143011886257155224)
232 def assert_raw_equals(obj, expect):
233 self.assertTrue(obj.decoded)
234 self.assertSequenceEqual(
235 raw[obj.offset:obj.offset + obj.tlvlen],
238 assert_raw_equals(tbs["serialNumber"], Integer(10143011886257155224))
239 algo_id = AlgorithmIdentifier((
240 ("algorithm", name2oid["id-sha1WithRSAEncryption"]),
241 ("parameters", Any(Null())),
243 self.assertEqual(tbs["signature"], algo_id)
244 assert_raw_equals(tbs["signature"], algo_id)
245 rdnSeq = RDNSequence()
246 for oid, klass, text in (
247 ("2.5.4.6", PrintableString, "XX"),
248 ("2.5.4.8", PrintableString, "Some-State"),
249 ("2.5.4.7", PrintableString, "City"),
250 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
251 ("2.5.4.3", PrintableString, "false.example.com"),
252 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
255 RelativeDistinguishedName((
256 AttributeTypeAndValue((
257 ("type", AttributeType(oid)),
258 ("value", AttributeValue(klass(text))),
262 issuer = Name(("rdnSequence", rdnSeq))
263 self.assertEqual(tbs["issuer"], issuer)
264 assert_raw_equals(tbs["issuer"], issuer)
265 validity = Validity((
267 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53)))
270 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53)))
273 self.assertEqual(tbs["validity"], validity)
274 assert_raw_equals(tbs["validity"], validity)
275 self.assertEqual(tbs["subject"], issuer)
276 assert_raw_equals(tbs["subject"], issuer)
277 spki = SubjectPublicKeyInfo()
278 algo_id["algorithm"] = name2oid["id-rsaEncryption"]
279 spki["algorithm"] = algo_id
280 spki["subjectPublicKey"] = BitString(hexdec("".join((
281 "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
282 "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
283 "deec357d0203010001",
285 self.assertEqual(tbs["subjectPublicKeyInfo"], spki)
286 assert_raw_equals(tbs["subjectPublicKeyInfo"], spki)
287 self.assertNotIn("issuerUniqueID", tbs)
288 self.assertNotIn("subjectUniqueID", tbs)
289 self.assertNotIn("extensions", tbs)
290 algo_id["algorithm"] = name2oid["id-sha1WithRSAEncryption"]
291 self.assertEqual(crt["signatureAlgorithm"], algo_id)
292 self.assertEqual(crt["signatureValue"], BitString(hexdec("".join((
293 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
294 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
296 self.assertSequenceEqual(crt.encode(), raw)
299 pickle_loads(pickle_dumps(crt, pickle_proto))
301 tbs = TBSCertificate()
302 tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
304 sign_algo_id = AlgorithmIdentifier((
305 ("algorithm", name2oid["id-sha1WithRSAEncryption"]),
306 ("parameters", Any(Null())),
308 tbs["signature"] = sign_algo_id
310 rdnSeq = RDNSequence()
311 for oid, klass, text in (
312 ("2.5.4.6", PrintableString, "XX"),
313 ("2.5.4.8", PrintableString, "Some-State"),
314 ("2.5.4.7", PrintableString, "City"),
315 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
316 ("2.5.4.3", PrintableString, "false.example.com"),
317 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
320 RelativeDistinguishedName((
321 AttributeTypeAndValue((
322 ("type", AttributeType(oid)),
323 ("value", AttributeValue(klass(text))),
328 issuer["rdnSequence"] = rdnSeq
329 tbs["issuer"] = issuer
330 tbs["subject"] = issuer
332 validity = Validity((
334 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53)),),
337 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53)),),
340 tbs["validity"] = validity
342 spki = SubjectPublicKeyInfo()
343 spki_algo_id = copy(sign_algo_id)
344 spki_algo_id["algorithm"] = name2oid["id-rsaEncryption"]
345 spki["algorithm"] = spki_algo_id
346 spki["subjectPublicKey"] = BitString(hexdec("".join((
347 "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
348 "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
349 "deec357d0203010001",
351 tbs["subjectPublicKeyInfo"] = spki
354 crt["tbsCertificate"] = tbs
355 crt["signatureAlgorithm"] = sign_algo_id
356 crt["signatureValue"] = BitString(hexdec("".join((
357 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
358 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
360 self.assertSequenceEqual(crt.encode(), raw)
362 Certificate().decod(encode_cer(crt), ctx={"bered": True}),
367 class TestGoPayPalVector(TestCase):
369 raw = hexdec("".join((
370 "30820644308205ada003020102020300f09b300d06092a864886f70d010105050",
371 "030820112310b3009060355040613024553311230100603550408130942617263",
372 "656c6f6e61311230100603550407130942617263656c6f6e61312930270603550",
373 "40a13204950532043657274696669636174696f6e20417574686f726974792073",
374 "2e6c2e312e302c060355040a142567656e6572616c4069707363612e636f6d204",
375 "32e492e462e2020422d423632323130363935312e302c060355040b1325697073",
376 "434120434c41534541312043657274696669636174696f6e20417574686f72697",
377 "479312e302c06035504031325697073434120434c415345413120436572746966",
378 "69636174696f6e20417574686f726974793120301e06092a864886f70d0109011",
379 "61167656e6572616c4069707363612e636f6d301e170d30393032323432333034",
380 "31375a170d3131303232343233303431375a308194310b3009060355040613025",
381 "553311330110603550408130a43616c69666f726e696131163014060355040713",
382 "0d53616e204672616e636973636f3111300f060355040a1308536563757269747",
383 "931143012060355040b130b53656375726520556e6974312f302d060355040313",
384 "267777772e70617970616c2e636f6d0073736c2e736563757265636f6e6e65637",
385 "4696f6e2e636330819f300d06092a864886f70d010101050003818d0030818902",
386 "818100d269fa6f3a00b4211bc8b102d73f19b2c46db454f88b8accdb72c29e3c6",
387 "0b9c6913d82b77d99ffd12984c173539c82ddfc248c77d541f3e81e42a1ad2d9e",
388 "ff5b1026ce9d571773162338c8d6f1baa3965b16674a4f73973a4d14a4f4e23f8",
389 "b058342d1d0dc2f7ae5b610b211c0dc212a90ffae97715a4981ac40f33bb859b2",
390 "4f0203010001a38203213082031d30090603551d1304023000301106096086480",
391 "186f8420101040403020640300b0603551d0f0404030203f830130603551d2504",
392 "0c300a06082b06010505070301301d0603551d0e04160414618f61344355147f2",
393 "709ce4c8bea9b7b1925bc6e301f0603551d230418301680140e0760d439c91b5b",
394 "5d907b23c8d2349d4a9a463930090603551d1104023000301c0603551d1204153",
395 "013811167656e6572616c4069707363612e636f6d307206096086480186f84201",
396 "0d046516634f7267616e697a6174696f6e20496e666f726d6174696f6e204e4f5",
397 "42056414c4944415445442e20434c415345413120536572766572204365727469",
398 "666963617465206973737565642062792068747470733a2f2f7777772e6970736",
399 "3612e636f6d2f302f06096086480186f84201020422162068747470733a2f2f77",
400 "77772e69707363612e636f6d2f6970736361323030322f304306096086480186f",
401 "84201040436163468747470733a2f2f7777772e69707363612e636f6d2f697073",
402 "6361323030322f697073636132303032434c41534541312e63726c30460609608",
403 "6480186f84201030439163768747470733a2f2f7777772e69707363612e636f6d",
404 "2f6970736361323030322f7265766f636174696f6e434c41534541312e68746d6",
405 "c3f304306096086480186f84201070436163468747470733a2f2f7777772e6970",
406 "7363612e636f6d2f6970736361323030322f72656e6577616c434c41534541312",
407 "e68746d6c3f304106096086480186f84201080434163268747470733a2f2f7777",
408 "772e69707363612e636f6d2f6970736361323030322f706f6c696379434c41534",
409 "541312e68746d6c3081830603551d1f047c307a3039a037a0358633687474703a",
410 "2f2f7777772e69707363612e636f6d2f6970736361323030322f6970736361323",
411 "03032434c41534541312e63726c303da03ba0398637687474703a2f2f77777762",
412 "61636b2e69707363612e636f6d2f6970736361323030322f69707363613230303",
413 "2434c41534541312e63726c303206082b0601050507010104263024302206082b",
414 "060105050730018616687474703a2f2f6f6373702e69707363612e636f6d2f300",
415 "d06092a864886f70d01010505000381810068ee799797dd3bef166a06f2149a6e",
416 "cd9e12f7aa8310bdd17c98fac7aed40e2c9e38059d5260a9990a81b498901daeb",
417 "b4ad7b9dc889e3778415bf782a5f2ba41255a901a1e4538a1525875942644fb20",
418 "07ba44cce54a2d723f9847f626dc054605076321ab469b9c78d5545b3d0c1ec86",
419 "48cb55023826fdbb8221c439607a8bb",
421 crt = Certificate().decod(raw)
422 self.assertSequenceEqual(crt.encode(), raw)
425 pickle_loads(pickle_dumps(crt, pickle_proto))
427 Certificate().decod(encode_cer(crt), ctx={"bered": True}),