| |
| |
| |
|
|
| from __future__ import annotations |
|
|
| import abc |
| import ipaddress |
| import typing |
| from email.utils import parseaddr |
|
|
| from cryptography.x509.name import Name |
| from cryptography.x509.oid import ObjectIdentifier |
|
|
| _IPAddressTypes = typing.Union[ |
| ipaddress.IPv4Address, |
| ipaddress.IPv6Address, |
| ipaddress.IPv4Network, |
| ipaddress.IPv6Network, |
| ] |
|
|
|
|
| class UnsupportedGeneralNameType(Exception): |
| pass |
|
|
|
|
| class GeneralName(metaclass=abc.ABCMeta): |
| @property |
| @abc.abstractmethod |
| def value(self) -> typing.Any: |
| """ |
| Return the value of the object |
| """ |
|
|
|
|
| class RFC822Name(GeneralName): |
| def __init__(self, value: str) -> None: |
| if isinstance(value, str): |
| try: |
| value.encode("ascii") |
| except UnicodeEncodeError: |
| raise ValueError( |
| "RFC822Name values should be passed as an A-label string. " |
| "This means unicode characters should be encoded via " |
| "a library like idna." |
| ) |
| else: |
| raise TypeError("value must be string") |
|
|
| name, address = parseaddr(value) |
| if name or not address: |
| |
| |
| raise ValueError("Invalid rfc822name value") |
|
|
| self._value = value |
|
|
| @property |
| def value(self) -> str: |
| return self._value |
|
|
| @classmethod |
| def _init_without_validation(cls, value: str) -> RFC822Name: |
| instance = cls.__new__(cls) |
| instance._value = value |
| return instance |
|
|
| def __repr__(self) -> str: |
| return f"<RFC822Name(value={self.value!r})>" |
|
|
| def __eq__(self, other: object) -> bool: |
| if not isinstance(other, RFC822Name): |
| return NotImplemented |
|
|
| return self.value == other.value |
|
|
| def __hash__(self) -> int: |
| return hash(self.value) |
|
|
|
|
| class DNSName(GeneralName): |
| def __init__(self, value: str) -> None: |
| if isinstance(value, str): |
| try: |
| value.encode("ascii") |
| except UnicodeEncodeError: |
| raise ValueError( |
| "DNSName values should be passed as an A-label string. " |
| "This means unicode characters should be encoded via " |
| "a library like idna." |
| ) |
| else: |
| raise TypeError("value must be string") |
|
|
| self._value = value |
|
|
| @property |
| def value(self) -> str: |
| return self._value |
|
|
| @classmethod |
| def _init_without_validation(cls, value: str) -> DNSName: |
| instance = cls.__new__(cls) |
| instance._value = value |
| return instance |
|
|
| def __repr__(self) -> str: |
| return f"<DNSName(value={self.value!r})>" |
|
|
| def __eq__(self, other: object) -> bool: |
| if not isinstance(other, DNSName): |
| return NotImplemented |
|
|
| return self.value == other.value |
|
|
| def __hash__(self) -> int: |
| return hash(self.value) |
|
|
|
|
| class UniformResourceIdentifier(GeneralName): |
| def __init__(self, value: str) -> None: |
| if isinstance(value, str): |
| try: |
| value.encode("ascii") |
| except UnicodeEncodeError: |
| raise ValueError( |
| "URI values should be passed as an A-label string. " |
| "This means unicode characters should be encoded via " |
| "a library like idna." |
| ) |
| else: |
| raise TypeError("value must be string") |
|
|
| self._value = value |
|
|
| @property |
| def value(self) -> str: |
| return self._value |
|
|
| @classmethod |
| def _init_without_validation(cls, value: str) -> UniformResourceIdentifier: |
| instance = cls.__new__(cls) |
| instance._value = value |
| return instance |
|
|
| def __repr__(self) -> str: |
| return f"<UniformResourceIdentifier(value={self.value!r})>" |
|
|
| def __eq__(self, other: object) -> bool: |
| if not isinstance(other, UniformResourceIdentifier): |
| return NotImplemented |
|
|
| return self.value == other.value |
|
|
| def __hash__(self) -> int: |
| return hash(self.value) |
|
|
|
|
| class DirectoryName(GeneralName): |
| def __init__(self, value: Name) -> None: |
| if not isinstance(value, Name): |
| raise TypeError("value must be a Name") |
|
|
| self._value = value |
|
|
| @property |
| def value(self) -> Name: |
| return self._value |
|
|
| def __repr__(self) -> str: |
| return f"<DirectoryName(value={self.value})>" |
|
|
| def __eq__(self, other: object) -> bool: |
| if not isinstance(other, DirectoryName): |
| return NotImplemented |
|
|
| return self.value == other.value |
|
|
| def __hash__(self) -> int: |
| return hash(self.value) |
|
|
|
|
| class RegisteredID(GeneralName): |
| def __init__(self, value: ObjectIdentifier) -> None: |
| if not isinstance(value, ObjectIdentifier): |
| raise TypeError("value must be an ObjectIdentifier") |
|
|
| self._value = value |
|
|
| @property |
| def value(self) -> ObjectIdentifier: |
| return self._value |
|
|
| def __repr__(self) -> str: |
| return f"<RegisteredID(value={self.value})>" |
|
|
| def __eq__(self, other: object) -> bool: |
| if not isinstance(other, RegisteredID): |
| return NotImplemented |
|
|
| return self.value == other.value |
|
|
| def __hash__(self) -> int: |
| return hash(self.value) |
|
|
|
|
| class IPAddress(GeneralName): |
| def __init__(self, value: _IPAddressTypes) -> None: |
| if not isinstance( |
| value, |
| ( |
| ipaddress.IPv4Address, |
| ipaddress.IPv6Address, |
| ipaddress.IPv4Network, |
| ipaddress.IPv6Network, |
| ), |
| ): |
| raise TypeError( |
| "value must be an instance of ipaddress.IPv4Address, " |
| "ipaddress.IPv6Address, ipaddress.IPv4Network, or " |
| "ipaddress.IPv6Network" |
| ) |
|
|
| self._value = value |
|
|
| @property |
| def value(self) -> _IPAddressTypes: |
| return self._value |
|
|
| def _packed(self) -> bytes: |
| if isinstance( |
| self.value, (ipaddress.IPv4Address, ipaddress.IPv6Address) |
| ): |
| return self.value.packed |
| else: |
| return ( |
| self.value.network_address.packed + self.value.netmask.packed |
| ) |
|
|
| def __repr__(self) -> str: |
| return f"<IPAddress(value={self.value})>" |
|
|
| def __eq__(self, other: object) -> bool: |
| if not isinstance(other, IPAddress): |
| return NotImplemented |
|
|
| return self.value == other.value |
|
|
| def __hash__(self) -> int: |
| return hash(self.value) |
|
|
|
|
| class OtherName(GeneralName): |
| def __init__(self, type_id: ObjectIdentifier, value: bytes) -> None: |
| if not isinstance(type_id, ObjectIdentifier): |
| raise TypeError("type_id must be an ObjectIdentifier") |
| if not isinstance(value, bytes): |
| raise TypeError("value must be a binary string") |
|
|
| self._type_id = type_id |
| self._value = value |
|
|
| @property |
| def type_id(self) -> ObjectIdentifier: |
| return self._type_id |
|
|
| @property |
| def value(self) -> bytes: |
| return self._value |
|
|
| def __repr__(self) -> str: |
| return f"<OtherName(type_id={self.type_id}, value={self.value!r})>" |
|
|
| def __eq__(self, other: object) -> bool: |
| if not isinstance(other, OtherName): |
| return NotImplemented |
|
|
| return self.type_id == other.type_id and self.value == other.value |
|
|
| def __hash__(self) -> int: |
| return hash((self.type_id, self.value)) |
|
|