common.go (12614B)
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 "math" 13 "strings" 14 "sync" 15 16 _ "crypto/sha1" 17 _ "crypto/sha256" 18 _ "crypto/sha512" 19 ) 20 21 // These are string constants in the SSH protocol. 22 const ( 23 compressionNone = "none" 24 serviceUserAuth = "ssh-userauth" 25 serviceSSH = "ssh-connection" 26 ) 27 28 // supportedCiphers lists ciphers we support but might not recommend. 29 var supportedCiphers = []string{ 30 "aes128-ctr", "aes192-ctr", "aes256-ctr", 31 "aes128-gcm@openssh.com", gcm256CipherID, 32 chacha20Poly1305ID, 33 "arcfour256", "arcfour128", "arcfour", 34 aes128cbcID, 35 tripledescbcID, 36 } 37 38 // preferredCiphers specifies the default preference for ciphers. 39 var preferredCiphers = []string{ 40 "aes128-gcm@openssh.com", gcm256CipherID, 41 chacha20Poly1305ID, 42 "aes128-ctr", "aes192-ctr", "aes256-ctr", 43 } 44 45 // supportedKexAlgos specifies the supported key-exchange algorithms in 46 // preference order. 47 var supportedKexAlgos = []string{ 48 kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH, 49 // P384 and P521 are not constant-time yet, but since we don't 50 // reuse ephemeral keys, using them for ECDH should be OK. 51 kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, 52 kexAlgoDH14SHA256, kexAlgoDH14SHA1, kexAlgoDH1SHA1, 53 } 54 55 // serverForbiddenKexAlgos contains key exchange algorithms, that are forbidden 56 // for the server half. 57 var serverForbiddenKexAlgos = map[string]struct{}{ 58 kexAlgoDHGEXSHA1: {}, // server half implementation is only minimal to satisfy the automated tests 59 kexAlgoDHGEXSHA256: {}, // server half implementation is only minimal to satisfy the automated tests 60 } 61 62 // preferredKexAlgos specifies the default preference for key-exchange algorithms 63 // in preference order. 64 var preferredKexAlgos = []string{ 65 kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH, 66 kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, 67 kexAlgoDH14SHA256, kexAlgoDH14SHA1, 68 } 69 70 // supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods 71 // of authenticating servers) in preference order. 72 var supportedHostKeyAlgos = []string{ 73 CertAlgoRSASHA512v01, CertAlgoRSASHA256v01, 74 CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, 75 CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01, 76 77 KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, 78 KeyAlgoRSASHA512, KeyAlgoRSASHA256, 79 KeyAlgoRSA, KeyAlgoDSA, 80 81 KeyAlgoED25519, 82 } 83 84 // supportedMACs specifies a default set of MAC algorithms in preference order. 85 // This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed 86 // because they have reached the end of their useful life. 87 var supportedMACs = []string{ 88 "hmac-sha2-512-etm@openssh.com", "hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96", 89 } 90 91 var supportedCompressions = []string{compressionNone} 92 93 // hashFuncs keeps the mapping of supported signature algorithms to their 94 // respective hashes needed for signing and verification. 95 var hashFuncs = map[string]crypto.Hash{ 96 KeyAlgoRSA: crypto.SHA1, 97 KeyAlgoRSASHA256: crypto.SHA256, 98 KeyAlgoRSASHA512: crypto.SHA512, 99 KeyAlgoDSA: crypto.SHA1, 100 KeyAlgoECDSA256: crypto.SHA256, 101 KeyAlgoECDSA384: crypto.SHA384, 102 KeyAlgoECDSA521: crypto.SHA512, 103 // KeyAlgoED25519 doesn't pre-hash. 104 KeyAlgoSKECDSA256: crypto.SHA256, 105 KeyAlgoSKED25519: crypto.SHA256, 106 } 107 108 // algorithmsForKeyFormat returns the supported signature algorithms for a given 109 // public key format (PublicKey.Type), in order of preference. See RFC 8332, 110 // Section 2. See also the note in sendKexInit on backwards compatibility. 111 func algorithmsForKeyFormat(keyFormat string) []string { 112 switch keyFormat { 113 case KeyAlgoRSA: 114 return []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA} 115 case CertAlgoRSAv01: 116 return []string{CertAlgoRSASHA256v01, CertAlgoRSASHA512v01, CertAlgoRSAv01} 117 default: 118 return []string{keyFormat} 119 } 120 } 121 122 // supportedPubKeyAuthAlgos specifies the supported client public key 123 // authentication algorithms. Note that this doesn't include certificate types 124 // since those use the underlying algorithm. This list is sent to the client if 125 // it supports the server-sig-algs extension. Order is irrelevant. 126 var supportedPubKeyAuthAlgos = []string{ 127 KeyAlgoED25519, 128 KeyAlgoSKED25519, KeyAlgoSKECDSA256, 129 KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, 130 KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA, 131 KeyAlgoDSA, 132 } 133 134 var supportedPubKeyAuthAlgosList = strings.Join(supportedPubKeyAuthAlgos, ",") 135 136 // unexpectedMessageError results when the SSH message that we received didn't 137 // match what we wanted. 138 func unexpectedMessageError(expected, got uint8) error { 139 return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected) 140 } 141 142 // parseError results from a malformed SSH message. 143 func parseError(tag uint8) error { 144 return fmt.Errorf("ssh: parse error in message type %d", tag) 145 } 146 147 func findCommon(what string, client []string, server []string) (common string, err error) { 148 for _, c := range client { 149 for _, s := range server { 150 if c == s { 151 return c, nil 152 } 153 } 154 } 155 return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server) 156 } 157 158 // directionAlgorithms records algorithm choices in one direction (either read or write) 159 type directionAlgorithms struct { 160 Cipher string 161 MAC string 162 Compression string 163 } 164 165 // rekeyBytes returns a rekeying intervals in bytes. 166 func (a *directionAlgorithms) rekeyBytes() int64 { 167 // According to RFC 4344 block ciphers should rekey after 168 // 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is 169 // 128. 170 switch a.Cipher { 171 case "aes128-ctr", "aes192-ctr", "aes256-ctr", gcm128CipherID, gcm256CipherID, aes128cbcID: 172 return 16 * (1 << 32) 173 174 } 175 176 // For others, stick with RFC 4253 recommendation to rekey after 1 Gb of data. 177 return 1 << 30 178 } 179 180 var aeadCiphers = map[string]bool{ 181 gcm128CipherID: true, 182 gcm256CipherID: true, 183 chacha20Poly1305ID: true, 184 } 185 186 type algorithms struct { 187 kex string 188 hostKey string 189 w directionAlgorithms 190 r directionAlgorithms 191 } 192 193 func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) { 194 result := &algorithms{} 195 196 result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos) 197 if err != nil { 198 return 199 } 200 201 result.hostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos) 202 if err != nil { 203 return 204 } 205 206 stoc, ctos := &result.w, &result.r 207 if isClient { 208 ctos, stoc = stoc, ctos 209 } 210 211 ctos.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer) 212 if err != nil { 213 return 214 } 215 216 stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient) 217 if err != nil { 218 return 219 } 220 221 if !aeadCiphers[ctos.Cipher] { 222 ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer) 223 if err != nil { 224 return 225 } 226 } 227 228 if !aeadCiphers[stoc.Cipher] { 229 stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient) 230 if err != nil { 231 return 232 } 233 } 234 235 ctos.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer) 236 if err != nil { 237 return 238 } 239 240 stoc.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient) 241 if err != nil { 242 return 243 } 244 245 return result, nil 246 } 247 248 // If rekeythreshold is too small, we can't make any progress sending 249 // stuff. 250 const minRekeyThreshold uint64 = 256 251 252 // Config contains configuration data common to both ServerConfig and 253 // ClientConfig. 254 type Config struct { 255 // Rand provides the source of entropy for cryptographic 256 // primitives. If Rand is nil, the cryptographic random reader 257 // in package crypto/rand will be used. 258 Rand io.Reader 259 260 // The maximum number of bytes sent or received after which a 261 // new key is negotiated. It must be at least 256. If 262 // unspecified, a size suitable for the chosen cipher is used. 263 RekeyThreshold uint64 264 265 // The allowed key exchanges algorithms. If unspecified then a 266 // default set of algorithms is used. 267 KeyExchanges []string 268 269 // The allowed cipher algorithms. If unspecified then a sensible 270 // default is used. 271 Ciphers []string 272 273 // The allowed MAC algorithms. If unspecified then a sensible default 274 // is used. 275 MACs []string 276 } 277 278 // SetDefaults sets sensible values for unset fields in config. This is 279 // exported for testing: Configs passed to SSH functions are copied and have 280 // default values set automatically. 281 func (c *Config) SetDefaults() { 282 if c.Rand == nil { 283 c.Rand = rand.Reader 284 } 285 if c.Ciphers == nil { 286 c.Ciphers = preferredCiphers 287 } 288 var ciphers []string 289 for _, c := range c.Ciphers { 290 if cipherModes[c] != nil { 291 // reject the cipher if we have no cipherModes definition 292 ciphers = append(ciphers, c) 293 } 294 } 295 c.Ciphers = ciphers 296 297 if c.KeyExchanges == nil { 298 c.KeyExchanges = preferredKexAlgos 299 } 300 301 if c.MACs == nil { 302 c.MACs = supportedMACs 303 } 304 305 if c.RekeyThreshold == 0 { 306 // cipher specific default 307 } else if c.RekeyThreshold < minRekeyThreshold { 308 c.RekeyThreshold = minRekeyThreshold 309 } else if c.RekeyThreshold >= math.MaxInt64 { 310 // Avoid weirdness if somebody uses -1 as a threshold. 311 c.RekeyThreshold = math.MaxInt64 312 } 313 } 314 315 // buildDataSignedForAuth returns the data that is signed in order to prove 316 // possession of a private key. See RFC 4252, section 7. algo is the advertised 317 // algorithm, and may be a certificate type. 318 func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo string, pubKey []byte) []byte { 319 data := struct { 320 Session []byte 321 Type byte 322 User string 323 Service string 324 Method string 325 Sign bool 326 Algo string 327 PubKey []byte 328 }{ 329 sessionID, 330 msgUserAuthRequest, 331 req.User, 332 req.Service, 333 req.Method, 334 true, 335 algo, 336 pubKey, 337 } 338 return Marshal(data) 339 } 340 341 func appendU16(buf []byte, n uint16) []byte { 342 return append(buf, byte(n>>8), byte(n)) 343 } 344 345 func appendU32(buf []byte, n uint32) []byte { 346 return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) 347 } 348 349 func appendU64(buf []byte, n uint64) []byte { 350 return append(buf, 351 byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), 352 byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) 353 } 354 355 func appendInt(buf []byte, n int) []byte { 356 return appendU32(buf, uint32(n)) 357 } 358 359 func appendString(buf []byte, s string) []byte { 360 buf = appendU32(buf, uint32(len(s))) 361 buf = append(buf, s...) 362 return buf 363 } 364 365 func appendBool(buf []byte, b bool) []byte { 366 if b { 367 return append(buf, 1) 368 } 369 return append(buf, 0) 370 } 371 372 // newCond is a helper to hide the fact that there is no usable zero 373 // value for sync.Cond. 374 func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) } 375 376 // window represents the buffer available to clients 377 // wishing to write to a channel. 378 type window struct { 379 *sync.Cond 380 win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1 381 writeWaiters int 382 closed bool 383 } 384 385 // add adds win to the amount of window available 386 // for consumers. 387 func (w *window) add(win uint32) bool { 388 // a zero sized window adjust is a noop. 389 if win == 0 { 390 return true 391 } 392 w.L.Lock() 393 if w.win+win < win { 394 w.L.Unlock() 395 return false 396 } 397 w.win += win 398 // It is unusual that multiple goroutines would be attempting to reserve 399 // window space, but not guaranteed. Use broadcast to notify all waiters 400 // that additional window is available. 401 w.Broadcast() 402 w.L.Unlock() 403 return true 404 } 405 406 // close sets the window to closed, so all reservations fail 407 // immediately. 408 func (w *window) close() { 409 w.L.Lock() 410 w.closed = true 411 w.Broadcast() 412 w.L.Unlock() 413 } 414 415 // reserve reserves win from the available window capacity. 416 // If no capacity remains, reserve will block. reserve may 417 // return less than requested. 418 func (w *window) reserve(win uint32) (uint32, error) { 419 var err error 420 w.L.Lock() 421 w.writeWaiters++ 422 w.Broadcast() 423 for w.win == 0 && !w.closed { 424 w.Wait() 425 } 426 w.writeWaiters-- 427 if w.win < win { 428 win = w.win 429 } 430 w.win -= win 431 if w.closed { 432 err = io.EOF 433 } 434 w.L.Unlock() 435 return win, err 436 } 437 438 // waitWriterBlocked waits until some goroutine is blocked for further 439 // writes. It is used in tests only. 440 func (w *window) waitWriterBlocked() { 441 w.Cond.L.Lock() 442 for w.writeWaiters == 0 { 443 w.Cond.Wait() 444 } 445 w.Cond.L.Unlock() 446 }