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