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