Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/x509/extensions.py: 45%
1038 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:50 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:50 +0000
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.
5from __future__ import annotations
7import abc
8import datetime
9import hashlib
10import ipaddress
11import typing
13from cryptography import utils
14from cryptography.hazmat.bindings._rust import asn1
15from cryptography.hazmat.bindings._rust import x509 as rust_x509
16from cryptography.hazmat.primitives import constant_time, serialization
17from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
18from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
19from cryptography.hazmat.primitives.asymmetric.types import (
20 CertificateIssuerPublicKeyTypes,
21 CertificatePublicKeyTypes,
22)
23from cryptography.x509.certificate_transparency import (
24 SignedCertificateTimestamp,
25)
26from cryptography.x509.general_name import (
27 DirectoryName,
28 DNSName,
29 GeneralName,
30 IPAddress,
31 OtherName,
32 RegisteredID,
33 RFC822Name,
34 UniformResourceIdentifier,
35 _IPAddressTypes,
36)
37from cryptography.x509.name import Name, RelativeDistinguishedName
38from cryptography.x509.oid import (
39 CRLEntryExtensionOID,
40 ExtensionOID,
41 ObjectIdentifier,
42 OCSPExtensionOID,
43)
45ExtensionTypeVar = typing.TypeVar(
46 "ExtensionTypeVar", bound="ExtensionType", covariant=True
47)
50def _key_identifier_from_public_key(
51 public_key: CertificatePublicKeyTypes,
52) -> bytes:
53 if isinstance(public_key, RSAPublicKey):
54 data = public_key.public_bytes(
55 serialization.Encoding.DER,
56 serialization.PublicFormat.PKCS1,
57 )
58 elif isinstance(public_key, EllipticCurvePublicKey):
59 data = public_key.public_bytes(
60 serialization.Encoding.X962,
61 serialization.PublicFormat.UncompressedPoint,
62 )
63 else:
64 # This is a very slow way to do this.
65 serialized = public_key.public_bytes(
66 serialization.Encoding.DER,
67 serialization.PublicFormat.SubjectPublicKeyInfo,
68 )
69 data = asn1.parse_spki_for_data(serialized)
71 return hashlib.sha1(data).digest()
74def _make_sequence_methods(field_name: str):
75 def len_method(self) -> int:
76 return len(getattr(self, field_name))
78 def iter_method(self):
79 return iter(getattr(self, field_name))
81 def getitem_method(self, idx):
82 return getattr(self, field_name)[idx]
84 return len_method, iter_method, getitem_method
87class DuplicateExtension(Exception):
88 def __init__(self, msg: str, oid: ObjectIdentifier) -> None:
89 super().__init__(msg)
90 self.oid = oid
93class ExtensionNotFound(Exception):
94 def __init__(self, msg: str, oid: ObjectIdentifier) -> None:
95 super().__init__(msg)
96 self.oid = oid
99class ExtensionType(metaclass=abc.ABCMeta):
100 oid: typing.ClassVar[ObjectIdentifier]
102 def public_bytes(self) -> bytes:
103 """
104 Serializes the extension type to DER.
105 """
106 raise NotImplementedError(
107 "public_bytes is not implemented for extension type {!r}".format(
108 self
109 )
110 )
113class Extensions:
114 def __init__(
115 self, extensions: typing.Iterable[Extension[ExtensionType]]
116 ) -> None:
117 self._extensions = list(extensions)
119 def get_extension_for_oid(
120 self, oid: ObjectIdentifier
121 ) -> Extension[ExtensionType]:
122 for ext in self:
123 if ext.oid == oid:
124 return ext
126 raise ExtensionNotFound(f"No {oid} extension was found", oid)
128 def get_extension_for_class(
129 self, extclass: typing.Type[ExtensionTypeVar]
130 ) -> Extension[ExtensionTypeVar]:
131 if extclass is UnrecognizedExtension:
132 raise TypeError(
133 "UnrecognizedExtension can't be used with "
134 "get_extension_for_class because more than one instance of the"
135 " class may be present."
136 )
138 for ext in self:
139 if isinstance(ext.value, extclass):
140 return ext
142 raise ExtensionNotFound(
143 f"No {extclass} extension was found", extclass.oid
144 )
146 __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions")
148 def __repr__(self) -> str:
149 return f"<Extensions({self._extensions})>"
152class CRLNumber(ExtensionType):
153 oid = ExtensionOID.CRL_NUMBER
155 def __init__(self, crl_number: int) -> None:
156 if not isinstance(crl_number, int):
157 raise TypeError("crl_number must be an integer")
159 self._crl_number = crl_number
161 def __eq__(self, other: object) -> bool:
162 if not isinstance(other, CRLNumber):
163 return NotImplemented
165 return self.crl_number == other.crl_number
167 def __hash__(self) -> int:
168 return hash(self.crl_number)
170 def __repr__(self) -> str:
171 return f"<CRLNumber({self.crl_number})>"
173 @property
174 def crl_number(self) -> int:
175 return self._crl_number
177 def public_bytes(self) -> bytes:
178 return rust_x509.encode_extension_value(self)
181class AuthorityKeyIdentifier(ExtensionType):
182 oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER
184 def __init__(
185 self,
186 key_identifier: typing.Optional[bytes],
187 authority_cert_issuer: typing.Optional[typing.Iterable[GeneralName]],
188 authority_cert_serial_number: typing.Optional[int],
189 ) -> None:
190 if (authority_cert_issuer is None) != (
191 authority_cert_serial_number is None
192 ):
193 raise ValueError(
194 "authority_cert_issuer and authority_cert_serial_number "
195 "must both be present or both None"
196 )
198 if authority_cert_issuer is not None:
199 authority_cert_issuer = list(authority_cert_issuer)
200 if not all(
201 isinstance(x, GeneralName) for x in authority_cert_issuer
202 ):
203 raise TypeError(
204 "authority_cert_issuer must be a list of GeneralName "
205 "objects"
206 )
208 if authority_cert_serial_number is not None and not isinstance(
209 authority_cert_serial_number, int
210 ):
211 raise TypeError("authority_cert_serial_number must be an integer")
213 self._key_identifier = key_identifier
214 self._authority_cert_issuer = authority_cert_issuer
215 self._authority_cert_serial_number = authority_cert_serial_number
217 # This takes a subset of CertificatePublicKeyTypes because an issuer
218 # cannot have an X25519/X448 key. This introduces some unfortunate
219 # asymmetry that requires typing users to explicitly
220 # narrow their type, but we should make this accurate and not just
221 # convenient.
222 @classmethod
223 def from_issuer_public_key(
224 cls, public_key: CertificateIssuerPublicKeyTypes
225 ) -> AuthorityKeyIdentifier:
226 digest = _key_identifier_from_public_key(public_key)
227 return cls(
228 key_identifier=digest,
229 authority_cert_issuer=None,
230 authority_cert_serial_number=None,
231 )
233 @classmethod
234 def from_issuer_subject_key_identifier(
235 cls, ski: SubjectKeyIdentifier
236 ) -> AuthorityKeyIdentifier:
237 return cls(
238 key_identifier=ski.digest,
239 authority_cert_issuer=None,
240 authority_cert_serial_number=None,
241 )
243 def __repr__(self) -> str:
244 return (
245 "<AuthorityKeyIdentifier(key_identifier={0.key_identifier!r}, "
246 "authority_cert_issuer={0.authority_cert_issuer}, "
247 "authority_cert_serial_number={0.authority_cert_serial_number}"
248 ")>".format(self)
249 )
251 def __eq__(self, other: object) -> bool:
252 if not isinstance(other, AuthorityKeyIdentifier):
253 return NotImplemented
255 return (
256 self.key_identifier == other.key_identifier
257 and self.authority_cert_issuer == other.authority_cert_issuer
258 and self.authority_cert_serial_number
259 == other.authority_cert_serial_number
260 )
262 def __hash__(self) -> int:
263 if self.authority_cert_issuer is None:
264 aci = None
265 else:
266 aci = tuple(self.authority_cert_issuer)
267 return hash(
268 (self.key_identifier, aci, self.authority_cert_serial_number)
269 )
271 @property
272 def key_identifier(self) -> typing.Optional[bytes]:
273 return self._key_identifier
275 @property
276 def authority_cert_issuer(
277 self,
278 ) -> typing.Optional[typing.List[GeneralName]]:
279 return self._authority_cert_issuer
281 @property
282 def authority_cert_serial_number(self) -> typing.Optional[int]:
283 return self._authority_cert_serial_number
285 def public_bytes(self) -> bytes:
286 return rust_x509.encode_extension_value(self)
289class SubjectKeyIdentifier(ExtensionType):
290 oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER
292 def __init__(self, digest: bytes) -> None:
293 self._digest = digest
295 @classmethod
296 def from_public_key(
297 cls, public_key: CertificatePublicKeyTypes
298 ) -> SubjectKeyIdentifier:
299 return cls(_key_identifier_from_public_key(public_key))
301 @property
302 def digest(self) -> bytes:
303 return self._digest
305 @property
306 def key_identifier(self) -> bytes:
307 return self._digest
309 def __repr__(self) -> str:
310 return f"<SubjectKeyIdentifier(digest={self.digest!r})>"
312 def __eq__(self, other: object) -> bool:
313 if not isinstance(other, SubjectKeyIdentifier):
314 return NotImplemented
316 return constant_time.bytes_eq(self.digest, other.digest)
318 def __hash__(self) -> int:
319 return hash(self.digest)
321 def public_bytes(self) -> bytes:
322 return rust_x509.encode_extension_value(self)
325class AuthorityInformationAccess(ExtensionType):
326 oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS
328 def __init__(
329 self, descriptions: typing.Iterable[AccessDescription]
330 ) -> None:
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 )
338 self._descriptions = descriptions
340 __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions")
342 def __repr__(self) -> str:
343 return f"<AuthorityInformationAccess({self._descriptions})>"
345 def __eq__(self, other: object) -> bool:
346 if not isinstance(other, AuthorityInformationAccess):
347 return NotImplemented
349 return self._descriptions == other._descriptions
351 def __hash__(self) -> int:
352 return hash(tuple(self._descriptions))
354 def public_bytes(self) -> bytes:
355 return rust_x509.encode_extension_value(self)
358class SubjectInformationAccess(ExtensionType):
359 oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS
361 def __init__(
362 self, descriptions: typing.Iterable[AccessDescription]
363 ) -> None:
364 descriptions = list(descriptions)
365 if not all(isinstance(x, AccessDescription) for x in descriptions):
366 raise TypeError(
367 "Every item in the descriptions list must be an "
368 "AccessDescription"
369 )
371 self._descriptions = descriptions
373 __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions")
375 def __repr__(self) -> str:
376 return f"<SubjectInformationAccess({self._descriptions})>"
378 def __eq__(self, other: object) -> bool:
379 if not isinstance(other, SubjectInformationAccess):
380 return NotImplemented
382 return self._descriptions == other._descriptions
384 def __hash__(self) -> int:
385 return hash(tuple(self._descriptions))
387 def public_bytes(self) -> bytes:
388 return rust_x509.encode_extension_value(self)
391class AccessDescription:
392 def __init__(
393 self, access_method: ObjectIdentifier, access_location: GeneralName
394 ) -> None:
395 if not isinstance(access_method, ObjectIdentifier):
396 raise TypeError("access_method must be an ObjectIdentifier")
398 if not isinstance(access_location, GeneralName):
399 raise TypeError("access_location must be a GeneralName")
401 self._access_method = access_method
402 self._access_location = access_location
404 def __repr__(self) -> str:
405 return (
406 "<AccessDescription(access_method={0.access_method}, access_locati"
407 "on={0.access_location})>".format(self)
408 )
410 def __eq__(self, other: object) -> bool:
411 if not isinstance(other, AccessDescription):
412 return NotImplemented
414 return (
415 self.access_method == other.access_method
416 and self.access_location == other.access_location
417 )
419 def __hash__(self) -> int:
420 return hash((self.access_method, self.access_location))
422 @property
423 def access_method(self) -> ObjectIdentifier:
424 return self._access_method
426 @property
427 def access_location(self) -> GeneralName:
428 return self._access_location
431class BasicConstraints(ExtensionType):
432 oid = ExtensionOID.BASIC_CONSTRAINTS
434 def __init__(self, ca: bool, path_length: typing.Optional[int]) -> None:
435 if not isinstance(ca, bool):
436 raise TypeError("ca must be a boolean value")
438 if path_length is not None and not ca:
439 raise ValueError("path_length must be None when ca is False")
441 if path_length is not None and (
442 not isinstance(path_length, int) or path_length < 0
443 ):
444 raise TypeError(
445 "path_length must be a non-negative integer or None"
446 )
448 self._ca = ca
449 self._path_length = path_length
451 @property
452 def ca(self) -> bool:
453 return self._ca
455 @property
456 def path_length(self) -> typing.Optional[int]:
457 return self._path_length
459 def __repr__(self) -> str:
460 return (
461 "<BasicConstraints(ca={0.ca}, " "path_length={0.path_length})>"
462 ).format(self)
464 def __eq__(self, other: object) -> bool:
465 if not isinstance(other, BasicConstraints):
466 return NotImplemented
468 return self.ca == other.ca and self.path_length == other.path_length
470 def __hash__(self) -> int:
471 return hash((self.ca, self.path_length))
473 def public_bytes(self) -> bytes:
474 return rust_x509.encode_extension_value(self)
477class DeltaCRLIndicator(ExtensionType):
478 oid = ExtensionOID.DELTA_CRL_INDICATOR
480 def __init__(self, crl_number: int) -> None:
481 if not isinstance(crl_number, int):
482 raise TypeError("crl_number must be an integer")
484 self._crl_number = crl_number
486 @property
487 def crl_number(self) -> int:
488 return self._crl_number
490 def __eq__(self, other: object) -> bool:
491 if not isinstance(other, DeltaCRLIndicator):
492 return NotImplemented
494 return self.crl_number == other.crl_number
496 def __hash__(self) -> int:
497 return hash(self.crl_number)
499 def __repr__(self) -> str:
500 return f"<DeltaCRLIndicator(crl_number={self.crl_number})>"
502 def public_bytes(self) -> bytes:
503 return rust_x509.encode_extension_value(self)
506class CRLDistributionPoints(ExtensionType):
507 oid = ExtensionOID.CRL_DISTRIBUTION_POINTS
509 def __init__(
510 self, distribution_points: typing.Iterable[DistributionPoint]
511 ) -> None:
512 distribution_points = list(distribution_points)
513 if not all(
514 isinstance(x, DistributionPoint) for x in distribution_points
515 ):
516 raise TypeError(
517 "distribution_points must be a list of DistributionPoint "
518 "objects"
519 )
521 self._distribution_points = distribution_points
523 __len__, __iter__, __getitem__ = _make_sequence_methods(
524 "_distribution_points"
525 )
527 def __repr__(self) -> str:
528 return f"<CRLDistributionPoints({self._distribution_points})>"
530 def __eq__(self, other: object) -> bool:
531 if not isinstance(other, CRLDistributionPoints):
532 return NotImplemented
534 return self._distribution_points == other._distribution_points
536 def __hash__(self) -> int:
537 return hash(tuple(self._distribution_points))
539 def public_bytes(self) -> bytes:
540 return rust_x509.encode_extension_value(self)
543class FreshestCRL(ExtensionType):
544 oid = ExtensionOID.FRESHEST_CRL
546 def __init__(
547 self, distribution_points: typing.Iterable[DistributionPoint]
548 ) -> None:
549 distribution_points = list(distribution_points)
550 if not all(
551 isinstance(x, DistributionPoint) for x in distribution_points
552 ):
553 raise TypeError(
554 "distribution_points must be a list of DistributionPoint "
555 "objects"
556 )
558 self._distribution_points = distribution_points
560 __len__, __iter__, __getitem__ = _make_sequence_methods(
561 "_distribution_points"
562 )
564 def __repr__(self) -> str:
565 return f"<FreshestCRL({self._distribution_points})>"
567 def __eq__(self, other: object) -> bool:
568 if not isinstance(other, FreshestCRL):
569 return NotImplemented
571 return self._distribution_points == other._distribution_points
573 def __hash__(self) -> int:
574 return hash(tuple(self._distribution_points))
576 def public_bytes(self) -> bytes:
577 return rust_x509.encode_extension_value(self)
580class DistributionPoint:
581 def __init__(
582 self,
583 full_name: typing.Optional[typing.Iterable[GeneralName]],
584 relative_name: typing.Optional[RelativeDistinguishedName],
585 reasons: typing.Optional[typing.FrozenSet[ReasonFlags]],
586 crl_issuer: typing.Optional[typing.Iterable[GeneralName]],
587 ) -> None:
588 if full_name and relative_name:
589 raise ValueError(
590 "You cannot provide both full_name and relative_name, at "
591 "least one must be None."
592 )
593 if not full_name and not relative_name and not crl_issuer:
594 raise ValueError(
595 "Either full_name, relative_name or crl_issuer must be "
596 "provided."
597 )
599 if full_name is not None:
600 full_name = list(full_name)
601 if not all(isinstance(x, GeneralName) for x in full_name):
602 raise TypeError(
603 "full_name must be a list of GeneralName objects"
604 )
606 if relative_name:
607 if not isinstance(relative_name, RelativeDistinguishedName):
608 raise TypeError(
609 "relative_name must be a RelativeDistinguishedName"
610 )
612 if crl_issuer is not None:
613 crl_issuer = list(crl_issuer)
614 if not all(isinstance(x, GeneralName) for x in crl_issuer):
615 raise TypeError(
616 "crl_issuer must be None or a list of general names"
617 )
619 if reasons and (
620 not isinstance(reasons, frozenset)
621 or not all(isinstance(x, ReasonFlags) for x in reasons)
622 ):
623 raise TypeError("reasons must be None or frozenset of ReasonFlags")
625 if reasons and (
626 ReasonFlags.unspecified in reasons
627 or ReasonFlags.remove_from_crl in reasons
628 ):
629 raise ValueError(
630 "unspecified and remove_from_crl are not valid reasons in a "
631 "DistributionPoint"
632 )
634 self._full_name = full_name
635 self._relative_name = relative_name
636 self._reasons = reasons
637 self._crl_issuer = crl_issuer
639 def __repr__(self) -> str:
640 return (
641 "<DistributionPoint(full_name={0.full_name}, relative_name={0.rela"
642 "tive_name}, reasons={0.reasons}, "
643 "crl_issuer={0.crl_issuer})>".format(self)
644 )
646 def __eq__(self, other: object) -> bool:
647 if not isinstance(other, DistributionPoint):
648 return NotImplemented
650 return (
651 self.full_name == other.full_name
652 and self.relative_name == other.relative_name
653 and self.reasons == other.reasons
654 and self.crl_issuer == other.crl_issuer
655 )
657 def __hash__(self) -> int:
658 if self.full_name is not None:
659 fn: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple(
660 self.full_name
661 )
662 else:
663 fn = None
665 if self.crl_issuer is not None:
666 crl_issuer: typing.Optional[
667 typing.Tuple[GeneralName, ...]
668 ] = tuple(self.crl_issuer)
669 else:
670 crl_issuer = None
672 return hash((fn, self.relative_name, self.reasons, crl_issuer))
674 @property
675 def full_name(self) -> typing.Optional[typing.List[GeneralName]]:
676 return self._full_name
678 @property
679 def relative_name(self) -> typing.Optional[RelativeDistinguishedName]:
680 return self._relative_name
682 @property
683 def reasons(self) -> typing.Optional[typing.FrozenSet[ReasonFlags]]:
684 return self._reasons
686 @property
687 def crl_issuer(self) -> typing.Optional[typing.List[GeneralName]]:
688 return self._crl_issuer
691class ReasonFlags(utils.Enum):
692 unspecified = "unspecified"
693 key_compromise = "keyCompromise"
694 ca_compromise = "cACompromise"
695 affiliation_changed = "affiliationChanged"
696 superseded = "superseded"
697 cessation_of_operation = "cessationOfOperation"
698 certificate_hold = "certificateHold"
699 privilege_withdrawn = "privilegeWithdrawn"
700 aa_compromise = "aACompromise"
701 remove_from_crl = "removeFromCRL"
704# These are distribution point bit string mappings. Not to be confused with
705# CRLReason reason flags bit string mappings.
706# ReasonFlags ::= BIT STRING {
707# unused (0),
708# keyCompromise (1),
709# cACompromise (2),
710# affiliationChanged (3),
711# superseded (4),
712# cessationOfOperation (5),
713# certificateHold (6),
714# privilegeWithdrawn (7),
715# aACompromise (8) }
716_REASON_BIT_MAPPING = {
717 1: ReasonFlags.key_compromise,
718 2: ReasonFlags.ca_compromise,
719 3: ReasonFlags.affiliation_changed,
720 4: ReasonFlags.superseded,
721 5: ReasonFlags.cessation_of_operation,
722 6: ReasonFlags.certificate_hold,
723 7: ReasonFlags.privilege_withdrawn,
724 8: ReasonFlags.aa_compromise,
725}
727_CRLREASONFLAGS = {
728 ReasonFlags.key_compromise: 1,
729 ReasonFlags.ca_compromise: 2,
730 ReasonFlags.affiliation_changed: 3,
731 ReasonFlags.superseded: 4,
732 ReasonFlags.cessation_of_operation: 5,
733 ReasonFlags.certificate_hold: 6,
734 ReasonFlags.privilege_withdrawn: 7,
735 ReasonFlags.aa_compromise: 8,
736}
739class PolicyConstraints(ExtensionType):
740 oid = ExtensionOID.POLICY_CONSTRAINTS
742 def __init__(
743 self,
744 require_explicit_policy: typing.Optional[int],
745 inhibit_policy_mapping: typing.Optional[int],
746 ) -> None:
747 if require_explicit_policy is not None and not isinstance(
748 require_explicit_policy, int
749 ):
750 raise TypeError(
751 "require_explicit_policy must be a non-negative integer or "
752 "None"
753 )
755 if inhibit_policy_mapping is not None and not isinstance(
756 inhibit_policy_mapping, int
757 ):
758 raise TypeError(
759 "inhibit_policy_mapping must be a non-negative integer or None"
760 )
762 if inhibit_policy_mapping is None and require_explicit_policy is None:
763 raise ValueError(
764 "At least one of require_explicit_policy and "
765 "inhibit_policy_mapping must not be None"
766 )
768 self._require_explicit_policy = require_explicit_policy
769 self._inhibit_policy_mapping = inhibit_policy_mapping
771 def __repr__(self) -> str:
772 return (
773 "<PolicyConstraints(require_explicit_policy={0.require_explicit"
774 "_policy}, inhibit_policy_mapping={0.inhibit_policy_"
775 "mapping})>".format(self)
776 )
778 def __eq__(self, other: object) -> bool:
779 if not isinstance(other, PolicyConstraints):
780 return NotImplemented
782 return (
783 self.require_explicit_policy == other.require_explicit_policy
784 and self.inhibit_policy_mapping == other.inhibit_policy_mapping
785 )
787 def __hash__(self) -> int:
788 return hash(
789 (self.require_explicit_policy, self.inhibit_policy_mapping)
790 )
792 @property
793 def require_explicit_policy(self) -> typing.Optional[int]:
794 return self._require_explicit_policy
796 @property
797 def inhibit_policy_mapping(self) -> typing.Optional[int]:
798 return self._inhibit_policy_mapping
800 def public_bytes(self) -> bytes:
801 return rust_x509.encode_extension_value(self)
804class CertificatePolicies(ExtensionType):
805 oid = ExtensionOID.CERTIFICATE_POLICIES
807 def __init__(self, policies: typing.Iterable[PolicyInformation]) -> None:
808 policies = list(policies)
809 if not all(isinstance(x, PolicyInformation) for x in policies):
810 raise TypeError(
811 "Every item in the policies list must be a "
812 "PolicyInformation"
813 )
815 self._policies = policies
817 __len__, __iter__, __getitem__ = _make_sequence_methods("_policies")
819 def __repr__(self) -> str:
820 return f"<CertificatePolicies({self._policies})>"
822 def __eq__(self, other: object) -> bool:
823 if not isinstance(other, CertificatePolicies):
824 return NotImplemented
826 return self._policies == other._policies
828 def __hash__(self) -> int:
829 return hash(tuple(self._policies))
831 def public_bytes(self) -> bytes:
832 return rust_x509.encode_extension_value(self)
835class PolicyInformation:
836 def __init__(
837 self,
838 policy_identifier: ObjectIdentifier,
839 policy_qualifiers: typing.Optional[
840 typing.Iterable[typing.Union[str, UserNotice]]
841 ],
842 ) -> None:
843 if not isinstance(policy_identifier, ObjectIdentifier):
844 raise TypeError("policy_identifier must be an ObjectIdentifier")
846 self._policy_identifier = policy_identifier
848 if policy_qualifiers is not None:
849 policy_qualifiers = list(policy_qualifiers)
850 if not all(
851 isinstance(x, (str, UserNotice)) for x in policy_qualifiers
852 ):
853 raise TypeError(
854 "policy_qualifiers must be a list of strings and/or "
855 "UserNotice objects or None"
856 )
858 self._policy_qualifiers = policy_qualifiers
860 def __repr__(self) -> str:
861 return (
862 "<PolicyInformation(policy_identifier={0.policy_identifier}, polic"
863 "y_qualifiers={0.policy_qualifiers})>".format(self)
864 )
866 def __eq__(self, other: object) -> bool:
867 if not isinstance(other, PolicyInformation):
868 return NotImplemented
870 return (
871 self.policy_identifier == other.policy_identifier
872 and self.policy_qualifiers == other.policy_qualifiers
873 )
875 def __hash__(self) -> int:
876 if self.policy_qualifiers is not None:
877 pq: typing.Optional[
878 typing.Tuple[typing.Union[str, UserNotice], ...]
879 ] = tuple(self.policy_qualifiers)
880 else:
881 pq = None
883 return hash((self.policy_identifier, pq))
885 @property
886 def policy_identifier(self) -> ObjectIdentifier:
887 return self._policy_identifier
889 @property
890 def policy_qualifiers(
891 self,
892 ) -> typing.Optional[typing.List[typing.Union[str, UserNotice]]]:
893 return self._policy_qualifiers
896class UserNotice:
897 def __init__(
898 self,
899 notice_reference: typing.Optional[NoticeReference],
900 explicit_text: typing.Optional[str],
901 ) -> None:
902 if notice_reference and not isinstance(
903 notice_reference, NoticeReference
904 ):
905 raise TypeError(
906 "notice_reference must be None or a NoticeReference"
907 )
909 self._notice_reference = notice_reference
910 self._explicit_text = explicit_text
912 def __repr__(self) -> str:
913 return (
914 "<UserNotice(notice_reference={0.notice_reference}, explicit_text="
915 "{0.explicit_text!r})>".format(self)
916 )
918 def __eq__(self, other: object) -> bool:
919 if not isinstance(other, UserNotice):
920 return NotImplemented
922 return (
923 self.notice_reference == other.notice_reference
924 and self.explicit_text == other.explicit_text
925 )
927 def __hash__(self) -> int:
928 return hash((self.notice_reference, self.explicit_text))
930 @property
931 def notice_reference(self) -> typing.Optional[NoticeReference]:
932 return self._notice_reference
934 @property
935 def explicit_text(self) -> typing.Optional[str]:
936 return self._explicit_text
939class NoticeReference:
940 def __init__(
941 self,
942 organization: typing.Optional[str],
943 notice_numbers: typing.Iterable[int],
944 ) -> None:
945 self._organization = organization
946 notice_numbers = list(notice_numbers)
947 if not all(isinstance(x, int) for x in notice_numbers):
948 raise TypeError("notice_numbers must be a list of integers")
950 self._notice_numbers = notice_numbers
952 def __repr__(self) -> str:
953 return (
954 "<NoticeReference(organization={0.organization!r}, notice_numbers="
955 "{0.notice_numbers})>".format(self)
956 )
958 def __eq__(self, other: object) -> bool:
959 if not isinstance(other, NoticeReference):
960 return NotImplemented
962 return (
963 self.organization == other.organization
964 and self.notice_numbers == other.notice_numbers
965 )
967 def __hash__(self) -> int:
968 return hash((self.organization, tuple(self.notice_numbers)))
970 @property
971 def organization(self) -> typing.Optional[str]:
972 return self._organization
974 @property
975 def notice_numbers(self) -> typing.List[int]:
976 return self._notice_numbers
979class ExtendedKeyUsage(ExtensionType):
980 oid = ExtensionOID.EXTENDED_KEY_USAGE
982 def __init__(self, usages: typing.Iterable[ObjectIdentifier]) -> None:
983 usages = list(usages)
984 if not all(isinstance(x, ObjectIdentifier) for x in usages):
985 raise TypeError(
986 "Every item in the usages list must be an ObjectIdentifier"
987 )
989 self._usages = usages
991 __len__, __iter__, __getitem__ = _make_sequence_methods("_usages")
993 def __repr__(self) -> str:
994 return f"<ExtendedKeyUsage({self._usages})>"
996 def __eq__(self, other: object) -> bool:
997 if not isinstance(other, ExtendedKeyUsage):
998 return NotImplemented
1000 return self._usages == other._usages
1002 def __hash__(self) -> int:
1003 return hash(tuple(self._usages))
1005 def public_bytes(self) -> bytes:
1006 return rust_x509.encode_extension_value(self)
1009class OCSPNoCheck(ExtensionType):
1010 oid = ExtensionOID.OCSP_NO_CHECK
1012 def __eq__(self, other: object) -> bool:
1013 if not isinstance(other, OCSPNoCheck):
1014 return NotImplemented
1016 return True
1018 def __hash__(self) -> int:
1019 return hash(OCSPNoCheck)
1021 def __repr__(self) -> str:
1022 return "<OCSPNoCheck()>"
1024 def public_bytes(self) -> bytes:
1025 return rust_x509.encode_extension_value(self)
1028class PrecertPoison(ExtensionType):
1029 oid = ExtensionOID.PRECERT_POISON
1031 def __eq__(self, other: object) -> bool:
1032 if not isinstance(other, PrecertPoison):
1033 return NotImplemented
1035 return True
1037 def __hash__(self) -> int:
1038 return hash(PrecertPoison)
1040 def __repr__(self) -> str:
1041 return "<PrecertPoison()>"
1043 def public_bytes(self) -> bytes:
1044 return rust_x509.encode_extension_value(self)
1047class TLSFeature(ExtensionType):
1048 oid = ExtensionOID.TLS_FEATURE
1050 def __init__(self, features: typing.Iterable[TLSFeatureType]) -> None:
1051 features = list(features)
1052 if (
1053 not all(isinstance(x, TLSFeatureType) for x in features)
1054 or len(features) == 0
1055 ):
1056 raise TypeError(
1057 "features must be a list of elements from the TLSFeatureType "
1058 "enum"
1059 )
1061 self._features = features
1063 __len__, __iter__, __getitem__ = _make_sequence_methods("_features")
1065 def __repr__(self) -> str:
1066 return f"<TLSFeature(features={self._features})>"
1068 def __eq__(self, other: object) -> bool:
1069 if not isinstance(other, TLSFeature):
1070 return NotImplemented
1072 return self._features == other._features
1074 def __hash__(self) -> int:
1075 return hash(tuple(self._features))
1077 def public_bytes(self) -> bytes:
1078 return rust_x509.encode_extension_value(self)
1081class TLSFeatureType(utils.Enum):
1082 # status_request is defined in RFC 6066 and is used for what is commonly
1083 # called OCSP Must-Staple when present in the TLS Feature extension in an
1084 # X.509 certificate.
1085 status_request = 5
1086 # status_request_v2 is defined in RFC 6961 and allows multiple OCSP
1087 # responses to be provided. It is not currently in use by clients or
1088 # servers.
1089 status_request_v2 = 17
1092_TLS_FEATURE_TYPE_TO_ENUM = {x.value: x for x in TLSFeatureType}
1095class InhibitAnyPolicy(ExtensionType):
1096 oid = ExtensionOID.INHIBIT_ANY_POLICY
1098 def __init__(self, skip_certs: int) -> None:
1099 if not isinstance(skip_certs, int):
1100 raise TypeError("skip_certs must be an integer")
1102 if skip_certs < 0:
1103 raise ValueError("skip_certs must be a non-negative integer")
1105 self._skip_certs = skip_certs
1107 def __repr__(self) -> str:
1108 return f"<InhibitAnyPolicy(skip_certs={self.skip_certs})>"
1110 def __eq__(self, other: object) -> bool:
1111 if not isinstance(other, InhibitAnyPolicy):
1112 return NotImplemented
1114 return self.skip_certs == other.skip_certs
1116 def __hash__(self) -> int:
1117 return hash(self.skip_certs)
1119 @property
1120 def skip_certs(self) -> int:
1121 return self._skip_certs
1123 def public_bytes(self) -> bytes:
1124 return rust_x509.encode_extension_value(self)
1127class KeyUsage(ExtensionType):
1128 oid = ExtensionOID.KEY_USAGE
1130 def __init__(
1131 self,
1132 digital_signature: bool,
1133 content_commitment: bool,
1134 key_encipherment: bool,
1135 data_encipherment: bool,
1136 key_agreement: bool,
1137 key_cert_sign: bool,
1138 crl_sign: bool,
1139 encipher_only: bool,
1140 decipher_only: bool,
1141 ) -> None:
1142 if not key_agreement and (encipher_only or decipher_only):
1143 raise ValueError(
1144 "encipher_only and decipher_only can only be true when "
1145 "key_agreement is true"
1146 )
1148 self._digital_signature = digital_signature
1149 self._content_commitment = content_commitment
1150 self._key_encipherment = key_encipherment
1151 self._data_encipherment = data_encipherment
1152 self._key_agreement = key_agreement
1153 self._key_cert_sign = key_cert_sign
1154 self._crl_sign = crl_sign
1155 self._encipher_only = encipher_only
1156 self._decipher_only = decipher_only
1158 @property
1159 def digital_signature(self) -> bool:
1160 return self._digital_signature
1162 @property
1163 def content_commitment(self) -> bool:
1164 return self._content_commitment
1166 @property
1167 def key_encipherment(self) -> bool:
1168 return self._key_encipherment
1170 @property
1171 def data_encipherment(self) -> bool:
1172 return self._data_encipherment
1174 @property
1175 def key_agreement(self) -> bool:
1176 return self._key_agreement
1178 @property
1179 def key_cert_sign(self) -> bool:
1180 return self._key_cert_sign
1182 @property
1183 def crl_sign(self) -> bool:
1184 return self._crl_sign
1186 @property
1187 def encipher_only(self) -> bool:
1188 if not self.key_agreement:
1189 raise ValueError(
1190 "encipher_only is undefined unless key_agreement is true"
1191 )
1192 else:
1193 return self._encipher_only
1195 @property
1196 def decipher_only(self) -> bool:
1197 if not self.key_agreement:
1198 raise ValueError(
1199 "decipher_only is undefined unless key_agreement is true"
1200 )
1201 else:
1202 return self._decipher_only
1204 def __repr__(self) -> str:
1205 try:
1206 encipher_only = self.encipher_only
1207 decipher_only = self.decipher_only
1208 except ValueError:
1209 # Users found None confusing because even though encipher/decipher
1210 # have no meaning unless key_agreement is true, to construct an
1211 # instance of the class you still need to pass False.
1212 encipher_only = False
1213 decipher_only = False
1215 return (
1216 "<KeyUsage(digital_signature={0.digital_signature}, "
1217 "content_commitment={0.content_commitment}, "
1218 "key_encipherment={0.key_encipherment}, "
1219 "data_encipherment={0.data_encipherment}, "
1220 "key_agreement={0.key_agreement}, "
1221 "key_cert_sign={0.key_cert_sign}, crl_sign={0.crl_sign}, "
1222 "encipher_only={1}, decipher_only={2})>"
1223 ).format(self, encipher_only, decipher_only)
1225 def __eq__(self, other: object) -> bool:
1226 if not isinstance(other, KeyUsage):
1227 return NotImplemented
1229 return (
1230 self.digital_signature == other.digital_signature
1231 and self.content_commitment == other.content_commitment
1232 and self.key_encipherment == other.key_encipherment
1233 and self.data_encipherment == other.data_encipherment
1234 and self.key_agreement == other.key_agreement
1235 and self.key_cert_sign == other.key_cert_sign
1236 and self.crl_sign == other.crl_sign
1237 and self._encipher_only == other._encipher_only
1238 and self._decipher_only == other._decipher_only
1239 )
1241 def __hash__(self) -> int:
1242 return hash(
1243 (
1244 self.digital_signature,
1245 self.content_commitment,
1246 self.key_encipherment,
1247 self.data_encipherment,
1248 self.key_agreement,
1249 self.key_cert_sign,
1250 self.crl_sign,
1251 self._encipher_only,
1252 self._decipher_only,
1253 )
1254 )
1256 def public_bytes(self) -> bytes:
1257 return rust_x509.encode_extension_value(self)
1260class NameConstraints(ExtensionType):
1261 oid = ExtensionOID.NAME_CONSTRAINTS
1263 def __init__(
1264 self,
1265 permitted_subtrees: typing.Optional[typing.Iterable[GeneralName]],
1266 excluded_subtrees: typing.Optional[typing.Iterable[GeneralName]],
1267 ) -> None:
1268 if permitted_subtrees is not None:
1269 permitted_subtrees = list(permitted_subtrees)
1270 if not permitted_subtrees:
1271 raise ValueError(
1272 "permitted_subtrees must be a non-empty list or None"
1273 )
1274 if not all(isinstance(x, GeneralName) for x in permitted_subtrees):
1275 raise TypeError(
1276 "permitted_subtrees must be a list of GeneralName objects "
1277 "or None"
1278 )
1280 self._validate_tree(permitted_subtrees)
1282 if excluded_subtrees is not None:
1283 excluded_subtrees = list(excluded_subtrees)
1284 if not excluded_subtrees:
1285 raise ValueError(
1286 "excluded_subtrees must be a non-empty list or None"
1287 )
1288 if not all(isinstance(x, GeneralName) for x in excluded_subtrees):
1289 raise TypeError(
1290 "excluded_subtrees must be a list of GeneralName objects "
1291 "or None"
1292 )
1294 self._validate_tree(excluded_subtrees)
1296 if permitted_subtrees is None and excluded_subtrees is None:
1297 raise ValueError(
1298 "At least one of permitted_subtrees and excluded_subtrees "
1299 "must not be None"
1300 )
1302 self._permitted_subtrees = permitted_subtrees
1303 self._excluded_subtrees = excluded_subtrees
1305 def __eq__(self, other: object) -> bool:
1306 if not isinstance(other, NameConstraints):
1307 return NotImplemented
1309 return (
1310 self.excluded_subtrees == other.excluded_subtrees
1311 and self.permitted_subtrees == other.permitted_subtrees
1312 )
1314 def _validate_tree(self, tree: typing.Iterable[GeneralName]) -> None:
1315 self._validate_ip_name(tree)
1316 self._validate_dns_name(tree)
1318 def _validate_ip_name(self, tree: typing.Iterable[GeneralName]) -> None:
1319 if any(
1320 isinstance(name, IPAddress)
1321 and not isinstance(
1322 name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network)
1323 )
1324 for name in tree
1325 ):
1326 raise TypeError(
1327 "IPAddress name constraints must be an IPv4Network or"
1328 " IPv6Network object"
1329 )
1331 def _validate_dns_name(self, tree: typing.Iterable[GeneralName]) -> None:
1332 if any(
1333 isinstance(name, DNSName) and "*" in name.value for name in tree
1334 ):
1335 raise ValueError(
1336 "DNSName name constraints must not contain the '*' wildcard"
1337 " character"
1338 )
1340 def __repr__(self) -> str:
1341 return (
1342 "<NameConstraints(permitted_subtrees={0.permitted_subtrees}, "
1343 "excluded_subtrees={0.excluded_subtrees})>".format(self)
1344 )
1346 def __hash__(self) -> int:
1347 if self.permitted_subtrees is not None:
1348 ps: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple(
1349 self.permitted_subtrees
1350 )
1351 else:
1352 ps = None
1354 if self.excluded_subtrees is not None:
1355 es: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple(
1356 self.excluded_subtrees
1357 )
1358 else:
1359 es = None
1361 return hash((ps, es))
1363 @property
1364 def permitted_subtrees(
1365 self,
1366 ) -> typing.Optional[typing.List[GeneralName]]:
1367 return self._permitted_subtrees
1369 @property
1370 def excluded_subtrees(
1371 self,
1372 ) -> typing.Optional[typing.List[GeneralName]]:
1373 return self._excluded_subtrees
1375 def public_bytes(self) -> bytes:
1376 return rust_x509.encode_extension_value(self)
1379class Extension(typing.Generic[ExtensionTypeVar]):
1380 def __init__(
1381 self, oid: ObjectIdentifier, critical: bool, value: ExtensionTypeVar
1382 ) -> None:
1383 if not isinstance(oid, ObjectIdentifier):
1384 raise TypeError(
1385 "oid argument must be an ObjectIdentifier instance."
1386 )
1388 if not isinstance(critical, bool):
1389 raise TypeError("critical must be a boolean value")
1391 self._oid = oid
1392 self._critical = critical
1393 self._value = value
1395 @property
1396 def oid(self) -> ObjectIdentifier:
1397 return self._oid
1399 @property
1400 def critical(self) -> bool:
1401 return self._critical
1403 @property
1404 def value(self) -> ExtensionTypeVar:
1405 return self._value
1407 def __repr__(self) -> str:
1408 return (
1409 "<Extension(oid={0.oid}, critical={0.critical}, "
1410 "value={0.value})>"
1411 ).format(self)
1413 def __eq__(self, other: object) -> bool:
1414 if not isinstance(other, Extension):
1415 return NotImplemented
1417 return (
1418 self.oid == other.oid
1419 and self.critical == other.critical
1420 and self.value == other.value
1421 )
1423 def __hash__(self) -> int:
1424 return hash((self.oid, self.critical, self.value))
1427class GeneralNames:
1428 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None:
1429 general_names = list(general_names)
1430 if not all(isinstance(x, GeneralName) for x in general_names):
1431 raise TypeError(
1432 "Every item in the general_names list must be an "
1433 "object conforming to the GeneralName interface"
1434 )
1436 self._general_names = general_names
1438 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1440 @typing.overload
1441 def get_values_for_type(
1442 self,
1443 type: typing.Union[
1444 typing.Type[DNSName],
1445 typing.Type[UniformResourceIdentifier],
1446 typing.Type[RFC822Name],
1447 ],
1448 ) -> typing.List[str]:
1449 ...
1451 @typing.overload
1452 def get_values_for_type(
1453 self,
1454 type: typing.Type[DirectoryName],
1455 ) -> typing.List[Name]:
1456 ...
1458 @typing.overload
1459 def get_values_for_type(
1460 self,
1461 type: typing.Type[RegisteredID],
1462 ) -> typing.List[ObjectIdentifier]:
1463 ...
1465 @typing.overload
1466 def get_values_for_type(
1467 self, type: typing.Type[IPAddress]
1468 ) -> typing.List[_IPAddressTypes]:
1469 ...
1471 @typing.overload
1472 def get_values_for_type(
1473 self, type: typing.Type[OtherName]
1474 ) -> typing.List[OtherName]:
1475 ...
1477 def get_values_for_type(
1478 self,
1479 type: typing.Union[
1480 typing.Type[DNSName],
1481 typing.Type[DirectoryName],
1482 typing.Type[IPAddress],
1483 typing.Type[OtherName],
1484 typing.Type[RFC822Name],
1485 typing.Type[RegisteredID],
1486 typing.Type[UniformResourceIdentifier],
1487 ],
1488 ) -> typing.Union[
1489 typing.List[_IPAddressTypes],
1490 typing.List[str],
1491 typing.List[OtherName],
1492 typing.List[Name],
1493 typing.List[ObjectIdentifier],
1494 ]:
1495 # Return the value of each GeneralName, except for OtherName instances
1496 # which we return directly because it has two important properties not
1497 # just one value.
1498 objs = (i for i in self if isinstance(i, type))
1499 if type != OtherName:
1500 return [i.value for i in objs]
1501 return list(objs)
1503 def __repr__(self) -> str:
1504 return f"<GeneralNames({self._general_names})>"
1506 def __eq__(self, other: object) -> bool:
1507 if not isinstance(other, GeneralNames):
1508 return NotImplemented
1510 return self._general_names == other._general_names
1512 def __hash__(self) -> int:
1513 return hash(tuple(self._general_names))
1516class SubjectAlternativeName(ExtensionType):
1517 oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME
1519 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None:
1520 self._general_names = GeneralNames(general_names)
1522 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1524 @typing.overload
1525 def get_values_for_type(
1526 self,
1527 type: typing.Union[
1528 typing.Type[DNSName],
1529 typing.Type[UniformResourceIdentifier],
1530 typing.Type[RFC822Name],
1531 ],
1532 ) -> typing.List[str]:
1533 ...
1535 @typing.overload
1536 def get_values_for_type(
1537 self,
1538 type: typing.Type[DirectoryName],
1539 ) -> typing.List[Name]:
1540 ...
1542 @typing.overload
1543 def get_values_for_type(
1544 self,
1545 type: typing.Type[RegisteredID],
1546 ) -> typing.List[ObjectIdentifier]:
1547 ...
1549 @typing.overload
1550 def get_values_for_type(
1551 self, type: typing.Type[IPAddress]
1552 ) -> typing.List[_IPAddressTypes]:
1553 ...
1555 @typing.overload
1556 def get_values_for_type(
1557 self, type: typing.Type[OtherName]
1558 ) -> typing.List[OtherName]:
1559 ...
1561 def get_values_for_type(
1562 self,
1563 type: typing.Union[
1564 typing.Type[DNSName],
1565 typing.Type[DirectoryName],
1566 typing.Type[IPAddress],
1567 typing.Type[OtherName],
1568 typing.Type[RFC822Name],
1569 typing.Type[RegisteredID],
1570 typing.Type[UniformResourceIdentifier],
1571 ],
1572 ) -> typing.Union[
1573 typing.List[_IPAddressTypes],
1574 typing.List[str],
1575 typing.List[OtherName],
1576 typing.List[Name],
1577 typing.List[ObjectIdentifier],
1578 ]:
1579 return self._general_names.get_values_for_type(type)
1581 def __repr__(self) -> str:
1582 return f"<SubjectAlternativeName({self._general_names})>"
1584 def __eq__(self, other: object) -> bool:
1585 if not isinstance(other, SubjectAlternativeName):
1586 return NotImplemented
1588 return self._general_names == other._general_names
1590 def __hash__(self) -> int:
1591 return hash(self._general_names)
1593 def public_bytes(self) -> bytes:
1594 return rust_x509.encode_extension_value(self)
1597class IssuerAlternativeName(ExtensionType):
1598 oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME
1600 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None:
1601 self._general_names = GeneralNames(general_names)
1603 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1605 @typing.overload
1606 def get_values_for_type(
1607 self,
1608 type: typing.Union[
1609 typing.Type[DNSName],
1610 typing.Type[UniformResourceIdentifier],
1611 typing.Type[RFC822Name],
1612 ],
1613 ) -> typing.List[str]:
1614 ...
1616 @typing.overload
1617 def get_values_for_type(
1618 self,
1619 type: typing.Type[DirectoryName],
1620 ) -> typing.List[Name]:
1621 ...
1623 @typing.overload
1624 def get_values_for_type(
1625 self,
1626 type: typing.Type[RegisteredID],
1627 ) -> typing.List[ObjectIdentifier]:
1628 ...
1630 @typing.overload
1631 def get_values_for_type(
1632 self, type: typing.Type[IPAddress]
1633 ) -> typing.List[_IPAddressTypes]:
1634 ...
1636 @typing.overload
1637 def get_values_for_type(
1638 self, type: typing.Type[OtherName]
1639 ) -> typing.List[OtherName]:
1640 ...
1642 def get_values_for_type(
1643 self,
1644 type: typing.Union[
1645 typing.Type[DNSName],
1646 typing.Type[DirectoryName],
1647 typing.Type[IPAddress],
1648 typing.Type[OtherName],
1649 typing.Type[RFC822Name],
1650 typing.Type[RegisteredID],
1651 typing.Type[UniformResourceIdentifier],
1652 ],
1653 ) -> typing.Union[
1654 typing.List[_IPAddressTypes],
1655 typing.List[str],
1656 typing.List[OtherName],
1657 typing.List[Name],
1658 typing.List[ObjectIdentifier],
1659 ]:
1660 return self._general_names.get_values_for_type(type)
1662 def __repr__(self) -> str:
1663 return f"<IssuerAlternativeName({self._general_names})>"
1665 def __eq__(self, other: object) -> bool:
1666 if not isinstance(other, IssuerAlternativeName):
1667 return NotImplemented
1669 return self._general_names == other._general_names
1671 def __hash__(self) -> int:
1672 return hash(self._general_names)
1674 def public_bytes(self) -> bytes:
1675 return rust_x509.encode_extension_value(self)
1678class CertificateIssuer(ExtensionType):
1679 oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER
1681 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None:
1682 self._general_names = GeneralNames(general_names)
1684 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1686 @typing.overload
1687 def get_values_for_type(
1688 self,
1689 type: typing.Union[
1690 typing.Type[DNSName],
1691 typing.Type[UniformResourceIdentifier],
1692 typing.Type[RFC822Name],
1693 ],
1694 ) -> typing.List[str]:
1695 ...
1697 @typing.overload
1698 def get_values_for_type(
1699 self,
1700 type: typing.Type[DirectoryName],
1701 ) -> typing.List[Name]:
1702 ...
1704 @typing.overload
1705 def get_values_for_type(
1706 self,
1707 type: typing.Type[RegisteredID],
1708 ) -> typing.List[ObjectIdentifier]:
1709 ...
1711 @typing.overload
1712 def get_values_for_type(
1713 self, type: typing.Type[IPAddress]
1714 ) -> typing.List[_IPAddressTypes]:
1715 ...
1717 @typing.overload
1718 def get_values_for_type(
1719 self, type: typing.Type[OtherName]
1720 ) -> typing.List[OtherName]:
1721 ...
1723 def get_values_for_type(
1724 self,
1725 type: typing.Union[
1726 typing.Type[DNSName],
1727 typing.Type[DirectoryName],
1728 typing.Type[IPAddress],
1729 typing.Type[OtherName],
1730 typing.Type[RFC822Name],
1731 typing.Type[RegisteredID],
1732 typing.Type[UniformResourceIdentifier],
1733 ],
1734 ) -> typing.Union[
1735 typing.List[_IPAddressTypes],
1736 typing.List[str],
1737 typing.List[OtherName],
1738 typing.List[Name],
1739 typing.List[ObjectIdentifier],
1740 ]:
1741 return self._general_names.get_values_for_type(type)
1743 def __repr__(self) -> str:
1744 return f"<CertificateIssuer({self._general_names})>"
1746 def __eq__(self, other: object) -> bool:
1747 if not isinstance(other, CertificateIssuer):
1748 return NotImplemented
1750 return self._general_names == other._general_names
1752 def __hash__(self) -> int:
1753 return hash(self._general_names)
1755 def public_bytes(self) -> bytes:
1756 return rust_x509.encode_extension_value(self)
1759class CRLReason(ExtensionType):
1760 oid = CRLEntryExtensionOID.CRL_REASON
1762 def __init__(self, reason: ReasonFlags) -> None:
1763 if not isinstance(reason, ReasonFlags):
1764 raise TypeError("reason must be an element from ReasonFlags")
1766 self._reason = reason
1768 def __repr__(self) -> str:
1769 return f"<CRLReason(reason={self._reason})>"
1771 def __eq__(self, other: object) -> bool:
1772 if not isinstance(other, CRLReason):
1773 return NotImplemented
1775 return self.reason == other.reason
1777 def __hash__(self) -> int:
1778 return hash(self.reason)
1780 @property
1781 def reason(self) -> ReasonFlags:
1782 return self._reason
1784 def public_bytes(self) -> bytes:
1785 return rust_x509.encode_extension_value(self)
1788class InvalidityDate(ExtensionType):
1789 oid = CRLEntryExtensionOID.INVALIDITY_DATE
1791 def __init__(self, invalidity_date: datetime.datetime) -> None:
1792 if not isinstance(invalidity_date, datetime.datetime):
1793 raise TypeError("invalidity_date must be a datetime.datetime")
1795 self._invalidity_date = invalidity_date
1797 def __repr__(self) -> str:
1798 return "<InvalidityDate(invalidity_date={})>".format(
1799 self._invalidity_date
1800 )
1802 def __eq__(self, other: object) -> bool:
1803 if not isinstance(other, InvalidityDate):
1804 return NotImplemented
1806 return self.invalidity_date == other.invalidity_date
1808 def __hash__(self) -> int:
1809 return hash(self.invalidity_date)
1811 @property
1812 def invalidity_date(self) -> datetime.datetime:
1813 return self._invalidity_date
1815 def public_bytes(self) -> bytes:
1816 return rust_x509.encode_extension_value(self)
1819class PrecertificateSignedCertificateTimestamps(ExtensionType):
1820 oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS
1822 def __init__(
1823 self,
1824 signed_certificate_timestamps: typing.Iterable[
1825 SignedCertificateTimestamp
1826 ],
1827 ) -> None:
1828 signed_certificate_timestamps = list(signed_certificate_timestamps)
1829 if not all(
1830 isinstance(sct, SignedCertificateTimestamp)
1831 for sct in signed_certificate_timestamps
1832 ):
1833 raise TypeError(
1834 "Every item in the signed_certificate_timestamps list must be "
1835 "a SignedCertificateTimestamp"
1836 )
1837 self._signed_certificate_timestamps = signed_certificate_timestamps
1839 __len__, __iter__, __getitem__ = _make_sequence_methods(
1840 "_signed_certificate_timestamps"
1841 )
1843 def __repr__(self) -> str:
1844 return "<PrecertificateSignedCertificateTimestamps({})>".format(
1845 list(self)
1846 )
1848 def __hash__(self) -> int:
1849 return hash(tuple(self._signed_certificate_timestamps))
1851 def __eq__(self, other: object) -> bool:
1852 if not isinstance(other, PrecertificateSignedCertificateTimestamps):
1853 return NotImplemented
1855 return (
1856 self._signed_certificate_timestamps
1857 == other._signed_certificate_timestamps
1858 )
1860 def public_bytes(self) -> bytes:
1861 return rust_x509.encode_extension_value(self)
1864class SignedCertificateTimestamps(ExtensionType):
1865 oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS
1867 def __init__(
1868 self,
1869 signed_certificate_timestamps: typing.Iterable[
1870 SignedCertificateTimestamp
1871 ],
1872 ) -> None:
1873 signed_certificate_timestamps = list(signed_certificate_timestamps)
1874 if not all(
1875 isinstance(sct, SignedCertificateTimestamp)
1876 for sct in signed_certificate_timestamps
1877 ):
1878 raise TypeError(
1879 "Every item in the signed_certificate_timestamps list must be "
1880 "a SignedCertificateTimestamp"
1881 )
1882 self._signed_certificate_timestamps = signed_certificate_timestamps
1884 __len__, __iter__, __getitem__ = _make_sequence_methods(
1885 "_signed_certificate_timestamps"
1886 )
1888 def __repr__(self) -> str:
1889 return f"<SignedCertificateTimestamps({list(self)})>"
1891 def __hash__(self) -> int:
1892 return hash(tuple(self._signed_certificate_timestamps))
1894 def __eq__(self, other: object) -> bool:
1895 if not isinstance(other, SignedCertificateTimestamps):
1896 return NotImplemented
1898 return (
1899 self._signed_certificate_timestamps
1900 == other._signed_certificate_timestamps
1901 )
1903 def public_bytes(self) -> bytes:
1904 return rust_x509.encode_extension_value(self)
1907class OCSPNonce(ExtensionType):
1908 oid = OCSPExtensionOID.NONCE
1910 def __init__(self, nonce: bytes) -> None:
1911 if not isinstance(nonce, bytes):
1912 raise TypeError("nonce must be bytes")
1914 self._nonce = nonce
1916 def __eq__(self, other: object) -> bool:
1917 if not isinstance(other, OCSPNonce):
1918 return NotImplemented
1920 return self.nonce == other.nonce
1922 def __hash__(self) -> int:
1923 return hash(self.nonce)
1925 def __repr__(self) -> str:
1926 return f"<OCSPNonce(nonce={self.nonce!r})>"
1928 @property
1929 def nonce(self) -> bytes:
1930 return self._nonce
1932 def public_bytes(self) -> bytes:
1933 return rust_x509.encode_extension_value(self)
1936class OCSPAcceptableResponses(ExtensionType):
1937 oid = OCSPExtensionOID.ACCEPTABLE_RESPONSES
1939 def __init__(self, responses: typing.Iterable[ObjectIdentifier]) -> None:
1940 responses = list(responses)
1941 if any(not isinstance(r, ObjectIdentifier) for r in responses):
1942 raise TypeError("All responses must be ObjectIdentifiers")
1944 self._responses = responses
1946 def __eq__(self, other: object) -> bool:
1947 if not isinstance(other, OCSPAcceptableResponses):
1948 return NotImplemented
1950 return self._responses == other._responses
1952 def __hash__(self) -> int:
1953 return hash(tuple(self._responses))
1955 def __repr__(self) -> str:
1956 return f"<OCSPAcceptableResponses(responses={self._responses})>"
1958 def __iter__(self) -> typing.Iterator[ObjectIdentifier]:
1959 return iter(self._responses)
1961 def public_bytes(self) -> bytes:
1962 return rust_x509.encode_extension_value(self)
1965class IssuingDistributionPoint(ExtensionType):
1966 oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT
1968 def __init__(
1969 self,
1970 full_name: typing.Optional[typing.Iterable[GeneralName]],
1971 relative_name: typing.Optional[RelativeDistinguishedName],
1972 only_contains_user_certs: bool,
1973 only_contains_ca_certs: bool,
1974 only_some_reasons: typing.Optional[typing.FrozenSet[ReasonFlags]],
1975 indirect_crl: bool,
1976 only_contains_attribute_certs: bool,
1977 ) -> None:
1978 if full_name is not None:
1979 full_name = list(full_name)
1981 if only_some_reasons and (
1982 not isinstance(only_some_reasons, frozenset)
1983 or not all(isinstance(x, ReasonFlags) for x in only_some_reasons)
1984 ):
1985 raise TypeError(
1986 "only_some_reasons must be None or frozenset of ReasonFlags"
1987 )
1989 if only_some_reasons and (
1990 ReasonFlags.unspecified in only_some_reasons
1991 or ReasonFlags.remove_from_crl in only_some_reasons
1992 ):
1993 raise ValueError(
1994 "unspecified and remove_from_crl are not valid reasons in an "
1995 "IssuingDistributionPoint"
1996 )
1998 if not (
1999 isinstance(only_contains_user_certs, bool)
2000 and isinstance(only_contains_ca_certs, bool)
2001 and isinstance(indirect_crl, bool)
2002 and isinstance(only_contains_attribute_certs, bool)
2003 ):
2004 raise TypeError(
2005 "only_contains_user_certs, only_contains_ca_certs, "
2006 "indirect_crl and only_contains_attribute_certs "
2007 "must all be boolean."
2008 )
2010 crl_constraints = [
2011 only_contains_user_certs,
2012 only_contains_ca_certs,
2013 indirect_crl,
2014 only_contains_attribute_certs,
2015 ]
2017 if len([x for x in crl_constraints if x]) > 1:
2018 raise ValueError(
2019 "Only one of the following can be set to True: "
2020 "only_contains_user_certs, only_contains_ca_certs, "
2021 "indirect_crl, only_contains_attribute_certs"
2022 )
2024 if not any(
2025 [
2026 only_contains_user_certs,
2027 only_contains_ca_certs,
2028 indirect_crl,
2029 only_contains_attribute_certs,
2030 full_name,
2031 relative_name,
2032 only_some_reasons,
2033 ]
2034 ):
2035 raise ValueError(
2036 "Cannot create empty extension: "
2037 "if only_contains_user_certs, only_contains_ca_certs, "
2038 "indirect_crl, and only_contains_attribute_certs are all False"
2039 ", then either full_name, relative_name, or only_some_reasons "
2040 "must have a value."
2041 )
2043 self._only_contains_user_certs = only_contains_user_certs
2044 self._only_contains_ca_certs = only_contains_ca_certs
2045 self._indirect_crl = indirect_crl
2046 self._only_contains_attribute_certs = only_contains_attribute_certs
2047 self._only_some_reasons = only_some_reasons
2048 self._full_name = full_name
2049 self._relative_name = relative_name
2051 def __repr__(self) -> str:
2052 return (
2053 "<IssuingDistributionPoint(full_name={0.full_name}, "
2054 "relative_name={0.relative_name}, "
2055 "only_contains_user_certs={0.only_contains_user_certs}, "
2056 "only_contains_ca_certs={0.only_contains_ca_certs}, "
2057 "only_some_reasons={0.only_some_reasons}, "
2058 "indirect_crl={0.indirect_crl}, "
2059 "only_contains_attribute_certs="
2060 "{0.only_contains_attribute_certs})>".format(self)
2061 )
2063 def __eq__(self, other: object) -> bool:
2064 if not isinstance(other, IssuingDistributionPoint):
2065 return NotImplemented
2067 return (
2068 self.full_name == other.full_name
2069 and self.relative_name == other.relative_name
2070 and self.only_contains_user_certs == other.only_contains_user_certs
2071 and self.only_contains_ca_certs == other.only_contains_ca_certs
2072 and self.only_some_reasons == other.only_some_reasons
2073 and self.indirect_crl == other.indirect_crl
2074 and self.only_contains_attribute_certs
2075 == other.only_contains_attribute_certs
2076 )
2078 def __hash__(self) -> int:
2079 return hash(
2080 (
2081 self.full_name,
2082 self.relative_name,
2083 self.only_contains_user_certs,
2084 self.only_contains_ca_certs,
2085 self.only_some_reasons,
2086 self.indirect_crl,
2087 self.only_contains_attribute_certs,
2088 )
2089 )
2091 @property
2092 def full_name(self) -> typing.Optional[typing.List[GeneralName]]:
2093 return self._full_name
2095 @property
2096 def relative_name(self) -> typing.Optional[RelativeDistinguishedName]:
2097 return self._relative_name
2099 @property
2100 def only_contains_user_certs(self) -> bool:
2101 return self._only_contains_user_certs
2103 @property
2104 def only_contains_ca_certs(self) -> bool:
2105 return self._only_contains_ca_certs
2107 @property
2108 def only_some_reasons(
2109 self,
2110 ) -> typing.Optional[typing.FrozenSet[ReasonFlags]]:
2111 return self._only_some_reasons
2113 @property
2114 def indirect_crl(self) -> bool:
2115 return self._indirect_crl
2117 @property
2118 def only_contains_attribute_certs(self) -> bool:
2119 return self._only_contains_attribute_certs
2121 def public_bytes(self) -> bytes:
2122 return rust_x509.encode_extension_value(self)
2125class MSCertificateTemplate(ExtensionType):
2126 oid = ExtensionOID.MS_CERTIFICATE_TEMPLATE
2128 def __init__(
2129 self,
2130 template_id: ObjectIdentifier,
2131 major_version: typing.Optional[int],
2132 minor_version: typing.Optional[int],
2133 ) -> None:
2134 if not isinstance(template_id, ObjectIdentifier):
2135 raise TypeError("oid must be an ObjectIdentifier")
2136 self._template_id = template_id
2137 if (
2138 major_version is not None and not isinstance(major_version, int)
2139 ) or (
2140 minor_version is not None and not isinstance(minor_version, int)
2141 ):
2142 raise TypeError(
2143 "major_version and minor_version must be integers or None"
2144 )
2145 self._major_version = major_version
2146 self._minor_version = minor_version
2148 @property
2149 def template_id(self) -> ObjectIdentifier:
2150 return self._template_id
2152 @property
2153 def major_version(self) -> typing.Optional[int]:
2154 return self._major_version
2156 @property
2157 def minor_version(self) -> typing.Optional[int]:
2158 return self._minor_version
2160 def __repr__(self) -> str:
2161 return (
2162 f"<MSCertificateTemplate(template_id={self.template_id}, "
2163 f"major_version={self.major_version}, "
2164 f"minor_version={self.minor_version})>"
2165 )
2167 def __eq__(self, other: object) -> bool:
2168 if not isinstance(other, MSCertificateTemplate):
2169 return NotImplemented
2171 return (
2172 self.template_id == other.template_id
2173 and self.major_version == other.major_version
2174 and self.minor_version == other.minor_version
2175 )
2177 def __hash__(self) -> int:
2178 return hash((self.template_id, self.major_version, self.minor_version))
2180 def public_bytes(self) -> bytes:
2181 return rust_x509.encode_extension_value(self)
2184class UnrecognizedExtension(ExtensionType):
2185 def __init__(self, oid: ObjectIdentifier, value: bytes) -> None:
2186 if not isinstance(oid, ObjectIdentifier):
2187 raise TypeError("oid must be an ObjectIdentifier")
2188 self._oid = oid
2189 self._value = value
2191 @property
2192 def oid(self) -> ObjectIdentifier: # type: ignore[override]
2193 return self._oid
2195 @property
2196 def value(self) -> bytes:
2197 return self._value
2199 def __repr__(self) -> str:
2200 return (
2201 "<UnrecognizedExtension(oid={0.oid}, "
2202 "value={0.value!r})>".format(self)
2203 )
2205 def __eq__(self, other: object) -> bool:
2206 if not isinstance(other, UnrecognizedExtension):
2207 return NotImplemented
2209 return self.oid == other.oid and self.value == other.value
2211 def __hash__(self) -> int:
2212 return hash((self.oid, self.value))
2214 def public_bytes(self) -> bytes:
2215 return self.value