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]-4 . . . . 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. If object has indefinite length
276 encoding, then subtract 2 bytes EOC from its length. If object has
277 explicit tag with indefinite length, then subtract another EOC bytes.
278 In example above, ``eContent`` field has both indefinite field encoding
279 and indefinite length explicit tag. ``BIT STRING``, ``OCTET STRING``
280 (and its derivatives), ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET
281 OF``, ``ANY`` could have indefinite length coding.
283 Only applicable to BER encoded data. If object has BER-specific
284 encoding, then ``BER`` will be shown. It does not depend on indefinite
285 length encoding. ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING`` (and its
286 derivatives) could be BERed.
288 As command line utility
289 -----------------------
291 You can decode DER/BER files using command line abilities and get the
292 same picture as above by executing::
294 % python -m pyderasn --schema tests.test_crts:Certificate path/to/file
296 If there is no schema for you file, then you can try parsing it without,
297 but of course IMPLICIT tags will often make it impossible. But result is
298 good enough for the certificate above::
300 % python -m pyderasn path/to/file
301 0 [1,3,1604] . >: SEQUENCE OF
302 4 [1,3,1453] . . >: SEQUENCE OF
303 8 [0,0, 5] . . . . >: [0] ANY
304 . . . . . A0:03:02:01:02
305 13 [1,1, 3] . . . . >: INTEGER 61595
306 18 [1,1, 13] . . . . >: SEQUENCE OF
307 20 [1,1, 9] . . . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
308 31 [1,1, 0] . . . . . . >: NULL
309 33 [1,3, 274] . . . . >: SEQUENCE OF
310 37 [1,1, 11] . . . . . . >: SET OF
311 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
312 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER 2.5.4.6
313 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
315 1409 [1,1, 50] . . . . . . >: SEQUENCE OF
316 1411 [1,1, 8] . . . . . . . . >: OBJECT IDENTIFIER 1.3.6.1.5.5.7.1.1
317 1421 [1,1, 38] . . . . . . . . >: OCTET STRING 38 bytes
318 . . . . . . . . . 30:24:30:22:06:08:2B:06:01:05:05:07:30:01:86:16
319 . . . . . . . . . 68:74:74:70:3A:2F:2F:6F:63:73:70:2E:69:70:73:63
320 . . . . . . . . . 61:2E:63:6F:6D:2F
321 1461 [1,1, 13] . . >: SEQUENCE OF
322 1463 [1,1, 9] . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
323 1474 [1,1, 0] . . . . >: NULL
324 1476 [1,2, 129] . . >: BIT STRING 1024 bits
325 . . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
326 . . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
329 If you have got dictionaries with ObjectIdentifiers, like example one
330 from ``tests/test_crts.py``::
333 "1.2.840.113549.1.1.1": "id-rsaEncryption",
334 "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
336 "2.5.4.10": "id-at-organizationName",
337 "2.5.4.11": "id-at-organizationalUnitName",
340 then you can pass it to pretty printer to see human readable OIDs::
342 % python -m pyderasn --oids tests.test_crts:some_oids path/to/file
344 37 [1,1, 11] . . . . . . >: SET OF
345 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
346 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
347 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
348 50 [1,1, 18] . . . . . . >: SET OF
349 52 [1,1, 16] . . . . . . . . >: SEQUENCE OF
350 54 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
351 59 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
352 70 [1,1, 18] . . . . . . >: SET OF
353 72 [1,1, 16] . . . . . . . . >: SEQUENCE OF
354 74 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
355 79 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
361 If you have bad DER/BER, then errors will show you where error occurred::
363 % python -m pyderasn --schema tests.test_crts:Certificate path/to/bad/file
364 Traceback (most recent call last):
366 pyderasn.DecodeError: UTCTime (tbsCertificate.validity.notAfter.utcTime) (at 328) invalid UTCTime format
370 % python -m pyderasn path/to/bad/file
372 pyderasn.DecodeError: UTCTime (0.SequenceOf.4.SequenceOf.1.UTCTime) (at 328) invalid UTCTime format
374 You can see, so called, decode path inside the structures:
375 ``tbsCertificate`` -> ``validity`` -> ``notAfter`` -> ``utcTime`` and
376 that object at byte 328 is invalid.
378 X.509 certificate creation
379 --------------------------
381 Let's create some simple self-signed X.509 certificate from the ground::
383 tbs = TBSCertificate()
384 tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
386 sign_algo_id = AlgorithmIdentifier((
387 ("algorithm", ObjectIdentifier("1.2.840.113549.1.1.5")),
388 ("parameters", Any(Null())),
390 tbs["signature"] = sign_algo_id
392 rdnSeq = RDNSequence()
393 for oid, klass, text in (
394 ("2.5.4.6", PrintableString, "XX"),
395 ("2.5.4.8", PrintableString, "Some-State"),
396 ("2.5.4.7", PrintableString, "City"),
397 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
398 ("2.5.4.3", PrintableString, "false.example.com"),
399 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
402 RelativeDistinguishedName((
403 AttributeTypeAndValue((
404 ("type", AttributeType(oid)),
405 ("value", AttributeValue(klass(text))),
409 issuer = Name(("rdnSequence", rdnSeq))
410 tbs["issuer"] = issuer
411 tbs["subject"] = issuer
413 validity = Validity((
415 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53))),
418 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53))),
421 tbs["validity"] = validity
423 spki = SubjectPublicKeyInfo()
424 spki_algo_id = sign_algo_id.copy()
425 spki_algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
426 spki["algorithm"] = spki_algo_id
427 spki["subjectPublicKey"] = BitString(hexdec("".join((
428 "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
429 "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
430 "deec357d0203010001",
432 tbs["subjectPublicKeyInfo"] = spki
435 crt["tbsCertificate"] = tbs
436 crt["signatureAlgorithm"] = sign_algo_id
437 crt["signatureValue"] = BitString(hexdec("".join((
438 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
439 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
443 And we will get the same certificate used in Go's library tests.
448 Here is only very simple example how you can define Any/OctetString
449 fields automatic decoding::
451 class AttributeTypeAndValue(Sequence):
453 ((("type",), AttributeType(defines=("value", {
454 id_at_countryName: PrintableString(),
455 id_at_stateOrProvinceName: PrintableString(),
456 id_at_localityName: PrintableString(),
457 id_at_organizationName: PrintableString(),
458 id_at_commonName: PrintableString(),
460 ("value", AttributeValue()),
463 And when you will try to decode X.509 certificate with it, your pretty
466 34 [0,0, 149] . . issuer: Name CHOICE rdnSequence
467 34 [1,2, 146] . . . rdnSequence: RDNSequence SEQUENCE OF
468 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
469 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
470 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
471 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
472 . . . . . . . 13:02:58:58
473 46 [1,1, 2] . . . . . . . DEFINED BY (2.5.4.6): PrintableString PrintableString XX
474 50 [1,1, 19] . . . . 1: RelativeDistinguishedName SET OF
475 52 [1,1, 17] . . . . . 0: AttributeTypeAndValue SEQUENCE
476 54 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
477 59 [0,0, 12] . . . . . . value: [UNIV 19] AttributeValue ANY
478 . . . . . . . 13:0A:53:6F:6D:65:2D:53:74:61:74:65
479 59 [1,1, 10] . . . . . . . DEFINED BY (2.5.4.8): PrintableString PrintableString Some-State
480 71 [1,1, 13] . . . . 2: RelativeDistinguishedName SET OF
481 73 [1,1, 11] . . . . . 0: AttributeTypeAndValue SEQUENCE
482 75 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
483 80 [0,0, 6] . . . . . . value: [UNIV 19] AttributeValue ANY
484 . . . . . . . 13:04:43:69:74:79
485 80 [1,1, 4] . . . . . . . DEFINED BY (2.5.4.7): PrintableString PrintableString City
486 86 [1,1, 33] . . . . 3: RelativeDistinguishedName SET OF
487 88 [1,1, 31] . . . . . 0: AttributeTypeAndValue SEQUENCE
488 90 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-organizationName (2.5.4.10)
489 95 [0,0, 26] . . . . . . value: [UNIV 19] AttributeValue ANY
490 . . . . . . . 13:18:49:6E:74:65:72:6E:65:74:20:57:69:64:67:69
491 . . . . . . . 74:73:20:50:74:79:20:4C:74:64
492 95 [1,1, 24] . . . . . . . DEFINED BY (2.5.4.10): PrintableString PrintableString Internet Widgits Pty Ltd
494 :ref:`Read more <definedby>` about that feature.