_kex.py 8.2 KB

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