blob: 22cba68252b93f0ab2faa5bed8235cc0b15441a0 [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
13from pyasn1.codec.der import decoder
14from pyasn1.type import namedtype, univ
15
16import six
17
18from cryptography import utils
Predrag Gruevski38995392015-09-21 21:53:49 -040019from cryptography.hazmat.primitives import constant_time, serialization
Paul Kehreraa7a3222015-08-11 00:00:54 -050020from cryptography.x509.general_name import GeneralName, IPAddress, OtherName
Paul Kehrer9f8069a2015-08-10 21:10:34 -050021from cryptography.x509.name import Name
Paul Kehrer49bb7562015-12-25 16:17:40 -060022from cryptography.x509.oid import (
23 CRLEntryExtensionOID, ExtensionOID, ObjectIdentifier
24)
Paul Kehrer890cb7f2015-08-10 21:05:34 -050025
26
27class _SubjectPublicKeyInfo(univ.Sequence):
28 componentType = namedtype.NamedTypes(
29 namedtype.NamedType('algorithm', univ.Sequence()),
30 namedtype.NamedType('subjectPublicKey', univ.BitString())
31 )
32
33
34def _key_identifier_from_public_key(public_key):
35 # This is a very slow way to do this.
36 serialized = public_key.public_bytes(
37 serialization.Encoding.DER,
38 serialization.PublicFormat.SubjectPublicKeyInfo
39 )
40 spki, remaining = decoder.decode(
41 serialized, asn1Spec=_SubjectPublicKeyInfo()
42 )
43 assert not remaining
44 # the univ.BitString object is a tuple of bits. We need bytes and
45 # pyasn1 really doesn't want to give them to us. To get it we'll
46 # build an integer and convert that to bytes.
47 bits = 0
48 for bit in spki.getComponentByName("subjectPublicKey"):
49 bits = bits << 1 | bit
50
51 data = utils.int_to_bytes(bits)
52 return hashlib.sha1(data).digest()
53
54
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -050055class DuplicateExtension(Exception):
56 def __init__(self, msg, oid):
57 super(DuplicateExtension, self).__init__(msg)
58 self.oid = oid
59
60
61class UnsupportedExtension(Exception):
62 def __init__(self, msg, oid):
63 super(UnsupportedExtension, self).__init__(msg)
64 self.oid = oid
65
66
67class ExtensionNotFound(Exception):
68 def __init__(self, msg, oid):
69 super(ExtensionNotFound, self).__init__(msg)
70 self.oid = oid
71
72
Paul Kehreraa7a3222015-08-11 00:00:54 -050073@six.add_metaclass(abc.ABCMeta)
74class ExtensionType(object):
75 @abc.abstractproperty
76 def oid(self):
77 """
78 Returns the oid associated with the given extension type.
79 """
80
81
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -050082class Extensions(object):
83 def __init__(self, extensions):
84 self._extensions = extensions
85
86 def get_extension_for_oid(self, oid):
87 for ext in self:
88 if ext.oid == oid:
89 return ext
90
91 raise ExtensionNotFound("No {0} extension was found".format(oid), oid)
92
Phoebe Queen64cf4cd2015-08-12 02:28:43 +010093 def get_extension_for_class(self, extclass):
94 for ext in self:
Phoebe Queen754be602015-08-12 03:11:35 +010095 if isinstance(ext.value, extclass):
Phoebe Queen64cf4cd2015-08-12 02:28:43 +010096 return ext
97
Phoebe Queen2cc111a2015-08-12 04:14:22 +010098 raise ExtensionNotFound(
Phoebe Queenecae9812015-08-12 05:00:32 +010099 "No {0} extension was found".format(extclass), extclass.oid
Phoebe Queen2cc111a2015-08-12 04:14:22 +0100100 )
Phoebe Queen64cf4cd2015-08-12 02:28:43 +0100101
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -0500102 def __iter__(self):
103 return iter(self._extensions)
104
105 def __len__(self):
106 return len(self._extensions)
107
Paul Kehrer5b90c972015-12-26 00:52:58 -0600108 def __getitem__(self, idx):
109 return self._extensions[idx]
110
Paul Kehrerafbe75b2015-10-20 08:08:43 -0500111 def __repr__(self):
112 return (
113 "<Extensions({0})>".format(self._extensions)
114 )
115
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -0500116
Paul Kehrer890cb7f2015-08-10 21:05:34 -0500117@utils.register_interface(ExtensionType)
Paul Kehrer3b95cd72015-12-22 21:40:20 -0600118class CRLNumber(object):
119 oid = ExtensionOID.CRL_NUMBER
120
121 def __init__(self, crl_number):
122 if not isinstance(crl_number, six.integer_types):
123 raise TypeError("crl_number must be an integer")
124
125 self._crl_number = crl_number
126
127 def __eq__(self, other):
128 if not isinstance(other, CRLNumber):
129 return NotImplemented
130
131 return self.crl_number == other.crl_number
132
133 def __ne__(self, other):
134 return not self == other
135
136 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):
148 if authority_cert_issuer or authority_cert_serial_number:
149 if not authority_cert_issuer or not authority_cert_serial_number:
150 raise ValueError(
151 "authority_cert_issuer and authority_cert_serial_number "
152 "must both be present or both None"
153 )
154
155 if not all(
156 isinstance(x, GeneralName) for x in authority_cert_issuer
157 ):
158 raise TypeError(
159 "authority_cert_issuer must be a list of GeneralName "
160 "objects"
161 )
162
163 if not isinstance(authority_cert_serial_number, six.integer_types):
164 raise TypeError(
165 "authority_cert_serial_number must be an integer"
166 )
167
168 self._key_identifier = key_identifier
169 self._authority_cert_issuer = authority_cert_issuer
170 self._authority_cert_serial_number = authority_cert_serial_number
171
172 @classmethod
173 def from_issuer_public_key(cls, public_key):
174 digest = _key_identifier_from_public_key(public_key)
175 return cls(
176 key_identifier=digest,
177 authority_cert_issuer=None,
178 authority_cert_serial_number=None
179 )
180
181 def __repr__(self):
182 return (
183 "<AuthorityKeyIdentifier(key_identifier={0.key_identifier!r}, "
184 "authority_cert_issuer={0.authority_cert_issuer}, "
185 "authority_cert_serial_number={0.authority_cert_serial_number}"
186 ")>".format(self)
187 )
188
189 def __eq__(self, other):
190 if not isinstance(other, AuthorityKeyIdentifier):
191 return NotImplemented
192
193 return (
194 self.key_identifier == other.key_identifier and
195 self.authority_cert_issuer == other.authority_cert_issuer and
196 self.authority_cert_serial_number ==
197 other.authority_cert_serial_number
198 )
199
200 def __ne__(self, other):
201 return not self == other
202
203 key_identifier = utils.read_only_property("_key_identifier")
204 authority_cert_issuer = utils.read_only_property("_authority_cert_issuer")
205 authority_cert_serial_number = utils.read_only_property(
206 "_authority_cert_serial_number"
207 )
208
209
210@utils.register_interface(ExtensionType)
211class SubjectKeyIdentifier(object):
212 oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER
213
214 def __init__(self, digest):
215 self._digest = digest
216
217 @classmethod
218 def from_public_key(cls, public_key):
219 return cls(_key_identifier_from_public_key(public_key))
220
221 digest = utils.read_only_property("_digest")
222
223 def __repr__(self):
224 return "<SubjectKeyIdentifier(digest={0!r})>".format(self.digest)
225
226 def __eq__(self, other):
227 if not isinstance(other, SubjectKeyIdentifier):
228 return NotImplemented
229
Predrag Gruevski57f3b3f2015-09-21 18:51:47 -0400230 return constant_time.bytes_eq(self.digest, other.digest)
Paul Kehrer890cb7f2015-08-10 21:05:34 -0500231
232 def __ne__(self, other):
233 return not self == other
Paul Kehrer9f8069a2015-08-10 21:10:34 -0500234
235
236@utils.register_interface(ExtensionType)
237class AuthorityInformationAccess(object):
238 oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS
239
240 def __init__(self, descriptions):
241 if not all(isinstance(x, AccessDescription) for x in descriptions):
242 raise TypeError(
243 "Every item in the descriptions list must be an "
244 "AccessDescription"
245 )
246
247 self._descriptions = descriptions
248
249 def __iter__(self):
250 return iter(self._descriptions)
251
252 def __len__(self):
253 return len(self._descriptions)
254
255 def __repr__(self):
256 return "<AuthorityInformationAccess({0})>".format(self._descriptions)
257
258 def __eq__(self, other):
259 if not isinstance(other, AuthorityInformationAccess):
260 return NotImplemented
261
262 return self._descriptions == other._descriptions
263
264 def __ne__(self, other):
265 return not self == other
266
267
268class AccessDescription(object):
269 def __init__(self, access_method, access_location):
Nick Bastind06763d2015-12-12 18:32:59 -0800270 if not isinstance(access_method, ObjectIdentifier):
Nick Bastinbd079ae2015-12-13 05:15:44 -0800271 raise TypeError("access_method must be an ObjectIdentifier")
Paul Kehrer9f8069a2015-08-10 21:10:34 -0500272
273 if not isinstance(access_location, GeneralName):
274 raise TypeError("access_location must be a GeneralName")
275
276 self._access_method = access_method
277 self._access_location = access_location
278
279 def __repr__(self):
280 return (
281 "<AccessDescription(access_method={0.access_method}, access_locati"
282 "on={0.access_location})>".format(self)
283 )
284
285 def __eq__(self, other):
286 if not isinstance(other, AccessDescription):
287 return NotImplemented
288
289 return (
290 self.access_method == other.access_method and
291 self.access_location == other.access_location
292 )
293
294 def __ne__(self, other):
295 return not self == other
296
297 access_method = utils.read_only_property("_access_method")
298 access_location = utils.read_only_property("_access_location")
299
300
301@utils.register_interface(ExtensionType)
302class BasicConstraints(object):
303 oid = ExtensionOID.BASIC_CONSTRAINTS
304
305 def __init__(self, ca, path_length):
306 if not isinstance(ca, bool):
307 raise TypeError("ca must be a boolean value")
308
309 if path_length is not None and not ca:
310 raise ValueError("path_length must be None when ca is False")
311
312 if (
313 path_length is not None and
314 (not isinstance(path_length, six.integer_types) or path_length < 0)
315 ):
316 raise TypeError(
317 "path_length must be a non-negative integer or None"
318 )
319
320 self._ca = ca
321 self._path_length = path_length
322
323 ca = utils.read_only_property("_ca")
324 path_length = utils.read_only_property("_path_length")
325
326 def __repr__(self):
327 return ("<BasicConstraints(ca={0.ca}, "
328 "path_length={0.path_length})>").format(self)
329
330 def __eq__(self, other):
331 if not isinstance(other, BasicConstraints):
332 return NotImplemented
333
334 return self.ca == other.ca and self.path_length == other.path_length
335
336 def __ne__(self, other):
337 return not self == other
338
339
340@utils.register_interface(ExtensionType)
341class CRLDistributionPoints(object):
342 oid = ExtensionOID.CRL_DISTRIBUTION_POINTS
343
344 def __init__(self, distribution_points):
345 if not all(
346 isinstance(x, DistributionPoint) for x in distribution_points
347 ):
348 raise TypeError(
349 "distribution_points must be a list of DistributionPoint "
350 "objects"
351 )
352
353 self._distribution_points = distribution_points
354
355 def __iter__(self):
356 return iter(self._distribution_points)
357
358 def __len__(self):
359 return len(self._distribution_points)
360
361 def __repr__(self):
362 return "<CRLDistributionPoints({0})>".format(self._distribution_points)
363
364 def __eq__(self, other):
365 if not isinstance(other, CRLDistributionPoints):
366 return NotImplemented
367
368 return self._distribution_points == other._distribution_points
369
370 def __ne__(self, other):
371 return not self == other
372
373
374class DistributionPoint(object):
375 def __init__(self, full_name, relative_name, reasons, crl_issuer):
376 if full_name and relative_name:
377 raise ValueError(
378 "You cannot provide both full_name and relative_name, at "
379 "least one must be None."
380 )
381
382 if full_name and not all(
383 isinstance(x, GeneralName) for x in full_name
384 ):
385 raise TypeError(
386 "full_name must be a list of GeneralName objects"
387 )
388
389 if relative_name and not isinstance(relative_name, Name):
390 raise TypeError("relative_name must be a Name")
391
392 if crl_issuer and not all(
393 isinstance(x, GeneralName) for x in crl_issuer
394 ):
395 raise TypeError(
396 "crl_issuer must be None or a list of general names"
397 )
398
399 if reasons and (not isinstance(reasons, frozenset) or not all(
400 isinstance(x, ReasonFlags) for x in reasons
401 )):
402 raise TypeError("reasons must be None or frozenset of ReasonFlags")
403
404 if reasons and (
405 ReasonFlags.unspecified in reasons or
406 ReasonFlags.remove_from_crl in reasons
407 ):
408 raise ValueError(
409 "unspecified and remove_from_crl are not valid reasons in a "
410 "DistributionPoint"
411 )
412
413 if reasons and not crl_issuer and not (full_name or relative_name):
414 raise ValueError(
415 "You must supply crl_issuer, full_name, or relative_name when "
416 "reasons is not None"
417 )
418
419 self._full_name = full_name
420 self._relative_name = relative_name
421 self._reasons = reasons
422 self._crl_issuer = crl_issuer
423
424 def __repr__(self):
425 return (
426 "<DistributionPoint(full_name={0.full_name}, relative_name={0.rela"
427 "tive_name}, reasons={0.reasons}, crl_issuer={0.crl_is"
428 "suer})>".format(self)
429 )
430
431 def __eq__(self, other):
432 if not isinstance(other, DistributionPoint):
433 return NotImplemented
434
435 return (
436 self.full_name == other.full_name and
437 self.relative_name == other.relative_name and
438 self.reasons == other.reasons and
439 self.crl_issuer == other.crl_issuer
440 )
441
442 def __ne__(self, other):
443 return not self == other
444
445 full_name = utils.read_only_property("_full_name")
446 relative_name = utils.read_only_property("_relative_name")
447 reasons = utils.read_only_property("_reasons")
448 crl_issuer = utils.read_only_property("_crl_issuer")
449
450
451class ReasonFlags(Enum):
452 unspecified = "unspecified"
453 key_compromise = "keyCompromise"
454 ca_compromise = "cACompromise"
455 affiliation_changed = "affiliationChanged"
456 superseded = "superseded"
457 cessation_of_operation = "cessationOfOperation"
458 certificate_hold = "certificateHold"
459 privilege_withdrawn = "privilegeWithdrawn"
460 aa_compromise = "aACompromise"
461 remove_from_crl = "removeFromCRL"
Paul Kehrer012262c2015-08-10 23:42:57 -0500462
463
464@utils.register_interface(ExtensionType)
465class CertificatePolicies(object):
466 oid = ExtensionOID.CERTIFICATE_POLICIES
467
468 def __init__(self, policies):
469 if not all(isinstance(x, PolicyInformation) for x in policies):
470 raise TypeError(
471 "Every item in the policies list must be a "
472 "PolicyInformation"
473 )
474
475 self._policies = policies
476
477 def __iter__(self):
478 return iter(self._policies)
479
480 def __len__(self):
481 return len(self._policies)
482
483 def __repr__(self):
484 return "<CertificatePolicies({0})>".format(self._policies)
485
486 def __eq__(self, other):
487 if not isinstance(other, CertificatePolicies):
488 return NotImplemented
489
490 return self._policies == other._policies
491
492 def __ne__(self, other):
493 return not self == other
494
495
496class PolicyInformation(object):
497 def __init__(self, policy_identifier, policy_qualifiers):
498 if not isinstance(policy_identifier, ObjectIdentifier):
499 raise TypeError("policy_identifier must be an ObjectIdentifier")
500
501 self._policy_identifier = policy_identifier
502 if policy_qualifiers and not all(
503 isinstance(
504 x, (six.text_type, UserNotice)
505 ) for x in policy_qualifiers
506 ):
507 raise TypeError(
508 "policy_qualifiers must be a list of strings and/or UserNotice"
509 " objects or None"
510 )
511
512 self._policy_qualifiers = policy_qualifiers
513
514 def __repr__(self):
515 return (
516 "<PolicyInformation(policy_identifier={0.policy_identifier}, polic"
517 "y_qualifiers={0.policy_qualifiers})>".format(self)
518 )
519
520 def __eq__(self, other):
521 if not isinstance(other, PolicyInformation):
522 return NotImplemented
523
524 return (
525 self.policy_identifier == other.policy_identifier and
526 self.policy_qualifiers == other.policy_qualifiers
527 )
528
529 def __ne__(self, other):
530 return not self == other
531
532 policy_identifier = utils.read_only_property("_policy_identifier")
533 policy_qualifiers = utils.read_only_property("_policy_qualifiers")
534
535
536class UserNotice(object):
537 def __init__(self, notice_reference, explicit_text):
538 if notice_reference and not isinstance(
539 notice_reference, NoticeReference
540 ):
541 raise TypeError(
542 "notice_reference must be None or a NoticeReference"
543 )
544
545 self._notice_reference = notice_reference
546 self._explicit_text = explicit_text
547
548 def __repr__(self):
549 return (
550 "<UserNotice(notice_reference={0.notice_reference}, explicit_text="
551 "{0.explicit_text!r})>".format(self)
552 )
553
554 def __eq__(self, other):
555 if not isinstance(other, UserNotice):
556 return NotImplemented
557
558 return (
559 self.notice_reference == other.notice_reference and
560 self.explicit_text == other.explicit_text
561 )
562
563 def __ne__(self, other):
564 return not self == other
565
566 notice_reference = utils.read_only_property("_notice_reference")
567 explicit_text = utils.read_only_property("_explicit_text")
568
569
570class NoticeReference(object):
571 def __init__(self, organization, notice_numbers):
572 self._organization = organization
573 if not isinstance(notice_numbers, list) or not all(
574 isinstance(x, int) for x in notice_numbers
575 ):
576 raise TypeError(
577 "notice_numbers must be a list of integers"
578 )
579
580 self._notice_numbers = notice_numbers
581
582 def __repr__(self):
583 return (
584 "<NoticeReference(organization={0.organization!r}, notice_numbers="
585 "{0.notice_numbers})>".format(self)
586 )
587
588 def __eq__(self, other):
589 if not isinstance(other, NoticeReference):
590 return NotImplemented
591
592 return (
593 self.organization == other.organization and
594 self.notice_numbers == other.notice_numbers
595 )
596
597 def __ne__(self, other):
598 return not self == other
599
600 organization = utils.read_only_property("_organization")
601 notice_numbers = utils.read_only_property("_notice_numbers")
602
603
604@utils.register_interface(ExtensionType)
605class ExtendedKeyUsage(object):
606 oid = ExtensionOID.EXTENDED_KEY_USAGE
607
608 def __init__(self, usages):
609 if not all(isinstance(x, ObjectIdentifier) for x in usages):
610 raise TypeError(
611 "Every item in the usages list must be an ObjectIdentifier"
612 )
613
614 self._usages = usages
615
616 def __iter__(self):
617 return iter(self._usages)
618
619 def __len__(self):
620 return len(self._usages)
621
622 def __repr__(self):
623 return "<ExtendedKeyUsage({0})>".format(self._usages)
624
625 def __eq__(self, other):
626 if not isinstance(other, ExtendedKeyUsage):
627 return NotImplemented
628
629 return self._usages == other._usages
630
631 def __ne__(self, other):
632 return not self == other
633
634
635@utils.register_interface(ExtensionType)
636class OCSPNoCheck(object):
637 oid = ExtensionOID.OCSP_NO_CHECK
638
639
640@utils.register_interface(ExtensionType)
641class InhibitAnyPolicy(object):
642 oid = ExtensionOID.INHIBIT_ANY_POLICY
643
644 def __init__(self, skip_certs):
645 if not isinstance(skip_certs, six.integer_types):
646 raise TypeError("skip_certs must be an integer")
647
648 if skip_certs < 0:
649 raise ValueError("skip_certs must be a non-negative integer")
650
651 self._skip_certs = skip_certs
652
653 def __repr__(self):
654 return "<InhibitAnyPolicy(skip_certs={0.skip_certs})>".format(self)
655
656 def __eq__(self, other):
657 if not isinstance(other, InhibitAnyPolicy):
658 return NotImplemented
659
660 return self.skip_certs == other.skip_certs
661
662 def __ne__(self, other):
663 return not self == other
664
665 skip_certs = utils.read_only_property("_skip_certs")
Paul Kehrerfbeaf2a2015-08-10 23:52:10 -0500666
667
668@utils.register_interface(ExtensionType)
669class KeyUsage(object):
670 oid = ExtensionOID.KEY_USAGE
671
672 def __init__(self, digital_signature, content_commitment, key_encipherment,
673 data_encipherment, key_agreement, key_cert_sign, crl_sign,
674 encipher_only, decipher_only):
675 if not key_agreement and (encipher_only or decipher_only):
676 raise ValueError(
677 "encipher_only and decipher_only can only be true when "
678 "key_agreement is true"
679 )
680
681 self._digital_signature = digital_signature
682 self._content_commitment = content_commitment
683 self._key_encipherment = key_encipherment
684 self._data_encipherment = data_encipherment
685 self._key_agreement = key_agreement
686 self._key_cert_sign = key_cert_sign
687 self._crl_sign = crl_sign
688 self._encipher_only = encipher_only
689 self._decipher_only = decipher_only
690
691 digital_signature = utils.read_only_property("_digital_signature")
692 content_commitment = utils.read_only_property("_content_commitment")
693 key_encipherment = utils.read_only_property("_key_encipherment")
694 data_encipherment = utils.read_only_property("_data_encipherment")
695 key_agreement = utils.read_only_property("_key_agreement")
696 key_cert_sign = utils.read_only_property("_key_cert_sign")
697 crl_sign = utils.read_only_property("_crl_sign")
698
699 @property
700 def encipher_only(self):
701 if not self.key_agreement:
702 raise ValueError(
703 "encipher_only is undefined unless key_agreement is true"
704 )
705 else:
706 return self._encipher_only
707
708 @property
709 def decipher_only(self):
710 if not self.key_agreement:
711 raise ValueError(
712 "decipher_only is undefined unless key_agreement is true"
713 )
714 else:
715 return self._decipher_only
716
717 def __repr__(self):
718 try:
719 encipher_only = self.encipher_only
720 decipher_only = self.decipher_only
721 except ValueError:
722 encipher_only = None
723 decipher_only = None
724
725 return ("<KeyUsage(digital_signature={0.digital_signature}, "
726 "content_commitment={0.content_commitment}, "
727 "key_encipherment={0.key_encipherment}, "
728 "data_encipherment={0.data_encipherment}, "
729 "key_agreement={0.key_agreement}, "
730 "key_cert_sign={0.key_cert_sign}, crl_sign={0.crl_sign}, "
731 "encipher_only={1}, decipher_only={2})>").format(
732 self, encipher_only, decipher_only)
733
734 def __eq__(self, other):
735 if not isinstance(other, KeyUsage):
736 return NotImplemented
737
738 return (
739 self.digital_signature == other.digital_signature and
740 self.content_commitment == other.content_commitment and
741 self.key_encipherment == other.key_encipherment and
742 self.data_encipherment == other.data_encipherment and
743 self.key_agreement == other.key_agreement and
744 self.key_cert_sign == other.key_cert_sign and
745 self.crl_sign == other.crl_sign and
746 self._encipher_only == other._encipher_only and
747 self._decipher_only == other._decipher_only
748 )
749
750 def __ne__(self, other):
751 return not self == other
752
753
754@utils.register_interface(ExtensionType)
755class NameConstraints(object):
756 oid = ExtensionOID.NAME_CONSTRAINTS
757
758 def __init__(self, permitted_subtrees, excluded_subtrees):
759 if permitted_subtrees is not None:
760 if not all(
761 isinstance(x, GeneralName) for x in permitted_subtrees
762 ):
763 raise TypeError(
764 "permitted_subtrees must be a list of GeneralName objects "
765 "or None"
766 )
767
768 self._validate_ip_name(permitted_subtrees)
769
770 if excluded_subtrees is not None:
771 if not all(
772 isinstance(x, GeneralName) for x in excluded_subtrees
773 ):
774 raise TypeError(
775 "excluded_subtrees must be a list of GeneralName objects "
776 "or None"
777 )
778
779 self._validate_ip_name(excluded_subtrees)
780
781 if permitted_subtrees is None and excluded_subtrees is None:
782 raise ValueError(
783 "At least one of permitted_subtrees and excluded_subtrees "
784 "must not be None"
785 )
786
787 self._permitted_subtrees = permitted_subtrees
788 self._excluded_subtrees = excluded_subtrees
789
790 def __eq__(self, other):
791 if not isinstance(other, NameConstraints):
792 return NotImplemented
793
794 return (
795 self.excluded_subtrees == other.excluded_subtrees and
796 self.permitted_subtrees == other.permitted_subtrees
797 )
798
799 def __ne__(self, other):
800 return not self == other
801
802 def _validate_ip_name(self, tree):
803 if any(isinstance(name, IPAddress) and not isinstance(
804 name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network)
805 ) for name in tree):
806 raise TypeError(
807 "IPAddress name constraints must be an IPv4Network or"
808 " IPv6Network object"
809 )
810
811 def __repr__(self):
812 return (
813 u"<NameConstraints(permitted_subtrees={0.permitted_subtrees}, "
814 u"excluded_subtrees={0.excluded_subtrees})>".format(self)
815 )
816
817 permitted_subtrees = utils.read_only_property("_permitted_subtrees")
818 excluded_subtrees = utils.read_only_property("_excluded_subtrees")
Paul Kehreraa7a3222015-08-11 00:00:54 -0500819
820
821class Extension(object):
822 def __init__(self, oid, critical, value):
823 if not isinstance(oid, ObjectIdentifier):
824 raise TypeError(
825 "oid argument must be an ObjectIdentifier instance."
826 )
827
828 if not isinstance(critical, bool):
829 raise TypeError("critical must be a boolean value")
830
831 self._oid = oid
832 self._critical = critical
833 self._value = value
834
835 oid = utils.read_only_property("_oid")
836 critical = utils.read_only_property("_critical")
837 value = utils.read_only_property("_value")
838
839 def __repr__(self):
840 return ("<Extension(oid={0.oid}, critical={0.critical}, "
841 "value={0.value})>").format(self)
842
843 def __eq__(self, other):
844 if not isinstance(other, Extension):
845 return NotImplemented
846
847 return (
848 self.oid == other.oid and
849 self.critical == other.critical and
850 self.value == other.value
851 )
852
853 def __ne__(self, other):
854 return not self == other
855
856
857class GeneralNames(object):
858 def __init__(self, general_names):
859 if not all(isinstance(x, GeneralName) for x in general_names):
860 raise TypeError(
861 "Every item in the general_names list must be an "
862 "object conforming to the GeneralName interface"
863 )
864
865 self._general_names = general_names
866
867 def __iter__(self):
868 return iter(self._general_names)
869
870 def __len__(self):
871 return len(self._general_names)
872
873 def get_values_for_type(self, type):
874 # Return the value of each GeneralName, except for OtherName instances
875 # which we return directly because it has two important properties not
876 # just one value.
877 objs = (i for i in self if isinstance(i, type))
878 if type != OtherName:
879 objs = (i.value for i in objs)
880 return list(objs)
881
882 def __repr__(self):
883 return "<GeneralNames({0})>".format(self._general_names)
884
885 def __eq__(self, other):
886 if not isinstance(other, GeneralNames):
887 return NotImplemented
888
889 return self._general_names == other._general_names
890
891 def __ne__(self, other):
892 return not self == other
893
894
895@utils.register_interface(ExtensionType)
896class SubjectAlternativeName(object):
897 oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME
898
899 def __init__(self, general_names):
900 self._general_names = GeneralNames(general_names)
901
902 def __iter__(self):
903 return iter(self._general_names)
904
905 def __len__(self):
906 return len(self._general_names)
907
908 def get_values_for_type(self, type):
909 return self._general_names.get_values_for_type(type)
910
911 def __repr__(self):
912 return "<SubjectAlternativeName({0})>".format(self._general_names)
913
914 def __eq__(self, other):
915 if not isinstance(other, SubjectAlternativeName):
916 return NotImplemented
917
918 return self._general_names == other._general_names
919
920 def __ne__(self, other):
921 return not self == other
922
923
924@utils.register_interface(ExtensionType)
925class IssuerAlternativeName(object):
926 oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME
927
928 def __init__(self, general_names):
929 self._general_names = GeneralNames(general_names)
930
931 def __iter__(self):
932 return iter(self._general_names)
933
934 def __len__(self):
935 return len(self._general_names)
936
937 def get_values_for_type(self, type):
938 return self._general_names.get_values_for_type(type)
939
940 def __repr__(self):
941 return "<IssuerAlternativeName({0})>".format(self._general_names)
942
943 def __eq__(self, other):
944 if not isinstance(other, IssuerAlternativeName):
945 return NotImplemented
946
947 return self._general_names == other._general_names
948
949 def __ne__(self, other):
950 return not self == other
Paul Kehrer49bb7562015-12-25 16:17:40 -0600951
952
953@utils.register_interface(ExtensionType)
954class CertificateIssuer(object):
955 oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER
956
957 def __init__(self, general_names):
958 self._general_names = GeneralNames(general_names)
959
960 def __iter__(self):
961 return iter(self._general_names)
962
963 def __len__(self):
964 return len(self._general_names)
965
966 def get_values_for_type(self, type):
967 return self._general_names.get_values_for_type(type)
968
969 def __repr__(self):
970 return "<CertificateIssuer({0})>".format(self._general_names)
971
972 def __eq__(self, other):
973 if not isinstance(other, CertificateIssuer):
974 return NotImplemented
975
976 return self._general_names == other._general_names
977
978 def __ne__(self, other):
979 return not self == other
Paul Kehrer7058ece2015-12-25 22:28:29 -0600980
981
982@utils.register_interface(ExtensionType)
983class CRLReason(object):
984 oid = CRLEntryExtensionOID.CRL_REASON
985
986 def __init__(self, reason):
987 if not isinstance(reason, ReasonFlags):
988 raise TypeError("reason must be an element from ReasonFlags")
989
990 self._reason = reason
991
992 def __repr__(self):
993 return "<CRLReason(reason={0})>".format(self._reason)
994
995 def __eq__(self, other):
996 if not isinstance(other, CRLReason):
997 return NotImplemented
998
999 return self.reason == other.reason
1000
1001 def __ne__(self, other):
1002 return not self == other
1003
1004 reason = utils.read_only_property("_reason")
Paul Kehrer23c0bbc2015-12-25 22:35:19 -06001005
1006
1007@utils.register_interface(ExtensionType)
1008class InvalidityDate(object):
1009 oid = CRLEntryExtensionOID.INVALIDITY_DATE
1010
1011 def __init__(self, invalidity_date):
1012 if not isinstance(invalidity_date, datetime.datetime):
1013 raise TypeError("invalidity_date must be a datetime.datetime")
1014
1015 self._invalidity_date = invalidity_date
1016
1017 def __repr__(self):
1018 return "<InvalidityDate(invalidity_date={0})>".format(
1019 self._invalidity_date
1020 )
1021
1022 def __eq__(self, other):
1023 if not isinstance(other, InvalidityDate):
1024 return NotImplemented
1025
1026 return self.invalidity_date == other.invalidity_date
1027
1028 def __ne__(self, other):
1029 return not self == other
1030
1031 invalidity_date = utils.read_only_property("_invalidity_date")