Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/asn1crypto/crl.py: 50%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# coding: utf-8
3"""
4ASN.1 type classes for certificate revocation lists (CRL). Exports the
5following items:
7 - CertificateList()
9Other type classes are defined that help compose the types listed above.
10"""
12from __future__ import unicode_literals, division, absolute_import, print_function
14import hashlib
16from .algos import SignedDigestAlgorithm
17from .core import (
18 Boolean,
19 Enumerated,
20 GeneralizedTime,
21 Integer,
22 ObjectIdentifier,
23 OctetBitString,
24 ParsableOctetString,
25 Sequence,
26 SequenceOf,
27)
28from .x509 import (
29 AuthorityInfoAccessSyntax,
30 AuthorityKeyIdentifier,
31 CRLDistributionPoints,
32 DistributionPointName,
33 GeneralNames,
34 Name,
35 ReasonFlags,
36 Time,
37)
40# The structures in this file are taken from https://tools.ietf.org/html/rfc5280
43class Version(Integer):
44 _map = {
45 0: 'v1',
46 1: 'v2',
47 2: 'v3',
48 }
51class IssuingDistributionPoint(Sequence):
52 _fields = [
53 ('distribution_point', DistributionPointName, {'explicit': 0, 'optional': True}),
54 ('only_contains_user_certs', Boolean, {'implicit': 1, 'default': False}),
55 ('only_contains_ca_certs', Boolean, {'implicit': 2, 'default': False}),
56 ('only_some_reasons', ReasonFlags, {'implicit': 3, 'optional': True}),
57 ('indirect_crl', Boolean, {'implicit': 4, 'default': False}),
58 ('only_contains_attribute_certs', Boolean, {'implicit': 5, 'default': False}),
59 ]
62class TBSCertListExtensionId(ObjectIdentifier):
63 _map = {
64 '2.5.29.18': 'issuer_alt_name',
65 '2.5.29.20': 'crl_number',
66 '2.5.29.27': 'delta_crl_indicator',
67 '2.5.29.28': 'issuing_distribution_point',
68 '2.5.29.35': 'authority_key_identifier',
69 '2.5.29.46': 'freshest_crl',
70 '1.3.6.1.5.5.7.1.1': 'authority_information_access',
71 }
74class TBSCertListExtension(Sequence):
75 _fields = [
76 ('extn_id', TBSCertListExtensionId),
77 ('critical', Boolean, {'default': False}),
78 ('extn_value', ParsableOctetString),
79 ]
81 _oid_pair = ('extn_id', 'extn_value')
82 _oid_specs = {
83 'issuer_alt_name': GeneralNames,
84 'crl_number': Integer,
85 'delta_crl_indicator': Integer,
86 'issuing_distribution_point': IssuingDistributionPoint,
87 'authority_key_identifier': AuthorityKeyIdentifier,
88 'freshest_crl': CRLDistributionPoints,
89 'authority_information_access': AuthorityInfoAccessSyntax,
90 }
93class TBSCertListExtensions(SequenceOf):
94 _child_spec = TBSCertListExtension
97class CRLReason(Enumerated):
98 _map = {
99 0: 'unspecified',
100 1: 'key_compromise',
101 2: 'ca_compromise',
102 3: 'affiliation_changed',
103 4: 'superseded',
104 5: 'cessation_of_operation',
105 6: 'certificate_hold',
106 8: 'remove_from_crl',
107 9: 'privilege_withdrawn',
108 10: 'aa_compromise',
109 }
111 @property
112 def human_friendly(self):
113 """
114 :return:
115 A unicode string with revocation description that is suitable to
116 show to end-users. Starts with a lower case letter and phrased in
117 such a way that it makes sense after the phrase "because of" or
118 "due to".
119 """
121 return {
122 'unspecified': 'an unspecified reason',
123 'key_compromise': 'a compromised key',
124 'ca_compromise': 'the CA being compromised',
125 'affiliation_changed': 'an affiliation change',
126 'superseded': 'certificate supersession',
127 'cessation_of_operation': 'a cessation of operation',
128 'certificate_hold': 'a certificate hold',
129 'remove_from_crl': 'removal from the CRL',
130 'privilege_withdrawn': 'privilege withdrawl',
131 'aa_compromise': 'the AA being compromised',
132 }[self.native]
135class CRLEntryExtensionId(ObjectIdentifier):
136 _map = {
137 '2.5.29.21': 'crl_reason',
138 '2.5.29.23': 'hold_instruction_code',
139 '2.5.29.24': 'invalidity_date',
140 '2.5.29.29': 'certificate_issuer',
141 }
144class CRLEntryExtension(Sequence):
145 _fields = [
146 ('extn_id', CRLEntryExtensionId),
147 ('critical', Boolean, {'default': False}),
148 ('extn_value', ParsableOctetString),
149 ]
151 _oid_pair = ('extn_id', 'extn_value')
152 _oid_specs = {
153 'crl_reason': CRLReason,
154 'hold_instruction_code': ObjectIdentifier,
155 'invalidity_date': GeneralizedTime,
156 'certificate_issuer': GeneralNames,
157 }
160class CRLEntryExtensions(SequenceOf):
161 _child_spec = CRLEntryExtension
164class RevokedCertificate(Sequence):
165 _fields = [
166 ('user_certificate', Integer),
167 ('revocation_date', Time),
168 ('crl_entry_extensions', CRLEntryExtensions, {'optional': True}),
169 ]
171 _processed_extensions = False
172 _critical_extensions = None
173 _crl_reason_value = None
174 _invalidity_date_value = None
175 _certificate_issuer_value = None
176 _issuer_name = False
178 def _set_extensions(self):
179 """
180 Sets common named extensions to private attributes and creates a list
181 of critical extensions
182 """
184 self._critical_extensions = set()
186 for extension in self['crl_entry_extensions']:
187 name = extension['extn_id'].native
188 attribute_name = '_%s_value' % name
189 if hasattr(self, attribute_name):
190 setattr(self, attribute_name, extension['extn_value'].parsed)
191 if extension['critical'].native:
192 self._critical_extensions.add(name)
194 self._processed_extensions = True
196 @property
197 def critical_extensions(self):
198 """
199 Returns a set of the names (or OID if not a known extension) of the
200 extensions marked as critical
202 :return:
203 A set of unicode strings
204 """
206 if not self._processed_extensions:
207 self._set_extensions()
208 return self._critical_extensions
210 @property
211 def crl_reason_value(self):
212 """
213 This extension indicates the reason that a certificate was revoked.
215 :return:
216 None or a CRLReason object
217 """
219 if self._processed_extensions is False:
220 self._set_extensions()
221 return self._crl_reason_value
223 @property
224 def invalidity_date_value(self):
225 """
226 This extension indicates the suspected date/time the private key was
227 compromised or the certificate became invalid. This would usually be
228 before the revocation date, which is when the CA processed the
229 revocation.
231 :return:
232 None or a GeneralizedTime object
233 """
235 if self._processed_extensions is False:
236 self._set_extensions()
237 return self._invalidity_date_value
239 @property
240 def certificate_issuer_value(self):
241 """
242 This extension indicates the issuer of the certificate in question,
243 and is used in indirect CRLs. CRL entries without this extension are
244 for certificates issued from the last seen issuer.
246 :return:
247 None or an x509.GeneralNames object
248 """
250 if self._processed_extensions is False:
251 self._set_extensions()
252 return self._certificate_issuer_value
254 @property
255 def issuer_name(self):
256 """
257 :return:
258 None, or an asn1crypto.x509.Name object for the issuer of the cert
259 """
261 if self._issuer_name is False:
262 self._issuer_name = None
263 if self.certificate_issuer_value:
264 for general_name in self.certificate_issuer_value:
265 if general_name.name == 'directory_name':
266 self._issuer_name = general_name.chosen
267 break
268 return self._issuer_name
271class RevokedCertificates(SequenceOf):
272 _child_spec = RevokedCertificate
275class TbsCertList(Sequence):
276 _fields = [
277 ('version', Version, {'optional': True}),
278 ('signature', SignedDigestAlgorithm),
279 ('issuer', Name),
280 ('this_update', Time),
281 ('next_update', Time, {'optional': True}),
282 ('revoked_certificates', RevokedCertificates, {'optional': True}),
283 ('crl_extensions', TBSCertListExtensions, {'explicit': 0, 'optional': True}),
284 ]
287class CertificateList(Sequence):
288 _fields = [
289 ('tbs_cert_list', TbsCertList),
290 ('signature_algorithm', SignedDigestAlgorithm),
291 ('signature', OctetBitString),
292 ]
294 _processed_extensions = False
295 _critical_extensions = None
296 _issuer_alt_name_value = None
297 _crl_number_value = None
298 _delta_crl_indicator_value = None
299 _issuing_distribution_point_value = None
300 _authority_key_identifier_value = None
301 _freshest_crl_value = None
302 _authority_information_access_value = None
303 _issuer_cert_urls = None
304 _delta_crl_distribution_points = None
305 _sha1 = None
306 _sha256 = None
308 def _set_extensions(self):
309 """
310 Sets common named extensions to private attributes and creates a list
311 of critical extensions
312 """
314 self._critical_extensions = set()
316 for extension in self['tbs_cert_list']['crl_extensions']:
317 name = extension['extn_id'].native
318 attribute_name = '_%s_value' % name
319 if hasattr(self, attribute_name):
320 setattr(self, attribute_name, extension['extn_value'].parsed)
321 if extension['critical'].native:
322 self._critical_extensions.add(name)
324 self._processed_extensions = True
326 @property
327 def critical_extensions(self):
328 """
329 Returns a set of the names (or OID if not a known extension) of the
330 extensions marked as critical
332 :return:
333 A set of unicode strings
334 """
336 if not self._processed_extensions:
337 self._set_extensions()
338 return self._critical_extensions
340 @property
341 def issuer_alt_name_value(self):
342 """
343 This extension allows associating one or more alternative names with
344 the issuer of the CRL.
346 :return:
347 None or an x509.GeneralNames object
348 """
350 if self._processed_extensions is False:
351 self._set_extensions()
352 return self._issuer_alt_name_value
354 @property
355 def crl_number_value(self):
356 """
357 This extension adds a monotonically increasing number to the CRL and is
358 used to distinguish different versions of the CRL.
360 :return:
361 None or an Integer object
362 """
364 if self._processed_extensions is False:
365 self._set_extensions()
366 return self._crl_number_value
368 @property
369 def delta_crl_indicator_value(self):
370 """
371 This extension indicates a CRL is a delta CRL, and contains the CRL
372 number of the base CRL that it is a delta from.
374 :return:
375 None or an Integer object
376 """
378 if self._processed_extensions is False:
379 self._set_extensions()
380 return self._delta_crl_indicator_value
382 @property
383 def issuing_distribution_point_value(self):
384 """
385 This extension includes information about what types of revocations
386 and certificates are part of the CRL.
388 :return:
389 None or an IssuingDistributionPoint object
390 """
392 if self._processed_extensions is False:
393 self._set_extensions()
394 return self._issuing_distribution_point_value
396 @property
397 def authority_key_identifier_value(self):
398 """
399 This extension helps in identifying the public key with which to
400 validate the authenticity of the CRL.
402 :return:
403 None or an AuthorityKeyIdentifier object
404 """
406 if self._processed_extensions is False:
407 self._set_extensions()
408 return self._authority_key_identifier_value
410 @property
411 def freshest_crl_value(self):
412 """
413 This extension is used in complete CRLs to indicate where a delta CRL
414 may be located.
416 :return:
417 None or a CRLDistributionPoints object
418 """
420 if self._processed_extensions is False:
421 self._set_extensions()
422 return self._freshest_crl_value
424 @property
425 def authority_information_access_value(self):
426 """
427 This extension is used to provide a URL with which to download the
428 certificate used to sign this CRL.
430 :return:
431 None or an AuthorityInfoAccessSyntax object
432 """
434 if self._processed_extensions is False:
435 self._set_extensions()
436 return self._authority_information_access_value
438 @property
439 def issuer(self):
440 """
441 :return:
442 An asn1crypto.x509.Name object for the issuer of the CRL
443 """
445 return self['tbs_cert_list']['issuer']
447 @property
448 def authority_key_identifier(self):
449 """
450 :return:
451 None or a byte string of the key_identifier from the authority key
452 identifier extension
453 """
455 if not self.authority_key_identifier_value:
456 return None
458 return self.authority_key_identifier_value['key_identifier'].native
460 @property
461 def issuer_cert_urls(self):
462 """
463 :return:
464 A list of unicode strings that are URLs that should contain either
465 an individual DER-encoded X.509 certificate, or a DER-encoded CMS
466 message containing multiple certificates
467 """
469 if self._issuer_cert_urls is None:
470 self._issuer_cert_urls = []
471 if self.authority_information_access_value:
472 for entry in self.authority_information_access_value:
473 if entry['access_method'].native == 'ca_issuers':
474 location = entry['access_location']
475 if location.name != 'uniform_resource_identifier':
476 continue
477 url = location.native
478 if url.lower()[0:7] == 'http://':
479 self._issuer_cert_urls.append(url)
480 return self._issuer_cert_urls
482 @property
483 def delta_crl_distribution_points(self):
484 """
485 Returns delta CRL URLs - only applies to complete CRLs
487 :return:
488 A list of zero or more DistributionPoint objects
489 """
491 if self._delta_crl_distribution_points is None:
492 self._delta_crl_distribution_points = []
494 if self.freshest_crl_value is not None:
495 for distribution_point in self.freshest_crl_value:
496 distribution_point_name = distribution_point['distribution_point']
497 # RFC 5280 indicates conforming CA should not use the relative form
498 if distribution_point_name.name == 'name_relative_to_crl_issuer':
499 continue
500 # This library is currently only concerned with HTTP-based CRLs
501 for general_name in distribution_point_name.chosen:
502 if general_name.name == 'uniform_resource_identifier':
503 self._delta_crl_distribution_points.append(distribution_point)
505 return self._delta_crl_distribution_points
507 @property
508 def signature(self):
509 """
510 :return:
511 A byte string of the signature
512 """
514 return self['signature'].native
516 @property
517 def sha1(self):
518 """
519 :return:
520 The SHA1 hash of the DER-encoded bytes of this certificate list
521 """
523 if self._sha1 is None:
524 self._sha1 = hashlib.sha1(self.dump()).digest()
525 return self._sha1
527 @property
528 def sha256(self):
529 """
530 :return:
531 The SHA-256 hash of the DER-encoded bytes of this certificate list
532 """
534 if self._sha256 is None:
535 self._sha256 = hashlib.sha256(self.dump()).digest()
536 return self._sha256