2 # PyDERASN -- Python ASN.1 DER 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 GeneralizedTime
31 from pyderasn import hexdec
32 from pyderasn import IA5String
33 from pyderasn import Integer
34 from pyderasn import Null
35 from pyderasn import ObjectIdentifier
36 from pyderasn import OctetString
37 from pyderasn import pprint
38 from pyderasn import PrintableString
39 from pyderasn import Sequence
40 from pyderasn import SequenceOf
41 from pyderasn import SetOf
42 from pyderasn import tag_ctxc
43 from pyderasn import tag_ctxp
44 from pyderasn import TeletexString
45 from pyderasn import UTCTime
49 "1.2.840.113549.1.1.1": "id-rsaEncryption",
50 "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
51 "1.2.840.113549.1.9.1": "id-emailAddress",
52 "2.5.29.14": "id-ce-subjectKeyIdentifier",
53 "2.5.29.15": "id-ce-keyUsage",
54 "2.5.29.17": "id-ce-subjectAltName",
55 "2.5.29.18": "id-ce-issuerAltName",
56 "2.5.29.19": "id-ce-basicConstraints",
57 "2.5.29.31": "id-ce-cRLDistributionPoints",
58 "2.5.29.35": "id-ce-authorityKeyIdentifier",
59 "2.5.29.37": "id-ce-extKeyUsage",
60 "2.5.4.3": "id-at-commonName",
61 "2.5.4.6": "id-at-countryName",
62 "2.5.4.7": "id-at-localityName",
63 "2.5.4.8": "id-at-stateOrProvinceName",
64 "2.5.4.10": "id-at-organizationName",
65 "2.5.4.11": "id-at-organizationalUnitName",
69 class Version(Integer):
77 class CertificateSerialNumber(Integer):
81 class AlgorithmIdentifier(Sequence):
83 ("algorithm", ObjectIdentifier()),
84 ("parameters", Any(optional=True)),
88 class AttributeType(ObjectIdentifier):
92 class AttributeValue(Any):
96 class OrganizationName(Choice):
98 ("printableString", PrintableString()),
99 ("teletexString", TeletexString()),
103 class AttributeTypeAndValue(Sequence):
105 ("type", AttributeType(defines=(((".", "value"), {
106 ObjectIdentifier("2.5.4.6"): PrintableString(),
107 ObjectIdentifier("2.5.4.8"): PrintableString(),
108 ObjectIdentifier("2.5.4.7"): PrintableString(),
109 ObjectIdentifier("2.5.4.10"): OrganizationName(),
110 ObjectIdentifier("2.5.4.3"): PrintableString(),
112 ("value", AttributeValue()),
116 class RelativeDistinguishedName(SetOf):
117 schema = AttributeTypeAndValue()
118 bounds = (1, float("+inf"))
121 class RDNSequence(SequenceOf):
122 schema = RelativeDistinguishedName()
127 ("rdnSequence", RDNSequence()),
133 ("utcTime", UTCTime()),
134 ("generalTime", GeneralizedTime()),
138 class Validity(Sequence):
140 ("notBefore", Time()),
141 ("notAfter", Time()),
145 class SubjectPublicKeyInfo(Sequence):
147 ("algorithm", AlgorithmIdentifier()),
148 ("subjectPublicKey", BitString()),
152 class UniqueIdentifier(BitString):
156 class Extension(Sequence):
158 ("extnID", ObjectIdentifier()),
159 ("critical", Boolean(default=False)),
160 ("extnValue", OctetString()),
164 class Extensions(SequenceOf):
166 bounds = (1, float("+inf"))
169 class TBSCertificate(Sequence):
171 ("version", Version(expl=tag_ctxc(0), default="v1")),
172 ("serialNumber", CertificateSerialNumber()),
173 ("signature", AlgorithmIdentifier()),
175 ("validity", Validity()),
177 ("subjectPublicKeyInfo", SubjectPublicKeyInfo()),
178 ("issuerUniqueID", UniqueIdentifier(impl=tag_ctxp(1), optional=True)),
179 ("subjectUniqueID", UniqueIdentifier(impl=tag_ctxp(2), optional=True)),
180 ("extensions", Extensions(expl=tag_ctxc(3), optional=True)),
184 class Certificate(Sequence):
186 ("tbsCertificate", TBSCertificate()),
187 ("signatureAlgorithm", AlgorithmIdentifier()),
188 ("signatureValue", BitString()),
192 class TestGoSelfSignedVector(TestCase):
194 raw = hexdec("".join((
195 "30820218308201c20209008cc3379210ec2c98300d06092a864886f70d0101050",
196 "500308192310b3009060355040613025858311330110603550408130a536f6d65",
197 "2d5374617465310d300b06035504071304436974793121301f060355040a13184",
198 "96e7465726e6574205769646769747320507479204c7464311a30180603550403",
199 "131166616c73652e6578616d706c652e636f6d3120301e06092a864886f70d010",
200 "901161166616c7365406578616d706c652e636f6d301e170d3039313030383030",
201 "323535335a170d3130313030383030323535335a308192310b300906035504061",
202 "3025858311330110603550408130a536f6d652d5374617465310d300b06035504",
203 "071304436974793121301f060355040a1318496e7465726e65742057696467697",
204 "47320507479204c7464311a30180603550403131166616c73652e6578616d706c",
205 "652e636f6d3120301e06092a864886f70d010901161166616c7365406578616d7",
206 "06c652e636f6d305c300d06092a864886f70d0101010500034b003048024100cd",
207 "b7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695a331b1deadea",
208 "dd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8fdeec357d0203",
209 "010001300d06092a864886f70d0101050500034100a67b06ec5ece92772ca413c",
210 "ba3ca12568fdc6c7b4511cd40a7f659980402df2b998bb9a4a8cbeb34c0f0a78c",
211 "f8d91ede14a5ed76bf116fe360aafa8821490435",
213 crt = Certificate().decod(raw)
214 tbs = crt["tbsCertificate"]
215 self.assertEqual(tbs["version"], 0)
216 self.assertFalse(tbs["version"].decoded)
217 self.assertNotIn("version", tbs)
218 self.assertEqual(tbs["serialNumber"], 10143011886257155224)
220 def assert_raw_equals(obj, expect):
221 self.assertTrue(obj.decoded)
222 self.assertSequenceEqual(
223 raw[obj.offset:obj.offset + obj.tlvlen],
226 assert_raw_equals(tbs["serialNumber"], Integer(10143011886257155224))
227 algo_id = AlgorithmIdentifier((
228 ("algorithm", ObjectIdentifier("1.2.840.113549.1.1.5")),
229 ("parameters", Any(Null())),
231 self.assertEqual(tbs["signature"], algo_id)
232 assert_raw_equals(tbs["signature"], algo_id)
233 rdnSeq = RDNSequence()
234 for oid, klass, text in (
235 ("2.5.4.6", PrintableString, "XX"),
236 ("2.5.4.8", PrintableString, "Some-State"),
237 ("2.5.4.7", PrintableString, "City"),
238 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
239 ("2.5.4.3", PrintableString, "false.example.com"),
240 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
243 RelativeDistinguishedName((
244 AttributeTypeAndValue((
245 ("type", AttributeType(oid)),
246 ("value", AttributeValue(klass(text))),
250 issuer = Name(("rdnSequence", rdnSeq))
251 self.assertEqual(tbs["issuer"], issuer)
252 assert_raw_equals(tbs["issuer"], issuer)
253 validity = Validity((
255 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53)))
258 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53)))
261 self.assertEqual(tbs["validity"], validity)
262 assert_raw_equals(tbs["validity"], validity)
263 self.assertEqual(tbs["subject"], issuer)
264 assert_raw_equals(tbs["subject"], issuer)
265 spki = SubjectPublicKeyInfo()
266 algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
267 spki["algorithm"] = algo_id
268 spki["subjectPublicKey"] = BitString(hexdec("".join((
269 "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
270 "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
271 "deec357d0203010001",
273 self.assertEqual(tbs["subjectPublicKeyInfo"], spki)
274 assert_raw_equals(tbs["subjectPublicKeyInfo"], spki)
275 self.assertNotIn("issuerUniqueID", tbs)
276 self.assertNotIn("subjectUniqueID", tbs)
277 self.assertNotIn("extensions", tbs)
278 algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.5")
279 self.assertEqual(crt["signatureAlgorithm"], algo_id)
280 self.assertEqual(crt["signatureValue"], BitString(hexdec("".join((
281 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
282 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
284 self.assertSequenceEqual(crt.encode(), raw)
287 pickle_loads(pickle_dumps(crt, pickle_proto))
289 tbs = TBSCertificate()
290 tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
292 sign_algo_id = AlgorithmIdentifier((
293 ("algorithm", ObjectIdentifier("1.2.840.113549.1.1.5")),
294 ("parameters", Any(Null())),
296 tbs["signature"] = sign_algo_id
298 rdnSeq = RDNSequence()
299 for oid, klass, text in (
300 ("2.5.4.6", PrintableString, "XX"),
301 ("2.5.4.8", PrintableString, "Some-State"),
302 ("2.5.4.7", PrintableString, "City"),
303 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
304 ("2.5.4.3", PrintableString, "false.example.com"),
305 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
308 RelativeDistinguishedName((
309 AttributeTypeAndValue((
310 ("type", AttributeType(oid)),
311 ("value", AttributeValue(klass(text))),
316 issuer["rdnSequence"] = rdnSeq
317 tbs["issuer"] = issuer
318 tbs["subject"] = issuer
320 validity = Validity((
322 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53)),),
325 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53)),),
328 tbs["validity"] = validity
330 spki = SubjectPublicKeyInfo()
331 spki_algo_id = copy(sign_algo_id)
332 spki_algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
333 spki["algorithm"] = spki_algo_id
334 spki["subjectPublicKey"] = BitString(hexdec("".join((
335 "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
336 "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
337 "deec357d0203010001",
339 tbs["subjectPublicKeyInfo"] = spki
342 crt["tbsCertificate"] = tbs
343 crt["signatureAlgorithm"] = sign_algo_id
344 crt["signatureValue"] = BitString(hexdec("".join((
345 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
346 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
348 self.assertSequenceEqual(crt.encode(), raw)
351 class TestGoPayPalVector(TestCase):
353 raw = hexdec("".join((
354 "30820644308205ada003020102020300f09b300d06092a864886f70d010105050",
355 "030820112310b3009060355040613024553311230100603550408130942617263",
356 "656c6f6e61311230100603550407130942617263656c6f6e61312930270603550",
357 "40a13204950532043657274696669636174696f6e20417574686f726974792073",
358 "2e6c2e312e302c060355040a142567656e6572616c4069707363612e636f6d204",
359 "32e492e462e2020422d423632323130363935312e302c060355040b1325697073",
360 "434120434c41534541312043657274696669636174696f6e20417574686f72697",
361 "479312e302c06035504031325697073434120434c415345413120436572746966",
362 "69636174696f6e20417574686f726974793120301e06092a864886f70d0109011",
363 "61167656e6572616c4069707363612e636f6d301e170d30393032323432333034",
364 "31375a170d3131303232343233303431375a308194310b3009060355040613025",
365 "553311330110603550408130a43616c69666f726e696131163014060355040713",
366 "0d53616e204672616e636973636f3111300f060355040a1308536563757269747",
367 "931143012060355040b130b53656375726520556e6974312f302d060355040313",
368 "267777772e70617970616c2e636f6d0073736c2e736563757265636f6e6e65637",
369 "4696f6e2e636330819f300d06092a864886f70d010101050003818d0030818902",
370 "818100d269fa6f3a00b4211bc8b102d73f19b2c46db454f88b8accdb72c29e3c6",
371 "0b9c6913d82b77d99ffd12984c173539c82ddfc248c77d541f3e81e42a1ad2d9e",
372 "ff5b1026ce9d571773162338c8d6f1baa3965b16674a4f73973a4d14a4f4e23f8",
373 "b058342d1d0dc2f7ae5b610b211c0dc212a90ffae97715a4981ac40f33bb859b2",
374 "4f0203010001a38203213082031d30090603551d1304023000301106096086480",
375 "186f8420101040403020640300b0603551d0f0404030203f830130603551d2504",
376 "0c300a06082b06010505070301301d0603551d0e04160414618f61344355147f2",
377 "709ce4c8bea9b7b1925bc6e301f0603551d230418301680140e0760d439c91b5b",
378 "5d907b23c8d2349d4a9a463930090603551d1104023000301c0603551d1204153",
379 "013811167656e6572616c4069707363612e636f6d307206096086480186f84201",
380 "0d046516634f7267616e697a6174696f6e20496e666f726d6174696f6e204e4f5",
381 "42056414c4944415445442e20434c415345413120536572766572204365727469",
382 "666963617465206973737565642062792068747470733a2f2f7777772e6970736",
383 "3612e636f6d2f302f06096086480186f84201020422162068747470733a2f2f77",
384 "77772e69707363612e636f6d2f6970736361323030322f304306096086480186f",
385 "84201040436163468747470733a2f2f7777772e69707363612e636f6d2f697073",
386 "6361323030322f697073636132303032434c41534541312e63726c30460609608",
387 "6480186f84201030439163768747470733a2f2f7777772e69707363612e636f6d",
388 "2f6970736361323030322f7265766f636174696f6e434c41534541312e68746d6",
389 "c3f304306096086480186f84201070436163468747470733a2f2f7777772e6970",
390 "7363612e636f6d2f6970736361323030322f72656e6577616c434c41534541312",
391 "e68746d6c3f304106096086480186f84201080434163268747470733a2f2f7777",
392 "772e69707363612e636f6d2f6970736361323030322f706f6c696379434c41534",
393 "541312e68746d6c3081830603551d1f047c307a3039a037a0358633687474703a",
394 "2f2f7777772e69707363612e636f6d2f6970736361323030322f6970736361323",
395 "03032434c41534541312e63726c303da03ba0398637687474703a2f2f77777762",
396 "61636b2e69707363612e636f6d2f6970736361323030322f69707363613230303",
397 "2434c41534541312e63726c303206082b0601050507010104263024302206082b",
398 "060105050730018616687474703a2f2f6f6373702e69707363612e636f6d2f300",
399 "d06092a864886f70d01010505000381810068ee799797dd3bef166a06f2149a6e",
400 "cd9e12f7aa8310bdd17c98fac7aed40e2c9e38059d5260a9990a81b498901daeb",
401 "b4ad7b9dc889e3778415bf782a5f2ba41255a901a1e4538a1525875942644fb20",
402 "07ba44cce54a2d723f9847f626dc054605076321ab469b9c78d5545b3d0c1ec86",
403 "48cb55023826fdbb8221c439607a8bb",
405 crt = Certificate().decod(raw)
406 self.assertSequenceEqual(crt.encode(), raw)
409 pickle_loads(pickle_dumps(crt, pickle_proto))