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