Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/x509/extensions.py: 45%
983 statements
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +0000
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +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 CERTIFICATE_ISSUER_PUBLIC_KEY_TYPES,
20 CERTIFICATE_PUBLIC_KEY_TYPES,
21)
22from cryptography.x509.certificate_transparency import (
23 SignedCertificateTimestamp,
24)
25from cryptography.x509.general_name import (
26 DNSName,
27 DirectoryName,
28 GeneralName,
29 IPAddress,
30 OtherName,
31 RFC822Name,
32 RegisteredID,
33 UniformResourceIdentifier,
34 _IPADDRESS_TYPES,
35)
36from cryptography.x509.name import Name, RelativeDistinguishedName
37from cryptography.x509.oid import (
38 CRLEntryExtensionOID,
39 ExtensionOID,
40 OCSPExtensionOID,
41 ObjectIdentifier,
42)
44ExtensionTypeVar = typing.TypeVar(
45 "ExtensionTypeVar", bound="ExtensionType", covariant=True
46)
49def _key_identifier_from_public_key(
50 public_key: CERTIFICATE_PUBLIC_KEY_TYPES,
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(DuplicateExtension, self).__init__(msg)
89 self.oid = oid
92class ExtensionNotFound(Exception):
93 def __init__(self, msg: str, oid: ObjectIdentifier) -> None:
94 super(ExtensionNotFound, self).__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 {0!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("No {} extension was found".format(oid), 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 "No {} extension was found".format(extclass), extclass.oid
143 )
145 __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions")
147 def __repr__(self) -> str:
148 return "<Extensions({})>".format(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 "<CRLNumber({})>".format(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 CERTIFICATE_PUBLIC_KEY_TYPES 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: CERTIFICATE_ISSUER_PUBLIC_KEY_TYPES
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: CERTIFICATE_PUBLIC_KEY_TYPES
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 "<SubjectKeyIdentifier(digest={0!r})>".format(self.digest)
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 "<AuthorityInformationAccess({})>".format(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 "<SubjectInformationAccess({})>".format(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 "<DeltaCRLIndicator(crl_number={0.crl_number})>".format(self)
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 "<CRLDistributionPoints({})>".format(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 "<FreshestCRL({})>".format(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 )
593 if full_name is not None:
594 full_name = list(full_name)
595 if not all(isinstance(x, GeneralName) for x in full_name):
596 raise TypeError(
597 "full_name must be a list of GeneralName objects"
598 )
600 if relative_name:
601 if not isinstance(relative_name, RelativeDistinguishedName):
602 raise TypeError(
603 "relative_name must be a RelativeDistinguishedName"
604 )
606 if crl_issuer is not None:
607 crl_issuer = list(crl_issuer)
608 if not all(isinstance(x, GeneralName) for x in crl_issuer):
609 raise TypeError(
610 "crl_issuer must be None or a list of general names"
611 )
613 if reasons and (
614 not isinstance(reasons, frozenset)
615 or not all(isinstance(x, ReasonFlags) for x in reasons)
616 ):
617 raise TypeError("reasons must be None or frozenset of ReasonFlags")
619 if reasons and (
620 ReasonFlags.unspecified in reasons
621 or ReasonFlags.remove_from_crl in reasons
622 ):
623 raise ValueError(
624 "unspecified and remove_from_crl are not valid reasons in a "
625 "DistributionPoint"
626 )
628 if reasons and not crl_issuer and not (full_name or relative_name):
629 raise ValueError(
630 "You must supply crl_issuer, full_name, or relative_name when "
631 "reasons is not None"
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 "<CertificatePolicies({})>".format(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 "<ExtendedKeyUsage({})>".format(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 "<TLSFeature(features={0._features})>".format(self)
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 "<InhibitAnyPolicy(skip_certs={0.skip_certs})>".format(self)
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_ip_name(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_ip_name(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_ip_name(self, tree: typing.Iterable[GeneralName]) -> None:
1315 if any(
1316 isinstance(name, IPAddress)
1317 and not isinstance(
1318 name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network)
1319 )
1320 for name in tree
1321 ):
1322 raise TypeError(
1323 "IPAddress name constraints must be an IPv4Network or"
1324 " IPv6Network object"
1325 )
1327 def __repr__(self) -> str:
1328 return (
1329 "<NameConstraints(permitted_subtrees={0.permitted_subtrees}, "
1330 "excluded_subtrees={0.excluded_subtrees})>".format(self)
1331 )
1333 def __hash__(self) -> int:
1334 if self.permitted_subtrees is not None:
1335 ps: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple(
1336 self.permitted_subtrees
1337 )
1338 else:
1339 ps = None
1341 if self.excluded_subtrees is not None:
1342 es: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple(
1343 self.excluded_subtrees
1344 )
1345 else:
1346 es = None
1348 return hash((ps, es))
1350 @property
1351 def permitted_subtrees(
1352 self,
1353 ) -> typing.Optional[typing.List[GeneralName]]:
1354 return self._permitted_subtrees
1356 @property
1357 def excluded_subtrees(
1358 self,
1359 ) -> typing.Optional[typing.List[GeneralName]]:
1360 return self._excluded_subtrees
1362 def public_bytes(self) -> bytes:
1363 return rust_x509.encode_extension_value(self)
1366class Extension(typing.Generic[ExtensionTypeVar]):
1367 def __init__(
1368 self, oid: ObjectIdentifier, critical: bool, value: ExtensionTypeVar
1369 ) -> None:
1370 if not isinstance(oid, ObjectIdentifier):
1371 raise TypeError(
1372 "oid argument must be an ObjectIdentifier instance."
1373 )
1375 if not isinstance(critical, bool):
1376 raise TypeError("critical must be a boolean value")
1378 self._oid = oid
1379 self._critical = critical
1380 self._value = value
1382 @property
1383 def oid(self) -> ObjectIdentifier:
1384 return self._oid
1386 @property
1387 def critical(self) -> bool:
1388 return self._critical
1390 @property
1391 def value(self) -> ExtensionTypeVar:
1392 return self._value
1394 def __repr__(self) -> str:
1395 return (
1396 "<Extension(oid={0.oid}, critical={0.critical}, "
1397 "value={0.value})>"
1398 ).format(self)
1400 def __eq__(self, other: object) -> bool:
1401 if not isinstance(other, Extension):
1402 return NotImplemented
1404 return (
1405 self.oid == other.oid
1406 and self.critical == other.critical
1407 and self.value == other.value
1408 )
1410 def __hash__(self) -> int:
1411 return hash((self.oid, self.critical, self.value))
1414class GeneralNames:
1415 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None:
1416 general_names = list(general_names)
1417 if not all(isinstance(x, GeneralName) for x in general_names):
1418 raise TypeError(
1419 "Every item in the general_names list must be an "
1420 "object conforming to the GeneralName interface"
1421 )
1423 self._general_names = general_names
1425 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1427 @typing.overload
1428 def get_values_for_type(
1429 self,
1430 type: typing.Union[
1431 typing.Type[DNSName],
1432 typing.Type[UniformResourceIdentifier],
1433 typing.Type[RFC822Name],
1434 ],
1435 ) -> typing.List[str]:
1436 ...
1438 @typing.overload
1439 def get_values_for_type(
1440 self,
1441 type: typing.Type[DirectoryName],
1442 ) -> typing.List[Name]:
1443 ...
1445 @typing.overload
1446 def get_values_for_type(
1447 self,
1448 type: typing.Type[RegisteredID],
1449 ) -> typing.List[ObjectIdentifier]:
1450 ...
1452 @typing.overload
1453 def get_values_for_type(
1454 self, type: typing.Type[IPAddress]
1455 ) -> typing.List[_IPADDRESS_TYPES]:
1456 ...
1458 @typing.overload
1459 def get_values_for_type(
1460 self, type: typing.Type[OtherName]
1461 ) -> typing.List[OtherName]:
1462 ...
1464 def get_values_for_type(
1465 self,
1466 type: typing.Union[
1467 typing.Type[DNSName],
1468 typing.Type[DirectoryName],
1469 typing.Type[IPAddress],
1470 typing.Type[OtherName],
1471 typing.Type[RFC822Name],
1472 typing.Type[RegisteredID],
1473 typing.Type[UniformResourceIdentifier],
1474 ],
1475 ) -> typing.Union[
1476 typing.List[_IPADDRESS_TYPES],
1477 typing.List[str],
1478 typing.List[OtherName],
1479 typing.List[Name],
1480 typing.List[ObjectIdentifier],
1481 ]:
1482 # Return the value of each GeneralName, except for OtherName instances
1483 # which we return directly because it has two important properties not
1484 # just one value.
1485 objs = (i for i in self if isinstance(i, type))
1486 if type != OtherName:
1487 return [i.value for i in objs]
1488 return list(objs)
1490 def __repr__(self) -> str:
1491 return "<GeneralNames({})>".format(self._general_names)
1493 def __eq__(self, other: object) -> bool:
1494 if not isinstance(other, GeneralNames):
1495 return NotImplemented
1497 return self._general_names == other._general_names
1499 def __hash__(self) -> int:
1500 return hash(tuple(self._general_names))
1503class SubjectAlternativeName(ExtensionType):
1504 oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME
1506 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None:
1507 self._general_names = GeneralNames(general_names)
1509 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1511 @typing.overload
1512 def get_values_for_type(
1513 self,
1514 type: typing.Union[
1515 typing.Type[DNSName],
1516 typing.Type[UniformResourceIdentifier],
1517 typing.Type[RFC822Name],
1518 ],
1519 ) -> typing.List[str]:
1520 ...
1522 @typing.overload
1523 def get_values_for_type(
1524 self,
1525 type: typing.Type[DirectoryName],
1526 ) -> typing.List[Name]:
1527 ...
1529 @typing.overload
1530 def get_values_for_type(
1531 self,
1532 type: typing.Type[RegisteredID],
1533 ) -> typing.List[ObjectIdentifier]:
1534 ...
1536 @typing.overload
1537 def get_values_for_type(
1538 self, type: typing.Type[IPAddress]
1539 ) -> typing.List[_IPADDRESS_TYPES]:
1540 ...
1542 @typing.overload
1543 def get_values_for_type(
1544 self, type: typing.Type[OtherName]
1545 ) -> typing.List[OtherName]:
1546 ...
1548 def get_values_for_type(
1549 self,
1550 type: typing.Union[
1551 typing.Type[DNSName],
1552 typing.Type[DirectoryName],
1553 typing.Type[IPAddress],
1554 typing.Type[OtherName],
1555 typing.Type[RFC822Name],
1556 typing.Type[RegisteredID],
1557 typing.Type[UniformResourceIdentifier],
1558 ],
1559 ) -> typing.Union[
1560 typing.List[_IPADDRESS_TYPES],
1561 typing.List[str],
1562 typing.List[OtherName],
1563 typing.List[Name],
1564 typing.List[ObjectIdentifier],
1565 ]:
1566 return self._general_names.get_values_for_type(type)
1568 def __repr__(self) -> str:
1569 return "<SubjectAlternativeName({})>".format(self._general_names)
1571 def __eq__(self, other: object) -> bool:
1572 if not isinstance(other, SubjectAlternativeName):
1573 return NotImplemented
1575 return self._general_names == other._general_names
1577 def __hash__(self) -> int:
1578 return hash(self._general_names)
1580 def public_bytes(self) -> bytes:
1581 return rust_x509.encode_extension_value(self)
1584class IssuerAlternativeName(ExtensionType):
1585 oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME
1587 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None:
1588 self._general_names = GeneralNames(general_names)
1590 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1592 @typing.overload
1593 def get_values_for_type(
1594 self,
1595 type: typing.Union[
1596 typing.Type[DNSName],
1597 typing.Type[UniformResourceIdentifier],
1598 typing.Type[RFC822Name],
1599 ],
1600 ) -> typing.List[str]:
1601 ...
1603 @typing.overload
1604 def get_values_for_type(
1605 self,
1606 type: typing.Type[DirectoryName],
1607 ) -> typing.List[Name]:
1608 ...
1610 @typing.overload
1611 def get_values_for_type(
1612 self,
1613 type: typing.Type[RegisteredID],
1614 ) -> typing.List[ObjectIdentifier]:
1615 ...
1617 @typing.overload
1618 def get_values_for_type(
1619 self, type: typing.Type[IPAddress]
1620 ) -> typing.List[_IPADDRESS_TYPES]:
1621 ...
1623 @typing.overload
1624 def get_values_for_type(
1625 self, type: typing.Type[OtherName]
1626 ) -> typing.List[OtherName]:
1627 ...
1629 def get_values_for_type(
1630 self,
1631 type: typing.Union[
1632 typing.Type[DNSName],
1633 typing.Type[DirectoryName],
1634 typing.Type[IPAddress],
1635 typing.Type[OtherName],
1636 typing.Type[RFC822Name],
1637 typing.Type[RegisteredID],
1638 typing.Type[UniformResourceIdentifier],
1639 ],
1640 ) -> typing.Union[
1641 typing.List[_IPADDRESS_TYPES],
1642 typing.List[str],
1643 typing.List[OtherName],
1644 typing.List[Name],
1645 typing.List[ObjectIdentifier],
1646 ]:
1647 return self._general_names.get_values_for_type(type)
1649 def __repr__(self) -> str:
1650 return "<IssuerAlternativeName({})>".format(self._general_names)
1652 def __eq__(self, other: object) -> bool:
1653 if not isinstance(other, IssuerAlternativeName):
1654 return NotImplemented
1656 return self._general_names == other._general_names
1658 def __hash__(self) -> int:
1659 return hash(self._general_names)
1661 def public_bytes(self) -> bytes:
1662 return rust_x509.encode_extension_value(self)
1665class CertificateIssuer(ExtensionType):
1666 oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER
1668 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None:
1669 self._general_names = GeneralNames(general_names)
1671 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1673 @typing.overload
1674 def get_values_for_type(
1675 self,
1676 type: typing.Union[
1677 typing.Type[DNSName],
1678 typing.Type[UniformResourceIdentifier],
1679 typing.Type[RFC822Name],
1680 ],
1681 ) -> typing.List[str]:
1682 ...
1684 @typing.overload
1685 def get_values_for_type(
1686 self,
1687 type: typing.Type[DirectoryName],
1688 ) -> typing.List[Name]:
1689 ...
1691 @typing.overload
1692 def get_values_for_type(
1693 self,
1694 type: typing.Type[RegisteredID],
1695 ) -> typing.List[ObjectIdentifier]:
1696 ...
1698 @typing.overload
1699 def get_values_for_type(
1700 self, type: typing.Type[IPAddress]
1701 ) -> typing.List[_IPADDRESS_TYPES]:
1702 ...
1704 @typing.overload
1705 def get_values_for_type(
1706 self, type: typing.Type[OtherName]
1707 ) -> typing.List[OtherName]:
1708 ...
1710 def get_values_for_type(
1711 self,
1712 type: typing.Union[
1713 typing.Type[DNSName],
1714 typing.Type[DirectoryName],
1715 typing.Type[IPAddress],
1716 typing.Type[OtherName],
1717 typing.Type[RFC822Name],
1718 typing.Type[RegisteredID],
1719 typing.Type[UniformResourceIdentifier],
1720 ],
1721 ) -> typing.Union[
1722 typing.List[_IPADDRESS_TYPES],
1723 typing.List[str],
1724 typing.List[OtherName],
1725 typing.List[Name],
1726 typing.List[ObjectIdentifier],
1727 ]:
1728 return self._general_names.get_values_for_type(type)
1730 def __repr__(self) -> str:
1731 return "<CertificateIssuer({})>".format(self._general_names)
1733 def __eq__(self, other: object) -> bool:
1734 if not isinstance(other, CertificateIssuer):
1735 return NotImplemented
1737 return self._general_names == other._general_names
1739 def __hash__(self) -> int:
1740 return hash(self._general_names)
1742 def public_bytes(self) -> bytes:
1743 return rust_x509.encode_extension_value(self)
1746class CRLReason(ExtensionType):
1747 oid = CRLEntryExtensionOID.CRL_REASON
1749 def __init__(self, reason: ReasonFlags) -> None:
1750 if not isinstance(reason, ReasonFlags):
1751 raise TypeError("reason must be an element from ReasonFlags")
1753 self._reason = reason
1755 def __repr__(self) -> str:
1756 return "<CRLReason(reason={})>".format(self._reason)
1758 def __eq__(self, other: object) -> bool:
1759 if not isinstance(other, CRLReason):
1760 return NotImplemented
1762 return self.reason == other.reason
1764 def __hash__(self) -> int:
1765 return hash(self.reason)
1767 @property
1768 def reason(self) -> ReasonFlags:
1769 return self._reason
1771 def public_bytes(self) -> bytes:
1772 return rust_x509.encode_extension_value(self)
1775class InvalidityDate(ExtensionType):
1776 oid = CRLEntryExtensionOID.INVALIDITY_DATE
1778 def __init__(self, invalidity_date: datetime.datetime) -> None:
1779 if not isinstance(invalidity_date, datetime.datetime):
1780 raise TypeError("invalidity_date must be a datetime.datetime")
1782 self._invalidity_date = invalidity_date
1784 def __repr__(self) -> str:
1785 return "<InvalidityDate(invalidity_date={})>".format(
1786 self._invalidity_date
1787 )
1789 def __eq__(self, other: object) -> bool:
1790 if not isinstance(other, InvalidityDate):
1791 return NotImplemented
1793 return self.invalidity_date == other.invalidity_date
1795 def __hash__(self) -> int:
1796 return hash(self.invalidity_date)
1798 @property
1799 def invalidity_date(self) -> datetime.datetime:
1800 return self._invalidity_date
1802 def public_bytes(self) -> bytes:
1803 return rust_x509.encode_extension_value(self)
1806class PrecertificateSignedCertificateTimestamps(ExtensionType):
1807 oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS
1809 def __init__(
1810 self,
1811 signed_certificate_timestamps: typing.Iterable[
1812 SignedCertificateTimestamp
1813 ],
1814 ) -> None:
1815 signed_certificate_timestamps = list(signed_certificate_timestamps)
1816 if not all(
1817 isinstance(sct, SignedCertificateTimestamp)
1818 for sct in signed_certificate_timestamps
1819 ):
1820 raise TypeError(
1821 "Every item in the signed_certificate_timestamps list must be "
1822 "a SignedCertificateTimestamp"
1823 )
1824 self._signed_certificate_timestamps = signed_certificate_timestamps
1826 __len__, __iter__, __getitem__ = _make_sequence_methods(
1827 "_signed_certificate_timestamps"
1828 )
1830 def __repr__(self) -> str:
1831 return "<PrecertificateSignedCertificateTimestamps({})>".format(
1832 list(self)
1833 )
1835 def __hash__(self) -> int:
1836 return hash(tuple(self._signed_certificate_timestamps))
1838 def __eq__(self, other: object) -> bool:
1839 if not isinstance(other, PrecertificateSignedCertificateTimestamps):
1840 return NotImplemented
1842 return (
1843 self._signed_certificate_timestamps
1844 == other._signed_certificate_timestamps
1845 )
1847 def public_bytes(self) -> bytes:
1848 return rust_x509.encode_extension_value(self)
1851class SignedCertificateTimestamps(ExtensionType):
1852 oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS
1854 def __init__(
1855 self,
1856 signed_certificate_timestamps: typing.Iterable[
1857 SignedCertificateTimestamp
1858 ],
1859 ) -> None:
1860 signed_certificate_timestamps = list(signed_certificate_timestamps)
1861 if not all(
1862 isinstance(sct, SignedCertificateTimestamp)
1863 for sct in signed_certificate_timestamps
1864 ):
1865 raise TypeError(
1866 "Every item in the signed_certificate_timestamps list must be "
1867 "a SignedCertificateTimestamp"
1868 )
1869 self._signed_certificate_timestamps = signed_certificate_timestamps
1871 __len__, __iter__, __getitem__ = _make_sequence_methods(
1872 "_signed_certificate_timestamps"
1873 )
1875 def __repr__(self) -> str:
1876 return "<SignedCertificateTimestamps({})>".format(list(self))
1878 def __hash__(self) -> int:
1879 return hash(tuple(self._signed_certificate_timestamps))
1881 def __eq__(self, other: object) -> bool:
1882 if not isinstance(other, SignedCertificateTimestamps):
1883 return NotImplemented
1885 return (
1886 self._signed_certificate_timestamps
1887 == other._signed_certificate_timestamps
1888 )
1890 def public_bytes(self) -> bytes:
1891 return rust_x509.encode_extension_value(self)
1894class OCSPNonce(ExtensionType):
1895 oid = OCSPExtensionOID.NONCE
1897 def __init__(self, nonce: bytes) -> None:
1898 if not isinstance(nonce, bytes):
1899 raise TypeError("nonce must be bytes")
1901 self._nonce = nonce
1903 def __eq__(self, other: object) -> bool:
1904 if not isinstance(other, OCSPNonce):
1905 return NotImplemented
1907 return self.nonce == other.nonce
1909 def __hash__(self) -> int:
1910 return hash(self.nonce)
1912 def __repr__(self) -> str:
1913 return "<OCSPNonce(nonce={0.nonce!r})>".format(self)
1915 @property
1916 def nonce(self) -> bytes:
1917 return self._nonce
1919 def public_bytes(self) -> bytes:
1920 return rust_x509.encode_extension_value(self)
1923class IssuingDistributionPoint(ExtensionType):
1924 oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT
1926 def __init__(
1927 self,
1928 full_name: typing.Optional[typing.Iterable[GeneralName]],
1929 relative_name: typing.Optional[RelativeDistinguishedName],
1930 only_contains_user_certs: bool,
1931 only_contains_ca_certs: bool,
1932 only_some_reasons: typing.Optional[typing.FrozenSet[ReasonFlags]],
1933 indirect_crl: bool,
1934 only_contains_attribute_certs: bool,
1935 ) -> None:
1936 if full_name is not None:
1937 full_name = list(full_name)
1939 if only_some_reasons and (
1940 not isinstance(only_some_reasons, frozenset)
1941 or not all(isinstance(x, ReasonFlags) for x in only_some_reasons)
1942 ):
1943 raise TypeError(
1944 "only_some_reasons must be None or frozenset of ReasonFlags"
1945 )
1947 if only_some_reasons and (
1948 ReasonFlags.unspecified in only_some_reasons
1949 or ReasonFlags.remove_from_crl in only_some_reasons
1950 ):
1951 raise ValueError(
1952 "unspecified and remove_from_crl are not valid reasons in an "
1953 "IssuingDistributionPoint"
1954 )
1956 if not (
1957 isinstance(only_contains_user_certs, bool)
1958 and isinstance(only_contains_ca_certs, bool)
1959 and isinstance(indirect_crl, bool)
1960 and isinstance(only_contains_attribute_certs, bool)
1961 ):
1962 raise TypeError(
1963 "only_contains_user_certs, only_contains_ca_certs, "
1964 "indirect_crl and only_contains_attribute_certs "
1965 "must all be boolean."
1966 )
1968 crl_constraints = [
1969 only_contains_user_certs,
1970 only_contains_ca_certs,
1971 indirect_crl,
1972 only_contains_attribute_certs,
1973 ]
1975 if len([x for x in crl_constraints if x]) > 1:
1976 raise ValueError(
1977 "Only one of the following can be set to True: "
1978 "only_contains_user_certs, only_contains_ca_certs, "
1979 "indirect_crl, only_contains_attribute_certs"
1980 )
1982 if not any(
1983 [
1984 only_contains_user_certs,
1985 only_contains_ca_certs,
1986 indirect_crl,
1987 only_contains_attribute_certs,
1988 full_name,
1989 relative_name,
1990 only_some_reasons,
1991 ]
1992 ):
1993 raise ValueError(
1994 "Cannot create empty extension: "
1995 "if only_contains_user_certs, only_contains_ca_certs, "
1996 "indirect_crl, and only_contains_attribute_certs are all False"
1997 ", then either full_name, relative_name, or only_some_reasons "
1998 "must have a value."
1999 )
2001 self._only_contains_user_certs = only_contains_user_certs
2002 self._only_contains_ca_certs = only_contains_ca_certs
2003 self._indirect_crl = indirect_crl
2004 self._only_contains_attribute_certs = only_contains_attribute_certs
2005 self._only_some_reasons = only_some_reasons
2006 self._full_name = full_name
2007 self._relative_name = relative_name
2009 def __repr__(self) -> str:
2010 return (
2011 "<IssuingDistributionPoint(full_name={0.full_name}, "
2012 "relative_name={0.relative_name}, "
2013 "only_contains_user_certs={0.only_contains_user_certs}, "
2014 "only_contains_ca_certs={0.only_contains_ca_certs}, "
2015 "only_some_reasons={0.only_some_reasons}, "
2016 "indirect_crl={0.indirect_crl}, "
2017 "only_contains_attribute_certs="
2018 "{0.only_contains_attribute_certs})>".format(self)
2019 )
2021 def __eq__(self, other: object) -> bool:
2022 if not isinstance(other, IssuingDistributionPoint):
2023 return NotImplemented
2025 return (
2026 self.full_name == other.full_name
2027 and self.relative_name == other.relative_name
2028 and self.only_contains_user_certs == other.only_contains_user_certs
2029 and self.only_contains_ca_certs == other.only_contains_ca_certs
2030 and self.only_some_reasons == other.only_some_reasons
2031 and self.indirect_crl == other.indirect_crl
2032 and self.only_contains_attribute_certs
2033 == other.only_contains_attribute_certs
2034 )
2036 def __hash__(self) -> int:
2037 return hash(
2038 (
2039 self.full_name,
2040 self.relative_name,
2041 self.only_contains_user_certs,
2042 self.only_contains_ca_certs,
2043 self.only_some_reasons,
2044 self.indirect_crl,
2045 self.only_contains_attribute_certs,
2046 )
2047 )
2049 @property
2050 def full_name(self) -> typing.Optional[typing.List[GeneralName]]:
2051 return self._full_name
2053 @property
2054 def relative_name(self) -> typing.Optional[RelativeDistinguishedName]:
2055 return self._relative_name
2057 @property
2058 def only_contains_user_certs(self) -> bool:
2059 return self._only_contains_user_certs
2061 @property
2062 def only_contains_ca_certs(self) -> bool:
2063 return self._only_contains_ca_certs
2065 @property
2066 def only_some_reasons(
2067 self,
2068 ) -> typing.Optional[typing.FrozenSet[ReasonFlags]]:
2069 return self._only_some_reasons
2071 @property
2072 def indirect_crl(self) -> bool:
2073 return self._indirect_crl
2075 @property
2076 def only_contains_attribute_certs(self) -> bool:
2077 return self._only_contains_attribute_certs
2079 def public_bytes(self) -> bytes:
2080 return rust_x509.encode_extension_value(self)
2083class UnrecognizedExtension(ExtensionType):
2084 def __init__(self, oid: ObjectIdentifier, value: bytes) -> None:
2085 if not isinstance(oid, ObjectIdentifier):
2086 raise TypeError("oid must be an ObjectIdentifier")
2087 self._oid = oid
2088 self._value = value
2090 @property
2091 def oid(self) -> ObjectIdentifier: # type: ignore[override]
2092 return self._oid
2094 @property
2095 def value(self) -> bytes:
2096 return self._value
2098 def __repr__(self) -> str:
2099 return (
2100 "<UnrecognizedExtension(oid={0.oid}, "
2101 "value={0.value!r})>".format(self)
2102 )
2104 def __eq__(self, other: object) -> bool:
2105 if not isinstance(other, UnrecognizedExtension):
2106 return NotImplemented
2108 return self.oid == other.oid and self.value == other.value
2110 def __hash__(self) -> int:
2111 return hash((self.oid, self.value))
2113 def public_bytes(self) -> bytes:
2114 return self.value