1# 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
7import abc
8import datetime
9import hashlib
10import ipaddress
11from enum import Enum
12
13import six
14
15from cryptography import utils
16from cryptography.hazmat._der import (
17    BIT_STRING,
18    DERReader,
19    OBJECT_IDENTIFIER,
20    SEQUENCE,
21)
22from cryptography.hazmat.primitives import constant_time, serialization
23from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
24from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
25from cryptography.x509.certificate_transparency import (
26    SignedCertificateTimestamp,
27)
28from cryptography.x509.general_name import GeneralName, IPAddress, OtherName
29from cryptography.x509.name import RelativeDistinguishedName
30from cryptography.x509.oid import (
31    CRLEntryExtensionOID,
32    ExtensionOID,
33    OCSPExtensionOID,
34    ObjectIdentifier,
35)
36
37
38def _key_identifier_from_public_key(public_key):
39    if isinstance(public_key, RSAPublicKey):
40        data = public_key.public_bytes(
41            serialization.Encoding.DER,
42            serialization.PublicFormat.PKCS1,
43        )
44    elif isinstance(public_key, EllipticCurvePublicKey):
45        data = public_key.public_bytes(
46            serialization.Encoding.X962,
47            serialization.PublicFormat.UncompressedPoint,
48        )
49    else:
50        # This is a very slow way to do this.
51        serialized = public_key.public_bytes(
52            serialization.Encoding.DER,
53            serialization.PublicFormat.SubjectPublicKeyInfo,
54        )
55
56        reader = DERReader(serialized)
57        with reader.read_single_element(SEQUENCE) as public_key_info:
58            algorithm = public_key_info.read_element(SEQUENCE)
59            public_key = public_key_info.read_element(BIT_STRING)
60
61        # Double-check the algorithm structure.
62        with algorithm:
63            algorithm.read_element(OBJECT_IDENTIFIER)
64            if not algorithm.is_empty():
65                # Skip the optional parameters field.
66                algorithm.read_any_element()
67
68        # BIT STRING contents begin with the number of padding bytes added. It
69        # must be zero for SubjectPublicKeyInfo structures.
70        if public_key.read_byte() != 0:
71            raise ValueError("Invalid public key encoding")
72
73        data = public_key.data
74
75    return hashlib.sha1(data).digest()
76
77
78def _make_sequence_methods(field_name):
79    def len_method(self):
80        return len(getattr(self, field_name))
81
82    def iter_method(self):
83        return iter(getattr(self, field_name))
84
85    def getitem_method(self, idx):
86        return getattr(self, field_name)[idx]
87
88    return len_method, iter_method, getitem_method
89
90
91class DuplicateExtension(Exception):
92    def __init__(self, msg, oid):
93        super(DuplicateExtension, self).__init__(msg)
94        self.oid = oid
95
96
97class ExtensionNotFound(Exception):
98    def __init__(self, msg, oid):
99        super(ExtensionNotFound, self).__init__(msg)
100        self.oid = oid
101
102
103@six.add_metaclass(abc.ABCMeta)
104class ExtensionType(object):
105    @abc.abstractproperty
106    def oid(self):
107        """
108        Returns the oid associated with the given extension type.
109        """
110
111
112class Extensions(object):
113    def __init__(self, extensions):
114        self._extensions = extensions
115
116    def get_extension_for_oid(self, oid):
117        for ext in self:
118            if ext.oid == oid:
119                return ext
120
121        raise ExtensionNotFound("No {} extension was found".format(oid), oid)
122
123    def get_extension_for_class(self, extclass):
124        if extclass is UnrecognizedExtension:
125            raise TypeError(
126                "UnrecognizedExtension can't be used with "
127                "get_extension_for_class because more than one instance of the"
128                " class may be present."
129            )
130
131        for ext in self:
132            if isinstance(ext.value, extclass):
133                return ext
134
135        raise ExtensionNotFound(
136            "No {} extension was found".format(extclass), extclass.oid
137        )
138
139    __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions")
140
141    def __repr__(self):
142        return "<Extensions({})>".format(self._extensions)
143
144
145@utils.register_interface(ExtensionType)
146class CRLNumber(object):
147    oid = ExtensionOID.CRL_NUMBER
148
149    def __init__(self, crl_number):
150        if not isinstance(crl_number, six.integer_types):
151            raise TypeError("crl_number must be an integer")
152
153        self._crl_number = crl_number
154
155    def __eq__(self, other):
156        if not isinstance(other, CRLNumber):
157            return NotImplemented
158
159        return self.crl_number == other.crl_number
160
161    def __ne__(self, other):
162        return not self == other
163
164    def __hash__(self):
165        return hash(self.crl_number)
166
167    def __repr__(self):
168        return "<CRLNumber({})>".format(self.crl_number)
169
170    crl_number = utils.read_only_property("_crl_number")
171
172
173@utils.register_interface(ExtensionType)
174class AuthorityKeyIdentifier(object):
175    oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER
176
177    def __init__(
178        self,
179        key_identifier,
180        authority_cert_issuer,
181        authority_cert_serial_number,
182    ):
183        if (authority_cert_issuer is None) != (
184            authority_cert_serial_number is None
185        ):
186            raise ValueError(
187                "authority_cert_issuer and authority_cert_serial_number "
188                "must both be present or both None"
189            )
190
191        if authority_cert_issuer is not None:
192            authority_cert_issuer = list(authority_cert_issuer)
193            if not all(
194                isinstance(x, GeneralName) for x in authority_cert_issuer
195            ):
196                raise TypeError(
197                    "authority_cert_issuer must be a list of GeneralName "
198                    "objects"
199                )
200
201        if authority_cert_serial_number is not None and not isinstance(
202            authority_cert_serial_number, six.integer_types
203        ):
204            raise TypeError("authority_cert_serial_number must be an integer")
205
206        self._key_identifier = key_identifier
207        self._authority_cert_issuer = authority_cert_issuer
208        self._authority_cert_serial_number = authority_cert_serial_number
209
210    @classmethod
211    def from_issuer_public_key(cls, public_key):
212        digest = _key_identifier_from_public_key(public_key)
213        return cls(
214            key_identifier=digest,
215            authority_cert_issuer=None,
216            authority_cert_serial_number=None,
217        )
218
219    @classmethod
220    def from_issuer_subject_key_identifier(cls, ski):
221        return cls(
222            key_identifier=ski.digest,
223            authority_cert_issuer=None,
224            authority_cert_serial_number=None,
225        )
226
227    def __repr__(self):
228        return (
229            "<AuthorityKeyIdentifier(key_identifier={0.key_identifier!r}, "
230            "authority_cert_issuer={0.authority_cert_issuer}, "
231            "authority_cert_serial_number={0.authority_cert_serial_number}"
232            ")>".format(self)
233        )
234
235    def __eq__(self, other):
236        if not isinstance(other, AuthorityKeyIdentifier):
237            return NotImplemented
238
239        return (
240            self.key_identifier == other.key_identifier
241            and self.authority_cert_issuer == other.authority_cert_issuer
242            and self.authority_cert_serial_number
243            == other.authority_cert_serial_number
244        )
245
246    def __ne__(self, other):
247        return not self == other
248
249    def __hash__(self):
250        if self.authority_cert_issuer is None:
251            aci = None
252        else:
253            aci = tuple(self.authority_cert_issuer)
254        return hash(
255            (self.key_identifier, aci, self.authority_cert_serial_number)
256        )
257
258    key_identifier = utils.read_only_property("_key_identifier")
259    authority_cert_issuer = utils.read_only_property("_authority_cert_issuer")
260    authority_cert_serial_number = utils.read_only_property(
261        "_authority_cert_serial_number"
262    )
263
264
265@utils.register_interface(ExtensionType)
266class SubjectKeyIdentifier(object):
267    oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER
268
269    def __init__(self, digest):
270        self._digest = digest
271
272    @classmethod
273    def from_public_key(cls, public_key):
274        return cls(_key_identifier_from_public_key(public_key))
275
276    digest = utils.read_only_property("_digest")
277
278    def __repr__(self):
279        return "<SubjectKeyIdentifier(digest={0!r})>".format(self.digest)
280
281    def __eq__(self, other):
282        if not isinstance(other, SubjectKeyIdentifier):
283            return NotImplemented
284
285        return constant_time.bytes_eq(self.digest, other.digest)
286
287    def __ne__(self, other):
288        return not self == other
289
290    def __hash__(self):
291        return hash(self.digest)
292
293
294@utils.register_interface(ExtensionType)
295class AuthorityInformationAccess(object):
296    oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS
297
298    def __init__(self, descriptions):
299        descriptions = list(descriptions)
300        if not all(isinstance(x, AccessDescription) for x in descriptions):
301            raise TypeError(
302                "Every item in the descriptions list must be an "
303                "AccessDescription"
304            )
305
306        self._descriptions = descriptions
307
308    __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions")
309
310    def __repr__(self):
311        return "<AuthorityInformationAccess({})>".format(self._descriptions)
312
313    def __eq__(self, other):
314        if not isinstance(other, AuthorityInformationAccess):
315            return NotImplemented
316
317        return self._descriptions == other._descriptions
318
319    def __ne__(self, other):
320        return not self == other
321
322    def __hash__(self):
323        return hash(tuple(self._descriptions))
324
325
326@utils.register_interface(ExtensionType)
327class SubjectInformationAccess(object):
328    oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS
329
330    def __init__(self, descriptions):
331        descriptions = list(descriptions)
332        if not all(isinstance(x, AccessDescription) for x in descriptions):
333            raise TypeError(
334                "Every item in the descriptions list must be an "
335                "AccessDescription"
336            )
337
338        self._descriptions = descriptions
339
340    __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions")
341
342    def __repr__(self):
343        return "<SubjectInformationAccess({})>".format(self._descriptions)
344
345    def __eq__(self, other):
346        if not isinstance(other, SubjectInformationAccess):
347            return NotImplemented
348
349        return self._descriptions == other._descriptions
350
351    def __ne__(self, other):
352        return not self == other
353
354    def __hash__(self):
355        return hash(tuple(self._descriptions))
356
357
358class AccessDescription(object):
359    def __init__(self, access_method, access_location):
360        if not isinstance(access_method, ObjectIdentifier):
361            raise TypeError("access_method must be an ObjectIdentifier")
362
363        if not isinstance(access_location, GeneralName):
364            raise TypeError("access_location must be a GeneralName")
365
366        self._access_method = access_method
367        self._access_location = access_location
368
369    def __repr__(self):
370        return (
371            "<AccessDescription(access_method={0.access_method}, access_locati"
372            "on={0.access_location})>".format(self)
373        )
374
375    def __eq__(self, other):
376        if not isinstance(other, AccessDescription):
377            return NotImplemented
378
379        return (
380            self.access_method == other.access_method
381            and self.access_location == other.access_location
382        )
383
384    def __ne__(self, other):
385        return not self == other
386
387    def __hash__(self):
388        return hash((self.access_method, self.access_location))
389
390    access_method = utils.read_only_property("_access_method")
391    access_location = utils.read_only_property("_access_location")
392
393
394@utils.register_interface(ExtensionType)
395class BasicConstraints(object):
396    oid = ExtensionOID.BASIC_CONSTRAINTS
397
398    def __init__(self, ca, path_length):
399        if not isinstance(ca, bool):
400            raise TypeError("ca must be a boolean value")
401
402        if path_length is not None and not ca:
403            raise ValueError("path_length must be None when ca is False")
404
405        if path_length is not None and (
406            not isinstance(path_length, six.integer_types) or path_length < 0
407        ):
408            raise TypeError(
409                "path_length must be a non-negative integer or None"
410            )
411
412        self._ca = ca
413        self._path_length = path_length
414
415    ca = utils.read_only_property("_ca")
416    path_length = utils.read_only_property("_path_length")
417
418    def __repr__(self):
419        return (
420            "<BasicConstraints(ca={0.ca}, " "path_length={0.path_length})>"
421        ).format(self)
422
423    def __eq__(self, other):
424        if not isinstance(other, BasicConstraints):
425            return NotImplemented
426
427        return self.ca == other.ca and self.path_length == other.path_length
428
429    def __ne__(self, other):
430        return not self == other
431
432    def __hash__(self):
433        return hash((self.ca, self.path_length))
434
435
436@utils.register_interface(ExtensionType)
437class DeltaCRLIndicator(object):
438    oid = ExtensionOID.DELTA_CRL_INDICATOR
439
440    def __init__(self, crl_number):
441        if not isinstance(crl_number, six.integer_types):
442            raise TypeError("crl_number must be an integer")
443
444        self._crl_number = crl_number
445
446    crl_number = utils.read_only_property("_crl_number")
447
448    def __eq__(self, other):
449        if not isinstance(other, DeltaCRLIndicator):
450            return NotImplemented
451
452        return self.crl_number == other.crl_number
453
454    def __ne__(self, other):
455        return not self == other
456
457    def __hash__(self):
458        return hash(self.crl_number)
459
460    def __repr__(self):
461        return "<DeltaCRLIndicator(crl_number={0.crl_number})>".format(self)
462
463
464@utils.register_interface(ExtensionType)
465class CRLDistributionPoints(object):
466    oid = ExtensionOID.CRL_DISTRIBUTION_POINTS
467
468    def __init__(self, distribution_points):
469        distribution_points = list(distribution_points)
470        if not all(
471            isinstance(x, DistributionPoint) for x in distribution_points
472        ):
473            raise TypeError(
474                "distribution_points must be a list of DistributionPoint "
475                "objects"
476            )
477
478        self._distribution_points = distribution_points
479
480    __len__, __iter__, __getitem__ = _make_sequence_methods(
481        "_distribution_points"
482    )
483
484    def __repr__(self):
485        return "<CRLDistributionPoints({})>".format(self._distribution_points)
486
487    def __eq__(self, other):
488        if not isinstance(other, CRLDistributionPoints):
489            return NotImplemented
490
491        return self._distribution_points == other._distribution_points
492
493    def __ne__(self, other):
494        return not self == other
495
496    def __hash__(self):
497        return hash(tuple(self._distribution_points))
498
499
500@utils.register_interface(ExtensionType)
501class FreshestCRL(object):
502    oid = ExtensionOID.FRESHEST_CRL
503
504    def __init__(self, distribution_points):
505        distribution_points = list(distribution_points)
506        if not all(
507            isinstance(x, DistributionPoint) for x in distribution_points
508        ):
509            raise TypeError(
510                "distribution_points must be a list of DistributionPoint "
511                "objects"
512            )
513
514        self._distribution_points = distribution_points
515
516    __len__, __iter__, __getitem__ = _make_sequence_methods(
517        "_distribution_points"
518    )
519
520    def __repr__(self):
521        return "<FreshestCRL({})>".format(self._distribution_points)
522
523    def __eq__(self, other):
524        if not isinstance(other, FreshestCRL):
525            return NotImplemented
526
527        return self._distribution_points == other._distribution_points
528
529    def __ne__(self, other):
530        return not self == other
531
532    def __hash__(self):
533        return hash(tuple(self._distribution_points))
534
535
536class DistributionPoint(object):
537    def __init__(self, full_name, relative_name, reasons, crl_issuer):
538        if full_name and relative_name:
539            raise ValueError(
540                "You cannot provide both full_name and relative_name, at "
541                "least one must be None."
542            )
543
544        if full_name:
545            full_name = list(full_name)
546            if not all(isinstance(x, GeneralName) for x in full_name):
547                raise TypeError(
548                    "full_name must be a list of GeneralName objects"
549                )
550
551        if relative_name:
552            if not isinstance(relative_name, RelativeDistinguishedName):
553                raise TypeError(
554                    "relative_name must be a RelativeDistinguishedName"
555                )
556
557        if crl_issuer:
558            crl_issuer = list(crl_issuer)
559            if not all(isinstance(x, GeneralName) for x in crl_issuer):
560                raise TypeError(
561                    "crl_issuer must be None or a list of general names"
562                )
563
564        if reasons and (
565            not isinstance(reasons, frozenset)
566            or not all(isinstance(x, ReasonFlags) for x in reasons)
567        ):
568            raise TypeError("reasons must be None or frozenset of ReasonFlags")
569
570        if reasons and (
571            ReasonFlags.unspecified in reasons
572            or ReasonFlags.remove_from_crl in reasons
573        ):
574            raise ValueError(
575                "unspecified and remove_from_crl are not valid reasons in a "
576                "DistributionPoint"
577            )
578
579        if reasons and not crl_issuer and not (full_name or relative_name):
580            raise ValueError(
581                "You must supply crl_issuer, full_name, or relative_name when "
582                "reasons is not None"
583            )
584
585        self._full_name = full_name
586        self._relative_name = relative_name
587        self._reasons = reasons
588        self._crl_issuer = crl_issuer
589
590    def __repr__(self):
591        return (
592            "<DistributionPoint(full_name={0.full_name}, relative_name={0.rela"
593            "tive_name}, reasons={0.reasons}, "
594            "crl_issuer={0.crl_issuer})>".format(self)
595        )
596
597    def __eq__(self, other):
598        if not isinstance(other, DistributionPoint):
599            return NotImplemented
600
601        return (
602            self.full_name == other.full_name
603            and self.relative_name == other.relative_name
604            and self.reasons == other.reasons
605            and self.crl_issuer == other.crl_issuer
606        )
607
608    def __ne__(self, other):
609        return not self == other
610
611    def __hash__(self):
612        if self.full_name is not None:
613            fn = tuple(self.full_name)
614        else:
615            fn = None
616
617        if self.crl_issuer is not None:
618            crl_issuer = tuple(self.crl_issuer)
619        else:
620            crl_issuer = None
621
622        return hash((fn, self.relative_name, self.reasons, crl_issuer))
623
624    full_name = utils.read_only_property("_full_name")
625    relative_name = utils.read_only_property("_relative_name")
626    reasons = utils.read_only_property("_reasons")
627    crl_issuer = utils.read_only_property("_crl_issuer")
628
629
630class ReasonFlags(Enum):
631    unspecified = "unspecified"
632    key_compromise = "keyCompromise"
633    ca_compromise = "cACompromise"
634    affiliation_changed = "affiliationChanged"
635    superseded = "superseded"
636    cessation_of_operation = "cessationOfOperation"
637    certificate_hold = "certificateHold"
638    privilege_withdrawn = "privilegeWithdrawn"
639    aa_compromise = "aACompromise"
640    remove_from_crl = "removeFromCRL"
641
642
643@utils.register_interface(ExtensionType)
644class PolicyConstraints(object):
645    oid = ExtensionOID.POLICY_CONSTRAINTS
646
647    def __init__(self, require_explicit_policy, inhibit_policy_mapping):
648        if require_explicit_policy is not None and not isinstance(
649            require_explicit_policy, six.integer_types
650        ):
651            raise TypeError(
652                "require_explicit_policy must be a non-negative integer or "
653                "None"
654            )
655
656        if inhibit_policy_mapping is not None and not isinstance(
657            inhibit_policy_mapping, six.integer_types
658        ):
659            raise TypeError(
660                "inhibit_policy_mapping must be a non-negative integer or None"
661            )
662
663        if inhibit_policy_mapping is None and require_explicit_policy is None:
664            raise ValueError(
665                "At least one of require_explicit_policy and "
666                "inhibit_policy_mapping must not be None"
667            )
668
669        self._require_explicit_policy = require_explicit_policy
670        self._inhibit_policy_mapping = inhibit_policy_mapping
671
672    def __repr__(self):
673        return (
674            u"<PolicyConstraints(require_explicit_policy={0.require_explicit"
675            u"_policy}, inhibit_policy_mapping={0.inhibit_policy_"
676            u"mapping})>".format(self)
677        )
678
679    def __eq__(self, other):
680        if not isinstance(other, PolicyConstraints):
681            return NotImplemented
682
683        return (
684            self.require_explicit_policy == other.require_explicit_policy
685            and self.inhibit_policy_mapping == other.inhibit_policy_mapping
686        )
687
688    def __ne__(self, other):
689        return not self == other
690
691    def __hash__(self):
692        return hash(
693            (self.require_explicit_policy, self.inhibit_policy_mapping)
694        )
695
696    require_explicit_policy = utils.read_only_property(
697        "_require_explicit_policy"
698    )
699    inhibit_policy_mapping = utils.read_only_property(
700        "_inhibit_policy_mapping"
701    )
702
703
704@utils.register_interface(ExtensionType)
705class CertificatePolicies(object):
706    oid = ExtensionOID.CERTIFICATE_POLICIES
707
708    def __init__(self, policies):
709        policies = list(policies)
710        if not all(isinstance(x, PolicyInformation) for x in policies):
711            raise TypeError(
712                "Every item in the policies list must be a "
713                "PolicyInformation"
714            )
715
716        self._policies = policies
717
718    __len__, __iter__, __getitem__ = _make_sequence_methods("_policies")
719
720    def __repr__(self):
721        return "<CertificatePolicies({})>".format(self._policies)
722
723    def __eq__(self, other):
724        if not isinstance(other, CertificatePolicies):
725            return NotImplemented
726
727        return self._policies == other._policies
728
729    def __ne__(self, other):
730        return not self == other
731
732    def __hash__(self):
733        return hash(tuple(self._policies))
734
735
736class PolicyInformation(object):
737    def __init__(self, policy_identifier, policy_qualifiers):
738        if not isinstance(policy_identifier, ObjectIdentifier):
739            raise TypeError("policy_identifier must be an ObjectIdentifier")
740
741        self._policy_identifier = policy_identifier
742
743        if policy_qualifiers:
744            policy_qualifiers = list(policy_qualifiers)
745            if not all(
746                isinstance(x, (six.text_type, UserNotice))
747                for x in policy_qualifiers
748            ):
749                raise TypeError(
750                    "policy_qualifiers must be a list of strings and/or "
751                    "UserNotice objects or None"
752                )
753
754        self._policy_qualifiers = policy_qualifiers
755
756    def __repr__(self):
757        return (
758            "<PolicyInformation(policy_identifier={0.policy_identifier}, polic"
759            "y_qualifiers={0.policy_qualifiers})>".format(self)
760        )
761
762    def __eq__(self, other):
763        if not isinstance(other, PolicyInformation):
764            return NotImplemented
765
766        return (
767            self.policy_identifier == other.policy_identifier
768            and self.policy_qualifiers == other.policy_qualifiers
769        )
770
771    def __ne__(self, other):
772        return not self == other
773
774    def __hash__(self):
775        if self.policy_qualifiers is not None:
776            pq = tuple(self.policy_qualifiers)
777        else:
778            pq = None
779
780        return hash((self.policy_identifier, pq))
781
782    policy_identifier = utils.read_only_property("_policy_identifier")
783    policy_qualifiers = utils.read_only_property("_policy_qualifiers")
784
785
786class UserNotice(object):
787    def __init__(self, notice_reference, explicit_text):
788        if notice_reference and not isinstance(
789            notice_reference, NoticeReference
790        ):
791            raise TypeError(
792                "notice_reference must be None or a NoticeReference"
793            )
794
795        self._notice_reference = notice_reference
796        self._explicit_text = explicit_text
797
798    def __repr__(self):
799        return (
800            "<UserNotice(notice_reference={0.notice_reference}, explicit_text="
801            "{0.explicit_text!r})>".format(self)
802        )
803
804    def __eq__(self, other):
805        if not isinstance(other, UserNotice):
806            return NotImplemented
807
808        return (
809            self.notice_reference == other.notice_reference
810            and self.explicit_text == other.explicit_text
811        )
812
813    def __ne__(self, other):
814        return not self == other
815
816    def __hash__(self):
817        return hash((self.notice_reference, self.explicit_text))
818
819    notice_reference = utils.read_only_property("_notice_reference")
820    explicit_text = utils.read_only_property("_explicit_text")
821
822
823class NoticeReference(object):
824    def __init__(self, organization, notice_numbers):
825        self._organization = organization
826        notice_numbers = list(notice_numbers)
827        if not all(isinstance(x, int) for x in notice_numbers):
828            raise TypeError("notice_numbers must be a list of integers")
829
830        self._notice_numbers = notice_numbers
831
832    def __repr__(self):
833        return (
834            "<NoticeReference(organization={0.organization!r}, notice_numbers="
835            "{0.notice_numbers})>".format(self)
836        )
837
838    def __eq__(self, other):
839        if not isinstance(other, NoticeReference):
840            return NotImplemented
841
842        return (
843            self.organization == other.organization
844            and self.notice_numbers == other.notice_numbers
845        )
846
847    def __ne__(self, other):
848        return not self == other
849
850    def __hash__(self):
851        return hash((self.organization, tuple(self.notice_numbers)))
852
853    organization = utils.read_only_property("_organization")
854    notice_numbers = utils.read_only_property("_notice_numbers")
855
856
857@utils.register_interface(ExtensionType)
858class ExtendedKeyUsage(object):
859    oid = ExtensionOID.EXTENDED_KEY_USAGE
860
861    def __init__(self, usages):
862        usages = list(usages)
863        if not all(isinstance(x, ObjectIdentifier) for x in usages):
864            raise TypeError(
865                "Every item in the usages list must be an ObjectIdentifier"
866            )
867
868        self._usages = usages
869
870    __len__, __iter__, __getitem__ = _make_sequence_methods("_usages")
871
872    def __repr__(self):
873        return "<ExtendedKeyUsage({})>".format(self._usages)
874
875    def __eq__(self, other):
876        if not isinstance(other, ExtendedKeyUsage):
877            return NotImplemented
878
879        return self._usages == other._usages
880
881    def __ne__(self, other):
882        return not self == other
883
884    def __hash__(self):
885        return hash(tuple(self._usages))
886
887
888@utils.register_interface(ExtensionType)
889class OCSPNoCheck(object):
890    oid = ExtensionOID.OCSP_NO_CHECK
891
892    def __eq__(self, other):
893        if not isinstance(other, OCSPNoCheck):
894            return NotImplemented
895
896        return True
897
898    def __ne__(self, other):
899        return not self == other
900
901    def __hash__(self):
902        return hash(OCSPNoCheck)
903
904    def __repr__(self):
905        return "<OCSPNoCheck()>"
906
907
908@utils.register_interface(ExtensionType)
909class PrecertPoison(object):
910    oid = ExtensionOID.PRECERT_POISON
911
912    def __eq__(self, other):
913        if not isinstance(other, PrecertPoison):
914            return NotImplemented
915
916        return True
917
918    def __ne__(self, other):
919        return not self == other
920
921    def __hash__(self):
922        return hash(PrecertPoison)
923
924    def __repr__(self):
925        return "<PrecertPoison()>"
926
927
928@utils.register_interface(ExtensionType)
929class TLSFeature(object):
930    oid = ExtensionOID.TLS_FEATURE
931
932    def __init__(self, features):
933        features = list(features)
934        if (
935            not all(isinstance(x, TLSFeatureType) for x in features)
936            or len(features) == 0
937        ):
938            raise TypeError(
939                "features must be a list of elements from the TLSFeatureType "
940                "enum"
941            )
942
943        self._features = features
944
945    __len__, __iter__, __getitem__ = _make_sequence_methods("_features")
946
947    def __repr__(self):
948        return "<TLSFeature(features={0._features})>".format(self)
949
950    def __eq__(self, other):
951        if not isinstance(other, TLSFeature):
952            return NotImplemented
953
954        return self._features == other._features
955
956    def __ne__(self, other):
957        return not self == other
958
959    def __hash__(self):
960        return hash(tuple(self._features))
961
962
963class TLSFeatureType(Enum):
964    # status_request is defined in RFC 6066 and is used for what is commonly
965    # called OCSP Must-Staple when present in the TLS Feature extension in an
966    # X.509 certificate.
967    status_request = 5
968    # status_request_v2 is defined in RFC 6961 and allows multiple OCSP
969    # responses to be provided. It is not currently in use by clients or
970    # servers.
971    status_request_v2 = 17
972
973
974_TLS_FEATURE_TYPE_TO_ENUM = {x.value: x for x in TLSFeatureType}
975
976
977@utils.register_interface(ExtensionType)
978class InhibitAnyPolicy(object):
979    oid = ExtensionOID.INHIBIT_ANY_POLICY
980
981    def __init__(self, skip_certs):
982        if not isinstance(skip_certs, six.integer_types):
983            raise TypeError("skip_certs must be an integer")
984
985        if skip_certs < 0:
986            raise ValueError("skip_certs must be a non-negative integer")
987
988        self._skip_certs = skip_certs
989
990    def __repr__(self):
991        return "<InhibitAnyPolicy(skip_certs={0.skip_certs})>".format(self)
992
993    def __eq__(self, other):
994        if not isinstance(other, InhibitAnyPolicy):
995            return NotImplemented
996
997        return self.skip_certs == other.skip_certs
998
999    def __ne__(self, other):
1000        return not self == other
1001
1002    def __hash__(self):
1003        return hash(self.skip_certs)
1004
1005    skip_certs = utils.read_only_property("_skip_certs")
1006
1007
1008@utils.register_interface(ExtensionType)
1009class KeyUsage(object):
1010    oid = ExtensionOID.KEY_USAGE
1011
1012    def __init__(
1013        self,
1014        digital_signature,
1015        content_commitment,
1016        key_encipherment,
1017        data_encipherment,
1018        key_agreement,
1019        key_cert_sign,
1020        crl_sign,
1021        encipher_only,
1022        decipher_only,
1023    ):
1024        if not key_agreement and (encipher_only or decipher_only):
1025            raise ValueError(
1026                "encipher_only and decipher_only can only be true when "
1027                "key_agreement is true"
1028            )
1029
1030        self._digital_signature = digital_signature
1031        self._content_commitment = content_commitment
1032        self._key_encipherment = key_encipherment
1033        self._data_encipherment = data_encipherment
1034        self._key_agreement = key_agreement
1035        self._key_cert_sign = key_cert_sign
1036        self._crl_sign = crl_sign
1037        self._encipher_only = encipher_only
1038        self._decipher_only = decipher_only
1039
1040    digital_signature = utils.read_only_property("_digital_signature")
1041    content_commitment = utils.read_only_property("_content_commitment")
1042    key_encipherment = utils.read_only_property("_key_encipherment")
1043    data_encipherment = utils.read_only_property("_data_encipherment")
1044    key_agreement = utils.read_only_property("_key_agreement")
1045    key_cert_sign = utils.read_only_property("_key_cert_sign")
1046    crl_sign = utils.read_only_property("_crl_sign")
1047
1048    @property
1049    def encipher_only(self):
1050        if not self.key_agreement:
1051            raise ValueError(
1052                "encipher_only is undefined unless key_agreement is true"
1053            )
1054        else:
1055            return self._encipher_only
1056
1057    @property
1058    def decipher_only(self):
1059        if not self.key_agreement:
1060            raise ValueError(
1061                "decipher_only is undefined unless key_agreement is true"
1062            )
1063        else:
1064            return self._decipher_only
1065
1066    def __repr__(self):
1067        try:
1068            encipher_only = self.encipher_only
1069            decipher_only = self.decipher_only
1070        except ValueError:
1071            # Users found None confusing because even though encipher/decipher
1072            # have no meaning unless key_agreement is true, to construct an
1073            # instance of the class you still need to pass False.
1074            encipher_only = False
1075            decipher_only = False
1076
1077        return (
1078            "<KeyUsage(digital_signature={0.digital_signature}, "
1079            "content_commitment={0.content_commitment}, "
1080            "key_encipherment={0.key_encipherment}, "
1081            "data_encipherment={0.data_encipherment}, "
1082            "key_agreement={0.key_agreement}, "
1083            "key_cert_sign={0.key_cert_sign}, crl_sign={0.crl_sign}, "
1084            "encipher_only={1}, decipher_only={2})>"
1085        ).format(self, encipher_only, decipher_only)
1086
1087    def __eq__(self, other):
1088        if not isinstance(other, KeyUsage):
1089            return NotImplemented
1090
1091        return (
1092            self.digital_signature == other.digital_signature
1093            and self.content_commitment == other.content_commitment
1094            and self.key_encipherment == other.key_encipherment
1095            and self.data_encipherment == other.data_encipherment
1096            and self.key_agreement == other.key_agreement
1097            and self.key_cert_sign == other.key_cert_sign
1098            and self.crl_sign == other.crl_sign
1099            and self._encipher_only == other._encipher_only
1100            and self._decipher_only == other._decipher_only
1101        )
1102
1103    def __ne__(self, other):
1104        return not self == other
1105
1106    def __hash__(self):
1107        return hash(
1108            (
1109                self.digital_signature,
1110                self.content_commitment,
1111                self.key_encipherment,
1112                self.data_encipherment,
1113                self.key_agreement,
1114                self.key_cert_sign,
1115                self.crl_sign,
1116                self._encipher_only,
1117                self._decipher_only,
1118            )
1119        )
1120
1121
1122@utils.register_interface(ExtensionType)
1123class NameConstraints(object):
1124    oid = ExtensionOID.NAME_CONSTRAINTS
1125
1126    def __init__(self, permitted_subtrees, excluded_subtrees):
1127        if permitted_subtrees is not None:
1128            permitted_subtrees = list(permitted_subtrees)
1129            if not all(isinstance(x, GeneralName) for x in permitted_subtrees):
1130                raise TypeError(
1131                    "permitted_subtrees must be a list of GeneralName objects "
1132                    "or None"
1133                )
1134
1135            self._validate_ip_name(permitted_subtrees)
1136
1137        if excluded_subtrees is not None:
1138            excluded_subtrees = list(excluded_subtrees)
1139            if not all(isinstance(x, GeneralName) for x in excluded_subtrees):
1140                raise TypeError(
1141                    "excluded_subtrees must be a list of GeneralName objects "
1142                    "or None"
1143                )
1144
1145            self._validate_ip_name(excluded_subtrees)
1146
1147        if permitted_subtrees is None and excluded_subtrees is None:
1148            raise ValueError(
1149                "At least one of permitted_subtrees and excluded_subtrees "
1150                "must not be None"
1151            )
1152
1153        self._permitted_subtrees = permitted_subtrees
1154        self._excluded_subtrees = excluded_subtrees
1155
1156    def __eq__(self, other):
1157        if not isinstance(other, NameConstraints):
1158            return NotImplemented
1159
1160        return (
1161            self.excluded_subtrees == other.excluded_subtrees
1162            and self.permitted_subtrees == other.permitted_subtrees
1163        )
1164
1165    def __ne__(self, other):
1166        return not self == other
1167
1168    def _validate_ip_name(self, tree):
1169        if any(
1170            isinstance(name, IPAddress)
1171            and not isinstance(
1172                name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network)
1173            )
1174            for name in tree
1175        ):
1176            raise TypeError(
1177                "IPAddress name constraints must be an IPv4Network or"
1178                " IPv6Network object"
1179            )
1180
1181    def __repr__(self):
1182        return (
1183            u"<NameConstraints(permitted_subtrees={0.permitted_subtrees}, "
1184            u"excluded_subtrees={0.excluded_subtrees})>".format(self)
1185        )
1186
1187    def __hash__(self):
1188        if self.permitted_subtrees is not None:
1189            ps = tuple(self.permitted_subtrees)
1190        else:
1191            ps = None
1192
1193        if self.excluded_subtrees is not None:
1194            es = tuple(self.excluded_subtrees)
1195        else:
1196            es = None
1197
1198        return hash((ps, es))
1199
1200    permitted_subtrees = utils.read_only_property("_permitted_subtrees")
1201    excluded_subtrees = utils.read_only_property("_excluded_subtrees")
1202
1203
1204class Extension(object):
1205    def __init__(self, oid, critical, value):
1206        if not isinstance(oid, ObjectIdentifier):
1207            raise TypeError(
1208                "oid argument must be an ObjectIdentifier instance."
1209            )
1210
1211        if not isinstance(critical, bool):
1212            raise TypeError("critical must be a boolean value")
1213
1214        self._oid = oid
1215        self._critical = critical
1216        self._value = value
1217
1218    oid = utils.read_only_property("_oid")
1219    critical = utils.read_only_property("_critical")
1220    value = utils.read_only_property("_value")
1221
1222    def __repr__(self):
1223        return (
1224            "<Extension(oid={0.oid}, critical={0.critical}, "
1225            "value={0.value})>"
1226        ).format(self)
1227
1228    def __eq__(self, other):
1229        if not isinstance(other, Extension):
1230            return NotImplemented
1231
1232        return (
1233            self.oid == other.oid
1234            and self.critical == other.critical
1235            and self.value == other.value
1236        )
1237
1238    def __ne__(self, other):
1239        return not self == other
1240
1241    def __hash__(self):
1242        return hash((self.oid, self.critical, self.value))
1243
1244
1245class GeneralNames(object):
1246    def __init__(self, general_names):
1247        general_names = list(general_names)
1248        if not all(isinstance(x, GeneralName) for x in general_names):
1249            raise TypeError(
1250                "Every item in the general_names list must be an "
1251                "object conforming to the GeneralName interface"
1252            )
1253
1254        self._general_names = general_names
1255
1256    __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1257
1258    def get_values_for_type(self, type):
1259        # Return the value of each GeneralName, except for OtherName instances
1260        # which we return directly because it has two important properties not
1261        # just one value.
1262        objs = (i for i in self if isinstance(i, type))
1263        if type != OtherName:
1264            objs = (i.value for i in objs)
1265        return list(objs)
1266
1267    def __repr__(self):
1268        return "<GeneralNames({})>".format(self._general_names)
1269
1270    def __eq__(self, other):
1271        if not isinstance(other, GeneralNames):
1272            return NotImplemented
1273
1274        return self._general_names == other._general_names
1275
1276    def __ne__(self, other):
1277        return not self == other
1278
1279    def __hash__(self):
1280        return hash(tuple(self._general_names))
1281
1282
1283@utils.register_interface(ExtensionType)
1284class SubjectAlternativeName(object):
1285    oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME
1286
1287    def __init__(self, general_names):
1288        self._general_names = GeneralNames(general_names)
1289
1290    __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1291
1292    def get_values_for_type(self, type):
1293        return self._general_names.get_values_for_type(type)
1294
1295    def __repr__(self):
1296        return "<SubjectAlternativeName({})>".format(self._general_names)
1297
1298    def __eq__(self, other):
1299        if not isinstance(other, SubjectAlternativeName):
1300            return NotImplemented
1301
1302        return self._general_names == other._general_names
1303
1304    def __ne__(self, other):
1305        return not self == other
1306
1307    def __hash__(self):
1308        return hash(self._general_names)
1309
1310
1311@utils.register_interface(ExtensionType)
1312class IssuerAlternativeName(object):
1313    oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME
1314
1315    def __init__(self, general_names):
1316        self._general_names = GeneralNames(general_names)
1317
1318    __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1319
1320    def get_values_for_type(self, type):
1321        return self._general_names.get_values_for_type(type)
1322
1323    def __repr__(self):
1324        return "<IssuerAlternativeName({})>".format(self._general_names)
1325
1326    def __eq__(self, other):
1327        if not isinstance(other, IssuerAlternativeName):
1328            return NotImplemented
1329
1330        return self._general_names == other._general_names
1331
1332    def __ne__(self, other):
1333        return not self == other
1334
1335    def __hash__(self):
1336        return hash(self._general_names)
1337
1338
1339@utils.register_interface(ExtensionType)
1340class CertificateIssuer(object):
1341    oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER
1342
1343    def __init__(self, general_names):
1344        self._general_names = GeneralNames(general_names)
1345
1346    __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1347
1348    def get_values_for_type(self, type):
1349        return self._general_names.get_values_for_type(type)
1350
1351    def __repr__(self):
1352        return "<CertificateIssuer({})>".format(self._general_names)
1353
1354    def __eq__(self, other):
1355        if not isinstance(other, CertificateIssuer):
1356            return NotImplemented
1357
1358        return self._general_names == other._general_names
1359
1360    def __ne__(self, other):
1361        return not self == other
1362
1363    def __hash__(self):
1364        return hash(self._general_names)
1365
1366
1367@utils.register_interface(ExtensionType)
1368class CRLReason(object):
1369    oid = CRLEntryExtensionOID.CRL_REASON
1370
1371    def __init__(self, reason):
1372        if not isinstance(reason, ReasonFlags):
1373            raise TypeError("reason must be an element from ReasonFlags")
1374
1375        self._reason = reason
1376
1377    def __repr__(self):
1378        return "<CRLReason(reason={})>".format(self._reason)
1379
1380    def __eq__(self, other):
1381        if not isinstance(other, CRLReason):
1382            return NotImplemented
1383
1384        return self.reason == other.reason
1385
1386    def __ne__(self, other):
1387        return not self == other
1388
1389    def __hash__(self):
1390        return hash(self.reason)
1391
1392    reason = utils.read_only_property("_reason")
1393
1394
1395@utils.register_interface(ExtensionType)
1396class InvalidityDate(object):
1397    oid = CRLEntryExtensionOID.INVALIDITY_DATE
1398
1399    def __init__(self, invalidity_date):
1400        if not isinstance(invalidity_date, datetime.datetime):
1401            raise TypeError("invalidity_date must be a datetime.datetime")
1402
1403        self._invalidity_date = invalidity_date
1404
1405    def __repr__(self):
1406        return "<InvalidityDate(invalidity_date={})>".format(
1407            self._invalidity_date
1408        )
1409
1410    def __eq__(self, other):
1411        if not isinstance(other, InvalidityDate):
1412            return NotImplemented
1413
1414        return self.invalidity_date == other.invalidity_date
1415
1416    def __ne__(self, other):
1417        return not self == other
1418
1419    def __hash__(self):
1420        return hash(self.invalidity_date)
1421
1422    invalidity_date = utils.read_only_property("_invalidity_date")
1423
1424
1425@utils.register_interface(ExtensionType)
1426class PrecertificateSignedCertificateTimestamps(object):
1427    oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS
1428
1429    def __init__(self, signed_certificate_timestamps):
1430        signed_certificate_timestamps = list(signed_certificate_timestamps)
1431        if not all(
1432            isinstance(sct, SignedCertificateTimestamp)
1433            for sct in signed_certificate_timestamps
1434        ):
1435            raise TypeError(
1436                "Every item in the signed_certificate_timestamps list must be "
1437                "a SignedCertificateTimestamp"
1438            )
1439        self._signed_certificate_timestamps = signed_certificate_timestamps
1440
1441    __len__, __iter__, __getitem__ = _make_sequence_methods(
1442        "_signed_certificate_timestamps"
1443    )
1444
1445    def __repr__(self):
1446        return "<PrecertificateSignedCertificateTimestamps({})>".format(
1447            list(self)
1448        )
1449
1450    def __hash__(self):
1451        return hash(tuple(self._signed_certificate_timestamps))
1452
1453    def __eq__(self, other):
1454        if not isinstance(other, PrecertificateSignedCertificateTimestamps):
1455            return NotImplemented
1456
1457        return (
1458            self._signed_certificate_timestamps
1459            == other._signed_certificate_timestamps
1460        )
1461
1462    def __ne__(self, other):
1463        return not self == other
1464
1465
1466@utils.register_interface(ExtensionType)
1467class SignedCertificateTimestamps(object):
1468    oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS
1469
1470    def __init__(self, signed_certificate_timestamps):
1471        signed_certificate_timestamps = list(signed_certificate_timestamps)
1472        if not all(
1473            isinstance(sct, SignedCertificateTimestamp)
1474            for sct in signed_certificate_timestamps
1475        ):
1476            raise TypeError(
1477                "Every item in the signed_certificate_timestamps list must be "
1478                "a SignedCertificateTimestamp"
1479            )
1480        self._signed_certificate_timestamps = signed_certificate_timestamps
1481
1482    __len__, __iter__, __getitem__ = _make_sequence_methods(
1483        "_signed_certificate_timestamps"
1484    )
1485
1486    def __repr__(self):
1487        return "<SignedCertificateTimestamps({})>".format(list(self))
1488
1489    def __hash__(self):
1490        return hash(tuple(self._signed_certificate_timestamps))
1491
1492    def __eq__(self, other):
1493        if not isinstance(other, SignedCertificateTimestamps):
1494            return NotImplemented
1495
1496        return (
1497            self._signed_certificate_timestamps
1498            == other._signed_certificate_timestamps
1499        )
1500
1501    def __ne__(self, other):
1502        return not self == other
1503
1504
1505@utils.register_interface(ExtensionType)
1506class OCSPNonce(object):
1507    oid = OCSPExtensionOID.NONCE
1508
1509    def __init__(self, nonce):
1510        if not isinstance(nonce, bytes):
1511            raise TypeError("nonce must be bytes")
1512
1513        self._nonce = nonce
1514
1515    def __eq__(self, other):
1516        if not isinstance(other, OCSPNonce):
1517            return NotImplemented
1518
1519        return self.nonce == other.nonce
1520
1521    def __ne__(self, other):
1522        return not self == other
1523
1524    def __hash__(self):
1525        return hash(self.nonce)
1526
1527    def __repr__(self):
1528        return "<OCSPNonce(nonce={0.nonce!r})>".format(self)
1529
1530    nonce = utils.read_only_property("_nonce")
1531
1532
1533@utils.register_interface(ExtensionType)
1534class IssuingDistributionPoint(object):
1535    oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT
1536
1537    def __init__(
1538        self,
1539        full_name,
1540        relative_name,
1541        only_contains_user_certs,
1542        only_contains_ca_certs,
1543        only_some_reasons,
1544        indirect_crl,
1545        only_contains_attribute_certs,
1546    ):
1547        if only_some_reasons and (
1548            not isinstance(only_some_reasons, frozenset)
1549            or not all(isinstance(x, ReasonFlags) for x in only_some_reasons)
1550        ):
1551            raise TypeError(
1552                "only_some_reasons must be None or frozenset of ReasonFlags"
1553            )
1554
1555        if only_some_reasons and (
1556            ReasonFlags.unspecified in only_some_reasons
1557            or ReasonFlags.remove_from_crl in only_some_reasons
1558        ):
1559            raise ValueError(
1560                "unspecified and remove_from_crl are not valid reasons in an "
1561                "IssuingDistributionPoint"
1562            )
1563
1564        if not (
1565            isinstance(only_contains_user_certs, bool)
1566            and isinstance(only_contains_ca_certs, bool)
1567            and isinstance(indirect_crl, bool)
1568            and isinstance(only_contains_attribute_certs, bool)
1569        ):
1570            raise TypeError(
1571                "only_contains_user_certs, only_contains_ca_certs, "
1572                "indirect_crl and only_contains_attribute_certs "
1573                "must all be boolean."
1574            )
1575
1576        crl_constraints = [
1577            only_contains_user_certs,
1578            only_contains_ca_certs,
1579            indirect_crl,
1580            only_contains_attribute_certs,
1581        ]
1582
1583        if len([x for x in crl_constraints if x]) > 1:
1584            raise ValueError(
1585                "Only one of the following can be set to True: "
1586                "only_contains_user_certs, only_contains_ca_certs, "
1587                "indirect_crl, only_contains_attribute_certs"
1588            )
1589
1590        if not any(
1591            [
1592                only_contains_user_certs,
1593                only_contains_ca_certs,
1594                indirect_crl,
1595                only_contains_attribute_certs,
1596                full_name,
1597                relative_name,
1598                only_some_reasons,
1599            ]
1600        ):
1601            raise ValueError(
1602                "Cannot create empty extension: "
1603                "if only_contains_user_certs, only_contains_ca_certs, "
1604                "indirect_crl, and only_contains_attribute_certs are all False"
1605                ", then either full_name, relative_name, or only_some_reasons "
1606                "must have a value."
1607            )
1608
1609        self._only_contains_user_certs = only_contains_user_certs
1610        self._only_contains_ca_certs = only_contains_ca_certs
1611        self._indirect_crl = indirect_crl
1612        self._only_contains_attribute_certs = only_contains_attribute_certs
1613        self._only_some_reasons = only_some_reasons
1614        self._full_name = full_name
1615        self._relative_name = relative_name
1616
1617    def __repr__(self):
1618        return (
1619            "<IssuingDistributionPoint(full_name={0.full_name}, "
1620            "relative_name={0.relative_name}, "
1621            "only_contains_user_certs={0.only_contains_user_certs}, "
1622            "only_contains_ca_certs={0.only_contains_ca_certs}, "
1623            "only_some_reasons={0.only_some_reasons}, "
1624            "indirect_crl={0.indirect_crl}, "
1625            "only_contains_attribute_certs="
1626            "{0.only_contains_attribute_certs})>".format(self)
1627        )
1628
1629    def __eq__(self, other):
1630        if not isinstance(other, IssuingDistributionPoint):
1631            return NotImplemented
1632
1633        return (
1634            self.full_name == other.full_name
1635            and self.relative_name == other.relative_name
1636            and self.only_contains_user_certs == other.only_contains_user_certs
1637            and self.only_contains_ca_certs == other.only_contains_ca_certs
1638            and self.only_some_reasons == other.only_some_reasons
1639            and self.indirect_crl == other.indirect_crl
1640            and self.only_contains_attribute_certs
1641            == other.only_contains_attribute_certs
1642        )
1643
1644    def __ne__(self, other):
1645        return not self == other
1646
1647    def __hash__(self):
1648        return hash(
1649            (
1650                self.full_name,
1651                self.relative_name,
1652                self.only_contains_user_certs,
1653                self.only_contains_ca_certs,
1654                self.only_some_reasons,
1655                self.indirect_crl,
1656                self.only_contains_attribute_certs,
1657            )
1658        )
1659
1660    full_name = utils.read_only_property("_full_name")
1661    relative_name = utils.read_only_property("_relative_name")
1662    only_contains_user_certs = utils.read_only_property(
1663        "_only_contains_user_certs"
1664    )
1665    only_contains_ca_certs = utils.read_only_property(
1666        "_only_contains_ca_certs"
1667    )
1668    only_some_reasons = utils.read_only_property("_only_some_reasons")
1669    indirect_crl = utils.read_only_property("_indirect_crl")
1670    only_contains_attribute_certs = utils.read_only_property(
1671        "_only_contains_attribute_certs"
1672    )
1673
1674
1675@utils.register_interface(ExtensionType)
1676class UnrecognizedExtension(object):
1677    def __init__(self, oid, value):
1678        if not isinstance(oid, ObjectIdentifier):
1679            raise TypeError("oid must be an ObjectIdentifier")
1680        self._oid = oid
1681        self._value = value
1682
1683    oid = utils.read_only_property("_oid")
1684    value = utils.read_only_property("_value")
1685
1686    def __repr__(self):
1687        return (
1688            "<UnrecognizedExtension(oid={0.oid}, "
1689            "value={0.value!r})>".format(self)
1690        )
1691
1692    def __eq__(self, other):
1693        if not isinstance(other, UnrecognizedExtension):
1694            return NotImplemented
1695
1696        return self.oid == other.oid and self.value == other.value
1697
1698    def __ne__(self, other):
1699        return not self == other
1700
1701    def __hash__(self):
1702        return hash((self.oid, self.value))
1703