github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/code.google.com/p/go.crypto/ssh/transport.go (about) 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 5 package ssh 6 7 import ( 8 "bufio" 9 "crypto" 10 "crypto/cipher" 11 "crypto/hmac" 12 "crypto/sha1" 13 "crypto/subtle" 14 "errors" 15 "hash" 16 "io" 17 "net" 18 "sync" 19 ) 20 21 const ( 22 packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher. 23 minPacketSize = 16 24 maxPacketSize = 36000 25 minPaddingSize = 4 // TODO(huin) should this be configurable? 26 ) 27 28 // filteredConn reduces the set of methods exposed when embeddeding 29 // a net.Conn inside ssh.transport. 30 // TODO(dfc) suggestions for a better name will be warmly received. 31 type filteredConn interface { 32 // Close closes the connection. 33 Close() error 34 35 // LocalAddr returns the local network address. 36 LocalAddr() net.Addr 37 38 // RemoteAddr returns the remote network address. 39 RemoteAddr() net.Addr 40 } 41 42 // Types implementing packetWriter provide the ability to send packets to 43 // an SSH peer. 44 type packetWriter interface { 45 // Encrypt and send a packet of data to the remote peer. 46 writePacket(packet []byte) error 47 } 48 49 // transport represents the SSH connection to the remote peer. 50 type transport struct { 51 reader 52 writer 53 54 filteredConn 55 } 56 57 // reader represents the incoming connection state. 58 type reader struct { 59 io.Reader 60 common 61 } 62 63 // writer represnts the outgoing connection state. 64 type writer struct { 65 *sync.Mutex // protects writer.Writer from concurrent writes 66 *bufio.Writer 67 rand io.Reader 68 common 69 } 70 71 // common represents the cipher state needed to process messages in a single 72 // direction. 73 type common struct { 74 seqNum uint32 75 mac hash.Hash 76 cipher cipher.Stream 77 78 cipherAlgo string 79 macAlgo string 80 compressionAlgo string 81 } 82 83 // Read and decrypt a single packet from the remote peer. 84 func (r *reader) readOnePacket() ([]byte, error) { 85 var lengthBytes = make([]byte, 5) 86 var macSize uint32 87 if _, err := io.ReadFull(r, lengthBytes); err != nil { 88 return nil, err 89 } 90 91 r.cipher.XORKeyStream(lengthBytes, lengthBytes) 92 93 if r.mac != nil { 94 r.mac.Reset() 95 seqNumBytes := []byte{ 96 byte(r.seqNum >> 24), 97 byte(r.seqNum >> 16), 98 byte(r.seqNum >> 8), 99 byte(r.seqNum), 100 } 101 r.mac.Write(seqNumBytes) 102 r.mac.Write(lengthBytes) 103 macSize = uint32(r.mac.Size()) 104 } 105 106 length := uint32(lengthBytes[0])<<24 | uint32(lengthBytes[1])<<16 | uint32(lengthBytes[2])<<8 | uint32(lengthBytes[3]) 107 paddingLength := uint32(lengthBytes[4]) 108 109 if length <= paddingLength+1 { 110 return nil, errors.New("invalid packet length") 111 } 112 if length > maxPacketSize { 113 return nil, errors.New("packet too large") 114 } 115 116 packet := make([]byte, length-1+macSize) 117 if _, err := io.ReadFull(r, packet); err != nil { 118 return nil, err 119 } 120 mac := packet[length-1:] 121 r.cipher.XORKeyStream(packet, packet[:length-1]) 122 123 if r.mac != nil { 124 r.mac.Write(packet[:length-1]) 125 if subtle.ConstantTimeCompare(r.mac.Sum(nil), mac) != 1 { 126 return nil, errors.New("ssh: MAC failure") 127 } 128 } 129 130 r.seqNum++ 131 return packet[:length-paddingLength-1], nil 132 } 133 134 // Read and decrypt next packet discarding debug and noop messages. 135 func (t *transport) readPacket() ([]byte, error) { 136 for { 137 packet, err := t.readOnePacket() 138 if err != nil { 139 return nil, err 140 } 141 if packet[0] != msgIgnore && packet[0] != msgDebug { 142 return packet, nil 143 } 144 } 145 panic("unreachable") 146 } 147 148 // Encrypt and send a packet of data to the remote peer. 149 func (w *writer) writePacket(packet []byte) error { 150 w.Mutex.Lock() 151 defer w.Mutex.Unlock() 152 153 paddingLength := packetSizeMultiple - (5+len(packet))%packetSizeMultiple 154 if paddingLength < 4 { 155 paddingLength += packetSizeMultiple 156 } 157 158 length := len(packet) + 1 + paddingLength 159 lengthBytes := []byte{ 160 byte(length >> 24), 161 byte(length >> 16), 162 byte(length >> 8), 163 byte(length), 164 byte(paddingLength), 165 } 166 padding := make([]byte, paddingLength) 167 _, err := io.ReadFull(w.rand, padding) 168 if err != nil { 169 return err 170 } 171 172 if w.mac != nil { 173 w.mac.Reset() 174 seqNumBytes := []byte{ 175 byte(w.seqNum >> 24), 176 byte(w.seqNum >> 16), 177 byte(w.seqNum >> 8), 178 byte(w.seqNum), 179 } 180 w.mac.Write(seqNumBytes) 181 w.mac.Write(lengthBytes) 182 w.mac.Write(packet) 183 w.mac.Write(padding) 184 } 185 186 // TODO(dfc) lengthBytes, packet and padding should be 187 // subslices of a single buffer 188 w.cipher.XORKeyStream(lengthBytes, lengthBytes) 189 w.cipher.XORKeyStream(packet, packet) 190 w.cipher.XORKeyStream(padding, padding) 191 192 if _, err := w.Write(lengthBytes); err != nil { 193 return err 194 } 195 if _, err := w.Write(packet); err != nil { 196 return err 197 } 198 if _, err := w.Write(padding); err != nil { 199 return err 200 } 201 202 if w.mac != nil { 203 if _, err := w.Write(w.mac.Sum(nil)); err != nil { 204 return err 205 } 206 } 207 208 if err := w.Flush(); err != nil { 209 return err 210 } 211 w.seqNum++ 212 return err 213 } 214 215 // Send a message to the remote peer 216 func (t *transport) sendMessage(typ uint8, msg interface{}) error { 217 packet := marshal(typ, msg) 218 return t.writePacket(packet) 219 } 220 221 func newTransport(conn net.Conn, rand io.Reader) *transport { 222 return &transport{ 223 reader: reader{ 224 Reader: bufio.NewReader(conn), 225 common: common{ 226 cipher: noneCipher{}, 227 }, 228 }, 229 writer: writer{ 230 Writer: bufio.NewWriter(conn), 231 rand: rand, 232 Mutex: new(sync.Mutex), 233 common: common{ 234 cipher: noneCipher{}, 235 }, 236 }, 237 filteredConn: conn, 238 } 239 } 240 241 type direction struct { 242 ivTag []byte 243 keyTag []byte 244 macKeyTag []byte 245 } 246 247 // TODO(dfc) can this be made a constant ? 248 var ( 249 serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}} 250 clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}} 251 ) 252 253 // setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as 254 // described in RFC 4253, section 6.4. direction should either be serverKeys 255 // (to setup server->client keys) or clientKeys (for client->server keys). 256 func (c *common) setupKeys(d direction, K, H, sessionId []byte, hashFunc crypto.Hash) error { 257 cipherMode := cipherModes[c.cipherAlgo] 258 259 macKeySize := 20 260 261 iv := make([]byte, cipherMode.ivSize) 262 key := make([]byte, cipherMode.keySize) 263 macKey := make([]byte, macKeySize) 264 265 h := hashFunc.New() 266 generateKeyMaterial(iv, d.ivTag, K, H, sessionId, h) 267 generateKeyMaterial(key, d.keyTag, K, H, sessionId, h) 268 generateKeyMaterial(macKey, d.macKeyTag, K, H, sessionId, h) 269 270 c.mac = truncatingMAC{12, hmac.New(sha1.New, macKey)} 271 272 cipher, err := cipherMode.createCipher(key, iv) 273 if err != nil { 274 return err 275 } 276 277 c.cipher = cipher 278 279 return nil 280 } 281 282 // generateKeyMaterial fills out with key material generated from tag, K, H 283 // and sessionId, as specified in RFC 4253, section 7.2. 284 func generateKeyMaterial(out, tag []byte, K, H, sessionId []byte, h hash.Hash) { 285 var digestsSoFar []byte 286 287 for len(out) > 0 { 288 h.Reset() 289 h.Write(K) 290 h.Write(H) 291 292 if len(digestsSoFar) == 0 { 293 h.Write(tag) 294 h.Write(sessionId) 295 } else { 296 h.Write(digestsSoFar) 297 } 298 299 digest := h.Sum(nil) 300 n := copy(out, digest) 301 out = out[n:] 302 if len(out) > 0 { 303 digestsSoFar = append(digestsSoFar, digest...) 304 } 305 } 306 } 307 308 // truncatingMAC wraps around a hash.Hash and truncates the output digest to 309 // a given size. 310 type truncatingMAC struct { 311 length int 312 hmac hash.Hash 313 } 314 315 func (t truncatingMAC) Write(data []byte) (int, error) { 316 return t.hmac.Write(data) 317 } 318 319 func (t truncatingMAC) Sum(in []byte) []byte { 320 out := t.hmac.Sum(in) 321 return out[:len(in)+t.length] 322 } 323 324 func (t truncatingMAC) Reset() { 325 t.hmac.Reset() 326 } 327 328 func (t truncatingMAC) Size() int { 329 return t.length 330 } 331 332 func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } 333 334 // maxVersionStringBytes is the maximum number of bytes that we'll accept as a 335 // version string. In the event that the client is talking a different protocol 336 // we need to set a limit otherwise we will keep using more and more memory 337 // while searching for the end of the version handshake. 338 const maxVersionStringBytes = 1024 339 340 // Read version string as specified by RFC 4253, section 4.2. 341 func readVersion(r io.Reader) ([]byte, error) { 342 versionString := make([]byte, 0, 64) 343 var ok bool 344 var buf [1]byte 345 forEachByte: 346 for len(versionString) < maxVersionStringBytes { 347 _, err := io.ReadFull(r, buf[:]) 348 if err != nil { 349 return nil, err 350 } 351 // The RFC says that the version should be terminated with \r\n 352 // but several SSH servers actually only send a \n. 353 if buf[0] == '\n' { 354 ok = true 355 break forEachByte 356 } 357 versionString = append(versionString, buf[0]) 358 } 359 360 if !ok { 361 return nil, errors.New("ssh: failed to read version string") 362 } 363 364 // There might be a '\r' on the end which we should remove. 365 if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' { 366 versionString = versionString[:len(versionString)-1] 367 } 368 return versionString, nil 369 }