github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/golang.org/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  	"errors"
    13  	"io"
    14  	"math/big"
    15  )
    16  
    17  const (
    18  	kexAlgoDH1SHA1  = "diffie-hellman-group1-sha1"
    19  	kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
    20  	kexAlgoECDH256  = "ecdh-sha2-nistp256"
    21  	kexAlgoECDH384  = "ecdh-sha2-nistp384"
    22  	kexAlgoECDH521  = "ecdh-sha2-nistp521"
    23  )
    24  
    25  // kexResult captures the outcome of a key exchange.
    26  type kexResult struct {
    27  	// Session hash. See also RFC 4253, section 8.
    28  	H []byte
    29  
    30  	// Shared secret. See also RFC 4253, section 8.
    31  	K []byte
    32  
    33  	// Host key as hashed into H.
    34  	HostKey []byte
    35  
    36  	// Signature of H.
    37  	Signature []byte
    38  
    39  	// A cryptographic hash function that matches the security
    40  	// level of the key exchange algorithm. It is used for
    41  	// calculating H, and for deriving keys from H and K.
    42  	Hash crypto.Hash
    43  
    44  	// The session ID, which is the first H computed. This is used
    45  	// to signal data inside transport.
    46  	SessionID []byte
    47  }
    48  
    49  // handshakeMagics contains data that is always included in the
    50  // session hash.
    51  type handshakeMagics struct {
    52  	clientVersion, serverVersion []byte
    53  	clientKexInit, serverKexInit []byte
    54  }
    55  
    56  func (m *handshakeMagics) write(w io.Writer) {
    57  	writeString(w, m.clientVersion)
    58  	writeString(w, m.serverVersion)
    59  	writeString(w, m.clientKexInit)
    60  	writeString(w, m.serverKexInit)
    61  }
    62  
    63  // kexAlgorithm abstracts different key exchange algorithms.
    64  type kexAlgorithm interface {
    65  	// Server runs server-side key agreement, signing the result
    66  	// with a hostkey.
    67  	Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error)
    68  
    69  	// Client runs the client-side key agreement. Caller is
    70  	// responsible for verifying the host key signature.
    71  	Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error)
    72  }
    73  
    74  // dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
    75  type dhGroup struct {
    76  	g, p *big.Int
    77  }
    78  
    79  func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
    80  	if theirPublic.Sign() <= 0 || theirPublic.Cmp(group.p) >= 0 {
    81  		return nil, errors.New("ssh: DH parameter out of bounds")
    82  	}
    83  	return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
    84  }
    85  
    86  func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
    87  	hashFunc := crypto.SHA1
    88  
    89  	x, err := rand.Int(randSource, group.p)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	X := new(big.Int).Exp(group.g, x, group.p)
    94  	kexDHInit := kexDHInitMsg{
    95  		X: X,
    96  	}
    97  	if err := c.writePacket(Marshal(&kexDHInit)); err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	packet, err := c.readPacket()
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  
   106  	var kexDHReply kexDHReplyMsg
   107  	if err = Unmarshal(packet, &kexDHReply); err != nil {
   108  		return nil, err
   109  	}
   110  
   111  	kInt, err := group.diffieHellman(kexDHReply.Y, x)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	h := hashFunc.New()
   117  	magics.write(h)
   118  	writeString(h, kexDHReply.HostKey)
   119  	writeInt(h, X)
   120  	writeInt(h, kexDHReply.Y)
   121  	K := make([]byte, intLength(kInt))
   122  	marshalInt(K, kInt)
   123  	h.Write(K)
   124  
   125  	return &kexResult{
   126  		H:         h.Sum(nil),
   127  		K:         K,
   128  		HostKey:   kexDHReply.HostKey,
   129  		Signature: kexDHReply.Signature,
   130  		Hash:      crypto.SHA1,
   131  	}, nil
   132  }
   133  
   134  func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
   135  	hashFunc := crypto.SHA1
   136  	packet, err := c.readPacket()
   137  	if err != nil {
   138  		return
   139  	}
   140  	var kexDHInit kexDHInitMsg
   141  	if err = Unmarshal(packet, &kexDHInit); err != nil {
   142  		return
   143  	}
   144  
   145  	y, err := rand.Int(randSource, group.p)
   146  	if err != nil {
   147  		return
   148  	}
   149  
   150  	Y := new(big.Int).Exp(group.g, y, group.p)
   151  	kInt, err := group.diffieHellman(kexDHInit.X, y)
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  
   156  	hostKeyBytes := priv.PublicKey().Marshal()
   157  
   158  	h := hashFunc.New()
   159  	magics.write(h)
   160  	writeString(h, hostKeyBytes)
   161  	writeInt(h, kexDHInit.X)
   162  	writeInt(h, Y)
   163  
   164  	K := make([]byte, intLength(kInt))
   165  	marshalInt(K, kInt)
   166  	h.Write(K)
   167  
   168  	H := h.Sum(nil)
   169  
   170  	// H is already a hash, but the hostkey signing will apply its
   171  	// own key-specific hash algorithm.
   172  	sig, err := signAndMarshal(priv, randSource, H)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  
   177  	kexDHReply := kexDHReplyMsg{
   178  		HostKey:   hostKeyBytes,
   179  		Y:         Y,
   180  		Signature: sig,
   181  	}
   182  	packet = Marshal(&kexDHReply)
   183  
   184  	err = c.writePacket(packet)
   185  	return &kexResult{
   186  		H:         H,
   187  		K:         K,
   188  		HostKey:   hostKeyBytes,
   189  		Signature: sig,
   190  		Hash:      crypto.SHA1,
   191  	}, nil
   192  }
   193  
   194  // ecdh performs Elliptic Curve Diffie-Hellman key exchange as
   195  // described in RFC 5656, section 4.
   196  type ecdh struct {
   197  	curve elliptic.Curve
   198  }
   199  
   200  func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
   201  	ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  
   206  	kexInit := kexECDHInitMsg{
   207  		ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y),
   208  	}
   209  
   210  	serialized := Marshal(&kexInit)
   211  	if err := c.writePacket(serialized); err != nil {
   212  		return nil, err
   213  	}
   214  
   215  	packet, err := c.readPacket()
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  
   220  	var reply kexECDHReplyMsg
   221  	if err = Unmarshal(packet, &reply); err != nil {
   222  		return nil, err
   223  	}
   224  
   225  	x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey)
   226  	if err != nil {
   227  		return nil, err
   228  	}
   229  
   230  	// generate shared secret
   231  	secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes())
   232  
   233  	h := ecHash(kex.curve).New()
   234  	magics.write(h)
   235  	writeString(h, reply.HostKey)
   236  	writeString(h, kexInit.ClientPubKey)
   237  	writeString(h, reply.EphemeralPubKey)
   238  	K := make([]byte, intLength(secret))
   239  	marshalInt(K, secret)
   240  	h.Write(K)
   241  
   242  	return &kexResult{
   243  		H:         h.Sum(nil),
   244  		K:         K,
   245  		HostKey:   reply.HostKey,
   246  		Signature: reply.Signature,
   247  		Hash:      ecHash(kex.curve),
   248  	}, nil
   249  }
   250  
   251  // unmarshalECKey parses and checks an EC key.
   252  func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) {
   253  	x, y = elliptic.Unmarshal(curve, pubkey)
   254  	if x == nil {
   255  		return nil, nil, errors.New("ssh: elliptic.Unmarshal failure")
   256  	}
   257  	if !validateECPublicKey(curve, x, y) {
   258  		return nil, nil, errors.New("ssh: public key not on curve")
   259  	}
   260  	return x, y, nil
   261  }
   262  
   263  // validateECPublicKey checks that the point is a valid public key for
   264  // the given curve. See [SEC1], 3.2.2
   265  func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool {
   266  	if x.Sign() == 0 && y.Sign() == 0 {
   267  		return false
   268  	}
   269  
   270  	if x.Cmp(curve.Params().P) >= 0 {
   271  		return false
   272  	}
   273  
   274  	if y.Cmp(curve.Params().P) >= 0 {
   275  		return false
   276  	}
   277  
   278  	if !curve.IsOnCurve(x, y) {
   279  		return false
   280  	}
   281  
   282  	// We don't check if N * PubKey == 0, since
   283  	//
   284  	// - the NIST curves have cofactor = 1, so this is implicit.
   285  	// (We don't foresee an implementation that supports non NIST
   286  	// curves)
   287  	//
   288  	// - for ephemeral keys, we don't need to worry about small
   289  	// subgroup attacks.
   290  	return true
   291  }
   292  
   293  func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
   294  	packet, err := c.readPacket()
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  
   299  	var kexECDHInit kexECDHInitMsg
   300  	if err = Unmarshal(packet, &kexECDHInit); err != nil {
   301  		return nil, err
   302  	}
   303  
   304  	clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey)
   305  	if err != nil {
   306  		return nil, err
   307  	}
   308  
   309  	// We could cache this key across multiple users/multiple
   310  	// connection attempts, but the benefit is small. OpenSSH
   311  	// generates a new key for each incoming connection.
   312  	ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
   313  	if err != nil {
   314  		return nil, err
   315  	}
   316  
   317  	hostKeyBytes := priv.PublicKey().Marshal()
   318  
   319  	serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y)
   320  
   321  	// generate shared secret
   322  	secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes())
   323  
   324  	h := ecHash(kex.curve).New()
   325  	magics.write(h)
   326  	writeString(h, hostKeyBytes)
   327  	writeString(h, kexECDHInit.ClientPubKey)
   328  	writeString(h, serializedEphKey)
   329  
   330  	K := make([]byte, intLength(secret))
   331  	marshalInt(K, secret)
   332  	h.Write(K)
   333  
   334  	H := h.Sum(nil)
   335  
   336  	// H is already a hash, but the hostkey signing will apply its
   337  	// own key-specific hash algorithm.
   338  	sig, err := signAndMarshal(priv, rand, H)
   339  	if err != nil {
   340  		return nil, err
   341  	}
   342  
   343  	reply := kexECDHReplyMsg{
   344  		EphemeralPubKey: serializedEphKey,
   345  		HostKey:         hostKeyBytes,
   346  		Signature:       sig,
   347  	}
   348  
   349  	serialized := Marshal(&reply)
   350  	if err := c.writePacket(serialized); err != nil {
   351  		return nil, err
   352  	}
   353  
   354  	return &kexResult{
   355  		H:         H,
   356  		K:         K,
   357  		HostKey:   reply.HostKey,
   358  		Signature: sig,
   359  		Hash:      ecHash(kex.curve),
   360  	}, nil
   361  }
   362  
   363  var kexAlgoMap = map[string]kexAlgorithm{}
   364  
   365  func init() {
   366  	// This is the group called diffie-hellman-group1-sha1 in RFC
   367  	// 4253 and Oakley Group 2 in RFC 2409.
   368  	p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
   369  	kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{
   370  		g: new(big.Int).SetInt64(2),
   371  		p: p,
   372  	}
   373  
   374  	// This is the group called diffie-hellman-group14-sha1 in RFC
   375  	// 4253 and Oakley Group 14 in RFC 3526.
   376  	p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
   377  
   378  	kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
   379  		g: new(big.Int).SetInt64(2),
   380  		p: p,
   381  	}
   382  
   383  	kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
   384  	kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
   385  	kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}
   386  }