9 Let's try to parse X.509 certificate. We have to define our structures
10 based on ASN.1 schema descriptions.
15 * - ASN.1 specification
19 Certificate ::= SEQUENCE {
20 tbsCertificate TBSCertificate,
21 signatureAlgorithm AlgorithmIdentifier,
22 signatureValue BIT STRING }
25 class Certificate(Sequence):
27 ("tbsCertificate", TBSCertificate()),
28 ("signatureAlgorithm", AlgorithmIdentifier()),
29 ("signatureValue", BitString()),
33 AlgorithmIdentifier ::= SEQUENCE {
34 algorithm OBJECT IDENTIFIER,
35 parameters ANY DEFINED BY algorithm OPTIONAL }
38 class AlgorithmIdentifier(Sequence):
40 ("algorithm", ObjectIdentifier()),
41 ("parameters", Any(optional=True)),
45 TBSCertificate ::= SEQUENCE {
46 version [0] EXPLICIT Version DEFAULT v1,
47 serialNumber CertificateSerialNumber,
48 signature AlgorithmIdentifier,
52 subjectPublicKeyInfo SubjectPublicKeyInfo,
53 issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
54 subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
55 extensions [3] EXPLICIT Extensions OPTIONAL }
58 class TBSCertificate(Sequence):
60 ("version", Version(expl=tag_ctxc(0), default="v1")),
61 ("serialNumber", CertificateSerialNumber()),
62 ("signature", AlgorithmIdentifier()),
64 ("validity", Validity()),
66 ("subjectPublicKeyInfo", SubjectPublicKeyInfo()),
67 ("issuerUniqueID", UniqueIdentifier(impl=tag_ctxp(1), optional=True)),
68 ("subjectUniqueID", UniqueIdentifier(impl=tag_ctxp(2), optional=True)),
69 ("extensions", Extensions(expl=tag_ctxc(3), optional=True)),
73 Version ::= INTEGER { v1(0), v2(1), v3(2) }
76 class Version(Integer):
77 schema = (("v1", 0), ("v2", 1), ("v3", 2))
80 CertificateSerialNumber ::= INTEGER
83 class CertificateSerialNumber(Integer):
87 Validity ::= SEQUENCE {
92 generalTime GeneralizedTime }
95 class Validity(Sequence):
97 ("notBefore", Time()),
102 ("utcTime", UTCTime()),
103 ("generalTime", GeneralizedTime()),
107 SubjectPublicKeyInfo ::= SEQUENCE {
108 algorithm AlgorithmIdentifier,
109 subjectPublicKey BIT STRING }
112 class SubjectPublicKeyInfo(Sequence):
114 ("algorithm", AlgorithmIdentifier()),
115 ("subjectPublicKey", BitString()),
119 UniqueIdentifier ::= BIT STRING
122 class UniqueIdentifier(BitString):
126 Name ::= CHOICE { rdnSequence RDNSequence }
128 RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
130 RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
132 AttributeTypeAndValue ::= SEQUENCE { type AttributeType, value AttributeValue }
134 AttributeType ::= OBJECT IDENTIFIER
136 AttributeValue ::= ANY -- DEFINED BY AttributeType
140 schema = (("rdnSequence", RDNSequence()),)
141 class RDNSequence(SequenceOf):
142 schema = RelativeDistinguishedName()
143 class RelativeDistinguishedName(SetOf):
144 schema = AttributeTypeAndValue()
145 bounds = (1, float("+inf"))
146 class AttributeTypeAndValue(Sequence):
148 ("type", AttributeType()),
149 ("value", AttributeValue()),
151 class AttributeType(ObjectIdentifier):
153 class AttributeValue(Any):
157 Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
159 Extension ::= SEQUENCE {
160 extnID OBJECT IDENTIFIER,
161 critical BOOLEAN DEFAULT FALSE,
162 extnValue OCTET STRING
166 class Extensions(SequenceOf):
168 bounds = (1, float("+inf"))
169 class Extension(Sequence):
171 ("extnID", ObjectIdentifier()),
172 ("critical", Boolean(default=False)),
173 ("extnValue", OctetString()),
176 We are ready to decode PayPal's certificate from Go `encoding/asn1
177 <https://golang.org/pkg/encoding/asn1/>`__ test suite (assuming that
178 it's DER encoded representation is already in ``raw`` variable)::
180 >>> crt, tail = Certificate().decode(raw)
182 Certificate SEQUENCE[TBSCertificate SEQUENCE[[0] EXPLICIT Version
183 INTEGER v3 OPTIONAL, CertificateSerialNumber INTEGER 61595,
184 AlgorithmIdentifier SEQUENCE[OBJECT IDENTIFIER 1.2.840.113549.1.1.5...
189 There is huge output. Let's pretty print it::
191 >>> print(pprint(crt))
192 0 [1,3,1604] Certificate SEQUENCE
193 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
194 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
195 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
196 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
197 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
198 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
200 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
201 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
202 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
203 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
204 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
205 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
206 . . . . . . . 13:02:45:53
208 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
209 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
210 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
212 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
213 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
214 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
219 Let's parse that output, human::
221 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
222 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
223 0 1 2 3 4 5 6 7 8 9 10 11
227 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
233 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
238 Offset of the object, where its DER encoding begins.
239 Pay attention that it does **not** include explicit tag.
241 If explicit tag exists, then this is its length (tag + encoded length).
243 Length of object's tag. For example CHOICE does not have its own tag,
246 Length of encoded length.
248 Length of encoded value.
250 Visual indentation to show the depth of object in the hierarchy.
252 Object's name inside SEQUENCE/CHOICE.
254 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
255 here. "IMPLICIT" is omitted.
257 Object's class name, if set. Omitted if it is just an ordinary simple
258 value (like with ``algorithm`` in example above).
262 Object's value, if set. Can consist of multiple words (like OCTET/BIT
263 STRINGs above). We see ``v3`` value in Version, because it is named.
264 ``rdnSequence`` is the choice of CHOICE type.
266 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
267 default one, specified in the schema.
269 As command line utility
270 -----------------------
272 You can decode DER files using command line abilities and get the same
273 picture as above by executing::
275 % python -m pyderasn --schema tests.test_crts:Certificate path/to/file
277 If there is no schema for you file, then you can try parsing it without,
278 but of course IMPLICIT tags will often make it impossible. But result is
279 good enough for the certificate above::
281 % python -m pyderasn path/to/file
282 0 [1,3,1604] . >: SEQUENCE OF
283 4 [1,3,1453] . . >: SEQUENCE OF
284 8 [0,0, 5] . . . . >: [0] ANY
285 . . . . . A0:03:02:01:02
286 13 [1,1, 3] . . . . >: INTEGER 61595
287 18 [1,1, 13] . . . . >: SEQUENCE OF
288 20 [1,1, 9] . . . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
289 31 [1,1, 0] . . . . . . >: NULL
290 33 [1,3, 274] . . . . >: SEQUENCE OF
291 37 [1,1, 11] . . . . . . >: SET OF
292 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
293 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER 2.5.4.6
294 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
296 1409 [1,1, 50] . . . . . . >: SEQUENCE OF
297 1411 [1,1, 8] . . . . . . . . >: OBJECT IDENTIFIER 1.3.6.1.5.5.7.1.1
298 1421 [1,1, 38] . . . . . . . . >: OCTET STRING 38 bytes
299 . . . . . . . . . 30:24:30:22:06:08:2B:06:01:05:05:07:30:01:86:16
300 . . . . . . . . . 68:74:74:70:3A:2F:2F:6F:63:73:70:2E:69:70:73:63
301 . . . . . . . . . 61:2E:63:6F:6D:2F
302 1461 [1,1, 13] . . >: SEQUENCE OF
303 1463 [1,1, 9] . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
304 1474 [1,1, 0] . . . . >: NULL
305 1476 [1,2, 129] . . >: BIT STRING 1024 bits
306 . . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
307 . . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
310 If you have got dictionaries with ObjectIdentifiers, like example one
311 from ``tests/test_crts.py``::
314 "1.2.840.113549.1.1.1": "id-rsaEncryption",
315 "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
317 "2.5.4.10": "id-at-organizationName",
318 "2.5.4.11": "id-at-organizationalUnitName",
321 then you can pass it to pretty printer to see human readable OIDs::
323 % python -m pyderasn --oids tests.test_crts:some_oids path/to/file
325 37 [1,1, 11] . . . . . . >: SET OF
326 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
327 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
328 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
329 50 [1,1, 18] . . . . . . >: SET OF
330 52 [1,1, 16] . . . . . . . . >: SEQUENCE OF
331 54 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
332 59 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
333 70 [1,1, 18] . . . . . . >: SET OF
334 72 [1,1, 16] . . . . . . . . >: SEQUENCE OF
335 74 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
336 79 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
342 If you have bad DER, then errors will show you where error occurred::
344 % python -m pyderasn --schema tests.test_crts:Certificate path/to/bad/file
345 Traceback (most recent call last):
347 pyderasn.DecodeError: UTCTime (tbsCertificate.validity.notAfter.utcTime) (at 328) invalid UTCTime format
351 % python -m pyderasn path/to/bad/file
353 pyderasn.DecodeError: UTCTime (0.SequenceOf.4.SequenceOf.1.UTCTime) (at 328) invalid UTCTime format
355 You can see, so called, decode path inside the structures:
356 ``tbsCertificate`` -> ``validity`` -> ``notAfter`` -> ``utcTime`` and
357 that object at byte 328 is invalid.
359 X.509 certificate creation
360 --------------------------
362 Let's create some simple self-signed X.509 certificate from the ground::
364 tbs = TBSCertificate()
365 tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
367 sign_algo_id = AlgorithmIdentifier()
368 sign_algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.5")
369 sign_algo_id["parameters"] = Any(Null())
370 tbs["signature"] = sign_algo_id
372 rdnSeq = RDNSequence()
373 for oid, klass, text in (
374 ("2.5.4.6", PrintableString, "XX"),
375 ("2.5.4.8", PrintableString, "Some-State"),
376 ("2.5.4.7", PrintableString, "City"),
377 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
378 ("2.5.4.3", PrintableString, "false.example.com"),
379 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
381 attr = AttributeTypeAndValue()
382 attr["type"] = AttributeType(oid)
383 attr["value"] = AttributeValue(klass(text))
384 rdn = RelativeDistinguishedName()
388 issuer["rdnSequence"] = rdnSeq
389 tbs["issuer"] = issuer
390 tbs["subject"] = issuer
392 validity = Validity()
393 validity["notBefore"] = Time(("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53))))
394 validity["notAfter"] = Time(("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53))))
395 tbs["validity"] = validity
397 spki = SubjectPublicKeyInfo()
398 spki_algo_id = sign_algo_id.copy()
399 spki_algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
400 spki["algorithm"] = spki_algo_id
401 spki["subjectPublicKey"] = BitString(hexdec("".join((
402 "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
403 "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
404 "deec357d0203010001",
406 tbs["subjectPublicKeyInfo"] = spki
409 crt["tbsCertificate"] = tbs
410 crt["signatureAlgorithm"] = sign_algo_id
411 crt["signatureValue"] = BitString(hexdec("".join((
412 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
413 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
417 And we will get the same certificate used in Go's library tests.