transport.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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. )
  14. // packetConn represents a transport that implements packet based
  15. // operations.
  16. type packetConn interface {
  17. // Encrypt and send a packet of data to the remote peer.
  18. writePacket(packet []byte) error
  19. // Read a packet from the connection
  20. readPacket() ([]byte, error)
  21. // Close closes the write-side of the connection.
  22. Close() error
  23. }
  24. // transport is the keyingTransport that implements the SSH packet
  25. // protocol.
  26. type transport struct {
  27. reader connectionState
  28. writer connectionState
  29. bufReader *bufio.Reader
  30. bufWriter *bufio.Writer
  31. rand io.Reader
  32. io.Closer
  33. // Initial H used for the session ID. Once assigned this does
  34. // not change, even during subsequent key exchanges.
  35. sessionID []byte
  36. }
  37. // getSessionID returns the ID of the SSH connection. The return value
  38. // should not be modified.
  39. func (t *transport) getSessionID() []byte {
  40. if t.sessionID == nil {
  41. panic("session ID not set yet")
  42. }
  43. return t.sessionID
  44. }
  45. // packetCipher represents a combination of SSH encryption/MAC
  46. // protocol. A single instance should be used for one direction only.
  47. type packetCipher interface {
  48. // writePacket encrypts the packet and writes it to w. The
  49. // contents of the packet are generally scrambled.
  50. writePacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error
  51. // readPacket reads and decrypts a packet of data. The
  52. // returned packet may be overwritten by future calls of
  53. // readPacket.
  54. readPacket(seqnum uint32, r io.Reader) ([]byte, error)
  55. }
  56. // connectionState represents one side (read or write) of the
  57. // connection. This is necessary because each direction has its own
  58. // keys, and can even have its own algorithms
  59. type connectionState struct {
  60. packetCipher
  61. seqNum uint32
  62. dir direction
  63. pendingKeyChange chan packetCipher
  64. }
  65. // prepareKeyChange sets up key material for a keychange. The key changes in
  66. // both directions are triggered by reading and writing a msgNewKey packet
  67. // respectively.
  68. func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) error {
  69. if t.sessionID == nil {
  70. t.sessionID = kexResult.H
  71. }
  72. kexResult.SessionID = t.sessionID
  73. if ciph, err := newPacketCipher(t.reader.dir, algs.r, kexResult); err != nil {
  74. return err
  75. } else {
  76. t.reader.pendingKeyChange <- ciph
  77. }
  78. if ciph, err := newPacketCipher(t.writer.dir, algs.w, kexResult); err != nil {
  79. return err
  80. } else {
  81. t.writer.pendingKeyChange <- ciph
  82. }
  83. return nil
  84. }
  85. // Read and decrypt next packet.
  86. func (t *transport) readPacket() ([]byte, error) {
  87. return t.reader.readPacket(t.bufReader)
  88. }
  89. func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) {
  90. packet, err := s.packetCipher.readPacket(s.seqNum, r)
  91. s.seqNum++
  92. if err == nil && len(packet) == 0 {
  93. err = errors.New("ssh: zero length packet")
  94. }
  95. if len(packet) > 0 {
  96. switch packet[0] {
  97. case msgNewKeys:
  98. select {
  99. case cipher := <-s.pendingKeyChange:
  100. s.packetCipher = cipher
  101. default:
  102. return nil, errors.New("ssh: got bogus newkeys message.")
  103. }
  104. case msgDisconnect:
  105. // Transform a disconnect message into an
  106. // error. Since this is lowest level at which
  107. // we interpret message types, doing it here
  108. // ensures that we don't have to handle it
  109. // elsewhere.
  110. var msg disconnectMsg
  111. if err := Unmarshal(packet, &msg); err != nil {
  112. return nil, err
  113. }
  114. return nil, &msg
  115. }
  116. }
  117. // The packet may point to an internal buffer, so copy the
  118. // packet out here.
  119. fresh := make([]byte, len(packet))
  120. copy(fresh, packet)
  121. return fresh, err
  122. }
  123. func (t *transport) writePacket(packet []byte) error {
  124. return t.writer.writePacket(t.bufWriter, t.rand, packet)
  125. }
  126. func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error {
  127. changeKeys := len(packet) > 0 && packet[0] == msgNewKeys
  128. err := s.packetCipher.writePacket(s.seqNum, w, rand, packet)
  129. if err != nil {
  130. return err
  131. }
  132. if err = w.Flush(); err != nil {
  133. return err
  134. }
  135. s.seqNum++
  136. if changeKeys {
  137. select {
  138. case cipher := <-s.pendingKeyChange:
  139. s.packetCipher = cipher
  140. default:
  141. panic("ssh: no key material for msgNewKeys")
  142. }
  143. }
  144. return err
  145. }
  146. func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transport {
  147. t := &transport{
  148. bufReader: bufio.NewReader(rwc),
  149. bufWriter: bufio.NewWriter(rwc),
  150. rand: rand,
  151. reader: connectionState{
  152. packetCipher: &streamPacketCipher{cipher: noneCipher{}},
  153. pendingKeyChange: make(chan packetCipher, 1),
  154. },
  155. writer: connectionState{
  156. packetCipher: &streamPacketCipher{cipher: noneCipher{}},
  157. pendingKeyChange: make(chan packetCipher, 1),
  158. },
  159. Closer: rwc,
  160. }
  161. if isClient {
  162. t.reader.dir = serverKeys
  163. t.writer.dir = clientKeys
  164. } else {
  165. t.reader.dir = clientKeys
  166. t.writer.dir = serverKeys
  167. }
  168. return t
  169. }
  170. type direction struct {
  171. ivTag []byte
  172. keyTag []byte
  173. macKeyTag []byte
  174. }
  175. var (
  176. serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}}
  177. clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}}
  178. )
  179. // generateKeys generates key material for IV, MAC and encryption.
  180. func generateKeys(d direction, algs directionAlgorithms, kex *kexResult) (iv, key, macKey []byte) {
  181. cipherMode := cipherModes[algs.Cipher]
  182. macMode := macModes[algs.MAC]
  183. iv = make([]byte, cipherMode.ivSize)
  184. key = make([]byte, cipherMode.keySize)
  185. macKey = make([]byte, macMode.keySize)
  186. generateKeyMaterial(iv, d.ivTag, kex)
  187. generateKeyMaterial(key, d.keyTag, kex)
  188. generateKeyMaterial(macKey, d.macKeyTag, kex)
  189. return
  190. }
  191. // setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as
  192. // described in RFC 4253, section 6.4. direction should either be serverKeys
  193. // (to setup server->client keys) or clientKeys (for client->server keys).
  194. func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) {
  195. iv, key, macKey := generateKeys(d, algs, kex)
  196. if algs.Cipher == gcmCipherID {
  197. return newGCMCipher(iv, key, macKey)
  198. }
  199. if algs.Cipher == aes128cbcID {
  200. return newAESCBCCipher(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. }