...

Source file src/golang.org/x/crypto/ssh/kex.go

Documentation: golang.org/x/crypto/ssh

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

View as plain text