transport.go 8.9 KB

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