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 = Certificate().decod(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...
187 .. seealso:: :ref:`Better pretty printing <pprint_example>`
189 As command line utility
190 -----------------------
192 .. seealso:: :ref:`cmdline`
197 If you have bad DER/BER, then errors will show you where error occurred::
199 $ python -m pyderasn --schema tests.test_crts:Certificate path/to/bad/file
200 Traceback (most recent call last):
202 pyderasn.DecodeError: UTCTime (tbsCertificate:validity:notAfter:utcTime) (at 328) invalid UTCTime format
206 $ python -m pyderasn path/to/bad/file
208 pyderasn.DecodeError: UTCTime (0:SequenceOf:4:SequenceOf:1:UTCTime) (at 328) invalid UTCTime format
210 You can see, so called, decode path inside the structures:
211 ``tbsCertificate`` -> ``validity`` -> ``notAfter`` -> ``utcTime`` and
212 that object at byte 328 is invalid.
214 X.509 certificate creation
215 --------------------------
217 Let's create some simple self-signed X.509 certificate from the ground::
219 tbs = TBSCertificate()
220 tbs["serialNumber"] = CertificateSerialNumber(10143011886257155224)
222 sign_algo_id = AlgorithmIdentifier((
223 ("algorithm", ObjectIdentifier("1.2.840.113549.1.1.5")),
224 ("parameters", Any(Null())),
226 tbs["signature"] = sign_algo_id
228 rdnSeq = RDNSequence()
229 for oid, klass, text in (
230 ("2.5.4.6", PrintableString, "XX"),
231 ("2.5.4.8", PrintableString, "Some-State"),
232 ("2.5.4.7", PrintableString, "City"),
233 ("2.5.4.10", PrintableString, "Internet Widgits Pty Ltd"),
234 ("2.5.4.3", PrintableString, "false.example.com"),
235 ("1.2.840.113549.1.9.1", IA5String, "false@example.com"),
238 RelativeDistinguishedName((
239 AttributeTypeAndValue((
240 ("type", AttributeType(oid)),
241 ("value", AttributeValue(klass(text))),
245 issuer = Name(("rdnSequence", rdnSeq))
246 tbs["issuer"] = issuer
247 tbs["subject"] = issuer
249 validity = Validity((
251 ("utcTime", UTCTime(datetime(2009, 10, 8, 0, 25, 53))),
254 ("utcTime", UTCTime(datetime(2010, 10, 8, 0, 25, 53))),
257 tbs["validity"] = validity
259 spki = SubjectPublicKeyInfo()
260 spki_algo_id = copy(sign_algo_id)
261 spki_algo_id["algorithm"] = ObjectIdentifier("1.2.840.113549.1.1.1")
262 spki["algorithm"] = spki_algo_id
263 spki["subjectPublicKey"] = BitString(hexdec("".join((
264 "3048024100cdb7639c3278f006aa277f6eaf42902b592d8cbcbe38a1c92ba4695",
265 "a331b1deadeadd8e9a5c27e8c4c2fd0a8889657722a4f2af7589cf2c77045dc8f",
266 "deec357d0203010001",
268 tbs["subjectPublicKeyInfo"] = spki
271 crt["tbsCertificate"] = tbs
272 crt["signatureAlgorithm"] = sign_algo_id
273 crt["signatureValue"] = BitString(hexdec("".join((
274 "a67b06ec5ece92772ca413cba3ca12568fdc6c7b4511cd40a7f659980402df2b",
275 "998bb9a4a8cbeb34c0f0a78cf8d91ede14a5ed76bf116fe360aafa8821490435",
279 And we will get the same certificate used in Go's library tests.
284 Here is only very simple example how you can define Any/OctetString
285 fields automatic decoding::
287 class AttributeTypeAndValue(Sequence):
289 ((("type",), AttributeType(defines=((("value",), {
290 id_at_countryName: PrintableString(),
291 id_at_stateOrProvinceName: PrintableString(),
292 id_at_localityName: PrintableString(),
293 id_at_organizationName: PrintableString(),
294 id_at_commonName: PrintableString(),
296 ("value", AttributeValue()),
299 And when you will try to decode X.509 certificate with it, your pretty
302 34 [0,0, 149] . . issuer: Name CHOICE rdnSequence
303 34 [1,2, 146] . . . rdnSequence: RDNSequence SEQUENCE OF
304 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
305 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
306 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
307 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
308 . . . . . . . 13:02:58:58
309 46 [1,1, 2] . . . . . . . DEFINED BY (2.5.4.6): PrintableString PrintableString XX
310 50 [1,1, 19] . . . . 1: RelativeDistinguishedName SET OF
311 52 [1,1, 17] . . . . . 0: AttributeTypeAndValue SEQUENCE
312 54 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
313 59 [0,0, 12] . . . . . . value: [UNIV 19] AttributeValue ANY
314 . . . . . . . 13:0A:53:6F:6D:65:2D:53:74:61:74:65
315 59 [1,1, 10] . . . . . . . DEFINED BY (2.5.4.8): PrintableString PrintableString Some-State
316 71 [1,1, 13] . . . . 2: RelativeDistinguishedName SET OF
317 73 [1,1, 11] . . . . . 0: AttributeTypeAndValue SEQUENCE
318 75 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
319 80 [0,0, 6] . . . . . . value: [UNIV 19] AttributeValue ANY
320 . . . . . . . 13:04:43:69:74:79
321 80 [1,1, 4] . . . . . . . DEFINED BY (2.5.4.7): PrintableString PrintableString City
322 86 [1,1, 33] . . . . 3: RelativeDistinguishedName SET OF
323 88 [1,1, 31] . . . . . 0: AttributeTypeAndValue SEQUENCE
324 90 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER id-at-organizationName (2.5.4.10)
325 95 [0,0, 26] . . . . . . value: [UNIV 19] AttributeValue ANY
326 . . . . . . . 13:18:49:6E:74:65:72:6E:65:74:20:57:69:64:67:69
327 . . . . . . . 74:73:20:50:74:79:20:4C:74:64
328 95 [1,1, 24] . . . . . . . DEFINED BY (2.5.4.10): PrintableString PrintableString Internet Widgits Pty Ltd
330 .. seealso:: :ref:`definedby`
332 Streaming and dealing with huge structures
333 ------------------------------------------
334 .. seealso:: :ref:`streaming`