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 "id-rsaEncryption": ObjectIdentifier("1.2.840.113549.1.1.1"),
50 "id-sha1WithRSAEncryption": ObjectIdentifier("1.2.840.113549.1.1.5"),
51 "id-emailAddress": ObjectIdentifier("1.2.840.113549.1.9.1"),
52 "id-ce-subjectKeyIdentifier": ObjectIdentifier("2.5.29.14"),
53 "id-ce-keyUsage": ObjectIdentifier("2.5.29.15"),
54 "id-ce-subjectAltName": ObjectIdentifier("2.5.29.17"),
55 "id-ce-issuerAltName": ObjectIdentifier("2.5.29.18"),
56 "id-ce-basicConstraints": ObjectIdentifier("2.5.29.19"),
57 "id-ce-cRLDistributionPoints": ObjectIdentifier("2.5.29.31"),
58 "id-ce-authorityKeyIdentifier": ObjectIdentifier("2.5.29.35"),
59 "id-ce-extKeyUsage": ObjectIdentifier("2.5.29.37"),
60 "id-at-commonName": ObjectIdentifier("2.5.4.3"),
61 "id-at-countryName": ObjectIdentifier("2.5.4.6"),
62 "id-at-localityName": ObjectIdentifier("2.5.4.7"),
63 "id-at-stateOrProvinceName": ObjectIdentifier("2.5.4.8"),
64 "id-at-organizationName": ObjectIdentifier("2.5.4.10"),
65 "id-at-organizationalUnitName": ObjectIdentifier("2.5.4.11"),
67 stroid2name = {str(oid): name for name, oid in name2oid.items()}
70 class Version(Integer):
78 class CertificateSerialNumber(Integer):
82 class AlgorithmIdentifier(Sequence):
84 ("algorithm", ObjectIdentifier()),
85 ("parameters", Any(optional=True)),
89 class AttributeType(ObjectIdentifier):
93 class AttributeValue(Any):
97 class OrganizationName(Choice):
99 ("printableString", PrintableString()),
100 ("teletexString", TeletexString()),
104 class AttributeTypeAndValue(Sequence):
106 ("type", AttributeType(defines=(((".", "value"), {
107 name2oid["id-at-countryName"]: PrintableString(),
108 name2oid["id-at-localityName"]: PrintableString(),
109 name2oid["id-at-stateOrProvinceName"]: PrintableString(),
110 name2oid["id-at-organizationName"]: OrganizationName(),
111 name2oid["id-at-commonName"]: PrintableString(),
113 ("value", AttributeValue()),
117 class RelativeDistinguishedName(SetOf):
118 schema = AttributeTypeAndValue()
119 bounds = (1, float("+inf"))
122 class RDNSequence(SequenceOf):
123 schema = RelativeDistinguishedName()
128 ("rdnSequence", RDNSequence()),
134 ("utcTime", UTCTime()),
135 ("generalTime", GeneralizedTime()),
139 class Validity(Sequence):
141 ("notBefore", Time()),
142 ("notAfter", Time()),
146 class SubjectPublicKeyInfo(Sequence):
148 ("algorithm", AlgorithmIdentifier()),
149 ("subjectPublicKey", BitString()),
153 class UniqueIdentifier(BitString):
157 class Extension(Sequence):
159 ("extnID", ObjectIdentifier()),
160 ("critical", Boolean(default=False)),
161 ("extnValue", OctetString()),
165 class Extensions(SequenceOf):
167 bounds = (1, float("+inf"))
170 class TBSCertificate(Sequence):
172 ("version", Version(expl=tag_ctxc(0), default="v1")),
173 ("serialNumber", CertificateSerialNumber()),
174 ("signature", AlgorithmIdentifier()),
176 ("validity", Validity()),
178 ("subjectPublicKeyInfo", SubjectPublicKeyInfo()),
179 ("issuerUniqueID", UniqueIdentifier(impl=tag_ctxp(1), optional=True)),
180 ("subjectUniqueID", UniqueIdentifier(impl=tag_ctxp(2), optional=True)),
181 ("extensions", Extensions(expl=tag_ctxc(3), optional=True)),
185 class Certificate(Sequence):
187 ("tbsCertificate", TBSCertificate()),
188 ("signatureAlgorithm", AlgorithmIdentifier()),
189 ("signatureValue", BitString()),
193 class TestGoSelfSignedVector(TestCase):
195 raw = hexdec("".join((
196 "30820218308201c20209008cc3379210ec2c98300d06092a864886f70d0101050",
197 "500308192310b3009060355040613025858311330110603550408130a536f6d65",
198 "2d5374617465310d300b06035504071304436974793121301f060355040a13184",
199 "96e7465726e6574205769646769747320507479204c7464311a30180603550403",
200 "131166616c73652e6578616d706c652e636f6d3120301e06092a864886f70d010",
201 "901161166616c7365406578616d706c652e636f6d301e170d3039313030383030",
202 "323535335a170d3130313030383030323535335a308192310b300906035504061",
203 "3025858311330110603550408130a536f6d652d5374617465310d300b06035504",
204 "071304436974793121301f060355040a1318496e7465726e65742057696467697",
205 "47320507479204c7464311a30180603550403131166616c73652e6578616d706c",
206 "652e636f6d3120301e06092a864886f70d010901161166616c7365406578616d7",
207 "06c652e636f6d305c300d06092a864886f70d0101010500034b003048024100cd",
208 "b7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695a331b1deadea",
209 "dd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8fdeec357d0203",
210 "010001300d06092a864886f70d0101050500034100a67b06ec5ece92772ca413c",
211 "ba3ca12568fdc6c7b4511cd40a7f659980402df2b998bb9a4a8cbeb34c0f0a78c",
212 "f8d91ede14a5ed76bf116fe360aafa8821490435",
214 crt = Certificate().decod(raw)
215 tbs = crt["tbsCertificate"]
216 self.assertEqual(tbs["version"], 0)
217 self.assertFalse(tbs["version"].decoded)
218 self.assertNotIn("version", tbs)
219 self.assertEqual(tbs["serialNumber"], 10143011886257155224)
221 def assert_raw_equals(obj, expect):
222 self.assertTrue(obj.decoded)
223 self.assertSequenceEqual(
224 raw[obj.offset:obj.offset + obj.tlvlen],
227 assert_raw_equals(tbs["serialNumber"], Integer(10143011886257155224))
228 algo_id = AlgorithmIdentifier((
229 ("algorithm", name2oid["id-sha1WithRSAEncryption"]),
230 ("parameters", Any(Null())),
232 self.assertEqual(tbs["signature"], algo_id)
233 assert_raw_equals(tbs["signature"], algo_id)
234 rdnSeq = RDNSequence()
235 for oid, klass, text in (
236 ("2.5.4.6", PrintableString, "XX"),
237 ("2.5.4.8", PrintableString, "Some-State"),
238 ("2.5.4.7", PrintableString, "City"),
239 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
240 ("2.5.4.3", PrintableString, "false.example.com"),
241 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
244 RelativeDistinguishedName((
245 AttributeTypeAndValue((
246 ("type", AttributeType(oid)),
247 ("value", AttributeValue(klass(text))),
251 issuer = Name(("rdnSequence", rdnSeq))
252 self.assertEqual(tbs["issuer"], issuer)
253 assert_raw_equals(tbs["issuer"], issuer)
254 validity = Validity((
256 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53)))
259 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53)))
262 self.assertEqual(tbs["validity"], validity)
263 assert_raw_equals(tbs["validity"], validity)
264 self.assertEqual(tbs["subject"], issuer)
265 assert_raw_equals(tbs["subject"], issuer)
266 spki = SubjectPublicKeyInfo()
267 algo_id["algorithm"] = name2oid["id-rsaEncryption"]
268 spki["algorithm"] = algo_id
269 spki["subjectPublicKey"] = BitString(hexdec("".join((
270 "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
271 "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
272 "deec357d0203010001",
274 self.assertEqual(tbs["subjectPublicKeyInfo"], spki)
275 assert_raw_equals(tbs["subjectPublicKeyInfo"], spki)
276 self.assertNotIn("issuerUniqueID", tbs)
277 self.assertNotIn("subjectUniqueID", tbs)
278 self.assertNotIn("extensions", tbs)
279 algo_id["algorithm"] = name2oid["id-sha1WithRSAEncryption"]
280 self.assertEqual(crt["signatureAlgorithm"], algo_id)
281 self.assertEqual(crt["signatureValue"], BitString(hexdec("".join((
282 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
283 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
285 self.assertSequenceEqual(crt.encode(), raw)
288 pickle_loads(pickle_dumps(crt, pickle_proto))
290 tbs = TBSCertificate()
291 tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
293 sign_algo_id = AlgorithmIdentifier((
294 ("algorithm", name2oid["id-sha1WithRSAEncryption"]),
295 ("parameters", Any(Null())),
297 tbs["signature"] = sign_algo_id
299 rdnSeq = RDNSequence()
300 for oid, klass, text in (
301 ("2.5.4.6", PrintableString, "XX"),
302 ("2.5.4.8", PrintableString, "Some-State"),
303 ("2.5.4.7", PrintableString, "City"),
304 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
305 ("2.5.4.3", PrintableString, "false.example.com"),
306 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
309 RelativeDistinguishedName((
310 AttributeTypeAndValue((
311 ("type", AttributeType(oid)),
312 ("value", AttributeValue(klass(text))),
317 issuer["rdnSequence"] = rdnSeq
318 tbs["issuer"] = issuer
319 tbs["subject"] = issuer
321 validity = Validity((
323 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53)),),
326 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53)),),
329 tbs["validity"] = validity
331 spki = SubjectPublicKeyInfo()
332 spki_algo_id = copy(sign_algo_id)
333 spki_algo_id["algorithm"] = name2oid["id-rsaEncryption"]
334 spki["algorithm"] = spki_algo_id
335 spki["subjectPublicKey"] = BitString(hexdec("".join((
336 "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
337 "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
338 "deec357d0203010001",
340 tbs["subjectPublicKeyInfo"] = spki
343 crt["tbsCertificate"] = tbs
344 crt["signatureAlgorithm"] = sign_algo_id
345 crt["signatureValue"] = BitString(hexdec("".join((
346 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
347 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
349 self.assertSequenceEqual(crt.encode(), raw)
352 class TestGoPayPalVector(TestCase):
354 raw = hexdec("".join((
355 "30820644308205ada003020102020300f09b300d06092a864886f70d010105050",
356 "030820112310b3009060355040613024553311230100603550408130942617263",
357 "656c6f6e61311230100603550407130942617263656c6f6e61312930270603550",
358 "40a13204950532043657274696669636174696f6e20417574686f726974792073",
359 "2e6c2e312e302c060355040a142567656e6572616c4069707363612e636f6d204",
360 "32e492e462e2020422d423632323130363935312e302c060355040b1325697073",
361 "434120434c41534541312043657274696669636174696f6e20417574686f72697",
362 "479312e302c06035504031325697073434120434c415345413120436572746966",
363 "69636174696f6e20417574686f726974793120301e06092a864886f70d0109011",
364 "61167656e6572616c4069707363612e636f6d301e170d30393032323432333034",
365 "31375a170d3131303232343233303431375a308194310b3009060355040613025",
366 "553311330110603550408130a43616c69666f726e696131163014060355040713",
367 "0d53616e204672616e636973636f3111300f060355040a1308536563757269747",
368 "931143012060355040b130b53656375726520556e6974312f302d060355040313",
369 "267777772e70617970616c2e636f6d0073736c2e736563757265636f6e6e65637",
370 "4696f6e2e636330819f300d06092a864886f70d010101050003818d0030818902",
371 "818100d269fa6f3a00b4211bc8b102d73f19b2c46db454f88b8accdb72c29e3c6",
372 "0b9c6913d82b77d99ffd12984c173539c82ddfc248c77d541f3e81e42a1ad2d9e",
373 "ff5b1026ce9d571773162338c8d6f1baa3965b16674a4f73973a4d14a4f4e23f8",
374 "b058342d1d0dc2f7ae5b610b211c0dc212a90ffae97715a4981ac40f33bb859b2",
375 "4f0203010001a38203213082031d30090603551d1304023000301106096086480",
376 "186f8420101040403020640300b0603551d0f0404030203f830130603551d2504",
377 "0c300a06082b06010505070301301d0603551d0e04160414618f61344355147f2",
378 "709ce4c8bea9b7b1925bc6e301f0603551d230418301680140e0760d439c91b5b",
379 "5d907b23c8d2349d4a9a463930090603551d1104023000301c0603551d1204153",
380 "013811167656e6572616c4069707363612e636f6d307206096086480186f84201",
381 "0d046516634f7267616e697a6174696f6e20496e666f726d6174696f6e204e4f5",
382 "42056414c4944415445442e20434c415345413120536572766572204365727469",
383 "666963617465206973737565642062792068747470733a2f2f7777772e6970736",
384 "3612e636f6d2f302f06096086480186f84201020422162068747470733a2f2f77",
385 "77772e69707363612e636f6d2f6970736361323030322f304306096086480186f",
386 "84201040436163468747470733a2f2f7777772e69707363612e636f6d2f697073",
387 "6361323030322f697073636132303032434c41534541312e63726c30460609608",
388 "6480186f84201030439163768747470733a2f2f7777772e69707363612e636f6d",
389 "2f6970736361323030322f7265766f636174696f6e434c41534541312e68746d6",
390 "c3f304306096086480186f84201070436163468747470733a2f2f7777772e6970",
391 "7363612e636f6d2f6970736361323030322f72656e6577616c434c41534541312",
392 "e68746d6c3f304106096086480186f84201080434163268747470733a2f2f7777",
393 "772e69707363612e636f6d2f6970736361323030322f706f6c696379434c41534",
394 "541312e68746d6c3081830603551d1f047c307a3039a037a0358633687474703a",
395 "2f2f7777772e69707363612e636f6d2f6970736361323030322f6970736361323",
396 "03032434c41534541312e63726c303da03ba0398637687474703a2f2f77777762",
397 "61636b2e69707363612e636f6d2f6970736361323030322f69707363613230303",
398 "2434c41534541312e63726c303206082b0601050507010104263024302206082b",
399 "060105050730018616687474703a2f2f6f6373702e69707363612e636f6d2f300",
400 "d06092a864886f70d01010505000381810068ee799797dd3bef166a06f2149a6e",
401 "cd9e12f7aa8310bdd17c98fac7aed40e2c9e38059d5260a9990a81b498901daeb",
402 "b4ad7b9dc889e3778415bf782a5f2ba41255a901a1e4538a1525875942644fb20",
403 "07ba44cce54a2d723f9847f626dc054605076321ab469b9c78d5545b3d0c1ec86",
404 "48cb55023826fdbb8221c439607a8bb",
406 crt = Certificate().decod(raw)
407 self.assertSequenceEqual(crt.encode(), raw)
410 pickle_loads(pickle_dumps(crt, pickle_proto))