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