kex.go raw

   1  // Copyright 2013 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/ecdsa"
  10  	"crypto/elliptic"
  11  	"crypto/fips140"
  12  	"crypto/rand"
  13  	"encoding/binary"
  14  	"errors"
  15  	"fmt"
  16  	"io"
  17  	"math/big"
  18  	"slices"
  19  
  20  	"golang.org/x/crypto/curve25519"
  21  )
  22  
  23  const (
  24  	// This is the group called diffie-hellman-group1-sha1 in RFC 4253 and
  25  	// Oakley Group 2 in RFC 2409.
  26  	oakleyGroup2 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
  27  	// This is the group called diffie-hellman-group14-sha1 in RFC 4253 and
  28  	// Oakley Group 14 in RFC 3526.
  29  	oakleyGroup14 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF"
  30  	// This is the group called diffie-hellman-group15-sha512 in RFC 8268 and
  31  	// Oakley Group 15 in RFC 3526.
  32  	oakleyGroup15 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF"
  33  	// This is the group called diffie-hellman-group16-sha512 in RFC 8268 and
  34  	// Oakley Group 16 in RFC 3526.
  35  	oakleyGroup16 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF"
  36  )
  37  
  38  // kexResult captures the outcome of a key exchange.
  39  type kexResult struct {
  40  	// Session hash. See also RFC 4253, section 8.
  41  	H []byte
  42  
  43  	// Shared secret. See also RFC 4253, section 8.
  44  	K []byte
  45  
  46  	// Host key as hashed into H.
  47  	HostKey []byte
  48  
  49  	// Signature of H.
  50  	Signature []byte
  51  
  52  	// A cryptographic hash function that matches the security
  53  	// level of the key exchange algorithm. It is used for
  54  	// calculating H, and for deriving keys from H and K.
  55  	Hash crypto.Hash
  56  
  57  	// The session ID, which is the first H computed. This is used
  58  	// to derive key material inside the transport.
  59  	SessionID []byte
  60  }
  61  
  62  // handshakeMagics contains data that is always included in the
  63  // session hash.
  64  type handshakeMagics struct {
  65  	clientVersion, serverVersion []byte
  66  	clientKexInit, serverKexInit []byte
  67  }
  68  
  69  func (m *handshakeMagics) write(w io.Writer) {
  70  	writeString(w, m.clientVersion)
  71  	writeString(w, m.serverVersion)
  72  	writeString(w, m.clientKexInit)
  73  	writeString(w, m.serverKexInit)
  74  }
  75  
  76  // kexAlgorithm abstracts different key exchange algorithms.
  77  type kexAlgorithm interface {
  78  	// Server runs server-side key agreement, signing the result
  79  	// with a hostkey. algo is the negotiated algorithm, and may
  80  	// be a certificate type.
  81  	Server(p packetConn, rand io.Reader, magics *handshakeMagics, s AlgorithmSigner, algo string) (*kexResult, error)
  82  
  83  	// Client runs the client-side key agreement. Caller is
  84  	// responsible for verifying the host key signature.
  85  	Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error)
  86  }
  87  
  88  // dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
  89  type dhGroup struct {
  90  	g, p, pMinus1 *big.Int
  91  	hashFunc      crypto.Hash
  92  }
  93  
  94  func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
  95  	if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 {
  96  		return nil, errors.New("ssh: DH parameter out of bounds")
  97  	}
  98  	return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
  99  }
 100  
 101  func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
 102  	var x *big.Int
 103  	for {
 104  		var err error
 105  		if x, err = rand.Int(randSource, group.pMinus1); err != nil {
 106  			return nil, err
 107  		}
 108  		if x.Sign() > 0 {
 109  			break
 110  		}
 111  	}
 112  
 113  	X := new(big.Int).Exp(group.g, x, group.p)
 114  	kexDHInit := kexDHInitMsg{
 115  		X: X,
 116  	}
 117  	if err := c.writePacket(Marshal(&kexDHInit)); err != nil {
 118  		return nil, err
 119  	}
 120  
 121  	packet, err := c.readPacket()
 122  	if err != nil {
 123  		return nil, err
 124  	}
 125  
 126  	var kexDHReply kexDHReplyMsg
 127  	if err = Unmarshal(packet, &kexDHReply); err != nil {
 128  		return nil, err
 129  	}
 130  
 131  	ki, err := group.diffieHellman(kexDHReply.Y, x)
 132  	if err != nil {
 133  		return nil, err
 134  	}
 135  
 136  	h := group.hashFunc.New()
 137  	magics.write(h)
 138  	writeString(h, kexDHReply.HostKey)
 139  	writeInt(h, X)
 140  	writeInt(h, kexDHReply.Y)
 141  	K := make([]byte, intLength(ki))
 142  	marshalInt(K, ki)
 143  	h.Write(K)
 144  
 145  	return &kexResult{
 146  		H:         h.Sum(nil),
 147  		K:         K,
 148  		HostKey:   kexDHReply.HostKey,
 149  		Signature: kexDHReply.Signature,
 150  		Hash:      group.hashFunc,
 151  	}, nil
 152  }
 153  
 154  func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
 155  	packet, err := c.readPacket()
 156  	if err != nil {
 157  		return
 158  	}
 159  	var kexDHInit kexDHInitMsg
 160  	if err = Unmarshal(packet, &kexDHInit); err != nil {
 161  		return
 162  	}
 163  
 164  	var y *big.Int
 165  	for {
 166  		if y, err = rand.Int(randSource, group.pMinus1); err != nil {
 167  			return
 168  		}
 169  		if y.Sign() > 0 {
 170  			break
 171  		}
 172  	}
 173  
 174  	Y := new(big.Int).Exp(group.g, y, group.p)
 175  	ki, err := group.diffieHellman(kexDHInit.X, y)
 176  	if err != nil {
 177  		return nil, err
 178  	}
 179  
 180  	hostKeyBytes := priv.PublicKey().Marshal()
 181  
 182  	h := group.hashFunc.New()
 183  	magics.write(h)
 184  	writeString(h, hostKeyBytes)
 185  	writeInt(h, kexDHInit.X)
 186  	writeInt(h, Y)
 187  
 188  	K := make([]byte, intLength(ki))
 189  	marshalInt(K, ki)
 190  	h.Write(K)
 191  
 192  	H := h.Sum(nil)
 193  
 194  	// H is already a hash, but the hostkey signing will apply its
 195  	// own key-specific hash algorithm.
 196  	sig, err := signAndMarshal(priv, randSource, H, algo)
 197  	if err != nil {
 198  		return nil, err
 199  	}
 200  
 201  	kexDHReply := kexDHReplyMsg{
 202  		HostKey:   hostKeyBytes,
 203  		Y:         Y,
 204  		Signature: sig,
 205  	}
 206  	packet = Marshal(&kexDHReply)
 207  
 208  	err = c.writePacket(packet)
 209  	return &kexResult{
 210  		H:         H,
 211  		K:         K,
 212  		HostKey:   hostKeyBytes,
 213  		Signature: sig,
 214  		Hash:      group.hashFunc,
 215  	}, err
 216  }
 217  
 218  // ecdh performs Elliptic Curve Diffie-Hellman key exchange as
 219  // described in RFC 5656, section 4.
 220  type ecdh struct {
 221  	curve elliptic.Curve
 222  }
 223  
 224  func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
 225  	ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
 226  	if err != nil {
 227  		return nil, err
 228  	}
 229  
 230  	kexInit := kexECDHInitMsg{
 231  		ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y),
 232  	}
 233  
 234  	serialized := Marshal(&kexInit)
 235  	if err := c.writePacket(serialized); err != nil {
 236  		return nil, err
 237  	}
 238  
 239  	packet, err := c.readPacket()
 240  	if err != nil {
 241  		return nil, err
 242  	}
 243  
 244  	var reply kexECDHReplyMsg
 245  	if err = Unmarshal(packet, &reply); err != nil {
 246  		return nil, err
 247  	}
 248  
 249  	x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey)
 250  	if err != nil {
 251  		return nil, err
 252  	}
 253  
 254  	// generate shared secret
 255  	secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes())
 256  
 257  	h := ecHash(kex.curve).New()
 258  	magics.write(h)
 259  	writeString(h, reply.HostKey)
 260  	writeString(h, kexInit.ClientPubKey)
 261  	writeString(h, reply.EphemeralPubKey)
 262  	K := make([]byte, intLength(secret))
 263  	marshalInt(K, secret)
 264  	h.Write(K)
 265  
 266  	return &kexResult{
 267  		H:         h.Sum(nil),
 268  		K:         K,
 269  		HostKey:   reply.HostKey,
 270  		Signature: reply.Signature,
 271  		Hash:      ecHash(kex.curve),
 272  	}, nil
 273  }
 274  
 275  // unmarshalECKey parses and checks an EC key.
 276  func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) {
 277  	x, y = elliptic.Unmarshal(curve, pubkey)
 278  	if x == nil {
 279  		return nil, nil, errors.New("ssh: elliptic.Unmarshal failure")
 280  	}
 281  	if !validateECPublicKey(curve, x, y) {
 282  		return nil, nil, errors.New("ssh: public key not on curve")
 283  	}
 284  	return x, y, nil
 285  }
 286  
 287  // validateECPublicKey checks that the point is a valid public key for
 288  // the given curve. See [SEC1], 3.2.2
 289  func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool {
 290  	if x.Sign() == 0 && y.Sign() == 0 {
 291  		return false
 292  	}
 293  
 294  	if x.Cmp(curve.Params().P) >= 0 {
 295  		return false
 296  	}
 297  
 298  	if y.Cmp(curve.Params().P) >= 0 {
 299  		return false
 300  	}
 301  
 302  	if !curve.IsOnCurve(x, y) {
 303  		return false
 304  	}
 305  
 306  	// We don't check if N * PubKey == 0, since
 307  	//
 308  	// - the NIST curves have cofactor = 1, so this is implicit.
 309  	// (We don't foresee an implementation that supports non NIST
 310  	// curves)
 311  	//
 312  	// - for ephemeral keys, we don't need to worry about small
 313  	// subgroup attacks.
 314  	return true
 315  }
 316  
 317  func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
 318  	packet, err := c.readPacket()
 319  	if err != nil {
 320  		return nil, err
 321  	}
 322  
 323  	var kexECDHInit kexECDHInitMsg
 324  	if err = Unmarshal(packet, &kexECDHInit); err != nil {
 325  		return nil, err
 326  	}
 327  
 328  	clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey)
 329  	if err != nil {
 330  		return nil, err
 331  	}
 332  
 333  	// We could cache this key across multiple users/multiple
 334  	// connection attempts, but the benefit is small. OpenSSH
 335  	// generates a new key for each incoming connection.
 336  	ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
 337  	if err != nil {
 338  		return nil, err
 339  	}
 340  
 341  	hostKeyBytes := priv.PublicKey().Marshal()
 342  
 343  	serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y)
 344  
 345  	// generate shared secret
 346  	secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes())
 347  
 348  	h := ecHash(kex.curve).New()
 349  	magics.write(h)
 350  	writeString(h, hostKeyBytes)
 351  	writeString(h, kexECDHInit.ClientPubKey)
 352  	writeString(h, serializedEphKey)
 353  
 354  	K := make([]byte, intLength(secret))
 355  	marshalInt(K, secret)
 356  	h.Write(K)
 357  
 358  	H := h.Sum(nil)
 359  
 360  	// H is already a hash, but the hostkey signing will apply its
 361  	// own key-specific hash algorithm.
 362  	sig, err := signAndMarshal(priv, rand, H, algo)
 363  	if err != nil {
 364  		return nil, err
 365  	}
 366  
 367  	reply := kexECDHReplyMsg{
 368  		EphemeralPubKey: serializedEphKey,
 369  		HostKey:         hostKeyBytes,
 370  		Signature:       sig,
 371  	}
 372  
 373  	serialized := Marshal(&reply)
 374  	if err := c.writePacket(serialized); err != nil {
 375  		return nil, err
 376  	}
 377  
 378  	return &kexResult{
 379  		H:         H,
 380  		K:         K,
 381  		HostKey:   reply.HostKey,
 382  		Signature: sig,
 383  		Hash:      ecHash(kex.curve),
 384  	}, nil
 385  }
 386  
 387  // ecHash returns the hash to match the given elliptic curve, see RFC
 388  // 5656, section 6.2.1
 389  func ecHash(curve elliptic.Curve) crypto.Hash {
 390  	bitSize := curve.Params().BitSize
 391  	switch {
 392  	case bitSize <= 256:
 393  		return crypto.SHA256
 394  	case bitSize <= 384:
 395  		return crypto.SHA384
 396  	}
 397  	return crypto.SHA512
 398  }
 399  
 400  // kexAlgoMap defines the supported KEXs. KEXs not included are not supported
 401  // and will not be negotiated, even if explicitly configured. When FIPS mode is
 402  // enabled, only FIPS-approved algorithms are included.
 403  var kexAlgoMap = map[string]kexAlgorithm{}
 404  
 405  func init() {
 406  	// mlkem768x25519-sha256 we'll work with fips140=on but not fips140=only
 407  	// until Go 1.26.
 408  	kexAlgoMap[KeyExchangeMLKEM768X25519] = &mlkem768WithCurve25519sha256{}
 409  	kexAlgoMap[KeyExchangeECDHP521] = &ecdh{elliptic.P521()}
 410  	kexAlgoMap[KeyExchangeECDHP384] = &ecdh{elliptic.P384()}
 411  	kexAlgoMap[KeyExchangeECDHP256] = &ecdh{elliptic.P256()}
 412  
 413  	if fips140.Enabled() {
 414  		defaultKexAlgos = slices.DeleteFunc(defaultKexAlgos, func(algo string) bool {
 415  			_, ok := kexAlgoMap[algo]
 416  			return !ok
 417  		})
 418  		return
 419  	}
 420  
 421  	p, _ := new(big.Int).SetString(oakleyGroup2, 16)
 422  	kexAlgoMap[InsecureKeyExchangeDH1SHA1] = &dhGroup{
 423  		g:        new(big.Int).SetInt64(2),
 424  		p:        p,
 425  		pMinus1:  new(big.Int).Sub(p, bigOne),
 426  		hashFunc: crypto.SHA1,
 427  	}
 428  
 429  	p, _ = new(big.Int).SetString(oakleyGroup14, 16)
 430  	group14 := &dhGroup{
 431  		g:       new(big.Int).SetInt64(2),
 432  		p:       p,
 433  		pMinus1: new(big.Int).Sub(p, bigOne),
 434  	}
 435  
 436  	kexAlgoMap[InsecureKeyExchangeDH14SHA1] = &dhGroup{
 437  		g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
 438  		hashFunc: crypto.SHA1,
 439  	}
 440  	kexAlgoMap[KeyExchangeDH14SHA256] = &dhGroup{
 441  		g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
 442  		hashFunc: crypto.SHA256,
 443  	}
 444  
 445  	p, _ = new(big.Int).SetString(oakleyGroup16, 16)
 446  
 447  	kexAlgoMap[KeyExchangeDH16SHA512] = &dhGroup{
 448  		g:        new(big.Int).SetInt64(2),
 449  		p:        p,
 450  		pMinus1:  new(big.Int).Sub(p, bigOne),
 451  		hashFunc: crypto.SHA512,
 452  	}
 453  
 454  	kexAlgoMap[KeyExchangeCurve25519] = &curve25519sha256{}
 455  	kexAlgoMap[keyExchangeCurve25519LibSSH] = &curve25519sha256{}
 456  	kexAlgoMap[InsecureKeyExchangeDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1}
 457  	kexAlgoMap[KeyExchangeDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256}
 458  }
 459  
 460  // curve25519sha256 implements the curve25519-sha256 (formerly known as
 461  // curve25519-sha256@libssh.org) key exchange method, as described in RFC 8731.
 462  type curve25519sha256 struct{}
 463  
 464  type curve25519KeyPair struct {
 465  	priv [32]byte
 466  	pub  [32]byte
 467  }
 468  
 469  func (kp *curve25519KeyPair) generate(rand io.Reader) error {
 470  	if _, err := io.ReadFull(rand, kp.priv[:]); err != nil {
 471  		return err
 472  	}
 473  	p, err := curve25519.X25519(kp.priv[:], curve25519.Basepoint)
 474  	if err != nil {
 475  		return fmt.Errorf("curve25519: %w", err)
 476  	}
 477  	if len(p) != 32 {
 478  		return fmt.Errorf("curve25519: internal error: X25519 returned %d bytes, expected 32", len(p))
 479  	}
 480  	copy(kp.pub[:], p)
 481  	return nil
 482  }
 483  
 484  func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
 485  	var kp curve25519KeyPair
 486  	if err := kp.generate(rand); err != nil {
 487  		return nil, err
 488  	}
 489  	if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil {
 490  		return nil, err
 491  	}
 492  
 493  	packet, err := c.readPacket()
 494  	if err != nil {
 495  		return nil, err
 496  	}
 497  
 498  	var reply kexECDHReplyMsg
 499  	if err = Unmarshal(packet, &reply); err != nil {
 500  		return nil, err
 501  	}
 502  	if len(reply.EphemeralPubKey) != 32 {
 503  		return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
 504  	}
 505  
 506  	secret, err := curve25519.X25519(kp.priv[:], reply.EphemeralPubKey)
 507  	if err != nil {
 508  		return nil, fmt.Errorf("ssh: peer's curve25519 public value is not valid: %w", err)
 509  	}
 510  
 511  	h := crypto.SHA256.New()
 512  	magics.write(h)
 513  	writeString(h, reply.HostKey)
 514  	writeString(h, kp.pub[:])
 515  	writeString(h, reply.EphemeralPubKey)
 516  
 517  	ki := new(big.Int).SetBytes(secret[:])
 518  	K := make([]byte, intLength(ki))
 519  	marshalInt(K, ki)
 520  	h.Write(K)
 521  
 522  	return &kexResult{
 523  		H:         h.Sum(nil),
 524  		K:         K,
 525  		HostKey:   reply.HostKey,
 526  		Signature: reply.Signature,
 527  		Hash:      crypto.SHA256,
 528  	}, nil
 529  }
 530  
 531  func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
 532  	packet, err := c.readPacket()
 533  	if err != nil {
 534  		return
 535  	}
 536  	var kexInit kexECDHInitMsg
 537  	if err = Unmarshal(packet, &kexInit); err != nil {
 538  		return
 539  	}
 540  
 541  	if len(kexInit.ClientPubKey) != 32 {
 542  		return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
 543  	}
 544  
 545  	var kp curve25519KeyPair
 546  	if err := kp.generate(rand); err != nil {
 547  		return nil, err
 548  	}
 549  
 550  	secret, err := curve25519.X25519(kp.priv[:], kexInit.ClientPubKey)
 551  	if err != nil {
 552  		return nil, fmt.Errorf("ssh: peer's curve25519 public value is not valid: %w", err)
 553  	}
 554  
 555  	hostKeyBytes := priv.PublicKey().Marshal()
 556  
 557  	h := crypto.SHA256.New()
 558  	magics.write(h)
 559  	writeString(h, hostKeyBytes)
 560  	writeString(h, kexInit.ClientPubKey)
 561  	writeString(h, kp.pub[:])
 562  
 563  	ki := new(big.Int).SetBytes(secret[:])
 564  	K := make([]byte, intLength(ki))
 565  	marshalInt(K, ki)
 566  	h.Write(K)
 567  
 568  	H := h.Sum(nil)
 569  
 570  	sig, err := signAndMarshal(priv, rand, H, algo)
 571  	if err != nil {
 572  		return nil, err
 573  	}
 574  
 575  	reply := kexECDHReplyMsg{
 576  		EphemeralPubKey: kp.pub[:],
 577  		HostKey:         hostKeyBytes,
 578  		Signature:       sig,
 579  	}
 580  	if err := c.writePacket(Marshal(&reply)); err != nil {
 581  		return nil, err
 582  	}
 583  	return &kexResult{
 584  		H:         H,
 585  		K:         K,
 586  		HostKey:   hostKeyBytes,
 587  		Signature: sig,
 588  		Hash:      crypto.SHA256,
 589  	}, nil
 590  }
 591  
 592  // dhGEXSHA implements the diffie-hellman-group-exchange-sha1 and
 593  // diffie-hellman-group-exchange-sha256 key agreement protocols,
 594  // as described in RFC 4419
 595  type dhGEXSHA struct {
 596  	hashFunc crypto.Hash
 597  }
 598  
 599  const (
 600  	dhGroupExchangeMinimumBits   = 2048
 601  	dhGroupExchangePreferredBits = 2048
 602  	dhGroupExchangeMaximumBits   = 8192
 603  )
 604  
 605  func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
 606  	// Send GexRequest
 607  	kexDHGexRequest := kexDHGexRequestMsg{
 608  		MinBits:       dhGroupExchangeMinimumBits,
 609  		PreferredBits: dhGroupExchangePreferredBits,
 610  		MaxBits:       dhGroupExchangeMaximumBits,
 611  	}
 612  	if err := c.writePacket(Marshal(&kexDHGexRequest)); err != nil {
 613  		return nil, err
 614  	}
 615  
 616  	// Receive GexGroup
 617  	packet, err := c.readPacket()
 618  	if err != nil {
 619  		return nil, err
 620  	}
 621  
 622  	var msg kexDHGexGroupMsg
 623  	if err = Unmarshal(packet, &msg); err != nil {
 624  		return nil, err
 625  	}
 626  
 627  	// reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits
 628  	if msg.P.BitLen() < dhGroupExchangeMinimumBits || msg.P.BitLen() > dhGroupExchangeMaximumBits {
 629  		return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", msg.P.BitLen())
 630  	}
 631  
 632  	// Check if g is safe by verifying that 1 < g < p-1
 633  	pMinusOne := new(big.Int).Sub(msg.P, bigOne)
 634  	if msg.G.Cmp(bigOne) <= 0 || msg.G.Cmp(pMinusOne) >= 0 {
 635  		return nil, fmt.Errorf("ssh: server provided gex g is not safe")
 636  	}
 637  
 638  	// Send GexInit
 639  	pHalf := new(big.Int).Rsh(msg.P, 1)
 640  	x, err := rand.Int(randSource, pHalf)
 641  	if err != nil {
 642  		return nil, err
 643  	}
 644  	X := new(big.Int).Exp(msg.G, x, msg.P)
 645  	kexDHGexInit := kexDHGexInitMsg{
 646  		X: X,
 647  	}
 648  	if err := c.writePacket(Marshal(&kexDHGexInit)); err != nil {
 649  		return nil, err
 650  	}
 651  
 652  	// Receive GexReply
 653  	packet, err = c.readPacket()
 654  	if err != nil {
 655  		return nil, err
 656  	}
 657  
 658  	var kexDHGexReply kexDHGexReplyMsg
 659  	if err = Unmarshal(packet, &kexDHGexReply); err != nil {
 660  		return nil, err
 661  	}
 662  
 663  	if kexDHGexReply.Y.Cmp(bigOne) <= 0 || kexDHGexReply.Y.Cmp(pMinusOne) >= 0 {
 664  		return nil, errors.New("ssh: DH parameter out of bounds")
 665  	}
 666  	kInt := new(big.Int).Exp(kexDHGexReply.Y, x, msg.P)
 667  
 668  	// Check if k is safe by verifying that k > 1 and k < p - 1
 669  	if kInt.Cmp(bigOne) <= 0 || kInt.Cmp(pMinusOne) >= 0 {
 670  		return nil, fmt.Errorf("ssh: derived k is not safe")
 671  	}
 672  
 673  	h := gex.hashFunc.New()
 674  	magics.write(h)
 675  	writeString(h, kexDHGexReply.HostKey)
 676  	binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
 677  	binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
 678  	binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
 679  	writeInt(h, msg.P)
 680  	writeInt(h, msg.G)
 681  	writeInt(h, X)
 682  	writeInt(h, kexDHGexReply.Y)
 683  	K := make([]byte, intLength(kInt))
 684  	marshalInt(K, kInt)
 685  	h.Write(K)
 686  
 687  	return &kexResult{
 688  		H:         h.Sum(nil),
 689  		K:         K,
 690  		HostKey:   kexDHGexReply.HostKey,
 691  		Signature: kexDHGexReply.Signature,
 692  		Hash:      gex.hashFunc,
 693  	}, nil
 694  }
 695  
 696  // Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256.
 697  func (gex *dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
 698  	// Receive GexRequest
 699  	packet, err := c.readPacket()
 700  	if err != nil {
 701  		return
 702  	}
 703  	var kexDHGexRequest kexDHGexRequestMsg
 704  	if err = Unmarshal(packet, &kexDHGexRequest); err != nil {
 705  		return
 706  	}
 707  	// We check that the request received is valid and that the MaxBits
 708  	// requested are at least equal to our supported minimum. This is the same
 709  	// check done in OpenSSH:
 710  	// https://github.com/openssh/openssh-portable/blob/80a2f64b/kexgexs.c#L94
 711  	//
 712  	// Furthermore, we also check that the required MinBits are less than or
 713  	// equal to 4096 because we can use up to Oakley Group 16.
 714  	if kexDHGexRequest.MaxBits < kexDHGexRequest.MinBits || kexDHGexRequest.PreferredBits < kexDHGexRequest.MinBits ||
 715  		kexDHGexRequest.MaxBits < kexDHGexRequest.PreferredBits || kexDHGexRequest.MaxBits < dhGroupExchangeMinimumBits ||
 716  		kexDHGexRequest.MinBits > 4096 {
 717  		return nil, fmt.Errorf("ssh: DH GEX request out of range, min: %d, max: %d, preferred: %d", kexDHGexRequest.MinBits,
 718  			kexDHGexRequest.MaxBits, kexDHGexRequest.PreferredBits)
 719  	}
 720  
 721  	var p *big.Int
 722  	// We hardcode sending Oakley Group 14 (2048 bits), Oakley Group 15 (3072
 723  	// bits) or Oakley Group 16 (4096 bits), based on the requested max size.
 724  	if kexDHGexRequest.MaxBits < 3072 {
 725  		p, _ = new(big.Int).SetString(oakleyGroup14, 16)
 726  	} else if kexDHGexRequest.MaxBits < 4096 {
 727  		p, _ = new(big.Int).SetString(oakleyGroup15, 16)
 728  	} else {
 729  		p, _ = new(big.Int).SetString(oakleyGroup16, 16)
 730  	}
 731  
 732  	g := big.NewInt(2)
 733  	msg := &kexDHGexGroupMsg{
 734  		P: p,
 735  		G: g,
 736  	}
 737  	if err := c.writePacket(Marshal(msg)); err != nil {
 738  		return nil, err
 739  	}
 740  
 741  	// Receive GexInit
 742  	packet, err = c.readPacket()
 743  	if err != nil {
 744  		return
 745  	}
 746  	var kexDHGexInit kexDHGexInitMsg
 747  	if err = Unmarshal(packet, &kexDHGexInit); err != nil {
 748  		return
 749  	}
 750  
 751  	pHalf := new(big.Int).Rsh(p, 1)
 752  
 753  	y, err := rand.Int(randSource, pHalf)
 754  	if err != nil {
 755  		return
 756  	}
 757  	Y := new(big.Int).Exp(g, y, p)
 758  
 759  	pMinusOne := new(big.Int).Sub(p, bigOne)
 760  	if kexDHGexInit.X.Cmp(bigOne) <= 0 || kexDHGexInit.X.Cmp(pMinusOne) >= 0 {
 761  		return nil, errors.New("ssh: DH parameter out of bounds")
 762  	}
 763  	kInt := new(big.Int).Exp(kexDHGexInit.X, y, p)
 764  
 765  	hostKeyBytes := priv.PublicKey().Marshal()
 766  
 767  	h := gex.hashFunc.New()
 768  	magics.write(h)
 769  	writeString(h, hostKeyBytes)
 770  	binary.Write(h, binary.BigEndian, kexDHGexRequest.MinBits)
 771  	binary.Write(h, binary.BigEndian, kexDHGexRequest.PreferredBits)
 772  	binary.Write(h, binary.BigEndian, kexDHGexRequest.MaxBits)
 773  	writeInt(h, p)
 774  	writeInt(h, g)
 775  	writeInt(h, kexDHGexInit.X)
 776  	writeInt(h, Y)
 777  
 778  	K := make([]byte, intLength(kInt))
 779  	marshalInt(K, kInt)
 780  	h.Write(K)
 781  
 782  	H := h.Sum(nil)
 783  
 784  	// H is already a hash, but the hostkey signing will apply its
 785  	// own key-specific hash algorithm.
 786  	sig, err := signAndMarshal(priv, randSource, H, algo)
 787  	if err != nil {
 788  		return nil, err
 789  	}
 790  
 791  	kexDHGexReply := kexDHGexReplyMsg{
 792  		HostKey:   hostKeyBytes,
 793  		Y:         Y,
 794  		Signature: sig,
 795  	}
 796  	packet = Marshal(&kexDHGexReply)
 797  
 798  	err = c.writePacket(packet)
 799  
 800  	return &kexResult{
 801  		H:         H,
 802  		K:         K,
 803  		HostKey:   hostKeyBytes,
 804  		Signature: sig,
 805  		Hash:      gex.hashFunc,
 806  	}, err
 807  }
 808