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: TBSCertificate SEQUENCE[
183 version: [0] EXPLICIT Version INTEGER v3 OPTIONAL;
184 serialNumber: CertificateSerialNumber INTEGER 61595;
185 signature: AlgorithmIdentifier SEQUENCE[OBJECT IDENTIFIER 1.2.840.113549.1.1.5...
190 There is huge output. Let's pretty print it::
192 >>> print(pprint(crt))
193 0 [1,3,1604] Certificate SEQUENCE
194 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
195 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
196 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
197 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
198 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
199 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
201 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
202 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
203 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
204 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
205 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
206 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
207 . . . . . . . 13:02:45:53
209 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
210 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
211 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
213 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
214 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
215 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
220 Let's parse that output, human::
222 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
223 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
224 0 1 2 3 4 5 6 7 8 9 10 11
228 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
234 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
240 52-2∞ [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
245 Offset of the object, where its DER/BER encoding begins.
246 Pay attention that it does **not** include explicit tag.
248 If explicit tag exists, then this is its length (tag + encoded length).
250 Length of object's tag. For example CHOICE does not have its own tag,
253 Length of encoded length.
255 Length of encoded value.
257 Visual indentation to show the depth of object in the hierarchy.
259 Object's name inside SEQUENCE/CHOICE.
261 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
262 here. "IMPLICIT" is omitted.
264 Object's class name, if set. Omitted if it is just an ordinary simple
265 value (like with ``algorithm`` in example above).
269 Object's value, if set. Can consist of multiple words (like OCTET/BIT
270 STRINGs above). We see ``v3`` value in Version, because it is named.
271 ``rdnSequence`` is the choice of CHOICE type.
273 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
274 default one, specified in the schema.
276 Only applicable to BER encoded data. Indefinite length encoding mark.
278 Only applicable to BER encoded data. If object has BER-specific
279 encoding, then ``BER`` will be shown. It does not depend on indefinite
280 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
281 (and its derivatives) could be BERed.
283 As command line utility
284 -----------------------
286 You can decode DER/BER files using command line abilities and get the
287 same picture as above by executing::
289 % python -m pyderasn --schema tests.test_crts:Certificate path/to/file
291 If there is no schema for you file, then you can try parsing it without,
292 but of course IMPLICIT tags will often make it impossible. But result is
293 good enough for the certificate above::
295 % python -m pyderasn path/to/file
296 0 [1,3,1604] . >: SEQUENCE OF
297 4 [1,3,1453] . . >: SEQUENCE OF
298 8 [0,0, 5] . . . . >: [0] ANY
299 . . . . . A0:03:02:01:02
300 13 [1,1, 3] . . . . >: INTEGER 61595
301 18 [1,1, 13] . . . . >: SEQUENCE OF
302 20 [1,1, 9] . . . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
303 31 [1,1, 0] . . . . . . >: NULL
304 33 [1,3, 274] . . . . >: SEQUENCE OF
305 37 [1,1, 11] . . . . . . >: SET OF
306 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
307 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER 2.5.4.6
308 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
310 1409 [1,1, 50] . . . . . . >: SEQUENCE OF
311 1411 [1,1, 8] . . . . . . . . >: OBJECT IDENTIFIER 1.3.6.1.5.5.7.1.1
312 1421 [1,1, 38] . . . . . . . . >: OCTET STRING 38 bytes
313 . . . . . . . . . 30:24:30:22:06:08:2B:06:01:05:05:07:30:01:86:16
314 . . . . . . . . . 68:74:74:70:3A:2F:2F:6F:63:73:70:2E:69:70:73:63
315 . . . . . . . . . 61:2E:63:6F:6D:2F
316 1461 [1,1, 13] . . >: SEQUENCE OF
317 1463 [1,1, 9] . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
318 1474 [1,1, 0] . . . . >: NULL
319 1476 [1,2, 129] . . >: BIT STRING 1024 bits
320 . . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
321 . . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
324 If you have got dictionaries with ObjectIdentifiers, like example one
325 from ``tests/test_crts.py``::
328 "1.2.840.113549.1.1.1": "id-rsaEncryption",
329 "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
331 "2.5.4.10": "id-at-organizationName",
332 "2.5.4.11": "id-at-organizationalUnitName",
335 then you can pass it to pretty printer to see human readable OIDs::
337 % python -m pyderasn --oids tests.test_crts:some_oids path/to/file
339 37 [1,1, 11] . . . . . . >: SET OF
340 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
341 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
342 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
343 50 [1,1, 18] . . . . . . >: SET OF
344 52 [1,1, 16] . . . . . . . . >: SEQUENCE OF
345 54 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
346 59 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
347 70 [1,1, 18] . . . . . . >: SET OF
348 72 [1,1, 16] . . . . . . . . >: SEQUENCE OF
349 74 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
350 79 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
356 If you have bad DER/BER, then errors will show you where error occurred::
358 % python -m pyderasn --schema tests.test_crts:Certificate path/to/bad/file
359 Traceback (most recent call last):
361 pyderasn.DecodeError: UTCTime (tbsCertificate.validity.notAfter.utcTime) (at 328) invalid UTCTime format
365 % python -m pyderasn path/to/bad/file
367 pyderasn.DecodeError: UTCTime (0.SequenceOf.4.SequenceOf.1.UTCTime) (at 328) invalid UTCTime format
369 You can see, so called, decode path inside the structures:
370 ``tbsCertificate`` -> ``validity`` -> ``notAfter`` -> ``utcTime`` and
371 that object at byte 328 is invalid.
373 X.509 certificate creation
374 --------------------------
376 Let's create some simple self-signed X.509 certificate from the ground::
378 tbs = TBSCertificate()
379 tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
381 sign_algo_id = AlgorithmIdentifier((
382 ("algorithm", ObjectIdentifier("1.2.840.113549.1.1.5")),
383 ("parameters", Any(Null())),
385 tbs["signature"] = sign_algo_id
387 rdnSeq = RDNSequence()
388 for oid, klass, text in (
389 ("2.5.4.6", PrintableString, "XX"),
390 ("2.5.4.8", PrintableString, "Some-State"),
391 ("2.5.4.7", PrintableString, "City"),
392 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
393 ("2.5.4.3", PrintableString, "false.example.com"),
394 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
397 RelativeDistinguishedName((
398 AttributeTypeAndValue((
399 ("type", AttributeType(oid)),
400 ("value", AttributeValue(klass(text))),
404 issuer = Name(("rdnSequence", rdnSeq))
405 tbs["issuer"] = issuer
406 tbs["subject"] = issuer
408 validity = Validity((
410 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53))),
413 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53))),
416 tbs["validity"] = validity
418 spki = SubjectPublicKeyInfo()
419 spki_algo_id = sign_algo_id.copy()
420 spki_algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
421 spki["algorithm"] = spki_algo_id
422 spki["subjectPublicKey"] = BitString(hexdec("".join((
423 "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
424 "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
425 "deec357d0203010001",
427 tbs["subjectPublicKeyInfo"] = spki
430 crt["tbsCertificate"] = tbs
431 crt["signatureAlgorithm"] = sign_algo_id
432 crt["signatureValue"] = BitString(hexdec("".join((
433 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
434 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
438 And we will get the same certificate used in Go's library tests.
443 Here is only very simple example how you can define Any/OctetString
444 fields automatic decoding::
446 class AttributeTypeAndValue(Sequence):
448 ((("type",), AttributeType(defines=("value", {
449 id_at_countryName: PrintableString(),
450 id_at_stateOrProvinceName: PrintableString(),
451 id_at_localityName: PrintableString(),
452 id_at_organizationName: PrintableString(),
453 id_at_commonName: PrintableString(),
455 ("value", AttributeValue()),
458 And when you will try to decode X.509 certificate with it, your pretty
461 34 [0,0, 149] . . issuer: Name CHOICE rdnSequence
462 34 [1,2, 146] . . . rdnSequence: RDNSequence SEQUENCE OF
463 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
464 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
465 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
466 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
467 . . . . . . . 13:02:58:58
468 46 [1,1, 2] . . . . . . . DEFINED BY (2.5.4.6): PrintableString PrintableString XX
469 50 [1,1, 19] . . . . 1: RelativeDistinguishedName SET OF
470 52 [1,1, 17] . . . . . 0: AttributeTypeAndValue SEQUENCE
471 54 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
472 59 [0,0, 12] . . . . . . value: [UNIV 19] AttributeValue ANY
473 . . . . . . . 13:0A:53:6F:6D:65:2D:53:74:61:74:65
474 59 [1,1, 10] . . . . . . . DEFINED BY (2.5.4.8): PrintableString PrintableString Some-State
475 71 [1,1, 13] . . . . 2: RelativeDistinguishedName SET OF
476 73 [1,1, 11] . . . . . 0: AttributeTypeAndValue SEQUENCE
477 75 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
478 80 [0,0, 6] . . . . . . value: [UNIV 19] AttributeValue ANY
479 . . . . . . . 13:04:43:69:74:79
480 80 [1,1, 4] . . . . . . . DEFINED BY (2.5.4.7): PrintableString PrintableString City
481 86 [1,1, 33] . . . . 3: RelativeDistinguishedName SET OF
482 88 [1,1, 31] . . . . . 0: AttributeTypeAndValue SEQUENCE
483 90 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-organizationName (2.5.4.10)
484 95 [0,0, 26] . . . . . . value: [UNIV 19] AttributeValue ANY
485 . . . . . . . 13:18:49:6E:74:65:72:6E:65:74:20:57:69:64:67:69
486 . . . . . . . 74:73:20:50:74:79:20:4C:74:64
487 95 [1,1, 24] . . . . . . . DEFINED BY (2.5.4.10): PrintableString PrintableString Internet Widgits Pty Ltd
489 :ref:`Read more <definedby>` about that feature.