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
239 52-2∞ [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
244 Offset of the object, where its DER/BER encoding begins.
245 Pay attention that it does **not** include explicit tag.
247 If explicit tag exists, then this is its length (tag + encoded length).
249 Length of object's tag. For example CHOICE does not have its own tag,
252 Length of encoded length.
254 Length of encoded value.
256 Visual indentation to show the depth of object in the hierarchy.
258 Object's name inside SEQUENCE/CHOICE.
260 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
261 here. "IMPLICIT" is omitted.
263 Object's class name, if set. Omitted if it is just an ordinary simple
264 value (like with ``algorithm`` in example above).
268 Object's value, if set. Can consist of multiple words (like OCTET/BIT
269 STRINGs above). We see ``v3`` value in Version, because it is named.
270 ``rdnSequence`` is the choice of CHOICE type.
272 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
273 default one, specified in the schema.
275 Only applicable to BER encoded data. Indefinite length encoding mark.
277 Only applicable to BER encoded data. If object has BER-specific
278 encoding, then ``BER`` will be shown. It does not depend on indefinite
279 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
280 (and its derivatives) could be BERed.
282 As command line utility
283 -----------------------
285 You can decode DER/BER files using command line abilities and get the
286 same picture as above by executing::
288 % python -m pyderasn --schema tests.test_crts:Certificate path/to/file
290 If there is no schema for you file, then you can try parsing it without,
291 but of course IMPLICIT tags will often make it impossible. But result is
292 good enough for the certificate above::
294 % python -m pyderasn path/to/file
295 0 [1,3,1604] . >: SEQUENCE OF
296 4 [1,3,1453] . . >: SEQUENCE OF
297 8 [0,0, 5] . . . . >: [0] ANY
298 . . . . . A0:03:02:01:02
299 13 [1,1, 3] . . . . >: INTEGER 61595
300 18 [1,1, 13] . . . . >: SEQUENCE OF
301 20 [1,1, 9] . . . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
302 31 [1,1, 0] . . . . . . >: NULL
303 33 [1,3, 274] . . . . >: SEQUENCE OF
304 37 [1,1, 11] . . . . . . >: SET OF
305 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
306 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER 2.5.4.6
307 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
309 1409 [1,1, 50] . . . . . . >: SEQUENCE OF
310 1411 [1,1, 8] . . . . . . . . >: OBJECT IDENTIFIER 1.3.6.1.5.5.7.1.1
311 1421 [1,1, 38] . . . . . . . . >: OCTET STRING 38 bytes
312 . . . . . . . . . 30:24:30:22:06:08:2B:06:01:05:05:07:30:01:86:16
313 . . . . . . . . . 68:74:74:70:3A:2F:2F:6F:63:73:70:2E:69:70:73:63
314 . . . . . . . . . 61:2E:63:6F:6D:2F
315 1461 [1,1, 13] . . >: SEQUENCE OF
316 1463 [1,1, 9] . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
317 1474 [1,1, 0] . . . . >: NULL
318 1476 [1,2, 129] . . >: BIT STRING 1024 bits
319 . . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
320 . . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
323 If you have got dictionaries with ObjectIdentifiers, like example one
324 from ``tests/test_crts.py``::
327 "1.2.840.113549.1.1.1": "id-rsaEncryption",
328 "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
330 "2.5.4.10": "id-at-organizationName",
331 "2.5.4.11": "id-at-organizationalUnitName",
334 then you can pass it to pretty printer to see human readable OIDs::
336 % python -m pyderasn --oids tests.test_crts:some_oids path/to/file
338 37 [1,1, 11] . . . . . . >: SET OF
339 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
340 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
341 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
342 50 [1,1, 18] . . . . . . >: SET OF
343 52 [1,1, 16] . . . . . . . . >: SEQUENCE OF
344 54 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
345 59 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
346 70 [1,1, 18] . . . . . . >: SET OF
347 72 [1,1, 16] . . . . . . . . >: SEQUENCE OF
348 74 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
349 79 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
355 If you have bad DER/BER, then errors will show you where error occurred::
357 % python -m pyderasn --schema tests.test_crts:Certificate path/to/bad/file
358 Traceback (most recent call last):
360 pyderasn.DecodeError: UTCTime (tbsCertificate.validity.notAfter.utcTime) (at 328) invalid UTCTime format
364 % python -m pyderasn path/to/bad/file
366 pyderasn.DecodeError: UTCTime (0.SequenceOf.4.SequenceOf.1.UTCTime) (at 328) invalid UTCTime format
368 You can see, so called, decode path inside the structures:
369 ``tbsCertificate`` -> ``validity`` -> ``notAfter`` -> ``utcTime`` and
370 that object at byte 328 is invalid.
372 X.509 certificate creation
373 --------------------------
375 Let's create some simple self-signed X.509 certificate from the ground::
377 tbs = TBSCertificate()
378 tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
380 sign_algo_id = AlgorithmIdentifier((
381 ("algorithm", ObjectIdentifier("1.2.840.113549.1.1.5")),
382 ("parameters", Any(Null())),
384 tbs["signature"] = sign_algo_id
386 rdnSeq = RDNSequence()
387 for oid, klass, text in (
388 ("2.5.4.6", PrintableString, "XX"),
389 ("2.5.4.8", PrintableString, "Some-State"),
390 ("2.5.4.7", PrintableString, "City"),
391 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
392 ("2.5.4.3", PrintableString, "false.example.com"),
393 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
396 RelativeDistinguishedName((
397 AttributeTypeAndValue((
398 ("type", AttributeType(oid)),
399 ("value", AttributeValue(klass(text))),
403 issuer = Name(("rdnSequence", rdnSeq))
404 tbs["issuer"] = issuer
405 tbs["subject"] = issuer
407 validity = Validity((
409 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53))),
412 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53))),
415 tbs["validity"] = validity
417 spki = SubjectPublicKeyInfo()
418 spki_algo_id = sign_algo_id.copy()
419 spki_algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
420 spki["algorithm"] = spki_algo_id
421 spki["subjectPublicKey"] = BitString(hexdec("".join((
422 "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
423 "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
424 "deec357d0203010001",
426 tbs["subjectPublicKeyInfo"] = spki
429 crt["tbsCertificate"] = tbs
430 crt["signatureAlgorithm"] = sign_algo_id
431 crt["signatureValue"] = BitString(hexdec("".join((
432 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
433 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
437 And we will get the same certificate used in Go's library tests.
442 Here is only very simple example how you can define Any/OctetString
443 fields automatic decoding::
445 class AttributeTypeAndValue(Sequence):
447 ((("type",), AttributeType(defines=("value", {
448 id_at_countryName: PrintableString(),
449 id_at_stateOrProvinceName: PrintableString(),
450 id_at_localityName: PrintableString(),
451 id_at_organizationName: PrintableString(),
452 id_at_commonName: PrintableString(),
454 ("value", AttributeValue()),
457 And when you will try to decode X.509 certificate with it, your pretty
460 34 [0,0, 149] . . issuer: Name CHOICE rdnSequence
461 34 [1,2, 146] . . . rdnSequence: RDNSequence SEQUENCE OF
462 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
463 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
464 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
465 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
466 . . . . . . . 13:02:58:58
467 46 [1,1, 2] . . . . . . . DEFINED BY (2.5.4.6): PrintableString PrintableString XX
468 50 [1,1, 19] . . . . 1: RelativeDistinguishedName SET OF
469 52 [1,1, 17] . . . . . 0: AttributeTypeAndValue SEQUENCE
470 54 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
471 59 [0,0, 12] . . . . . . value: [UNIV 19] AttributeValue ANY
472 . . . . . . . 13:0A:53:6F:6D:65:2D:53:74:61:74:65
473 59 [1,1, 10] . . . . . . . DEFINED BY (2.5.4.8): PrintableString PrintableString Some-State
474 71 [1,1, 13] . . . . 2: RelativeDistinguishedName SET OF
475 73 [1,1, 11] . . . . . 0: AttributeTypeAndValue SEQUENCE
476 75 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
477 80 [0,0, 6] . . . . . . value: [UNIV 19] AttributeValue ANY
478 . . . . . . . 13:04:43:69:74:79
479 80 [1,1, 4] . . . . . . . DEFINED BY (2.5.4.7): PrintableString PrintableString City
480 86 [1,1, 33] . . . . 3: RelativeDistinguishedName SET OF
481 88 [1,1, 31] . . . . . 0: AttributeTypeAndValue SEQUENCE
482 90 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-organizationName (2.5.4.10)
483 95 [0,0, 26] . . . . . . value: [UNIV 19] AttributeValue ANY
484 . . . . . . . 13:18:49:6E:74:65:72:6E:65:74:20:57:69:64:67:69
485 . . . . . . . 74:73:20:50:74:79:20:4C:74:64
486 95 [1,1, 24] . . . . . . . DEFINED BY (2.5.4.10): PrintableString PrintableString Internet Widgits Pty Ltd
488 :ref:`Read more <definedby>` about that feature.