general_name.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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 __ne__(self, other: object) -> bool:
  58. return not self == other
  59. def __hash__(self) -> int:
  60. return hash(self.value)
  61. class DNSName(GeneralName):
  62. def __init__(self, value: str) -> None:
  63. if isinstance(value, str):
  64. try:
  65. value.encode("ascii")
  66. except UnicodeEncodeError:
  67. raise ValueError(
  68. "DNSName values should be passed as an A-label string. "
  69. "This means unicode characters should be encoded via "
  70. "a library like idna."
  71. )
  72. else:
  73. raise TypeError("value must be string")
  74. self._value = value
  75. @property
  76. def value(self) -> str:
  77. return self._value
  78. @classmethod
  79. def _init_without_validation(cls, value: str) -> "DNSName":
  80. instance = cls.__new__(cls)
  81. instance._value = value
  82. return instance
  83. def __repr__(self) -> str:
  84. return "<DNSName(value={0!r})>".format(self.value)
  85. def __eq__(self, other: object) -> bool:
  86. if not isinstance(other, DNSName):
  87. return NotImplemented
  88. return self.value == other.value
  89. def __ne__(self, other: object) -> bool:
  90. return not self == other
  91. def __hash__(self) -> int:
  92. return hash(self.value)
  93. class UniformResourceIdentifier(GeneralName):
  94. def __init__(self, value: str) -> None:
  95. if isinstance(value, str):
  96. try:
  97. value.encode("ascii")
  98. except UnicodeEncodeError:
  99. raise ValueError(
  100. "URI values should be passed as an A-label string. "
  101. "This means unicode characters should be encoded via "
  102. "a library like idna."
  103. )
  104. else:
  105. raise TypeError("value must be string")
  106. self._value = value
  107. @property
  108. def value(self) -> str:
  109. return self._value
  110. @classmethod
  111. def _init_without_validation(
  112. cls, value: str
  113. ) -> "UniformResourceIdentifier":
  114. instance = cls.__new__(cls)
  115. instance._value = value
  116. return instance
  117. def __repr__(self) -> str:
  118. return "<UniformResourceIdentifier(value={0!r})>".format(self.value)
  119. def __eq__(self, other: object) -> bool:
  120. if not isinstance(other, UniformResourceIdentifier):
  121. return NotImplemented
  122. return self.value == other.value
  123. def __ne__(self, other: object) -> bool:
  124. return not self == other
  125. def __hash__(self) -> int:
  126. return hash(self.value)
  127. class DirectoryName(GeneralName):
  128. def __init__(self, value: Name) -> None:
  129. if not isinstance(value, Name):
  130. raise TypeError("value must be a Name")
  131. self._value = value
  132. @property
  133. def value(self) -> Name:
  134. return self._value
  135. def __repr__(self) -> str:
  136. return "<DirectoryName(value={})>".format(self.value)
  137. def __eq__(self, other: object) -> bool:
  138. if not isinstance(other, DirectoryName):
  139. return NotImplemented
  140. return self.value == other.value
  141. def __ne__(self, other: object) -> bool:
  142. return not self == other
  143. def __hash__(self) -> int:
  144. return hash(self.value)
  145. class RegisteredID(GeneralName):
  146. def __init__(self, value: ObjectIdentifier) -> None:
  147. if not isinstance(value, ObjectIdentifier):
  148. raise TypeError("value must be an ObjectIdentifier")
  149. self._value = value
  150. @property
  151. def value(self) -> ObjectIdentifier:
  152. return self._value
  153. def __repr__(self) -> str:
  154. return "<RegisteredID(value={})>".format(self.value)
  155. def __eq__(self, other: object) -> bool:
  156. if not isinstance(other, RegisteredID):
  157. return NotImplemented
  158. return self.value == other.value
  159. def __ne__(self, other: object) -> bool:
  160. return not self == other
  161. def __hash__(self) -> int:
  162. return hash(self.value)
  163. class IPAddress(GeneralName):
  164. def __init__(self, value: _IPADDRESS_TYPES) -> None:
  165. if not isinstance(
  166. value,
  167. (
  168. ipaddress.IPv4Address,
  169. ipaddress.IPv6Address,
  170. ipaddress.IPv4Network,
  171. ipaddress.IPv6Network,
  172. ),
  173. ):
  174. raise TypeError(
  175. "value must be an instance of ipaddress.IPv4Address, "
  176. "ipaddress.IPv6Address, ipaddress.IPv4Network, or "
  177. "ipaddress.IPv6Network"
  178. )
  179. self._value = value
  180. @property
  181. def value(self) -> _IPADDRESS_TYPES:
  182. return self._value
  183. def _packed(self) -> bytes:
  184. if isinstance(
  185. self.value, (ipaddress.IPv4Address, ipaddress.IPv6Address)
  186. ):
  187. return self.value.packed
  188. else:
  189. return (
  190. self.value.network_address.packed + self.value.netmask.packed
  191. )
  192. def __repr__(self) -> str:
  193. return "<IPAddress(value={})>".format(self.value)
  194. def __eq__(self, other: object) -> bool:
  195. if not isinstance(other, IPAddress):
  196. return NotImplemented
  197. return self.value == other.value
  198. def __ne__(self, other: object) -> bool:
  199. return not self == other
  200. def __hash__(self) -> int:
  201. return hash(self.value)
  202. class OtherName(GeneralName):
  203. def __init__(self, type_id: ObjectIdentifier, value: bytes) -> None:
  204. if not isinstance(type_id, ObjectIdentifier):
  205. raise TypeError("type_id must be an ObjectIdentifier")
  206. if not isinstance(value, bytes):
  207. raise TypeError("value must be a binary string")
  208. self._type_id = type_id
  209. self._value = value
  210. @property
  211. def type_id(self) -> ObjectIdentifier:
  212. return self._type_id
  213. @property
  214. def value(self) -> bytes:
  215. return self._value
  216. def __repr__(self) -> str:
  217. return "<OtherName(type_id={}, value={!r})>".format(
  218. self.type_id, self.value
  219. )
  220. def __eq__(self, other: object) -> bool:
  221. if not isinstance(other, OtherName):
  222. return NotImplemented
  223. return self.type_id == other.type_id and self.value == other.value
  224. def __ne__(self, other: object) -> bool:
  225. return not self == other
  226. def __hash__(self) -> int:
  227. return hash((self.type_id, self.value))