blob: f6957b9dd7728794f85d3a715c8e3bf7d1086b3d [file] [log] [blame]
Paul Kehrer890cb7f2015-08-10 21:05:34 -05001# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4
5from __future__ import absolute_import, division, print_function
6
Paul Kehreraa7a3222015-08-11 00:00:54 -05007import abc
Paul Kehrer23c0bbc2015-12-25 22:35:19 -06008import datetime
Paul Kehrer890cb7f2015-08-10 21:05:34 -05009import hashlib
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -050010import ipaddress
Paul Kehrer9f8069a2015-08-10 21:10:34 -050011from enum import Enum
Paul Kehrer890cb7f2015-08-10 21:05:34 -050012
Ofek Lev0e6a1292017-02-08 00:09:41 -050013from asn1crypto.keys import PublicKeyInfo
Paul Kehrer890cb7f2015-08-10 21:05:34 -050014
15import six
16
17from cryptography import utils
Predrag Gruevski38995392015-09-21 21:53:49 -040018from cryptography.hazmat.primitives import constant_time, serialization
Alex Gaynor01c70492016-03-27 17:00:59 -040019from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
Alex Gaynorbeb25512016-03-27 16:39:49 -040020from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
Alex Gaynor6a0718f2017-06-04 13:36:58 -040021from cryptography.x509.certificate_transparency import (
22 SignedCertificateTimestamp
23)
Paul Kehreraa7a3222015-08-11 00:00:54 -050024from cryptography.x509.general_name import GeneralName, IPAddress, OtherName
Alex Gaynora783c572017-03-21 09:24:12 -040025from cryptography.x509.name import RelativeDistinguishedName
Paul Kehrer49bb7562015-12-25 16:17:40 -060026from cryptography.x509.oid import (
27 CRLEntryExtensionOID, ExtensionOID, ObjectIdentifier
28)
Paul Kehrer890cb7f2015-08-10 21:05:34 -050029
30
Paul Kehrer890cb7f2015-08-10 21:05:34 -050031def _key_identifier_from_public_key(public_key):
Alex Gaynorbeb25512016-03-27 16:39:49 -040032 if isinstance(public_key, RSAPublicKey):
33 data = public_key.public_bytes(
34 serialization.Encoding.DER,
35 serialization.PublicFormat.PKCS1,
36 )
Alex Gaynor01c70492016-03-27 17:00:59 -040037 elif isinstance(public_key, EllipticCurvePublicKey):
38 data = public_key.public_numbers().encode_point()
Alex Gaynorbeb25512016-03-27 16:39:49 -040039 else:
40 # This is a very slow way to do this.
41 serialized = public_key.public_bytes(
42 serialization.Encoding.DER,
43 serialization.PublicFormat.SubjectPublicKeyInfo
44 )
Paul Kehrer890cb7f2015-08-10 21:05:34 -050045
Ofek Lev0e6a1292017-02-08 00:09:41 -050046 data = six.binary_type(PublicKeyInfo.load(serialized)['public_key'])
Alex Gaynorbeb25512016-03-27 16:39:49 -040047
Paul Kehrer890cb7f2015-08-10 21:05:34 -050048 return hashlib.sha1(data).digest()
49
50
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -050051class DuplicateExtension(Exception):
52 def __init__(self, msg, oid):
53 super(DuplicateExtension, self).__init__(msg)
54 self.oid = oid
55
56
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -050057class ExtensionNotFound(Exception):
58 def __init__(self, msg, oid):
59 super(ExtensionNotFound, self).__init__(msg)
60 self.oid = oid
61
62
Paul Kehreraa7a3222015-08-11 00:00:54 -050063@six.add_metaclass(abc.ABCMeta)
64class ExtensionType(object):
65 @abc.abstractproperty
66 def oid(self):
67 """
68 Returns the oid associated with the given extension type.
69 """
70
71
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -050072class Extensions(object):
73 def __init__(self, extensions):
74 self._extensions = extensions
75
76 def get_extension_for_oid(self, oid):
77 for ext in self:
78 if ext.oid == oid:
79 return ext
80
81 raise ExtensionNotFound("No {0} extension was found".format(oid), oid)
82
Phoebe Queen64cf4cd2015-08-12 02:28:43 +010083 def get_extension_for_class(self, extclass):
Paul Kehrere69c5fe2015-12-30 21:03:26 -060084 if extclass is UnrecognizedExtension:
85 raise TypeError(
86 "UnrecognizedExtension can't be used with "
87 "get_extension_for_class because more than one instance of the"
88 " class may be present."
89 )
90
Phoebe Queen64cf4cd2015-08-12 02:28:43 +010091 for ext in self:
Phoebe Queen754be602015-08-12 03:11:35 +010092 if isinstance(ext.value, extclass):
Phoebe Queen64cf4cd2015-08-12 02:28:43 +010093 return ext
94
Phoebe Queen2cc111a2015-08-12 04:14:22 +010095 raise ExtensionNotFound(
Phoebe Queenecae9812015-08-12 05:00:32 +010096 "No {0} extension was found".format(extclass), extclass.oid
Phoebe Queen2cc111a2015-08-12 04:14:22 +010097 )
Phoebe Queen64cf4cd2015-08-12 02:28:43 +010098
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -050099 def __iter__(self):
100 return iter(self._extensions)
101
102 def __len__(self):
103 return len(self._extensions)
104
Paul Kehrer5b90c972015-12-26 00:52:58 -0600105 def __getitem__(self, idx):
106 return self._extensions[idx]
107
Paul Kehrerafbe75b2015-10-20 08:08:43 -0500108 def __repr__(self):
109 return (
110 "<Extensions({0})>".format(self._extensions)
111 )
112
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -0500113
Paul Kehrer890cb7f2015-08-10 21:05:34 -0500114@utils.register_interface(ExtensionType)
Paul Kehrer3b95cd72015-12-22 21:40:20 -0600115class CRLNumber(object):
116 oid = ExtensionOID.CRL_NUMBER
117
118 def __init__(self, crl_number):
119 if not isinstance(crl_number, six.integer_types):
120 raise TypeError("crl_number must be an integer")
121
122 self._crl_number = crl_number
123
124 def __eq__(self, other):
125 if not isinstance(other, CRLNumber):
126 return NotImplemented
127
128 return self.crl_number == other.crl_number
129
130 def __ne__(self, other):
131 return not self == other
132
Alex Gaynorf9a77b62015-12-26 12:14:25 -0500133 def __hash__(self):
134 return hash(self.crl_number)
135
Paul Kehrer3b95cd72015-12-22 21:40:20 -0600136 def __repr__(self):
137 return "<CRLNumber({0})>".format(self.crl_number)
138
139 crl_number = utils.read_only_property("_crl_number")
140
141
142@utils.register_interface(ExtensionType)
Paul Kehrer890cb7f2015-08-10 21:05:34 -0500143class AuthorityKeyIdentifier(object):
144 oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER
145
146 def __init__(self, key_identifier, authority_cert_issuer,
147 authority_cert_serial_number):
Paul Kehrer0d943bb2016-01-05 19:02:32 -0600148 if (authority_cert_issuer is None) != (
149 authority_cert_serial_number is None
150 ):
151 raise ValueError(
152 "authority_cert_issuer and authority_cert_serial_number "
153 "must both be present or both None"
154 )
Paul Kehrer890cb7f2015-08-10 21:05:34 -0500155
Marti40f19992016-08-26 04:26:31 +0300156 if authority_cert_issuer is not None:
157 authority_cert_issuer = list(authority_cert_issuer)
158 if not all(
159 isinstance(x, GeneralName) for x in authority_cert_issuer
160 ):
161 raise TypeError(
162 "authority_cert_issuer must be a list of GeneralName "
163 "objects"
164 )
Paul Kehrer890cb7f2015-08-10 21:05:34 -0500165
Paul Kehrer0d943bb2016-01-05 19:02:32 -0600166 if authority_cert_serial_number is not None and not isinstance(
167 authority_cert_serial_number, six.integer_types
168 ):
169 raise TypeError(
170 "authority_cert_serial_number must be an integer"
171 )
Paul Kehrer890cb7f2015-08-10 21:05:34 -0500172
173 self._key_identifier = key_identifier
174 self._authority_cert_issuer = authority_cert_issuer
175 self._authority_cert_serial_number = authority_cert_serial_number
176
177 @classmethod
178 def from_issuer_public_key(cls, public_key):
179 digest = _key_identifier_from_public_key(public_key)
180 return cls(
181 key_identifier=digest,
182 authority_cert_issuer=None,
183 authority_cert_serial_number=None
184 )
185
Paul Kehrer61ff3562016-03-11 22:51:27 -0400186 @classmethod
187 def from_issuer_subject_key_identifier(cls, ski):
188 return cls(
189 key_identifier=ski.value.digest,
190 authority_cert_issuer=None,
191 authority_cert_serial_number=None
192 )
193
Paul Kehrer890cb7f2015-08-10 21:05:34 -0500194 def __repr__(self):
195 return (
196 "<AuthorityKeyIdentifier(key_identifier={0.key_identifier!r}, "
197 "authority_cert_issuer={0.authority_cert_issuer}, "
198 "authority_cert_serial_number={0.authority_cert_serial_number}"
199 ")>".format(self)
200 )
201
202 def __eq__(self, other):
203 if not isinstance(other, AuthorityKeyIdentifier):
204 return NotImplemented
205
206 return (
207 self.key_identifier == other.key_identifier and
208 self.authority_cert_issuer == other.authority_cert_issuer and
209 self.authority_cert_serial_number ==
210 other.authority_cert_serial_number
211 )
212
213 def __ne__(self, other):
214 return not self == other
215
Paul Kehrer979c2632017-09-14 04:24:30 +0800216 def __hash__(self):
217 if self.authority_cert_issuer is None:
218 aci = None
219 else:
220 aci = tuple(self.authority_cert_issuer)
221 return hash((
222 self.key_identifier, aci, self.authority_cert_serial_number
223 ))
224
Paul Kehrer890cb7f2015-08-10 21:05:34 -0500225 key_identifier = utils.read_only_property("_key_identifier")
226 authority_cert_issuer = utils.read_only_property("_authority_cert_issuer")
227 authority_cert_serial_number = utils.read_only_property(
228 "_authority_cert_serial_number"
229 )
230
231
232@utils.register_interface(ExtensionType)
233class SubjectKeyIdentifier(object):
234 oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER
235
236 def __init__(self, digest):
237 self._digest = digest
238
239 @classmethod
240 def from_public_key(cls, public_key):
241 return cls(_key_identifier_from_public_key(public_key))
242
243 digest = utils.read_only_property("_digest")
244
245 def __repr__(self):
246 return "<SubjectKeyIdentifier(digest={0!r})>".format(self.digest)
247
248 def __eq__(self, other):
249 if not isinstance(other, SubjectKeyIdentifier):
250 return NotImplemented
251
Predrag Gruevski57f3b3f2015-09-21 18:51:47 -0400252 return constant_time.bytes_eq(self.digest, other.digest)
Paul Kehrer890cb7f2015-08-10 21:05:34 -0500253
254 def __ne__(self, other):
255 return not self == other
Paul Kehrer9f8069a2015-08-10 21:10:34 -0500256
Alex Gaynor410fe352015-12-26 15:01:25 -0500257 def __hash__(self):
258 return hash(self.digest)
259
Paul Kehrer9f8069a2015-08-10 21:10:34 -0500260
261@utils.register_interface(ExtensionType)
262class AuthorityInformationAccess(object):
263 oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS
264
265 def __init__(self, descriptions):
Marti40f19992016-08-26 04:26:31 +0300266 descriptions = list(descriptions)
Paul Kehrer9f8069a2015-08-10 21:10:34 -0500267 if not all(isinstance(x, AccessDescription) for x in descriptions):
268 raise TypeError(
269 "Every item in the descriptions list must be an "
270 "AccessDescription"
271 )
272
273 self._descriptions = descriptions
274
275 def __iter__(self):
276 return iter(self._descriptions)
277
278 def __len__(self):
279 return len(self._descriptions)
280
281 def __repr__(self):
282 return "<AuthorityInformationAccess({0})>".format(self._descriptions)
283
284 def __eq__(self, other):
285 if not isinstance(other, AuthorityInformationAccess):
286 return NotImplemented
287
288 return self._descriptions == other._descriptions
289
290 def __ne__(self, other):
291 return not self == other
292
Paul Kehrerad4b3592015-12-27 17:27:40 -0600293 def __getitem__(self, idx):
294 return self._descriptions[idx]
295
Paul Kehrer54024492017-09-14 01:55:31 +0800296 def __hash__(self):
297 return hash(tuple(self._descriptions))
298
Paul Kehrer9f8069a2015-08-10 21:10:34 -0500299
300class AccessDescription(object):
301 def __init__(self, access_method, access_location):
Nick Bastind06763d2015-12-12 18:32:59 -0800302 if not isinstance(access_method, ObjectIdentifier):
Nick Bastinbd079ae2015-12-13 05:15:44 -0800303 raise TypeError("access_method must be an ObjectIdentifier")
Paul Kehrer9f8069a2015-08-10 21:10:34 -0500304
305 if not isinstance(access_location, GeneralName):
306 raise TypeError("access_location must be a GeneralName")
307
308 self._access_method = access_method
309 self._access_location = access_location
310
311 def __repr__(self):
312 return (
313 "<AccessDescription(access_method={0.access_method}, access_locati"
314 "on={0.access_location})>".format(self)
315 )
316
317 def __eq__(self, other):
318 if not isinstance(other, AccessDescription):
319 return NotImplemented
320
321 return (
322 self.access_method == other.access_method and
323 self.access_location == other.access_location
324 )
325
326 def __ne__(self, other):
327 return not self == other
328
Eeshan Gargd8e0d852016-01-31 16:46:22 -0330329 def __hash__(self):
330 return hash((self.access_method, self.access_location))
331
Paul Kehrer9f8069a2015-08-10 21:10:34 -0500332 access_method = utils.read_only_property("_access_method")
333 access_location = utils.read_only_property("_access_location")
334
335
336@utils.register_interface(ExtensionType)
337class BasicConstraints(object):
338 oid = ExtensionOID.BASIC_CONSTRAINTS
339
340 def __init__(self, ca, path_length):
341 if not isinstance(ca, bool):
342 raise TypeError("ca must be a boolean value")
343
344 if path_length is not None and not ca:
345 raise ValueError("path_length must be None when ca is False")
346
347 if (
348 path_length is not None and
349 (not isinstance(path_length, six.integer_types) or path_length < 0)
350 ):
351 raise TypeError(
352 "path_length must be a non-negative integer or None"
353 )
354
355 self._ca = ca
356 self._path_length = path_length
357
358 ca = utils.read_only_property("_ca")
359 path_length = utils.read_only_property("_path_length")
360
361 def __repr__(self):
362 return ("<BasicConstraints(ca={0.ca}, "
363 "path_length={0.path_length})>").format(self)
364
365 def __eq__(self, other):
366 if not isinstance(other, BasicConstraints):
367 return NotImplemented
368
369 return self.ca == other.ca and self.path_length == other.path_length
370
371 def __ne__(self, other):
372 return not self == other
373
Paul Kehrer2eb69f62015-12-27 11:46:11 -0600374 def __hash__(self):
375 return hash((self.ca, self.path_length))
376
Paul Kehrer9f8069a2015-08-10 21:10:34 -0500377
378@utils.register_interface(ExtensionType)
379class CRLDistributionPoints(object):
380 oid = ExtensionOID.CRL_DISTRIBUTION_POINTS
381
382 def __init__(self, distribution_points):
Marti40f19992016-08-26 04:26:31 +0300383 distribution_points = list(distribution_points)
Paul Kehrer9f8069a2015-08-10 21:10:34 -0500384 if not all(
385 isinstance(x, DistributionPoint) for x in distribution_points
386 ):
387 raise TypeError(
388 "distribution_points must be a list of DistributionPoint "
389 "objects"
390 )
391
392 self._distribution_points = distribution_points
393
394 def __iter__(self):
395 return iter(self._distribution_points)
396
397 def __len__(self):
398 return len(self._distribution_points)
399
400 def __repr__(self):
401 return "<CRLDistributionPoints({0})>".format(self._distribution_points)
402
403 def __eq__(self, other):
404 if not isinstance(other, CRLDistributionPoints):
405 return NotImplemented
406
407 return self._distribution_points == other._distribution_points
408
409 def __ne__(self, other):
410 return not self == other
411
Paul Kehreree2e92d2015-12-27 17:29:37 -0600412 def __getitem__(self, idx):
413 return self._distribution_points[idx]
414
Paul Kehrer9f8069a2015-08-10 21:10:34 -0500415
416class DistributionPoint(object):
417 def __init__(self, full_name, relative_name, reasons, crl_issuer):
418 if full_name and relative_name:
419 raise ValueError(
420 "You cannot provide both full_name and relative_name, at "
421 "least one must be None."
422 )
423
Marti40f19992016-08-26 04:26:31 +0300424 if full_name:
425 full_name = list(full_name)
426 if not all(isinstance(x, GeneralName) for x in full_name):
427 raise TypeError(
428 "full_name must be a list of GeneralName objects"
429 )
Paul Kehrer9f8069a2015-08-10 21:10:34 -0500430
Fraser Tweedale02467dd2016-11-07 15:54:04 +1000431 if relative_name:
Alex Gaynora783c572017-03-21 09:24:12 -0400432 if not isinstance(relative_name, RelativeDistinguishedName):
Fraser Tweedale02467dd2016-11-07 15:54:04 +1000433 raise TypeError(
434 "relative_name must be a RelativeDistinguishedName"
435 )
Paul Kehrer9f8069a2015-08-10 21:10:34 -0500436
Marti40f19992016-08-26 04:26:31 +0300437 if crl_issuer:
438 crl_issuer = list(crl_issuer)
439 if not all(isinstance(x, GeneralName) for x in crl_issuer):
440 raise TypeError(
441 "crl_issuer must be None or a list of general names"
442 )
Paul Kehrer9f8069a2015-08-10 21:10:34 -0500443
444 if reasons and (not isinstance(reasons, frozenset) or not all(
445 isinstance(x, ReasonFlags) for x in reasons
446 )):
447 raise TypeError("reasons must be None or frozenset of ReasonFlags")
448
449 if reasons and (
450 ReasonFlags.unspecified in reasons or
451 ReasonFlags.remove_from_crl in reasons
452 ):
453 raise ValueError(
454 "unspecified and remove_from_crl are not valid reasons in a "
455 "DistributionPoint"
456 )
457
458 if reasons and not crl_issuer and not (full_name or relative_name):
459 raise ValueError(
460 "You must supply crl_issuer, full_name, or relative_name when "
461 "reasons is not None"
462 )
463
464 self._full_name = full_name
465 self._relative_name = relative_name
466 self._reasons = reasons
467 self._crl_issuer = crl_issuer
468
469 def __repr__(self):
470 return (
471 "<DistributionPoint(full_name={0.full_name}, relative_name={0.rela"
472 "tive_name}, reasons={0.reasons}, crl_issuer={0.crl_is"
473 "suer})>".format(self)
474 )
475
476 def __eq__(self, other):
477 if not isinstance(other, DistributionPoint):
478 return NotImplemented
479
480 return (
481 self.full_name == other.full_name and
482 self.relative_name == other.relative_name and
483 self.reasons == other.reasons and
484 self.crl_issuer == other.crl_issuer
485 )
486
487 def __ne__(self, other):
488 return not self == other
489
490 full_name = utils.read_only_property("_full_name")
491 relative_name = utils.read_only_property("_relative_name")
492 reasons = utils.read_only_property("_reasons")
493 crl_issuer = utils.read_only_property("_crl_issuer")
494
495
496class ReasonFlags(Enum):
497 unspecified = "unspecified"
498 key_compromise = "keyCompromise"
499 ca_compromise = "cACompromise"
500 affiliation_changed = "affiliationChanged"
501 superseded = "superseded"
502 cessation_of_operation = "cessationOfOperation"
503 certificate_hold = "certificateHold"
504 privilege_withdrawn = "privilegeWithdrawn"
505 aa_compromise = "aACompromise"
506 remove_from_crl = "removeFromCRL"
Paul Kehrer012262c2015-08-10 23:42:57 -0500507
508
509@utils.register_interface(ExtensionType)
Paul Kehrer7e8fe9d2015-05-18 09:53:47 -0700510class PolicyConstraints(object):
Paul Kehrer159b3b52016-02-26 08:27:22 -0600511 oid = ExtensionOID.POLICY_CONSTRAINTS
512
Paul Kehrer7e8fe9d2015-05-18 09:53:47 -0700513 def __init__(self, require_explicit_policy, inhibit_policy_mapping):
514 if require_explicit_policy is not None and not isinstance(
515 require_explicit_policy, six.integer_types
516 ):
517 raise TypeError(
518 "require_explicit_policy must be a non-negative integer or "
519 "None"
520 )
521
522 if inhibit_policy_mapping is not None and not isinstance(
523 inhibit_policy_mapping, six.integer_types
524 ):
525 raise TypeError(
526 "inhibit_policy_mapping must be a non-negative integer or None"
527 )
528
529 if inhibit_policy_mapping is None and require_explicit_policy is None:
530 raise ValueError(
531 "At least one of require_explicit_policy and "
532 "inhibit_policy_mapping must not be None"
533 )
534
535 self._require_explicit_policy = require_explicit_policy
536 self._inhibit_policy_mapping = inhibit_policy_mapping
537
538 def __repr__(self):
539 return (
540 u"<PolicyConstraints(require_explicit_policy={0.require_explicit"
541 u"_policy}, inhibit_policy_mapping={0.inhibit_policy_"
542 u"mapping})>".format(self)
543 )
544
545 def __eq__(self, other):
546 if not isinstance(other, PolicyConstraints):
547 return NotImplemented
548
549 return (
550 self.require_explicit_policy == other.require_explicit_policy and
551 self.inhibit_policy_mapping == other.inhibit_policy_mapping
552 )
553
554 def __ne__(self, other):
555 return not self == other
556
557 require_explicit_policy = utils.read_only_property(
558 "_require_explicit_policy"
559 )
560 inhibit_policy_mapping = utils.read_only_property(
561 "_inhibit_policy_mapping"
562 )
563
564
565@utils.register_interface(ExtensionType)
Paul Kehrer012262c2015-08-10 23:42:57 -0500566class CertificatePolicies(object):
567 oid = ExtensionOID.CERTIFICATE_POLICIES
568
569 def __init__(self, policies):
Marti40f19992016-08-26 04:26:31 +0300570 policies = list(policies)
Paul Kehrer012262c2015-08-10 23:42:57 -0500571 if not all(isinstance(x, PolicyInformation) for x in policies):
572 raise TypeError(
573 "Every item in the policies list must be a "
574 "PolicyInformation"
575 )
576
577 self._policies = policies
578
579 def __iter__(self):
580 return iter(self._policies)
581
582 def __len__(self):
583 return len(self._policies)
584
585 def __repr__(self):
586 return "<CertificatePolicies({0})>".format(self._policies)
587
588 def __eq__(self, other):
589 if not isinstance(other, CertificatePolicies):
590 return NotImplemented
591
592 return self._policies == other._policies
593
594 def __ne__(self, other):
595 return not self == other
596
Paul Kehrere8db7bd2015-12-27 17:32:57 -0600597 def __getitem__(self, idx):
598 return self._policies[idx]
599
Paul Kehrerab96a532017-09-14 07:42:33 +0800600 def __hash__(self):
601 return hash(tuple(self._policies))
602
Paul Kehrer012262c2015-08-10 23:42:57 -0500603
604class PolicyInformation(object):
605 def __init__(self, policy_identifier, policy_qualifiers):
606 if not isinstance(policy_identifier, ObjectIdentifier):
607 raise TypeError("policy_identifier must be an ObjectIdentifier")
608
609 self._policy_identifier = policy_identifier
Marti40f19992016-08-26 04:26:31 +0300610
611 if policy_qualifiers:
612 policy_qualifiers = list(policy_qualifiers)
613 if not all(
614 isinstance(x, (six.text_type, UserNotice))
615 for x in policy_qualifiers
616 ):
617 raise TypeError(
618 "policy_qualifiers must be a list of strings and/or "
619 "UserNotice objects or None"
620 )
Paul Kehrer012262c2015-08-10 23:42:57 -0500621
622 self._policy_qualifiers = policy_qualifiers
623
624 def __repr__(self):
625 return (
626 "<PolicyInformation(policy_identifier={0.policy_identifier}, polic"
627 "y_qualifiers={0.policy_qualifiers})>".format(self)
628 )
629
630 def __eq__(self, other):
631 if not isinstance(other, PolicyInformation):
632 return NotImplemented
633
634 return (
635 self.policy_identifier == other.policy_identifier and
636 self.policy_qualifiers == other.policy_qualifiers
637 )
638
639 def __ne__(self, other):
640 return not self == other
641
Paul Kehrerab96a532017-09-14 07:42:33 +0800642 def __hash__(self):
643 if self.policy_qualifiers is not None:
644 pq = tuple(self.policy_qualifiers)
645 else:
646 pq = None
647
648 return hash((self.policy_identifier, pq))
649
Paul Kehrer012262c2015-08-10 23:42:57 -0500650 policy_identifier = utils.read_only_property("_policy_identifier")
651 policy_qualifiers = utils.read_only_property("_policy_qualifiers")
652
653
654class UserNotice(object):
655 def __init__(self, notice_reference, explicit_text):
656 if notice_reference and not isinstance(
657 notice_reference, NoticeReference
658 ):
659 raise TypeError(
660 "notice_reference must be None or a NoticeReference"
661 )
662
663 self._notice_reference = notice_reference
664 self._explicit_text = explicit_text
665
666 def __repr__(self):
667 return (
668 "<UserNotice(notice_reference={0.notice_reference}, explicit_text="
669 "{0.explicit_text!r})>".format(self)
670 )
671
672 def __eq__(self, other):
673 if not isinstance(other, UserNotice):
674 return NotImplemented
675
676 return (
677 self.notice_reference == other.notice_reference and
678 self.explicit_text == other.explicit_text
679 )
680
681 def __ne__(self, other):
682 return not self == other
683
Paul Kehrerab96a532017-09-14 07:42:33 +0800684 def __hash__(self):
685 return hash((self.notice_reference, self.explicit_text))
686
Paul Kehrer012262c2015-08-10 23:42:57 -0500687 notice_reference = utils.read_only_property("_notice_reference")
688 explicit_text = utils.read_only_property("_explicit_text")
689
690
691class NoticeReference(object):
692 def __init__(self, organization, notice_numbers):
693 self._organization = organization
Marti40f19992016-08-26 04:26:31 +0300694 notice_numbers = list(notice_numbers)
695 if not all(isinstance(x, int) for x in notice_numbers):
Paul Kehrer012262c2015-08-10 23:42:57 -0500696 raise TypeError(
697 "notice_numbers must be a list of integers"
698 )
699
700 self._notice_numbers = notice_numbers
701
702 def __repr__(self):
703 return (
704 "<NoticeReference(organization={0.organization!r}, notice_numbers="
705 "{0.notice_numbers})>".format(self)
706 )
707
708 def __eq__(self, other):
709 if not isinstance(other, NoticeReference):
710 return NotImplemented
711
712 return (
713 self.organization == other.organization and
714 self.notice_numbers == other.notice_numbers
715 )
716
717 def __ne__(self, other):
718 return not self == other
719
Paul Kehrerab96a532017-09-14 07:42:33 +0800720 def __hash__(self):
721 return hash((self.organization, tuple(self.notice_numbers)))
722
Paul Kehrer012262c2015-08-10 23:42:57 -0500723 organization = utils.read_only_property("_organization")
724 notice_numbers = utils.read_only_property("_notice_numbers")
725
726
727@utils.register_interface(ExtensionType)
728class ExtendedKeyUsage(object):
729 oid = ExtensionOID.EXTENDED_KEY_USAGE
730
731 def __init__(self, usages):
Marti40f19992016-08-26 04:26:31 +0300732 usages = list(usages)
Paul Kehrer012262c2015-08-10 23:42:57 -0500733 if not all(isinstance(x, ObjectIdentifier) for x in usages):
734 raise TypeError(
735 "Every item in the usages list must be an ObjectIdentifier"
736 )
737
738 self._usages = usages
739
740 def __iter__(self):
741 return iter(self._usages)
742
743 def __len__(self):
744 return len(self._usages)
745
746 def __repr__(self):
747 return "<ExtendedKeyUsage({0})>".format(self._usages)
748
749 def __eq__(self, other):
750 if not isinstance(other, ExtendedKeyUsage):
751 return NotImplemented
752
753 return self._usages == other._usages
754
755 def __ne__(self, other):
756 return not self == other
757
Paul Kehrer7b6be922017-09-14 07:43:07 +0800758 def __hash__(self):
759 return hash(tuple(self._usages))
760
Paul Kehrer012262c2015-08-10 23:42:57 -0500761
762@utils.register_interface(ExtensionType)
763class OCSPNoCheck(object):
764 oid = ExtensionOID.OCSP_NO_CHECK
765
766
767@utils.register_interface(ExtensionType)
Paul Kehrer5d669662017-09-11 09:16:34 +0800768class TLSFeature(object):
769 oid = ExtensionOID.TLS_FEATURE
770
771 def __init__(self, features):
772 features = list(features)
773 if (
774 not all(isinstance(x, TLSFeatureType) for x in features) or
775 len(features) == 0
776 ):
777 raise TypeError(
778 "features must be a list of elements from the TLSFeatureType "
779 "enum"
780 )
781
782 self._features = features
783
784 def __iter__(self):
785 return iter(self._features)
786
787 def __len__(self):
788 return len(self._features)
789
790 def __repr__(self):
791 return "<TLSFeature(features={0._features})>".format(self)
792
793 def __eq__(self, other):
794 if not isinstance(other, TLSFeature):
795 return NotImplemented
796
797 return self._features == other._features
798
799 def __getitem__(self, idx):
800 return self._features[idx]
801
802 def __ne__(self, other):
803 return not self == other
804
805 def __hash__(self):
806 return hash(tuple(self._features))
807
808
809class TLSFeatureType(Enum):
810 # status_request is defined in RFC 6066 and is used for what is commonly
811 # called OCSP Must-Staple when present in the TLS Feature extension in an
812 # X.509 certificate.
813 status_request = 5
814 # status_request_v2 is defined in RFC 6961 and allows multiple OCSP
815 # responses to be provided. It is not currently in use by clients or
816 # servers.
817 status_request_v2 = 17
818
819
820_TLS_FEATURE_TYPE_TO_ENUM = dict((x.value, x) for x in TLSFeatureType)
821
822
823@utils.register_interface(ExtensionType)
Paul Kehrer012262c2015-08-10 23:42:57 -0500824class InhibitAnyPolicy(object):
825 oid = ExtensionOID.INHIBIT_ANY_POLICY
826
827 def __init__(self, skip_certs):
828 if not isinstance(skip_certs, six.integer_types):
829 raise TypeError("skip_certs must be an integer")
830
831 if skip_certs < 0:
832 raise ValueError("skip_certs must be a non-negative integer")
833
834 self._skip_certs = skip_certs
835
836 def __repr__(self):
837 return "<InhibitAnyPolicy(skip_certs={0.skip_certs})>".format(self)
838
839 def __eq__(self, other):
840 if not isinstance(other, InhibitAnyPolicy):
841 return NotImplemented
842
843 return self.skip_certs == other.skip_certs
844
845 def __ne__(self, other):
846 return not self == other
847
Eeshan Garg0a0293e2016-02-01 12:56:40 -0330848 def __hash__(self):
849 return hash(self.skip_certs)
850
Paul Kehrer012262c2015-08-10 23:42:57 -0500851 skip_certs = utils.read_only_property("_skip_certs")
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -0500852
853
854@utils.register_interface(ExtensionType)
855class KeyUsage(object):
856 oid = ExtensionOID.KEY_USAGE
857
858 def __init__(self, digital_signature, content_commitment, key_encipherment,
859 data_encipherment, key_agreement, key_cert_sign, crl_sign,
860 encipher_only, decipher_only):
861 if not key_agreement and (encipher_only or decipher_only):
862 raise ValueError(
863 "encipher_only and decipher_only can only be true when "
864 "key_agreement is true"
865 )
866
867 self._digital_signature = digital_signature
868 self._content_commitment = content_commitment
869 self._key_encipherment = key_encipherment
870 self._data_encipherment = data_encipherment
871 self._key_agreement = key_agreement
872 self._key_cert_sign = key_cert_sign
873 self._crl_sign = crl_sign
874 self._encipher_only = encipher_only
875 self._decipher_only = decipher_only
876
877 digital_signature = utils.read_only_property("_digital_signature")
878 content_commitment = utils.read_only_property("_content_commitment")
879 key_encipherment = utils.read_only_property("_key_encipherment")
880 data_encipherment = utils.read_only_property("_data_encipherment")
881 key_agreement = utils.read_only_property("_key_agreement")
882 key_cert_sign = utils.read_only_property("_key_cert_sign")
883 crl_sign = utils.read_only_property("_crl_sign")
884
885 @property
886 def encipher_only(self):
887 if not self.key_agreement:
888 raise ValueError(
889 "encipher_only is undefined unless key_agreement is true"
890 )
891 else:
892 return self._encipher_only
893
894 @property
895 def decipher_only(self):
896 if not self.key_agreement:
897 raise ValueError(
898 "decipher_only is undefined unless key_agreement is true"
899 )
900 else:
901 return self._decipher_only
902
903 def __repr__(self):
904 try:
905 encipher_only = self.encipher_only
906 decipher_only = self.decipher_only
907 except ValueError:
908 encipher_only = None
909 decipher_only = None
910
911 return ("<KeyUsage(digital_signature={0.digital_signature}, "
912 "content_commitment={0.content_commitment}, "
913 "key_encipherment={0.key_encipherment}, "
914 "data_encipherment={0.data_encipherment}, "
915 "key_agreement={0.key_agreement}, "
916 "key_cert_sign={0.key_cert_sign}, crl_sign={0.crl_sign}, "
917 "encipher_only={1}, decipher_only={2})>").format(
918 self, encipher_only, decipher_only)
919
920 def __eq__(self, other):
921 if not isinstance(other, KeyUsage):
922 return NotImplemented
923
924 return (
925 self.digital_signature == other.digital_signature and
926 self.content_commitment == other.content_commitment and
927 self.key_encipherment == other.key_encipherment and
928 self.data_encipherment == other.data_encipherment and
929 self.key_agreement == other.key_agreement and
930 self.key_cert_sign == other.key_cert_sign and
931 self.crl_sign == other.crl_sign and
932 self._encipher_only == other._encipher_only and
933 self._decipher_only == other._decipher_only
934 )
935
936 def __ne__(self, other):
937 return not self == other
938
Paul Kehrer7b6be922017-09-14 07:43:07 +0800939 def __hash__(self):
940 return hash((
941 self.digital_signature, self.content_commitment,
942 self.key_encipherment, self.data_encipherment,
943 self.key_agreement, self.key_cert_sign,
944 self.crl_sign, self._encipher_only,
945 self._decipher_only
946 ))
947
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -0500948
949@utils.register_interface(ExtensionType)
950class NameConstraints(object):
951 oid = ExtensionOID.NAME_CONSTRAINTS
952
953 def __init__(self, permitted_subtrees, excluded_subtrees):
954 if permitted_subtrees is not None:
Marti40f19992016-08-26 04:26:31 +0300955 permitted_subtrees = list(permitted_subtrees)
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -0500956 if not all(
957 isinstance(x, GeneralName) for x in permitted_subtrees
958 ):
959 raise TypeError(
960 "permitted_subtrees must be a list of GeneralName objects "
961 "or None"
962 )
963
964 self._validate_ip_name(permitted_subtrees)
965
966 if excluded_subtrees is not None:
Marti40f19992016-08-26 04:26:31 +0300967 excluded_subtrees = list(excluded_subtrees)
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -0500968 if not all(
969 isinstance(x, GeneralName) for x in excluded_subtrees
970 ):
971 raise TypeError(
972 "excluded_subtrees must be a list of GeneralName objects "
973 "or None"
974 )
975
976 self._validate_ip_name(excluded_subtrees)
977
978 if permitted_subtrees is None and excluded_subtrees is None:
979 raise ValueError(
980 "At least one of permitted_subtrees and excluded_subtrees "
981 "must not be None"
982 )
983
984 self._permitted_subtrees = permitted_subtrees
985 self._excluded_subtrees = excluded_subtrees
986
987 def __eq__(self, other):
988 if not isinstance(other, NameConstraints):
989 return NotImplemented
990
991 return (
992 self.excluded_subtrees == other.excluded_subtrees and
993 self.permitted_subtrees == other.permitted_subtrees
994 )
995
996 def __ne__(self, other):
997 return not self == other
998
999 def _validate_ip_name(self, tree):
1000 if any(isinstance(name, IPAddress) and not isinstance(
1001 name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network)
1002 ) for name in tree):
1003 raise TypeError(
1004 "IPAddress name constraints must be an IPv4Network or"
1005 " IPv6Network object"
1006 )
1007
1008 def __repr__(self):
1009 return (
1010 u"<NameConstraints(permitted_subtrees={0.permitted_subtrees}, "
1011 u"excluded_subtrees={0.excluded_subtrees})>".format(self)
1012 )
1013
Paul Kehrerbdad0512017-09-14 04:24:20 +08001014 def __hash__(self):
1015 if self.permitted_subtrees is not None:
1016 ps = tuple(self.permitted_subtrees)
1017 else:
1018 ps = None
1019
1020 if self.excluded_subtrees is not None:
1021 es = tuple(self.excluded_subtrees)
1022 else:
1023 es = None
1024
1025 return hash((ps, es))
1026
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -05001027 permitted_subtrees = utils.read_only_property("_permitted_subtrees")
1028 excluded_subtrees = utils.read_only_property("_excluded_subtrees")
Paul Kehreraa7a3222015-08-11 00:00:54 -05001029
1030
1031class Extension(object):
1032 def __init__(self, oid, critical, value):
1033 if not isinstance(oid, ObjectIdentifier):
1034 raise TypeError(
1035 "oid argument must be an ObjectIdentifier instance."
1036 )
1037
1038 if not isinstance(critical, bool):
1039 raise TypeError("critical must be a boolean value")
1040
1041 self._oid = oid
1042 self._critical = critical
1043 self._value = value
1044
1045 oid = utils.read_only_property("_oid")
1046 critical = utils.read_only_property("_critical")
1047 value = utils.read_only_property("_value")
1048
1049 def __repr__(self):
1050 return ("<Extension(oid={0.oid}, critical={0.critical}, "
1051 "value={0.value})>").format(self)
1052
1053 def __eq__(self, other):
1054 if not isinstance(other, Extension):
1055 return NotImplemented
1056
1057 return (
1058 self.oid == other.oid and
1059 self.critical == other.critical and
1060 self.value == other.value
1061 )
1062
1063 def __ne__(self, other):
1064 return not self == other
1065
1066
1067class GeneralNames(object):
1068 def __init__(self, general_names):
Marti40f19992016-08-26 04:26:31 +03001069 general_names = list(general_names)
Paul Kehreraa7a3222015-08-11 00:00:54 -05001070 if not all(isinstance(x, GeneralName) for x in general_names):
1071 raise TypeError(
1072 "Every item in the general_names list must be an "
1073 "object conforming to the GeneralName interface"
1074 )
1075
1076 self._general_names = general_names
1077
1078 def __iter__(self):
1079 return iter(self._general_names)
1080
1081 def __len__(self):
1082 return len(self._general_names)
1083
1084 def get_values_for_type(self, type):
1085 # Return the value of each GeneralName, except for OtherName instances
1086 # which we return directly because it has two important properties not
1087 # just one value.
1088 objs = (i for i in self if isinstance(i, type))
1089 if type != OtherName:
1090 objs = (i.value for i in objs)
1091 return list(objs)
1092
1093 def __repr__(self):
1094 return "<GeneralNames({0})>".format(self._general_names)
1095
1096 def __eq__(self, other):
1097 if not isinstance(other, GeneralNames):
1098 return NotImplemented
1099
1100 return self._general_names == other._general_names
1101
1102 def __ne__(self, other):
1103 return not self == other
1104
Paul Kehrer8adb5962015-12-26 14:46:58 -06001105 def __getitem__(self, idx):
1106 return self._general_names[idx]
1107
Paul Kehreraa7a3222015-08-11 00:00:54 -05001108
1109@utils.register_interface(ExtensionType)
1110class SubjectAlternativeName(object):
1111 oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME
1112
1113 def __init__(self, general_names):
1114 self._general_names = GeneralNames(general_names)
1115
1116 def __iter__(self):
1117 return iter(self._general_names)
1118
1119 def __len__(self):
1120 return len(self._general_names)
1121
1122 def get_values_for_type(self, type):
1123 return self._general_names.get_values_for_type(type)
1124
1125 def __repr__(self):
1126 return "<SubjectAlternativeName({0})>".format(self._general_names)
1127
1128 def __eq__(self, other):
1129 if not isinstance(other, SubjectAlternativeName):
1130 return NotImplemented
1131
1132 return self._general_names == other._general_names
1133
Paul Kehrer8adb5962015-12-26 14:46:58 -06001134 def __getitem__(self, idx):
1135 return self._general_names[idx]
1136
Paul Kehreraa7a3222015-08-11 00:00:54 -05001137 def __ne__(self, other):
1138 return not self == other
1139
1140
1141@utils.register_interface(ExtensionType)
1142class IssuerAlternativeName(object):
1143 oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME
1144
1145 def __init__(self, general_names):
1146 self._general_names = GeneralNames(general_names)
1147
1148 def __iter__(self):
1149 return iter(self._general_names)
1150
1151 def __len__(self):
1152 return len(self._general_names)
1153
1154 def get_values_for_type(self, type):
1155 return self._general_names.get_values_for_type(type)
1156
1157 def __repr__(self):
1158 return "<IssuerAlternativeName({0})>".format(self._general_names)
1159
1160 def __eq__(self, other):
1161 if not isinstance(other, IssuerAlternativeName):
1162 return NotImplemented
1163
1164 return self._general_names == other._general_names
1165
1166 def __ne__(self, other):
1167 return not self == other
Paul Kehrer49bb7562015-12-25 16:17:40 -06001168
Paul Kehrer5c999d32015-12-26 17:45:20 -06001169 def __getitem__(self, idx):
1170 return self._general_names[idx]
1171
Paul Kehrer49bb7562015-12-25 16:17:40 -06001172
1173@utils.register_interface(ExtensionType)
1174class CertificateIssuer(object):
1175 oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER
1176
1177 def __init__(self, general_names):
1178 self._general_names = GeneralNames(general_names)
1179
1180 def __iter__(self):
1181 return iter(self._general_names)
1182
1183 def __len__(self):
1184 return len(self._general_names)
1185
1186 def get_values_for_type(self, type):
1187 return self._general_names.get_values_for_type(type)
1188
1189 def __repr__(self):
1190 return "<CertificateIssuer({0})>".format(self._general_names)
1191
1192 def __eq__(self, other):
1193 if not isinstance(other, CertificateIssuer):
1194 return NotImplemented
1195
1196 return self._general_names == other._general_names
1197
1198 def __ne__(self, other):
1199 return not self == other
Paul Kehrer7058ece2015-12-25 22:28:29 -06001200
Paul Kehrer5c999d32015-12-26 17:45:20 -06001201 def __getitem__(self, idx):
1202 return self._general_names[idx]
1203
Paul Kehrer7058ece2015-12-25 22:28:29 -06001204
1205@utils.register_interface(ExtensionType)
1206class CRLReason(object):
1207 oid = CRLEntryExtensionOID.CRL_REASON
1208
1209 def __init__(self, reason):
1210 if not isinstance(reason, ReasonFlags):
1211 raise TypeError("reason must be an element from ReasonFlags")
1212
1213 self._reason = reason
1214
1215 def __repr__(self):
1216 return "<CRLReason(reason={0})>".format(self._reason)
1217
1218 def __eq__(self, other):
1219 if not isinstance(other, CRLReason):
1220 return NotImplemented
1221
1222 return self.reason == other.reason
1223
1224 def __ne__(self, other):
1225 return not self == other
1226
Alex Gaynor07d5cae2015-12-27 15:30:39 -05001227 def __hash__(self):
1228 return hash(self.reason)
1229
Paul Kehrer7058ece2015-12-25 22:28:29 -06001230 reason = utils.read_only_property("_reason")
Paul Kehrer23c0bbc2015-12-25 22:35:19 -06001231
1232
1233@utils.register_interface(ExtensionType)
1234class InvalidityDate(object):
1235 oid = CRLEntryExtensionOID.INVALIDITY_DATE
1236
1237 def __init__(self, invalidity_date):
1238 if not isinstance(invalidity_date, datetime.datetime):
1239 raise TypeError("invalidity_date must be a datetime.datetime")
1240
1241 self._invalidity_date = invalidity_date
1242
1243 def __repr__(self):
1244 return "<InvalidityDate(invalidity_date={0})>".format(
1245 self._invalidity_date
1246 )
1247
1248 def __eq__(self, other):
1249 if not isinstance(other, InvalidityDate):
1250 return NotImplemented
1251
1252 return self.invalidity_date == other.invalidity_date
1253
1254 def __ne__(self, other):
1255 return not self == other
1256
Paul Kehrer67cde762015-12-26 11:37:14 -06001257 def __hash__(self):
1258 return hash(self.invalidity_date)
1259
Paul Kehrer23c0bbc2015-12-25 22:35:19 -06001260 invalidity_date = utils.read_only_property("_invalidity_date")
Paul Kehrer14fd6972015-12-30 10:58:25 -06001261
1262
1263@utils.register_interface(ExtensionType)
Alex Gaynor6a0718f2017-06-04 13:36:58 -04001264class PrecertificateSignedCertificateTimestamps(object):
1265 oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS
1266
1267 def __init__(self, signed_certificate_timestamps):
1268 signed_certificate_timestamps = list(signed_certificate_timestamps)
1269 if not all(
1270 isinstance(sct, SignedCertificateTimestamp)
1271 for sct in signed_certificate_timestamps
1272 ):
1273 raise TypeError(
1274 "Every item in the signed_certificate_timestamps list must be "
1275 "a SignedCertificateTimestamp"
1276 )
1277 self._signed_certificate_timestamps = signed_certificate_timestamps
1278
1279 def __iter__(self):
1280 return iter(self._signed_certificate_timestamps)
1281
1282 def __len__(self):
1283 return len(self._signed_certificate_timestamps)
1284
1285 def __getitem__(self, idx):
1286 return self._signed_certificate_timestamps[idx]
1287
1288 def __repr__(self):
1289 return (
1290 "<PrecertificateSignedCertificateTimestamps({0})>".format(
1291 list(self)
1292 )
1293 )
1294
1295
1296@utils.register_interface(ExtensionType)
Paul Kehrer14fd6972015-12-30 10:58:25 -06001297class UnrecognizedExtension(object):
1298 def __init__(self, oid, value):
1299 if not isinstance(oid, ObjectIdentifier):
1300 raise TypeError("oid must be an ObjectIdentifier")
1301 self._oid = oid
1302 self._value = value
1303
1304 oid = utils.read_only_property("_oid")
1305 value = utils.read_only_property("_value")
1306
1307 def __repr__(self):
1308 return (
1309 "<UnrecognizedExtension(oid={0.oid}, value={0.value!r})>".format(
1310 self
1311 )
1312 )
1313
1314 def __eq__(self, other):
1315 if not isinstance(other, UnrecognizedExtension):
1316 return NotImplemented
1317
1318 return self.oid == other.oid and self.value == other.value
1319
1320 def __ne__(self, other):
1321 return not self == other
1322
1323 def __hash__(self):
1324 return hash((self.oid, self.value))