PageRenderTime 39ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/transport.go

https://bitbucket.org/taruti/ssh.go/
Go | 236 lines | 194 code | 39 blank | 3 comment | 33 complexity | 752ce92252379ca8bf7e3ce5fc8cced0 MD5 | raw file
  1. package ssh
  2. import (
  3. "bitbucket.org/taruti/bigendian"
  4. "bufio"
  5. "bytes"
  6. "crypto/cipher"
  7. "hash"
  8. "io"
  9. "net"
  10. "os"
  11. )
  12. type ssh struct {
  13. c net.Conn
  14. r *bufio.Reader
  15. rc cipher.BlockMode
  16. wc cipher.BlockMode
  17. rh hash.Hash
  18. wh hash.Hash
  19. rseq, wseq uint32
  20. rident string
  21. ckex, skex []byte
  22. session_id []byte
  23. }
  24. func connect(host string) (*ssh,os.Error) {
  25. c,err := net.Dial("tcp", host+":22")
  26. if err!=nil {
  27. return nil,err
  28. }
  29. _,err = c.Write([]byte(ident+"\r\n"))
  30. if err!=nil {
  31. return nil,err
  32. }
  33. r := bufio.NewReader(c)
  34. var line []byte
  35. var prefix bool
  36. for {
  37. line, prefix, err = r.ReadLine()
  38. if err!=nil {
  39. return nil,err
  40. }
  41. if prefix {
  42. return nil,os.NewError("Too long identification line")
  43. }
  44. Log(1,"%s",line)
  45. if bytes.HasPrefix(line, []byte("SSH-2.0-")) {
  46. break
  47. }
  48. if bytes.HasPrefix(line, []byte("SSH-")) {
  49. return nil,os.NewError("Unsupported ssh version")
  50. }
  51. }
  52. return &ssh{c, r, NullCrypto{}, NullCrypto{}, NullHash{}, NullHash{}, 0, 0, string(line), nil, nil, nil}, nil
  53. }
  54. func readPacket(c *ssh) ([]byte, os.Error) {
  55. l := c.rc.BlockSize()
  56. if l < 16 {
  57. l = 16
  58. }
  59. // read packet header
  60. b := make([]byte, l)
  61. _, err := io.ReadFull(c.r, b)
  62. if err!=nil {
  63. return nil,err
  64. }
  65. Log(9,"WIRE = %X",b)
  66. // decrypt header
  67. c.rc.CryptBlocks(b,b)
  68. Log(9,"DEC = %X",b)
  69. lfield := int(bigendian.U32(b))
  70. lpadding := int(b[4])
  71. // FIXME add checks here to validate packet
  72. lhash := c.rh.Size()
  73. lrest := 4 + lfield + lhash - len(b)
  74. if lrest > 12*1024*1024 || lfield<0 {
  75. Log(0, "lfield %d lrest %d", lfield, lrest)
  76. return nil, os.NewError("too large packet")
  77. }
  78. packet := make([]byte, len(b)+lrest)
  79. copy(packet, b)
  80. rest := packet[len(b):]
  81. _,err = io.ReadFull(c.r,rest)
  82. if err!=nil {
  83. return nil,err
  84. }
  85. c.rc.CryptBlocks(rest[0:lrest-lhash], rest[0:lrest-lhash])
  86. var rseqb [4]byte
  87. bigendian.PutU32(rseqb[:], c.rseq)
  88. c.rseq++
  89. c.rh.Reset()
  90. c.rh.Write(rseqb[:])
  91. c.rh.Write(packet[0:len(packet)-lhash])
  92. if !constEq(c.rh.Sum(), packet[len(packet)-lhash:]) {
  93. return nil,os.NewError("Invalid mac")
  94. }
  95. return packet[5:4+lfield-lpadding],nil
  96. }
  97. func writePacket(c *ssh, fun func(*bigendian.Printer)) {
  98. p := bigendian.NewPrinterWith(make([]byte, 5, 32))
  99. fun(p)
  100. b := p.Out()
  101. bs := c.wc.BlockSize()
  102. if bs < 16 {
  103. bs = 16
  104. }
  105. padding := bs - (len(b) % bs)
  106. if padding < 4 {
  107. padding += bs
  108. }
  109. b[4] = byte(padding)
  110. b = append(b, rand(padding)...)
  111. bigendian.PutU32(b, uint32(len(b)-4))
  112. var wseqb [4]byte
  113. bigendian.PutU32(wseqb[:], c.wseq)
  114. c.wseq++
  115. c.wh.Reset()
  116. c.wh.Write(wseqb[:])
  117. c.wh.Write(b)
  118. c.wc.CryptBlocks(b,b)
  119. b = append(b, c.wh.Sum()...)
  120. c.c.Write(b)
  121. }
  122. func writeKexInit(c *ssh) {
  123. p := bigendian.NewPrinter()
  124. p.Byte(msgKexInit).Bytes(rand(16))
  125. p.U32String(kexKex).U32String(kexShk)
  126. p.U32String(kexEnc).U32String(kexEnc)
  127. p.U32String(kexMac).U32String(kexMac)
  128. p.U32String(kexCom).U32String(kexCom)
  129. p.U32String(kexLan).U32String(kexLan)
  130. p.Byte(0).U32(0)
  131. c.ckex = p.Out()
  132. writePacket(c, func(p *bigendian.Printer) { p.Bytes(c.ckex) })
  133. }
  134. type kexres struct {
  135. Kex, Shk, EncCS, EncSC, MacCS, MacSC, ComCS, ComSC string
  136. }
  137. func parseKexInit(c *ssh, b []byte) (*kexres,os.Error) {
  138. var cookie []byte
  139. var kex, shk, ecs, esc, mcs, msc, ccs, csc, lcs, lsc string
  140. var follows byte
  141. var reserved uint32
  142. p := bigendian.NewParser(b).NBytes(16, &cookie)
  143. p.U32String(&kex).U32String(&shk)
  144. p.U32String(&ecs).U32String(&esc)
  145. p.U32String(&mcs).U32String(&msc)
  146. p.U32String(&ccs).U32String(&csc)
  147. p.U32String(&lcs).U32String(&lsc)
  148. p.Byte(&follows).U32(&reserved).End()
  149. guessed := true
  150. var r kexres
  151. var g bool
  152. var err os.Error
  153. r.Kex,g,err = namelistCheck(kexKex, kex)
  154. if err!=nil {
  155. return nil,err
  156. }
  157. guessed = g && guessed
  158. r.Shk,g,err = namelistCheck(kexShk, shk)
  159. if err!=nil {
  160. return nil,err
  161. }
  162. guessed = g && guessed
  163. r.EncCS,g,err = namelistCheck(kexEnc, ecs)
  164. if err!=nil {
  165. return nil,err
  166. }
  167. guessed = g && guessed
  168. r.EncSC,g,err = namelistCheck(kexEnc, esc)
  169. if err!=nil {
  170. return nil,err
  171. }
  172. guessed = g && guessed
  173. r.MacCS,g,err = namelistCheck(kexMac, mcs)
  174. if err!=nil {
  175. return nil,err
  176. }
  177. guessed = g && guessed
  178. r.MacSC,g,err = namelistCheck(kexMac, msc)
  179. if err!=nil {
  180. return nil,err
  181. }
  182. guessed = g && guessed
  183. r.ComCS,g,err = namelistCheck(kexCom, ccs)
  184. if err!=nil {
  185. return nil,err
  186. }
  187. guessed = g && guessed
  188. r.ComSC,g,err = namelistCheck(kexCom, csc)
  189. if err!=nil {
  190. return nil,err
  191. }
  192. guessed = g && guessed
  193. if guessed==false && follows>0 {
  194. readPacket(c)
  195. }
  196. return &r, nil
  197. }