transport.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package ssh
  5. import (
  6. "bufio"
  7. "crypto/cipher"
  8. "crypto/subtle"
  9. "encoding/binary"
  10. "errors"
  11. "hash"
  12. "io"
  13. "net"
  14. "sync"
  15. )
  16. const (
  17. packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher.
  18. // RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations
  19. // MUST be able to process (plus a few more kilobytes for padding and mac). The RFC
  20. // indicates implementations SHOULD be able to handle larger packet sizes, but then
  21. // waffles on about reasonable limits.
  22. //
  23. // OpenSSH caps their maxPacket at 256kb so we choose to do the same.
  24. maxPacket = 256 * 1024
  25. )
  26. // packetConn represents a transport that implements packet based
  27. // operations.
  28. type packetConn interface {
  29. // Encrypt and send a packet of data to the remote peer.
  30. writePacket(packet []byte) error
  31. // Read a packet from the connection
  32. readPacket() ([]byte, error)
  33. // Close closes the write-side of the connection.
  34. Close() error
  35. }
  36. // transport represents the SSH connection to the remote peer.
  37. type transport struct {
  38. reader
  39. writer
  40. net.Conn
  41. // Initial H used for the session ID. Once assigned this does
  42. // not change, even during subsequent key exchanges.
  43. sessionID []byte
  44. }
  45. // reader represents the incoming connection state.
  46. type reader struct {
  47. io.Reader
  48. common
  49. }
  50. // writer represents the outgoing connection state.
  51. type writer struct {
  52. sync.Mutex // protects writer.Writer from concurrent writes
  53. *bufio.Writer
  54. rand io.Reader
  55. common
  56. }
  57. // prepareKeyChange sets up key material for a keychange. The key changes in
  58. // both directions are triggered by reading and writing a msgNewKey packet
  59. // respectively.
  60. func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) error {
  61. t.writer.cipherAlgo = algs.wCipher
  62. t.writer.macAlgo = algs.wMAC
  63. t.writer.compressionAlgo = algs.wCompression
  64. t.reader.cipherAlgo = algs.rCipher
  65. t.reader.macAlgo = algs.rMAC
  66. t.reader.compressionAlgo = algs.rCompression
  67. if t.sessionID == nil {
  68. t.sessionID = kexResult.H
  69. }
  70. kexResult.SessionID = t.sessionID
  71. t.reader.pendingKeyChange <- kexResult
  72. t.writer.pendingKeyChange <- kexResult
  73. return nil
  74. }
  75. // common represents the cipher state needed to process messages in a single
  76. // direction.
  77. type common struct {
  78. seqNum uint32
  79. mac hash.Hash
  80. cipher cipher.Stream
  81. cipherAlgo string
  82. macAlgo string
  83. compressionAlgo string
  84. dir direction
  85. pendingKeyChange chan *kexResult
  86. }
  87. // Read and decrypt a single packet from the remote peer.
  88. func (r *reader) readPacket() ([]byte, error) {
  89. var lengthBytes = make([]byte, 5)
  90. var macSize uint32
  91. if _, err := io.ReadFull(r, lengthBytes); err != nil {
  92. return nil, err
  93. }
  94. r.cipher.XORKeyStream(lengthBytes, lengthBytes)
  95. if r.mac != nil {
  96. r.mac.Reset()
  97. seqNumBytes := []byte{
  98. byte(r.seqNum >> 24),
  99. byte(r.seqNum >> 16),
  100. byte(r.seqNum >> 8),
  101. byte(r.seqNum),
  102. }
  103. r.mac.Write(seqNumBytes)
  104. r.mac.Write(lengthBytes)
  105. macSize = uint32(r.mac.Size())
  106. }
  107. length := binary.BigEndian.Uint32(lengthBytes[0:4])
  108. paddingLength := uint32(lengthBytes[4])
  109. if length <= paddingLength+1 {
  110. return nil, errors.New("ssh: invalid packet length, packet too small")
  111. }
  112. if length > maxPacket {
  113. return nil, errors.New("ssh: invalid packet length, packet too large")
  114. }
  115. packet := make([]byte, length-1+macSize)
  116. if _, err := io.ReadFull(r, packet); err != nil {
  117. return nil, err
  118. }
  119. mac := packet[length-1:]
  120. r.cipher.XORKeyStream(packet, packet[:length-1])
  121. if r.mac != nil {
  122. r.mac.Write(packet[:length-1])
  123. if subtle.ConstantTimeCompare(r.mac.Sum(nil), mac) != 1 {
  124. return nil, errors.New("ssh: MAC failure")
  125. }
  126. }
  127. r.seqNum++
  128. packet = packet[:length-paddingLength-1]
  129. if len(packet) > 0 && packet[0] == msgNewKeys {
  130. select {
  131. case k := <-r.pendingKeyChange:
  132. if err := r.setupKeys(r.dir, k); err != nil {
  133. return nil, err
  134. }
  135. default:
  136. return nil, errors.New("ssh: got bogus newkeys message.")
  137. }
  138. }
  139. return packet, nil
  140. }
  141. // Read and decrypt next packet discarding debug and noop messages.
  142. func (t *transport) readPacket() ([]byte, error) {
  143. for {
  144. packet, err := t.reader.readPacket()
  145. if err != nil {
  146. return nil, err
  147. }
  148. if len(packet) == 0 {
  149. return nil, errors.New("ssh: zero length packet")
  150. }
  151. if packet[0] != msgIgnore && packet[0] != msgDebug {
  152. return packet, nil
  153. }
  154. }
  155. panic("unreachable")
  156. }
  157. // Encrypt and send a packet of data to the remote peer.
  158. func (w *writer) writePacket(packet []byte) error {
  159. changeKeys := len(packet) > 0 && packet[0] == msgNewKeys
  160. if len(packet) > maxPacket {
  161. return errors.New("ssh: packet too large")
  162. }
  163. w.Mutex.Lock()
  164. defer w.Mutex.Unlock()
  165. paddingLength := packetSizeMultiple - (5+len(packet))%packetSizeMultiple
  166. if paddingLength < 4 {
  167. paddingLength += packetSizeMultiple
  168. }
  169. length := len(packet) + 1 + paddingLength
  170. lengthBytes := []byte{
  171. byte(length >> 24),
  172. byte(length >> 16),
  173. byte(length >> 8),
  174. byte(length),
  175. byte(paddingLength),
  176. }
  177. padding := make([]byte, paddingLength)
  178. _, err := io.ReadFull(w.rand, padding)
  179. if err != nil {
  180. return err
  181. }
  182. if w.mac != nil {
  183. w.mac.Reset()
  184. seqNumBytes := []byte{
  185. byte(w.seqNum >> 24),
  186. byte(w.seqNum >> 16),
  187. byte(w.seqNum >> 8),
  188. byte(w.seqNum),
  189. }
  190. w.mac.Write(seqNumBytes)
  191. w.mac.Write(lengthBytes)
  192. w.mac.Write(packet)
  193. w.mac.Write(padding)
  194. }
  195. // TODO(dfc) lengthBytes, packet and padding should be
  196. // subslices of a single buffer
  197. w.cipher.XORKeyStream(lengthBytes, lengthBytes)
  198. w.cipher.XORKeyStream(packet, packet)
  199. w.cipher.XORKeyStream(padding, padding)
  200. if _, err := w.Write(lengthBytes); err != nil {
  201. return err
  202. }
  203. if _, err := w.Write(packet); err != nil {
  204. return err
  205. }
  206. if _, err := w.Write(padding); err != nil {
  207. return err
  208. }
  209. if w.mac != nil {
  210. if _, err := w.Write(w.mac.Sum(nil)); err != nil {
  211. return err
  212. }
  213. }
  214. w.seqNum++
  215. if err = w.Flush(); err != nil {
  216. return err
  217. }
  218. if changeKeys {
  219. select {
  220. case k := <-w.pendingKeyChange:
  221. err = w.setupKeys(w.dir, k)
  222. default:
  223. panic("ssh: no key material for msgNewKeys")
  224. }
  225. }
  226. return err
  227. }
  228. func newTransport(conn net.Conn, rand io.Reader, isClient bool) *transport {
  229. t := &transport{
  230. reader: reader{
  231. Reader: bufio.NewReader(conn),
  232. common: common{
  233. cipher: noneCipher{},
  234. pendingKeyChange: make(chan *kexResult, 1),
  235. },
  236. },
  237. writer: writer{
  238. Writer: bufio.NewWriter(conn),
  239. rand: rand,
  240. common: common{
  241. cipher: noneCipher{},
  242. pendingKeyChange: make(chan *kexResult, 1),
  243. },
  244. },
  245. Conn: conn,
  246. }
  247. if isClient {
  248. t.reader.dir = serverKeys
  249. t.writer.dir = clientKeys
  250. } else {
  251. t.reader.dir = clientKeys
  252. t.writer.dir = serverKeys
  253. }
  254. return t
  255. }
  256. type direction struct {
  257. ivTag []byte
  258. keyTag []byte
  259. macKeyTag []byte
  260. }
  261. // TODO(dfc) can this be made a constant ?
  262. var (
  263. serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}}
  264. clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}}
  265. )
  266. // setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as
  267. // described in RFC 4253, section 6.4. direction should either be serverKeys
  268. // (to setup server->client keys) or clientKeys (for client->server keys).
  269. func (c *common) setupKeys(d direction, r *kexResult) error {
  270. cipherMode := cipherModes[c.cipherAlgo]
  271. macMode := macModes[c.macAlgo]
  272. iv := make([]byte, cipherMode.ivSize)
  273. key := make([]byte, cipherMode.keySize)
  274. macKey := make([]byte, macMode.keySize)
  275. h := r.Hash.New()
  276. generateKeyMaterial(iv, d.ivTag, r.K, r.H, r.SessionID, h)
  277. generateKeyMaterial(key, d.keyTag, r.K, r.H, r.SessionID, h)
  278. generateKeyMaterial(macKey, d.macKeyTag, r.K, r.H, r.SessionID, h)
  279. c.mac = macMode.new(macKey)
  280. var err error
  281. c.cipher, err = cipherMode.createCipher(key, iv)
  282. return err
  283. }
  284. // generateKeyMaterial fills out with key material generated from tag, K, H
  285. // and sessionId, as specified in RFC 4253, section 7.2.
  286. func generateKeyMaterial(out, tag []byte, K, H, sessionId []byte, h hash.Hash) {
  287. var digestsSoFar []byte
  288. for len(out) > 0 {
  289. h.Reset()
  290. h.Write(K)
  291. h.Write(H)
  292. if len(digestsSoFar) == 0 {
  293. h.Write(tag)
  294. h.Write(sessionId)
  295. } else {
  296. h.Write(digestsSoFar)
  297. }
  298. digest := h.Sum(nil)
  299. n := copy(out, digest)
  300. out = out[n:]
  301. if len(out) > 0 {
  302. digestsSoFar = append(digestsSoFar, digest...)
  303. }
  304. }
  305. }
  306. const packageVersion = "SSH-2.0-Go"
  307. // Sends and receives a version line. The versionLine string should
  308. // be US ASCII, start with "SSH-2.0-", and should not include a
  309. // newline. exchangeVersions returns the other side's version line.
  310. func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err error) {
  311. // Contrary to the RFC, we do not ignore lines that don't
  312. // start with "SSH-2.0-" to make the library usable with
  313. // nonconforming servers.
  314. for _, c := range versionLine {
  315. // The spec disallows non US-ASCII chars, and
  316. // specifically forbids null chars.
  317. if c < 32 {
  318. return nil, errors.New("ssh: junk character in version line")
  319. }
  320. }
  321. if _, err = rw.Write(append(versionLine, '\r', '\n')); err != nil {
  322. return
  323. }
  324. them, err = readVersion(rw)
  325. return them, err
  326. }
  327. // maxVersionStringBytes is the maximum number of bytes that we'll
  328. // accept as a version string. RFC 4253 section 4.2 limits this at 255
  329. // chars
  330. const maxVersionStringBytes = 255
  331. // Read version string as specified by RFC 4253, section 4.2.
  332. func readVersion(r io.Reader) ([]byte, error) {
  333. versionString := make([]byte, 0, 64)
  334. var ok bool
  335. var buf [1]byte
  336. for len(versionString) < maxVersionStringBytes {
  337. _, err := io.ReadFull(r, buf[:])
  338. if err != nil {
  339. return nil, err
  340. }
  341. // The RFC says that the version should be terminated with \r\n
  342. // but several SSH servers actually only send a \n.
  343. if buf[0] == '\n' {
  344. ok = true
  345. break
  346. }
  347. // non ASCII chars are disallowed, but we are lenient,
  348. // since Go doesn't use null-terminated strings.
  349. // The RFC allows a comment after a space, however,
  350. // all of it (version and comments) goes into the
  351. // session hash.
  352. versionString = append(versionString, buf[0])
  353. }
  354. if !ok {
  355. return nil, errors.New("ssh: overflow reading version string")
  356. }
  357. // There might be a '\r' on the end which we should remove.
  358. if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' {
  359. versionString = versionString[:len(versionString)-1]
  360. }
  361. return versionString, nil
  362. }