common.go raw

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