github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/golang.org/x/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 var ciphers []string 210 for _, c := range c.Ciphers { 211 if cipherModes[c] != nil { 212 // reject the cipher if we have no cipherModes definition 213 ciphers = append(ciphers, c) 214 } 215 } 216 c.Ciphers = ciphers 217 218 if c.KeyExchanges == nil { 219 c.KeyExchanges = supportedKexAlgos 220 } 221 222 if c.MACs == nil { 223 c.MACs = supportedMACs 224 } 225 226 if c.RekeyThreshold == 0 { 227 // RFC 4253, section 9 suggests rekeying after 1G. 228 c.RekeyThreshold = 1 << 30 229 } 230 if c.RekeyThreshold < minRekeyThreshold { 231 c.RekeyThreshold = minRekeyThreshold 232 } 233 } 234 235 // buildDataSignedForAuth returns the data that is signed in order to prove 236 // possession of a private key. See RFC 4252, section 7. 237 func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte { 238 data := struct { 239 Session []byte 240 Type byte 241 User string 242 Service string 243 Method string 244 Sign bool 245 Algo []byte 246 PubKey []byte 247 }{ 248 sessionId, 249 msgUserAuthRequest, 250 req.User, 251 req.Service, 252 req.Method, 253 true, 254 algo, 255 pubKey, 256 } 257 return Marshal(data) 258 } 259 260 func appendU16(buf []byte, n uint16) []byte { 261 return append(buf, byte(n>>8), byte(n)) 262 } 263 264 func appendU32(buf []byte, n uint32) []byte { 265 return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) 266 } 267 268 func appendU64(buf []byte, n uint64) []byte { 269 return append(buf, 270 byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), 271 byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) 272 } 273 274 func appendInt(buf []byte, n int) []byte { 275 return appendU32(buf, uint32(n)) 276 } 277 278 func appendString(buf []byte, s string) []byte { 279 buf = appendU32(buf, uint32(len(s))) 280 buf = append(buf, s...) 281 return buf 282 } 283 284 func appendBool(buf []byte, b bool) []byte { 285 if b { 286 return append(buf, 1) 287 } 288 return append(buf, 0) 289 } 290 291 // newCond is a helper to hide the fact that there is no usable zero 292 // value for sync.Cond. 293 func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) } 294 295 // window represents the buffer available to clients 296 // wishing to write to a channel. 297 type window struct { 298 *sync.Cond 299 win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1 300 writeWaiters int 301 closed bool 302 } 303 304 // add adds win to the amount of window available 305 // for consumers. 306 func (w *window) add(win uint32) bool { 307 // a zero sized window adjust is a noop. 308 if win == 0 { 309 return true 310 } 311 w.L.Lock() 312 if w.win+win < win { 313 w.L.Unlock() 314 return false 315 } 316 w.win += win 317 // It is unusual that multiple goroutines would be attempting to reserve 318 // window space, but not guaranteed. Use broadcast to notify all waiters 319 // that additional window is available. 320 w.Broadcast() 321 w.L.Unlock() 322 return true 323 } 324 325 // close sets the window to closed, so all reservations fail 326 // immediately. 327 func (w *window) close() { 328 w.L.Lock() 329 w.closed = true 330 w.Broadcast() 331 w.L.Unlock() 332 } 333 334 // reserve reserves win from the available window capacity. 335 // If no capacity remains, reserve will block. reserve may 336 // return less than requested. 337 func (w *window) reserve(win uint32) (uint32, error) { 338 var err error 339 w.L.Lock() 340 w.writeWaiters++ 341 w.Broadcast() 342 for w.win == 0 && !w.closed { 343 w.Wait() 344 } 345 w.writeWaiters-- 346 if w.win < win { 347 win = w.win 348 } 349 w.win -= win 350 if w.closed { 351 err = io.EOF 352 } 353 w.L.Unlock() 354 return win, err 355 } 356 357 // waitWriterBlocked waits until some goroutine is blocked for further 358 // writes. It is used in tests only. 359 func (w *window) waitWriterBlocked() { 360 w.Cond.L.Lock() 361 for w.writeWaiters == 0 { 362 w.Cond.Wait() 363 } 364 w.Cond.L.Unlock() 365 }