2 # PyDERASN -- Python ASN.1 DER codec with abstract structures
3 # Copyright (C) 2017-2018 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, either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
19 from datetime import datetime
20 from unittest import TestCase
22 from pyderasn import Any
23 from pyderasn import BitString
24 from pyderasn import Boolean
25 from pyderasn import Choice
26 from pyderasn import GeneralizedTime
27 from pyderasn import hexdec
28 from pyderasn import IA5String
29 from pyderasn import Integer
30 from pyderasn import Null
31 from pyderasn import ObjectIdentifier
32 from pyderasn import OctetString
33 from pyderasn import pprint
34 from pyderasn import PrintableString
35 from pyderasn import Sequence
36 from pyderasn import SequenceOf
37 from pyderasn import SetOf
38 from pyderasn import tag_ctxc
39 from pyderasn import tag_ctxp
40 from pyderasn import TeletexString
41 from pyderasn import UTCTime
45 "1.2.840.113549.1.1.1": "id-rsaEncryption",
46 "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
47 "1.2.840.113549.1.9.1": "id-emailAddress",
48 "2.5.29.14": "id-ce-subjectKeyIdentifier",
49 "2.5.29.15": "id-ce-keyUsage",
50 "2.5.29.17": "id-ce-subjectAltName",
51 "2.5.29.18": "id-ce-issuerAltName",
52 "2.5.29.19": "id-ce-basicConstraints",
53 "2.5.29.31": "id-ce-cRLDistributionPoints",
54 "2.5.29.35": "id-ce-authorityKeyIdentifier",
55 "2.5.29.37": "id-ce-extKeyUsage",
56 "2.5.4.3": "id-at-commonName",
57 "2.5.4.6": "id-at-countryName",
58 "2.5.4.7": "id-at-localityName",
59 "2.5.4.8": "id-at-stateOrProvinceName",
60 "2.5.4.10": "id-at-organizationName",
61 "2.5.4.11": "id-at-organizationalUnitName",
65 class Version(Integer):
73 class CertificateSerialNumber(Integer):
77 class AlgorithmIdentifier(Sequence):
79 ("algorithm", ObjectIdentifier()),
80 ("parameters", Any(optional=True)),
84 class AttributeType(ObjectIdentifier):
88 class AttributeValue(Any):
92 class OrganizationName(Choice):
94 ('printableString', PrintableString()),
95 ('teletexString', TeletexString()),
99 class AttributeTypeAndValue(Sequence):
101 ("type", AttributeType(defines=("value", {
102 ObjectIdentifier("2.5.4.6"): PrintableString(),
103 ObjectIdentifier("2.5.4.8"): PrintableString(),
104 ObjectIdentifier("2.5.4.7"): PrintableString(),
105 ObjectIdentifier("2.5.4.10"): OrganizationName(),
106 ObjectIdentifier("2.5.4.3"): PrintableString(),
108 ("value", AttributeValue()),
112 class RelativeDistinguishedName(SetOf):
113 schema = AttributeTypeAndValue()
114 bounds = (1, float("+inf"))
117 class RDNSequence(SequenceOf):
118 schema = RelativeDistinguishedName()
123 ("rdnSequence", RDNSequence()),
129 ("utcTime", UTCTime()),
130 ("generalTime", GeneralizedTime()),
134 class Validity(Sequence):
136 ("notBefore", Time()),
137 ("notAfter", Time()),
141 class SubjectPublicKeyInfo(Sequence):
143 ("algorithm", AlgorithmIdentifier()),
144 ("subjectPublicKey", BitString()),
148 class UniqueIdentifier(BitString):
152 class Extension(Sequence):
154 ("extnID", ObjectIdentifier()),
155 ("critical", Boolean(default=False)),
156 ("extnValue", OctetString()),
160 class Extensions(SequenceOf):
162 bounds = (1, float("+inf"))
165 class TBSCertificate(Sequence):
167 ("version", Version(expl=tag_ctxc(0), default="v1")),
168 ("serialNumber", CertificateSerialNumber()),
169 ("signature", AlgorithmIdentifier()),
171 ("validity", Validity()),
173 ("subjectPublicKeyInfo", SubjectPublicKeyInfo()),
174 ("issuerUniqueID", UniqueIdentifier(impl=tag_ctxp(1), optional=True)),
175 ("subjectUniqueID", UniqueIdentifier(impl=tag_ctxp(2), optional=True)),
176 ("extensions", Extensions(expl=tag_ctxc(3), optional=True)),
180 class Certificate(Sequence):
182 ("tbsCertificate", TBSCertificate()),
183 ("signatureAlgorithm", AlgorithmIdentifier()),
184 ("signatureValue", BitString()),
188 class TestGoSelfSignedVector(TestCase):
190 raw = hexdec("".join((
191 "30820218308201c20209008cc3379210ec2c98300d06092a864886f70d0101050",
192 "500308192310b3009060355040613025858311330110603550408130a536f6d65",
193 "2d5374617465310d300b06035504071304436974793121301f060355040a13184",
194 "96e7465726e6574205769646769747320507479204c7464311a30180603550403",
195 "131166616c73652e6578616d706c652e636f6d3120301e06092a864886f70d010",
196 "901161166616c7365406578616d706c652e636f6d301e170d3039313030383030",
197 "323535335a170d3130313030383030323535335a308192310b300906035504061",
198 "3025858311330110603550408130a536f6d652d5374617465310d300b06035504",
199 "071304436974793121301f060355040a1318496e7465726e65742057696467697",
200 "47320507479204c7464311a30180603550403131166616c73652e6578616d706c",
201 "652e636f6d3120301e06092a864886f70d010901161166616c7365406578616d7",
202 "06c652e636f6d305c300d06092a864886f70d0101010500034b003048024100cd",
203 "b7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695a331b1deadea",
204 "dd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8fdeec357d0203",
205 "010001300d06092a864886f70d0101050500034100a67b06ec5ece92772ca413c",
206 "ba3ca12568fdc6c7b4511cd40a7f659980402df2b998bb9a4a8cbeb34c0f0a78c",
207 "f8d91ede14a5ed76bf116fe360aafa8821490435",
209 crt, tail = Certificate().decode(raw)
210 self.assertSequenceEqual(tail, b"")
211 tbs = crt["tbsCertificate"]
212 self.assertEqual(tbs["version"], 0)
213 self.assertFalse(tbs["version"].decoded)
214 self.assertNotIn("version", tbs)
215 self.assertEqual(tbs["serialNumber"], 10143011886257155224)
217 def assert_raw_equals(obj, expect):
218 self.assertTrue(obj.decoded)
219 self.assertSequenceEqual(
220 raw[obj.offset:obj.offset + obj.tlvlen],
223 assert_raw_equals(tbs["serialNumber"], Integer(10143011886257155224))
224 algo_id = AlgorithmIdentifier()
225 algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.5")
226 algo_id["parameters"] = Any(Null())
227 self.assertEqual(tbs["signature"], algo_id)
228 assert_raw_equals(tbs["signature"], algo_id)
230 rdnSeq = RDNSequence()
231 for oid, klass, text in (
232 ("2.5.4.6", PrintableString, "XX"),
233 ("2.5.4.8", PrintableString, "Some-State"),
234 ("2.5.4.7", PrintableString, "City"),
235 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
236 ("2.5.4.3", PrintableString, "false.example.com"),
237 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
239 attr = AttributeTypeAndValue()
240 attr["type"] = AttributeType(oid)
241 attr["value"] = AttributeValue(klass(text))
242 rdn = RelativeDistinguishedName()
245 issuer["rdnSequence"] = rdnSeq
246 self.assertEqual(tbs["issuer"], issuer)
247 assert_raw_equals(tbs["issuer"], issuer)
248 validity = Validity()
249 validity["notBefore"] = Time(
250 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53)))
252 validity["notAfter"] = Time(
253 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53)))
255 self.assertEqual(tbs["validity"], validity)
256 assert_raw_equals(tbs["validity"], validity)
257 self.assertEqual(tbs["subject"], issuer)
258 assert_raw_equals(tbs["subject"], issuer)
259 spki = SubjectPublicKeyInfo()
260 algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
261 spki["algorithm"] = algo_id
262 spki["subjectPublicKey"] = BitString(hexdec("".join((
263 "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
264 "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
265 "deec357d0203010001",
267 self.assertEqual(tbs["subjectPublicKeyInfo"], spki)
268 assert_raw_equals(tbs["subjectPublicKeyInfo"], spki)
269 self.assertNotIn("issuerUniqueID", tbs)
270 self.assertNotIn("subjectUniqueID", tbs)
271 self.assertNotIn("extensions", tbs)
272 algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.5")
273 self.assertEqual(crt["signatureAlgorithm"], algo_id)
274 self.assertEqual(crt["signatureValue"], BitString(hexdec("".join((
275 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
276 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
278 self.assertSequenceEqual(crt.encode(), raw)
282 tbs = TBSCertificate()
283 tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
285 sign_algo_id = AlgorithmIdentifier()
286 sign_algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.5")
287 sign_algo_id["parameters"] = Any(Null())
288 tbs["signature"] = sign_algo_id
290 rdnSeq = RDNSequence()
291 for oid, klass, text in (
292 ("2.5.4.6", PrintableString, "XX"),
293 ("2.5.4.8", PrintableString, "Some-State"),
294 ("2.5.4.7", PrintableString, "City"),
295 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
296 ("2.5.4.3", PrintableString, "false.example.com"),
297 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
299 attr = AttributeTypeAndValue()
300 attr["type"] = AttributeType(oid)
301 attr["value"] = AttributeValue(klass(text))
302 rdn = RelativeDistinguishedName()
306 issuer["rdnSequence"] = rdnSeq
307 tbs["issuer"] = issuer
308 tbs["subject"] = issuer
310 validity = Validity()
311 validity["notBefore"] = Time(("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53))))
312 validity["notAfter"] = Time(("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53))))
313 tbs["validity"] = validity
315 spki = SubjectPublicKeyInfo()
316 spki_algo_id = sign_algo_id.copy()
317 spki_algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
318 spki["algorithm"] = spki_algo_id
319 spki["subjectPublicKey"] = BitString(hexdec("".join((
320 "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
321 "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
322 "deec357d0203010001",
324 tbs["subjectPublicKeyInfo"] = spki
327 crt["tbsCertificate"] = tbs
328 crt["signatureAlgorithm"] = sign_algo_id
329 crt["signatureValue"] = BitString(hexdec("".join((
330 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
331 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
333 self.assertSequenceEqual(crt.encode(), raw)
336 class TestGoPayPalVector(TestCase):
338 raw = hexdec("".join((
339 "30820644308205ada003020102020300f09b300d06092a864886f70d010105050",
340 "030820112310b3009060355040613024553311230100603550408130942617263",
341 "656c6f6e61311230100603550407130942617263656c6f6e61312930270603550",
342 "40a13204950532043657274696669636174696f6e20417574686f726974792073",
343 "2e6c2e312e302c060355040a142567656e6572616c4069707363612e636f6d204",
344 "32e492e462e2020422d423632323130363935312e302c060355040b1325697073",
345 "434120434c41534541312043657274696669636174696f6e20417574686f72697",
346 "479312e302c06035504031325697073434120434c415345413120436572746966",
347 "69636174696f6e20417574686f726974793120301e06092a864886f70d0109011",
348 "61167656e6572616c4069707363612e636f6d301e170d30393032323432333034",
349 "31375a170d3131303232343233303431375a308194310b3009060355040613025",
350 "553311330110603550408130a43616c69666f726e696131163014060355040713",
351 "0d53616e204672616e636973636f3111300f060355040a1308536563757269747",
352 "931143012060355040b130b53656375726520556e6974312f302d060355040313",
353 "267777772e70617970616c2e636f6d0073736c2e736563757265636f6e6e65637",
354 "4696f6e2e636330819f300d06092a864886f70d010101050003818d0030818902",
355 "818100d269fa6f3a00b4211bc8b102d73f19b2c46db454f88b8accdb72c29e3c6",
356 "0b9c6913d82b77d99ffd12984c173539c82ddfc248c77d541f3e81e42a1ad2d9e",
357 "ff5b1026ce9d571773162338c8d6f1baa3965b16674a4f73973a4d14a4f4e23f8",
358 "b058342d1d0dc2f7ae5b610b211c0dc212a90ffae97715a4981ac40f33bb859b2",
359 "4f0203010001a38203213082031d30090603551d1304023000301106096086480",
360 "186f8420101040403020640300b0603551d0f0404030203f830130603551d2504",
361 "0c300a06082b06010505070301301d0603551d0e04160414618f61344355147f2",
362 "709ce4c8bea9b7b1925bc6e301f0603551d230418301680140e0760d439c91b5b",
363 "5d907b23c8d2349d4a9a463930090603551d1104023000301c0603551d1204153",
364 "013811167656e6572616c4069707363612e636f6d307206096086480186f84201",
365 "0d046516634f7267616e697a6174696f6e20496e666f726d6174696f6e204e4f5",
366 "42056414c4944415445442e20434c415345413120536572766572204365727469",
367 "666963617465206973737565642062792068747470733a2f2f7777772e6970736",
368 "3612e636f6d2f302f06096086480186f84201020422162068747470733a2f2f77",
369 "77772e69707363612e636f6d2f6970736361323030322f304306096086480186f",
370 "84201040436163468747470733a2f2f7777772e69707363612e636f6d2f697073",
371 "6361323030322f697073636132303032434c41534541312e63726c30460609608",
372 "6480186f84201030439163768747470733a2f2f7777772e69707363612e636f6d",
373 "2f6970736361323030322f7265766f636174696f6e434c41534541312e68746d6",
374 "c3f304306096086480186f84201070436163468747470733a2f2f7777772e6970",
375 "7363612e636f6d2f6970736361323030322f72656e6577616c434c41534541312",
376 "e68746d6c3f304106096086480186f84201080434163268747470733a2f2f7777",
377 "772e69707363612e636f6d2f6970736361323030322f706f6c696379434c41534",
378 "541312e68746d6c3081830603551d1f047c307a3039a037a0358633687474703a",
379 "2f2f7777772e69707363612e636f6d2f6970736361323030322f6970736361323",
380 "03032434c41534541312e63726c303da03ba0398637687474703a2f2f77777762",
381 "61636b2e69707363612e636f6d2f6970736361323030322f69707363613230303",
382 "2434c41534541312e63726c303206082b0601050507010104263024302206082b",
383 "060105050730018616687474703a2f2f6f6373702e69707363612e636f6d2f300",
384 "d06092a864886f70d01010505000381810068ee799797dd3bef166a06f2149a6e",
385 "cd9e12f7aa8310bdd17c98fac7aed40e2c9e38059d5260a9990a81b498901daeb",
386 "b4ad7b9dc889e3778415bf782a5f2ba41255a901a1e4538a1525875942644fb20",
387 "07ba44cce54a2d723f9847f626dc054605076321ab469b9c78d5545b3d0c1ec86",
388 "48cb55023826fdbb8221c439607a8bb",
390 crt, tail = Certificate().decode(raw)
391 self.assertSequenceEqual(tail, b"")
392 self.assertSequenceEqual(crt.encode(), raw)