github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/crypto/ssh/kex.go (about)

     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  	"errors"
    14  	"io"
    15  	"math/big"
    16  
    17  	"golang.org/x/crypto/curve25519"
    18  )
    19  
    20  const (
    21  	kexAlgoDH1SHA1          = "diffie-hellman-group1-sha1"
    22  	kexAlgoDH14SHA1         = "diffie-hellman-group14-sha1"
    23  	kexAlgoECDH256          = "ecdh-sha2-nistp256"
    24  	kexAlgoECDH384          = "ecdh-sha2-nistp384"
    25  	kexAlgoECDH521          = "ecdh-sha2-nistp521"
    26  	kexAlgoCurve25519SHA256 = "curve25519-sha256@libssh.org"
    27  )
    28  
    29  // kexResult captures the outcome of a key exchange.
    30  type kexResult struct {
    31  	// Session hash. See also RFC 4253, section 8.
    32  	H []byte
    33  
    34  	// Shared secret. See also RFC 4253, section 8.
    35  	K []byte
    36  
    37  	// Host key as hashed into H.
    38  	HostKey []byte
    39  
    40  	// Signature of H.
    41  	Signature []byte
    42  
    43  	// A cryptographic hash function that matches the security
    44  	// level of the key exchange algorithm. It is used for
    45  	// calculating H, and for deriving keys from H and K.
    46  	Hash crypto.Hash
    47  
    48  	// The session ID, which is the first H computed. This is used
    49  	// to signal data inside transport.
    50  	SessionID []byte
    51  }
    52  
    53  // handshakeMagics contains data that is always included in the
    54  // session hash.
    55  type handshakeMagics struct {
    56  	clientVersion, serverVersion []byte
    57  	clientKexInit, serverKexInit []byte
    58  }
    59  
    60  func (m *handshakeMagics) write(w io.Writer) {
    61  	writeString(w, m.clientVersion)
    62  	writeString(w, m.serverVersion)
    63  	writeString(w, m.clientKexInit)
    64  	writeString(w, m.serverKexInit)
    65  }
    66  
    67  // kexAlgorithm abstracts different key exchange algorithms.
    68  type kexAlgorithm interface {
    69  	// Server runs server-side key agreement, signing the result
    70  	// with a hostkey.
    71  	Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error)
    72  
    73  	// Client runs the client-side key agreement. Caller is
    74  	// responsible for verifying the host key signature.
    75  	Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error)
    76  }
    77  
    78  // dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
    79  type dhGroup struct {
    80  	g, p *big.Int
    81  }
    82  
    83  func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
    84  	if theirPublic.Sign() <= 0 || theirPublic.Cmp(group.p) >= 0 {
    85  		return nil, errors.New("ssh: DH parameter out of bounds")
    86  	}
    87  	return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
    88  }
    89  
    90  func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
    91  	hashFunc := crypto.SHA1
    92  
    93  	x, err := rand.Int(randSource, group.p)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  	X := new(big.Int).Exp(group.g, x, group.p)
    98  	kexDHInit := kexDHInitMsg{
    99  		X: X,
   100  	}
   101  	if err := c.writePacket(Marshal(&kexDHInit)); err != nil {
   102  		return nil, err
   103  	}
   104  
   105  	packet, err := c.readPacket()
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  
   110  	var kexDHReply kexDHReplyMsg
   111  	if err = Unmarshal(packet, &kexDHReply); err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	kInt, err := group.diffieHellman(kexDHReply.Y, x)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	h := hashFunc.New()
   121  	magics.write(h)
   122  	writeString(h, kexDHReply.HostKey)
   123  	writeInt(h, X)
   124  	writeInt(h, kexDHReply.Y)
   125  	K := make([]byte, intLength(kInt))
   126  	marshalInt(K, kInt)
   127  	h.Write(K)
   128  
   129  	return &kexResult{
   130  		H:         h.Sum(nil),
   131  		K:         K,
   132  		HostKey:   kexDHReply.HostKey,
   133  		Signature: kexDHReply.Signature,
   134  		Hash:      crypto.SHA1,
   135  	}, nil
   136  }
   137  
   138  func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
   139  	hashFunc := crypto.SHA1
   140  	packet, err := c.readPacket()
   141  	if err != nil {
   142  		return
   143  	}
   144  	var kexDHInit kexDHInitMsg
   145  	if err = Unmarshal(packet, &kexDHInit); err != nil {
   146  		return
   147  	}
   148  
   149  	y, err := rand.Int(randSource, group.p)
   150  	if err != nil {
   151  		return
   152  	}
   153  
   154  	Y := new(big.Int).Exp(group.g, y, group.p)
   155  	kInt, err := group.diffieHellman(kexDHInit.X, y)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  
   160  	hostKeyBytes := priv.PublicKey().Marshal()
   161  
   162  	h := hashFunc.New()
   163  	magics.write(h)
   164  	writeString(h, hostKeyBytes)
   165  	writeInt(h, kexDHInit.X)
   166  	writeInt(h, Y)
   167  
   168  	K := make([]byte, intLength(kInt))
   169  	marshalInt(K, kInt)
   170  	h.Write(K)
   171  
   172  	H := h.Sum(nil)
   173  
   174  	// H is already a hash, but the hostkey signing will apply its
   175  	// own key-specific hash algorithm.
   176  	sig, err := signAndMarshal(priv, randSource, H)
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  
   181  	kexDHReply := kexDHReplyMsg{
   182  		HostKey:   hostKeyBytes,
   183  		Y:         Y,
   184  		Signature: sig,
   185  	}
   186  	packet = Marshal(&kexDHReply)
   187  
   188  	err = c.writePacket(packet)
   189  	return &kexResult{
   190  		H:         H,
   191  		K:         K,
   192  		HostKey:   hostKeyBytes,
   193  		Signature: sig,
   194  		Hash:      crypto.SHA1,
   195  	}, nil
   196  }
   197  
   198  // ecdh performs Elliptic Curve Diffie-Hellman key exchange as
   199  // described in RFC 5656, section 4.
   200  type ecdh struct {
   201  	curve elliptic.Curve
   202  }
   203  
   204  func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
   205  	ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  
   210  	kexInit := kexECDHInitMsg{
   211  		ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y),
   212  	}
   213  
   214  	serialized := Marshal(&kexInit)
   215  	if err := c.writePacket(serialized); err != nil {
   216  		return nil, err
   217  	}
   218  
   219  	packet, err := c.readPacket()
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  
   224  	var reply kexECDHReplyMsg
   225  	if err = Unmarshal(packet, &reply); err != nil {
   226  		return nil, err
   227  	}
   228  
   229  	x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey)
   230  	if err != nil {
   231  		return nil, err
   232  	}
   233  
   234  	// generate shared secret
   235  	secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes())
   236  
   237  	h := ecHash(kex.curve).New()
   238  	magics.write(h)
   239  	writeString(h, reply.HostKey)
   240  	writeString(h, kexInit.ClientPubKey)
   241  	writeString(h, reply.EphemeralPubKey)
   242  	K := make([]byte, intLength(secret))
   243  	marshalInt(K, secret)
   244  	h.Write(K)
   245  
   246  	return &kexResult{
   247  		H:         h.Sum(nil),
   248  		K:         K,
   249  		HostKey:   reply.HostKey,
   250  		Signature: reply.Signature,
   251  		Hash:      ecHash(kex.curve),
   252  	}, nil
   253  }
   254  
   255  // unmarshalECKey parses and checks an EC key.
   256  func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) {
   257  	x, y = elliptic.Unmarshal(curve, pubkey)
   258  	if x == nil {
   259  		return nil, nil, errors.New("ssh: elliptic.Unmarshal failure")
   260  	}
   261  	if !validateECPublicKey(curve, x, y) {
   262  		return nil, nil, errors.New("ssh: public key not on curve")
   263  	}
   264  	return x, y, nil
   265  }
   266  
   267  // validateECPublicKey checks that the point is a valid public key for
   268  // the given curve. See [SEC1], 3.2.2
   269  func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool {
   270  	if x.Sign() == 0 && y.Sign() == 0 {
   271  		return false
   272  	}
   273  
   274  	if x.Cmp(curve.Params().P) >= 0 {
   275  		return false
   276  	}
   277  
   278  	if y.Cmp(curve.Params().P) >= 0 {
   279  		return false
   280  	}
   281  
   282  	if !curve.IsOnCurve(x, y) {
   283  		return false
   284  	}
   285  
   286  	// We don't check if N * PubKey == 0, since
   287  	//
   288  	// - the NIST curves have cofactor = 1, so this is implicit.
   289  	// (We don't foresee an implementation that supports non NIST
   290  	// curves)
   291  	//
   292  	// - for ephemeral keys, we don't need to worry about small
   293  	// subgroup attacks.
   294  	return true
   295  }
   296  
   297  func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
   298  	packet, err := c.readPacket()
   299  	if err != nil {
   300  		return nil, err
   301  	}
   302  
   303  	var kexECDHInit kexECDHInitMsg
   304  	if err = Unmarshal(packet, &kexECDHInit); err != nil {
   305  		return nil, err
   306  	}
   307  
   308  	clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey)
   309  	if err != nil {
   310  		return nil, err
   311  	}
   312  
   313  	// We could cache this key across multiple users/multiple
   314  	// connection attempts, but the benefit is small. OpenSSH
   315  	// generates a new key for each incoming connection.
   316  	ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
   317  	if err != nil {
   318  		return nil, err
   319  	}
   320  
   321  	hostKeyBytes := priv.PublicKey().Marshal()
   322  
   323  	serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y)
   324  
   325  	// generate shared secret
   326  	secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes())
   327  
   328  	h := ecHash(kex.curve).New()
   329  	magics.write(h)
   330  	writeString(h, hostKeyBytes)
   331  	writeString(h, kexECDHInit.ClientPubKey)
   332  	writeString(h, serializedEphKey)
   333  
   334  	K := make([]byte, intLength(secret))
   335  	marshalInt(K, secret)
   336  	h.Write(K)
   337  
   338  	H := h.Sum(nil)
   339  
   340  	// H is already a hash, but the hostkey signing will apply its
   341  	// own key-specific hash algorithm.
   342  	sig, err := signAndMarshal(priv, rand, H)
   343  	if err != nil {
   344  		return nil, err
   345  	}
   346  
   347  	reply := kexECDHReplyMsg{
   348  		EphemeralPubKey: serializedEphKey,
   349  		HostKey:         hostKeyBytes,
   350  		Signature:       sig,
   351  	}
   352  
   353  	serialized := Marshal(&reply)
   354  	if err := c.writePacket(serialized); err != nil {
   355  		return nil, err
   356  	}
   357  
   358  	return &kexResult{
   359  		H:         H,
   360  		K:         K,
   361  		HostKey:   reply.HostKey,
   362  		Signature: sig,
   363  		Hash:      ecHash(kex.curve),
   364  	}, nil
   365  }
   366  
   367  var kexAlgoMap = map[string]kexAlgorithm{}
   368  
   369  func init() {
   370  	// This is the group called diffie-hellman-group1-sha1 in RFC
   371  	// 4253 and Oakley Group 2 in RFC 2409.
   372  	p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
   373  	kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{
   374  		g: new(big.Int).SetInt64(2),
   375  		p: p,
   376  	}
   377  
   378  	// This is the group called diffie-hellman-group14-sha1 in RFC
   379  	// 4253 and Oakley Group 14 in RFC 3526.
   380  	p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
   381  
   382  	kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
   383  		g: new(big.Int).SetInt64(2),
   384  		p: p,
   385  	}
   386  
   387  	kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
   388  	kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
   389  	kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}
   390  	kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{}
   391  }
   392  
   393  // curve25519sha256 implements the curve25519-sha256@libssh.org key
   394  // agreement protocol, as described in
   395  // https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt
   396  type curve25519sha256 struct{}
   397  
   398  type curve25519KeyPair struct {
   399  	priv [32]byte
   400  	pub  [32]byte
   401  }
   402  
   403  func (kp *curve25519KeyPair) generate(rand io.Reader) error {
   404  	if _, err := io.ReadFull(rand, kp.priv[:]); err != nil {
   405  		return err
   406  	}
   407  	curve25519.ScalarBaseMult(&kp.pub, &kp.priv)
   408  	return nil
   409  }
   410  
   411  // curve25519Zeros is just an array of 32 zero bytes so that we have something
   412  // convenient to compare against in order to reject curve25519 points with the
   413  // wrong order.
   414  var curve25519Zeros [32]byte
   415  
   416  func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
   417  	var kp curve25519KeyPair
   418  	if err := kp.generate(rand); err != nil {
   419  		return nil, err
   420  	}
   421  	if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil {
   422  		return nil, err
   423  	}
   424  
   425  	packet, err := c.readPacket()
   426  	if err != nil {
   427  		return nil, err
   428  	}
   429  
   430  	var reply kexECDHReplyMsg
   431  	if err = Unmarshal(packet, &reply); err != nil {
   432  		return nil, err
   433  	}
   434  	if len(reply.EphemeralPubKey) != 32 {
   435  		return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
   436  	}
   437  
   438  	var servPub, secret [32]byte
   439  	copy(servPub[:], reply.EphemeralPubKey)
   440  	curve25519.ScalarMult(&secret, &kp.priv, &servPub)
   441  	if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 {
   442  		return nil, errors.New("ssh: peer's curve25519 public value has wrong order")
   443  	}
   444  
   445  	h := crypto.SHA256.New()
   446  	magics.write(h)
   447  	writeString(h, reply.HostKey)
   448  	writeString(h, kp.pub[:])
   449  	writeString(h, reply.EphemeralPubKey)
   450  
   451  	kInt := new(big.Int).SetBytes(secret[:])
   452  	K := make([]byte, intLength(kInt))
   453  	marshalInt(K, kInt)
   454  	h.Write(K)
   455  
   456  	return &kexResult{
   457  		H:         h.Sum(nil),
   458  		K:         K,
   459  		HostKey:   reply.HostKey,
   460  		Signature: reply.Signature,
   461  		Hash:      crypto.SHA256,
   462  	}, nil
   463  }
   464  
   465  func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
   466  	packet, err := c.readPacket()
   467  	if err != nil {
   468  		return
   469  	}
   470  	var kexInit kexECDHInitMsg
   471  	if err = Unmarshal(packet, &kexInit); err != nil {
   472  		return
   473  	}
   474  
   475  	if len(kexInit.ClientPubKey) != 32 {
   476  		return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
   477  	}
   478  
   479  	var kp curve25519KeyPair
   480  	if err := kp.generate(rand); err != nil {
   481  		return nil, err
   482  	}
   483  
   484  	var clientPub, secret [32]byte
   485  	copy(clientPub[:], kexInit.ClientPubKey)
   486  	curve25519.ScalarMult(&secret, &kp.priv, &clientPub)
   487  	if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 {
   488  		return nil, errors.New("ssh: peer's curve25519 public value has wrong order")
   489  	}
   490  
   491  	hostKeyBytes := priv.PublicKey().Marshal()
   492  
   493  	h := crypto.SHA256.New()
   494  	magics.write(h)
   495  	writeString(h, hostKeyBytes)
   496  	writeString(h, kexInit.ClientPubKey)
   497  	writeString(h, kp.pub[:])
   498  
   499  	kInt := new(big.Int).SetBytes(secret[:])
   500  	K := make([]byte, intLength(kInt))
   501  	marshalInt(K, kInt)
   502  	h.Write(K)
   503  
   504  	H := h.Sum(nil)
   505  
   506  	sig, err := signAndMarshal(priv, rand, H)
   507  	if err != nil {
   508  		return nil, err
   509  	}
   510  
   511  	reply := kexECDHReplyMsg{
   512  		EphemeralPubKey: kp.pub[:],
   513  		HostKey:         hostKeyBytes,
   514  		Signature:       sig,
   515  	}
   516  	if err := c.writePacket(Marshal(&reply)); err != nil {
   517  		return nil, err
   518  	}
   519  	return &kexResult{
   520  		H:         H,
   521  		K:         K,
   522  		HostKey:   hostKeyBytes,
   523  		Signature: sig,
   524  		Hash:      crypto.SHA256,
   525  	}, nil
   526  }