github.com/inflatablewoman/deis@v1.0.1-0.20141111034523-a4511c46a6ce/deisctl/Godeps/_workspace/src/code.google.com/p/go.crypto/ssh/common.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 "crypto" 9 "crypto/rand" 10 "fmt" 11 "io" 12 "sync" 13 14 _ "crypto/sha1" 15 _ "crypto/sha256" 16 _ "crypto/sha512" 17 ) 18 19 // These are string constants in the SSH protocol. 20 const ( 21 compressionNone = "none" 22 serviceUserAuth = "ssh-userauth" 23 serviceSSH = "ssh-connection" 24 ) 25 26 // supportedCiphers specifies the supported ciphers in preference order. 27 var supportedCiphers = []string{ 28 "aes128-ctr", "aes192-ctr", "aes256-ctr", 29 "aes128-gcm@openssh.com", 30 "arcfour256", "arcfour128", 31 } 32 33 // supportedKexAlgos specifies the supported key-exchange algorithms in 34 // preference order. 35 var supportedKexAlgos = []string{ 36 // P384 and P521 are not constant-time yet, but since we don't 37 // reuse ephemeral keys, using them for ECDH should be OK. 38 kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, 39 kexAlgoDH14SHA1, kexAlgoDH1SHA1, 40 } 41 42 // supportedKexAlgos specifies the supported host-key algorithms (i.e. methods 43 // of authenticating servers) in preference order. 44 var supportedHostKeyAlgos = []string{ 45 CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, 46 CertAlgoECDSA384v01, CertAlgoECDSA521v01, 47 48 KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, 49 KeyAlgoRSA, KeyAlgoDSA, 50 } 51 52 // supportedMACs specifies a default set of MAC algorithms in preference order. 53 // This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed 54 // because they have reached the end of their useful life. 55 var supportedMACs = []string{ 56 "hmac-sha1", "hmac-sha1-96", 57 } 58 59 var supportedCompressions = []string{compressionNone} 60 61 // hashFuncs keeps the mapping of supported algorithms to their respective 62 // hashes needed for signature verification. 63 var hashFuncs = map[string]crypto.Hash{ 64 KeyAlgoRSA: crypto.SHA1, 65 KeyAlgoDSA: crypto.SHA1, 66 KeyAlgoECDSA256: crypto.SHA256, 67 KeyAlgoECDSA384: crypto.SHA384, 68 KeyAlgoECDSA521: crypto.SHA512, 69 CertAlgoRSAv01: crypto.SHA1, 70 CertAlgoDSAv01: crypto.SHA1, 71 CertAlgoECDSA256v01: crypto.SHA256, 72 CertAlgoECDSA384v01: crypto.SHA384, 73 CertAlgoECDSA521v01: crypto.SHA512, 74 } 75 76 // unexpectedMessageError results when the SSH message that we received didn't 77 // match what we wanted. 78 func unexpectedMessageError(expected, got uint8) error { 79 return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected) 80 } 81 82 // parseError results from a malformed SSH message. 83 func parseError(tag uint8) error { 84 return fmt.Errorf("ssh: parse error in message type %d", tag) 85 } 86 87 func findCommonAlgorithm(clientAlgos []string, serverAlgos []string) (commonAlgo string, ok bool) { 88 for _, clientAlgo := range clientAlgos { 89 for _, serverAlgo := range serverAlgos { 90 if clientAlgo == serverAlgo { 91 return clientAlgo, true 92 } 93 } 94 } 95 return 96 } 97 98 func findCommonCipher(clientCiphers []string, serverCiphers []string) (commonCipher string, ok bool) { 99 for _, clientCipher := range clientCiphers { 100 for _, serverCipher := range serverCiphers { 101 // reject the cipher if we have no cipherModes definition 102 if clientCipher == serverCipher && cipherModes[clientCipher] != nil { 103 return clientCipher, true 104 } 105 } 106 } 107 return 108 } 109 110 type directionAlgorithms struct { 111 Cipher string 112 MAC string 113 Compression string 114 } 115 116 type algorithms struct { 117 kex string 118 hostKey string 119 w directionAlgorithms 120 r directionAlgorithms 121 } 122 123 func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms) { 124 var ok bool 125 result := &algorithms{} 126 result.kex, ok = findCommonAlgorithm(clientKexInit.KexAlgos, serverKexInit.KexAlgos) 127 if !ok { 128 return 129 } 130 131 result.hostKey, ok = findCommonAlgorithm(clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos) 132 if !ok { 133 return 134 } 135 136 result.w.Cipher, ok = findCommonCipher(clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer) 137 if !ok { 138 return 139 } 140 141 result.r.Cipher, ok = findCommonCipher(clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient) 142 if !ok { 143 return 144 } 145 146 result.w.MAC, ok = findCommonAlgorithm(clientKexInit.MACsClientServer, serverKexInit.MACsClientServer) 147 if !ok { 148 return 149 } 150 151 result.r.MAC, ok = findCommonAlgorithm(clientKexInit.MACsServerClient, serverKexInit.MACsServerClient) 152 if !ok { 153 return 154 } 155 156 result.w.Compression, ok = findCommonAlgorithm(clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer) 157 if !ok { 158 return 159 } 160 161 result.r.Compression, ok = findCommonAlgorithm(clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient) 162 if !ok { 163 return 164 } 165 166 return result 167 } 168 169 // If rekeythreshold is too small, we can't make any progress sending 170 // stuff. 171 const minRekeyThreshold uint64 = 256 172 173 // Config contains configuration data common to both ServerConfig and 174 // ClientConfig. 175 type Config struct { 176 // Rand provides the source of entropy for cryptographic 177 // primitives. If Rand is nil, the cryptographic random reader 178 // in package crypto/rand will be used. 179 Rand io.Reader 180 181 // The maximum number of bytes sent or received after which a 182 // new key is negotiated. It must be at least 256. If 183 // unspecified, 1 gigabyte is used. 184 RekeyThreshold uint64 185 186 // The allowed key exchanges algorithms. If unspecified then a 187 // default set of algorithms is used. 188 KeyExchanges []string 189 190 // The allowed cipher algorithms. If unspecified then a sensible 191 // default is used. 192 Ciphers []string 193 194 // The allowed MAC algorithms. If unspecified then a sensible default 195 // is used. 196 MACs []string 197 } 198 199 // SetDefaults sets sensible values for unset fields in config. This is 200 // exported for testing: Configs passed to SSH functions are copied and have 201 // default values set automatically. 202 func (c *Config) SetDefaults() { 203 if c.Rand == nil { 204 c.Rand = rand.Reader 205 } 206 if c.Ciphers == nil { 207 c.Ciphers = supportedCiphers 208 } 209 210 if c.KeyExchanges == nil { 211 c.KeyExchanges = supportedKexAlgos 212 } 213 214 if c.MACs == nil { 215 c.MACs = supportedMACs 216 } 217 218 if c.RekeyThreshold == 0 { 219 // RFC 4253, section 9 suggests rekeying after 1G. 220 c.RekeyThreshold = 1 << 30 221 } 222 if c.RekeyThreshold < minRekeyThreshold { 223 c.RekeyThreshold = minRekeyThreshold 224 } 225 } 226 227 // buildDataSignedForAuth returns the data that is signed in order to prove 228 // possession of a private key. See RFC 4252, section 7. 229 func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte { 230 data := struct { 231 Session []byte 232 Type byte 233 User string 234 Service string 235 Method string 236 Sign bool 237 Algo []byte 238 PubKey []byte 239 }{ 240 sessionId, 241 msgUserAuthRequest, 242 req.User, 243 req.Service, 244 req.Method, 245 true, 246 algo, 247 pubKey, 248 } 249 return Marshal(data) 250 } 251 252 func appendU16(buf []byte, n uint16) []byte { 253 return append(buf, byte(n>>8), byte(n)) 254 } 255 256 func appendU32(buf []byte, n uint32) []byte { 257 return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) 258 } 259 260 func appendU64(buf []byte, n uint64) []byte { 261 return append(buf, 262 byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), 263 byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) 264 } 265 266 func appendInt(buf []byte, n int) []byte { 267 return appendU32(buf, uint32(n)) 268 } 269 270 func appendString(buf []byte, s string) []byte { 271 buf = appendU32(buf, uint32(len(s))) 272 buf = append(buf, s...) 273 return buf 274 } 275 276 func appendBool(buf []byte, b bool) []byte { 277 if b { 278 return append(buf, 1) 279 } 280 return append(buf, 0) 281 } 282 283 // newCond is a helper to hide the fact that there is no usable zero 284 // value for sync.Cond. 285 func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) } 286 287 // window represents the buffer available to clients 288 // wishing to write to a channel. 289 type window struct { 290 *sync.Cond 291 win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1 292 writeWaiters int 293 closed bool 294 } 295 296 // add adds win to the amount of window available 297 // for consumers. 298 func (w *window) add(win uint32) bool { 299 // a zero sized window adjust is a noop. 300 if win == 0 { 301 return true 302 } 303 w.L.Lock() 304 if w.win+win < win { 305 w.L.Unlock() 306 return false 307 } 308 w.win += win 309 // It is unusual that multiple goroutines would be attempting to reserve 310 // window space, but not guaranteed. Use broadcast to notify all waiters 311 // that additional window is available. 312 w.Broadcast() 313 w.L.Unlock() 314 return true 315 } 316 317 // close sets the window to closed, so all reservations fail 318 // immediately. 319 func (w *window) close() { 320 w.L.Lock() 321 w.closed = true 322 w.Broadcast() 323 w.L.Unlock() 324 } 325 326 // reserve reserves win from the available window capacity. 327 // If no capacity remains, reserve will block. reserve may 328 // return less than requested. 329 func (w *window) reserve(win uint32) (uint32, error) { 330 var err error 331 w.L.Lock() 332 w.writeWaiters++ 333 w.Broadcast() 334 for w.win == 0 && !w.closed { 335 w.Wait() 336 } 337 w.writeWaiters-- 338 if w.win < win { 339 win = w.win 340 } 341 w.win -= win 342 if w.closed { 343 err = io.EOF 344 } 345 w.L.Unlock() 346 return win, err 347 } 348 349 // waitWriterBlocked waits until some goroutine is blocked for further 350 // writes. It is used in tests only. 351 func (w *window) waitWriterBlocked() { 352 w.Cond.L.Lock() 353 for w.writeWaiters == 0 { 354 w.Cond.Wait() 355 } 356 w.Cond.L.Unlock() 357 }