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
327 If you have got dictionaries with ObjectIdentifiers, like example one
328 from ``tests/test_crts.py``::
331 "1.2.840.113549.1.1.1": "id-rsaEncryption",
332 "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
334 "2.5.4.10": "id-at-organizationName",
335 "2.5.4.11": "id-at-organizationalUnitName",
338 then you can pass it to pretty printer to see human readable OIDs::
340 % python -m pyderasn --oids tests.test_crts:some_oids path/to/file
342 37 [1,1, 11] . . . . . . >: SET OF
343 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
344 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
345 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
346 50 [1,1, 18] . . . . . . >: SET OF
347 52 [1,1, 16] . . . . . . . . >: SEQUENCE OF
348 54 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
349 59 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
350 70 [1,1, 18] . . . . . . >: SET OF
351 72 [1,1, 16] . . . . . . . . >: SEQUENCE OF
352 74 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
353 79 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
359 Each decoded element has so-called decode path: sequence of structure
360 names it is passing during the decode process. Each element has its own
361 unique path inside the whole ASN.1 tree. You can print it out with
362 ``--print-decode-path`` option::
364 % python -m pyderasn --schema path.to:Certificate --print-decode-path path/to/file
365 0 [1,3,1604] Certificate SEQUENCE []
366 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE [tbsCertificate]
367 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL [tbsCertificate:version]
368 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595 [tbsCertificate:serialNumber]
369 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE [tbsCertificate:signature]
370 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5 [tbsCertificate:signature:algorithm]
371 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL [tbsCertificate:signature:parameters]
373 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence [tbsCertificate:issuer]
374 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF [tbsCertificate:issuer:rdnSequence]
375 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF [tbsCertificate:issuer:rdnSequence:0]
376 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE [tbsCertificate:issuer:rdnSequence:0:0]
377 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6 [tbsCertificate:issuer:rdnSequence:0:0:type]
378 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY [tbsCertificate:issuer:rdnSequence:0:0:value]
379 . . . . . . . 13:02:45:53
380 46 [1,1, 2] . . . . . . . DEFINED BY 2.5.4.6: CountryName PrintableString ES [tbsCertificate:issuer:rdnSequence:0:0:value:DEFINED BY 2.5.4.6]
383 Now you can print only the specified tree, for example signature algorithm::
385 % python -m pyderasn --schema path.to:Certificate --decode-path-only tbsCertificate:signature path/to/file
386 18 [1,1, 13] AlgorithmIdentifier SEQUENCE
387 20 [1,1, 9] . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
388 31 [0,0, 2] . parameters: [UNIV 5] ANY OPTIONAL
394 If you have bad DER/BER, then errors will show you where error occurred::
396 % python -m pyderasn --schema tests.test_crts:Certificate path/to/bad/file
397 Traceback (most recent call last):
399 pyderasn.DecodeError: UTCTime (tbsCertificate:validity:notAfter:utcTime) (at 328) invalid UTCTime format
403 % python -m pyderasn path/to/bad/file
405 pyderasn.DecodeError: UTCTime (0:SequenceOf:4:SequenceOf:1:UTCTime) (at 328) invalid UTCTime format
407 You can see, so called, decode path inside the structures:
408 ``tbsCertificate`` -> ``validity`` -> ``notAfter`` -> ``utcTime`` and
409 that object at byte 328 is invalid.
411 X.509 certificate creation
412 --------------------------
414 Let's create some simple self-signed X.509 certificate from the ground::
416 tbs = TBSCertificate()
417 tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
419 sign_algo_id = AlgorithmIdentifier((
420 ("algorithm", ObjectIdentifier("1.2.840.113549.1.1.5")),
421 ("parameters", Any(Null())),
423 tbs["signature"] = sign_algo_id
425 rdnSeq = RDNSequence()
426 for oid, klass, text in (
427 ("2.5.4.6", PrintableString, "XX"),
428 ("2.5.4.8", PrintableString, "Some-State"),
429 ("2.5.4.7", PrintableString, "City"),
430 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
431 ("2.5.4.3", PrintableString, "false.example.com"),
432 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
435 RelativeDistinguishedName((
436 AttributeTypeAndValue((
437 ("type", AttributeType(oid)),
438 ("value", AttributeValue(klass(text))),
442 issuer = Name(("rdnSequence", rdnSeq))
443 tbs["issuer"] = issuer
444 tbs["subject"] = issuer
446 validity = Validity((
448 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53))),
451 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53))),
454 tbs["validity"] = validity
456 spki = SubjectPublicKeyInfo()
457 spki_algo_id = sign_algo_id.copy()
458 spki_algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
459 spki["algorithm"] = spki_algo_id
460 spki["subjectPublicKey"] = BitString(hexdec("".join((
461 "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
462 "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
463 "deec357d0203010001",
465 tbs["subjectPublicKeyInfo"] = spki
468 crt["tbsCertificate"] = tbs
469 crt["signatureAlgorithm"] = sign_algo_id
470 crt["signatureValue"] = BitString(hexdec("".join((
471 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
472 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
476 And we will get the same certificate used in Go's library tests.
481 Here is only very simple example how you can define Any/OctetString
482 fields automatic decoding::
484 class AttributeTypeAndValue(Sequence):
486 ((("type",), AttributeType(defines=("value", {
487 id_at_countryName: PrintableString(),
488 id_at_stateOrProvinceName: PrintableString(),
489 id_at_localityName: PrintableString(),
490 id_at_organizationName: PrintableString(),
491 id_at_commonName: PrintableString(),
493 ("value", AttributeValue()),
496 And when you will try to decode X.509 certificate with it, your pretty
499 34 [0,0, 149] . . issuer: Name CHOICE rdnSequence
500 34 [1,2, 146] . . . rdnSequence: RDNSequence SEQUENCE OF
501 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
502 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
503 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
504 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
505 . . . . . . . 13:02:58:58
506 46 [1,1, 2] . . . . . . . DEFINED BY (2.5.4.6): PrintableString PrintableString XX
507 50 [1,1, 19] . . . . 1: RelativeDistinguishedName SET OF
508 52 [1,1, 17] . . . . . 0: AttributeTypeAndValue SEQUENCE
509 54 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
510 59 [0,0, 12] . . . . . . value: [UNIV 19] AttributeValue ANY
511 . . . . . . . 13:0A:53:6F:6D:65:2D:53:74:61:74:65
512 59 [1,1, 10] . . . . . . . DEFINED BY (2.5.4.8): PrintableString PrintableString Some-State
513 71 [1,1, 13] . . . . 2: RelativeDistinguishedName SET OF
514 73 [1,1, 11] . . . . . 0: AttributeTypeAndValue SEQUENCE
515 75 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
516 80 [0,0, 6] . . . . . . value: [UNIV 19] AttributeValue ANY
517 . . . . . . . 13:04:43:69:74:79
518 80 [1,1, 4] . . . . . . . DEFINED BY (2.5.4.7): PrintableString PrintableString City
519 86 [1,1, 33] . . . . 3: RelativeDistinguishedName SET OF
520 88 [1,1, 31] . . . . . 0: AttributeTypeAndValue SEQUENCE
521 90 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-organizationName (2.5.4.10)
522 95 [0,0, 26] . . . . . . value: [UNIV 19] AttributeValue ANY
523 . . . . . . . 13:18:49:6E:74:65:72:6E:65:74:20:57:69:64:67:69
524 . . . . . . . 74:73:20:50:74:79:20:4C:74:64
525 95 [1,1, 24] . . . . . . . DEFINED BY (2.5.4.10): PrintableString PrintableString Internet Widgits Pty Ltd
527 :ref:`Read more <definedby>` about that feature.