github.com/deis/deis@v1.13.5-0.20170519182049-1d9e59fbdbfc/Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/client.go (about)

     1  // Copyright 2012 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  /*
     6    Package agent implements a client to an ssh-agent daemon.
     7  
     8  References:
     9    [PROTOCOL.agent]:    http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.agent
    10  */
    11  package agent
    12  
    13  import (
    14  	"bytes"
    15  	"crypto/dsa"
    16  	"crypto/ecdsa"
    17  	"crypto/elliptic"
    18  	"crypto/rsa"
    19  	"encoding/base64"
    20  	"encoding/binary"
    21  	"errors"
    22  	"fmt"
    23  	"io"
    24  	"math/big"
    25  	"sync"
    26  
    27  	"golang.org/x/crypto/ssh"
    28  )
    29  
    30  // Agent represents the capabilities of an ssh-agent.
    31  type Agent interface {
    32  	// List returns the identities known to the agent.
    33  	List() ([]*Key, error)
    34  
    35  	// Sign has the agent sign the data using a protocol 2 key as defined
    36  	// in [PROTOCOL.agent] section 2.6.2.
    37  	Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error)
    38  
    39  	// Insert adds a private key to the agent. If a certificate
    40  	// is given, that certificate is added as public key.
    41  	Add(s interface{}, cert *ssh.Certificate, comment string) error
    42  
    43  	// Remove removes all identities with the given public key.
    44  	Remove(key ssh.PublicKey) error
    45  
    46  	// RemoveAll removes all identities.
    47  	RemoveAll() error
    48  
    49  	// Lock locks the agent. Sign and Remove will fail, and List will empty an empty list.
    50  	Lock(passphrase []byte) error
    51  
    52  	// Unlock undoes the effect of Lock
    53  	Unlock(passphrase []byte) error
    54  
    55  	// Signers returns signers for all the known keys.
    56  	Signers() ([]ssh.Signer, error)
    57  }
    58  
    59  // See [PROTOCOL.agent], section 3.
    60  const (
    61  	agentRequestV1Identities = 1
    62  
    63  	// 3.2 Requests from client to agent for protocol 2 key operations
    64  	agentAddIdentity         = 17
    65  	agentRemoveIdentity      = 18
    66  	agentRemoveAllIdentities = 19
    67  	agentAddIdConstrained    = 25
    68  
    69  	// 3.3 Key-type independent requests from client to agent
    70  	agentAddSmartcardKey            = 20
    71  	agentRemoveSmartcardKey         = 21
    72  	agentLock                       = 22
    73  	agentUnlock                     = 23
    74  	agentAddSmartcardKeyConstrained = 26
    75  
    76  	// 3.7 Key constraint identifiers
    77  	agentConstrainLifetime = 1
    78  	agentConstrainConfirm  = 2
    79  )
    80  
    81  // maxAgentResponseBytes is the maximum agent reply size that is accepted. This
    82  // is a sanity check, not a limit in the spec.
    83  const maxAgentResponseBytes = 16 << 20
    84  
    85  // Agent messages:
    86  // These structures mirror the wire format of the corresponding ssh agent
    87  // messages found in [PROTOCOL.agent].
    88  
    89  // 3.4 Generic replies from agent to client
    90  const agentFailure = 5
    91  
    92  type failureAgentMsg struct{}
    93  
    94  const agentSuccess = 6
    95  
    96  type successAgentMsg struct{}
    97  
    98  // See [PROTOCOL.agent], section 2.5.2.
    99  const agentRequestIdentities = 11
   100  
   101  type requestIdentitiesAgentMsg struct{}
   102  
   103  // See [PROTOCOL.agent], section 2.5.2.
   104  const agentIdentitiesAnswer = 12
   105  
   106  type identitiesAnswerAgentMsg struct {
   107  	NumKeys uint32 `sshtype:"12"`
   108  	Keys    []byte `ssh:"rest"`
   109  }
   110  
   111  // See [PROTOCOL.agent], section 2.6.2.
   112  const agentSignRequest = 13
   113  
   114  type signRequestAgentMsg struct {
   115  	KeyBlob []byte `sshtype:"13"`
   116  	Data    []byte
   117  	Flags   uint32
   118  }
   119  
   120  // See [PROTOCOL.agent], section 2.6.2.
   121  
   122  // 3.6 Replies from agent to client for protocol 2 key operations
   123  const agentSignResponse = 14
   124  
   125  type signResponseAgentMsg struct {
   126  	SigBlob []byte `sshtype:"14"`
   127  }
   128  
   129  type publicKey struct {
   130  	Format string
   131  	Rest   []byte `ssh:"rest"`
   132  }
   133  
   134  // Key represents a protocol 2 public key as defined in
   135  // [PROTOCOL.agent], section 2.5.2.
   136  type Key struct {
   137  	Format  string
   138  	Blob    []byte
   139  	Comment string
   140  }
   141  
   142  func clientErr(err error) error {
   143  	return fmt.Errorf("agent: client error: %v", err)
   144  }
   145  
   146  // String returns the storage form of an agent key with the format, base64
   147  // encoded serialized key, and the comment if it is not empty.
   148  func (k *Key) String() string {
   149  	s := string(k.Format) + " " + base64.StdEncoding.EncodeToString(k.Blob)
   150  
   151  	if k.Comment != "" {
   152  		s += " " + k.Comment
   153  	}
   154  
   155  	return s
   156  }
   157  
   158  // Type returns the public key type.
   159  func (k *Key) Type() string {
   160  	return k.Format
   161  }
   162  
   163  // Marshal returns key blob to satisfy the ssh.PublicKey interface.
   164  func (k *Key) Marshal() []byte {
   165  	return k.Blob
   166  }
   167  
   168  // Verify satisfies the ssh.PublicKey interface, but is not
   169  // implemented for agent keys.
   170  func (k *Key) Verify(data []byte, sig *ssh.Signature) error {
   171  	return errors.New("agent: agent key does not know how to verify")
   172  }
   173  
   174  type wireKey struct {
   175  	Format string
   176  	Rest   []byte `ssh:"rest"`
   177  }
   178  
   179  func parseKey(in []byte) (out *Key, rest []byte, err error) {
   180  	var record struct {
   181  		Blob    []byte
   182  		Comment string
   183  		Rest    []byte `ssh:"rest"`
   184  	}
   185  
   186  	if err := ssh.Unmarshal(in, &record); err != nil {
   187  		return nil, nil, err
   188  	}
   189  
   190  	var wk wireKey
   191  	if err := ssh.Unmarshal(record.Blob, &wk); err != nil {
   192  		return nil, nil, err
   193  	}
   194  
   195  	return &Key{
   196  		Format:  wk.Format,
   197  		Blob:    record.Blob,
   198  		Comment: record.Comment,
   199  	}, record.Rest, nil
   200  }
   201  
   202  // client is a client for an ssh-agent process.
   203  type client struct {
   204  	// conn is typically a *net.UnixConn
   205  	conn io.ReadWriter
   206  	// mu is used to prevent concurrent access to the agent
   207  	mu sync.Mutex
   208  }
   209  
   210  // NewClient returns an Agent that talks to an ssh-agent process over
   211  // the given connection.
   212  func NewClient(rw io.ReadWriter) Agent {
   213  	return &client{conn: rw}
   214  }
   215  
   216  // call sends an RPC to the agent. On success, the reply is
   217  // unmarshaled into reply and replyType is set to the first byte of
   218  // the reply, which contains the type of the message.
   219  func (c *client) call(req []byte) (reply interface{}, err error) {
   220  	c.mu.Lock()
   221  	defer c.mu.Unlock()
   222  
   223  	msg := make([]byte, 4+len(req))
   224  	binary.BigEndian.PutUint32(msg, uint32(len(req)))
   225  	copy(msg[4:], req)
   226  	if _, err = c.conn.Write(msg); err != nil {
   227  		return nil, clientErr(err)
   228  	}
   229  
   230  	var respSizeBuf [4]byte
   231  	if _, err = io.ReadFull(c.conn, respSizeBuf[:]); err != nil {
   232  		return nil, clientErr(err)
   233  	}
   234  	respSize := binary.BigEndian.Uint32(respSizeBuf[:])
   235  	if respSize > maxAgentResponseBytes {
   236  		return nil, clientErr(err)
   237  	}
   238  
   239  	buf := make([]byte, respSize)
   240  	if _, err = io.ReadFull(c.conn, buf); err != nil {
   241  		return nil, clientErr(err)
   242  	}
   243  	reply, err = unmarshal(buf)
   244  	if err != nil {
   245  		return nil, clientErr(err)
   246  	}
   247  	return reply, err
   248  }
   249  
   250  func (c *client) simpleCall(req []byte) error {
   251  	resp, err := c.call(req)
   252  	if err != nil {
   253  		return err
   254  	}
   255  	if _, ok := resp.(*successAgentMsg); ok {
   256  		return nil
   257  	}
   258  	return errors.New("agent: failure")
   259  }
   260  
   261  func (c *client) RemoveAll() error {
   262  	return c.simpleCall([]byte{agentRemoveAllIdentities})
   263  }
   264  
   265  func (c *client) Remove(key ssh.PublicKey) error {
   266  	req := ssh.Marshal(&agentRemoveIdentityMsg{
   267  		KeyBlob: key.Marshal(),
   268  	})
   269  	return c.simpleCall(req)
   270  }
   271  
   272  func (c *client) Lock(passphrase []byte) error {
   273  	req := ssh.Marshal(&agentLockMsg{
   274  		Passphrase: passphrase,
   275  	})
   276  	return c.simpleCall(req)
   277  }
   278  
   279  func (c *client) Unlock(passphrase []byte) error {
   280  	req := ssh.Marshal(&agentUnlockMsg{
   281  		Passphrase: passphrase,
   282  	})
   283  	return c.simpleCall(req)
   284  }
   285  
   286  // List returns the identities known to the agent.
   287  func (c *client) List() ([]*Key, error) {
   288  	// see [PROTOCOL.agent] section 2.5.2.
   289  	req := []byte{agentRequestIdentities}
   290  
   291  	msg, err := c.call(req)
   292  	if err != nil {
   293  		return nil, err
   294  	}
   295  
   296  	switch msg := msg.(type) {
   297  	case *identitiesAnswerAgentMsg:
   298  		if msg.NumKeys > maxAgentResponseBytes/8 {
   299  			return nil, errors.New("agent: too many keys in agent reply")
   300  		}
   301  		keys := make([]*Key, msg.NumKeys)
   302  		data := msg.Keys
   303  		for i := uint32(0); i < msg.NumKeys; i++ {
   304  			var key *Key
   305  			var err error
   306  			if key, data, err = parseKey(data); err != nil {
   307  				return nil, err
   308  			}
   309  			keys[i] = key
   310  		}
   311  		return keys, nil
   312  	case *failureAgentMsg:
   313  		return nil, errors.New("agent: failed to list keys")
   314  	}
   315  	panic("unreachable")
   316  }
   317  
   318  // Sign has the agent sign the data using a protocol 2 key as defined
   319  // in [PROTOCOL.agent] section 2.6.2.
   320  func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
   321  	req := ssh.Marshal(signRequestAgentMsg{
   322  		KeyBlob: key.Marshal(),
   323  		Data:    data,
   324  	})
   325  
   326  	msg, err := c.call(req)
   327  	if err != nil {
   328  		return nil, err
   329  	}
   330  
   331  	switch msg := msg.(type) {
   332  	case *signResponseAgentMsg:
   333  		var sig ssh.Signature
   334  		if err := ssh.Unmarshal(msg.SigBlob, &sig); err != nil {
   335  			return nil, err
   336  		}
   337  
   338  		return &sig, nil
   339  	case *failureAgentMsg:
   340  		return nil, errors.New("agent: failed to sign challenge")
   341  	}
   342  	panic("unreachable")
   343  }
   344  
   345  // unmarshal parses an agent message in packet, returning the parsed
   346  // form and the message type of packet.
   347  func unmarshal(packet []byte) (interface{}, error) {
   348  	if len(packet) < 1 {
   349  		return nil, errors.New("agent: empty packet")
   350  	}
   351  	var msg interface{}
   352  	switch packet[0] {
   353  	case agentFailure:
   354  		return new(failureAgentMsg), nil
   355  	case agentSuccess:
   356  		return new(successAgentMsg), nil
   357  	case agentIdentitiesAnswer:
   358  		msg = new(identitiesAnswerAgentMsg)
   359  	case agentSignResponse:
   360  		msg = new(signResponseAgentMsg)
   361  	default:
   362  		return nil, fmt.Errorf("agent: unknown type tag %d", packet[0])
   363  	}
   364  	if err := ssh.Unmarshal(packet, msg); err != nil {
   365  		return nil, err
   366  	}
   367  	return msg, nil
   368  }
   369  
   370  type rsaKeyMsg struct {
   371  	Type     string `sshtype:"17"`
   372  	N        *big.Int
   373  	E        *big.Int
   374  	D        *big.Int
   375  	Iqmp     *big.Int // IQMP = Inverse Q Mod P
   376  	P        *big.Int
   377  	Q        *big.Int
   378  	Comments string
   379  }
   380  
   381  type dsaKeyMsg struct {
   382  	Type     string `sshtype:"17"`
   383  	P        *big.Int
   384  	Q        *big.Int
   385  	G        *big.Int
   386  	Y        *big.Int
   387  	X        *big.Int
   388  	Comments string
   389  }
   390  
   391  type ecdsaKeyMsg struct {
   392  	Type     string `sshtype:"17"`
   393  	Curve    string
   394  	KeyBytes []byte
   395  	D        *big.Int
   396  	Comments string
   397  }
   398  
   399  // Insert adds a private key to the agent.
   400  func (c *client) insertKey(s interface{}, comment string) error {
   401  	var req []byte
   402  	switch k := s.(type) {
   403  	case *rsa.PrivateKey:
   404  		if len(k.Primes) != 2 {
   405  			return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes))
   406  		}
   407  		k.Precompute()
   408  		req = ssh.Marshal(rsaKeyMsg{
   409  			Type:     ssh.KeyAlgoRSA,
   410  			N:        k.N,
   411  			E:        big.NewInt(int64(k.E)),
   412  			D:        k.D,
   413  			Iqmp:     k.Precomputed.Qinv,
   414  			P:        k.Primes[0],
   415  			Q:        k.Primes[1],
   416  			Comments: comment,
   417  		})
   418  	case *dsa.PrivateKey:
   419  		req = ssh.Marshal(dsaKeyMsg{
   420  			Type:     ssh.KeyAlgoDSA,
   421  			P:        k.P,
   422  			Q:        k.Q,
   423  			G:        k.G,
   424  			Y:        k.Y,
   425  			X:        k.X,
   426  			Comments: comment,
   427  		})
   428  	case *ecdsa.PrivateKey:
   429  		nistID := fmt.Sprintf("nistp%d", k.Params().BitSize)
   430  		req = ssh.Marshal(ecdsaKeyMsg{
   431  			Type:     "ecdsa-sha2-" + nistID,
   432  			Curve:    nistID,
   433  			KeyBytes: elliptic.Marshal(k.Curve, k.X, k.Y),
   434  			D:        k.D,
   435  			Comments: comment,
   436  		})
   437  	default:
   438  		return fmt.Errorf("agent: unsupported key type %T", s)
   439  	}
   440  	resp, err := c.call(req)
   441  	if err != nil {
   442  		return err
   443  	}
   444  	if _, ok := resp.(*successAgentMsg); ok {
   445  		return nil
   446  	}
   447  	return errors.New("agent: failure")
   448  }
   449  
   450  type rsaCertMsg struct {
   451  	Type      string `sshtype:"17"`
   452  	CertBytes []byte
   453  	D         *big.Int
   454  	Iqmp      *big.Int // IQMP = Inverse Q Mod P
   455  	P         *big.Int
   456  	Q         *big.Int
   457  	Comments  string
   458  }
   459  
   460  type dsaCertMsg struct {
   461  	Type      string `sshtype:"17"`
   462  	CertBytes []byte
   463  	X         *big.Int
   464  	Comments  string
   465  }
   466  
   467  type ecdsaCertMsg struct {
   468  	Type      string `sshtype:"17"`
   469  	CertBytes []byte
   470  	D         *big.Int
   471  	Comments  string
   472  }
   473  
   474  // Insert adds a private key to the agent. If a certificate is given,
   475  // that certificate is added instead as public key.
   476  func (c *client) Add(s interface{}, cert *ssh.Certificate, comment string) error {
   477  	if cert == nil {
   478  		return c.insertKey(s, comment)
   479  	} else {
   480  		return c.insertCert(s, cert, comment)
   481  	}
   482  }
   483  
   484  func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string) error {
   485  	var req []byte
   486  	switch k := s.(type) {
   487  	case *rsa.PrivateKey:
   488  		if len(k.Primes) != 2 {
   489  			return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes))
   490  		}
   491  		k.Precompute()
   492  		req = ssh.Marshal(rsaCertMsg{
   493  			Type:      cert.Type(),
   494  			CertBytes: cert.Marshal(),
   495  			D:         k.D,
   496  			Iqmp:      k.Precomputed.Qinv,
   497  			P:         k.Primes[0],
   498  			Q:         k.Primes[1],
   499  			Comments:  comment,
   500  		})
   501  	case *dsa.PrivateKey:
   502  		req = ssh.Marshal(dsaCertMsg{
   503  			Type:      cert.Type(),
   504  			CertBytes: cert.Marshal(),
   505  			X:         k.X,
   506  			Comments:  comment,
   507  		})
   508  	case *ecdsa.PrivateKey:
   509  		req = ssh.Marshal(ecdsaCertMsg{
   510  			Type:      cert.Type(),
   511  			CertBytes: cert.Marshal(),
   512  			D:         k.D,
   513  			Comments:  comment,
   514  		})
   515  	default:
   516  		return fmt.Errorf("agent: unsupported key type %T", s)
   517  	}
   518  
   519  	signer, err := ssh.NewSignerFromKey(s)
   520  	if err != nil {
   521  		return err
   522  	}
   523  	if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 {
   524  		return errors.New("agent: signer and cert have different public key")
   525  	}
   526  
   527  	resp, err := c.call(req)
   528  	if err != nil {
   529  		return err
   530  	}
   531  	if _, ok := resp.(*successAgentMsg); ok {
   532  		return nil
   533  	}
   534  	return errors.New("agent: failure")
   535  }
   536  
   537  // Signers provides a callback for client authentication.
   538  func (c *client) Signers() ([]ssh.Signer, error) {
   539  	keys, err := c.List()
   540  	if err != nil {
   541  		return nil, err
   542  	}
   543  
   544  	var result []ssh.Signer
   545  	for _, k := range keys {
   546  		result = append(result, &agentKeyringSigner{c, k})
   547  	}
   548  	return result, nil
   549  }
   550  
   551  type agentKeyringSigner struct {
   552  	agent *client
   553  	pub   ssh.PublicKey
   554  }
   555  
   556  func (s *agentKeyringSigner) PublicKey() ssh.PublicKey {
   557  	return s.pub
   558  }
   559  
   560  func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, error) {
   561  	// The agent has its own entropy source, so the rand argument is ignored.
   562  	return s.agent.Sign(s.pub, data)
   563  }