transport.py 80 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258
  1. # -*- test-case-name: twisted.conch.test.test_transport -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. The lowest level SSH protocol. This handles the key negotiation, the
  6. encryption and the compression. The transport layer is described in
  7. RFC 4253.
  8. Maintainer: Paul Swartz
  9. """
  10. from __future__ import annotations
  11. import binascii
  12. import hmac
  13. import struct
  14. import types
  15. import zlib
  16. from hashlib import md5, sha1, sha256, sha384, sha512
  17. from typing import Any, Callable, Dict, Tuple, Union
  18. from cryptography.exceptions import UnsupportedAlgorithm
  19. from cryptography.hazmat.backends import default_backend
  20. from cryptography.hazmat.primitives import serialization
  21. from cryptography.hazmat.primitives.asymmetric import dh, ec, x25519
  22. from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
  23. from typing_extensions import Literal
  24. from twisted import __version__ as twisted_version
  25. from twisted.conch.ssh import _kex, address, keys
  26. from twisted.conch.ssh.common import MP, NS, ffs, getMP, getNS
  27. from twisted.internet import defer, protocol
  28. from twisted.logger import Logger
  29. from twisted.python import randbytes
  30. from twisted.python.compat import iterbytes, networkString
  31. # This import is needed if SHA256 hashing is used.
  32. # from twisted.python.compat import nativeString
  33. def _mpFromBytes(data):
  34. """Make an SSH multiple-precision integer from big-endian L{bytes}.
  35. Used in ECDH key exchange.
  36. @type data: L{bytes}
  37. @param data: The input data, interpreted as a big-endian octet string.
  38. @rtype: L{bytes}
  39. @return: The given data encoded as an SSH multiple-precision integer.
  40. """
  41. return MP(int.from_bytes(data, "big"))
  42. # from https://github.com/python/typeshed/blob/703ed36d5a5c9505c903ea2182e6eed679d9bddb/stdlib/hmac.pyi#L9-L10
  43. _Hash = Any
  44. _DigestMod = Union[str, Callable[[], _Hash], types.ModuleType]
  45. class _MACParams(Tuple[_DigestMod, bytes, bytes, int]):
  46. """
  47. L{_MACParams} represents the parameters necessary to compute SSH MAC
  48. (Message Authenticate Codes).
  49. L{_MACParams} is a L{tuple} subclass to maintain compatibility with older
  50. versions of the code. The elements of a L{_MACParams} are::
  51. 0. The digest object used for the MAC
  52. 1. The inner pad ("ipad") string
  53. 2. The outer pad ("opad") string
  54. 3. The size of the digest produced by the digest object
  55. L{_MACParams} is also an object lesson in why tuples are a bad type for
  56. public APIs.
  57. @ivar key: The HMAC key which will be used.
  58. """
  59. key: bytes
  60. class SSHCiphers:
  61. """
  62. SSHCiphers represents all the encryption operations that need to occur
  63. to encrypt and authenticate the SSH connection.
  64. @cvar cipherMap: A dictionary mapping SSH encryption names to 3-tuples of
  65. (<cryptography.hazmat.primitives.interfaces.CipherAlgorithm>,
  66. <block size>, <cryptography.hazmat.primitives.interfaces.Mode>)
  67. @cvar macMap: A dictionary mapping SSH MAC names to hash modules.
  68. @ivar outCipType: the string type of the outgoing cipher.
  69. @ivar inCipType: the string type of the incoming cipher.
  70. @ivar outMACType: the string type of the incoming MAC.
  71. @ivar inMACType: the string type of the incoming MAC.
  72. @ivar encBlockSize: the block size of the outgoing cipher.
  73. @ivar decBlockSize: the block size of the incoming cipher.
  74. @ivar verifyDigestSize: the size of the incoming MAC.
  75. @ivar outMAC: a tuple of (<hash module>, <inner key>, <outer key>,
  76. <digest size>) representing the outgoing MAC.
  77. @ivar inMAc: see outMAC, but for the incoming MAC.
  78. """
  79. cipherMap = {
  80. b"3des-cbc": (algorithms.TripleDES, 24, modes.CBC),
  81. b"aes256-cbc": (algorithms.AES, 32, modes.CBC),
  82. b"aes192-cbc": (algorithms.AES, 24, modes.CBC),
  83. b"aes128-cbc": (algorithms.AES, 16, modes.CBC),
  84. b"aes128-ctr": (algorithms.AES, 16, modes.CTR),
  85. b"aes192-ctr": (algorithms.AES, 24, modes.CTR),
  86. b"aes256-ctr": (algorithms.AES, 32, modes.CTR),
  87. b"3des-ctr": (algorithms.TripleDES, 24, modes.CTR),
  88. b"none": (None, 0, modes.CBC),
  89. }
  90. macMap = {
  91. b"hmac-sha2-512": sha512,
  92. b"hmac-sha2-384": sha384,
  93. b"hmac-sha2-256": sha256,
  94. b"hmac-sha1": sha1,
  95. b"hmac-md5": md5,
  96. b"none": None,
  97. }
  98. def __init__(self, outCip, inCip, outMac, inMac):
  99. self.outCipType = outCip
  100. self.inCipType = inCip
  101. self.outMACType = outMac
  102. self.inMACType = inMac
  103. self.encBlockSize = 0
  104. self.decBlockSize = 0
  105. self.verifyDigestSize = 0
  106. self.outMAC = (None, b"", b"", 0)
  107. self.inMAC = (None, b"", b"", 0)
  108. def setKeys(self, outIV, outKey, inIV, inKey, outInteg, inInteg):
  109. """
  110. Set up the ciphers and hashes using the given keys,
  111. @param outIV: the outgoing initialization vector
  112. @param outKey: the outgoing encryption key
  113. @param inIV: the incoming initialization vector
  114. @param inKey: the incoming encryption key
  115. @param outInteg: the outgoing integrity key
  116. @param inInteg: the incoming integrity key.
  117. """
  118. o = self._getCipher(self.outCipType, outIV, outKey)
  119. self.encryptor = o.encryptor()
  120. self.encBlockSize = o.algorithm.block_size // 8
  121. o = self._getCipher(self.inCipType, inIV, inKey)
  122. self.decryptor = o.decryptor()
  123. self.decBlockSize = o.algorithm.block_size // 8
  124. self.outMAC = self._getMAC(self.outMACType, outInteg)
  125. self.inMAC = self._getMAC(self.inMACType, inInteg)
  126. if self.inMAC:
  127. self.verifyDigestSize = self.inMAC[3]
  128. def _getCipher(self, cip, iv, key):
  129. """
  130. Creates an initialized cipher object.
  131. @param cip: the name of the cipher, maps into cipherMap
  132. @param iv: the initialzation vector
  133. @param key: the encryption key
  134. @return: the cipher object.
  135. """
  136. algorithmClass, keySize, modeClass = self.cipherMap[cip]
  137. if algorithmClass is None:
  138. return _DummyCipher()
  139. return Cipher(
  140. algorithmClass(key[:keySize]),
  141. modeClass(iv[: algorithmClass.block_size // 8]),
  142. backend=default_backend(),
  143. )
  144. def _getMAC(
  145. self, mac: bytes, key: bytes
  146. ) -> tuple[None, Literal[b""], Literal[b""], Literal[0]] | _MACParams:
  147. """
  148. Gets a 4-tuple representing the message authentication code.
  149. (<hash module>, <inner hash value>, <outer hash value>,
  150. <digest size>)
  151. @type mac: L{bytes}
  152. @param mac: a key mapping into macMap
  153. @type key: L{bytes}
  154. @param key: the MAC key.
  155. @rtype: L{bytes}
  156. @return: The MAC components.
  157. """
  158. mod = self.macMap[mac]
  159. if not mod:
  160. return (None, b"", b"", 0)
  161. # With stdlib we can only get attributes fron an instantiated object.
  162. hashObject = mod()
  163. digestSize = hashObject.digest_size
  164. blockSize = hashObject.block_size
  165. # Truncation here appears to contravene RFC 2104, section 2. However,
  166. # implementing the hashing behavior prescribed by the RFC breaks
  167. # interoperability with OpenSSH (at least version 5.5p1).
  168. key = key[:digestSize] + (b"\x00" * (blockSize - digestSize))
  169. i = key.translate(hmac.trans_36)
  170. o = key.translate(hmac.trans_5C)
  171. result = _MACParams((mod, i, o, digestSize))
  172. result.key = key
  173. return result
  174. def encrypt(self, blocks):
  175. """
  176. Encrypt some data.
  177. @type blocks: L{bytes}
  178. @param blocks: The data to encrypt.
  179. @rtype: L{bytes}
  180. @return: The encrypted data.
  181. """
  182. return self.encryptor.update(blocks)
  183. def decrypt(self, blocks):
  184. """
  185. Decrypt some data.
  186. @type blocks: L{bytes}
  187. @param blocks: The data to decrypt.
  188. @rtype: L{bytes}
  189. @return: The decrypted data.
  190. """
  191. return self.decryptor.update(blocks)
  192. def makeMAC(self, seqid, data):
  193. """
  194. Create a message authentication code (MAC) for the given packet using
  195. the outgoing MAC values.
  196. @type seqid: L{int}
  197. @param seqid: The sequence ID of the outgoing packet.
  198. @type data: L{bytes}
  199. @param data: The data to create a MAC for.
  200. @rtype: L{str}
  201. @return: The serialized MAC.
  202. """
  203. if not self.outMAC[0]:
  204. return b""
  205. data = struct.pack(">L", seqid) + data
  206. return hmac.HMAC(self.outMAC.key, data, self.outMAC[0]).digest()
  207. def verify(self, seqid, data, mac):
  208. """
  209. Verify an incoming MAC using the incoming MAC values.
  210. @type seqid: L{int}
  211. @param seqid: The sequence ID of the incoming packet.
  212. @type data: L{bytes}
  213. @param data: The packet data to verify.
  214. @type mac: L{bytes}
  215. @param mac: The MAC sent with the packet.
  216. @rtype: L{bool}
  217. @return: C{True} if the MAC is valid.
  218. """
  219. if not self.inMAC[0]:
  220. return mac == b""
  221. data = struct.pack(">L", seqid) + data
  222. outer = hmac.HMAC(self.inMAC.key, data, self.inMAC[0]).digest()
  223. return hmac.compare_digest(mac, outer)
  224. def _getSupportedCiphers():
  225. """
  226. Build a list of ciphers that are supported by the backend in use.
  227. @return: a list of supported ciphers.
  228. @rtype: L{list} of L{str}
  229. """
  230. supportedCiphers = []
  231. cs = [
  232. b"aes256-ctr",
  233. b"aes256-cbc",
  234. b"aes192-ctr",
  235. b"aes192-cbc",
  236. b"aes128-ctr",
  237. b"aes128-cbc",
  238. b"3des-ctr",
  239. b"3des-cbc",
  240. ]
  241. for cipher in cs:
  242. algorithmClass, keySize, modeClass = SSHCiphers.cipherMap[cipher]
  243. try:
  244. Cipher(
  245. algorithmClass(b" " * keySize),
  246. modeClass(b" " * (algorithmClass.block_size // 8)),
  247. backend=default_backend(),
  248. ).encryptor()
  249. except UnsupportedAlgorithm:
  250. pass
  251. else:
  252. supportedCiphers.append(cipher)
  253. return supportedCiphers
  254. class SSHTransportBase(protocol.Protocol):
  255. """
  256. Protocol supporting basic SSH functionality: sending/receiving packets
  257. and message dispatch. To connect to or run a server, you must use
  258. SSHClientTransport or SSHServerTransport.
  259. @ivar protocolVersion: A string representing the version of the SSH
  260. protocol we support. Currently defaults to '2.0'.
  261. @ivar version: A string representing the version of the server or client.
  262. Currently defaults to 'Twisted'.
  263. @ivar comment: An optional string giving more information about the
  264. server or client.
  265. @ivar supportedCiphers: A list of strings representing the encryption
  266. algorithms supported, in order from most-preferred to least.
  267. @ivar supportedMACs: A list of strings representing the message
  268. authentication codes (hashes) supported, in order from most-preferred
  269. to least. Both this and supportedCiphers can include 'none' to use
  270. no encryption or authentication, but that must be done manually,
  271. @ivar supportedKeyExchanges: A list of strings representing the
  272. key exchanges supported, in order from most-preferred to least.
  273. @ivar supportedPublicKeys: A list of strings representing the
  274. public key algorithms supported, in order from most-preferred to
  275. least.
  276. @ivar supportedCompressions: A list of strings representing compression
  277. types supported, from most-preferred to least.
  278. @ivar supportedLanguages: A list of strings representing languages
  279. supported, from most-preferred to least.
  280. @ivar supportedVersions: A container of strings representing supported ssh
  281. protocol version numbers.
  282. @ivar isClient: A boolean indicating whether this is a client or server.
  283. @ivar gotVersion: A boolean indicating whether we have received the
  284. version string from the other side.
  285. @ivar buf: Data we've received but hasn't been parsed into a packet.
  286. @ivar outgoingPacketSequence: the sequence number of the next packet we
  287. will send.
  288. @ivar incomingPacketSequence: the sequence number of the next packet we
  289. are expecting from the other side.
  290. @ivar outgoingCompression: an object supporting the .compress(str) and
  291. .flush() methods, or None if there is no outgoing compression. Used to
  292. compress outgoing data.
  293. @ivar outgoingCompressionType: A string representing the outgoing
  294. compression type.
  295. @ivar incomingCompression: an object supporting the .decompress(str)
  296. method, or None if there is no incoming compression. Used to
  297. decompress incoming data.
  298. @ivar incomingCompressionType: A string representing the incoming
  299. compression type.
  300. @ivar ourVersionString: the version string that we sent to the other side.
  301. Used in the key exchange.
  302. @ivar otherVersionString: the version string sent by the other side. Used
  303. in the key exchange.
  304. @ivar ourKexInitPayload: the MSG_KEXINIT payload we sent. Used in the key
  305. exchange.
  306. @ivar otherKexInitPayload: the MSG_KEXINIT payload we received. Used in
  307. the key exchange
  308. @ivar sessionID: a string that is unique to this SSH session. Created as
  309. part of the key exchange, sessionID is used to generate the various
  310. encryption and authentication keys.
  311. @ivar service: an SSHService instance, or None. If it's set to an object,
  312. it's the currently running service.
  313. @ivar kexAlg: the agreed-upon key exchange algorithm.
  314. @ivar keyAlg: the agreed-upon public key type for the key exchange.
  315. @ivar currentEncryptions: an SSHCiphers instance. It represents the
  316. current encryption and authentication options for the transport.
  317. @ivar nextEncryptions: an SSHCiphers instance. Held here until the
  318. MSG_NEWKEYS messages are exchanged, when nextEncryptions is
  319. transitioned to currentEncryptions.
  320. @ivar first: the first bytes of the next packet. In order to avoid
  321. decrypting data twice, the first bytes are decrypted and stored until
  322. the whole packet is available.
  323. @ivar _keyExchangeState: The current protocol state with respect to key
  324. exchange. This is either C{_KEY_EXCHANGE_NONE} if no key exchange is
  325. in progress (and returns to this value after any key exchange
  326. completqes), C{_KEY_EXCHANGE_REQUESTED} if this side of the connection
  327. initiated a key exchange, and C{_KEY_EXCHANGE_PROGRESSING} if the other
  328. side of the connection initiated a key exchange. C{_KEY_EXCHANGE_NONE}
  329. is the initial value (however SSH connections begin with key exchange,
  330. so it will quickly change to another state).
  331. @ivar _blockedByKeyExchange: Whenever C{_keyExchangeState} is not
  332. C{_KEY_EXCHANGE_NONE}, this is a C{list} of pending messages which were
  333. passed to L{sendPacket} but could not be sent because it is not legal
  334. to send them while a key exchange is in progress. When the key
  335. exchange completes, another attempt is made to send these messages.
  336. @ivar _peerSupportsExtensions: a boolean indicating whether the other side
  337. of the connection supports RFC 8308 extension negotiation.
  338. @ivar peerExtensions: a dict of extensions supported by the other side of
  339. the connection.
  340. """
  341. _log = Logger()
  342. protocolVersion = b"2.0"
  343. version = b"Twisted_" + twisted_version.encode("ascii")
  344. comment = b""
  345. ourVersionString = (
  346. b"SSH-" + protocolVersion + b"-" + version + b" " + comment
  347. ).strip()
  348. # L{None} is supported as cipher and hmac. For security they are disabled
  349. # by default. To enable them, subclass this class and add it, or do:
  350. # SSHTransportBase.supportedCiphers.append('none')
  351. # List ordered by preference.
  352. supportedCiphers = _getSupportedCiphers()
  353. supportedMACs = [
  354. b"hmac-sha2-512",
  355. b"hmac-sha2-384",
  356. b"hmac-sha2-256",
  357. b"hmac-sha1",
  358. b"hmac-md5",
  359. # `none`,
  360. ]
  361. supportedKeyExchanges = _kex.getSupportedKeyExchanges()
  362. supportedPublicKeys = []
  363. # Add the supported EC keys, and change the name from ecdh* to ecdsa*
  364. for eckey in supportedKeyExchanges:
  365. if eckey.find(b"ecdh") != -1:
  366. supportedPublicKeys += [eckey.replace(b"ecdh", b"ecdsa")]
  367. supportedPublicKeys += [b"rsa-sha2-512", b"rsa-sha2-256", b"ssh-rsa", b"ssh-dss"]
  368. if default_backend().ed25519_supported():
  369. supportedPublicKeys.append(b"ssh-ed25519")
  370. supportedCompressions = [b"none", b"zlib"]
  371. supportedLanguages = ()
  372. supportedVersions = (b"1.99", b"2.0")
  373. isClient = False
  374. gotVersion = False
  375. buf = b""
  376. outgoingPacketSequence = 0
  377. incomingPacketSequence = 0
  378. outgoingCompression = None
  379. incomingCompression = None
  380. sessionID = None
  381. service = None
  382. # There is no key exchange activity in progress.
  383. _KEY_EXCHANGE_NONE = "_KEY_EXCHANGE_NONE"
  384. # Key exchange is in progress and we started it.
  385. _KEY_EXCHANGE_REQUESTED = "_KEY_EXCHANGE_REQUESTED"
  386. # Key exchange is in progress and both sides have sent KEXINIT messages.
  387. _KEY_EXCHANGE_PROGRESSING = "_KEY_EXCHANGE_PROGRESSING"
  388. # There is a fourth conceptual state not represented here: KEXINIT received
  389. # but not sent. Since we always send a KEXINIT as soon as we get it, we
  390. # can't ever be in that state.
  391. # The current key exchange state.
  392. _keyExchangeState = _KEY_EXCHANGE_NONE
  393. _blockedByKeyExchange = None
  394. # Added to key exchange algorithms by a client to indicate support for
  395. # extension negotiation.
  396. _EXT_INFO_C = b"ext-info-c"
  397. # Added to key exchange algorithms by a server to indicate support for
  398. # extension negotiation.
  399. _EXT_INFO_S = b"ext-info-s"
  400. _peerSupportsExtensions = False
  401. peerExtensions: Dict[bytes, bytes] = {}
  402. def connectionLost(self, reason):
  403. """
  404. When the underlying connection is closed, stop the running service (if
  405. any), and log out the avatar (if any).
  406. @type reason: L{twisted.python.failure.Failure}
  407. @param reason: The cause of the connection being closed.
  408. """
  409. if self.service:
  410. self.service.serviceStopped()
  411. if hasattr(self, "avatar"):
  412. self.logoutFunction()
  413. self._log.info("connection lost")
  414. def connectionMade(self):
  415. """
  416. Called when the connection is made to the other side. We sent our
  417. version and the MSG_KEXINIT packet.
  418. """
  419. self.transport.write(self.ourVersionString + b"\r\n")
  420. self.currentEncryptions = SSHCiphers(b"none", b"none", b"none", b"none")
  421. self.currentEncryptions.setKeys(b"", b"", b"", b"", b"", b"")
  422. self.sendKexInit()
  423. def sendKexInit(self):
  424. """
  425. Send a I{KEXINIT} message to initiate key exchange or to respond to a
  426. key exchange initiated by the peer.
  427. @raise RuntimeError: If a key exchange has already been started and it
  428. is not appropriate to send a I{KEXINIT} message at this time.
  429. @return: L{None}
  430. """
  431. if self._keyExchangeState != self._KEY_EXCHANGE_NONE:
  432. raise RuntimeError(
  433. "Cannot send KEXINIT while key exchange state is %r"
  434. % (self._keyExchangeState,)
  435. )
  436. supportedKeyExchanges = list(self.supportedKeyExchanges)
  437. # Advertise extension negotiation (RFC 8308, section 2.1). At
  438. # present, the Conch client processes the "server-sig-algs"
  439. # extension (section 3.1), and the Conch server sends that but
  440. # ignores any extensions sent by the client, so strictly speaking at
  441. # the moment we only need to send this in the client case; however,
  442. # there's nothing to forbid the server from sending it as well, and
  443. # doing so makes things easier if it needs to process extensions
  444. # sent by clients in future.
  445. supportedKeyExchanges.append(
  446. self._EXT_INFO_C if self.isClient else self._EXT_INFO_S
  447. )
  448. self.ourKexInitPayload = b"".join(
  449. [
  450. bytes((MSG_KEXINIT,)),
  451. randbytes.secureRandom(16),
  452. NS(b",".join(supportedKeyExchanges)),
  453. NS(b",".join(self.supportedPublicKeys)),
  454. NS(b",".join(self.supportedCiphers)),
  455. NS(b",".join(self.supportedCiphers)),
  456. NS(b",".join(self.supportedMACs)),
  457. NS(b",".join(self.supportedMACs)),
  458. NS(b",".join(self.supportedCompressions)),
  459. NS(b",".join(self.supportedCompressions)),
  460. NS(b",".join(self.supportedLanguages)),
  461. NS(b",".join(self.supportedLanguages)),
  462. b"\000\000\000\000\000",
  463. ]
  464. )
  465. self.sendPacket(MSG_KEXINIT, self.ourKexInitPayload[1:])
  466. self._keyExchangeState = self._KEY_EXCHANGE_REQUESTED
  467. self._blockedByKeyExchange = []
  468. def _allowedKeyExchangeMessageType(self, messageType):
  469. """
  470. Determine if the given message type may be sent while key exchange is
  471. in progress.
  472. @param messageType: The type of message
  473. @type messageType: L{int}
  474. @return: C{True} if the given type of message may be sent while key
  475. exchange is in progress, C{False} if it may not.
  476. @rtype: L{bool}
  477. @see: U{http://tools.ietf.org/html/rfc4253#section-7.1}
  478. """
  479. # Written somewhat peculularly to reflect the way the specification
  480. # defines the allowed message types.
  481. if 1 <= messageType <= 19:
  482. return messageType not in (
  483. MSG_SERVICE_REQUEST,
  484. MSG_SERVICE_ACCEPT,
  485. MSG_EXT_INFO,
  486. )
  487. if 20 <= messageType <= 29:
  488. return messageType not in (MSG_KEXINIT,)
  489. return 30 <= messageType <= 49
  490. def sendPacket(self, messageType, payload):
  491. """
  492. Sends a packet. If it's been set up, compress the data, encrypt it,
  493. and authenticate it before sending. If key exchange is in progress and
  494. the message is not part of key exchange, queue it to be sent later.
  495. @param messageType: The type of the packet; generally one of the
  496. MSG_* values.
  497. @type messageType: L{int}
  498. @param payload: The payload for the message.
  499. @type payload: L{str}
  500. """
  501. if self._keyExchangeState != self._KEY_EXCHANGE_NONE:
  502. if not self._allowedKeyExchangeMessageType(messageType):
  503. self._blockedByKeyExchange.append((messageType, payload))
  504. return
  505. payload = bytes((messageType,)) + payload
  506. if self.outgoingCompression:
  507. payload = self.outgoingCompression.compress(
  508. payload
  509. ) + self.outgoingCompression.flush(2)
  510. bs = self.currentEncryptions.encBlockSize
  511. # 4 for the packet length and 1 for the padding length
  512. totalSize = 5 + len(payload)
  513. lenPad = bs - (totalSize % bs)
  514. if lenPad < 4:
  515. lenPad = lenPad + bs
  516. packet = (
  517. struct.pack("!LB", totalSize + lenPad - 4, lenPad)
  518. + payload
  519. + randbytes.secureRandom(lenPad)
  520. )
  521. encPacket = self.currentEncryptions.encrypt(
  522. packet
  523. ) + self.currentEncryptions.makeMAC(self.outgoingPacketSequence, packet)
  524. self.transport.write(encPacket)
  525. self.outgoingPacketSequence += 1
  526. def getPacket(self):
  527. """
  528. Try to return a decrypted, authenticated, and decompressed packet
  529. out of the buffer. If there is not enough data, return None.
  530. @rtype: L{str} or L{None}
  531. @return: The decoded packet, if any.
  532. """
  533. bs = self.currentEncryptions.decBlockSize
  534. ms = self.currentEncryptions.verifyDigestSize
  535. if len(self.buf) < bs:
  536. # Not enough data for a block
  537. return
  538. if not hasattr(self, "first"):
  539. first = self.currentEncryptions.decrypt(self.buf[:bs])
  540. else:
  541. first = self.first
  542. del self.first
  543. packetLen, paddingLen = struct.unpack("!LB", first[:5])
  544. if packetLen > 1048576: # 1024 ** 2
  545. self.sendDisconnect(
  546. DISCONNECT_PROTOCOL_ERROR,
  547. networkString(f"bad packet length {packetLen}"),
  548. )
  549. return
  550. if len(self.buf) < packetLen + 4 + ms:
  551. # Not enough data for a packet
  552. self.first = first
  553. return
  554. if (packetLen + 4) % bs != 0:
  555. self.sendDisconnect(
  556. DISCONNECT_PROTOCOL_ERROR,
  557. networkString(
  558. "bad packet mod (%i%%%i == %i)"
  559. % (packetLen + 4, bs, (packetLen + 4) % bs)
  560. ),
  561. )
  562. return
  563. encData, self.buf = self.buf[: 4 + packetLen], self.buf[4 + packetLen :]
  564. packet = first + self.currentEncryptions.decrypt(encData[bs:])
  565. if len(packet) != 4 + packetLen:
  566. self.sendDisconnect(DISCONNECT_PROTOCOL_ERROR, b"bad decryption")
  567. return
  568. if ms:
  569. macData, self.buf = self.buf[:ms], self.buf[ms:]
  570. if not self.currentEncryptions.verify(
  571. self.incomingPacketSequence, packet, macData
  572. ):
  573. self.sendDisconnect(DISCONNECT_MAC_ERROR, b"bad MAC")
  574. return
  575. payload = packet[5:-paddingLen]
  576. if self.incomingCompression:
  577. try:
  578. payload = self.incomingCompression.decompress(payload)
  579. except Exception:
  580. # Tolerate any errors in decompression
  581. self._log.failure("Error decompressing payload")
  582. self.sendDisconnect(DISCONNECT_COMPRESSION_ERROR, b"compression error")
  583. return
  584. self.incomingPacketSequence += 1
  585. return payload
  586. def _unsupportedVersionReceived(self, remoteVersion):
  587. """
  588. Called when an unsupported version of the ssh protocol is received from
  589. the remote endpoint.
  590. @param remoteVersion: remote ssh protocol version which is unsupported
  591. by us.
  592. @type remoteVersion: L{str}
  593. """
  594. self.sendDisconnect(
  595. DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED, b"bad version " + remoteVersion
  596. )
  597. def dataReceived(self, data):
  598. """
  599. First, check for the version string (SSH-2.0-*). After that has been
  600. received, this method adds data to the buffer, and pulls out any
  601. packets.
  602. @type data: L{bytes}
  603. @param data: The data that was received.
  604. """
  605. self.buf = self.buf + data
  606. if not self.gotVersion:
  607. if len(self.buf) > 4096:
  608. self.sendDisconnect(
  609. DISCONNECT_CONNECTION_LOST,
  610. b"Peer version string longer than 4KB. "
  611. b"Preventing a denial of service attack.",
  612. )
  613. return
  614. if self.buf.find(b"\n", self.buf.find(b"SSH-")) == -1:
  615. return
  616. # RFC 4253 section 4.2 ask for strict `\r\n` line ending.
  617. # Here we are a bit more relaxed and accept implementations ending
  618. # only in '\n'.
  619. # https://tools.ietf.org/html/rfc4253#section-4.2
  620. lines = self.buf.split(b"\n")
  621. for p in lines:
  622. if p.startswith(b"SSH-"):
  623. self.gotVersion = True
  624. # Since the line was split on '\n' and most of the time
  625. # it uses '\r\n' we may get an extra '\r'.
  626. self.otherVersionString = p.rstrip(b"\r")
  627. remoteVersion = p.split(b"-")[1]
  628. if remoteVersion not in self.supportedVersions:
  629. self._unsupportedVersionReceived(remoteVersion)
  630. return
  631. i = lines.index(p)
  632. self.buf = b"\n".join(lines[i + 1 :])
  633. packet = self.getPacket()
  634. while packet:
  635. messageNum = ord(packet[0:1])
  636. self.dispatchMessage(messageNum, packet[1:])
  637. packet = self.getPacket()
  638. def dispatchMessage(self, messageNum, payload):
  639. """
  640. Send a received message to the appropriate method.
  641. @type messageNum: L{int}
  642. @param messageNum: The message number.
  643. @type payload: L{bytes}
  644. @param payload: The message payload.
  645. """
  646. if messageNum < 50 and messageNum in messages:
  647. messageType = messages[messageNum][4:]
  648. f = getattr(self, f"ssh_{messageType}", None)
  649. if f is not None:
  650. f(payload)
  651. else:
  652. self._log.debug(
  653. "couldn't handle {messageType}: {payload!r}",
  654. messageType=messageType,
  655. payload=payload,
  656. )
  657. self.sendUnimplemented()
  658. elif self.service:
  659. self.service.packetReceived(messageNum, payload)
  660. else:
  661. self._log.debug(
  662. "couldn't handle {messageNum}: {payload!r}",
  663. messageNum=messageNum,
  664. payload=payload,
  665. )
  666. self.sendUnimplemented()
  667. def getPeer(self):
  668. """
  669. Returns an L{SSHTransportAddress} corresponding to the other (peer)
  670. side of this transport.
  671. @return: L{SSHTransportAddress} for the peer
  672. @rtype: L{SSHTransportAddress}
  673. @since: 12.1
  674. """
  675. return address.SSHTransportAddress(self.transport.getPeer())
  676. def getHost(self):
  677. """
  678. Returns an L{SSHTransportAddress} corresponding to the this side of
  679. transport.
  680. @return: L{SSHTransportAddress} for the peer
  681. @rtype: L{SSHTransportAddress}
  682. @since: 12.1
  683. """
  684. return address.SSHTransportAddress(self.transport.getHost())
  685. @property
  686. def kexAlg(self):
  687. """
  688. The key exchange algorithm name agreed between client and server.
  689. """
  690. return self._kexAlg
  691. @kexAlg.setter
  692. def kexAlg(self, value):
  693. """
  694. Set the key exchange algorithm name.
  695. """
  696. self._kexAlg = value
  697. # Client-initiated rekeying looks like this:
  698. #
  699. # C> MSG_KEXINIT
  700. # S> MSG_KEXINIT
  701. # C> MSG_KEX_DH_GEX_REQUEST or MSG_KEXDH_INIT
  702. # S> MSG_KEX_DH_GEX_GROUP or MSG_KEXDH_REPLY
  703. # C> MSG_KEX_DH_GEX_INIT or --
  704. # S> MSG_KEX_DH_GEX_REPLY or --
  705. # C> MSG_NEWKEYS
  706. # S> MSG_NEWKEYS
  707. #
  708. # Server-initiated rekeying is the same, only the first two messages are
  709. # switched.
  710. def ssh_KEXINIT(self, packet):
  711. """
  712. Called when we receive a MSG_KEXINIT message. Payload::
  713. bytes[16] cookie
  714. string keyExchangeAlgorithms
  715. string keyAlgorithms
  716. string incomingEncryptions
  717. string outgoingEncryptions
  718. string incomingAuthentications
  719. string outgoingAuthentications
  720. string incomingCompressions
  721. string outgoingCompressions
  722. string incomingLanguages
  723. string outgoingLanguages
  724. bool firstPacketFollows
  725. unit32 0 (reserved)
  726. Starts setting up the key exchange, keys, encryptions, and
  727. authentications. Extended by ssh_KEXINIT in SSHServerTransport and
  728. SSHClientTransport.
  729. @type packet: L{bytes}
  730. @param packet: The message data.
  731. @return: A L{tuple} of negotiated key exchange algorithms, key
  732. algorithms, and unhandled data, or L{None} if something went wrong.
  733. """
  734. self.otherKexInitPayload = bytes((MSG_KEXINIT,)) + packet
  735. # This is useless to us:
  736. # cookie = packet[: 16]
  737. k = getNS(packet[16:], 10)
  738. strings, rest = k[:-1], k[-1]
  739. (
  740. kexAlgs,
  741. keyAlgs,
  742. encCS,
  743. encSC,
  744. macCS,
  745. macSC,
  746. compCS,
  747. compSC,
  748. langCS,
  749. langSC,
  750. ) = (s.split(b",") for s in strings)
  751. # These are the server directions
  752. outs = [encSC, macSC, compSC]
  753. ins = [encCS, macCS, compCS]
  754. if self.isClient:
  755. outs, ins = ins, outs # Switch directions
  756. server = (
  757. self.supportedKeyExchanges,
  758. self.supportedPublicKeys,
  759. self.supportedCiphers,
  760. self.supportedCiphers,
  761. self.supportedMACs,
  762. self.supportedMACs,
  763. self.supportedCompressions,
  764. self.supportedCompressions,
  765. )
  766. client = (kexAlgs, keyAlgs, outs[0], ins[0], outs[1], ins[1], outs[2], ins[2])
  767. if self.isClient:
  768. server, client = client, server
  769. self.kexAlg = ffs(client[0], server[0])
  770. self.keyAlg = ffs(client[1], server[1])
  771. self.nextEncryptions = SSHCiphers(
  772. ffs(client[2], server[2]),
  773. ffs(client[3], server[3]),
  774. ffs(client[4], server[4]),
  775. ffs(client[5], server[5]),
  776. )
  777. self.outgoingCompressionType = ffs(client[6], server[6])
  778. self.incomingCompressionType = ffs(client[7], server[7])
  779. if (
  780. None
  781. in (
  782. self.kexAlg,
  783. self.keyAlg,
  784. self.outgoingCompressionType,
  785. self.incomingCompressionType,
  786. )
  787. # We MUST disconnect if an extension negotiation indication ends
  788. # up being negotiated as a key exchange method (RFC 8308,
  789. # section 2.2).
  790. or self.kexAlg in (self._EXT_INFO_C, self._EXT_INFO_S)
  791. ):
  792. self.sendDisconnect(
  793. DISCONNECT_KEY_EXCHANGE_FAILED, b"couldn't match all kex parts"
  794. )
  795. return
  796. if None in self.nextEncryptions.__dict__.values():
  797. self.sendDisconnect(
  798. DISCONNECT_KEY_EXCHANGE_FAILED, b"couldn't match all kex parts"
  799. )
  800. return
  801. self._peerSupportsExtensions = (
  802. self._EXT_INFO_S if self.isClient else self._EXT_INFO_C
  803. ) in kexAlgs
  804. self._log.debug(
  805. "kex alg={kexAlg!r} key alg={keyAlg!r}",
  806. kexAlg=self.kexAlg,
  807. keyAlg=self.keyAlg,
  808. )
  809. self._log.debug(
  810. "outgoing: {cip!r} {mac!r} {compression!r}",
  811. cip=self.nextEncryptions.outCipType,
  812. mac=self.nextEncryptions.outMACType,
  813. compression=self.outgoingCompressionType,
  814. )
  815. self._log.debug(
  816. "incoming: {cip!r} {mac!r} {compression!r}",
  817. cip=self.nextEncryptions.inCipType,
  818. mac=self.nextEncryptions.inMACType,
  819. compression=self.incomingCompressionType,
  820. )
  821. if self._keyExchangeState == self._KEY_EXCHANGE_REQUESTED:
  822. self._keyExchangeState = self._KEY_EXCHANGE_PROGRESSING
  823. else:
  824. self.sendKexInit()
  825. return kexAlgs, keyAlgs, rest # For SSHServerTransport to use
  826. def ssh_DISCONNECT(self, packet):
  827. """
  828. Called when we receive a MSG_DISCONNECT message. Payload::
  829. long code
  830. string description
  831. This means that the other side has disconnected. Pass the message up
  832. and disconnect ourselves.
  833. @type packet: L{bytes}
  834. @param packet: The message data.
  835. """
  836. reasonCode = struct.unpack(">L", packet[:4])[0]
  837. description, foo = getNS(packet[4:])
  838. self.receiveError(reasonCode, description)
  839. self.transport.loseConnection()
  840. def ssh_IGNORE(self, packet):
  841. """
  842. Called when we receive a MSG_IGNORE message. No payload.
  843. This means nothing; we simply return.
  844. @type packet: L{bytes}
  845. @param packet: The message data.
  846. """
  847. def ssh_UNIMPLEMENTED(self, packet):
  848. """
  849. Called when we receive a MSG_UNIMPLEMENTED message. Payload::
  850. long packet
  851. This means that the other side did not implement one of our packets.
  852. @type packet: L{bytes}
  853. @param packet: The message data.
  854. """
  855. (seqnum,) = struct.unpack(">L", packet)
  856. self.receiveUnimplemented(seqnum)
  857. def ssh_DEBUG(self, packet):
  858. """
  859. Called when we receive a MSG_DEBUG message. Payload::
  860. bool alwaysDisplay
  861. string message
  862. string language
  863. This means the other side has passed along some debugging info.
  864. @type packet: L{bytes}
  865. @param packet: The message data.
  866. """
  867. alwaysDisplay = bool(ord(packet[0:1]))
  868. message, lang, foo = getNS(packet[1:], 2)
  869. self.receiveDebug(alwaysDisplay, message, lang)
  870. def ssh_EXT_INFO(self, packet):
  871. """
  872. Called when we get a MSG_EXT_INFO message. Payload::
  873. uint32 nr-extensions
  874. repeat the following 2 fields "nr-extensions" times:
  875. string extension-name
  876. string extension-value (binary)
  877. @type packet: L{bytes}
  878. @param packet: The message data.
  879. """
  880. (numExtensions,) = struct.unpack(">L", packet[:4])
  881. packet = packet[4:]
  882. extensions = {}
  883. for _ in range(numExtensions):
  884. extName, extValue, packet = getNS(packet, 2)
  885. extensions[extName] = extValue
  886. self.peerExtensions = extensions
  887. def setService(self, service):
  888. """
  889. Set our service to service and start it running. If we were
  890. running a service previously, stop it first.
  891. @type service: C{SSHService}
  892. @param service: The service to attach.
  893. """
  894. self._log.debug("starting service {service!r}", service=service.name)
  895. if self.service:
  896. self.service.serviceStopped()
  897. self.service = service
  898. service.transport = self
  899. self.service.serviceStarted()
  900. def sendDebug(self, message, alwaysDisplay=False, language=b""):
  901. """
  902. Send a debug message to the other side.
  903. @param message: the message to send.
  904. @type message: L{str}
  905. @param alwaysDisplay: if True, tell the other side to always
  906. display this message.
  907. @type alwaysDisplay: L{bool}
  908. @param language: optionally, the language the message is in.
  909. @type language: L{str}
  910. """
  911. self.sendPacket(
  912. MSG_DEBUG, (b"\1" if alwaysDisplay else b"\0") + NS(message) + NS(language)
  913. )
  914. def sendIgnore(self, message):
  915. """
  916. Send a message that will be ignored by the other side. This is
  917. useful to fool attacks based on guessing packet sizes in the
  918. encrypted stream.
  919. @param message: data to send with the message
  920. @type message: L{str}
  921. """
  922. self.sendPacket(MSG_IGNORE, NS(message))
  923. def sendUnimplemented(self):
  924. """
  925. Send a message to the other side that the last packet was not
  926. understood.
  927. """
  928. seqnum = self.incomingPacketSequence
  929. self.sendPacket(MSG_UNIMPLEMENTED, struct.pack("!L", seqnum))
  930. def sendDisconnect(self, reason, desc):
  931. """
  932. Send a disconnect message to the other side and then disconnect.
  933. @param reason: the reason for the disconnect. Should be one of the
  934. DISCONNECT_* values.
  935. @type reason: L{int}
  936. @param desc: a descrption of the reason for the disconnection.
  937. @type desc: L{str}
  938. """
  939. self.sendPacket(MSG_DISCONNECT, struct.pack(">L", reason) + NS(desc) + NS(b""))
  940. self._log.info(
  941. "Disconnecting with error, code {code}\nreason: {description}",
  942. code=reason,
  943. description=desc,
  944. )
  945. self.transport.loseConnection()
  946. def sendExtInfo(self, extensions):
  947. """
  948. Send an RFC 8308 extension advertisement to the remote peer.
  949. Nothing is sent if the peer doesn't support negotiations.
  950. @type extensions: L{list} of (L{bytes}, L{bytes})
  951. @param extensions: a list of (extension-name, extension-value) pairs.
  952. """
  953. if self._peerSupportsExtensions:
  954. payload = b"".join(
  955. [struct.pack(">L", len(extensions))]
  956. + [NS(name) + NS(value) for name, value in extensions]
  957. )
  958. self.sendPacket(MSG_EXT_INFO, payload)
  959. def _startEphemeralDH(self):
  960. """
  961. Prepares for a Diffie-Hellman key agreement exchange.
  962. Creates an ephemeral keypair in the group defined by (self.g,
  963. self.p) and stores it.
  964. """
  965. numbers = dh.DHParameterNumbers(self.p, self.g)
  966. parameters = numbers.parameters(default_backend())
  967. self.dhSecretKey = parameters.generate_private_key()
  968. y = self.dhSecretKey.public_key().public_numbers().y
  969. self.dhSecretKeyPublicMP = MP(y)
  970. def _finishEphemeralDH(self, remoteDHpublicKey):
  971. """
  972. Completes the Diffie-Hellman key agreement started by
  973. _startEphemeralDH, and forgets the ephemeral secret key.
  974. @type remoteDHpublicKey: L{int}
  975. @rtype: L{bytes}
  976. @return: The new shared secret, in SSH C{mpint} format.
  977. """
  978. remoteKey = dh.DHPublicNumbers(
  979. remoteDHpublicKey, dh.DHParameterNumbers(self.p, self.g)
  980. ).public_key(default_backend())
  981. secret = self.dhSecretKey.exchange(remoteKey)
  982. del self.dhSecretKey
  983. # The result of a Diffie-Hellman exchange is an integer, but
  984. # the Cryptography module returns it as bytes in a form that
  985. # is only vaguely documented. We fix it up to match the SSH
  986. # MP-integer format as described in RFC4251.
  987. secret = secret.lstrip(b"\x00")
  988. ch = ord(secret[0:1])
  989. if ch & 0x80: # High bit set?
  990. # Make room for the sign bit
  991. prefix = struct.pack(">L", len(secret) + 1) + b"\x00"
  992. else:
  993. prefix = struct.pack(">L", len(secret))
  994. return prefix + secret
  995. def _getKey(self, c, sharedSecret, exchangeHash):
  996. """
  997. Get one of the keys for authentication/encryption.
  998. @type c: L{bytes}
  999. @param c: The letter identifying which key this is.
  1000. @type sharedSecret: L{bytes}
  1001. @param sharedSecret: The shared secret K.
  1002. @type exchangeHash: L{bytes}
  1003. @param exchangeHash: The hash H from key exchange.
  1004. @rtype: L{bytes}
  1005. @return: The derived key.
  1006. """
  1007. hashProcessor = _kex.getHashProcessor(self.kexAlg)
  1008. k1 = hashProcessor(sharedSecret + exchangeHash + c + self.sessionID)
  1009. k1 = k1.digest()
  1010. k2 = hashProcessor(sharedSecret + exchangeHash + k1).digest()
  1011. k3 = hashProcessor(sharedSecret + exchangeHash + k1 + k2).digest()
  1012. k4 = hashProcessor(sharedSecret + exchangeHash + k1 + k2 + k3).digest()
  1013. return k1 + k2 + k3 + k4
  1014. def _keySetup(self, sharedSecret, exchangeHash):
  1015. """
  1016. Set up the keys for the connection and sends MSG_NEWKEYS when
  1017. finished,
  1018. @param sharedSecret: a secret string agreed upon using a Diffie-
  1019. Hellman exchange, so it is only shared between
  1020. the server and the client.
  1021. @type sharedSecret: L{str}
  1022. @param exchangeHash: A hash of various data known by both sides.
  1023. @type exchangeHash: L{str}
  1024. """
  1025. if not self.sessionID:
  1026. self.sessionID = exchangeHash
  1027. initIVCS = self._getKey(b"A", sharedSecret, exchangeHash)
  1028. initIVSC = self._getKey(b"B", sharedSecret, exchangeHash)
  1029. encKeyCS = self._getKey(b"C", sharedSecret, exchangeHash)
  1030. encKeySC = self._getKey(b"D", sharedSecret, exchangeHash)
  1031. integKeyCS = self._getKey(b"E", sharedSecret, exchangeHash)
  1032. integKeySC = self._getKey(b"F", sharedSecret, exchangeHash)
  1033. outs = [initIVSC, encKeySC, integKeySC]
  1034. ins = [initIVCS, encKeyCS, integKeyCS]
  1035. if self.isClient: # Reverse for the client
  1036. outs, ins = ins, outs
  1037. self.nextEncryptions.setKeys(outs[0], outs[1], ins[0], ins[1], outs[2], ins[2])
  1038. self.sendPacket(MSG_NEWKEYS, b"")
  1039. def _newKeys(self):
  1040. """
  1041. Called back by a subclass once a I{MSG_NEWKEYS} message has been
  1042. received. This indicates key exchange has completed and new encryption
  1043. and compression parameters should be adopted. Any messages which were
  1044. queued during key exchange will also be flushed.
  1045. """
  1046. self._log.debug("NEW KEYS")
  1047. self.currentEncryptions = self.nextEncryptions
  1048. if self.outgoingCompressionType == b"zlib":
  1049. self.outgoingCompression = zlib.compressobj(6)
  1050. if self.incomingCompressionType == b"zlib":
  1051. self.incomingCompression = zlib.decompressobj()
  1052. self._keyExchangeState = self._KEY_EXCHANGE_NONE
  1053. messages = self._blockedByKeyExchange
  1054. self._blockedByKeyExchange = None
  1055. for messageType, payload in messages:
  1056. self.sendPacket(messageType, payload)
  1057. def isEncrypted(self, direction="out"):
  1058. """
  1059. Check if the connection is encrypted in the given direction.
  1060. @type direction: L{str}
  1061. @param direction: The direction: one of 'out', 'in', or 'both'.
  1062. @rtype: L{bool}
  1063. @return: C{True} if it is encrypted.
  1064. """
  1065. if direction == "out":
  1066. return self.currentEncryptions.outCipType != b"none"
  1067. elif direction == "in":
  1068. return self.currentEncryptions.inCipType != b"none"
  1069. elif direction == "both":
  1070. return self.isEncrypted("in") and self.isEncrypted("out")
  1071. else:
  1072. raise TypeError('direction must be "out", "in", or "both"')
  1073. def isVerified(self, direction="out"):
  1074. """
  1075. Check if the connection is verified/authentication in the given direction.
  1076. @type direction: L{str}
  1077. @param direction: The direction: one of 'out', 'in', or 'both'.
  1078. @rtype: L{bool}
  1079. @return: C{True} if it is verified.
  1080. """
  1081. if direction == "out":
  1082. return self.currentEncryptions.outMACType != b"none"
  1083. elif direction == "in":
  1084. return self.currentEncryptions.inMACType != b"none"
  1085. elif direction == "both":
  1086. return self.isVerified("in") and self.isVerified("out")
  1087. else:
  1088. raise TypeError('direction must be "out", "in", or "both"')
  1089. def loseConnection(self):
  1090. """
  1091. Lose the connection to the other side, sending a
  1092. DISCONNECT_CONNECTION_LOST message.
  1093. """
  1094. self.sendDisconnect(DISCONNECT_CONNECTION_LOST, b"user closed connection")
  1095. # Client methods
  1096. def receiveError(self, reasonCode, description):
  1097. """
  1098. Called when we receive a disconnect error message from the other
  1099. side.
  1100. @param reasonCode: the reason for the disconnect, one of the
  1101. DISCONNECT_ values.
  1102. @type reasonCode: L{int}
  1103. @param description: a human-readable description of the
  1104. disconnection.
  1105. @type description: L{str}
  1106. """
  1107. self._log.error(
  1108. "Got remote error, code {code}\nreason: {description}",
  1109. code=reasonCode,
  1110. description=description,
  1111. )
  1112. def receiveUnimplemented(self, seqnum):
  1113. """
  1114. Called when we receive an unimplemented packet message from the other
  1115. side.
  1116. @param seqnum: the sequence number that was not understood.
  1117. @type seqnum: L{int}
  1118. """
  1119. self._log.warn("other side unimplemented packet #{seqnum}", seqnum=seqnum)
  1120. def receiveDebug(self, alwaysDisplay, message, lang):
  1121. """
  1122. Called when we receive a debug message from the other side.
  1123. @param alwaysDisplay: if True, this message should always be
  1124. displayed.
  1125. @type alwaysDisplay: L{bool}
  1126. @param message: the debug message
  1127. @type message: L{str}
  1128. @param lang: optionally the language the message is in.
  1129. @type lang: L{str}
  1130. """
  1131. if alwaysDisplay:
  1132. self._log.debug("Remote Debug Message: {message}", message=message)
  1133. def _generateECPrivateKey(self):
  1134. """
  1135. Generate an private key for ECDH key exchange.
  1136. @rtype: The appropriate private key type matching C{self.kexAlg}:
  1137. L{ec.EllipticCurvePrivateKey} for C{ecdh-sha2-nistp*}, or
  1138. L{x25519.X25519PrivateKey} for C{curve25519-sha256}.
  1139. @return: The generated private key.
  1140. """
  1141. if self.kexAlg.startswith(b"ecdh-sha2-nistp"):
  1142. try:
  1143. curve = keys._curveTable[b"ecdsa" + self.kexAlg[4:]]
  1144. except KeyError:
  1145. raise UnsupportedAlgorithm("unused-key")
  1146. return ec.generate_private_key(curve, default_backend())
  1147. elif self.kexAlg in (b"curve25519-sha256", b"curve25519-sha256@libssh.org"):
  1148. return x25519.X25519PrivateKey.generate()
  1149. else:
  1150. raise UnsupportedAlgorithm(
  1151. "Cannot generate elliptic curve private key for {!r}".format(
  1152. self.kexAlg
  1153. )
  1154. )
  1155. def _encodeECPublicKey(self, ecPub):
  1156. """
  1157. Encode an elliptic curve public key to bytes.
  1158. @type ecPub: The appropriate public key type matching
  1159. C{self.kexAlg}: L{ec.EllipticCurvePublicKey} for
  1160. C{ecdh-sha2-nistp*}, or L{x25519.X25519PublicKey} for
  1161. C{curve25519-sha256}.
  1162. @param ecPub: The public key to encode.
  1163. @rtype: L{bytes}
  1164. @return: The encoded public key.
  1165. """
  1166. if self.kexAlg.startswith(b"ecdh-sha2-nistp"):
  1167. return ecPub.public_bytes(
  1168. serialization.Encoding.X962,
  1169. serialization.PublicFormat.UncompressedPoint,
  1170. )
  1171. elif self.kexAlg in (b"curve25519-sha256", b"curve25519-sha256@libssh.org"):
  1172. return ecPub.public_bytes(
  1173. serialization.Encoding.Raw, serialization.PublicFormat.Raw
  1174. )
  1175. else:
  1176. raise UnsupportedAlgorithm(
  1177. f"Cannot encode elliptic curve public key for {self.kexAlg!r}"
  1178. )
  1179. def _generateECSharedSecret(self, ecPriv, theirECPubBytes):
  1180. """
  1181. Generate a shared secret for ECDH key exchange.
  1182. @type ecPriv: The appropriate private key type matching
  1183. C{self.kexAlg}: L{ec.EllipticCurvePrivateKey} for
  1184. C{ecdh-sha2-nistp*}, or L{x25519.X25519PrivateKey} for
  1185. C{curve25519-sha256}.
  1186. @param ecPriv: Our private key.
  1187. @rtype: L{bytes}
  1188. @return: The generated shared secret, as an SSH multiple-precision
  1189. integer.
  1190. """
  1191. if self.kexAlg.startswith(b"ecdh-sha2-nistp"):
  1192. try:
  1193. curve = keys._curveTable[b"ecdsa" + self.kexAlg[4:]]
  1194. except KeyError:
  1195. raise UnsupportedAlgorithm("unused-key")
  1196. theirECPub = ec.EllipticCurvePublicKey.from_encoded_point(
  1197. curve, theirECPubBytes
  1198. )
  1199. sharedSecret = ecPriv.exchange(ec.ECDH(), theirECPub)
  1200. elif self.kexAlg in (b"curve25519-sha256", b"curve25519-sha256@libssh.org"):
  1201. theirECPub = x25519.X25519PublicKey.from_public_bytes(theirECPubBytes)
  1202. sharedSecret = ecPriv.exchange(theirECPub)
  1203. else:
  1204. raise UnsupportedAlgorithm(
  1205. "Cannot generate elliptic curve shared secret for {!r}".format(
  1206. self.kexAlg
  1207. )
  1208. )
  1209. return _mpFromBytes(sharedSecret)
  1210. class SSHServerTransport(SSHTransportBase):
  1211. """
  1212. SSHServerTransport implements the server side of the SSH protocol.
  1213. @ivar isClient: since we are never the client, this is always False.
  1214. @ivar ignoreNextPacket: if True, ignore the next key exchange packet. This
  1215. is set when the client sends a guessed key exchange packet but with
  1216. an incorrect guess.
  1217. @ivar dhGexRequest: the KEX_DH_GEX_REQUEST(_OLD) that the client sent.
  1218. The key generation needs this to be stored.
  1219. @ivar g: the Diffie-Hellman group generator.
  1220. @ivar p: the Diffie-Hellman group prime.
  1221. """
  1222. isClient = False
  1223. ignoreNextPacket = 0
  1224. def _getHostKeys(self, keyAlg):
  1225. """
  1226. Get the public and private host keys corresponding to the given
  1227. public key signature algorithm.
  1228. The factory stores public and private host keys by their key format,
  1229. which is not quite the same as the key signature algorithm: for
  1230. example, an ssh-rsa key can sign using any of the ssh-rsa,
  1231. rsa-sha2-256, or rsa-sha2-512 algorithms.
  1232. @type keyAlg: L{bytes}
  1233. @param keyAlg: A public key signature algorithm name.
  1234. @rtype: 2-L{tuple} of L{keys.Key}
  1235. @return: The public and private host keys.
  1236. @raises KeyError: if the factory does not have both a public and a
  1237. private host key for this signature algorithm.
  1238. """
  1239. if keyAlg in {b"rsa-sha2-256", b"rsa-sha2-512"}:
  1240. keyFormat = b"ssh-rsa"
  1241. else:
  1242. keyFormat = keyAlg
  1243. return self.factory.publicKeys[keyFormat], self.factory.privateKeys[keyFormat]
  1244. def ssh_KEXINIT(self, packet):
  1245. """
  1246. Called when we receive a MSG_KEXINIT message. For a description
  1247. of the packet, see SSHTransportBase.ssh_KEXINIT(). Additionally,
  1248. this method checks if a guessed key exchange packet was sent. If
  1249. it was sent, and it guessed incorrectly, the next key exchange
  1250. packet MUST be ignored.
  1251. """
  1252. retval = SSHTransportBase.ssh_KEXINIT(self, packet)
  1253. if not retval: # Disconnected
  1254. return
  1255. else:
  1256. kexAlgs, keyAlgs, rest = retval
  1257. if ord(rest[0:1]): # Flag first_kex_packet_follows?
  1258. if (
  1259. kexAlgs[0] != self.supportedKeyExchanges[0]
  1260. or keyAlgs[0] != self.supportedPublicKeys[0]
  1261. ):
  1262. self.ignoreNextPacket = True # Guess was wrong
  1263. def _ssh_KEX_ECDH_INIT(self, packet):
  1264. """
  1265. Called from L{ssh_KEX_DH_GEX_REQUEST_OLD} to handle
  1266. elliptic curve key exchanges.
  1267. Payload::
  1268. string client Elliptic Curve Diffie-Hellman public key
  1269. Just like L{_ssh_KEXDH_INIT} this message type is also not dispatched
  1270. directly. Extra check to determine if this is really KEX_ECDH_INIT
  1271. is required.
  1272. First we load the host's public/private keys.
  1273. Then we generate the ECDH public/private keypair for the given curve.
  1274. With that we generate the shared secret key.
  1275. Then we compute the hash to sign and send back to the client
  1276. Along with the server's public key and the ECDH public key.
  1277. @type packet: L{bytes}
  1278. @param packet: The message data.
  1279. @return: None.
  1280. """
  1281. # Get the raw client public key.
  1282. pktPub, packet = getNS(packet)
  1283. # Get the host's public and private keys
  1284. pubHostKey, privHostKey = self._getHostKeys(self.keyAlg)
  1285. # Generate the private key
  1286. ecPriv = self._generateECPrivateKey()
  1287. # Get the public key
  1288. self.ecPub = ecPriv.public_key()
  1289. encPub = self._encodeECPublicKey(self.ecPub)
  1290. # Generate the shared secret
  1291. sharedSecret = self._generateECSharedSecret(ecPriv, pktPub)
  1292. # Finish update and digest
  1293. h = _kex.getHashProcessor(self.kexAlg)()
  1294. h.update(NS(self.otherVersionString))
  1295. h.update(NS(self.ourVersionString))
  1296. h.update(NS(self.otherKexInitPayload))
  1297. h.update(NS(self.ourKexInitPayload))
  1298. h.update(NS(pubHostKey.blob()))
  1299. h.update(NS(pktPub))
  1300. h.update(NS(encPub))
  1301. h.update(sharedSecret)
  1302. exchangeHash = h.digest()
  1303. self.sendPacket(
  1304. MSG_KEXDH_REPLY,
  1305. NS(pubHostKey.blob())
  1306. + NS(encPub)
  1307. + NS(privHostKey.sign(exchangeHash, signatureType=self.keyAlg)),
  1308. )
  1309. self._keySetup(sharedSecret, exchangeHash)
  1310. def _ssh_KEXDH_INIT(self, packet):
  1311. """
  1312. Called to handle the beginning of a non-group key exchange.
  1313. Unlike other message types, this is not dispatched automatically. It
  1314. is called from C{ssh_KEX_DH_GEX_REQUEST_OLD} because an extra check is
  1315. required to determine if this is really a KEXDH_INIT message or if it
  1316. is a KEX_DH_GEX_REQUEST_OLD message.
  1317. The KEXDH_INIT payload::
  1318. integer e (the client's Diffie-Hellman public key)
  1319. We send the KEXDH_REPLY with our host key and signature.
  1320. @type packet: L{bytes}
  1321. @param packet: The message data.
  1322. """
  1323. clientDHpublicKey, foo = getMP(packet)
  1324. pubHostKey, privHostKey = self._getHostKeys(self.keyAlg)
  1325. self.g, self.p = _kex.getDHGeneratorAndPrime(self.kexAlg)
  1326. self._startEphemeralDH()
  1327. sharedSecret = self._finishEphemeralDH(clientDHpublicKey)
  1328. h = _kex.getHashProcessor(self.kexAlg)()
  1329. h.update(NS(self.otherVersionString))
  1330. h.update(NS(self.ourVersionString))
  1331. h.update(NS(self.otherKexInitPayload))
  1332. h.update(NS(self.ourKexInitPayload))
  1333. h.update(NS(pubHostKey.blob()))
  1334. h.update(MP(clientDHpublicKey))
  1335. h.update(self.dhSecretKeyPublicMP)
  1336. h.update(sharedSecret)
  1337. exchangeHash = h.digest()
  1338. self.sendPacket(
  1339. MSG_KEXDH_REPLY,
  1340. NS(pubHostKey.blob())
  1341. + self.dhSecretKeyPublicMP
  1342. + NS(privHostKey.sign(exchangeHash, signatureType=self.keyAlg)),
  1343. )
  1344. self._keySetup(sharedSecret, exchangeHash)
  1345. def ssh_KEX_DH_GEX_REQUEST_OLD(self, packet):
  1346. """
  1347. This represents different key exchange methods that share the same
  1348. integer value. If the message is determined to be a KEXDH_INIT,
  1349. L{_ssh_KEXDH_INIT} is called to handle it. If it is a KEX_ECDH_INIT,
  1350. L{_ssh_KEX_ECDH_INIT} is called.
  1351. Otherwise, for KEX_DH_GEX_REQUEST_OLD payload::
  1352. integer ideal (ideal size for the Diffie-Hellman prime)
  1353. We send the KEX_DH_GEX_GROUP message with the group that is
  1354. closest in size to ideal.
  1355. If we were told to ignore the next key exchange packet by ssh_KEXINIT,
  1356. drop it on the floor and return.
  1357. @type packet: L{bytes}
  1358. @param packet: The message data.
  1359. """
  1360. if self.ignoreNextPacket:
  1361. self.ignoreNextPacket = 0
  1362. return
  1363. # KEXDH_INIT, KEX_ECDH_INIT, and KEX_DH_GEX_REQUEST_OLD
  1364. # have the same value, so use another cue
  1365. # to decide what kind of message the peer sent us.
  1366. if _kex.isFixedGroup(self.kexAlg):
  1367. return self._ssh_KEXDH_INIT(packet)
  1368. elif _kex.isEllipticCurve(self.kexAlg):
  1369. return self._ssh_KEX_ECDH_INIT(packet)
  1370. else:
  1371. self.dhGexRequest = packet
  1372. ideal = struct.unpack(">L", packet)[0]
  1373. self.g, self.p = self.factory.getDHPrime(ideal)
  1374. self._startEphemeralDH()
  1375. self.sendPacket(MSG_KEX_DH_GEX_GROUP, MP(self.p) + MP(self.g))
  1376. def ssh_KEX_DH_GEX_REQUEST(self, packet):
  1377. """
  1378. Called when we receive a MSG_KEX_DH_GEX_REQUEST message. Payload::
  1379. integer minimum
  1380. integer ideal
  1381. integer maximum
  1382. The client is asking for a Diffie-Hellman group between minimum and
  1383. maximum size, and close to ideal if possible. We reply with a
  1384. MSG_KEX_DH_GEX_GROUP message.
  1385. If we were told to ignore the next key exchange packet by ssh_KEXINIT,
  1386. drop it on the floor and return.
  1387. @type packet: L{bytes}
  1388. @param packet: The message data.
  1389. """
  1390. if self.ignoreNextPacket:
  1391. self.ignoreNextPacket = 0
  1392. return
  1393. self.dhGexRequest = packet
  1394. min, ideal, max = struct.unpack(">3L", packet)
  1395. self.g, self.p = self.factory.getDHPrime(ideal)
  1396. self._startEphemeralDH()
  1397. self.sendPacket(MSG_KEX_DH_GEX_GROUP, MP(self.p) + MP(self.g))
  1398. def ssh_KEX_DH_GEX_INIT(self, packet):
  1399. """
  1400. Called when we get a MSG_KEX_DH_GEX_INIT message. Payload::
  1401. integer e (client DH public key)
  1402. We send the MSG_KEX_DH_GEX_REPLY message with our host key and
  1403. signature.
  1404. @type packet: L{bytes}
  1405. @param packet: The message data.
  1406. """
  1407. clientDHpublicKey, foo = getMP(packet)
  1408. pubHostKey, privHostKey = self._getHostKeys(self.keyAlg)
  1409. # TODO: we should also look at the value they send to us and reject
  1410. # insecure values of f (if g==2 and f has a single '1' bit while the
  1411. # rest are '0's, then they must have used a small y also).
  1412. # TODO: This could be computed when self.p is set up
  1413. # or do as openssh does and scan f for a single '1' bit instead
  1414. sharedSecret = self._finishEphemeralDH(clientDHpublicKey)
  1415. h = _kex.getHashProcessor(self.kexAlg)()
  1416. h.update(NS(self.otherVersionString))
  1417. h.update(NS(self.ourVersionString))
  1418. h.update(NS(self.otherKexInitPayload))
  1419. h.update(NS(self.ourKexInitPayload))
  1420. h.update(NS(pubHostKey.blob()))
  1421. h.update(self.dhGexRequest)
  1422. h.update(MP(self.p))
  1423. h.update(MP(self.g))
  1424. h.update(MP(clientDHpublicKey))
  1425. h.update(self.dhSecretKeyPublicMP)
  1426. h.update(sharedSecret)
  1427. exchangeHash = h.digest()
  1428. self.sendPacket(
  1429. MSG_KEX_DH_GEX_REPLY,
  1430. NS(pubHostKey.blob())
  1431. + self.dhSecretKeyPublicMP
  1432. + NS(privHostKey.sign(exchangeHash, signatureType=self.keyAlg)),
  1433. )
  1434. self._keySetup(sharedSecret, exchangeHash)
  1435. def _keySetup(self, sharedSecret, exchangeHash):
  1436. """
  1437. See SSHTransportBase._keySetup().
  1438. """
  1439. firstKey = self.sessionID is None
  1440. SSHTransportBase._keySetup(self, sharedSecret, exchangeHash)
  1441. # RFC 8308 section 2.4 says that the server MAY send EXT_INFO at
  1442. # zero, one, or both of the following opportunities: the next packet
  1443. # following the server's first MSG_NEWKEYS, or immediately preceding
  1444. # the server's MSG_USERAUTH_SUCCESS. We have no need for the
  1445. # latter, so make sure we only send it in the former case.
  1446. if firstKey:
  1447. self.sendExtInfo(
  1448. [(b"server-sig-algs", b",".join(self.supportedPublicKeys))]
  1449. )
  1450. def ssh_NEWKEYS(self, packet):
  1451. """
  1452. Called when we get a MSG_NEWKEYS message. No payload.
  1453. When we get this, the keys have been set on both sides, and we
  1454. start using them to encrypt and authenticate the connection.
  1455. @type packet: L{bytes}
  1456. @param packet: The message data.
  1457. """
  1458. if packet != b"":
  1459. self.sendDisconnect(DISCONNECT_PROTOCOL_ERROR, b"NEWKEYS takes no data")
  1460. return
  1461. self._newKeys()
  1462. def ssh_SERVICE_REQUEST(self, packet):
  1463. """
  1464. Called when we get a MSG_SERVICE_REQUEST message. Payload::
  1465. string serviceName
  1466. The client has requested a service. If we can start the service,
  1467. start it; otherwise, disconnect with
  1468. DISCONNECT_SERVICE_NOT_AVAILABLE.
  1469. @type packet: L{bytes}
  1470. @param packet: The message data.
  1471. """
  1472. service, rest = getNS(packet)
  1473. cls = self.factory.getService(self, service)
  1474. if not cls:
  1475. self.sendDisconnect(
  1476. DISCONNECT_SERVICE_NOT_AVAILABLE, b"don't have service " + service
  1477. )
  1478. return
  1479. else:
  1480. self.sendPacket(MSG_SERVICE_ACCEPT, NS(service))
  1481. self.setService(cls())
  1482. class SSHClientTransport(SSHTransportBase):
  1483. """
  1484. SSHClientTransport implements the client side of the SSH protocol.
  1485. @ivar isClient: since we are always the client, this is always True.
  1486. @ivar _gotNewKeys: if we receive a MSG_NEWKEYS message before we are
  1487. ready to transition to the new keys, this is set to True so we
  1488. can transition when the keys are ready locally.
  1489. @ivar x: our Diffie-Hellman private key.
  1490. @ivar e: our Diffie-Hellman public key.
  1491. @ivar g: the Diffie-Hellman group generator.
  1492. @ivar p: the Diffie-Hellman group prime
  1493. @ivar instance: the SSHService object we are requesting.
  1494. @ivar _dhMinimalGroupSize: Minimal acceptable group size advertised by the
  1495. client in MSG_KEX_DH_GEX_REQUEST.
  1496. @type _dhMinimalGroupSize: int
  1497. @ivar _dhMaximalGroupSize: Maximal acceptable group size advertised by the
  1498. client in MSG_KEX_DH_GEX_REQUEST.
  1499. @type _dhMaximalGroupSize: int
  1500. @ivar _dhPreferredGroupSize: Preferred group size advertised by the client
  1501. in MSG_KEX_DH_GEX_REQUEST.
  1502. @type _dhPreferredGroupSize: int
  1503. """
  1504. isClient = True
  1505. # Recommended minimal and maximal values from RFC 4419, 3.
  1506. _dhMinimalGroupSize = 1024
  1507. _dhMaximalGroupSize = 8192
  1508. # FIXME: https://twistedmatrix.com/trac/ticket/8103
  1509. # This may need to be more dynamic; compare kexgex_client in
  1510. # OpenSSH.
  1511. _dhPreferredGroupSize = 2048
  1512. def connectionMade(self):
  1513. """
  1514. Called when the connection is started with the server. Just sets
  1515. up a private instance variable.
  1516. """
  1517. SSHTransportBase.connectionMade(self)
  1518. self._gotNewKeys = 0
  1519. def ssh_KEXINIT(self, packet):
  1520. """
  1521. Called when we receive a MSG_KEXINIT message. For a description
  1522. of the packet, see SSHTransportBase.ssh_KEXINIT(). Additionally,
  1523. this method sends the first key exchange packet.
  1524. If the agreed-upon exchange is ECDH, generate a key pair for the
  1525. corresponding curve and send the public key.
  1526. If the agreed-upon exchange has a fixed prime/generator group,
  1527. generate a public key and send it in a MSG_KEXDH_INIT message.
  1528. Otherwise, ask for a 2048 bit group with a MSG_KEX_DH_GEX_REQUEST
  1529. message.
  1530. """
  1531. if SSHTransportBase.ssh_KEXINIT(self, packet) is None:
  1532. # Connection was disconnected while doing base processing.
  1533. # Maybe no common protocols were agreed.
  1534. return
  1535. # Are we using ECDH?
  1536. if _kex.isEllipticCurve(self.kexAlg):
  1537. # Generate the keys
  1538. self.ecPriv = self._generateECPrivateKey()
  1539. self.ecPub = self.ecPriv.public_key()
  1540. # DH_GEX_REQUEST_OLD is the same number we need.
  1541. self.sendPacket(
  1542. MSG_KEX_DH_GEX_REQUEST_OLD, NS(self._encodeECPublicKey(self.ecPub))
  1543. )
  1544. elif _kex.isFixedGroup(self.kexAlg):
  1545. # We agreed on a fixed group key exchange algorithm.
  1546. self.g, self.p = _kex.getDHGeneratorAndPrime(self.kexAlg)
  1547. self._startEphemeralDH()
  1548. self.sendPacket(MSG_KEXDH_INIT, self.dhSecretKeyPublicMP)
  1549. else:
  1550. # We agreed on a dynamic group. Tell the server what range of
  1551. # group sizes we accept, and what size we prefer; the server
  1552. # will then select a group.
  1553. self.sendPacket(
  1554. MSG_KEX_DH_GEX_REQUEST,
  1555. struct.pack(
  1556. "!LLL",
  1557. self._dhMinimalGroupSize,
  1558. self._dhPreferredGroupSize,
  1559. self._dhMaximalGroupSize,
  1560. ),
  1561. )
  1562. def _ssh_KEX_ECDH_REPLY(self, packet):
  1563. """
  1564. Called to handle a reply to a ECDH exchange message(KEX_ECDH_INIT).
  1565. Like the handler for I{KEXDH_INIT}, this message type has an
  1566. overlapping value. This method is called from C{ssh_KEX_DH_GEX_GROUP}
  1567. if that method detects a non-group key exchange is in progress.
  1568. Payload::
  1569. string serverHostKey
  1570. string server Elliptic Curve Diffie-Hellman public key
  1571. string signature
  1572. We verify the host key and continue if it passes verificiation.
  1573. Otherwise raise an exception and return.
  1574. @type packet: L{bytes}
  1575. @param packet: The message data.
  1576. @return: A deferred firing when key exchange is complete.
  1577. """
  1578. def _continue_KEX_ECDH_REPLY(ignored, hostKey, pubKey, signature):
  1579. # Save off the host public key.
  1580. theirECHost = hostKey
  1581. sharedSecret = self._generateECSharedSecret(self.ecPriv, pubKey)
  1582. h = _kex.getHashProcessor(self.kexAlg)()
  1583. h.update(NS(self.ourVersionString))
  1584. h.update(NS(self.otherVersionString))
  1585. h.update(NS(self.ourKexInitPayload))
  1586. h.update(NS(self.otherKexInitPayload))
  1587. h.update(NS(theirECHost))
  1588. h.update(NS(self._encodeECPublicKey(self.ecPub)))
  1589. h.update(NS(pubKey))
  1590. h.update(sharedSecret)
  1591. exchangeHash = h.digest()
  1592. if not keys.Key.fromString(theirECHost).verify(signature, exchangeHash):
  1593. self.sendDisconnect(DISCONNECT_KEY_EXCHANGE_FAILED, b"bad signature")
  1594. else:
  1595. self._keySetup(sharedSecret, exchangeHash)
  1596. # Get the host public key,
  1597. # the raw ECDH public key bytes and the signature
  1598. hostKey, pubKey, signature, packet = getNS(packet, 3)
  1599. # Easier to comment this out for now than to update all of the tests.
  1600. # fingerprint = nativeString(base64.b64encode(
  1601. # sha256(hostKey).digest()))
  1602. fingerprint = b":".join(
  1603. [binascii.hexlify(ch) for ch in iterbytes(md5(hostKey).digest())]
  1604. )
  1605. d = self.verifyHostKey(hostKey, fingerprint)
  1606. d.addCallback(_continue_KEX_ECDH_REPLY, hostKey, pubKey, signature)
  1607. d.addErrback(
  1608. lambda unused: self.sendDisconnect(
  1609. DISCONNECT_HOST_KEY_NOT_VERIFIABLE, b"bad host key"
  1610. )
  1611. )
  1612. return d
  1613. def _ssh_KEXDH_REPLY(self, packet):
  1614. """
  1615. Called to handle a reply to a non-group key exchange message
  1616. (KEXDH_INIT).
  1617. Like the handler for I{KEXDH_INIT}, this message type has an
  1618. overlapping value. This method is called from C{ssh_KEX_DH_GEX_GROUP}
  1619. if that method detects a non-group key exchange is in progress.
  1620. Payload::
  1621. string serverHostKey
  1622. integer f (server Diffie-Hellman public key)
  1623. string signature
  1624. We verify the host key by calling verifyHostKey, then continue in
  1625. _continueKEXDH_REPLY.
  1626. @type packet: L{bytes}
  1627. @param packet: The message data.
  1628. @return: A deferred firing when key exchange is complete.
  1629. """
  1630. pubKey, packet = getNS(packet)
  1631. f, packet = getMP(packet)
  1632. signature, packet = getNS(packet)
  1633. fingerprint = b":".join(
  1634. [binascii.hexlify(ch) for ch in iterbytes(md5(pubKey).digest())]
  1635. )
  1636. d = self.verifyHostKey(pubKey, fingerprint)
  1637. d.addCallback(self._continueKEXDH_REPLY, pubKey, f, signature)
  1638. d.addErrback(
  1639. lambda unused: self.sendDisconnect(
  1640. DISCONNECT_HOST_KEY_NOT_VERIFIABLE, b"bad host key"
  1641. )
  1642. )
  1643. return d
  1644. def ssh_KEX_DH_GEX_GROUP(self, packet):
  1645. """
  1646. This handles different messages which share an integer value.
  1647. If the key exchange does not have a fixed prime/generator group,
  1648. we generate a Diffie-Hellman public key and send it in a
  1649. MSG_KEX_DH_GEX_INIT message.
  1650. Payload::
  1651. string g (group generator)
  1652. string p (group prime)
  1653. @type packet: L{bytes}
  1654. @param packet: The message data.
  1655. """
  1656. if _kex.isFixedGroup(self.kexAlg):
  1657. return self._ssh_KEXDH_REPLY(packet)
  1658. elif _kex.isEllipticCurve(self.kexAlg):
  1659. return self._ssh_KEX_ECDH_REPLY(packet)
  1660. else:
  1661. self.p, rest = getMP(packet)
  1662. self.g, rest = getMP(rest)
  1663. self._startEphemeralDH()
  1664. self.sendPacket(MSG_KEX_DH_GEX_INIT, self.dhSecretKeyPublicMP)
  1665. def _continueKEXDH_REPLY(self, ignored, pubKey, f, signature):
  1666. """
  1667. The host key has been verified, so we generate the keys.
  1668. @param ignored: Ignored.
  1669. @param pubKey: the public key blob for the server's public key.
  1670. @type pubKey: L{str}
  1671. @param f: the server's Diffie-Hellman public key.
  1672. @type f: L{int}
  1673. @param signature: the server's signature, verifying that it has the
  1674. correct private key.
  1675. @type signature: L{str}
  1676. """
  1677. serverKey = keys.Key.fromString(pubKey)
  1678. sharedSecret = self._finishEphemeralDH(f)
  1679. h = _kex.getHashProcessor(self.kexAlg)()
  1680. h.update(NS(self.ourVersionString))
  1681. h.update(NS(self.otherVersionString))
  1682. h.update(NS(self.ourKexInitPayload))
  1683. h.update(NS(self.otherKexInitPayload))
  1684. h.update(NS(pubKey))
  1685. h.update(self.dhSecretKeyPublicMP)
  1686. h.update(MP(f))
  1687. h.update(sharedSecret)
  1688. exchangeHash = h.digest()
  1689. if not serverKey.verify(signature, exchangeHash):
  1690. self.sendDisconnect(DISCONNECT_KEY_EXCHANGE_FAILED, b"bad signature")
  1691. return
  1692. self._keySetup(sharedSecret, exchangeHash)
  1693. def ssh_KEX_DH_GEX_REPLY(self, packet):
  1694. """
  1695. Called when we receive a MSG_KEX_DH_GEX_REPLY message. Payload::
  1696. string server host key
  1697. integer f (server DH public key)
  1698. We verify the host key by calling verifyHostKey, then continue in
  1699. _continueGEX_REPLY.
  1700. @type packet: L{bytes}
  1701. @param packet: The message data.
  1702. @return: A deferred firing once key exchange is complete.
  1703. """
  1704. pubKey, packet = getNS(packet)
  1705. f, packet = getMP(packet)
  1706. signature, packet = getNS(packet)
  1707. fingerprint = b":".join(
  1708. [binascii.hexlify(c) for c in iterbytes(md5(pubKey).digest())]
  1709. )
  1710. d = self.verifyHostKey(pubKey, fingerprint)
  1711. d.addCallback(self._continueGEX_REPLY, pubKey, f, signature)
  1712. d.addErrback(
  1713. lambda unused: self.sendDisconnect(
  1714. DISCONNECT_HOST_KEY_NOT_VERIFIABLE, b"bad host key"
  1715. )
  1716. )
  1717. return d
  1718. def _continueGEX_REPLY(self, ignored, pubKey, f, signature):
  1719. """
  1720. The host key has been verified, so we generate the keys.
  1721. @param ignored: Ignored.
  1722. @param pubKey: the public key blob for the server's public key.
  1723. @type pubKey: L{str}
  1724. @param f: the server's Diffie-Hellman public key.
  1725. @type f: L{int}
  1726. @param signature: the server's signature, verifying that it has the
  1727. correct private key.
  1728. @type signature: L{str}
  1729. """
  1730. serverKey = keys.Key.fromString(pubKey)
  1731. sharedSecret = self._finishEphemeralDH(f)
  1732. h = _kex.getHashProcessor(self.kexAlg)()
  1733. h.update(NS(self.ourVersionString))
  1734. h.update(NS(self.otherVersionString))
  1735. h.update(NS(self.ourKexInitPayload))
  1736. h.update(NS(self.otherKexInitPayload))
  1737. h.update(NS(pubKey))
  1738. h.update(
  1739. struct.pack(
  1740. "!LLL",
  1741. self._dhMinimalGroupSize,
  1742. self._dhPreferredGroupSize,
  1743. self._dhMaximalGroupSize,
  1744. )
  1745. )
  1746. h.update(MP(self.p))
  1747. h.update(MP(self.g))
  1748. h.update(self.dhSecretKeyPublicMP)
  1749. h.update(MP(f))
  1750. h.update(sharedSecret)
  1751. exchangeHash = h.digest()
  1752. if not serverKey.verify(signature, exchangeHash):
  1753. self.sendDisconnect(DISCONNECT_KEY_EXCHANGE_FAILED, b"bad signature")
  1754. return
  1755. self._keySetup(sharedSecret, exchangeHash)
  1756. def _keySetup(self, sharedSecret, exchangeHash):
  1757. """
  1758. See SSHTransportBase._keySetup().
  1759. """
  1760. SSHTransportBase._keySetup(self, sharedSecret, exchangeHash)
  1761. if self._gotNewKeys:
  1762. self.ssh_NEWKEYS(b"")
  1763. def ssh_NEWKEYS(self, packet):
  1764. """
  1765. Called when we receive a MSG_NEWKEYS message. No payload.
  1766. If we've finished setting up our own keys, start using them.
  1767. Otherwise, remember that we've received this message.
  1768. @type packet: L{bytes}
  1769. @param packet: The message data.
  1770. """
  1771. if packet != b"":
  1772. self.sendDisconnect(DISCONNECT_PROTOCOL_ERROR, b"NEWKEYS takes no data")
  1773. return
  1774. if not self.nextEncryptions.encBlockSize:
  1775. self._gotNewKeys = 1
  1776. return
  1777. self._newKeys()
  1778. self.connectionSecure()
  1779. def ssh_SERVICE_ACCEPT(self, packet):
  1780. """
  1781. Called when we receive a MSG_SERVICE_ACCEPT message. Payload::
  1782. string service name
  1783. Start the service we requested.
  1784. @type packet: L{bytes}
  1785. @param packet: The message data.
  1786. """
  1787. if packet == b"":
  1788. self._log.info("got SERVICE_ACCEPT without payload")
  1789. else:
  1790. name = getNS(packet)[0]
  1791. if name != self.instance.name:
  1792. self.sendDisconnect(
  1793. DISCONNECT_PROTOCOL_ERROR,
  1794. b"received accept for service we did not request",
  1795. )
  1796. self.setService(self.instance)
  1797. def requestService(self, instance):
  1798. """
  1799. Request that a service be run over this transport.
  1800. @type instance: subclass of L{twisted.conch.ssh.service.SSHService}
  1801. @param instance: The service to run.
  1802. """
  1803. self.sendPacket(MSG_SERVICE_REQUEST, NS(instance.name))
  1804. self.instance = instance
  1805. # Client methods
  1806. def verifyHostKey(self, hostKey, fingerprint):
  1807. """
  1808. Returns a Deferred that gets a callback if it is a valid key, or
  1809. an errback if not.
  1810. @type hostKey: L{bytes}
  1811. @param hostKey: The host key to verify.
  1812. @type fingerprint: L{bytes}
  1813. @param fingerprint: The fingerprint of the key.
  1814. @return: A deferred firing with C{True} if the key is valid.
  1815. """
  1816. return defer.fail(NotImplementedError())
  1817. def connectionSecure(self):
  1818. """
  1819. Called when the encryption has been set up. Generally,
  1820. requestService() is called to run another service over the transport.
  1821. """
  1822. raise NotImplementedError()
  1823. class _NullEncryptionContext:
  1824. """
  1825. An encryption context that does not actually encrypt anything.
  1826. """
  1827. def update(self, data):
  1828. """
  1829. 'Encrypt' new data by doing nothing.
  1830. @type data: L{bytes}
  1831. @param data: The data to 'encrypt'.
  1832. @rtype: L{bytes}
  1833. @return: The 'encrypted' data.
  1834. """
  1835. return data
  1836. class _DummyAlgorithm:
  1837. """
  1838. An encryption algorithm that does not actually encrypt anything.
  1839. """
  1840. block_size = 64
  1841. class _DummyCipher:
  1842. """
  1843. A cipher for the none encryption method.
  1844. @ivar block_size: the block size of the encryption. In the case of the
  1845. none cipher, this is 8 bytes.
  1846. """
  1847. algorithm = _DummyAlgorithm()
  1848. def encryptor(self):
  1849. """
  1850. Construct a noop encryptor.
  1851. @return: The encryptor.
  1852. """
  1853. return _NullEncryptionContext()
  1854. def decryptor(self):
  1855. """
  1856. Construct a noop decryptor.
  1857. @return: The decryptor.
  1858. """
  1859. return _NullEncryptionContext()
  1860. DH_GENERATOR, DH_PRIME = _kex.getDHGeneratorAndPrime(b"diffie-hellman-group14-sha1")
  1861. MSG_DISCONNECT = 1
  1862. MSG_IGNORE = 2
  1863. MSG_UNIMPLEMENTED = 3
  1864. MSG_DEBUG = 4
  1865. MSG_SERVICE_REQUEST = 5
  1866. MSG_SERVICE_ACCEPT = 6
  1867. MSG_EXT_INFO = 7
  1868. MSG_KEXINIT = 20
  1869. MSG_NEWKEYS = 21
  1870. MSG_KEXDH_INIT = 30
  1871. MSG_KEXDH_REPLY = 31
  1872. MSG_KEX_DH_GEX_REQUEST_OLD = 30
  1873. MSG_KEX_DH_GEX_REQUEST = 34
  1874. MSG_KEX_DH_GEX_GROUP = 31
  1875. MSG_KEX_DH_GEX_INIT = 32
  1876. MSG_KEX_DH_GEX_REPLY = 33
  1877. DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT = 1
  1878. DISCONNECT_PROTOCOL_ERROR = 2
  1879. DISCONNECT_KEY_EXCHANGE_FAILED = 3
  1880. DISCONNECT_RESERVED = 4
  1881. DISCONNECT_MAC_ERROR = 5
  1882. DISCONNECT_COMPRESSION_ERROR = 6
  1883. DISCONNECT_SERVICE_NOT_AVAILABLE = 7
  1884. DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED = 8
  1885. DISCONNECT_HOST_KEY_NOT_VERIFIABLE = 9
  1886. DISCONNECT_CONNECTION_LOST = 10
  1887. DISCONNECT_BY_APPLICATION = 11
  1888. DISCONNECT_TOO_MANY_CONNECTIONS = 12
  1889. DISCONNECT_AUTH_CANCELLED_BY_USER = 13
  1890. DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 14
  1891. DISCONNECT_ILLEGAL_USER_NAME = 15
  1892. messages = {}
  1893. for name, value in list(globals().items()):
  1894. # Avoid legacy messages which overlap with never ones
  1895. if name.startswith("MSG_") and not name.startswith("MSG_KEXDH_"):
  1896. messages[value] = name
  1897. # Check for regressions (#5352)
  1898. if "MSG_KEXDH_INIT" in messages or "MSG_KEXDH_REPLY" in messages:
  1899. raise RuntimeError("legacy SSH mnemonics should not end up in messages dict")