blob: 435a86cbdbc7913eff5c4dc4dbcad69e2e18ea35 [file] [log] [blame]
wbonde91513e2015-06-03 14:52:18 -04001# coding: utf-8
wbondea25fc22015-06-19 15:07:04 -04002
3"""
4ASN.1 type classes for certificate revocation lists (CRL). Exports the
5following items:
6
7 - CertificateList()
8
9Other type classes are defined that help compose the types listed above.
10"""
11
wbond6b66ab52015-06-21 10:26:45 -040012from __future__ import unicode_literals, division, absolute_import, print_function
wbonde91513e2015-06-03 14:52:18 -040013
14from .algos import SignedDigestAlgorithm
15from .core import (
16 Boolean,
17 Enumerated,
18 GeneralizedTime,
19 Integer,
20 ObjectIdentifier,
21 OctetBitString,
22 OctetString,
23 Sequence,
24 SequenceOf,
25)
26from .x509 import (
wbonda0d45482015-07-13 22:10:20 -040027 AuthorityInfoAccessSyntax,
wbonde91513e2015-06-03 14:52:18 -040028 AuthorityKeyIdentifier,
29 CRLDistributionPoints,
30 DistributionPointName,
wbonde91513e2015-06-03 14:52:18 -040031 GeneralNames,
32 Name,
33 ReasonFlags,
34 Time,
35)
36
37
38
39# The structures in this file are taken from https://tools.ietf.org/html/rfc5280
40
41
42class Version(Integer):
43 _map = {
44 0: 'v1',
45 1: 'v2',
46 2: 'v3',
47 }
48
49
50class IssuingDistributionPoint(Sequence):
51 _fields = [
52 ('distribution_point', DistributionPointName, {'tag_type': 'explicit', 'tag': 0, 'optional': True}),
53 ('only_contains_user_certs', Boolean, {'tag_type': 'implicit', 'tag': 1, 'default': False}),
54 ('only_contains_ca_certs', Boolean, {'tag_type': 'implicit', 'tag': 2, 'default': False}),
55 ('only_some_reasons', ReasonFlags, {'tag_type': 'implicit', 'tag': 3, 'optional': True}),
56 ('indirect_crl', Boolean, {'tag_type': 'implicit', 'tag': 4, 'default': False}),
57 ('only_contains_attribute_certs', Boolean, {'tag_type': 'implicit', 'tag': 5, 'default': False}),
58 ]
59
60
wbonde91513e2015-06-03 14:52:18 -040061class TBSCertListExtensionId(ObjectIdentifier):
62 _map = {
63 '2.5.29.18': 'issuer_alt_name',
64 '2.5.29.20': 'crl_number',
65 '2.5.29.27': 'delta_crl_indicator',
66 '2.5.29.28': 'issuing_distribution_point',
67 '2.5.29.35': 'authority_key_identifier',
68 '2.5.29.46': 'freshest_crl',
69 '1.3.6.1.5.5.7.1.1': 'authority_information_access',
70 }
71
72
73class TBSCertListExtension(Sequence):
74 _fields = [
75 ('extn_id', TBSCertListExtensionId),
76 ('critical', Boolean, {'default': False}),
77 ('extn_value', OctetString),
78 ]
79
80 _oid_pair = ('extn_id', 'extn_value')
81 _oid_specs = {
82 'issuer_alt_name': GeneralNames,
83 'crl_number': Integer,
84 'delta_crl_indicator': Integer,
85 'issuing_distribution_point': IssuingDistributionPoint,
86 'authority_key_identifier': AuthorityKeyIdentifier,
87 'freshest_crl': CRLDistributionPoints,
88 'authority_information_access': AuthorityInfoAccessSyntax,
89 }
90
91
92class TBSCertListExtensions(SequenceOf):
93 _child_spec = TBSCertListExtension
94
95
96class CRLReason(Enumerated):
97 _map = {
98 0: 'unspecified',
99 1: 'key_compromise',
100 2: 'ca_compromise',
101 3: 'affiliation_changed',
102 4: 'superseded',
103 5: 'cessation_of_operation',
104 6: 'certificate_hold',
105 8: 'remove_from_crl',
106 9: 'privilege_withdrawn',
107 10: 'aa_compromise',
108 }
109
wbond2f1eb262015-07-20 08:52:34 -0400110 @property
111 def human_friendly(self):
112 """
113 :return:
114 A unicode string with revocation description that is suitable to
115 show to end-users. Starts with a lower case letter and phrased in
116 such a way that it makes sense after the phrase "because of" or
117 "due to".
118 """
119
120 return {
121 'unspecified': 'an unspecified reason',
122 'key_compromise': 'a compromised key',
123 'ca_compromise': 'the CA being compromised',
124 'affiliation_changed': 'an affiliation change',
125 'superseded': 'certificate supersession',
126 'cessation_of_operation': 'a cessation of operation',
127 'certificate_hold': 'a certificate hold',
128 'remove_from_crl': 'removal from the CRL',
129 'privilege_withdrawn': 'privilege withdrawl',
130 'aa_compromise': 'the AA being compromised',
131 }[self.native]
132
wbonde91513e2015-06-03 14:52:18 -0400133
134class CRLEntryExtensionId(ObjectIdentifier):
135 _map = {
136 '2.5.29.21': 'crl_reason',
137 '2.5.29.24': 'invalidity_date',
138 '2.5.29.29': 'certificate_issuer',
139 }
140
141
142class CRLEntryExtension(Sequence):
143 _fields = [
144 ('extn_id', CRLEntryExtensionId),
145 ('critical', Boolean, {'default': False}),
146 ('extn_value', OctetString),
147 ]
148
149 _oid_pair = ('extn_id', 'extn_value')
150 _oid_specs = {
151 'crl_reason': CRLReason,
152 'invalidity_date': GeneralizedTime,
153 'certificate_issuer': GeneralNames,
154 }
155
156
157class CRLEntryExtensions(SequenceOf):
158 _child_spec = CRLEntryExtension
159
160
161class RevokedCertificate(Sequence):
162 _fields = [
163 ('user_certificate', Integer),
164 ('revocation_date', Time),
165 ('crl_entry_extensions', CRLEntryExtensions, {'optional': True}),
166 ]
167
wbond598c2282015-07-20 08:54:22 -0400168 _processed_extensions = False
169 _critical_extensions = None
170 _crl_reason_value = None
171 _invalidity_date_value = None
172 _certificate_issuer_value = None
173
174 def _set_extensions(self):
175 """
176 Sets common named extensions to private attributes and creates a list
177 of critical extensions
178 """
179
180 self._critical_extensions = []
181
182 for extension in self['crl_entry_extensions']:
183 name = extension['extn_id'].native
184 attribute_name = '_%s_value' % name
185 if hasattr(self, attribute_name):
186 setattr(self, attribute_name, extension['extn_value'].parsed)
187 if extension['critical'].native:
188 self._critical_extensions.append(name)
189
190 self._processed_extensions = True
191
192 @property
193 def critical_extensions(self):
194 """
195 Returns a list of the names (or OID if not a known extension) of the
196 extensions marked as critical
197
198 :return:
199 A list of unicode strings
200 """
201
202 if not self._processed_extensions:
203 self._set_extensions()
204 return self._critical_extensions
205
206 @property
207 def crl_reason_value(self):
208 """
209 This extension indicates the reason that a certificate was revoked.
210
211 :return:
212 None or a CRLReason object
213 """
214
215 if self._processed_extensions is False:
216 self._processed_extensions()
217 return self._crl_reason_value
218
219 @property
220 def invalidity_date_value(self):
221 """
222 This extension indicates the suspected date/time the private key was
223 compromised or the certificate became invalid. This would usually be
224 before the revocation date, which is when the CA processed the
225 revocation.
226
227 :return:
228 None or a GeneralizedTime object
229 """
230
231 if self._processed_extensions is False:
232 self._processed_extensions()
233 return self._invalidity_date_value
234
235 @property
236 def certificate_issuer_value(self):
237 """
238 This extension indicates the issuer of the certificate in question,
239 and is used in indirect CRLs. CRL entries without this extension are
240 for certificates issued from the last seen issuer.
241
242 :return:
243 None or an x509.GeneralNames object
244 """
245
246 if self._processed_extensions is False:
247 self._processed_extensions()
248 return self._certificate_issuer_value
249
wbonde91513e2015-06-03 14:52:18 -0400250
251class RevokedCertificates(SequenceOf):
252 _child_spec = RevokedCertificate
253
254
255class TbsCertList(Sequence):
256 _fields = [
257 ('version', Version, {'optional': True}),
258 ('signature', SignedDigestAlgorithm),
259 ('issuer', Name),
260 ('this_update', Time),
261 ('next_update', Time),
262 ('revoked_certificates', RevokedCertificates, {'optional': True}),
263 ('crl_extensions', TBSCertListExtensions, {'tag_type': 'explicit', 'tag': 0, 'optional': True}),
264 ]
265
266
267class CertificateList(Sequence):
268 _fields = [
269 ('tbs_cert_list', TbsCertList),
270 ('signature_algorith', SignedDigestAlgorithm),
271 ('signature', OctetBitString),
272 ]
wbond598c2282015-07-20 08:54:22 -0400273
274 _processed_extensions = False
275 _critical_extensions = None
wbonda613f812015-07-20 10:13:47 -0400276 _issuer_alt_name_value = None
277 _crl_number_value = None
278 _delta_crl_indicator_value = None
279 _issuing_distribution_point_value = None
280 _authority_key_identifier_value = None
281 _freshest_crl_value = None
282 _authority_information_access_value = None
wbond598c2282015-07-20 08:54:22 -0400283
284 def _set_extensions(self):
285 """
286 Sets common named extensions to private attributes and creates a list
287 of critical extensions
288 """
289
290 self._critical_extensions = []
291
292 for extension in self['tbs_cert_list']['crl_extensions']:
293 name = extension['extn_id'].native
294 attribute_name = '_%s_value' % name
295 if hasattr(self, attribute_name):
296 setattr(self, attribute_name, extension['extn_value'].parsed)
297 if extension['critical'].native:
298 self._critical_extensions.append(name)
299
300 self._processed_extensions = True
301
302 @property
303 def critical_extensions(self):
304 """
305 Returns a list of the names (or OID if not a known extension) of the
306 extensions marked as critical
307
308 :return:
309 A list of unicode strings
310 """
311
312 if not self._processed_extensions:
313 self._set_extensions()
314 return self._critical_extensions
315
316 @property
317 def issuer_alt_name_value(self):
318 """
319 This extension allows associating one or more alternative names with
320 the issuer of the CRL.
321
322 :return:
323 None or an x509.GeneralNames object
324 """
325
326 if self._processed_extensions is False:
327 self._processed_extensions()
328 return self._issuer_alt_name_value
329
330 @property
331 def crl_number_value(self):
332 """
333 This extension adds a monotonically increasing number to the CRL and is
334 used to distinguish different versions of the CRL.
335
336 :return:
337 None or an Integer object
338 """
339
340 if self._processed_extensions is False:
341 self._processed_extensions()
342 return self._crl_number_value
343
344 @property
345 def delta_crl_indicator_value(self):
346 """
347 This extension indicates a CRL is a delta CRL, and contains the CRL
348 number of the base CRL that it is a delta from.
349
350 :return:
351 None or an Integer object
352 """
353
354 if self._processed_extensions is False:
355 self._processed_extensions()
356 return self._delta_crl_indicator_value
357
358 @property
359 def issuing_distribution_point_value(self):
360 """
361 This extension includes information about what types of revocations
362 and certificates are part of the CRL.
363
364 :return:
365 None or an IssuingDistributionPoint object
366 """
367
368 if self._processed_extensions is False:
369 self._processed_extensions()
370 return self._issuing_distribution_point_value
371
372 @property
373 def authority_key_identifier_value(self):
374 """
375 This extension helps in identifying the public key with which to
376 validate the authenticity of the CRL.
377
378 :return:
379 None or an AuthorityKeyIdentifier object
380 """
381
382 if self._processed_extensions is False:
383 self._processed_extensions()
384 return self._authority_key_identifier_value
385
386 @property
387 def freshest_crl_value(self):
388 """
389 This extension is used in complete CRLs to indicate where a delta CRL
390 may be located.
391
392 :return:
393 None or a CRLDistributionPoints object
394 """
395
396 if self._processed_extensions is False:
397 self._processed_extensions()
398 return self._freshest_crl_value
399
400 @property
401 def authority_information_access_value(self):
402 """
403 This extension is used to provide a URL with which to download the
404 certificate used to sign this CRL.
405
406 :return:
407 None or an AuthorityInfoAccessSyntax object
408 """
409
410 if self._processed_extensions is False:
411 self._processed_extensions()
412 return self._authority_information_access_value