_kex.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. # -*- test-case-name: twisted.conch.test.test_transport -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. SSH key exchange handling.
  6. """
  7. from hashlib import sha1, sha256, sha384, sha512
  8. from zope.interface import Attribute, Interface, implementer
  9. from twisted.conch import error
  10. class _IKexAlgorithm(Interface):
  11. """
  12. An L{_IKexAlgorithm} describes a key exchange algorithm.
  13. """
  14. preference = Attribute(
  15. "An L{int} giving the preference of the algorithm when negotiating "
  16. "key exchange. Algorithms with lower precedence values are more "
  17. "preferred."
  18. )
  19. hashProcessor = Attribute(
  20. "A callable hash algorithm constructor (e.g. C{hashlib.sha256}) "
  21. "suitable for use with this key exchange algorithm."
  22. )
  23. class _IFixedGroupKexAlgorithm(_IKexAlgorithm):
  24. """
  25. An L{_IFixedGroupKexAlgorithm} describes a key exchange algorithm with a
  26. fixed prime / generator group.
  27. """
  28. prime = Attribute(
  29. "An L{int} giving the prime number used in Diffie-Hellman key "
  30. "exchange, or L{None} if not applicable."
  31. )
  32. generator = Attribute(
  33. "An L{int} giving the generator number used in Diffie-Hellman key "
  34. "exchange, or L{None} if not applicable. (This is not related to "
  35. "Python generator functions.)"
  36. )
  37. class _IEllipticCurveExchangeKexAlgorithm(_IKexAlgorithm):
  38. """
  39. An L{_IEllipticCurveExchangeKexAlgorithm} describes a key exchange algorithm
  40. that uses an elliptic curve exchange between the client and server.
  41. """
  42. class _IGroupExchangeKexAlgorithm(_IKexAlgorithm):
  43. """
  44. An L{_IGroupExchangeKexAlgorithm} describes a key exchange algorithm
  45. that uses group exchange between the client and server.
  46. A prime / generator group should be chosen at run time based on the
  47. requested size. See RFC 4419.
  48. """
  49. @implementer(_IEllipticCurveExchangeKexAlgorithm)
  50. class _Curve25519SHA256:
  51. """
  52. Elliptic Curve Key Exchange using Curve25519 and SHA256. Defined in
  53. U{https://datatracker.ietf.org/doc/draft-ietf-curdle-ssh-curves/}.
  54. """
  55. preference = 1
  56. hashProcessor = sha256
  57. @implementer(_IEllipticCurveExchangeKexAlgorithm)
  58. class _Curve25519SHA256LibSSH:
  59. """
  60. As L{_Curve25519SHA256}, but with a pre-standardized algorithm name.
  61. """
  62. preference = 2
  63. hashProcessor = sha256
  64. @implementer(_IEllipticCurveExchangeKexAlgorithm)
  65. class _ECDH256:
  66. """
  67. Elliptic Curve Key Exchange with SHA-256 as HASH. Defined in
  68. RFC 5656.
  69. Note that C{ecdh-sha2-nistp256} takes priority over nistp384 or nistp512.
  70. This is the same priority from OpenSSH.
  71. C{ecdh-sha2-nistp256} is considered preety good cryptography.
  72. If you need something better consider using C{curve25519-sha256}.
  73. """
  74. preference = 3
  75. hashProcessor = sha256
  76. @implementer(_IEllipticCurveExchangeKexAlgorithm)
  77. class _ECDH384:
  78. """
  79. Elliptic Curve Key Exchange with SHA-384 as HASH. Defined in
  80. RFC 5656.
  81. """
  82. preference = 4
  83. hashProcessor = sha384
  84. @implementer(_IEllipticCurveExchangeKexAlgorithm)
  85. class _ECDH512:
  86. """
  87. Elliptic Curve Key Exchange with SHA-512 as HASH. Defined in
  88. RFC 5656.
  89. """
  90. preference = 5
  91. hashProcessor = sha512
  92. @implementer(_IGroupExchangeKexAlgorithm)
  93. class _DHGroupExchangeSHA256:
  94. """
  95. Diffie-Hellman Group and Key Exchange with SHA-256 as HASH. Defined in
  96. RFC 4419, 4.2.
  97. """
  98. preference = 6
  99. hashProcessor = sha256
  100. @implementer(_IGroupExchangeKexAlgorithm)
  101. class _DHGroupExchangeSHA1:
  102. """
  103. Diffie-Hellman Group and Key Exchange with SHA-1 as HASH. Defined in
  104. RFC 4419, 4.1.
  105. """
  106. preference = 7
  107. hashProcessor = sha1
  108. @implementer(_IFixedGroupKexAlgorithm)
  109. class _DHGroup14SHA1:
  110. """
  111. Diffie-Hellman key exchange with SHA-1 as HASH and Oakley Group 14
  112. (2048-bit MODP Group). Defined in RFC 4253, 8.2.
  113. """
  114. preference = 8
  115. hashProcessor = sha1
  116. # Diffie-Hellman primes from Oakley Group 14 (RFC 3526, 3).
  117. prime = int(
  118. "323170060713110073003389139264238282488179412411402391128420"
  119. "097514007417066343542226196894173635693471179017379097041917"
  120. "546058732091950288537589861856221532121754125149017745202702"
  121. "357960782362488842461894775876411059286460994117232454266225"
  122. "221932305409190376805242355191256797158701170010580558776510"
  123. "388618472802579760549035697325615261670813393617995413364765"
  124. "591603683178967290731783845896806396719009772021941686472258"
  125. "710314113364293195361934716365332097170774482279885885653692"
  126. "086452966360772502689555059283627511211740969729980684105543"
  127. "595848665832916421362182310789909994486524682624169720359118"
  128. "52507045361090559"
  129. )
  130. generator = 2
  131. # Which ECDH hash function to use is dependent on the size.
  132. _kexAlgorithms = {
  133. b"curve25519-sha256": _Curve25519SHA256(),
  134. b"curve25519-sha256@libssh.org": _Curve25519SHA256LibSSH(),
  135. b"diffie-hellman-group-exchange-sha256": _DHGroupExchangeSHA256(),
  136. b"diffie-hellman-group-exchange-sha1": _DHGroupExchangeSHA1(),
  137. b"diffie-hellman-group14-sha1": _DHGroup14SHA1(),
  138. b"ecdh-sha2-nistp256": _ECDH256(),
  139. b"ecdh-sha2-nistp384": _ECDH384(),
  140. b"ecdh-sha2-nistp521": _ECDH512(),
  141. }
  142. def getKex(kexAlgorithm):
  143. """
  144. Get a description of a named key exchange algorithm.
  145. @param kexAlgorithm: The key exchange algorithm name.
  146. @type kexAlgorithm: L{bytes}
  147. @return: A description of the key exchange algorithm named by
  148. C{kexAlgorithm}.
  149. @rtype: L{_IKexAlgorithm}
  150. @raises ConchError: if the key exchange algorithm is not found.
  151. """
  152. if kexAlgorithm not in _kexAlgorithms:
  153. raise error.ConchError(f"Unsupported key exchange algorithm: {kexAlgorithm}")
  154. return _kexAlgorithms[kexAlgorithm]
  155. def isEllipticCurve(kexAlgorithm):
  156. """
  157. Returns C{True} if C{kexAlgorithm} is an elliptic curve.
  158. @param kexAlgorithm: The key exchange algorithm name.
  159. @type kexAlgorithm: C{str}
  160. @return: C{True} if C{kexAlgorithm} is an elliptic curve,
  161. otherwise C{False}.
  162. @rtype: C{bool}
  163. """
  164. return _IEllipticCurveExchangeKexAlgorithm.providedBy(getKex(kexAlgorithm))
  165. def isFixedGroup(kexAlgorithm):
  166. """
  167. Returns C{True} if C{kexAlgorithm} has a fixed prime / generator group.
  168. @param kexAlgorithm: The key exchange algorithm name.
  169. @type kexAlgorithm: L{bytes}
  170. @return: C{True} if C{kexAlgorithm} has a fixed prime / generator group,
  171. otherwise C{False}.
  172. @rtype: L{bool}
  173. """
  174. return _IFixedGroupKexAlgorithm.providedBy(getKex(kexAlgorithm))
  175. def getHashProcessor(kexAlgorithm):
  176. """
  177. Get the hash algorithm callable to use in key exchange.
  178. @param kexAlgorithm: The key exchange algorithm name.
  179. @type kexAlgorithm: L{bytes}
  180. @return: A callable hash algorithm constructor (e.g. C{hashlib.sha256}).
  181. @rtype: C{callable}
  182. """
  183. kex = getKex(kexAlgorithm)
  184. return kex.hashProcessor
  185. def getDHGeneratorAndPrime(kexAlgorithm):
  186. """
  187. Get the generator and the prime to use in key exchange.
  188. @param kexAlgorithm: The key exchange algorithm name.
  189. @type kexAlgorithm: L{bytes}
  190. @return: A L{tuple} containing L{int} generator and L{int} prime.
  191. @rtype: L{tuple}
  192. """
  193. kex = getKex(kexAlgorithm)
  194. return kex.generator, kex.prime
  195. def getSupportedKeyExchanges():
  196. """
  197. Get a list of supported key exchange algorithm names in order of
  198. preference.
  199. @return: A C{list} of supported key exchange algorithm names.
  200. @rtype: C{list} of L{bytes}
  201. """
  202. from cryptography.hazmat.backends import default_backend
  203. from cryptography.hazmat.primitives.asymmetric import ec
  204. from twisted.conch.ssh.keys import _curveTable
  205. backend = default_backend()
  206. kexAlgorithms = _kexAlgorithms.copy()
  207. for keyAlgorithm in list(kexAlgorithms):
  208. if keyAlgorithm.startswith(b"ecdh"):
  209. keyAlgorithmDsa = keyAlgorithm.replace(b"ecdh", b"ecdsa")
  210. supported = backend.elliptic_curve_exchange_algorithm_supported(
  211. ec.ECDH(), _curveTable[keyAlgorithmDsa]
  212. )
  213. elif keyAlgorithm.startswith(b"curve25519-sha256"):
  214. supported = backend.x25519_supported()
  215. else:
  216. supported = True
  217. if not supported:
  218. kexAlgorithms.pop(keyAlgorithm)
  219. return sorted(
  220. kexAlgorithms, key=lambda kexAlgorithm: kexAlgorithms[kexAlgorithm].preference
  221. )