Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/x509/extensions.py: 45%
989 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:36 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:36 +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.
6import abc
7import datetime
8import hashlib
9import ipaddress
10import typing
12from cryptography import utils
13from cryptography.hazmat.bindings._rust import asn1
14from cryptography.hazmat.bindings._rust import x509 as rust_x509
15from cryptography.hazmat.primitives import constant_time, serialization
16from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
17from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
18from cryptography.hazmat.primitives.asymmetric.types import (
19 CertificateIssuerPublicKeyTypes,
20 CertificatePublicKeyTypes,
21)
22from cryptography.x509.certificate_transparency import (
23 SignedCertificateTimestamp,
24)
25from cryptography.x509.general_name import (
26 DirectoryName,
27 DNSName,
28 GeneralName,
29 IPAddress,
30 OtherName,
31 RegisteredID,
32 RFC822Name,
33 UniformResourceIdentifier,
34 _IPAddressTypes,
35)
36from cryptography.x509.name import Name, RelativeDistinguishedName
37from cryptography.x509.oid import (
38 CRLEntryExtensionOID,
39 ExtensionOID,
40 ObjectIdentifier,
41 OCSPExtensionOID,
42)
44ExtensionTypeVar = typing.TypeVar(
45 "ExtensionTypeVar", bound="ExtensionType", covariant=True
46)
49def _key_identifier_from_public_key(
50 public_key: CertificatePublicKeyTypes,
51) -> bytes:
52 if isinstance(public_key, RSAPublicKey):
53 data = public_key.public_bytes(
54 serialization.Encoding.DER,
55 serialization.PublicFormat.PKCS1,
56 )
57 elif isinstance(public_key, EllipticCurvePublicKey):
58 data = public_key.public_bytes(
59 serialization.Encoding.X962,
60 serialization.PublicFormat.UncompressedPoint,
61 )
62 else:
63 # This is a very slow way to do this.
64 serialized = public_key.public_bytes(
65 serialization.Encoding.DER,
66 serialization.PublicFormat.SubjectPublicKeyInfo,
67 )
68 data = asn1.parse_spki_for_data(serialized)
70 return hashlib.sha1(data).digest()
73def _make_sequence_methods(field_name: str):
74 def len_method(self) -> int:
75 return len(getattr(self, field_name))
77 def iter_method(self):
78 return iter(getattr(self, field_name))
80 def getitem_method(self, idx):
81 return getattr(self, field_name)[idx]
83 return len_method, iter_method, getitem_method
86class DuplicateExtension(Exception):
87 def __init__(self, msg: str, oid: ObjectIdentifier) -> None:
88 super().__init__(msg)
89 self.oid = oid
92class ExtensionNotFound(Exception):
93 def __init__(self, msg: str, oid: ObjectIdentifier) -> None:
94 super().__init__(msg)
95 self.oid = oid
98class ExtensionType(metaclass=abc.ABCMeta):
99 oid: typing.ClassVar[ObjectIdentifier]
101 def public_bytes(self) -> bytes:
102 """
103 Serializes the extension type to DER.
104 """
105 raise NotImplementedError(
106 "public_bytes is not implemented for extension type {!r}".format(
107 self
108 )
109 )
112class Extensions:
113 def __init__(
114 self, extensions: typing.Iterable["Extension[ExtensionType]"]
115 ) -> None:
116 self._extensions = list(extensions)
118 def get_extension_for_oid(
119 self, oid: ObjectIdentifier
120 ) -> "Extension[ExtensionType]":
121 for ext in self:
122 if ext.oid == oid:
123 return ext
125 raise ExtensionNotFound(f"No {oid} extension was found", oid)
127 def get_extension_for_class(
128 self, extclass: typing.Type[ExtensionTypeVar]
129 ) -> "Extension[ExtensionTypeVar]":
130 if extclass is UnrecognizedExtension:
131 raise TypeError(
132 "UnrecognizedExtension can't be used with "
133 "get_extension_for_class because more than one instance of the"
134 " class may be present."
135 )
137 for ext in self:
138 if isinstance(ext.value, extclass):
139 return ext
141 raise ExtensionNotFound(
142 f"No {extclass} extension was found", extclass.oid
143 )
145 __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions")
147 def __repr__(self) -> str:
148 return f"<Extensions({self._extensions})>"
151class CRLNumber(ExtensionType):
152 oid = ExtensionOID.CRL_NUMBER
154 def __init__(self, crl_number: int) -> None:
155 if not isinstance(crl_number, int):
156 raise TypeError("crl_number must be an integer")
158 self._crl_number = crl_number
160 def __eq__(self, other: object) -> bool:
161 if not isinstance(other, CRLNumber):
162 return NotImplemented
164 return self.crl_number == other.crl_number
166 def __hash__(self) -> int:
167 return hash(self.crl_number)
169 def __repr__(self) -> str:
170 return f"<CRLNumber({self.crl_number})>"
172 @property
173 def crl_number(self) -> int:
174 return self._crl_number
176 def public_bytes(self) -> bytes:
177 return rust_x509.encode_extension_value(self)
180class AuthorityKeyIdentifier(ExtensionType):
181 oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER
183 def __init__(
184 self,
185 key_identifier: typing.Optional[bytes],
186 authority_cert_issuer: typing.Optional[typing.Iterable[GeneralName]],
187 authority_cert_serial_number: typing.Optional[int],
188 ) -> None:
189 if (authority_cert_issuer is None) != (
190 authority_cert_serial_number is None
191 ):
192 raise ValueError(
193 "authority_cert_issuer and authority_cert_serial_number "
194 "must both be present or both None"
195 )
197 if authority_cert_issuer is not None:
198 authority_cert_issuer = list(authority_cert_issuer)
199 if not all(
200 isinstance(x, GeneralName) for x in authority_cert_issuer
201 ):
202 raise TypeError(
203 "authority_cert_issuer must be a list of GeneralName "
204 "objects"
205 )
207 if authority_cert_serial_number is not None and not isinstance(
208 authority_cert_serial_number, int
209 ):
210 raise TypeError("authority_cert_serial_number must be an integer")
212 self._key_identifier = key_identifier
213 self._authority_cert_issuer = authority_cert_issuer
214 self._authority_cert_serial_number = authority_cert_serial_number
216 # This takes a subset of CertificatePublicKeyTypes because an issuer
217 # cannot have an X25519/X448 key. This introduces some unfortunate
218 # asymmetry that requires typing users to explicitly
219 # narrow their type, but we should make this accurate and not just
220 # convenient.
221 @classmethod
222 def from_issuer_public_key(
223 cls, public_key: CertificateIssuerPublicKeyTypes
224 ) -> "AuthorityKeyIdentifier":
225 digest = _key_identifier_from_public_key(public_key)
226 return cls(
227 key_identifier=digest,
228 authority_cert_issuer=None,
229 authority_cert_serial_number=None,
230 )
232 @classmethod
233 def from_issuer_subject_key_identifier(
234 cls, ski: "SubjectKeyIdentifier"
235 ) -> "AuthorityKeyIdentifier":
236 return cls(
237 key_identifier=ski.digest,
238 authority_cert_issuer=None,
239 authority_cert_serial_number=None,
240 )
242 def __repr__(self) -> str:
243 return (
244 "<AuthorityKeyIdentifier(key_identifier={0.key_identifier!r}, "
245 "authority_cert_issuer={0.authority_cert_issuer}, "
246 "authority_cert_serial_number={0.authority_cert_serial_number}"
247 ")>".format(self)
248 )
250 def __eq__(self, other: object) -> bool:
251 if not isinstance(other, AuthorityKeyIdentifier):
252 return NotImplemented
254 return (
255 self.key_identifier == other.key_identifier
256 and self.authority_cert_issuer == other.authority_cert_issuer
257 and self.authority_cert_serial_number
258 == other.authority_cert_serial_number
259 )
261 def __hash__(self) -> int:
262 if self.authority_cert_issuer is None:
263 aci = None
264 else:
265 aci = tuple(self.authority_cert_issuer)
266 return hash(
267 (self.key_identifier, aci, self.authority_cert_serial_number)
268 )
270 @property
271 def key_identifier(self) -> typing.Optional[bytes]:
272 return self._key_identifier
274 @property
275 def authority_cert_issuer(
276 self,
277 ) -> typing.Optional[typing.List[GeneralName]]:
278 return self._authority_cert_issuer
280 @property
281 def authority_cert_serial_number(self) -> typing.Optional[int]:
282 return self._authority_cert_serial_number
284 def public_bytes(self) -> bytes:
285 return rust_x509.encode_extension_value(self)
288class SubjectKeyIdentifier(ExtensionType):
289 oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER
291 def __init__(self, digest: bytes) -> None:
292 self._digest = digest
294 @classmethod
295 def from_public_key(
296 cls, public_key: CertificatePublicKeyTypes
297 ) -> "SubjectKeyIdentifier":
298 return cls(_key_identifier_from_public_key(public_key))
300 @property
301 def digest(self) -> bytes:
302 return self._digest
304 @property
305 def key_identifier(self) -> bytes:
306 return self._digest
308 def __repr__(self) -> str:
309 return f"<SubjectKeyIdentifier(digest={self.digest!r})>"
311 def __eq__(self, other: object) -> bool:
312 if not isinstance(other, SubjectKeyIdentifier):
313 return NotImplemented
315 return constant_time.bytes_eq(self.digest, other.digest)
317 def __hash__(self) -> int:
318 return hash(self.digest)
320 def public_bytes(self) -> bytes:
321 return rust_x509.encode_extension_value(self)
324class AuthorityInformationAccess(ExtensionType):
325 oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS
327 def __init__(
328 self, descriptions: typing.Iterable["AccessDescription"]
329 ) -> None:
330 descriptions = list(descriptions)
331 if not all(isinstance(x, AccessDescription) for x in descriptions):
332 raise TypeError(
333 "Every item in the descriptions list must be an "
334 "AccessDescription"
335 )
337 self._descriptions = descriptions
339 __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions")
341 def __repr__(self) -> str:
342 return f"<AuthorityInformationAccess({self._descriptions})>"
344 def __eq__(self, other: object) -> bool:
345 if not isinstance(other, AuthorityInformationAccess):
346 return NotImplemented
348 return self._descriptions == other._descriptions
350 def __hash__(self) -> int:
351 return hash(tuple(self._descriptions))
353 def public_bytes(self) -> bytes:
354 return rust_x509.encode_extension_value(self)
357class SubjectInformationAccess(ExtensionType):
358 oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS
360 def __init__(
361 self, descriptions: typing.Iterable["AccessDescription"]
362 ) -> None:
363 descriptions = list(descriptions)
364 if not all(isinstance(x, AccessDescription) for x in descriptions):
365 raise TypeError(
366 "Every item in the descriptions list must be an "
367 "AccessDescription"
368 )
370 self._descriptions = descriptions
372 __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions")
374 def __repr__(self) -> str:
375 return f"<SubjectInformationAccess({self._descriptions})>"
377 def __eq__(self, other: object) -> bool:
378 if not isinstance(other, SubjectInformationAccess):
379 return NotImplemented
381 return self._descriptions == other._descriptions
383 def __hash__(self) -> int:
384 return hash(tuple(self._descriptions))
386 def public_bytes(self) -> bytes:
387 return rust_x509.encode_extension_value(self)
390class AccessDescription:
391 def __init__(
392 self, access_method: ObjectIdentifier, access_location: GeneralName
393 ) -> None:
394 if not isinstance(access_method, ObjectIdentifier):
395 raise TypeError("access_method must be an ObjectIdentifier")
397 if not isinstance(access_location, GeneralName):
398 raise TypeError("access_location must be a GeneralName")
400 self._access_method = access_method
401 self._access_location = access_location
403 def __repr__(self) -> str:
404 return (
405 "<AccessDescription(access_method={0.access_method}, access_locati"
406 "on={0.access_location})>".format(self)
407 )
409 def __eq__(self, other: object) -> bool:
410 if not isinstance(other, AccessDescription):
411 return NotImplemented
413 return (
414 self.access_method == other.access_method
415 and self.access_location == other.access_location
416 )
418 def __hash__(self) -> int:
419 return hash((self.access_method, self.access_location))
421 @property
422 def access_method(self) -> ObjectIdentifier:
423 return self._access_method
425 @property
426 def access_location(self) -> GeneralName:
427 return self._access_location
430class BasicConstraints(ExtensionType):
431 oid = ExtensionOID.BASIC_CONSTRAINTS
433 def __init__(self, ca: bool, path_length: typing.Optional[int]) -> None:
434 if not isinstance(ca, bool):
435 raise TypeError("ca must be a boolean value")
437 if path_length is not None and not ca:
438 raise ValueError("path_length must be None when ca is False")
440 if path_length is not None and (
441 not isinstance(path_length, int) or path_length < 0
442 ):
443 raise TypeError(
444 "path_length must be a non-negative integer or None"
445 )
447 self._ca = ca
448 self._path_length = path_length
450 @property
451 def ca(self) -> bool:
452 return self._ca
454 @property
455 def path_length(self) -> typing.Optional[int]:
456 return self._path_length
458 def __repr__(self) -> str:
459 return (
460 "<BasicConstraints(ca={0.ca}, " "path_length={0.path_length})>"
461 ).format(self)
463 def __eq__(self, other: object) -> bool:
464 if not isinstance(other, BasicConstraints):
465 return NotImplemented
467 return self.ca == other.ca and self.path_length == other.path_length
469 def __hash__(self) -> int:
470 return hash((self.ca, self.path_length))
472 def public_bytes(self) -> bytes:
473 return rust_x509.encode_extension_value(self)
476class DeltaCRLIndicator(ExtensionType):
477 oid = ExtensionOID.DELTA_CRL_INDICATOR
479 def __init__(self, crl_number: int) -> None:
480 if not isinstance(crl_number, int):
481 raise TypeError("crl_number must be an integer")
483 self._crl_number = crl_number
485 @property
486 def crl_number(self) -> int:
487 return self._crl_number
489 def __eq__(self, other: object) -> bool:
490 if not isinstance(other, DeltaCRLIndicator):
491 return NotImplemented
493 return self.crl_number == other.crl_number
495 def __hash__(self) -> int:
496 return hash(self.crl_number)
498 def __repr__(self) -> str:
499 return f"<DeltaCRLIndicator(crl_number={self.crl_number})>"
501 def public_bytes(self) -> bytes:
502 return rust_x509.encode_extension_value(self)
505class CRLDistributionPoints(ExtensionType):
506 oid = ExtensionOID.CRL_DISTRIBUTION_POINTS
508 def __init__(
509 self, distribution_points: typing.Iterable["DistributionPoint"]
510 ) -> None:
511 distribution_points = list(distribution_points)
512 if not all(
513 isinstance(x, DistributionPoint) for x in distribution_points
514 ):
515 raise TypeError(
516 "distribution_points must be a list of DistributionPoint "
517 "objects"
518 )
520 self._distribution_points = distribution_points
522 __len__, __iter__, __getitem__ = _make_sequence_methods(
523 "_distribution_points"
524 )
526 def __repr__(self) -> str:
527 return f"<CRLDistributionPoints({self._distribution_points})>"
529 def __eq__(self, other: object) -> bool:
530 if not isinstance(other, CRLDistributionPoints):
531 return NotImplemented
533 return self._distribution_points == other._distribution_points
535 def __hash__(self) -> int:
536 return hash(tuple(self._distribution_points))
538 def public_bytes(self) -> bytes:
539 return rust_x509.encode_extension_value(self)
542class FreshestCRL(ExtensionType):
543 oid = ExtensionOID.FRESHEST_CRL
545 def __init__(
546 self, distribution_points: typing.Iterable["DistributionPoint"]
547 ) -> None:
548 distribution_points = list(distribution_points)
549 if not all(
550 isinstance(x, DistributionPoint) for x in distribution_points
551 ):
552 raise TypeError(
553 "distribution_points must be a list of DistributionPoint "
554 "objects"
555 )
557 self._distribution_points = distribution_points
559 __len__, __iter__, __getitem__ = _make_sequence_methods(
560 "_distribution_points"
561 )
563 def __repr__(self) -> str:
564 return f"<FreshestCRL({self._distribution_points})>"
566 def __eq__(self, other: object) -> bool:
567 if not isinstance(other, FreshestCRL):
568 return NotImplemented
570 return self._distribution_points == other._distribution_points
572 def __hash__(self) -> int:
573 return hash(tuple(self._distribution_points))
575 def public_bytes(self) -> bytes:
576 return rust_x509.encode_extension_value(self)
579class DistributionPoint:
580 def __init__(
581 self,
582 full_name: typing.Optional[typing.Iterable[GeneralName]],
583 relative_name: typing.Optional[RelativeDistinguishedName],
584 reasons: typing.Optional[typing.FrozenSet["ReasonFlags"]],
585 crl_issuer: typing.Optional[typing.Iterable[GeneralName]],
586 ) -> None:
587 if full_name and relative_name:
588 raise ValueError(
589 "You cannot provide both full_name and relative_name, at "
590 "least one must be None."
591 )
592 if not full_name and not relative_name and not crl_issuer:
593 raise ValueError(
594 "Either full_name, relative_name or crl_issuer must be "
595 "provided."
596 )
598 if full_name is not None:
599 full_name = list(full_name)
600 if not all(isinstance(x, GeneralName) for x in full_name):
601 raise TypeError(
602 "full_name must be a list of GeneralName objects"
603 )
605 if relative_name:
606 if not isinstance(relative_name, RelativeDistinguishedName):
607 raise TypeError(
608 "relative_name must be a RelativeDistinguishedName"
609 )
611 if crl_issuer is not None:
612 crl_issuer = list(crl_issuer)
613 if not all(isinstance(x, GeneralName) for x in crl_issuer):
614 raise TypeError(
615 "crl_issuer must be None or a list of general names"
616 )
618 if reasons and (
619 not isinstance(reasons, frozenset)
620 or not all(isinstance(x, ReasonFlags) for x in reasons)
621 ):
622 raise TypeError("reasons must be None or frozenset of ReasonFlags")
624 if reasons and (
625 ReasonFlags.unspecified in reasons
626 or ReasonFlags.remove_from_crl in reasons
627 ):
628 raise ValueError(
629 "unspecified and remove_from_crl are not valid reasons in a "
630 "DistributionPoint"
631 )
633 self._full_name = full_name
634 self._relative_name = relative_name
635 self._reasons = reasons
636 self._crl_issuer = crl_issuer
638 def __repr__(self) -> str:
639 return (
640 "<DistributionPoint(full_name={0.full_name}, relative_name={0.rela"
641 "tive_name}, reasons={0.reasons}, "
642 "crl_issuer={0.crl_issuer})>".format(self)
643 )
645 def __eq__(self, other: object) -> bool:
646 if not isinstance(other, DistributionPoint):
647 return NotImplemented
649 return (
650 self.full_name == other.full_name
651 and self.relative_name == other.relative_name
652 and self.reasons == other.reasons
653 and self.crl_issuer == other.crl_issuer
654 )
656 def __hash__(self) -> int:
657 if self.full_name is not None:
658 fn: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple(
659 self.full_name
660 )
661 else:
662 fn = None
664 if self.crl_issuer is not None:
665 crl_issuer: typing.Optional[
666 typing.Tuple[GeneralName, ...]
667 ] = tuple(self.crl_issuer)
668 else:
669 crl_issuer = None
671 return hash((fn, self.relative_name, self.reasons, crl_issuer))
673 @property
674 def full_name(self) -> typing.Optional[typing.List[GeneralName]]:
675 return self._full_name
677 @property
678 def relative_name(self) -> typing.Optional[RelativeDistinguishedName]:
679 return self._relative_name
681 @property
682 def reasons(self) -> typing.Optional[typing.FrozenSet["ReasonFlags"]]:
683 return self._reasons
685 @property
686 def crl_issuer(self) -> typing.Optional[typing.List[GeneralName]]:
687 return self._crl_issuer
690class ReasonFlags(utils.Enum):
691 unspecified = "unspecified"
692 key_compromise = "keyCompromise"
693 ca_compromise = "cACompromise"
694 affiliation_changed = "affiliationChanged"
695 superseded = "superseded"
696 cessation_of_operation = "cessationOfOperation"
697 certificate_hold = "certificateHold"
698 privilege_withdrawn = "privilegeWithdrawn"
699 aa_compromise = "aACompromise"
700 remove_from_crl = "removeFromCRL"
703# These are distribution point bit string mappings. Not to be confused with
704# CRLReason reason flags bit string mappings.
705# ReasonFlags ::= BIT STRING {
706# unused (0),
707# keyCompromise (1),
708# cACompromise (2),
709# affiliationChanged (3),
710# superseded (4),
711# cessationOfOperation (5),
712# certificateHold (6),
713# privilegeWithdrawn (7),
714# aACompromise (8) }
715_REASON_BIT_MAPPING = {
716 1: ReasonFlags.key_compromise,
717 2: ReasonFlags.ca_compromise,
718 3: ReasonFlags.affiliation_changed,
719 4: ReasonFlags.superseded,
720 5: ReasonFlags.cessation_of_operation,
721 6: ReasonFlags.certificate_hold,
722 7: ReasonFlags.privilege_withdrawn,
723 8: ReasonFlags.aa_compromise,
724}
726_CRLREASONFLAGS = {
727 ReasonFlags.key_compromise: 1,
728 ReasonFlags.ca_compromise: 2,
729 ReasonFlags.affiliation_changed: 3,
730 ReasonFlags.superseded: 4,
731 ReasonFlags.cessation_of_operation: 5,
732 ReasonFlags.certificate_hold: 6,
733 ReasonFlags.privilege_withdrawn: 7,
734 ReasonFlags.aa_compromise: 8,
735}
738class PolicyConstraints(ExtensionType):
739 oid = ExtensionOID.POLICY_CONSTRAINTS
741 def __init__(
742 self,
743 require_explicit_policy: typing.Optional[int],
744 inhibit_policy_mapping: typing.Optional[int],
745 ) -> None:
746 if require_explicit_policy is not None and not isinstance(
747 require_explicit_policy, int
748 ):
749 raise TypeError(
750 "require_explicit_policy must be a non-negative integer or "
751 "None"
752 )
754 if inhibit_policy_mapping is not None and not isinstance(
755 inhibit_policy_mapping, int
756 ):
757 raise TypeError(
758 "inhibit_policy_mapping must be a non-negative integer or None"
759 )
761 if inhibit_policy_mapping is None and require_explicit_policy is None:
762 raise ValueError(
763 "At least one of require_explicit_policy and "
764 "inhibit_policy_mapping must not be None"
765 )
767 self._require_explicit_policy = require_explicit_policy
768 self._inhibit_policy_mapping = inhibit_policy_mapping
770 def __repr__(self) -> str:
771 return (
772 "<PolicyConstraints(require_explicit_policy={0.require_explicit"
773 "_policy}, inhibit_policy_mapping={0.inhibit_policy_"
774 "mapping})>".format(self)
775 )
777 def __eq__(self, other: object) -> bool:
778 if not isinstance(other, PolicyConstraints):
779 return NotImplemented
781 return (
782 self.require_explicit_policy == other.require_explicit_policy
783 and self.inhibit_policy_mapping == other.inhibit_policy_mapping
784 )
786 def __hash__(self) -> int:
787 return hash(
788 (self.require_explicit_policy, self.inhibit_policy_mapping)
789 )
791 @property
792 def require_explicit_policy(self) -> typing.Optional[int]:
793 return self._require_explicit_policy
795 @property
796 def inhibit_policy_mapping(self) -> typing.Optional[int]:
797 return self._inhibit_policy_mapping
799 def public_bytes(self) -> bytes:
800 return rust_x509.encode_extension_value(self)
803class CertificatePolicies(ExtensionType):
804 oid = ExtensionOID.CERTIFICATE_POLICIES
806 def __init__(self, policies: typing.Iterable["PolicyInformation"]) -> None:
807 policies = list(policies)
808 if not all(isinstance(x, PolicyInformation) for x in policies):
809 raise TypeError(
810 "Every item in the policies list must be a "
811 "PolicyInformation"
812 )
814 self._policies = policies
816 __len__, __iter__, __getitem__ = _make_sequence_methods("_policies")
818 def __repr__(self) -> str:
819 return f"<CertificatePolicies({self._policies})>"
821 def __eq__(self, other: object) -> bool:
822 if not isinstance(other, CertificatePolicies):
823 return NotImplemented
825 return self._policies == other._policies
827 def __hash__(self) -> int:
828 return hash(tuple(self._policies))
830 def public_bytes(self) -> bytes:
831 return rust_x509.encode_extension_value(self)
834class PolicyInformation:
835 def __init__(
836 self,
837 policy_identifier: ObjectIdentifier,
838 policy_qualifiers: typing.Optional[
839 typing.Iterable[typing.Union[str, "UserNotice"]]
840 ],
841 ) -> None:
842 if not isinstance(policy_identifier, ObjectIdentifier):
843 raise TypeError("policy_identifier must be an ObjectIdentifier")
845 self._policy_identifier = policy_identifier
847 if policy_qualifiers is not None:
848 policy_qualifiers = list(policy_qualifiers)
849 if not all(
850 isinstance(x, (str, UserNotice)) for x in policy_qualifiers
851 ):
852 raise TypeError(
853 "policy_qualifiers must be a list of strings and/or "
854 "UserNotice objects or None"
855 )
857 self._policy_qualifiers = policy_qualifiers
859 def __repr__(self) -> str:
860 return (
861 "<PolicyInformation(policy_identifier={0.policy_identifier}, polic"
862 "y_qualifiers={0.policy_qualifiers})>".format(self)
863 )
865 def __eq__(self, other: object) -> bool:
866 if not isinstance(other, PolicyInformation):
867 return NotImplemented
869 return (
870 self.policy_identifier == other.policy_identifier
871 and self.policy_qualifiers == other.policy_qualifiers
872 )
874 def __hash__(self) -> int:
875 if self.policy_qualifiers is not None:
876 pq: typing.Optional[
877 typing.Tuple[typing.Union[str, "UserNotice"], ...]
878 ] = tuple(self.policy_qualifiers)
879 else:
880 pq = None
882 return hash((self.policy_identifier, pq))
884 @property
885 def policy_identifier(self) -> ObjectIdentifier:
886 return self._policy_identifier
888 @property
889 def policy_qualifiers(
890 self,
891 ) -> typing.Optional[typing.List[typing.Union[str, "UserNotice"]]]:
892 return self._policy_qualifiers
895class UserNotice:
896 def __init__(
897 self,
898 notice_reference: typing.Optional["NoticeReference"],
899 explicit_text: typing.Optional[str],
900 ) -> None:
901 if notice_reference and not isinstance(
902 notice_reference, NoticeReference
903 ):
904 raise TypeError(
905 "notice_reference must be None or a NoticeReference"
906 )
908 self._notice_reference = notice_reference
909 self._explicit_text = explicit_text
911 def __repr__(self) -> str:
912 return (
913 "<UserNotice(notice_reference={0.notice_reference}, explicit_text="
914 "{0.explicit_text!r})>".format(self)
915 )
917 def __eq__(self, other: object) -> bool:
918 if not isinstance(other, UserNotice):
919 return NotImplemented
921 return (
922 self.notice_reference == other.notice_reference
923 and self.explicit_text == other.explicit_text
924 )
926 def __hash__(self) -> int:
927 return hash((self.notice_reference, self.explicit_text))
929 @property
930 def notice_reference(self) -> typing.Optional["NoticeReference"]:
931 return self._notice_reference
933 @property
934 def explicit_text(self) -> typing.Optional[str]:
935 return self._explicit_text
938class NoticeReference:
939 def __init__(
940 self,
941 organization: typing.Optional[str],
942 notice_numbers: typing.Iterable[int],
943 ) -> None:
944 self._organization = organization
945 notice_numbers = list(notice_numbers)
946 if not all(isinstance(x, int) for x in notice_numbers):
947 raise TypeError("notice_numbers must be a list of integers")
949 self._notice_numbers = notice_numbers
951 def __repr__(self) -> str:
952 return (
953 "<NoticeReference(organization={0.organization!r}, notice_numbers="
954 "{0.notice_numbers})>".format(self)
955 )
957 def __eq__(self, other: object) -> bool:
958 if not isinstance(other, NoticeReference):
959 return NotImplemented
961 return (
962 self.organization == other.organization
963 and self.notice_numbers == other.notice_numbers
964 )
966 def __hash__(self) -> int:
967 return hash((self.organization, tuple(self.notice_numbers)))
969 @property
970 def organization(self) -> typing.Optional[str]:
971 return self._organization
973 @property
974 def notice_numbers(self) -> typing.List[int]:
975 return self._notice_numbers
978class ExtendedKeyUsage(ExtensionType):
979 oid = ExtensionOID.EXTENDED_KEY_USAGE
981 def __init__(self, usages: typing.Iterable[ObjectIdentifier]) -> None:
982 usages = list(usages)
983 if not all(isinstance(x, ObjectIdentifier) for x in usages):
984 raise TypeError(
985 "Every item in the usages list must be an ObjectIdentifier"
986 )
988 self._usages = usages
990 __len__, __iter__, __getitem__ = _make_sequence_methods("_usages")
992 def __repr__(self) -> str:
993 return f"<ExtendedKeyUsage({self._usages})>"
995 def __eq__(self, other: object) -> bool:
996 if not isinstance(other, ExtendedKeyUsage):
997 return NotImplemented
999 return self._usages == other._usages
1001 def __hash__(self) -> int:
1002 return hash(tuple(self._usages))
1004 def public_bytes(self) -> bytes:
1005 return rust_x509.encode_extension_value(self)
1008class OCSPNoCheck(ExtensionType):
1009 oid = ExtensionOID.OCSP_NO_CHECK
1011 def __eq__(self, other: object) -> bool:
1012 if not isinstance(other, OCSPNoCheck):
1013 return NotImplemented
1015 return True
1017 def __hash__(self) -> int:
1018 return hash(OCSPNoCheck)
1020 def __repr__(self) -> str:
1021 return "<OCSPNoCheck()>"
1023 def public_bytes(self) -> bytes:
1024 return rust_x509.encode_extension_value(self)
1027class PrecertPoison(ExtensionType):
1028 oid = ExtensionOID.PRECERT_POISON
1030 def __eq__(self, other: object) -> bool:
1031 if not isinstance(other, PrecertPoison):
1032 return NotImplemented
1034 return True
1036 def __hash__(self) -> int:
1037 return hash(PrecertPoison)
1039 def __repr__(self) -> str:
1040 return "<PrecertPoison()>"
1042 def public_bytes(self) -> bytes:
1043 return rust_x509.encode_extension_value(self)
1046class TLSFeature(ExtensionType):
1047 oid = ExtensionOID.TLS_FEATURE
1049 def __init__(self, features: typing.Iterable["TLSFeatureType"]) -> None:
1050 features = list(features)
1051 if (
1052 not all(isinstance(x, TLSFeatureType) for x in features)
1053 or len(features) == 0
1054 ):
1055 raise TypeError(
1056 "features must be a list of elements from the TLSFeatureType "
1057 "enum"
1058 )
1060 self._features = features
1062 __len__, __iter__, __getitem__ = _make_sequence_methods("_features")
1064 def __repr__(self) -> str:
1065 return f"<TLSFeature(features={self._features})>"
1067 def __eq__(self, other: object) -> bool:
1068 if not isinstance(other, TLSFeature):
1069 return NotImplemented
1071 return self._features == other._features
1073 def __hash__(self) -> int:
1074 return hash(tuple(self._features))
1076 def public_bytes(self) -> bytes:
1077 return rust_x509.encode_extension_value(self)
1080class TLSFeatureType(utils.Enum):
1081 # status_request is defined in RFC 6066 and is used for what is commonly
1082 # called OCSP Must-Staple when present in the TLS Feature extension in an
1083 # X.509 certificate.
1084 status_request = 5
1085 # status_request_v2 is defined in RFC 6961 and allows multiple OCSP
1086 # responses to be provided. It is not currently in use by clients or
1087 # servers.
1088 status_request_v2 = 17
1091_TLS_FEATURE_TYPE_TO_ENUM = {x.value: x for x in TLSFeatureType}
1094class InhibitAnyPolicy(ExtensionType):
1095 oid = ExtensionOID.INHIBIT_ANY_POLICY
1097 def __init__(self, skip_certs: int) -> None:
1098 if not isinstance(skip_certs, int):
1099 raise TypeError("skip_certs must be an integer")
1101 if skip_certs < 0:
1102 raise ValueError("skip_certs must be a non-negative integer")
1104 self._skip_certs = skip_certs
1106 def __repr__(self) -> str:
1107 return f"<InhibitAnyPolicy(skip_certs={self.skip_certs})>"
1109 def __eq__(self, other: object) -> bool:
1110 if not isinstance(other, InhibitAnyPolicy):
1111 return NotImplemented
1113 return self.skip_certs == other.skip_certs
1115 def __hash__(self) -> int:
1116 return hash(self.skip_certs)
1118 @property
1119 def skip_certs(self) -> int:
1120 return self._skip_certs
1122 def public_bytes(self) -> bytes:
1123 return rust_x509.encode_extension_value(self)
1126class KeyUsage(ExtensionType):
1127 oid = ExtensionOID.KEY_USAGE
1129 def __init__(
1130 self,
1131 digital_signature: bool,
1132 content_commitment: bool,
1133 key_encipherment: bool,
1134 data_encipherment: bool,
1135 key_agreement: bool,
1136 key_cert_sign: bool,
1137 crl_sign: bool,
1138 encipher_only: bool,
1139 decipher_only: bool,
1140 ) -> None:
1141 if not key_agreement and (encipher_only or decipher_only):
1142 raise ValueError(
1143 "encipher_only and decipher_only can only be true when "
1144 "key_agreement is true"
1145 )
1147 self._digital_signature = digital_signature
1148 self._content_commitment = content_commitment
1149 self._key_encipherment = key_encipherment
1150 self._data_encipherment = data_encipherment
1151 self._key_agreement = key_agreement
1152 self._key_cert_sign = key_cert_sign
1153 self._crl_sign = crl_sign
1154 self._encipher_only = encipher_only
1155 self._decipher_only = decipher_only
1157 @property
1158 def digital_signature(self) -> bool:
1159 return self._digital_signature
1161 @property
1162 def content_commitment(self) -> bool:
1163 return self._content_commitment
1165 @property
1166 def key_encipherment(self) -> bool:
1167 return self._key_encipherment
1169 @property
1170 def data_encipherment(self) -> bool:
1171 return self._data_encipherment
1173 @property
1174 def key_agreement(self) -> bool:
1175 return self._key_agreement
1177 @property
1178 def key_cert_sign(self) -> bool:
1179 return self._key_cert_sign
1181 @property
1182 def crl_sign(self) -> bool:
1183 return self._crl_sign
1185 @property
1186 def encipher_only(self) -> bool:
1187 if not self.key_agreement:
1188 raise ValueError(
1189 "encipher_only is undefined unless key_agreement is true"
1190 )
1191 else:
1192 return self._encipher_only
1194 @property
1195 def decipher_only(self) -> bool:
1196 if not self.key_agreement:
1197 raise ValueError(
1198 "decipher_only is undefined unless key_agreement is true"
1199 )
1200 else:
1201 return self._decipher_only
1203 def __repr__(self) -> str:
1204 try:
1205 encipher_only = self.encipher_only
1206 decipher_only = self.decipher_only
1207 except ValueError:
1208 # Users found None confusing because even though encipher/decipher
1209 # have no meaning unless key_agreement is true, to construct an
1210 # instance of the class you still need to pass False.
1211 encipher_only = False
1212 decipher_only = False
1214 return (
1215 "<KeyUsage(digital_signature={0.digital_signature}, "
1216 "content_commitment={0.content_commitment}, "
1217 "key_encipherment={0.key_encipherment}, "
1218 "data_encipherment={0.data_encipherment}, "
1219 "key_agreement={0.key_agreement}, "
1220 "key_cert_sign={0.key_cert_sign}, crl_sign={0.crl_sign}, "
1221 "encipher_only={1}, decipher_only={2})>"
1222 ).format(self, encipher_only, decipher_only)
1224 def __eq__(self, other: object) -> bool:
1225 if not isinstance(other, KeyUsage):
1226 return NotImplemented
1228 return (
1229 self.digital_signature == other.digital_signature
1230 and self.content_commitment == other.content_commitment
1231 and self.key_encipherment == other.key_encipherment
1232 and self.data_encipherment == other.data_encipherment
1233 and self.key_agreement == other.key_agreement
1234 and self.key_cert_sign == other.key_cert_sign
1235 and self.crl_sign == other.crl_sign
1236 and self._encipher_only == other._encipher_only
1237 and self._decipher_only == other._decipher_only
1238 )
1240 def __hash__(self) -> int:
1241 return hash(
1242 (
1243 self.digital_signature,
1244 self.content_commitment,
1245 self.key_encipherment,
1246 self.data_encipherment,
1247 self.key_agreement,
1248 self.key_cert_sign,
1249 self.crl_sign,
1250 self._encipher_only,
1251 self._decipher_only,
1252 )
1253 )
1255 def public_bytes(self) -> bytes:
1256 return rust_x509.encode_extension_value(self)
1259class NameConstraints(ExtensionType):
1260 oid = ExtensionOID.NAME_CONSTRAINTS
1262 def __init__(
1263 self,
1264 permitted_subtrees: typing.Optional[typing.Iterable[GeneralName]],
1265 excluded_subtrees: typing.Optional[typing.Iterable[GeneralName]],
1266 ) -> None:
1267 if permitted_subtrees is not None:
1268 permitted_subtrees = list(permitted_subtrees)
1269 if not permitted_subtrees:
1270 raise ValueError(
1271 "permitted_subtrees must be a non-empty list or None"
1272 )
1273 if not all(isinstance(x, GeneralName) for x in permitted_subtrees):
1274 raise TypeError(
1275 "permitted_subtrees must be a list of GeneralName objects "
1276 "or None"
1277 )
1279 self._validate_tree(permitted_subtrees)
1281 if excluded_subtrees is not None:
1282 excluded_subtrees = list(excluded_subtrees)
1283 if not excluded_subtrees:
1284 raise ValueError(
1285 "excluded_subtrees must be a non-empty list or None"
1286 )
1287 if not all(isinstance(x, GeneralName) for x in excluded_subtrees):
1288 raise TypeError(
1289 "excluded_subtrees must be a list of GeneralName objects "
1290 "or None"
1291 )
1293 self._validate_tree(excluded_subtrees)
1295 if permitted_subtrees is None and excluded_subtrees is None:
1296 raise ValueError(
1297 "At least one of permitted_subtrees and excluded_subtrees "
1298 "must not be None"
1299 )
1301 self._permitted_subtrees = permitted_subtrees
1302 self._excluded_subtrees = excluded_subtrees
1304 def __eq__(self, other: object) -> bool:
1305 if not isinstance(other, NameConstraints):
1306 return NotImplemented
1308 return (
1309 self.excluded_subtrees == other.excluded_subtrees
1310 and self.permitted_subtrees == other.permitted_subtrees
1311 )
1313 def _validate_tree(self, tree: typing.Iterable[GeneralName]) -> None:
1314 self._validate_ip_name(tree)
1315 self._validate_dns_name(tree)
1317 def _validate_ip_name(self, tree: typing.Iterable[GeneralName]) -> None:
1318 if any(
1319 isinstance(name, IPAddress)
1320 and not isinstance(
1321 name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network)
1322 )
1323 for name in tree
1324 ):
1325 raise TypeError(
1326 "IPAddress name constraints must be an IPv4Network or"
1327 " IPv6Network object"
1328 )
1330 def _validate_dns_name(self, tree: typing.Iterable[GeneralName]) -> None:
1331 if any(
1332 isinstance(name, DNSName) and "*" in name.value for name in tree
1333 ):
1334 raise ValueError(
1335 "DNSName name constraints must not contain the '*' wildcard"
1336 " character"
1337 )
1339 def __repr__(self) -> str:
1340 return (
1341 "<NameConstraints(permitted_subtrees={0.permitted_subtrees}, "
1342 "excluded_subtrees={0.excluded_subtrees})>".format(self)
1343 )
1345 def __hash__(self) -> int:
1346 if self.permitted_subtrees is not None:
1347 ps: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple(
1348 self.permitted_subtrees
1349 )
1350 else:
1351 ps = None
1353 if self.excluded_subtrees is not None:
1354 es: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple(
1355 self.excluded_subtrees
1356 )
1357 else:
1358 es = None
1360 return hash((ps, es))
1362 @property
1363 def permitted_subtrees(
1364 self,
1365 ) -> typing.Optional[typing.List[GeneralName]]:
1366 return self._permitted_subtrees
1368 @property
1369 def excluded_subtrees(
1370 self,
1371 ) -> typing.Optional[typing.List[GeneralName]]:
1372 return self._excluded_subtrees
1374 def public_bytes(self) -> bytes:
1375 return rust_x509.encode_extension_value(self)
1378class Extension(typing.Generic[ExtensionTypeVar]):
1379 def __init__(
1380 self, oid: ObjectIdentifier, critical: bool, value: ExtensionTypeVar
1381 ) -> None:
1382 if not isinstance(oid, ObjectIdentifier):
1383 raise TypeError(
1384 "oid argument must be an ObjectIdentifier instance."
1385 )
1387 if not isinstance(critical, bool):
1388 raise TypeError("critical must be a boolean value")
1390 self._oid = oid
1391 self._critical = critical
1392 self._value = value
1394 @property
1395 def oid(self) -> ObjectIdentifier:
1396 return self._oid
1398 @property
1399 def critical(self) -> bool:
1400 return self._critical
1402 @property
1403 def value(self) -> ExtensionTypeVar:
1404 return self._value
1406 def __repr__(self) -> str:
1407 return (
1408 "<Extension(oid={0.oid}, critical={0.critical}, "
1409 "value={0.value})>"
1410 ).format(self)
1412 def __eq__(self, other: object) -> bool:
1413 if not isinstance(other, Extension):
1414 return NotImplemented
1416 return (
1417 self.oid == other.oid
1418 and self.critical == other.critical
1419 and self.value == other.value
1420 )
1422 def __hash__(self) -> int:
1423 return hash((self.oid, self.critical, self.value))
1426class GeneralNames:
1427 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None:
1428 general_names = list(general_names)
1429 if not all(isinstance(x, GeneralName) for x in general_names):
1430 raise TypeError(
1431 "Every item in the general_names list must be an "
1432 "object conforming to the GeneralName interface"
1433 )
1435 self._general_names = general_names
1437 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1439 @typing.overload
1440 def get_values_for_type(
1441 self,
1442 type: typing.Union[
1443 typing.Type[DNSName],
1444 typing.Type[UniformResourceIdentifier],
1445 typing.Type[RFC822Name],
1446 ],
1447 ) -> typing.List[str]:
1448 ...
1450 @typing.overload
1451 def get_values_for_type(
1452 self,
1453 type: typing.Type[DirectoryName],
1454 ) -> typing.List[Name]:
1455 ...
1457 @typing.overload
1458 def get_values_for_type(
1459 self,
1460 type: typing.Type[RegisteredID],
1461 ) -> typing.List[ObjectIdentifier]:
1462 ...
1464 @typing.overload
1465 def get_values_for_type(
1466 self, type: typing.Type[IPAddress]
1467 ) -> typing.List[_IPAddressTypes]:
1468 ...
1470 @typing.overload
1471 def get_values_for_type(
1472 self, type: typing.Type[OtherName]
1473 ) -> typing.List[OtherName]:
1474 ...
1476 def get_values_for_type(
1477 self,
1478 type: typing.Union[
1479 typing.Type[DNSName],
1480 typing.Type[DirectoryName],
1481 typing.Type[IPAddress],
1482 typing.Type[OtherName],
1483 typing.Type[RFC822Name],
1484 typing.Type[RegisteredID],
1485 typing.Type[UniformResourceIdentifier],
1486 ],
1487 ) -> typing.Union[
1488 typing.List[_IPAddressTypes],
1489 typing.List[str],
1490 typing.List[OtherName],
1491 typing.List[Name],
1492 typing.List[ObjectIdentifier],
1493 ]:
1494 # Return the value of each GeneralName, except for OtherName instances
1495 # which we return directly because it has two important properties not
1496 # just one value.
1497 objs = (i for i in self if isinstance(i, type))
1498 if type != OtherName:
1499 return [i.value for i in objs]
1500 return list(objs)
1502 def __repr__(self) -> str:
1503 return f"<GeneralNames({self._general_names})>"
1505 def __eq__(self, other: object) -> bool:
1506 if not isinstance(other, GeneralNames):
1507 return NotImplemented
1509 return self._general_names == other._general_names
1511 def __hash__(self) -> int:
1512 return hash(tuple(self._general_names))
1515class SubjectAlternativeName(ExtensionType):
1516 oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME
1518 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None:
1519 self._general_names = GeneralNames(general_names)
1521 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1523 @typing.overload
1524 def get_values_for_type(
1525 self,
1526 type: typing.Union[
1527 typing.Type[DNSName],
1528 typing.Type[UniformResourceIdentifier],
1529 typing.Type[RFC822Name],
1530 ],
1531 ) -> typing.List[str]:
1532 ...
1534 @typing.overload
1535 def get_values_for_type(
1536 self,
1537 type: typing.Type[DirectoryName],
1538 ) -> typing.List[Name]:
1539 ...
1541 @typing.overload
1542 def get_values_for_type(
1543 self,
1544 type: typing.Type[RegisteredID],
1545 ) -> typing.List[ObjectIdentifier]:
1546 ...
1548 @typing.overload
1549 def get_values_for_type(
1550 self, type: typing.Type[IPAddress]
1551 ) -> typing.List[_IPAddressTypes]:
1552 ...
1554 @typing.overload
1555 def get_values_for_type(
1556 self, type: typing.Type[OtherName]
1557 ) -> typing.List[OtherName]:
1558 ...
1560 def get_values_for_type(
1561 self,
1562 type: typing.Union[
1563 typing.Type[DNSName],
1564 typing.Type[DirectoryName],
1565 typing.Type[IPAddress],
1566 typing.Type[OtherName],
1567 typing.Type[RFC822Name],
1568 typing.Type[RegisteredID],
1569 typing.Type[UniformResourceIdentifier],
1570 ],
1571 ) -> typing.Union[
1572 typing.List[_IPAddressTypes],
1573 typing.List[str],
1574 typing.List[OtherName],
1575 typing.List[Name],
1576 typing.List[ObjectIdentifier],
1577 ]:
1578 return self._general_names.get_values_for_type(type)
1580 def __repr__(self) -> str:
1581 return f"<SubjectAlternativeName({self._general_names})>"
1583 def __eq__(self, other: object) -> bool:
1584 if not isinstance(other, SubjectAlternativeName):
1585 return NotImplemented
1587 return self._general_names == other._general_names
1589 def __hash__(self) -> int:
1590 return hash(self._general_names)
1592 def public_bytes(self) -> bytes:
1593 return rust_x509.encode_extension_value(self)
1596class IssuerAlternativeName(ExtensionType):
1597 oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME
1599 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None:
1600 self._general_names = GeneralNames(general_names)
1602 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1604 @typing.overload
1605 def get_values_for_type(
1606 self,
1607 type: typing.Union[
1608 typing.Type[DNSName],
1609 typing.Type[UniformResourceIdentifier],
1610 typing.Type[RFC822Name],
1611 ],
1612 ) -> typing.List[str]:
1613 ...
1615 @typing.overload
1616 def get_values_for_type(
1617 self,
1618 type: typing.Type[DirectoryName],
1619 ) -> typing.List[Name]:
1620 ...
1622 @typing.overload
1623 def get_values_for_type(
1624 self,
1625 type: typing.Type[RegisteredID],
1626 ) -> typing.List[ObjectIdentifier]:
1627 ...
1629 @typing.overload
1630 def get_values_for_type(
1631 self, type: typing.Type[IPAddress]
1632 ) -> typing.List[_IPAddressTypes]:
1633 ...
1635 @typing.overload
1636 def get_values_for_type(
1637 self, type: typing.Type[OtherName]
1638 ) -> typing.List[OtherName]:
1639 ...
1641 def get_values_for_type(
1642 self,
1643 type: typing.Union[
1644 typing.Type[DNSName],
1645 typing.Type[DirectoryName],
1646 typing.Type[IPAddress],
1647 typing.Type[OtherName],
1648 typing.Type[RFC822Name],
1649 typing.Type[RegisteredID],
1650 typing.Type[UniformResourceIdentifier],
1651 ],
1652 ) -> typing.Union[
1653 typing.List[_IPAddressTypes],
1654 typing.List[str],
1655 typing.List[OtherName],
1656 typing.List[Name],
1657 typing.List[ObjectIdentifier],
1658 ]:
1659 return self._general_names.get_values_for_type(type)
1661 def __repr__(self) -> str:
1662 return f"<IssuerAlternativeName({self._general_names})>"
1664 def __eq__(self, other: object) -> bool:
1665 if not isinstance(other, IssuerAlternativeName):
1666 return NotImplemented
1668 return self._general_names == other._general_names
1670 def __hash__(self) -> int:
1671 return hash(self._general_names)
1673 def public_bytes(self) -> bytes:
1674 return rust_x509.encode_extension_value(self)
1677class CertificateIssuer(ExtensionType):
1678 oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER
1680 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None:
1681 self._general_names = GeneralNames(general_names)
1683 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1685 @typing.overload
1686 def get_values_for_type(
1687 self,
1688 type: typing.Union[
1689 typing.Type[DNSName],
1690 typing.Type[UniformResourceIdentifier],
1691 typing.Type[RFC822Name],
1692 ],
1693 ) -> typing.List[str]:
1694 ...
1696 @typing.overload
1697 def get_values_for_type(
1698 self,
1699 type: typing.Type[DirectoryName],
1700 ) -> typing.List[Name]:
1701 ...
1703 @typing.overload
1704 def get_values_for_type(
1705 self,
1706 type: typing.Type[RegisteredID],
1707 ) -> typing.List[ObjectIdentifier]:
1708 ...
1710 @typing.overload
1711 def get_values_for_type(
1712 self, type: typing.Type[IPAddress]
1713 ) -> typing.List[_IPAddressTypes]:
1714 ...
1716 @typing.overload
1717 def get_values_for_type(
1718 self, type: typing.Type[OtherName]
1719 ) -> typing.List[OtherName]:
1720 ...
1722 def get_values_for_type(
1723 self,
1724 type: typing.Union[
1725 typing.Type[DNSName],
1726 typing.Type[DirectoryName],
1727 typing.Type[IPAddress],
1728 typing.Type[OtherName],
1729 typing.Type[RFC822Name],
1730 typing.Type[RegisteredID],
1731 typing.Type[UniformResourceIdentifier],
1732 ],
1733 ) -> typing.Union[
1734 typing.List[_IPAddressTypes],
1735 typing.List[str],
1736 typing.List[OtherName],
1737 typing.List[Name],
1738 typing.List[ObjectIdentifier],
1739 ]:
1740 return self._general_names.get_values_for_type(type)
1742 def __repr__(self) -> str:
1743 return f"<CertificateIssuer({self._general_names})>"
1745 def __eq__(self, other: object) -> bool:
1746 if not isinstance(other, CertificateIssuer):
1747 return NotImplemented
1749 return self._general_names == other._general_names
1751 def __hash__(self) -> int:
1752 return hash(self._general_names)
1754 def public_bytes(self) -> bytes:
1755 return rust_x509.encode_extension_value(self)
1758class CRLReason(ExtensionType):
1759 oid = CRLEntryExtensionOID.CRL_REASON
1761 def __init__(self, reason: ReasonFlags) -> None:
1762 if not isinstance(reason, ReasonFlags):
1763 raise TypeError("reason must be an element from ReasonFlags")
1765 self._reason = reason
1767 def __repr__(self) -> str:
1768 return f"<CRLReason(reason={self._reason})>"
1770 def __eq__(self, other: object) -> bool:
1771 if not isinstance(other, CRLReason):
1772 return NotImplemented
1774 return self.reason == other.reason
1776 def __hash__(self) -> int:
1777 return hash(self.reason)
1779 @property
1780 def reason(self) -> ReasonFlags:
1781 return self._reason
1783 def public_bytes(self) -> bytes:
1784 return rust_x509.encode_extension_value(self)
1787class InvalidityDate(ExtensionType):
1788 oid = CRLEntryExtensionOID.INVALIDITY_DATE
1790 def __init__(self, invalidity_date: datetime.datetime) -> None:
1791 if not isinstance(invalidity_date, datetime.datetime):
1792 raise TypeError("invalidity_date must be a datetime.datetime")
1794 self._invalidity_date = invalidity_date
1796 def __repr__(self) -> str:
1797 return "<InvalidityDate(invalidity_date={})>".format(
1798 self._invalidity_date
1799 )
1801 def __eq__(self, other: object) -> bool:
1802 if not isinstance(other, InvalidityDate):
1803 return NotImplemented
1805 return self.invalidity_date == other.invalidity_date
1807 def __hash__(self) -> int:
1808 return hash(self.invalidity_date)
1810 @property
1811 def invalidity_date(self) -> datetime.datetime:
1812 return self._invalidity_date
1814 def public_bytes(self) -> bytes:
1815 return rust_x509.encode_extension_value(self)
1818class PrecertificateSignedCertificateTimestamps(ExtensionType):
1819 oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS
1821 def __init__(
1822 self,
1823 signed_certificate_timestamps: typing.Iterable[
1824 SignedCertificateTimestamp
1825 ],
1826 ) -> None:
1827 signed_certificate_timestamps = list(signed_certificate_timestamps)
1828 if not all(
1829 isinstance(sct, SignedCertificateTimestamp)
1830 for sct in signed_certificate_timestamps
1831 ):
1832 raise TypeError(
1833 "Every item in the signed_certificate_timestamps list must be "
1834 "a SignedCertificateTimestamp"
1835 )
1836 self._signed_certificate_timestamps = signed_certificate_timestamps
1838 __len__, __iter__, __getitem__ = _make_sequence_methods(
1839 "_signed_certificate_timestamps"
1840 )
1842 def __repr__(self) -> str:
1843 return "<PrecertificateSignedCertificateTimestamps({})>".format(
1844 list(self)
1845 )
1847 def __hash__(self) -> int:
1848 return hash(tuple(self._signed_certificate_timestamps))
1850 def __eq__(self, other: object) -> bool:
1851 if not isinstance(other, PrecertificateSignedCertificateTimestamps):
1852 return NotImplemented
1854 return (
1855 self._signed_certificate_timestamps
1856 == other._signed_certificate_timestamps
1857 )
1859 def public_bytes(self) -> bytes:
1860 return rust_x509.encode_extension_value(self)
1863class SignedCertificateTimestamps(ExtensionType):
1864 oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS
1866 def __init__(
1867 self,
1868 signed_certificate_timestamps: typing.Iterable[
1869 SignedCertificateTimestamp
1870 ],
1871 ) -> None:
1872 signed_certificate_timestamps = list(signed_certificate_timestamps)
1873 if not all(
1874 isinstance(sct, SignedCertificateTimestamp)
1875 for sct in signed_certificate_timestamps
1876 ):
1877 raise TypeError(
1878 "Every item in the signed_certificate_timestamps list must be "
1879 "a SignedCertificateTimestamp"
1880 )
1881 self._signed_certificate_timestamps = signed_certificate_timestamps
1883 __len__, __iter__, __getitem__ = _make_sequence_methods(
1884 "_signed_certificate_timestamps"
1885 )
1887 def __repr__(self) -> str:
1888 return f"<SignedCertificateTimestamps({list(self)})>"
1890 def __hash__(self) -> int:
1891 return hash(tuple(self._signed_certificate_timestamps))
1893 def __eq__(self, other: object) -> bool:
1894 if not isinstance(other, SignedCertificateTimestamps):
1895 return NotImplemented
1897 return (
1898 self._signed_certificate_timestamps
1899 == other._signed_certificate_timestamps
1900 )
1902 def public_bytes(self) -> bytes:
1903 return rust_x509.encode_extension_value(self)
1906class OCSPNonce(ExtensionType):
1907 oid = OCSPExtensionOID.NONCE
1909 def __init__(self, nonce: bytes) -> None:
1910 if not isinstance(nonce, bytes):
1911 raise TypeError("nonce must be bytes")
1913 self._nonce = nonce
1915 def __eq__(self, other: object) -> bool:
1916 if not isinstance(other, OCSPNonce):
1917 return NotImplemented
1919 return self.nonce == other.nonce
1921 def __hash__(self) -> int:
1922 return hash(self.nonce)
1924 def __repr__(self) -> str:
1925 return f"<OCSPNonce(nonce={self.nonce!r})>"
1927 @property
1928 def nonce(self) -> bytes:
1929 return self._nonce
1931 def public_bytes(self) -> bytes:
1932 return rust_x509.encode_extension_value(self)
1935class IssuingDistributionPoint(ExtensionType):
1936 oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT
1938 def __init__(
1939 self,
1940 full_name: typing.Optional[typing.Iterable[GeneralName]],
1941 relative_name: typing.Optional[RelativeDistinguishedName],
1942 only_contains_user_certs: bool,
1943 only_contains_ca_certs: bool,
1944 only_some_reasons: typing.Optional[typing.FrozenSet[ReasonFlags]],
1945 indirect_crl: bool,
1946 only_contains_attribute_certs: bool,
1947 ) -> None:
1948 if full_name is not None:
1949 full_name = list(full_name)
1951 if only_some_reasons and (
1952 not isinstance(only_some_reasons, frozenset)
1953 or not all(isinstance(x, ReasonFlags) for x in only_some_reasons)
1954 ):
1955 raise TypeError(
1956 "only_some_reasons must be None or frozenset of ReasonFlags"
1957 )
1959 if only_some_reasons and (
1960 ReasonFlags.unspecified in only_some_reasons
1961 or ReasonFlags.remove_from_crl in only_some_reasons
1962 ):
1963 raise ValueError(
1964 "unspecified and remove_from_crl are not valid reasons in an "
1965 "IssuingDistributionPoint"
1966 )
1968 if not (
1969 isinstance(only_contains_user_certs, bool)
1970 and isinstance(only_contains_ca_certs, bool)
1971 and isinstance(indirect_crl, bool)
1972 and isinstance(only_contains_attribute_certs, bool)
1973 ):
1974 raise TypeError(
1975 "only_contains_user_certs, only_contains_ca_certs, "
1976 "indirect_crl and only_contains_attribute_certs "
1977 "must all be boolean."
1978 )
1980 crl_constraints = [
1981 only_contains_user_certs,
1982 only_contains_ca_certs,
1983 indirect_crl,
1984 only_contains_attribute_certs,
1985 ]
1987 if len([x for x in crl_constraints if x]) > 1:
1988 raise ValueError(
1989 "Only one of the following can be set to True: "
1990 "only_contains_user_certs, only_contains_ca_certs, "
1991 "indirect_crl, only_contains_attribute_certs"
1992 )
1994 if not any(
1995 [
1996 only_contains_user_certs,
1997 only_contains_ca_certs,
1998 indirect_crl,
1999 only_contains_attribute_certs,
2000 full_name,
2001 relative_name,
2002 only_some_reasons,
2003 ]
2004 ):
2005 raise ValueError(
2006 "Cannot create empty extension: "
2007 "if only_contains_user_certs, only_contains_ca_certs, "
2008 "indirect_crl, and only_contains_attribute_certs are all False"
2009 ", then either full_name, relative_name, or only_some_reasons "
2010 "must have a value."
2011 )
2013 self._only_contains_user_certs = only_contains_user_certs
2014 self._only_contains_ca_certs = only_contains_ca_certs
2015 self._indirect_crl = indirect_crl
2016 self._only_contains_attribute_certs = only_contains_attribute_certs
2017 self._only_some_reasons = only_some_reasons
2018 self._full_name = full_name
2019 self._relative_name = relative_name
2021 def __repr__(self) -> str:
2022 return (
2023 "<IssuingDistributionPoint(full_name={0.full_name}, "
2024 "relative_name={0.relative_name}, "
2025 "only_contains_user_certs={0.only_contains_user_certs}, "
2026 "only_contains_ca_certs={0.only_contains_ca_certs}, "
2027 "only_some_reasons={0.only_some_reasons}, "
2028 "indirect_crl={0.indirect_crl}, "
2029 "only_contains_attribute_certs="
2030 "{0.only_contains_attribute_certs})>".format(self)
2031 )
2033 def __eq__(self, other: object) -> bool:
2034 if not isinstance(other, IssuingDistributionPoint):
2035 return NotImplemented
2037 return (
2038 self.full_name == other.full_name
2039 and self.relative_name == other.relative_name
2040 and self.only_contains_user_certs == other.only_contains_user_certs
2041 and self.only_contains_ca_certs == other.only_contains_ca_certs
2042 and self.only_some_reasons == other.only_some_reasons
2043 and self.indirect_crl == other.indirect_crl
2044 and self.only_contains_attribute_certs
2045 == other.only_contains_attribute_certs
2046 )
2048 def __hash__(self) -> int:
2049 return hash(
2050 (
2051 self.full_name,
2052 self.relative_name,
2053 self.only_contains_user_certs,
2054 self.only_contains_ca_certs,
2055 self.only_some_reasons,
2056 self.indirect_crl,
2057 self.only_contains_attribute_certs,
2058 )
2059 )
2061 @property
2062 def full_name(self) -> typing.Optional[typing.List[GeneralName]]:
2063 return self._full_name
2065 @property
2066 def relative_name(self) -> typing.Optional[RelativeDistinguishedName]:
2067 return self._relative_name
2069 @property
2070 def only_contains_user_certs(self) -> bool:
2071 return self._only_contains_user_certs
2073 @property
2074 def only_contains_ca_certs(self) -> bool:
2075 return self._only_contains_ca_certs
2077 @property
2078 def only_some_reasons(
2079 self,
2080 ) -> typing.Optional[typing.FrozenSet[ReasonFlags]]:
2081 return self._only_some_reasons
2083 @property
2084 def indirect_crl(self) -> bool:
2085 return self._indirect_crl
2087 @property
2088 def only_contains_attribute_certs(self) -> bool:
2089 return self._only_contains_attribute_certs
2091 def public_bytes(self) -> bytes:
2092 return rust_x509.encode_extension_value(self)
2095class UnrecognizedExtension(ExtensionType):
2096 def __init__(self, oid: ObjectIdentifier, value: bytes) -> None:
2097 if not isinstance(oid, ObjectIdentifier):
2098 raise TypeError("oid must be an ObjectIdentifier")
2099 self._oid = oid
2100 self._value = value
2102 @property
2103 def oid(self) -> ObjectIdentifier: # type: ignore[override]
2104 return self._oid
2106 @property
2107 def value(self) -> bytes:
2108 return self._value
2110 def __repr__(self) -> str:
2111 return (
2112 "<UnrecognizedExtension(oid={0.oid}, "
2113 "value={0.value!r})>".format(self)
2114 )
2116 def __eq__(self, other: object) -> bool:
2117 if not isinstance(other, UnrecognizedExtension):
2118 return NotImplemented
2120 return self.oid == other.oid and self.value == other.value
2122 def __hash__(self) -> int:
2123 return hash((self.oid, self.value))
2125 def public_bytes(self) -> bytes:
2126 return self.value