text: // Copyright 2012 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  // Package agent implements the ssh-agent protocol, and provides both
  // a client and a server. The client can talk to a standard ssh-agent
  // that uses UNIX sockets, and one could implement an alternative
  // ssh-agent process using the sample server.
  //
  // References:
  //  [PROTOCOL.agent]:    http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.agent?rev=HEAD
  package agent // import "golang.org/x/crypto/ssh/agent"
  
  import (
  	"bytes"
  	"crypto/dsa"
  	"crypto/ecdsa"
  	"crypto/elliptic"
  	"crypto/rsa"
  	"encoding/base64"
  	"encoding/binary"
  	"errors"
  	"fmt"
  	"io"
  	"math/big"
  	"sync"
  
  	"golang.org/x/crypto/ed25519"
  	"golang.org/x/crypto/ssh"
  )
  
  // Agent represents the capabilities of an ssh-agent.
  type Agent interface {
  	// List returns the identities known to the agent.
  	List() ([]*Key, error)
  
  	// Sign has the agent sign the data using a protocol 2 key as defined
  	// in [PROTOCOL.agent] section 2.6.2.
  	Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error)
  
  	// Add adds a private key to the agent.
  	Add(key AddedKey) error
  
  	// Remove removes all identities with the given public key.
  	Remove(key ssh.PublicKey) error
  
  	// RemoveAll removes all identities.
  	RemoveAll() error
  
  	// Lock locks the agent. Sign and Remove will fail, and List will empty an empty list.
  	Lock(passphrase []byte) error
  
  	// Unlock undoes the effect of Lock
  	Unlock(passphrase []byte) error
  
  	// Signers returns signers for all the known keys.
  	Signers() ([]ssh.Signer, error)
  }
  
  // ConstraintExtension describes an optional constraint defined by users.
  type ConstraintExtension struct {
  	// ExtensionName consist of a UTF-8 string suffixed by the
  	// implementation domain following the naming scheme defined
  	// in Section 4.2 of [RFC4251], e.g.  "foo@example.com".
  	ExtensionName string
  	// ExtensionDetails contains the actual content of the extended
  	// constraint.
  	ExtensionDetails []byte
  }
  
  // AddedKey describes an SSH key to be added to an Agent.
  type AddedKey struct {
  	// PrivateKey must be a *rsa.PrivateKey, *dsa.PrivateKey or
  	// *ecdsa.PrivateKey, which will be inserted into the agent.
  	PrivateKey interface{}
  	// Certificate, if not nil, is communicated to the agent and will be
  	// stored with the key.
  	Certificate *ssh.Certificate
  	// Comment is an optional, free-form string.
  	Comment string
  	// LifetimeSecs, if not zero, is the number of seconds that the
  	// agent will store the key for.
  	LifetimeSecs uint32
  	// ConfirmBeforeUse, if true, requests that the agent confirm with the
  	// user before each use of this key.
  	ConfirmBeforeUse bool
  	// ConstraintExtensions are the experimental or private-use constraints
  	// defined by users.
  	ConstraintExtensions []ConstraintExtension
  }
  
  // See [PROTOCOL.agent], section 3.
  const (
  	agentRequestV1Identities   = 1
  	agentRemoveAllV1Identities = 9
  
  	// 3.2 Requests from client to agent for protocol 2 key operations
  	agentAddIdentity         = 17
  	agentRemoveIdentity      = 18
  	agentRemoveAllIdentities = 19
  	agentAddIDConstrained    = 25
  
  	// 3.3 Key-type independent requests from client to agent
  	agentAddSmartcardKey            = 20
  	agentRemoveSmartcardKey         = 21
  	agentLock                       = 22
  	agentUnlock                     = 23
  	agentAddSmartcardKeyConstrained = 26
  
  	// 3.7 Key constraint identifiers
  	agentConstrainLifetime  = 1
  	agentConstrainConfirm   = 2
  	agentConstrainExtension = 3
  )
  
  // maxAgentResponseBytes is the maximum agent reply size that is accepted. This
  // is a sanity check, not a limit in the spec.
  const maxAgentResponseBytes = 16 << 20
  
  // Agent messages:
  // These structures mirror the wire format of the corresponding ssh agent
  // messages found in [PROTOCOL.agent].
  
  // 3.4 Generic replies from agent to client
  const agentFailure = 5
  
  type failureAgentMsg struct{}
  
  const agentSuccess = 6
  
  type successAgentMsg struct{}
  
  // See [PROTOCOL.agent], section 2.5.2.
  const agentRequestIdentities = 11
  
  type requestIdentitiesAgentMsg struct{}
  
  // See [PROTOCOL.agent], section 2.5.2.
  const agentIdentitiesAnswer = 12
  
  type identitiesAnswerAgentMsg struct {
  	NumKeys uint32 `sshtype:"12"`
  	Keys    []byte `ssh:"rest"`
  }
  
  // See [PROTOCOL.agent], section 2.6.2.
  const agentSignRequest = 13
  
  type signRequestAgentMsg struct {
  	KeyBlob []byte `sshtype:"13"`
  	Data    []byte
  	Flags   uint32
  }
  
  // See [PROTOCOL.agent], section 2.6.2.
  
  // 3.6 Replies from agent to client for protocol 2 key operations
  const agentSignResponse = 14
  
  type signResponseAgentMsg struct {
  	SigBlob []byte `sshtype:"14"`
  }
  
  type publicKey struct {
  	Format string
  	Rest   []byte `ssh:"rest"`
  }
  
  // 3.7 Key constraint identifiers
  type constrainLifetimeAgentMsg struct {
  	LifetimeSecs uint32 `sshtype:"1"`
  }
  
  type constrainExtensionAgentMsg struct {
  	ExtensionName    string `sshtype:"3"`
  	ExtensionDetails []byte
  
  	// Rest is a field used for parsing, not part of message
  	Rest []byte `ssh:"rest"`
  }
  
  // Key represents a protocol 2 public key as defined in
  // [PROTOCOL.agent], section 2.5.2.
  type Key struct {
  	Format  string
  	Blob    []byte
  	Comment string
  }
  
  func clientErr(err error) error {
  	return fmt.Errorf("agent: client error: %v", err)
  }
  
  // String returns the storage form of an agent key with the format, base64
  // encoded serialized key, and the comment if it is not empty.
  func (k *Key) String() string {
  	s := string(k.Format) + " " + base64.StdEncoding.EncodeToString(k.Blob)
  
  	if k.Comment != "" {
  		s += " " + k.Comment
  	}
  
  	return s
  }
  
  // Type returns the public key type.
  func (k *Key) Type() string {
  	return k.Format
  }
  
  // Marshal returns key blob to satisfy the ssh.PublicKey interface.
  func (k *Key) Marshal() []byte {
  	return k.Blob
  }
  
  // Verify satisfies the ssh.PublicKey interface.
  func (k *Key) Verify(data []byte, sig *ssh.Signature) error {
  	pubKey, err := ssh.ParsePublicKey(k.Blob)
  	if err != nil {
  		return fmt.Errorf("agent: bad public key: %v", err)
  	}
  	return pubKey.Verify(data, sig)
  }
  
  type wireKey struct {
  	Format string
  	Rest   []byte `ssh:"rest"`
  }
  
  func parseKey(in []byte) (out *Key, rest []byte, err error) {
  	var record struct {
  		Blob    []byte
  		Comment string
  		Rest    []byte `ssh:"rest"`
  	}
  
  	if err := ssh.Unmarshal(in, &record); err != nil {
  		return nil, nil, err
  	}
  
  	var wk wireKey
  	if err := ssh.Unmarshal(record.Blob, &wk); err != nil {
  		return nil, nil, err
  	}
  
  	return &Key{
  		Format:  wk.Format,
  		Blob:    record.Blob,
  		Comment: record.Comment,
  	}, record.Rest, nil
  }
  
  // client is a client for an ssh-agent process.
  type client struct {
  	// conn is typically a *net.UnixConn
  	conn io.ReadWriter
  	// mu is used to prevent concurrent access to the agent
  	mu sync.Mutex
  }
  
  // NewClient returns an Agent that talks to an ssh-agent process over
  // the given connection.
  func NewClient(rw io.ReadWriter) Agent {
  	return &client{conn: rw}
  }
  
  // call sends an RPC to the agent. On success, the reply is
  // unmarshaled into reply and replyType is set to the first byte of
  // the reply, which contains the type of the message.
  func (c *client) call(req []byte) (reply interface{}, err error) {
  	c.mu.Lock()
  	defer c.mu.Unlock()
  
  	msg := make([]byte, 4+len(req))
  	binary.BigEndian.PutUint32(msg, uint32(len(req)))
  	copy(msg[4:], req)
  	if _, err = c.conn.Write(msg); err != nil {
  		return nil, clientErr(err)
  	}
  
  	var respSizeBuf [4]byte
  	if _, err = io.ReadFull(c.conn, respSizeBuf[:]); err != nil {
  		return nil, clientErr(err)
  	}
  	respSize := binary.BigEndian.Uint32(respSizeBuf[:])
  	if respSize > maxAgentResponseBytes {
  		return nil, clientErr(err)
  	}
  
  	buf := make([]byte, respSize)
  	if _, err = io.ReadFull(c.conn, buf); err != nil {
  		return nil, clientErr(err)
  	}
  	reply, err = unmarshal(buf)
  	if err != nil {
  		return nil, clientErr(err)
  	}
  	return reply, err
  }
  
  func (c *client) simpleCall(req []byte) error {
  	resp, err := c.call(req)
  	if err != nil {
  		return err
  	}
  	if _, ok := resp.(*successAgentMsg); ok {
  		return nil
  	}
  	return errors.New("agent: failure")
  }
  
  func (c *client) RemoveAll() error {
  	return c.simpleCall([]byte{agentRemoveAllIdentities})
  }
  
  func (c *client) Remove(key ssh.PublicKey) error {
  	req := ssh.Marshal(&agentRemoveIdentityMsg{
  		KeyBlob: key.Marshal(),
  	})
  	return c.simpleCall(req)
  }
  
  func (c *client) Lock(passphrase []byte) error {
  	req := ssh.Marshal(&agentLockMsg{
  		Passphrase: passphrase,
  	})
  	return c.simpleCall(req)
  }
  
  func (c *client) Unlock(passphrase []byte) error {
  	req := ssh.Marshal(&agentUnlockMsg{
  		Passphrase: passphrase,
  	})
  	return c.simpleCall(req)
  }
  
  // List returns the identities known to the agent.
  func (c *client) List() ([]*Key, error) {
  	// see [PROTOCOL.agent] section 2.5.2.
  	req := []byte{agentRequestIdentities}
  
  	msg, err := c.call(req)
  	if err != nil {
  		return nil, err
  	}
  
  	switch msg := msg.(type) {
  	case *identitiesAnswerAgentMsg:
  		if msg.NumKeys > maxAgentResponseBytes/8 {
  			return nil, errors.New("agent: too many keys in agent reply")
  		}
  		keys := make([]*Key, msg.NumKeys)
  		data := msg.Keys
  		for i := uint32(0); i < msg.NumKeys; i++ {
  			var key *Key
  			var err error
  			if key, data, err = parseKey(data); err != nil {
  				return nil, err
  			}
  			keys[i] = key
  		}
  		return keys, nil
  	case *failureAgentMsg:
  		return nil, errors.New("agent: failed to list keys")
  	}
  	panic("unreachable")
  }
  
  // Sign has the agent sign the data using a protocol 2 key as defined
  // in [PROTOCOL.agent] section 2.6.2.
  func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
  	req := ssh.Marshal(signRequestAgentMsg{
  		KeyBlob: key.Marshal(),
  		Data:    data,
  	})
  
  	msg, err := c.call(req)
  	if err != nil {
  		return nil, err
  	}
  
  	switch msg := msg.(type) {
  	case *signResponseAgentMsg:
  		var sig ssh.Signature
  		if err := ssh.Unmarshal(msg.SigBlob, &sig); err != nil {
  			return nil, err
  		}
  
  		return &sig, nil
  	case *failureAgentMsg:
  		return nil, errors.New("agent: failed to sign challenge")
  	}
  	panic("unreachable")
  }
  
  // unmarshal parses an agent message in packet, returning the parsed
  // form and the message type of packet.
  func unmarshal(packet []byte) (interface{}, error) {
  	if len(packet) < 1 {
  		return nil, errors.New("agent: empty packet")
  	}
  	var msg interface{}
  	switch packet[0] {
  	case agentFailure:
  		return new(failureAgentMsg), nil
  	case agentSuccess:
  		return new(successAgentMsg), nil
  	case agentIdentitiesAnswer:
  		msg = new(identitiesAnswerAgentMsg)
  	case agentSignResponse:
  		msg = new(signResponseAgentMsg)
  	case agentV1IdentitiesAnswer:
  		msg = new(agentV1IdentityMsg)
  	default:
  		return nil, fmt.Errorf("agent: unknown type tag %d", packet[0])
  	}
  	if err := ssh.Unmarshal(packet, msg); err != nil {
  		return nil, err
  	}
  	return msg, nil
  }
  
  type rsaKeyMsg struct {
  	Type        string `sshtype:"17|25"`
  	N           *big.Int
  	E           *big.Int
  	D           *big.Int
  	Iqmp        *big.Int // IQMP = Inverse Q Mod P
  	P           *big.Int
  	Q           *big.Int
  	Comments    string
  	Constraints []byte `ssh:"rest"`
  }
  
  type dsaKeyMsg struct {
  	Type        string `sshtype:"17|25"`
  	P           *big.Int
  	Q           *big.Int
  	G           *big.Int
  	Y           *big.Int
  	X           *big.Int
  	Comments    string
  	Constraints []byte `ssh:"rest"`
  }
  
  type ecdsaKeyMsg struct {
  	Type        string `sshtype:"17|25"`
  	Curve       string
  	KeyBytes    []byte
  	D           *big.Int
  	Comments    string
  	Constraints []byte `ssh:"rest"`
  }
  
  type ed25519KeyMsg struct {
  	Type        string `sshtype:"17|25"`
  	Pub         []byte
  	Priv        []byte
  	Comments    string
  	Constraints []byte `ssh:"rest"`
  }
  
  // Insert adds a private key to the agent.
  func (c *client) insertKey(s interface{}, comment string, constraints []byte) error {
  	var req []byte
  	switch k := s.(type) {
  	case *rsa.PrivateKey:
  		if len(k.Primes) != 2 {
  			return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes))
  		}
  		k.Precompute()
  		req = ssh.Marshal(rsaKeyMsg{
  			Type:        ssh.KeyAlgoRSA,
  			N:           k.N,
  			E:           big.NewInt(int64(k.E)),
  			D:           k.D,
  			Iqmp:        k.Precomputed.Qinv,
  			P:           k.Primes[0],
  			Q:           k.Primes[1],
  			Comments:    comment,
  			Constraints: constraints,
  		})
  	case *dsa.PrivateKey:
  		req = ssh.Marshal(dsaKeyMsg{
  			Type:        ssh.KeyAlgoDSA,
  			P:           k.P,
  			Q:           k.Q,
  			G:           k.G,
  			Y:           k.Y,
  			X:           k.X,
  			Comments:    comment,
  			Constraints: constraints,
  		})
  	case *ecdsa.PrivateKey:
  		nistID := fmt.Sprintf("nistp%d", k.Params().BitSize)
  		req = ssh.Marshal(ecdsaKeyMsg{
  			Type:        "ecdsa-sha2-" + nistID,
  			Curve:       nistID,
  			KeyBytes:    elliptic.Marshal(k.Curve, k.X, k.Y),
  			D:           k.D,
  			Comments:    comment,
  			Constraints: constraints,
  		})
  	case *ed25519.PrivateKey:
  		req = ssh.Marshal(ed25519KeyMsg{
  			Type:        ssh.KeyAlgoED25519,
  			Pub:         []byte(*k)[32:],
  			Priv:        []byte(*k),
  			Comments:    comment,
  			Constraints: constraints,
  		})
  	default:
  		return fmt.Errorf("agent: unsupported key type %T", s)
  	}
  
  	// if constraints are present then the message type needs to be changed.
  	if len(constraints) != 0 {
  		req[0] = agentAddIDConstrained
  	}
  
  	resp, err := c.call(req)
  	if err != nil {
  		return err
  	}
  	if _, ok := resp.(*successAgentMsg); ok {
  		return nil
  	}
  	return errors.New("agent: failure")
  }
  
  type rsaCertMsg struct {
  	Type        string `sshtype:"17|25"`
  	CertBytes   []byte
  	D           *big.Int
  	Iqmp        *big.Int // IQMP = Inverse Q Mod P
  	P           *big.Int
  	Q           *big.Int
  	Comments    string
  	Constraints []byte `ssh:"rest"`
  }
  
  type dsaCertMsg struct {
  	Type        string `sshtype:"17|25"`
  	CertBytes   []byte
  	X           *big.Int
  	Comments    string
  	Constraints []byte `ssh:"rest"`
  }
  
  type ecdsaCertMsg struct {
  	Type        string `sshtype:"17|25"`
  	CertBytes   []byte
  	D           *big.Int
  	Comments    string
  	Constraints []byte `ssh:"rest"`
  }
  
  type ed25519CertMsg struct {
  	Type        string `sshtype:"17|25"`
  	CertBytes   []byte
  	Pub         []byte
  	Priv        []byte
  	Comments    string
  	Constraints []byte `ssh:"rest"`
  }
  
  // Add adds a private key to the agent. If a certificate is given,
  // that certificate is added instead as public key.
  func (c *client) Add(key AddedKey) error {
  	var constraints []byte
  
  	if secs := key.LifetimeSecs; secs != 0 {
  		constraints = append(constraints, ssh.Marshal(constrainLifetimeAgentMsg{secs})...)
  	}
  
  	if key.ConfirmBeforeUse {
  		constraints = append(constraints, agentConstrainConfirm)
  	}
  
  	cert := key.Certificate
  	if cert == nil {
  		return c.insertKey(key.PrivateKey, key.Comment, constraints)
  	}
  	return c.insertCert(key.PrivateKey, cert, key.Comment, constraints)
  }
  
  func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string, constraints []byte) error {
  	var req []byte
  	switch k := s.(type) {
  	case *rsa.PrivateKey:
  		if len(k.Primes) != 2 {
  			return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes))
  		}
  		k.Precompute()
  		req = ssh.Marshal(rsaCertMsg{
  			Type:        cert.Type(),
  			CertBytes:   cert.Marshal(),
  			D:           k.D,
  			Iqmp:        k.Precomputed.Qinv,
  			P:           k.Primes[0],
  			Q:           k.Primes[1],
  			Comments:    comment,
  			Constraints: constraints,
  		})
  	case *dsa.PrivateKey:
  		req = ssh.Marshal(dsaCertMsg{
  			Type:        cert.Type(),
  			CertBytes:   cert.Marshal(),
  			X:           k.X,
  			Comments:    comment,
  			Constraints: constraints,
  		})
  	case *ecdsa.PrivateKey:
  		req = ssh.Marshal(ecdsaCertMsg{
  			Type:        cert.Type(),
  			CertBytes:   cert.Marshal(),
  			D:           k.D,
  			Comments:    comment,
  			Constraints: constraints,
  		})
  	case *ed25519.PrivateKey:
  		req = ssh.Marshal(ed25519CertMsg{
  			Type:        cert.Type(),
  			CertBytes:   cert.Marshal(),
  			Pub:         []byte(*k)[32:],
  			Priv:        []byte(*k),
  			Comments:    comment,
  			Constraints: constraints,
  		})
  	default:
  		return fmt.Errorf("agent: unsupported key type %T", s)
  	}
  
  	// if constraints are present then the message type needs to be changed.
  	if len(constraints) != 0 {
  		req[0] = agentAddIDConstrained
  	}
  
  	signer, err := ssh.NewSignerFromKey(s)
  	if err != nil {
  		return err
  	}
  	if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 {
  		return errors.New("agent: signer and cert have different public key")
  	}
  
  	resp, err := c.call(req)
  	if err != nil {
  		return err
  	}
  	if _, ok := resp.(*successAgentMsg); ok {
  		return nil
  	}
  	return errors.New("agent: failure")
  }
  
  // Signers provides a callback for client authentication.
  func (c *client) Signers() ([]ssh.Signer, error) {
  	keys, err := c.List()
  	if err != nil {
  		return nil, err
  	}
  
  	var result []ssh.Signer
  	for _, k := range keys {
  		result = append(result, &agentKeyringSigner{c, k})
  	}
  	return result, nil
  }
  
  type agentKeyringSigner struct {
  	agent *client
  	pub   ssh.PublicKey
  }
  
  func (s *agentKeyringSigner) PublicKey() ssh.PublicKey {
  	return s.pub
  }
  
  func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, error) {
  	// The agent has its own entropy source, so the rand argument is ignored.
  	return s.agent.Sign(s.pub, data)
  }
  