Spaces:
Sleeping
Sleeping
| # This file is dual licensed under the terms of the Apache License, Version | |
| # 2.0, and the BSD License. See the LICENSE file in the root of this repository | |
| # for complete details. | |
| from __future__ import annotations | |
| import abc | |
| import datetime | |
| import hashlib | |
| import ipaddress | |
| import typing | |
| from collections.abc import Iterable, Iterator | |
| from cryptography import utils | |
| from cryptography.hazmat.bindings._rust import asn1 | |
| from cryptography.hazmat.bindings._rust import x509 as rust_x509 | |
| from cryptography.hazmat.primitives import constant_time, serialization | |
| from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey | |
| from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey | |
| from cryptography.hazmat.primitives.asymmetric.types import ( | |
| CertificateIssuerPublicKeyTypes, | |
| CertificatePublicKeyTypes, | |
| ) | |
| from cryptography.x509.certificate_transparency import ( | |
| SignedCertificateTimestamp, | |
| ) | |
| from cryptography.x509.general_name import ( | |
| DirectoryName, | |
| DNSName, | |
| GeneralName, | |
| IPAddress, | |
| OtherName, | |
| RegisteredID, | |
| RFC822Name, | |
| UniformResourceIdentifier, | |
| _IPAddressTypes, | |
| ) | |
| from cryptography.x509.name import Name, RelativeDistinguishedName | |
| from cryptography.x509.oid import ( | |
| CRLEntryExtensionOID, | |
| ExtensionOID, | |
| ObjectIdentifier, | |
| OCSPExtensionOID, | |
| ) | |
| ExtensionTypeVar = typing.TypeVar( | |
| "ExtensionTypeVar", bound="ExtensionType", covariant=True | |
| ) | |
| def _key_identifier_from_public_key( | |
| public_key: CertificatePublicKeyTypes, | |
| ) -> bytes: | |
| if isinstance(public_key, RSAPublicKey): | |
| data = public_key.public_bytes( | |
| serialization.Encoding.DER, | |
| serialization.PublicFormat.PKCS1, | |
| ) | |
| elif isinstance(public_key, EllipticCurvePublicKey): | |
| data = public_key.public_bytes( | |
| serialization.Encoding.X962, | |
| serialization.PublicFormat.UncompressedPoint, | |
| ) | |
| else: | |
| # This is a very slow way to do this. | |
| serialized = public_key.public_bytes( | |
| serialization.Encoding.DER, | |
| serialization.PublicFormat.SubjectPublicKeyInfo, | |
| ) | |
| data = asn1.parse_spki_for_data(serialized) | |
| return hashlib.sha1(data).digest() | |
| def _make_sequence_methods(field_name: str): | |
| def len_method(self) -> int: | |
| return len(getattr(self, field_name)) | |
| def iter_method(self): | |
| return iter(getattr(self, field_name)) | |
| def getitem_method(self, idx): | |
| return getattr(self, field_name)[idx] | |
| return len_method, iter_method, getitem_method | |
| class DuplicateExtension(Exception): | |
| def __init__(self, msg: str, oid: ObjectIdentifier) -> None: | |
| super().__init__(msg) | |
| self.oid = oid | |
| class ExtensionNotFound(Exception): | |
| def __init__(self, msg: str, oid: ObjectIdentifier) -> None: | |
| super().__init__(msg) | |
| self.oid = oid | |
| class ExtensionType(metaclass=abc.ABCMeta): | |
| oid: typing.ClassVar[ObjectIdentifier] | |
| def public_bytes(self) -> bytes: | |
| """ | |
| Serializes the extension type to DER. | |
| """ | |
| raise NotImplementedError( | |
| f"public_bytes is not implemented for extension type {self!r}" | |
| ) | |
| class Extensions: | |
| def __init__(self, extensions: Iterable[Extension[ExtensionType]]) -> None: | |
| self._extensions = list(extensions) | |
| def get_extension_for_oid( | |
| self, oid: ObjectIdentifier | |
| ) -> Extension[ExtensionType]: | |
| for ext in self: | |
| if ext.oid == oid: | |
| return ext | |
| raise ExtensionNotFound(f"No {oid} extension was found", oid) | |
| def get_extension_for_class( | |
| self, extclass: type[ExtensionTypeVar] | |
| ) -> Extension[ExtensionTypeVar]: | |
| if extclass is UnrecognizedExtension: | |
| raise TypeError( | |
| "UnrecognizedExtension can't be used with " | |
| "get_extension_for_class because more than one instance of the" | |
| " class may be present." | |
| ) | |
| for ext in self: | |
| if isinstance(ext.value, extclass): | |
| return ext | |
| raise ExtensionNotFound( | |
| f"No {extclass} extension was found", extclass.oid | |
| ) | |
| __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions") | |
| def __repr__(self) -> str: | |
| return f"<Extensions({self._extensions})>" | |
| class CRLNumber(ExtensionType): | |
| oid = ExtensionOID.CRL_NUMBER | |
| def __init__(self, crl_number: int) -> None: | |
| if not isinstance(crl_number, int): | |
| raise TypeError("crl_number must be an integer") | |
| self._crl_number = crl_number | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, CRLNumber): | |
| return NotImplemented | |
| return self.crl_number == other.crl_number | |
| def __hash__(self) -> int: | |
| return hash(self.crl_number) | |
| def __repr__(self) -> str: | |
| return f"<CRLNumber({self.crl_number})>" | |
| def crl_number(self) -> int: | |
| return self._crl_number | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class AuthorityKeyIdentifier(ExtensionType): | |
| oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER | |
| def __init__( | |
| self, | |
| key_identifier: bytes | None, | |
| authority_cert_issuer: Iterable[GeneralName] | None, | |
| authority_cert_serial_number: int | None, | |
| ) -> None: | |
| if (authority_cert_issuer is None) != ( | |
| authority_cert_serial_number is None | |
| ): | |
| raise ValueError( | |
| "authority_cert_issuer and authority_cert_serial_number " | |
| "must both be present or both None" | |
| ) | |
| if authority_cert_issuer is not None: | |
| authority_cert_issuer = list(authority_cert_issuer) | |
| if not all( | |
| isinstance(x, GeneralName) for x in authority_cert_issuer | |
| ): | |
| raise TypeError( | |
| "authority_cert_issuer must be a list of GeneralName " | |
| "objects" | |
| ) | |
| if authority_cert_serial_number is not None and not isinstance( | |
| authority_cert_serial_number, int | |
| ): | |
| raise TypeError("authority_cert_serial_number must be an integer") | |
| self._key_identifier = key_identifier | |
| self._authority_cert_issuer = authority_cert_issuer | |
| self._authority_cert_serial_number = authority_cert_serial_number | |
| # This takes a subset of CertificatePublicKeyTypes because an issuer | |
| # cannot have an X25519/X448 key. This introduces some unfortunate | |
| # asymmetry that requires typing users to explicitly | |
| # narrow their type, but we should make this accurate and not just | |
| # convenient. | |
| def from_issuer_public_key( | |
| cls, public_key: CertificateIssuerPublicKeyTypes | |
| ) -> AuthorityKeyIdentifier: | |
| digest = _key_identifier_from_public_key(public_key) | |
| return cls( | |
| key_identifier=digest, | |
| authority_cert_issuer=None, | |
| authority_cert_serial_number=None, | |
| ) | |
| def from_issuer_subject_key_identifier( | |
| cls, ski: SubjectKeyIdentifier | |
| ) -> AuthorityKeyIdentifier: | |
| return cls( | |
| key_identifier=ski.digest, | |
| authority_cert_issuer=None, | |
| authority_cert_serial_number=None, | |
| ) | |
| def __repr__(self) -> str: | |
| return ( | |
| f"<AuthorityKeyIdentifier(key_identifier={self.key_identifier!r}, " | |
| f"authority_cert_issuer={self.authority_cert_issuer}, " | |
| f"authority_cert_serial_number={self.authority_cert_serial_number}" | |
| ")>" | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, AuthorityKeyIdentifier): | |
| return NotImplemented | |
| return ( | |
| self.key_identifier == other.key_identifier | |
| and self.authority_cert_issuer == other.authority_cert_issuer | |
| and self.authority_cert_serial_number | |
| == other.authority_cert_serial_number | |
| ) | |
| def __hash__(self) -> int: | |
| if self.authority_cert_issuer is None: | |
| aci = None | |
| else: | |
| aci = tuple(self.authority_cert_issuer) | |
| return hash( | |
| (self.key_identifier, aci, self.authority_cert_serial_number) | |
| ) | |
| def key_identifier(self) -> bytes | None: | |
| return self._key_identifier | |
| def authority_cert_issuer( | |
| self, | |
| ) -> list[GeneralName] | None: | |
| return self._authority_cert_issuer | |
| def authority_cert_serial_number(self) -> int | None: | |
| return self._authority_cert_serial_number | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class SubjectKeyIdentifier(ExtensionType): | |
| oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER | |
| def __init__(self, digest: bytes) -> None: | |
| self._digest = digest | |
| def from_public_key( | |
| cls, public_key: CertificatePublicKeyTypes | |
| ) -> SubjectKeyIdentifier: | |
| return cls(_key_identifier_from_public_key(public_key)) | |
| def digest(self) -> bytes: | |
| return self._digest | |
| def key_identifier(self) -> bytes: | |
| return self._digest | |
| def __repr__(self) -> str: | |
| return f"<SubjectKeyIdentifier(digest={self.digest!r})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, SubjectKeyIdentifier): | |
| return NotImplemented | |
| return constant_time.bytes_eq(self.digest, other.digest) | |
| def __hash__(self) -> int: | |
| return hash(self.digest) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class AuthorityInformationAccess(ExtensionType): | |
| oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS | |
| def __init__(self, descriptions: Iterable[AccessDescription]) -> None: | |
| descriptions = list(descriptions) | |
| if not all(isinstance(x, AccessDescription) for x in descriptions): | |
| raise TypeError( | |
| "Every item in the descriptions list must be an " | |
| "AccessDescription" | |
| ) | |
| self._descriptions = descriptions | |
| __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") | |
| def __repr__(self) -> str: | |
| return f"<AuthorityInformationAccess({self._descriptions})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, AuthorityInformationAccess): | |
| return NotImplemented | |
| return self._descriptions == other._descriptions | |
| def __hash__(self) -> int: | |
| return hash(tuple(self._descriptions)) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class SubjectInformationAccess(ExtensionType): | |
| oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS | |
| def __init__(self, descriptions: Iterable[AccessDescription]) -> None: | |
| descriptions = list(descriptions) | |
| if not all(isinstance(x, AccessDescription) for x in descriptions): | |
| raise TypeError( | |
| "Every item in the descriptions list must be an " | |
| "AccessDescription" | |
| ) | |
| self._descriptions = descriptions | |
| __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") | |
| def __repr__(self) -> str: | |
| return f"<SubjectInformationAccess({self._descriptions})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, SubjectInformationAccess): | |
| return NotImplemented | |
| return self._descriptions == other._descriptions | |
| def __hash__(self) -> int: | |
| return hash(tuple(self._descriptions)) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class AccessDescription: | |
| def __init__( | |
| self, access_method: ObjectIdentifier, access_location: GeneralName | |
| ) -> None: | |
| if not isinstance(access_method, ObjectIdentifier): | |
| raise TypeError("access_method must be an ObjectIdentifier") | |
| if not isinstance(access_location, GeneralName): | |
| raise TypeError("access_location must be a GeneralName") | |
| self._access_method = access_method | |
| self._access_location = access_location | |
| def __repr__(self) -> str: | |
| return ( | |
| f"<AccessDescription(access_method={self.access_method}, " | |
| f"access_location={self.access_location})>" | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, AccessDescription): | |
| return NotImplemented | |
| return ( | |
| self.access_method == other.access_method | |
| and self.access_location == other.access_location | |
| ) | |
| def __hash__(self) -> int: | |
| return hash((self.access_method, self.access_location)) | |
| def access_method(self) -> ObjectIdentifier: | |
| return self._access_method | |
| def access_location(self) -> GeneralName: | |
| return self._access_location | |
| class BasicConstraints(ExtensionType): | |
| oid = ExtensionOID.BASIC_CONSTRAINTS | |
| def __init__(self, ca: bool, path_length: int | None) -> None: | |
| if not isinstance(ca, bool): | |
| raise TypeError("ca must be a boolean value") | |
| if path_length is not None and not ca: | |
| raise ValueError("path_length must be None when ca is False") | |
| if path_length is not None and ( | |
| not isinstance(path_length, int) or path_length < 0 | |
| ): | |
| raise TypeError( | |
| "path_length must be a non-negative integer or None" | |
| ) | |
| self._ca = ca | |
| self._path_length = path_length | |
| def ca(self) -> bool: | |
| return self._ca | |
| def path_length(self) -> int | None: | |
| return self._path_length | |
| def __repr__(self) -> str: | |
| return ( | |
| f"<BasicConstraints(ca={self.ca}, path_length={self.path_length})>" | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, BasicConstraints): | |
| return NotImplemented | |
| return self.ca == other.ca and self.path_length == other.path_length | |
| def __hash__(self) -> int: | |
| return hash((self.ca, self.path_length)) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class DeltaCRLIndicator(ExtensionType): | |
| oid = ExtensionOID.DELTA_CRL_INDICATOR | |
| def __init__(self, crl_number: int) -> None: | |
| if not isinstance(crl_number, int): | |
| raise TypeError("crl_number must be an integer") | |
| self._crl_number = crl_number | |
| def crl_number(self) -> int: | |
| return self._crl_number | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, DeltaCRLIndicator): | |
| return NotImplemented | |
| return self.crl_number == other.crl_number | |
| def __hash__(self) -> int: | |
| return hash(self.crl_number) | |
| def __repr__(self) -> str: | |
| return f"<DeltaCRLIndicator(crl_number={self.crl_number})>" | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class CRLDistributionPoints(ExtensionType): | |
| oid = ExtensionOID.CRL_DISTRIBUTION_POINTS | |
| def __init__( | |
| self, distribution_points: Iterable[DistributionPoint] | |
| ) -> None: | |
| distribution_points = list(distribution_points) | |
| if not all( | |
| isinstance(x, DistributionPoint) for x in distribution_points | |
| ): | |
| raise TypeError( | |
| "distribution_points must be a list of DistributionPoint " | |
| "objects" | |
| ) | |
| self._distribution_points = distribution_points | |
| __len__, __iter__, __getitem__ = _make_sequence_methods( | |
| "_distribution_points" | |
| ) | |
| def __repr__(self) -> str: | |
| return f"<CRLDistributionPoints({self._distribution_points})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, CRLDistributionPoints): | |
| return NotImplemented | |
| return self._distribution_points == other._distribution_points | |
| def __hash__(self) -> int: | |
| return hash(tuple(self._distribution_points)) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class FreshestCRL(ExtensionType): | |
| oid = ExtensionOID.FRESHEST_CRL | |
| def __init__( | |
| self, distribution_points: Iterable[DistributionPoint] | |
| ) -> None: | |
| distribution_points = list(distribution_points) | |
| if not all( | |
| isinstance(x, DistributionPoint) for x in distribution_points | |
| ): | |
| raise TypeError( | |
| "distribution_points must be a list of DistributionPoint " | |
| "objects" | |
| ) | |
| self._distribution_points = distribution_points | |
| __len__, __iter__, __getitem__ = _make_sequence_methods( | |
| "_distribution_points" | |
| ) | |
| def __repr__(self) -> str: | |
| return f"<FreshestCRL({self._distribution_points})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, FreshestCRL): | |
| return NotImplemented | |
| return self._distribution_points == other._distribution_points | |
| def __hash__(self) -> int: | |
| return hash(tuple(self._distribution_points)) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class DistributionPoint: | |
| def __init__( | |
| self, | |
| full_name: Iterable[GeneralName] | None, | |
| relative_name: RelativeDistinguishedName | None, | |
| reasons: frozenset[ReasonFlags] | None, | |
| crl_issuer: Iterable[GeneralName] | None, | |
| ) -> None: | |
| if full_name and relative_name: | |
| raise ValueError( | |
| "You cannot provide both full_name and relative_name, at " | |
| "least one must be None." | |
| ) | |
| if not full_name and not relative_name and not crl_issuer: | |
| raise ValueError( | |
| "Either full_name, relative_name or crl_issuer must be " | |
| "provided." | |
| ) | |
| if full_name is not None: | |
| full_name = list(full_name) | |
| if not all(isinstance(x, GeneralName) for x in full_name): | |
| raise TypeError( | |
| "full_name must be a list of GeneralName objects" | |
| ) | |
| if relative_name: | |
| if not isinstance(relative_name, RelativeDistinguishedName): | |
| raise TypeError( | |
| "relative_name must be a RelativeDistinguishedName" | |
| ) | |
| if crl_issuer is not None: | |
| crl_issuer = list(crl_issuer) | |
| if not all(isinstance(x, GeneralName) for x in crl_issuer): | |
| raise TypeError( | |
| "crl_issuer must be None or a list of general names" | |
| ) | |
| if reasons and ( | |
| not isinstance(reasons, frozenset) | |
| or not all(isinstance(x, ReasonFlags) for x in reasons) | |
| ): | |
| raise TypeError("reasons must be None or frozenset of ReasonFlags") | |
| if reasons and ( | |
| ReasonFlags.unspecified in reasons | |
| or ReasonFlags.remove_from_crl in reasons | |
| ): | |
| raise ValueError( | |
| "unspecified and remove_from_crl are not valid reasons in a " | |
| "DistributionPoint" | |
| ) | |
| self._full_name = full_name | |
| self._relative_name = relative_name | |
| self._reasons = reasons | |
| self._crl_issuer = crl_issuer | |
| def __repr__(self) -> str: | |
| return ( | |
| "<DistributionPoint(full_name={0.full_name}, relative_name={0.rela" | |
| "tive_name}, reasons={0.reasons}, " | |
| "crl_issuer={0.crl_issuer})>".format(self) | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, DistributionPoint): | |
| return NotImplemented | |
| return ( | |
| self.full_name == other.full_name | |
| and self.relative_name == other.relative_name | |
| and self.reasons == other.reasons | |
| and self.crl_issuer == other.crl_issuer | |
| ) | |
| def __hash__(self) -> int: | |
| if self.full_name is not None: | |
| fn: tuple[GeneralName, ...] | None = tuple(self.full_name) | |
| else: | |
| fn = None | |
| if self.crl_issuer is not None: | |
| crl_issuer: tuple[GeneralName, ...] | None = tuple(self.crl_issuer) | |
| else: | |
| crl_issuer = None | |
| return hash((fn, self.relative_name, self.reasons, crl_issuer)) | |
| def full_name(self) -> list[GeneralName] | None: | |
| return self._full_name | |
| def relative_name(self) -> RelativeDistinguishedName | None: | |
| return self._relative_name | |
| def reasons(self) -> frozenset[ReasonFlags] | None: | |
| return self._reasons | |
| def crl_issuer(self) -> list[GeneralName] | None: | |
| return self._crl_issuer | |
| class ReasonFlags(utils.Enum): | |
| unspecified = "unspecified" | |
| key_compromise = "keyCompromise" | |
| ca_compromise = "cACompromise" | |
| affiliation_changed = "affiliationChanged" | |
| superseded = "superseded" | |
| cessation_of_operation = "cessationOfOperation" | |
| certificate_hold = "certificateHold" | |
| privilege_withdrawn = "privilegeWithdrawn" | |
| aa_compromise = "aACompromise" | |
| remove_from_crl = "removeFromCRL" | |
| # These are distribution point bit string mappings. Not to be confused with | |
| # CRLReason reason flags bit string mappings. | |
| # ReasonFlags ::= BIT STRING { | |
| # unused (0), | |
| # keyCompromise (1), | |
| # cACompromise (2), | |
| # affiliationChanged (3), | |
| # superseded (4), | |
| # cessationOfOperation (5), | |
| # certificateHold (6), | |
| # privilegeWithdrawn (7), | |
| # aACompromise (8) } | |
| _REASON_BIT_MAPPING = { | |
| 1: ReasonFlags.key_compromise, | |
| 2: ReasonFlags.ca_compromise, | |
| 3: ReasonFlags.affiliation_changed, | |
| 4: ReasonFlags.superseded, | |
| 5: ReasonFlags.cessation_of_operation, | |
| 6: ReasonFlags.certificate_hold, | |
| 7: ReasonFlags.privilege_withdrawn, | |
| 8: ReasonFlags.aa_compromise, | |
| } | |
| _CRLREASONFLAGS = { | |
| ReasonFlags.key_compromise: 1, | |
| ReasonFlags.ca_compromise: 2, | |
| ReasonFlags.affiliation_changed: 3, | |
| ReasonFlags.superseded: 4, | |
| ReasonFlags.cessation_of_operation: 5, | |
| ReasonFlags.certificate_hold: 6, | |
| ReasonFlags.privilege_withdrawn: 7, | |
| ReasonFlags.aa_compromise: 8, | |
| } | |
| # CRLReason ::= ENUMERATED { | |
| # unspecified (0), | |
| # keyCompromise (1), | |
| # cACompromise (2), | |
| # affiliationChanged (3), | |
| # superseded (4), | |
| # cessationOfOperation (5), | |
| # certificateHold (6), | |
| # -- value 7 is not used | |
| # removeFromCRL (8), | |
| # privilegeWithdrawn (9), | |
| # aACompromise (10) } | |
| _CRL_ENTRY_REASON_ENUM_TO_CODE = { | |
| ReasonFlags.unspecified: 0, | |
| ReasonFlags.key_compromise: 1, | |
| ReasonFlags.ca_compromise: 2, | |
| ReasonFlags.affiliation_changed: 3, | |
| ReasonFlags.superseded: 4, | |
| ReasonFlags.cessation_of_operation: 5, | |
| ReasonFlags.certificate_hold: 6, | |
| ReasonFlags.remove_from_crl: 8, | |
| ReasonFlags.privilege_withdrawn: 9, | |
| ReasonFlags.aa_compromise: 10, | |
| } | |
| class PolicyConstraints(ExtensionType): | |
| oid = ExtensionOID.POLICY_CONSTRAINTS | |
| def __init__( | |
| self, | |
| require_explicit_policy: int | None, | |
| inhibit_policy_mapping: int | None, | |
| ) -> None: | |
| if require_explicit_policy is not None and not isinstance( | |
| require_explicit_policy, int | |
| ): | |
| raise TypeError( | |
| "require_explicit_policy must be a non-negative integer or " | |
| "None" | |
| ) | |
| if inhibit_policy_mapping is not None and not isinstance( | |
| inhibit_policy_mapping, int | |
| ): | |
| raise TypeError( | |
| "inhibit_policy_mapping must be a non-negative integer or None" | |
| ) | |
| if inhibit_policy_mapping is None and require_explicit_policy is None: | |
| raise ValueError( | |
| "At least one of require_explicit_policy and " | |
| "inhibit_policy_mapping must not be None" | |
| ) | |
| self._require_explicit_policy = require_explicit_policy | |
| self._inhibit_policy_mapping = inhibit_policy_mapping | |
| def __repr__(self) -> str: | |
| return ( | |
| "<PolicyConstraints(require_explicit_policy={0.require_explicit" | |
| "_policy}, inhibit_policy_mapping={0.inhibit_policy_" | |
| "mapping})>".format(self) | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, PolicyConstraints): | |
| return NotImplemented | |
| return ( | |
| self.require_explicit_policy == other.require_explicit_policy | |
| and self.inhibit_policy_mapping == other.inhibit_policy_mapping | |
| ) | |
| def __hash__(self) -> int: | |
| return hash( | |
| (self.require_explicit_policy, self.inhibit_policy_mapping) | |
| ) | |
| def require_explicit_policy(self) -> int | None: | |
| return self._require_explicit_policy | |
| def inhibit_policy_mapping(self) -> int | None: | |
| return self._inhibit_policy_mapping | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class CertificatePolicies(ExtensionType): | |
| oid = ExtensionOID.CERTIFICATE_POLICIES | |
| def __init__(self, policies: Iterable[PolicyInformation]) -> None: | |
| policies = list(policies) | |
| if not all(isinstance(x, PolicyInformation) for x in policies): | |
| raise TypeError( | |
| "Every item in the policies list must be a PolicyInformation" | |
| ) | |
| self._policies = policies | |
| __len__, __iter__, __getitem__ = _make_sequence_methods("_policies") | |
| def __repr__(self) -> str: | |
| return f"<CertificatePolicies({self._policies})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, CertificatePolicies): | |
| return NotImplemented | |
| return self._policies == other._policies | |
| def __hash__(self) -> int: | |
| return hash(tuple(self._policies)) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class PolicyInformation: | |
| def __init__( | |
| self, | |
| policy_identifier: ObjectIdentifier, | |
| policy_qualifiers: Iterable[str | UserNotice] | None, | |
| ) -> None: | |
| if not isinstance(policy_identifier, ObjectIdentifier): | |
| raise TypeError("policy_identifier must be an ObjectIdentifier") | |
| self._policy_identifier = policy_identifier | |
| if policy_qualifiers is not None: | |
| policy_qualifiers = list(policy_qualifiers) | |
| if not all( | |
| isinstance(x, (str, UserNotice)) for x in policy_qualifiers | |
| ): | |
| raise TypeError( | |
| "policy_qualifiers must be a list of strings and/or " | |
| "UserNotice objects or None" | |
| ) | |
| self._policy_qualifiers = policy_qualifiers | |
| def __repr__(self) -> str: | |
| return ( | |
| f"<PolicyInformation(policy_identifier={self.policy_identifier}, " | |
| f"policy_qualifiers={self.policy_qualifiers})>" | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, PolicyInformation): | |
| return NotImplemented | |
| return ( | |
| self.policy_identifier == other.policy_identifier | |
| and self.policy_qualifiers == other.policy_qualifiers | |
| ) | |
| def __hash__(self) -> int: | |
| if self.policy_qualifiers is not None: | |
| pq = tuple(self.policy_qualifiers) | |
| else: | |
| pq = None | |
| return hash((self.policy_identifier, pq)) | |
| def policy_identifier(self) -> ObjectIdentifier: | |
| return self._policy_identifier | |
| def policy_qualifiers( | |
| self, | |
| ) -> list[str | UserNotice] | None: | |
| return self._policy_qualifiers | |
| class UserNotice: | |
| def __init__( | |
| self, | |
| notice_reference: NoticeReference | None, | |
| explicit_text: str | None, | |
| ) -> None: | |
| if notice_reference and not isinstance( | |
| notice_reference, NoticeReference | |
| ): | |
| raise TypeError( | |
| "notice_reference must be None or a NoticeReference" | |
| ) | |
| self._notice_reference = notice_reference | |
| self._explicit_text = explicit_text | |
| def __repr__(self) -> str: | |
| return ( | |
| f"<UserNotice(notice_reference={self.notice_reference}, " | |
| f"explicit_text={self.explicit_text!r})>" | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, UserNotice): | |
| return NotImplemented | |
| return ( | |
| self.notice_reference == other.notice_reference | |
| and self.explicit_text == other.explicit_text | |
| ) | |
| def __hash__(self) -> int: | |
| return hash((self.notice_reference, self.explicit_text)) | |
| def notice_reference(self) -> NoticeReference | None: | |
| return self._notice_reference | |
| def explicit_text(self) -> str | None: | |
| return self._explicit_text | |
| class NoticeReference: | |
| def __init__( | |
| self, | |
| organization: str | None, | |
| notice_numbers: Iterable[int], | |
| ) -> None: | |
| self._organization = organization | |
| notice_numbers = list(notice_numbers) | |
| if not all(isinstance(x, int) for x in notice_numbers): | |
| raise TypeError("notice_numbers must be a list of integers") | |
| self._notice_numbers = notice_numbers | |
| def __repr__(self) -> str: | |
| return ( | |
| f"<NoticeReference(organization={self.organization!r}, " | |
| f"notice_numbers={self.notice_numbers})>" | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, NoticeReference): | |
| return NotImplemented | |
| return ( | |
| self.organization == other.organization | |
| and self.notice_numbers == other.notice_numbers | |
| ) | |
| def __hash__(self) -> int: | |
| return hash((self.organization, tuple(self.notice_numbers))) | |
| def organization(self) -> str | None: | |
| return self._organization | |
| def notice_numbers(self) -> list[int]: | |
| return self._notice_numbers | |
| class ExtendedKeyUsage(ExtensionType): | |
| oid = ExtensionOID.EXTENDED_KEY_USAGE | |
| def __init__(self, usages: Iterable[ObjectIdentifier]) -> None: | |
| usages = list(usages) | |
| if not all(isinstance(x, ObjectIdentifier) for x in usages): | |
| raise TypeError( | |
| "Every item in the usages list must be an ObjectIdentifier" | |
| ) | |
| self._usages = usages | |
| __len__, __iter__, __getitem__ = _make_sequence_methods("_usages") | |
| def __repr__(self) -> str: | |
| return f"<ExtendedKeyUsage({self._usages})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, ExtendedKeyUsage): | |
| return NotImplemented | |
| return self._usages == other._usages | |
| def __hash__(self) -> int: | |
| return hash(tuple(self._usages)) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class OCSPNoCheck(ExtensionType): | |
| oid = ExtensionOID.OCSP_NO_CHECK | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, OCSPNoCheck): | |
| return NotImplemented | |
| return True | |
| def __hash__(self) -> int: | |
| return hash(OCSPNoCheck) | |
| def __repr__(self) -> str: | |
| return "<OCSPNoCheck()>" | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class PrecertPoison(ExtensionType): | |
| oid = ExtensionOID.PRECERT_POISON | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, PrecertPoison): | |
| return NotImplemented | |
| return True | |
| def __hash__(self) -> int: | |
| return hash(PrecertPoison) | |
| def __repr__(self) -> str: | |
| return "<PrecertPoison()>" | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class TLSFeature(ExtensionType): | |
| oid = ExtensionOID.TLS_FEATURE | |
| def __init__(self, features: Iterable[TLSFeatureType]) -> None: | |
| features = list(features) | |
| if ( | |
| not all(isinstance(x, TLSFeatureType) for x in features) | |
| or len(features) == 0 | |
| ): | |
| raise TypeError( | |
| "features must be a list of elements from the TLSFeatureType " | |
| "enum" | |
| ) | |
| self._features = features | |
| __len__, __iter__, __getitem__ = _make_sequence_methods("_features") | |
| def __repr__(self) -> str: | |
| return f"<TLSFeature(features={self._features})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, TLSFeature): | |
| return NotImplemented | |
| return self._features == other._features | |
| def __hash__(self) -> int: | |
| return hash(tuple(self._features)) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class TLSFeatureType(utils.Enum): | |
| # status_request is defined in RFC 6066 and is used for what is commonly | |
| # called OCSP Must-Staple when present in the TLS Feature extension in an | |
| # X.509 certificate. | |
| status_request = 5 | |
| # status_request_v2 is defined in RFC 6961 and allows multiple OCSP | |
| # responses to be provided. It is not currently in use by clients or | |
| # servers. | |
| status_request_v2 = 17 | |
| _TLS_FEATURE_TYPE_TO_ENUM = {x.value: x for x in TLSFeatureType} | |
| class InhibitAnyPolicy(ExtensionType): | |
| oid = ExtensionOID.INHIBIT_ANY_POLICY | |
| def __init__(self, skip_certs: int) -> None: | |
| if not isinstance(skip_certs, int): | |
| raise TypeError("skip_certs must be an integer") | |
| if skip_certs < 0: | |
| raise ValueError("skip_certs must be a non-negative integer") | |
| self._skip_certs = skip_certs | |
| def __repr__(self) -> str: | |
| return f"<InhibitAnyPolicy(skip_certs={self.skip_certs})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, InhibitAnyPolicy): | |
| return NotImplemented | |
| return self.skip_certs == other.skip_certs | |
| def __hash__(self) -> int: | |
| return hash(self.skip_certs) | |
| def skip_certs(self) -> int: | |
| return self._skip_certs | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class KeyUsage(ExtensionType): | |
| oid = ExtensionOID.KEY_USAGE | |
| def __init__( | |
| self, | |
| digital_signature: bool, | |
| content_commitment: bool, | |
| key_encipherment: bool, | |
| data_encipherment: bool, | |
| key_agreement: bool, | |
| key_cert_sign: bool, | |
| crl_sign: bool, | |
| encipher_only: bool, | |
| decipher_only: bool, | |
| ) -> None: | |
| if not key_agreement and (encipher_only or decipher_only): | |
| raise ValueError( | |
| "encipher_only and decipher_only can only be true when " | |
| "key_agreement is true" | |
| ) | |
| self._digital_signature = digital_signature | |
| self._content_commitment = content_commitment | |
| self._key_encipherment = key_encipherment | |
| self._data_encipherment = data_encipherment | |
| self._key_agreement = key_agreement | |
| self._key_cert_sign = key_cert_sign | |
| self._crl_sign = crl_sign | |
| self._encipher_only = encipher_only | |
| self._decipher_only = decipher_only | |
| def digital_signature(self) -> bool: | |
| return self._digital_signature | |
| def content_commitment(self) -> bool: | |
| return self._content_commitment | |
| def key_encipherment(self) -> bool: | |
| return self._key_encipherment | |
| def data_encipherment(self) -> bool: | |
| return self._data_encipherment | |
| def key_agreement(self) -> bool: | |
| return self._key_agreement | |
| def key_cert_sign(self) -> bool: | |
| return self._key_cert_sign | |
| def crl_sign(self) -> bool: | |
| return self._crl_sign | |
| def encipher_only(self) -> bool: | |
| if not self.key_agreement: | |
| raise ValueError( | |
| "encipher_only is undefined unless key_agreement is true" | |
| ) | |
| else: | |
| return self._encipher_only | |
| def decipher_only(self) -> bool: | |
| if not self.key_agreement: | |
| raise ValueError( | |
| "decipher_only is undefined unless key_agreement is true" | |
| ) | |
| else: | |
| return self._decipher_only | |
| def __repr__(self) -> str: | |
| try: | |
| encipher_only = self.encipher_only | |
| decipher_only = self.decipher_only | |
| except ValueError: | |
| # Users found None confusing because even though encipher/decipher | |
| # have no meaning unless key_agreement is true, to construct an | |
| # instance of the class you still need to pass False. | |
| encipher_only = False | |
| decipher_only = False | |
| return ( | |
| f"<KeyUsage(digital_signature={self.digital_signature}, " | |
| f"content_commitment={self.content_commitment}, " | |
| f"key_encipherment={self.key_encipherment}, " | |
| f"data_encipherment={self.data_encipherment}, " | |
| f"key_agreement={self.key_agreement}, " | |
| f"key_cert_sign={self.key_cert_sign}, crl_sign={self.crl_sign}, " | |
| f"encipher_only={encipher_only}, decipher_only={decipher_only})>" | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, KeyUsage): | |
| return NotImplemented | |
| return ( | |
| self.digital_signature == other.digital_signature | |
| and self.content_commitment == other.content_commitment | |
| and self.key_encipherment == other.key_encipherment | |
| and self.data_encipherment == other.data_encipherment | |
| and self.key_agreement == other.key_agreement | |
| and self.key_cert_sign == other.key_cert_sign | |
| and self.crl_sign == other.crl_sign | |
| and self._encipher_only == other._encipher_only | |
| and self._decipher_only == other._decipher_only | |
| ) | |
| def __hash__(self) -> int: | |
| return hash( | |
| ( | |
| self.digital_signature, | |
| self.content_commitment, | |
| self.key_encipherment, | |
| self.data_encipherment, | |
| self.key_agreement, | |
| self.key_cert_sign, | |
| self.crl_sign, | |
| self._encipher_only, | |
| self._decipher_only, | |
| ) | |
| ) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class PrivateKeyUsagePeriod(ExtensionType): | |
| oid = ExtensionOID.PRIVATE_KEY_USAGE_PERIOD | |
| def __init__( | |
| self, | |
| not_before: datetime.datetime | None, | |
| not_after: datetime.datetime | None, | |
| ) -> None: | |
| if ( | |
| not isinstance(not_before, datetime.datetime) | |
| and not_before is not None | |
| ): | |
| raise TypeError("not_before must be a datetime.datetime or None") | |
| if ( | |
| not isinstance(not_after, datetime.datetime) | |
| and not_after is not None | |
| ): | |
| raise TypeError("not_after must be a datetime.datetime or None") | |
| if not_before is None and not_after is None: | |
| raise ValueError( | |
| "At least one of not_before and not_after must not be None" | |
| ) | |
| if ( | |
| not_before is not None | |
| and not_after is not None | |
| and not_before > not_after | |
| ): | |
| raise ValueError("not_before must be before not_after") | |
| self._not_before = not_before | |
| self._not_after = not_after | |
| def not_before(self) -> datetime.datetime | None: | |
| return self._not_before | |
| def not_after(self) -> datetime.datetime | None: | |
| return self._not_after | |
| def __repr__(self) -> str: | |
| return ( | |
| f"<PrivateKeyUsagePeriod(not_before={self.not_before}, " | |
| f"not_after={self.not_after})>" | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, PrivateKeyUsagePeriod): | |
| return NotImplemented | |
| return ( | |
| self.not_before == other.not_before | |
| and self.not_after == other.not_after | |
| ) | |
| def __hash__(self) -> int: | |
| return hash((self.not_before, self.not_after)) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class NameConstraints(ExtensionType): | |
| oid = ExtensionOID.NAME_CONSTRAINTS | |
| def __init__( | |
| self, | |
| permitted_subtrees: Iterable[GeneralName] | None, | |
| excluded_subtrees: Iterable[GeneralName] | None, | |
| ) -> None: | |
| if permitted_subtrees is not None: | |
| permitted_subtrees = list(permitted_subtrees) | |
| if not permitted_subtrees: | |
| raise ValueError( | |
| "permitted_subtrees must be a non-empty list or None" | |
| ) | |
| if not all(isinstance(x, GeneralName) for x in permitted_subtrees): | |
| raise TypeError( | |
| "permitted_subtrees must be a list of GeneralName objects " | |
| "or None" | |
| ) | |
| self._validate_tree(permitted_subtrees) | |
| if excluded_subtrees is not None: | |
| excluded_subtrees = list(excluded_subtrees) | |
| if not excluded_subtrees: | |
| raise ValueError( | |
| "excluded_subtrees must be a non-empty list or None" | |
| ) | |
| if not all(isinstance(x, GeneralName) for x in excluded_subtrees): | |
| raise TypeError( | |
| "excluded_subtrees must be a list of GeneralName objects " | |
| "or None" | |
| ) | |
| self._validate_tree(excluded_subtrees) | |
| if permitted_subtrees is None and excluded_subtrees is None: | |
| raise ValueError( | |
| "At least one of permitted_subtrees and excluded_subtrees " | |
| "must not be None" | |
| ) | |
| self._permitted_subtrees = permitted_subtrees | |
| self._excluded_subtrees = excluded_subtrees | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, NameConstraints): | |
| return NotImplemented | |
| return ( | |
| self.excluded_subtrees == other.excluded_subtrees | |
| and self.permitted_subtrees == other.permitted_subtrees | |
| ) | |
| def _validate_tree(self, tree: Iterable[GeneralName]) -> None: | |
| self._validate_ip_name(tree) | |
| self._validate_dns_name(tree) | |
| def _validate_ip_name(self, tree: Iterable[GeneralName]) -> None: | |
| if any( | |
| isinstance(name, IPAddress) | |
| and not isinstance( | |
| name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network) | |
| ) | |
| for name in tree | |
| ): | |
| raise TypeError( | |
| "IPAddress name constraints must be an IPv4Network or" | |
| " IPv6Network object" | |
| ) | |
| def _validate_dns_name(self, tree: Iterable[GeneralName]) -> None: | |
| if any( | |
| isinstance(name, DNSName) and "*" in name.value for name in tree | |
| ): | |
| raise ValueError( | |
| "DNSName name constraints must not contain the '*' wildcard" | |
| " character" | |
| ) | |
| def __repr__(self) -> str: | |
| return ( | |
| f"<NameConstraints(permitted_subtrees={self.permitted_subtrees}, " | |
| f"excluded_subtrees={self.excluded_subtrees})>" | |
| ) | |
| def __hash__(self) -> int: | |
| if self.permitted_subtrees is not None: | |
| ps: tuple[GeneralName, ...] | None = tuple(self.permitted_subtrees) | |
| else: | |
| ps = None | |
| if self.excluded_subtrees is not None: | |
| es: tuple[GeneralName, ...] | None = tuple(self.excluded_subtrees) | |
| else: | |
| es = None | |
| return hash((ps, es)) | |
| def permitted_subtrees( | |
| self, | |
| ) -> list[GeneralName] | None: | |
| return self._permitted_subtrees | |
| def excluded_subtrees( | |
| self, | |
| ) -> list[GeneralName] | None: | |
| return self._excluded_subtrees | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class Extension(typing.Generic[ExtensionTypeVar]): | |
| def __init__( | |
| self, oid: ObjectIdentifier, critical: bool, value: ExtensionTypeVar | |
| ) -> None: | |
| if not isinstance(oid, ObjectIdentifier): | |
| raise TypeError( | |
| "oid argument must be an ObjectIdentifier instance." | |
| ) | |
| if not isinstance(critical, bool): | |
| raise TypeError("critical must be a boolean value") | |
| self._oid = oid | |
| self._critical = critical | |
| self._value = value | |
| def oid(self) -> ObjectIdentifier: | |
| return self._oid | |
| def critical(self) -> bool: | |
| return self._critical | |
| def value(self) -> ExtensionTypeVar: | |
| return self._value | |
| def __repr__(self) -> str: | |
| return ( | |
| f"<Extension(oid={self.oid}, critical={self.critical}, " | |
| f"value={self.value})>" | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, Extension): | |
| return NotImplemented | |
| return ( | |
| self.oid == other.oid | |
| and self.critical == other.critical | |
| and self.value == other.value | |
| ) | |
| def __hash__(self) -> int: | |
| return hash((self.oid, self.critical, self.value)) | |
| class GeneralNames: | |
| def __init__(self, general_names: Iterable[GeneralName]) -> None: | |
| general_names = list(general_names) | |
| if not all(isinstance(x, GeneralName) for x in general_names): | |
| raise TypeError( | |
| "Every item in the general_names list must be an " | |
| "object conforming to the GeneralName interface" | |
| ) | |
| self._general_names = general_names | |
| __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") | |
| def get_values_for_type( | |
| self, | |
| type: type[DNSName] | |
| | type[UniformResourceIdentifier] | |
| | type[RFC822Name], | |
| ) -> list[str]: ... | |
| def get_values_for_type( | |
| self, | |
| type: type[DirectoryName], | |
| ) -> list[Name]: ... | |
| def get_values_for_type( | |
| self, | |
| type: type[RegisteredID], | |
| ) -> list[ObjectIdentifier]: ... | |
| def get_values_for_type( | |
| self, type: type[IPAddress] | |
| ) -> list[_IPAddressTypes]: ... | |
| def get_values_for_type( | |
| self, type: type[OtherName] | |
| ) -> list[OtherName]: ... | |
| def get_values_for_type( | |
| self, | |
| type: type[DNSName] | |
| | type[DirectoryName] | |
| | type[IPAddress] | |
| | type[OtherName] | |
| | type[RFC822Name] | |
| | type[RegisteredID] | |
| | type[UniformResourceIdentifier], | |
| ) -> ( | |
| list[_IPAddressTypes] | |
| | list[str] | |
| | list[OtherName] | |
| | list[Name] | |
| | list[ObjectIdentifier] | |
| ): | |
| # Return the value of each GeneralName, except for OtherName instances | |
| # which we return directly because it has two important properties not | |
| # just one value. | |
| objs = (i for i in self if isinstance(i, type)) | |
| if type != OtherName: | |
| return [i.value for i in objs] | |
| return list(objs) | |
| def __repr__(self) -> str: | |
| return f"<GeneralNames({self._general_names})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, GeneralNames): | |
| return NotImplemented | |
| return self._general_names == other._general_names | |
| def __hash__(self) -> int: | |
| return hash(tuple(self._general_names)) | |
| class SubjectAlternativeName(ExtensionType): | |
| oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME | |
| def __init__(self, general_names: Iterable[GeneralName]) -> None: | |
| self._general_names = GeneralNames(general_names) | |
| __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") | |
| def get_values_for_type( | |
| self, | |
| type: type[DNSName] | |
| | type[UniformResourceIdentifier] | |
| | type[RFC822Name], | |
| ) -> list[str]: ... | |
| def get_values_for_type( | |
| self, | |
| type: type[DirectoryName], | |
| ) -> list[Name]: ... | |
| def get_values_for_type( | |
| self, | |
| type: type[RegisteredID], | |
| ) -> list[ObjectIdentifier]: ... | |
| def get_values_for_type( | |
| self, type: type[IPAddress] | |
| ) -> list[_IPAddressTypes]: ... | |
| def get_values_for_type( | |
| self, type: type[OtherName] | |
| ) -> list[OtherName]: ... | |
| def get_values_for_type( | |
| self, | |
| type: type[DNSName] | |
| | type[DirectoryName] | |
| | type[IPAddress] | |
| | type[OtherName] | |
| | type[RFC822Name] | |
| | type[RegisteredID] | |
| | type[UniformResourceIdentifier], | |
| ) -> ( | |
| list[_IPAddressTypes] | |
| | list[str] | |
| | list[OtherName] | |
| | list[Name] | |
| | list[ObjectIdentifier] | |
| ): | |
| return self._general_names.get_values_for_type(type) | |
| def __repr__(self) -> str: | |
| return f"<SubjectAlternativeName({self._general_names})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, SubjectAlternativeName): | |
| return NotImplemented | |
| return self._general_names == other._general_names | |
| def __hash__(self) -> int: | |
| return hash(self._general_names) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class IssuerAlternativeName(ExtensionType): | |
| oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME | |
| def __init__(self, general_names: Iterable[GeneralName]) -> None: | |
| self._general_names = GeneralNames(general_names) | |
| __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") | |
| def get_values_for_type( | |
| self, | |
| type: type[DNSName] | |
| | type[UniformResourceIdentifier] | |
| | type[RFC822Name], | |
| ) -> list[str]: ... | |
| def get_values_for_type( | |
| self, | |
| type: type[DirectoryName], | |
| ) -> list[Name]: ... | |
| def get_values_for_type( | |
| self, | |
| type: type[RegisteredID], | |
| ) -> list[ObjectIdentifier]: ... | |
| def get_values_for_type( | |
| self, type: type[IPAddress] | |
| ) -> list[_IPAddressTypes]: ... | |
| def get_values_for_type( | |
| self, type: type[OtherName] | |
| ) -> list[OtherName]: ... | |
| def get_values_for_type( | |
| self, | |
| type: type[DNSName] | |
| | type[DirectoryName] | |
| | type[IPAddress] | |
| | type[OtherName] | |
| | type[RFC822Name] | |
| | type[RegisteredID] | |
| | type[UniformResourceIdentifier], | |
| ) -> ( | |
| list[_IPAddressTypes] | |
| | list[str] | |
| | list[OtherName] | |
| | list[Name] | |
| | list[ObjectIdentifier] | |
| ): | |
| return self._general_names.get_values_for_type(type) | |
| def __repr__(self) -> str: | |
| return f"<IssuerAlternativeName({self._general_names})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, IssuerAlternativeName): | |
| return NotImplemented | |
| return self._general_names == other._general_names | |
| def __hash__(self) -> int: | |
| return hash(self._general_names) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class CertificateIssuer(ExtensionType): | |
| oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER | |
| def __init__(self, general_names: Iterable[GeneralName]) -> None: | |
| self._general_names = GeneralNames(general_names) | |
| __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") | |
| def get_values_for_type( | |
| self, | |
| type: type[DNSName] | |
| | type[UniformResourceIdentifier] | |
| | type[RFC822Name], | |
| ) -> list[str]: ... | |
| def get_values_for_type( | |
| self, | |
| type: type[DirectoryName], | |
| ) -> list[Name]: ... | |
| def get_values_for_type( | |
| self, | |
| type: type[RegisteredID], | |
| ) -> list[ObjectIdentifier]: ... | |
| def get_values_for_type( | |
| self, type: type[IPAddress] | |
| ) -> list[_IPAddressTypes]: ... | |
| def get_values_for_type( | |
| self, type: type[OtherName] | |
| ) -> list[OtherName]: ... | |
| def get_values_for_type( | |
| self, | |
| type: type[DNSName] | |
| | type[DirectoryName] | |
| | type[IPAddress] | |
| | type[OtherName] | |
| | type[RFC822Name] | |
| | type[RegisteredID] | |
| | type[UniformResourceIdentifier], | |
| ) -> ( | |
| list[_IPAddressTypes] | |
| | list[str] | |
| | list[OtherName] | |
| | list[Name] | |
| | list[ObjectIdentifier] | |
| ): | |
| return self._general_names.get_values_for_type(type) | |
| def __repr__(self) -> str: | |
| return f"<CertificateIssuer({self._general_names})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, CertificateIssuer): | |
| return NotImplemented | |
| return self._general_names == other._general_names | |
| def __hash__(self) -> int: | |
| return hash(self._general_names) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class CRLReason(ExtensionType): | |
| oid = CRLEntryExtensionOID.CRL_REASON | |
| def __init__(self, reason: ReasonFlags) -> None: | |
| if not isinstance(reason, ReasonFlags): | |
| raise TypeError("reason must be an element from ReasonFlags") | |
| self._reason = reason | |
| def __repr__(self) -> str: | |
| return f"<CRLReason(reason={self._reason})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, CRLReason): | |
| return NotImplemented | |
| return self.reason == other.reason | |
| def __hash__(self) -> int: | |
| return hash(self.reason) | |
| def reason(self) -> ReasonFlags: | |
| return self._reason | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class InvalidityDate(ExtensionType): | |
| oid = CRLEntryExtensionOID.INVALIDITY_DATE | |
| def __init__(self, invalidity_date: datetime.datetime) -> None: | |
| if not isinstance(invalidity_date, datetime.datetime): | |
| raise TypeError("invalidity_date must be a datetime.datetime") | |
| self._invalidity_date = invalidity_date | |
| def __repr__(self) -> str: | |
| return f"<InvalidityDate(invalidity_date={self._invalidity_date})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, InvalidityDate): | |
| return NotImplemented | |
| return self.invalidity_date == other.invalidity_date | |
| def __hash__(self) -> int: | |
| return hash(self.invalidity_date) | |
| def invalidity_date(self) -> datetime.datetime: | |
| return self._invalidity_date | |
| def invalidity_date_utc(self) -> datetime.datetime: | |
| if self._invalidity_date.tzinfo is None: | |
| return self._invalidity_date.replace(tzinfo=datetime.timezone.utc) | |
| else: | |
| return self._invalidity_date.astimezone(tz=datetime.timezone.utc) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class PrecertificateSignedCertificateTimestamps(ExtensionType): | |
| oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS | |
| def __init__( | |
| self, | |
| signed_certificate_timestamps: Iterable[SignedCertificateTimestamp], | |
| ) -> None: | |
| signed_certificate_timestamps = list(signed_certificate_timestamps) | |
| if not all( | |
| isinstance(sct, SignedCertificateTimestamp) | |
| for sct in signed_certificate_timestamps | |
| ): | |
| raise TypeError( | |
| "Every item in the signed_certificate_timestamps list must be " | |
| "a SignedCertificateTimestamp" | |
| ) | |
| self._signed_certificate_timestamps = signed_certificate_timestamps | |
| __len__, __iter__, __getitem__ = _make_sequence_methods( | |
| "_signed_certificate_timestamps" | |
| ) | |
| def __repr__(self) -> str: | |
| return f"<PrecertificateSignedCertificateTimestamps({list(self)})>" | |
| def __hash__(self) -> int: | |
| return hash(tuple(self._signed_certificate_timestamps)) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, PrecertificateSignedCertificateTimestamps): | |
| return NotImplemented | |
| return ( | |
| self._signed_certificate_timestamps | |
| == other._signed_certificate_timestamps | |
| ) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class SignedCertificateTimestamps(ExtensionType): | |
| oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS | |
| def __init__( | |
| self, | |
| signed_certificate_timestamps: Iterable[SignedCertificateTimestamp], | |
| ) -> None: | |
| signed_certificate_timestamps = list(signed_certificate_timestamps) | |
| if not all( | |
| isinstance(sct, SignedCertificateTimestamp) | |
| for sct in signed_certificate_timestamps | |
| ): | |
| raise TypeError( | |
| "Every item in the signed_certificate_timestamps list must be " | |
| "a SignedCertificateTimestamp" | |
| ) | |
| self._signed_certificate_timestamps = signed_certificate_timestamps | |
| __len__, __iter__, __getitem__ = _make_sequence_methods( | |
| "_signed_certificate_timestamps" | |
| ) | |
| def __repr__(self) -> str: | |
| return f"<SignedCertificateTimestamps({list(self)})>" | |
| def __hash__(self) -> int: | |
| return hash(tuple(self._signed_certificate_timestamps)) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, SignedCertificateTimestamps): | |
| return NotImplemented | |
| return ( | |
| self._signed_certificate_timestamps | |
| == other._signed_certificate_timestamps | |
| ) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class OCSPNonce(ExtensionType): | |
| oid = OCSPExtensionOID.NONCE | |
| def __init__(self, nonce: bytes) -> None: | |
| if not isinstance(nonce, bytes): | |
| raise TypeError("nonce must be bytes") | |
| self._nonce = nonce | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, OCSPNonce): | |
| return NotImplemented | |
| return self.nonce == other.nonce | |
| def __hash__(self) -> int: | |
| return hash(self.nonce) | |
| def __repr__(self) -> str: | |
| return f"<OCSPNonce(nonce={self.nonce!r})>" | |
| def nonce(self) -> bytes: | |
| return self._nonce | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class OCSPAcceptableResponses(ExtensionType): | |
| oid = OCSPExtensionOID.ACCEPTABLE_RESPONSES | |
| def __init__(self, responses: Iterable[ObjectIdentifier]) -> None: | |
| responses = list(responses) | |
| if any(not isinstance(r, ObjectIdentifier) for r in responses): | |
| raise TypeError("All responses must be ObjectIdentifiers") | |
| self._responses = responses | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, OCSPAcceptableResponses): | |
| return NotImplemented | |
| return self._responses == other._responses | |
| def __hash__(self) -> int: | |
| return hash(tuple(self._responses)) | |
| def __repr__(self) -> str: | |
| return f"<OCSPAcceptableResponses(responses={self._responses})>" | |
| def __iter__(self) -> Iterator[ObjectIdentifier]: | |
| return iter(self._responses) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class IssuingDistributionPoint(ExtensionType): | |
| oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT | |
| def __init__( | |
| self, | |
| full_name: Iterable[GeneralName] | None, | |
| relative_name: RelativeDistinguishedName | None, | |
| only_contains_user_certs: bool, | |
| only_contains_ca_certs: bool, | |
| only_some_reasons: frozenset[ReasonFlags] | None, | |
| indirect_crl: bool, | |
| only_contains_attribute_certs: bool, | |
| ) -> None: | |
| if full_name is not None: | |
| full_name = list(full_name) | |
| if only_some_reasons and ( | |
| not isinstance(only_some_reasons, frozenset) | |
| or not all(isinstance(x, ReasonFlags) for x in only_some_reasons) | |
| ): | |
| raise TypeError( | |
| "only_some_reasons must be None or frozenset of ReasonFlags" | |
| ) | |
| if only_some_reasons and ( | |
| ReasonFlags.unspecified in only_some_reasons | |
| or ReasonFlags.remove_from_crl in only_some_reasons | |
| ): | |
| raise ValueError( | |
| "unspecified and remove_from_crl are not valid reasons in an " | |
| "IssuingDistributionPoint" | |
| ) | |
| if not ( | |
| isinstance(only_contains_user_certs, bool) | |
| and isinstance(only_contains_ca_certs, bool) | |
| and isinstance(indirect_crl, bool) | |
| and isinstance(only_contains_attribute_certs, bool) | |
| ): | |
| raise TypeError( | |
| "only_contains_user_certs, only_contains_ca_certs, " | |
| "indirect_crl and only_contains_attribute_certs " | |
| "must all be boolean." | |
| ) | |
| # Per RFC5280 Section 5.2.5, the Issuing Distribution Point extension | |
| # in a CRL can have only one of onlyContainsUserCerts, | |
| # onlyContainsCACerts, onlyContainsAttributeCerts set to TRUE. | |
| crl_constraints = [ | |
| only_contains_user_certs, | |
| only_contains_ca_certs, | |
| only_contains_attribute_certs, | |
| ] | |
| if len([x for x in crl_constraints if x]) > 1: | |
| raise ValueError( | |
| "Only one of the following can be set to True: " | |
| "only_contains_user_certs, only_contains_ca_certs, " | |
| "only_contains_attribute_certs" | |
| ) | |
| if not any( | |
| [ | |
| only_contains_user_certs, | |
| only_contains_ca_certs, | |
| indirect_crl, | |
| only_contains_attribute_certs, | |
| full_name, | |
| relative_name, | |
| only_some_reasons, | |
| ] | |
| ): | |
| raise ValueError( | |
| "Cannot create empty extension: " | |
| "if only_contains_user_certs, only_contains_ca_certs, " | |
| "indirect_crl, and only_contains_attribute_certs are all False" | |
| ", then either full_name, relative_name, or only_some_reasons " | |
| "must have a value." | |
| ) | |
| self._only_contains_user_certs = only_contains_user_certs | |
| self._only_contains_ca_certs = only_contains_ca_certs | |
| self._indirect_crl = indirect_crl | |
| self._only_contains_attribute_certs = only_contains_attribute_certs | |
| self._only_some_reasons = only_some_reasons | |
| self._full_name = full_name | |
| self._relative_name = relative_name | |
| def __repr__(self) -> str: | |
| return ( | |
| f"<IssuingDistributionPoint(full_name={self.full_name}, " | |
| f"relative_name={self.relative_name}, " | |
| f"only_contains_user_certs={self.only_contains_user_certs}, " | |
| f"only_contains_ca_certs={self.only_contains_ca_certs}, " | |
| f"only_some_reasons={self.only_some_reasons}, " | |
| f"indirect_crl={self.indirect_crl}, " | |
| "only_contains_attribute_certs=" | |
| f"{self.only_contains_attribute_certs})>" | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, IssuingDistributionPoint): | |
| return NotImplemented | |
| return ( | |
| self.full_name == other.full_name | |
| and self.relative_name == other.relative_name | |
| and self.only_contains_user_certs == other.only_contains_user_certs | |
| and self.only_contains_ca_certs == other.only_contains_ca_certs | |
| and self.only_some_reasons == other.only_some_reasons | |
| and self.indirect_crl == other.indirect_crl | |
| and self.only_contains_attribute_certs | |
| == other.only_contains_attribute_certs | |
| ) | |
| def __hash__(self) -> int: | |
| return hash( | |
| ( | |
| self.full_name, | |
| self.relative_name, | |
| self.only_contains_user_certs, | |
| self.only_contains_ca_certs, | |
| self.only_some_reasons, | |
| self.indirect_crl, | |
| self.only_contains_attribute_certs, | |
| ) | |
| ) | |
| def full_name(self) -> list[GeneralName] | None: | |
| return self._full_name | |
| def relative_name(self) -> RelativeDistinguishedName | None: | |
| return self._relative_name | |
| def only_contains_user_certs(self) -> bool: | |
| return self._only_contains_user_certs | |
| def only_contains_ca_certs(self) -> bool: | |
| return self._only_contains_ca_certs | |
| def only_some_reasons( | |
| self, | |
| ) -> frozenset[ReasonFlags] | None: | |
| return self._only_some_reasons | |
| def indirect_crl(self) -> bool: | |
| return self._indirect_crl | |
| def only_contains_attribute_certs(self) -> bool: | |
| return self._only_contains_attribute_certs | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class MSCertificateTemplate(ExtensionType): | |
| oid = ExtensionOID.MS_CERTIFICATE_TEMPLATE | |
| def __init__( | |
| self, | |
| template_id: ObjectIdentifier, | |
| major_version: int | None, | |
| minor_version: int | None, | |
| ) -> None: | |
| if not isinstance(template_id, ObjectIdentifier): | |
| raise TypeError("oid must be an ObjectIdentifier") | |
| self._template_id = template_id | |
| if ( | |
| major_version is not None and not isinstance(major_version, int) | |
| ) or ( | |
| minor_version is not None and not isinstance(minor_version, int) | |
| ): | |
| raise TypeError( | |
| "major_version and minor_version must be integers or None" | |
| ) | |
| self._major_version = major_version | |
| self._minor_version = minor_version | |
| def template_id(self) -> ObjectIdentifier: | |
| return self._template_id | |
| def major_version(self) -> int | None: | |
| return self._major_version | |
| def minor_version(self) -> int | None: | |
| return self._minor_version | |
| def __repr__(self) -> str: | |
| return ( | |
| f"<MSCertificateTemplate(template_id={self.template_id}, " | |
| f"major_version={self.major_version}, " | |
| f"minor_version={self.minor_version})>" | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, MSCertificateTemplate): | |
| return NotImplemented | |
| return ( | |
| self.template_id == other.template_id | |
| and self.major_version == other.major_version | |
| and self.minor_version == other.minor_version | |
| ) | |
| def __hash__(self) -> int: | |
| return hash((self.template_id, self.major_version, self.minor_version)) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class NamingAuthority: | |
| def __init__( | |
| self, | |
| id: ObjectIdentifier | None, | |
| url: str | None, | |
| text: str | None, | |
| ) -> None: | |
| if id is not None and not isinstance(id, ObjectIdentifier): | |
| raise TypeError("id must be an ObjectIdentifier") | |
| if url is not None and not isinstance(url, str): | |
| raise TypeError("url must be a str") | |
| if text is not None and not isinstance(text, str): | |
| raise TypeError("text must be a str") | |
| self._id = id | |
| self._url = url | |
| self._text = text | |
| def id(self) -> ObjectIdentifier | None: | |
| return self._id | |
| def url(self) -> str | None: | |
| return self._url | |
| def text(self) -> str | None: | |
| return self._text | |
| def __repr__(self) -> str: | |
| return ( | |
| f"<NamingAuthority(" | |
| f"id={self.id}, url={self.url}, text={self.text})>" | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, NamingAuthority): | |
| return NotImplemented | |
| return ( | |
| self.id == other.id | |
| and self.url == other.url | |
| and self.text == other.text | |
| ) | |
| def __hash__(self) -> int: | |
| return hash( | |
| ( | |
| self.id, | |
| self.url, | |
| self.text, | |
| ) | |
| ) | |
| class ProfessionInfo: | |
| def __init__( | |
| self, | |
| naming_authority: NamingAuthority | None, | |
| profession_items: Iterable[str], | |
| profession_oids: Iterable[ObjectIdentifier] | None, | |
| registration_number: str | None, | |
| add_profession_info: bytes | None, | |
| ) -> None: | |
| if naming_authority is not None and not isinstance( | |
| naming_authority, NamingAuthority | |
| ): | |
| raise TypeError("naming_authority must be a NamingAuthority") | |
| profession_items = list(profession_items) | |
| if not all(isinstance(item, str) for item in profession_items): | |
| raise TypeError( | |
| "Every item in the profession_items list must be a str" | |
| ) | |
| if profession_oids is not None: | |
| profession_oids = list(profession_oids) | |
| if not all( | |
| isinstance(oid, ObjectIdentifier) for oid in profession_oids | |
| ): | |
| raise TypeError( | |
| "Every item in the profession_oids list must be an " | |
| "ObjectIdentifier" | |
| ) | |
| if registration_number is not None and not isinstance( | |
| registration_number, str | |
| ): | |
| raise TypeError("registration_number must be a str") | |
| if add_profession_info is not None and not isinstance( | |
| add_profession_info, bytes | |
| ): | |
| raise TypeError("add_profession_info must be bytes") | |
| self._naming_authority = naming_authority | |
| self._profession_items = profession_items | |
| self._profession_oids = profession_oids | |
| self._registration_number = registration_number | |
| self._add_profession_info = add_profession_info | |
| def naming_authority(self) -> NamingAuthority | None: | |
| return self._naming_authority | |
| def profession_items(self) -> list[str]: | |
| return self._profession_items | |
| def profession_oids(self) -> list[ObjectIdentifier] | None: | |
| return self._profession_oids | |
| def registration_number(self) -> str | None: | |
| return self._registration_number | |
| def add_profession_info(self) -> bytes | None: | |
| return self._add_profession_info | |
| def __repr__(self) -> str: | |
| return ( | |
| f"<ProfessionInfo(naming_authority={self.naming_authority}, " | |
| f"profession_items={self.profession_items}, " | |
| f"profession_oids={self.profession_oids}, " | |
| f"registration_number={self.registration_number}, " | |
| f"add_profession_info={self.add_profession_info!r})>" | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, ProfessionInfo): | |
| return NotImplemented | |
| return ( | |
| self.naming_authority == other.naming_authority | |
| and self.profession_items == other.profession_items | |
| and self.profession_oids == other.profession_oids | |
| and self.registration_number == other.registration_number | |
| and self.add_profession_info == other.add_profession_info | |
| ) | |
| def __hash__(self) -> int: | |
| if self.profession_oids is not None: | |
| profession_oids = tuple(self.profession_oids) | |
| else: | |
| profession_oids = None | |
| return hash( | |
| ( | |
| self.naming_authority, | |
| tuple(self.profession_items), | |
| profession_oids, | |
| self.registration_number, | |
| self.add_profession_info, | |
| ) | |
| ) | |
| class Admission: | |
| def __init__( | |
| self, | |
| admission_authority: GeneralName | None, | |
| naming_authority: NamingAuthority | None, | |
| profession_infos: Iterable[ProfessionInfo], | |
| ) -> None: | |
| if admission_authority is not None and not isinstance( | |
| admission_authority, GeneralName | |
| ): | |
| raise TypeError("admission_authority must be a GeneralName") | |
| if naming_authority is not None and not isinstance( | |
| naming_authority, NamingAuthority | |
| ): | |
| raise TypeError("naming_authority must be a NamingAuthority") | |
| profession_infos = list(profession_infos) | |
| if not all( | |
| isinstance(info, ProfessionInfo) for info in profession_infos | |
| ): | |
| raise TypeError( | |
| "Every item in the profession_infos list must be a " | |
| "ProfessionInfo" | |
| ) | |
| self._admission_authority = admission_authority | |
| self._naming_authority = naming_authority | |
| self._profession_infos = profession_infos | |
| def admission_authority(self) -> GeneralName | None: | |
| return self._admission_authority | |
| def naming_authority(self) -> NamingAuthority | None: | |
| return self._naming_authority | |
| def profession_infos(self) -> list[ProfessionInfo]: | |
| return self._profession_infos | |
| def __repr__(self) -> str: | |
| return ( | |
| f"<Admission(admission_authority={self.admission_authority}, " | |
| f"naming_authority={self.naming_authority}, " | |
| f"profession_infos={self.profession_infos})>" | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, Admission): | |
| return NotImplemented | |
| return ( | |
| self.admission_authority == other.admission_authority | |
| and self.naming_authority == other.naming_authority | |
| and self.profession_infos == other.profession_infos | |
| ) | |
| def __hash__(self) -> int: | |
| return hash( | |
| ( | |
| self.admission_authority, | |
| self.naming_authority, | |
| tuple(self.profession_infos), | |
| ) | |
| ) | |
| class Admissions(ExtensionType): | |
| oid = ExtensionOID.ADMISSIONS | |
| def __init__( | |
| self, | |
| authority: GeneralName | None, | |
| admissions: Iterable[Admission], | |
| ) -> None: | |
| if authority is not None and not isinstance(authority, GeneralName): | |
| raise TypeError("authority must be a GeneralName") | |
| admissions = list(admissions) | |
| if not all( | |
| isinstance(admission, Admission) for admission in admissions | |
| ): | |
| raise TypeError( | |
| "Every item in the contents_of_admissions list must be an " | |
| "Admission" | |
| ) | |
| self._authority = authority | |
| self._admissions = admissions | |
| __len__, __iter__, __getitem__ = _make_sequence_methods("_admissions") | |
| def authority(self) -> GeneralName | None: | |
| return self._authority | |
| def __repr__(self) -> str: | |
| return ( | |
| f"<Admissions(authority={self._authority}, " | |
| f"admissions={self._admissions})>" | |
| ) | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, Admissions): | |
| return NotImplemented | |
| return ( | |
| self.authority == other.authority | |
| and self._admissions == other._admissions | |
| ) | |
| def __hash__(self) -> int: | |
| return hash((self.authority, tuple(self._admissions))) | |
| def public_bytes(self) -> bytes: | |
| return rust_x509.encode_extension_value(self) | |
| class UnrecognizedExtension(ExtensionType): | |
| def __init__(self, oid: ObjectIdentifier, value: bytes) -> None: | |
| if not isinstance(oid, ObjectIdentifier): | |
| raise TypeError("oid must be an ObjectIdentifier") | |
| self._oid = oid | |
| self._value = value | |
| def oid(self) -> ObjectIdentifier: # type: ignore[override] | |
| return self._oid | |
| def value(self) -> bytes: | |
| return self._value | |
| def __repr__(self) -> str: | |
| return f"<UnrecognizedExtension(oid={self.oid}, value={self.value!r})>" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, UnrecognizedExtension): | |
| return NotImplemented | |
| return self.oid == other.oid and self.value == other.value | |
| def __hash__(self) -> int: | |
| return hash((self.oid, self.value)) | |
| def public_bytes(self) -> bytes: | |
| return self.value | |