a geicko-2 based round robin ranking system designed to test c++ battleship submissions
battleship.dunkirk.sh
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 "slices"
14 "sync"
15
16 _ "crypto/sha1"
17 _ "crypto/sha256"
18 _ "crypto/sha512"
19)
20
21// These are string constants in the SSH protocol.
22const (
23 compressionNone = "none"
24 serviceUserAuth = "ssh-userauth"
25 serviceSSH = "ssh-connection"
26)
27
28// The ciphers currently or previously implemented by this library, to use in
29// [Config.Ciphers]. For a list, see the [Algorithms.Ciphers] returned by
30// [SupportedAlgorithms] or [InsecureAlgorithms].
31const (
32 CipherAES128GCM = "aes128-gcm@openssh.com"
33 CipherAES256GCM = "aes256-gcm@openssh.com"
34 CipherChaCha20Poly1305 = "chacha20-poly1305@openssh.com"
35 CipherAES128CTR = "aes128-ctr"
36 CipherAES192CTR = "aes192-ctr"
37 CipherAES256CTR = "aes256-ctr"
38 InsecureCipherAES128CBC = "aes128-cbc"
39 InsecureCipherTripleDESCBC = "3des-cbc"
40 InsecureCipherRC4 = "arcfour"
41 InsecureCipherRC4128 = "arcfour128"
42 InsecureCipherRC4256 = "arcfour256"
43)
44
45// The key exchanges currently or previously implemented by this library, to use
46// in [Config.KeyExchanges]. For a list, see the
47// [Algorithms.KeyExchanges] returned by [SupportedAlgorithms] or
48// [InsecureAlgorithms].
49const (
50 InsecureKeyExchangeDH1SHA1 = "diffie-hellman-group1-sha1"
51 InsecureKeyExchangeDH14SHA1 = "diffie-hellman-group14-sha1"
52 KeyExchangeDH14SHA256 = "diffie-hellman-group14-sha256"
53 KeyExchangeDH16SHA512 = "diffie-hellman-group16-sha512"
54 KeyExchangeECDHP256 = "ecdh-sha2-nistp256"
55 KeyExchangeECDHP384 = "ecdh-sha2-nistp384"
56 KeyExchangeECDHP521 = "ecdh-sha2-nistp521"
57 KeyExchangeCurve25519 = "curve25519-sha256"
58 InsecureKeyExchangeDHGEXSHA1 = "diffie-hellman-group-exchange-sha1"
59 KeyExchangeDHGEXSHA256 = "diffie-hellman-group-exchange-sha256"
60 // KeyExchangeMLKEM768X25519 is supported from Go 1.24.
61 KeyExchangeMLKEM768X25519 = "mlkem768x25519-sha256"
62
63 // An alias for KeyExchangeCurve25519SHA256. This kex ID will be added if
64 // KeyExchangeCurve25519SHA256 is requested for backward compatibility with
65 // OpenSSH versions up to 7.2.
66 keyExchangeCurve25519LibSSH = "curve25519-sha256@libssh.org"
67)
68
69// The message authentication code (MAC) currently or previously implemented by
70// this library, to use in [Config.MACs]. For a list, see the
71// [Algorithms.MACs] returned by [SupportedAlgorithms] or
72// [InsecureAlgorithms].
73const (
74 HMACSHA256ETM = "hmac-sha2-256-etm@openssh.com"
75 HMACSHA512ETM = "hmac-sha2-512-etm@openssh.com"
76 HMACSHA256 = "hmac-sha2-256"
77 HMACSHA512 = "hmac-sha2-512"
78 HMACSHA1 = "hmac-sha1"
79 InsecureHMACSHA196 = "hmac-sha1-96"
80)
81
82var (
83 // supportedKexAlgos specifies key-exchange algorithms implemented by this
84 // package in preference order, excluding those with security issues.
85 supportedKexAlgos = []string{
86 KeyExchangeCurve25519,
87 KeyExchangeECDHP256,
88 KeyExchangeECDHP384,
89 KeyExchangeECDHP521,
90 KeyExchangeDH14SHA256,
91 KeyExchangeDH16SHA512,
92 KeyExchangeDHGEXSHA256,
93 }
94 // defaultKexAlgos specifies the default preference for key-exchange
95 // algorithms in preference order.
96 defaultKexAlgos = []string{
97 KeyExchangeCurve25519,
98 KeyExchangeECDHP256,
99 KeyExchangeECDHP384,
100 KeyExchangeECDHP521,
101 KeyExchangeDH14SHA256,
102 InsecureKeyExchangeDH14SHA1,
103 }
104 // insecureKexAlgos specifies key-exchange algorithms implemented by this
105 // package and which have security issues.
106 insecureKexAlgos = []string{
107 InsecureKeyExchangeDH14SHA1,
108 InsecureKeyExchangeDH1SHA1,
109 InsecureKeyExchangeDHGEXSHA1,
110 }
111 // supportedCiphers specifies cipher algorithms implemented by this package
112 // in preference order, excluding those with security issues.
113 supportedCiphers = []string{
114 CipherAES128GCM,
115 CipherAES256GCM,
116 CipherChaCha20Poly1305,
117 CipherAES128CTR,
118 CipherAES192CTR,
119 CipherAES256CTR,
120 }
121 // defaultCiphers specifies the default preference for ciphers algorithms
122 // in preference order.
123 defaultCiphers = supportedCiphers
124 // insecureCiphers specifies cipher algorithms implemented by this
125 // package and which have security issues.
126 insecureCiphers = []string{
127 InsecureCipherAES128CBC,
128 InsecureCipherTripleDESCBC,
129 InsecureCipherRC4256,
130 InsecureCipherRC4128,
131 InsecureCipherRC4,
132 }
133 // supportedMACs specifies MAC algorithms implemented by this package in
134 // preference order, excluding those with security issues.
135 supportedMACs = []string{
136 HMACSHA256ETM,
137 HMACSHA512ETM,
138 HMACSHA256,
139 HMACSHA512,
140 HMACSHA1,
141 }
142 // defaultMACs specifies the default preference for MAC algorithms in
143 // preference order.
144 defaultMACs = []string{
145 HMACSHA256ETM,
146 HMACSHA512ETM,
147 HMACSHA256,
148 HMACSHA512,
149 HMACSHA1,
150 InsecureHMACSHA196,
151 }
152 // insecureMACs specifies MAC algorithms implemented by this
153 // package and which have security issues.
154 insecureMACs = []string{
155 InsecureHMACSHA196,
156 }
157 // supportedHostKeyAlgos specifies the supported host-key algorithms (i.e.
158 // methods of authenticating servers) implemented by this package in
159 // preference order, excluding those with security issues.
160 supportedHostKeyAlgos = []string{
161 CertAlgoRSASHA256v01,
162 CertAlgoRSASHA512v01,
163 CertAlgoECDSA256v01,
164 CertAlgoECDSA384v01,
165 CertAlgoECDSA521v01,
166 CertAlgoED25519v01,
167 KeyAlgoRSASHA256,
168 KeyAlgoRSASHA512,
169 KeyAlgoECDSA256,
170 KeyAlgoECDSA384,
171 KeyAlgoECDSA521,
172 KeyAlgoED25519,
173 }
174 // defaultHostKeyAlgos specifies the default preference for host-key
175 // algorithms in preference order.
176 defaultHostKeyAlgos = []string{
177 CertAlgoRSASHA256v01,
178 CertAlgoRSASHA512v01,
179 CertAlgoRSAv01,
180 InsecureCertAlgoDSAv01,
181 CertAlgoECDSA256v01,
182 CertAlgoECDSA384v01,
183 CertAlgoECDSA521v01,
184 CertAlgoED25519v01,
185 KeyAlgoECDSA256,
186 KeyAlgoECDSA384,
187 KeyAlgoECDSA521,
188 KeyAlgoRSASHA256,
189 KeyAlgoRSASHA512,
190 KeyAlgoRSA,
191 InsecureKeyAlgoDSA,
192 KeyAlgoED25519,
193 }
194 // insecureHostKeyAlgos specifies host-key algorithms implemented by this
195 // package and which have security issues.
196 insecureHostKeyAlgos = []string{
197 KeyAlgoRSA,
198 InsecureKeyAlgoDSA,
199 CertAlgoRSAv01,
200 InsecureCertAlgoDSAv01,
201 }
202 // supportedPubKeyAuthAlgos specifies the supported client public key
203 // authentication algorithms. Note that this doesn't include certificate
204 // types since those use the underlying algorithm. Order is irrelevant.
205 supportedPubKeyAuthAlgos = []string{
206 KeyAlgoED25519,
207 KeyAlgoSKED25519,
208 KeyAlgoSKECDSA256,
209 KeyAlgoECDSA256,
210 KeyAlgoECDSA384,
211 KeyAlgoECDSA521,
212 KeyAlgoRSASHA256,
213 KeyAlgoRSASHA512,
214 }
215
216 // defaultPubKeyAuthAlgos specifies the preferred client public key
217 // authentication algorithms. This list is sent to the client if it supports
218 // the server-sig-algs extension. Order is irrelevant.
219 defaultPubKeyAuthAlgos = []string{
220 KeyAlgoED25519,
221 KeyAlgoSKED25519,
222 KeyAlgoSKECDSA256,
223 KeyAlgoECDSA256,
224 KeyAlgoECDSA384,
225 KeyAlgoECDSA521,
226 KeyAlgoRSASHA256,
227 KeyAlgoRSASHA512,
228 KeyAlgoRSA,
229 InsecureKeyAlgoDSA,
230 }
231 // insecurePubKeyAuthAlgos specifies client public key authentication
232 // algorithms implemented by this package and which have security issues.
233 insecurePubKeyAuthAlgos = []string{
234 KeyAlgoRSA,
235 InsecureKeyAlgoDSA,
236 }
237)
238
239// NegotiatedAlgorithms defines algorithms negotiated between client and server.
240type NegotiatedAlgorithms struct {
241 KeyExchange string
242 HostKey string
243 Read DirectionAlgorithms
244 Write DirectionAlgorithms
245}
246
247// Algorithms defines a set of algorithms that can be configured in the client
248// or server config for negotiation during a handshake.
249type Algorithms struct {
250 KeyExchanges []string
251 Ciphers []string
252 MACs []string
253 HostKeys []string
254 PublicKeyAuths []string
255}
256
257// SupportedAlgorithms returns algorithms currently implemented by this package,
258// excluding those with security issues, which are returned by
259// InsecureAlgorithms. The algorithms listed here are in preference order.
260func SupportedAlgorithms() Algorithms {
261 return Algorithms{
262 Ciphers: slices.Clone(supportedCiphers),
263 MACs: slices.Clone(supportedMACs),
264 KeyExchanges: slices.Clone(supportedKexAlgos),
265 HostKeys: slices.Clone(supportedHostKeyAlgos),
266 PublicKeyAuths: slices.Clone(supportedPubKeyAuthAlgos),
267 }
268}
269
270// InsecureAlgorithms returns algorithms currently implemented by this package
271// and which have security issues.
272func InsecureAlgorithms() Algorithms {
273 return Algorithms{
274 KeyExchanges: slices.Clone(insecureKexAlgos),
275 Ciphers: slices.Clone(insecureCiphers),
276 MACs: slices.Clone(insecureMACs),
277 HostKeys: slices.Clone(insecureHostKeyAlgos),
278 PublicKeyAuths: slices.Clone(insecurePubKeyAuthAlgos),
279 }
280}
281
282var supportedCompressions = []string{compressionNone}
283
284// hashFuncs keeps the mapping of supported signature algorithms to their
285// respective hashes needed for signing and verification.
286var hashFuncs = map[string]crypto.Hash{
287 KeyAlgoRSA: crypto.SHA1,
288 KeyAlgoRSASHA256: crypto.SHA256,
289 KeyAlgoRSASHA512: crypto.SHA512,
290 InsecureKeyAlgoDSA: crypto.SHA1,
291 KeyAlgoECDSA256: crypto.SHA256,
292 KeyAlgoECDSA384: crypto.SHA384,
293 KeyAlgoECDSA521: crypto.SHA512,
294 // KeyAlgoED25519 doesn't pre-hash.
295 KeyAlgoSKECDSA256: crypto.SHA256,
296 KeyAlgoSKED25519: crypto.SHA256,
297}
298
299// algorithmsForKeyFormat returns the supported signature algorithms for a given
300// public key format (PublicKey.Type), in order of preference. See RFC 8332,
301// Section 2. See also the note in sendKexInit on backwards compatibility.
302func algorithmsForKeyFormat(keyFormat string) []string {
303 switch keyFormat {
304 case KeyAlgoRSA:
305 return []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA}
306 case CertAlgoRSAv01:
307 return []string{CertAlgoRSASHA256v01, CertAlgoRSASHA512v01, CertAlgoRSAv01}
308 default:
309 return []string{keyFormat}
310 }
311}
312
313// isRSA returns whether algo is a supported RSA algorithm, including certificate
314// algorithms.
315func isRSA(algo string) bool {
316 algos := algorithmsForKeyFormat(KeyAlgoRSA)
317 return contains(algos, underlyingAlgo(algo))
318}
319
320func isRSACert(algo string) bool {
321 _, ok := certKeyAlgoNames[algo]
322 if !ok {
323 return false
324 }
325 return isRSA(algo)
326}
327
328// unexpectedMessageError results when the SSH message that we received didn't
329// match what we wanted.
330func unexpectedMessageError(expected, got uint8) error {
331 return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected)
332}
333
334// parseError results from a malformed SSH message.
335func parseError(tag uint8) error {
336 return fmt.Errorf("ssh: parse error in message type %d", tag)
337}
338
339func findCommon(what string, client []string, server []string, isClient bool) (string, error) {
340 for _, c := range client {
341 for _, s := range server {
342 if c == s {
343 return c, nil
344 }
345 }
346 }
347 err := &AlgorithmNegotiationError{
348 What: what,
349 }
350 if isClient {
351 err.SupportedAlgorithms = client
352 err.RequestedAlgorithms = server
353 } else {
354 err.SupportedAlgorithms = server
355 err.RequestedAlgorithms = client
356 }
357 return "", err
358}
359
360// AlgorithmNegotiationError defines the error returned if the client and the
361// server cannot agree on an algorithm for key exchange, host key, cipher, MAC.
362type AlgorithmNegotiationError struct {
363 What string
364 // RequestedAlgorithms lists the algorithms supported by the peer.
365 RequestedAlgorithms []string
366 // SupportedAlgorithms lists the algorithms supported on our side.
367 SupportedAlgorithms []string
368}
369
370func (a *AlgorithmNegotiationError) Error() string {
371 return fmt.Sprintf("ssh: no common algorithm for %s; we offered: %v, peer offered: %v",
372 a.What, a.SupportedAlgorithms, a.RequestedAlgorithms)
373}
374
375// DirectionAlgorithms defines the algorithms negotiated in one direction
376// (either read or write).
377type DirectionAlgorithms struct {
378 Cipher string
379 MAC string
380 compression string
381}
382
383// rekeyBytes returns a rekeying intervals in bytes.
384func (a *DirectionAlgorithms) rekeyBytes() int64 {
385 // According to RFC 4344 block ciphers should rekey after
386 // 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is
387 // 128.
388 switch a.Cipher {
389 case CipherAES128CTR, CipherAES192CTR, CipherAES256CTR, CipherAES128GCM, CipherAES256GCM, InsecureCipherAES128CBC:
390 return 16 * (1 << 32)
391
392 }
393
394 // For others, stick with RFC 4253 recommendation to rekey after 1 Gb of data.
395 return 1 << 30
396}
397
398var aeadCiphers = map[string]bool{
399 CipherAES128GCM: true,
400 CipherAES256GCM: true,
401 CipherChaCha20Poly1305: true,
402}
403
404func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMsg) (algs *NegotiatedAlgorithms, err error) {
405 result := &NegotiatedAlgorithms{}
406
407 result.KeyExchange, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos, isClient)
408 if err != nil {
409 return
410 }
411
412 result.HostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos, isClient)
413 if err != nil {
414 return
415 }
416
417 stoc, ctos := &result.Write, &result.Read
418 if isClient {
419 ctos, stoc = stoc, ctos
420 }
421
422 ctos.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer, isClient)
423 if err != nil {
424 return
425 }
426
427 stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient, isClient)
428 if err != nil {
429 return
430 }
431
432 if !aeadCiphers[ctos.Cipher] {
433 ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer, isClient)
434 if err != nil {
435 return
436 }
437 }
438
439 if !aeadCiphers[stoc.Cipher] {
440 stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient, isClient)
441 if err != nil {
442 return
443 }
444 }
445
446 ctos.compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer, isClient)
447 if err != nil {
448 return
449 }
450
451 stoc.compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient, isClient)
452 if err != nil {
453 return
454 }
455
456 return result, nil
457}
458
459// If rekeythreshold is too small, we can't make any progress sending
460// stuff.
461const minRekeyThreshold uint64 = 256
462
463// Config contains configuration data common to both ServerConfig and
464// ClientConfig.
465type Config struct {
466 // Rand provides the source of entropy for cryptographic
467 // primitives. If Rand is nil, the cryptographic random reader
468 // in package crypto/rand will be used.
469 Rand io.Reader
470
471 // The maximum number of bytes sent or received after which a
472 // new key is negotiated. It must be at least 256. If
473 // unspecified, a size suitable for the chosen cipher is used.
474 RekeyThreshold uint64
475
476 // The allowed key exchanges algorithms. If unspecified then a default set
477 // of algorithms is used. Unsupported values are silently ignored.
478 KeyExchanges []string
479
480 // The allowed cipher algorithms. If unspecified then a sensible default is
481 // used. Unsupported values are silently ignored.
482 Ciphers []string
483
484 // The allowed MAC algorithms. If unspecified then a sensible default is
485 // used. Unsupported values are silently ignored.
486 MACs []string
487}
488
489// SetDefaults sets sensible values for unset fields in config. This is
490// exported for testing: Configs passed to SSH functions are copied and have
491// default values set automatically.
492func (c *Config) SetDefaults() {
493 if c.Rand == nil {
494 c.Rand = rand.Reader
495 }
496 if c.Ciphers == nil {
497 c.Ciphers = defaultCiphers
498 }
499 var ciphers []string
500 for _, c := range c.Ciphers {
501 if cipherModes[c] != nil {
502 // Ignore the cipher if we have no cipherModes definition.
503 ciphers = append(ciphers, c)
504 }
505 }
506 c.Ciphers = ciphers
507
508 if c.KeyExchanges == nil {
509 c.KeyExchanges = defaultKexAlgos
510 }
511 var kexs []string
512 for _, k := range c.KeyExchanges {
513 if kexAlgoMap[k] != nil {
514 // Ignore the KEX if we have no kexAlgoMap definition.
515 kexs = append(kexs, k)
516 if k == KeyExchangeCurve25519 && !contains(c.KeyExchanges, keyExchangeCurve25519LibSSH) {
517 kexs = append(kexs, keyExchangeCurve25519LibSSH)
518 }
519 }
520 }
521 c.KeyExchanges = kexs
522
523 if c.MACs == nil {
524 c.MACs = defaultMACs
525 }
526 var macs []string
527 for _, m := range c.MACs {
528 if macModes[m] != nil {
529 // Ignore the MAC if we have no macModes definition.
530 macs = append(macs, m)
531 }
532 }
533 c.MACs = macs
534
535 if c.RekeyThreshold == 0 {
536 // cipher specific default
537 } else if c.RekeyThreshold < minRekeyThreshold {
538 c.RekeyThreshold = minRekeyThreshold
539 } else if c.RekeyThreshold >= math.MaxInt64 {
540 // Avoid weirdness if somebody uses -1 as a threshold.
541 c.RekeyThreshold = math.MaxInt64
542 }
543}
544
545// buildDataSignedForAuth returns the data that is signed in order to prove
546// possession of a private key. See RFC 4252, section 7. algo is the advertised
547// algorithm, and may be a certificate type.
548func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo string, pubKey []byte) []byte {
549 data := struct {
550 Session []byte
551 Type byte
552 User string
553 Service string
554 Method string
555 Sign bool
556 Algo string
557 PubKey []byte
558 }{
559 sessionID,
560 msgUserAuthRequest,
561 req.User,
562 req.Service,
563 req.Method,
564 true,
565 algo,
566 pubKey,
567 }
568 return Marshal(data)
569}
570
571func appendU16(buf []byte, n uint16) []byte {
572 return append(buf, byte(n>>8), byte(n))
573}
574
575func appendU32(buf []byte, n uint32) []byte {
576 return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
577}
578
579func appendU64(buf []byte, n uint64) []byte {
580 return append(buf,
581 byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32),
582 byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
583}
584
585func appendInt(buf []byte, n int) []byte {
586 return appendU32(buf, uint32(n))
587}
588
589func appendString(buf []byte, s string) []byte {
590 buf = appendU32(buf, uint32(len(s)))
591 buf = append(buf, s...)
592 return buf
593}
594
595func appendBool(buf []byte, b bool) []byte {
596 if b {
597 return append(buf, 1)
598 }
599 return append(buf, 0)
600}
601
602// newCond is a helper to hide the fact that there is no usable zero
603// value for sync.Cond.
604func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
605
606// window represents the buffer available to clients
607// wishing to write to a channel.
608type window struct {
609 *sync.Cond
610 win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1
611 writeWaiters int
612 closed bool
613}
614
615// add adds win to the amount of window available
616// for consumers.
617func (w *window) add(win uint32) bool {
618 // a zero sized window adjust is a noop.
619 if win == 0 {
620 return true
621 }
622 w.L.Lock()
623 if w.win+win < win {
624 w.L.Unlock()
625 return false
626 }
627 w.win += win
628 // It is unusual that multiple goroutines would be attempting to reserve
629 // window space, but not guaranteed. Use broadcast to notify all waiters
630 // that additional window is available.
631 w.Broadcast()
632 w.L.Unlock()
633 return true
634}
635
636// close sets the window to closed, so all reservations fail
637// immediately.
638func (w *window) close() {
639 w.L.Lock()
640 w.closed = true
641 w.Broadcast()
642 w.L.Unlock()
643}
644
645// reserve reserves win from the available window capacity.
646// If no capacity remains, reserve will block. reserve may
647// return less than requested.
648func (w *window) reserve(win uint32) (uint32, error) {
649 var err error
650 w.L.Lock()
651 w.writeWaiters++
652 w.Broadcast()
653 for w.win == 0 && !w.closed {
654 w.Wait()
655 }
656 w.writeWaiters--
657 if w.win < win {
658 win = w.win
659 }
660 w.win -= win
661 if w.closed {
662 err = io.EOF
663 }
664 w.L.Unlock()
665 return win, err
666}
667
668// waitWriterBlocked waits until some goroutine is blocked for further
669// writes. It is used in tests only.
670func (w *window) waitWriterBlocked() {
671 w.Cond.L.Lock()
672 for w.writeWaiters == 0 {
673 w.Cond.Wait()
674 }
675 w.Cond.L.Unlock()
676}