transport.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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. "bytes"
  8. "errors"
  9. "io"
  10. "log"
  11. )
  12. // debugTransport if set, will print packet types as they go over the
  13. // wire. No message decoding is done, to minimize the impact on timing.
  14. const debugTransport = false
  15. const (
  16. gcm128CipherID = "aes128-gcm@openssh.com"
  17. gcm256CipherID = "aes256-gcm@openssh.com"
  18. aes128cbcID = "aes128-cbc"
  19. tripledescbcID = "3des-cbc"
  20. )
  21. // packetConn represents a transport that implements packet based
  22. // operations.
  23. type packetConn interface {
  24. // Encrypt and send a packet of data to the remote peer.
  25. writePacket(packet []byte) error
  26. // Read a packet from the connection. The read is blocking,
  27. // i.e. if error is nil, then the returned byte slice is
  28. // always non-empty.
  29. readPacket() ([]byte, error)
  30. // Close closes the write-side of the connection.
  31. Close() error
  32. }
  33. // transport is the keyingTransport that implements the SSH packet
  34. // protocol.
  35. type transport struct {
  36. reader connectionState
  37. writer connectionState
  38. bufReader *bufio.Reader
  39. bufWriter *bufio.Writer
  40. rand io.Reader
  41. isClient bool
  42. io.Closer
  43. }
  44. // packetCipher represents a combination of SSH encryption/MAC
  45. // protocol. A single instance should be used for one direction only.
  46. type packetCipher interface {
  47. // writeCipherPacket encrypts the packet and writes it to w. The
  48. // contents of the packet are generally scrambled.
  49. writeCipherPacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error
  50. // readCipherPacket reads and decrypts a packet of data. The
  51. // returned packet may be overwritten by future calls of
  52. // readPacket.
  53. readCipherPacket(seqnum uint32, r io.Reader) ([]byte, error)
  54. }
  55. // connectionState represents one side (read or write) of the
  56. // connection. This is necessary because each direction has its own
  57. // keys, and can even have its own algorithms
  58. type connectionState struct {
  59. packetCipher
  60. seqNum uint32
  61. dir direction
  62. pendingKeyChange chan packetCipher
  63. }
  64. // prepareKeyChange sets up key material for a keychange. The key changes in
  65. // both directions are triggered by reading and writing a msgNewKey packet
  66. // respectively.
  67. func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) error {
  68. ciph, err := newPacketCipher(t.reader.dir, algs.r, kexResult)
  69. if err != nil {
  70. return err
  71. }
  72. t.reader.pendingKeyChange <- ciph
  73. ciph, err = newPacketCipher(t.writer.dir, algs.w, kexResult)
  74. if err != nil {
  75. return err
  76. }
  77. t.writer.pendingKeyChange <- ciph
  78. return nil
  79. }
  80. func (t *transport) printPacket(p []byte, write bool) {
  81. if len(p) == 0 {
  82. return
  83. }
  84. who := "server"
  85. if t.isClient {
  86. who = "client"
  87. }
  88. what := "read"
  89. if write {
  90. what = "write"
  91. }
  92. log.Println(what, who, p[0])
  93. }
  94. // Read and decrypt next packet.
  95. func (t *transport) readPacket() (p []byte, err error) {
  96. for {
  97. p, err = t.reader.readPacket(t.bufReader)
  98. if err != nil {
  99. break
  100. }
  101. if len(p) == 0 || (p[0] != msgIgnore && p[0] != msgDebug) {
  102. break
  103. }
  104. }
  105. if debugTransport {
  106. t.printPacket(p, false)
  107. }
  108. return p, err
  109. }
  110. func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) {
  111. packet, err := s.packetCipher.readCipherPacket(s.seqNum, r)
  112. s.seqNum++
  113. if err == nil && len(packet) == 0 {
  114. err = errors.New("ssh: zero length packet")
  115. }
  116. if len(packet) > 0 {
  117. switch packet[0] {
  118. case msgNewKeys:
  119. select {
  120. case cipher := <-s.pendingKeyChange:
  121. s.packetCipher = cipher
  122. default:
  123. return nil, errors.New("ssh: got bogus newkeys message")
  124. }
  125. case msgDisconnect:
  126. // Transform a disconnect message into an
  127. // error. Since this is lowest level at which
  128. // we interpret message types, doing it here
  129. // ensures that we don't have to handle it
  130. // elsewhere.
  131. var msg disconnectMsg
  132. if err := Unmarshal(packet, &msg); err != nil {
  133. return nil, err
  134. }
  135. return nil, &msg
  136. }
  137. }
  138. // The packet may point to an internal buffer, so copy the
  139. // packet out here.
  140. fresh := make([]byte, len(packet))
  141. copy(fresh, packet)
  142. return fresh, err
  143. }
  144. func (t *transport) writePacket(packet []byte) error {
  145. if debugTransport {
  146. t.printPacket(packet, true)
  147. }
  148. return t.writer.writePacket(t.bufWriter, t.rand, packet)
  149. }
  150. func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error {
  151. changeKeys := len(packet) > 0 && packet[0] == msgNewKeys
  152. err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet)
  153. if err != nil {
  154. return err
  155. }
  156. if err = w.Flush(); err != nil {
  157. return err
  158. }
  159. s.seqNum++
  160. if changeKeys {
  161. select {
  162. case cipher := <-s.pendingKeyChange:
  163. s.packetCipher = cipher
  164. default:
  165. panic("ssh: no key material for msgNewKeys")
  166. }
  167. }
  168. return err
  169. }
  170. func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transport {
  171. t := &transport{
  172. bufReader: bufio.NewReader(rwc),
  173. bufWriter: bufio.NewWriter(rwc),
  174. rand: rand,
  175. reader: connectionState{
  176. packetCipher: &streamPacketCipher{cipher: noneCipher{}},
  177. pendingKeyChange: make(chan packetCipher, 1),
  178. },
  179. writer: connectionState{
  180. packetCipher: &streamPacketCipher{cipher: noneCipher{}},
  181. pendingKeyChange: make(chan packetCipher, 1),
  182. },
  183. Closer: rwc,
  184. }
  185. t.isClient = isClient
  186. if isClient {
  187. t.reader.dir = serverKeys
  188. t.writer.dir = clientKeys
  189. } else {
  190. t.reader.dir = clientKeys
  191. t.writer.dir = serverKeys
  192. }
  193. return t
  194. }
  195. type direction struct {
  196. ivTag []byte
  197. keyTag []byte
  198. macKeyTag []byte
  199. }
  200. var (
  201. serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}}
  202. clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}}
  203. )
  204. // setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as
  205. // described in RFC 4253, section 6.4. direction should either be serverKeys
  206. // (to setup server->client keys) or clientKeys (for client->server keys).
  207. func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) {
  208. cipherMode := cipherModes[algs.Cipher]
  209. iv := make([]byte, cipherMode.ivSize)
  210. key := make([]byte, cipherMode.keySize)
  211. generateKeyMaterial(iv, d.ivTag, kex)
  212. generateKeyMaterial(key, d.keyTag, kex)
  213. var macKey []byte
  214. if !aeadCiphers[algs.Cipher] {
  215. macMode := macModes[algs.MAC]
  216. macKey = make([]byte, macMode.keySize)
  217. generateKeyMaterial(macKey, d.macKeyTag, kex)
  218. }
  219. return cipherModes[algs.Cipher].create(key, iv, macKey, algs)
  220. }
  221. // generateKeyMaterial fills out with key material generated from tag, K, H
  222. // and sessionId, as specified in RFC 4253, section 7.2.
  223. func generateKeyMaterial(out, tag []byte, r *kexResult) {
  224. var digestsSoFar []byte
  225. h := r.Hash.New()
  226. for len(out) > 0 {
  227. h.Reset()
  228. h.Write(r.K)
  229. h.Write(r.H)
  230. if len(digestsSoFar) == 0 {
  231. h.Write(tag)
  232. h.Write(r.SessionID)
  233. } else {
  234. h.Write(digestsSoFar)
  235. }
  236. digest := h.Sum(nil)
  237. n := copy(out, digest)
  238. out = out[n:]
  239. if len(out) > 0 {
  240. digestsSoFar = append(digestsSoFar, digest...)
  241. }
  242. }
  243. }
  244. const packageVersion = "SSH-2.0-Go"
  245. // Sends and receives a version line. The versionLine string should
  246. // be US ASCII, start with "SSH-2.0-", and should not include a
  247. // newline. exchangeVersions returns the other side's version line.
  248. func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err error) {
  249. // Contrary to the RFC, we do not ignore lines that don't
  250. // start with "SSH-2.0-" to make the library usable with
  251. // nonconforming servers.
  252. for _, c := range versionLine {
  253. // The spec disallows non US-ASCII chars, and
  254. // specifically forbids null chars.
  255. if c < 32 {
  256. return nil, errors.New("ssh: junk character in version line")
  257. }
  258. }
  259. if _, err = rw.Write(append(versionLine, '\r', '\n')); err != nil {
  260. return
  261. }
  262. them, err = readVersion(rw)
  263. return them, err
  264. }
  265. // maxVersionStringBytes is the maximum number of bytes that we'll
  266. // accept as a version string. RFC 4253 section 4.2 limits this at 255
  267. // chars
  268. const maxVersionStringBytes = 255
  269. // Read version string as specified by RFC 4253, section 4.2.
  270. func readVersion(r io.Reader) ([]byte, error) {
  271. versionString := make([]byte, 0, 64)
  272. var ok bool
  273. var buf [1]byte
  274. for length := 0; length < maxVersionStringBytes; length++ {
  275. _, err := io.ReadFull(r, buf[:])
  276. if err != nil {
  277. return nil, err
  278. }
  279. // The RFC says that the version should be terminated with \r\n
  280. // but several SSH servers actually only send a \n.
  281. if buf[0] == '\n' {
  282. if !bytes.HasPrefix(versionString, []byte("SSH-")) {
  283. // RFC 4253 says we need to ignore all version string lines
  284. // except the one containing the SSH version (provided that
  285. // all the lines do not exceed 255 bytes in total).
  286. versionString = versionString[:0]
  287. continue
  288. }
  289. ok = true
  290. break
  291. }
  292. // non ASCII chars are disallowed, but we are lenient,
  293. // since Go doesn't use null-terminated strings.
  294. // The RFC allows a comment after a space, however,
  295. // all of it (version and comments) goes into the
  296. // session hash.
  297. versionString = append(versionString, buf[0])
  298. }
  299. if !ok {
  300. return nil, errors.New("ssh: overflow reading version string")
  301. }
  302. // There might be a '\r' on the end which we should remove.
  303. if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' {
  304. versionString = versionString[:len(versionString)-1]
  305. }
  306. return versionString, nil
  307. }