general_name.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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.
  4. import abc
  5. import ipaddress
  6. import typing
  7. from email.utils import parseaddr
  8. from cryptography.x509.name import Name
  9. from cryptography.x509.oid import ObjectIdentifier
  10. _IPADDRESS_TYPES = typing.Union[
  11. ipaddress.IPv4Address,
  12. ipaddress.IPv6Address,
  13. ipaddress.IPv4Network,
  14. ipaddress.IPv6Network,
  15. ]
  16. class UnsupportedGeneralNameType(Exception):
  17. pass
  18. class GeneralName(metaclass=abc.ABCMeta):
  19. @property
  20. @abc.abstractmethod
  21. def value(self) -> typing.Any:
  22. """
  23. Return the value of the object
  24. """
  25. class RFC822Name(GeneralName):
  26. def __init__(self, value: str) -> None:
  27. if isinstance(value, str):
  28. try:
  29. value.encode("ascii")
  30. except UnicodeEncodeError:
  31. raise ValueError(
  32. "RFC822Name values should be passed as an A-label string. "
  33. "This means unicode characters should be encoded via "
  34. "a library like idna."
  35. )
  36. else:
  37. raise TypeError("value must be string")
  38. name, address = parseaddr(value)
  39. if name or not address:
  40. # parseaddr has found a name (e.g. Name <email>) or the entire
  41. # value is an empty string.
  42. raise ValueError("Invalid rfc822name value")
  43. self._value = value
  44. @property
  45. def value(self) -> str:
  46. return self._value
  47. @classmethod
  48. def _init_without_validation(cls, value: str) -> "RFC822Name":
  49. instance = cls.__new__(cls)
  50. instance._value = value
  51. return instance
  52. def __repr__(self) -> str:
  53. return "<RFC822Name(value={0!r})>".format(self.value)
  54. def __eq__(self, other: object) -> bool:
  55. if not isinstance(other, RFC822Name):
  56. return NotImplemented
  57. return self.value == other.value
  58. def __hash__(self) -> int:
  59. return hash(self.value)
  60. class DNSName(GeneralName):
  61. def __init__(self, value: str) -> None:
  62. if isinstance(value, str):
  63. try:
  64. value.encode("ascii")
  65. except UnicodeEncodeError:
  66. raise ValueError(
  67. "DNSName values should be passed as an A-label string. "
  68. "This means unicode characters should be encoded via "
  69. "a library like idna."
  70. )
  71. else:
  72. raise TypeError("value must be string")
  73. self._value = value
  74. @property
  75. def value(self) -> str:
  76. return self._value
  77. @classmethod
  78. def _init_without_validation(cls, value: str) -> "DNSName":
  79. instance = cls.__new__(cls)
  80. instance._value = value
  81. return instance
  82. def __repr__(self) -> str:
  83. return "<DNSName(value={0!r})>".format(self.value)
  84. def __eq__(self, other: object) -> bool:
  85. if not isinstance(other, DNSName):
  86. return NotImplemented
  87. return self.value == other.value
  88. def __hash__(self) -> int:
  89. return hash(self.value)
  90. class UniformResourceIdentifier(GeneralName):
  91. def __init__(self, value: str) -> None:
  92. if isinstance(value, str):
  93. try:
  94. value.encode("ascii")
  95. except UnicodeEncodeError:
  96. raise ValueError(
  97. "URI values should be passed as an A-label string. "
  98. "This means unicode characters should be encoded via "
  99. "a library like idna."
  100. )
  101. else:
  102. raise TypeError("value must be string")
  103. self._value = value
  104. @property
  105. def value(self) -> str:
  106. return self._value
  107. @classmethod
  108. def _init_without_validation(
  109. cls, value: str
  110. ) -> "UniformResourceIdentifier":
  111. instance = cls.__new__(cls)
  112. instance._value = value
  113. return instance
  114. def __repr__(self) -> str:
  115. return "<UniformResourceIdentifier(value={0!r})>".format(self.value)
  116. def __eq__(self, other: object) -> bool:
  117. if not isinstance(other, UniformResourceIdentifier):
  118. return NotImplemented
  119. return self.value == other.value
  120. def __hash__(self) -> int:
  121. return hash(self.value)
  122. class DirectoryName(GeneralName):
  123. def __init__(self, value: Name) -> None:
  124. if not isinstance(value, Name):
  125. raise TypeError("value must be a Name")
  126. self._value = value
  127. @property
  128. def value(self) -> Name:
  129. return self._value
  130. def __repr__(self) -> str:
  131. return "<DirectoryName(value={})>".format(self.value)
  132. def __eq__(self, other: object) -> bool:
  133. if not isinstance(other, DirectoryName):
  134. return NotImplemented
  135. return self.value == other.value
  136. def __hash__(self) -> int:
  137. return hash(self.value)
  138. class RegisteredID(GeneralName):
  139. def __init__(self, value: ObjectIdentifier) -> None:
  140. if not isinstance(value, ObjectIdentifier):
  141. raise TypeError("value must be an ObjectIdentifier")
  142. self._value = value
  143. @property
  144. def value(self) -> ObjectIdentifier:
  145. return self._value
  146. def __repr__(self) -> str:
  147. return "<RegisteredID(value={})>".format(self.value)
  148. def __eq__(self, other: object) -> bool:
  149. if not isinstance(other, RegisteredID):
  150. return NotImplemented
  151. return self.value == other.value
  152. def __hash__(self) -> int:
  153. return hash(self.value)
  154. class IPAddress(GeneralName):
  155. def __init__(self, value: _IPADDRESS_TYPES) -> None:
  156. if not isinstance(
  157. value,
  158. (
  159. ipaddress.IPv4Address,
  160. ipaddress.IPv6Address,
  161. ipaddress.IPv4Network,
  162. ipaddress.IPv6Network,
  163. ),
  164. ):
  165. raise TypeError(
  166. "value must be an instance of ipaddress.IPv4Address, "
  167. "ipaddress.IPv6Address, ipaddress.IPv4Network, or "
  168. "ipaddress.IPv6Network"
  169. )
  170. self._value = value
  171. @property
  172. def value(self) -> _IPADDRESS_TYPES:
  173. return self._value
  174. def _packed(self) -> bytes:
  175. if isinstance(
  176. self.value, (ipaddress.IPv4Address, ipaddress.IPv6Address)
  177. ):
  178. return self.value.packed
  179. else:
  180. return (
  181. self.value.network_address.packed + self.value.netmask.packed
  182. )
  183. def __repr__(self) -> str:
  184. return "<IPAddress(value={})>".format(self.value)
  185. def __eq__(self, other: object) -> bool:
  186. if not isinstance(other, IPAddress):
  187. return NotImplemented
  188. return self.value == other.value
  189. def __hash__(self) -> int:
  190. return hash(self.value)
  191. class OtherName(GeneralName):
  192. def __init__(self, type_id: ObjectIdentifier, value: bytes) -> None:
  193. if not isinstance(type_id, ObjectIdentifier):
  194. raise TypeError("type_id must be an ObjectIdentifier")
  195. if not isinstance(value, bytes):
  196. raise TypeError("value must be a binary string")
  197. self._type_id = type_id
  198. self._value = value
  199. @property
  200. def type_id(self) -> ObjectIdentifier:
  201. return self._type_id
  202. @property
  203. def value(self) -> bytes:
  204. return self._value
  205. def __repr__(self) -> str:
  206. return "<OtherName(type_id={}, value={!r})>".format(
  207. self.type_id, self.value
  208. )
  209. def __eq__(self, other: object) -> bool:
  210. if not isinstance(other, OtherName):
  211. return NotImplemented
  212. return self.type_id == other.type_id and self.value == other.value
  213. def __hash__(self) -> int:
  214. return hash((self.type_id, self.value))