general_name.py 8.0 KB

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