1
0

transport.go 9.5 KB

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