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]: https://tools.ietf.org/html/draft-miller-ssh-agent-00
package agent // import "golang.org/x/crypto/ssh/agent"

import (
	
	
	
	
	
	
	
	
	
	
	
	

	
	
	
)
SignatureFlags represent additional flags that can be passed to the signature requests an defined in [PROTOCOL.agent] section 4.5.1.
SignatureFlag values as defined in [PROTOCOL.agent] section 5.3.
Agent represents the capabilities of an ssh-agent.
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)
}

type ExtendedAgent interface {
	Agent
SignWithFlags signs like Sign, but allows for additional flags to be sent/received
	SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error)
Extension processes a custom extension request. Standard-compliant agents are not required to support any extensions, but this method allows agents to implement vendor-specific methods or add experimental features. See [PROTOCOL.agent] section 4.7. If agent extensions are unsupported entirely this method MUST return an ErrExtensionUnsupported error. Similarly, if just the specific extensionType in the request is unsupported by the agent then ErrExtensionUnsupported MUST be returned. In the case of success, since [PROTOCOL.agent] section 4.7 specifies that the contents of the response are unspecified (including the type of the message), the complete response will be returned as a []byte slice, including the "type" byte of the message.
	Extension(extensionType string, contents []byte) ([]byte, error)
}
ConstraintExtension describes an optional constraint defined by users.
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".
ExtensionDetails contains the actual content of the extended constraint.
AddedKey describes an SSH key to be added to an Agent.
PrivateKey must be a *rsa.PrivateKey, *dsa.PrivateKey, ed25519.PrivateKey or *ecdsa.PrivateKey, which will be inserted into the agent.
Certificate, if not nil, is communicated to the agent and will be stored with the key.
Comment is an optional, free-form string.
LifetimeSecs, if not zero, is the number of seconds that the agent will store the key for.
ConfirmBeforeUse, if true, requests that the agent confirm with the user before each use of this key.
ConstraintExtensions are the experimental or private-use constraints defined by users.
See [PROTOCOL.agent], section 3.
3.2 Requests from client to agent for protocol 2 key operations
3.3 Key-type independent requests from client to agent
3.7 Key constraint identifiers
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.
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
Rest is a field used for parsing, not part of message
	Rest []byte `ssh:"rest"`
}
See [PROTOCOL.agent], section 4.7
const agentExtension = 27
const agentExtensionFailure = 28
ErrExtensionUnsupported indicates that an extension defined in [PROTOCOL.agent] section 4.7 is unsupported by the agent. Specifically this error indicates that the agent returned a standard SSH_AGENT_FAILURE message as the result of a SSH_AGENTC_EXTENSION request. Note that the protocol specification (and therefore this error) does not distinguish between a specific extension being unsupported and extensions being unsupported entirely.
var ErrExtensionUnsupported = errors.New("agent: extension unsupported")

type extensionAgentMsg struct {
	ExtensionType string `sshtype:"27"`
	Contents      []byte
}
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 ( error) error {
	return fmt.Errorf("agent: client error: %v", )
}
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 ( *Key) () string {
	 := string(.Format) + " " + base64.StdEncoding.EncodeToString(.Blob)

	if .Comment != "" {
		 += " " + .Comment
	}

	return 
}
Type returns the public key type.
func ( *Key) () string {
	return .Format
}
Marshal returns key blob to satisfy the ssh.PublicKey interface.
func ( *Key) () []byte {
	return .Blob
}
Verify satisfies the ssh.PublicKey interface.
func ( *Key) ( []byte,  *ssh.Signature) error {
	,  := ssh.ParsePublicKey(.Blob)
	if  != nil {
		return fmt.Errorf("agent: bad public key: %v", )
	}
	return .Verify(, )
}

type wireKey struct {
	Format string
	Rest   []byte `ssh:"rest"`
}

func ( []byte) ( *Key,  []byte,  error) {
	var  struct {
		    []byte
		 string
		    []byte `ssh:"rest"`
	}

	if  := ssh.Unmarshal(, &);  != nil {
		return nil, nil, 
	}

	var  wireKey
	if  := ssh.Unmarshal(., &);  != nil {
		return nil, nil, 
	}

	return &Key{
		Format:  .Format,
		Blob:    .,
		Comment: .,
	}, ., nil
}
client is a client for an ssh-agent process.
conn is typically a *net.UnixConn
mu is used to prevent concurrent access to the agent
NewClient returns an Agent that talks to an ssh-agent process over the given connection.
func ( io.ReadWriter) ExtendedAgent {
	return &client{conn: }
}
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 ( *client) ( []byte) ( interface{},  error) {
	,  := .callRaw()
	if  != nil {
		return nil, 
	}
	,  = unmarshal()
	if  != nil {
		return nil, clientErr()
	}
	return , nil
}
callRaw sends an RPC to the agent. On success, the raw bytes of the response are returned; no unmarshalling is performed on the response.
func ( *client) ( []byte) ( []byte,  error) {
	.mu.Lock()
	defer .mu.Unlock()

	 := make([]byte, 4+len())
	binary.BigEndian.PutUint32(, uint32(len()))
	copy([4:], )
	if _,  = .conn.Write();  != nil {
		return nil, clientErr()
	}

	var  [4]byte
	if _,  = io.ReadFull(.conn, [:]);  != nil {
		return nil, clientErr()
	}
	 := binary.BigEndian.Uint32([:])
	if  > maxAgentResponseBytes {
		return nil, clientErr(errors.New("response too large"))
	}

	 := make([]byte, )
	if _,  = io.ReadFull(.conn, );  != nil {
		return nil, clientErr()
	}
	return , nil
}

func ( *client) ( []byte) error {
	,  := .call()
	if  != nil {
		return 
	}
	if ,  := .(*successAgentMsg);  {
		return nil
	}
	return errors.New("agent: failure")
}

func ( *client) () error {
	return .simpleCall([]byte{agentRemoveAllIdentities})
}

func ( *client) ( ssh.PublicKey) error {
	 := ssh.Marshal(&agentRemoveIdentityMsg{
		KeyBlob: .Marshal(),
	})
	return .simpleCall()
}

func ( *client) ( []byte) error {
	 := ssh.Marshal(&agentLockMsg{
		Passphrase: ,
	})
	return .simpleCall()
}

func ( *client) ( []byte) error {
	 := ssh.Marshal(&agentUnlockMsg{
		Passphrase: ,
	})
	return .simpleCall()
}
List returns the identities known to the agent.
see [PROTOCOL.agent] section 2.5.2.
	 := []byte{agentRequestIdentities}

	,  := .call()
	if  != nil {
		return nil, 
	}

	switch msg := .(type) {
	case *identitiesAnswerAgentMsg:
		if .NumKeys > maxAgentResponseBytes/8 {
			return nil, errors.New("agent: too many keys in agent reply")
		}
		 := make([]*Key, .NumKeys)
		 := .Keys
		for  := uint32(0);  < .NumKeys; ++ {
			var  *Key
			var  error
			if , ,  = parseKey();  != nil {
				return nil, 
			}
			[] = 
		}
		return , 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 ( *client) ( ssh.PublicKey,  []byte) (*ssh.Signature, error) {
	return .SignWithFlags(, , 0)
}

func ( *client) ( ssh.PublicKey,  []byte,  SignatureFlags) (*ssh.Signature, error) {
	 := ssh.Marshal(signRequestAgentMsg{
		KeyBlob: .Marshal(),
		Data:    ,
		Flags:   uint32(),
	})

	,  := .call()
	if  != nil {
		return nil, 
	}

	switch msg := .(type) {
	case *signResponseAgentMsg:
		var  ssh.Signature
		if  := ssh.Unmarshal(.SigBlob, &);  != nil {
			return nil, 
		}

		return &, 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 ( []byte) (interface{}, error) {
	if len() < 1 {
		return nil, errors.New("agent: empty packet")
	}
	var  interface{}
	switch [0] {
	case agentFailure:
		return new(failureAgentMsg), nil
	case agentSuccess:
		return new(successAgentMsg), nil
	case agentIdentitiesAnswer:
		 = new(identitiesAnswerAgentMsg)
	case agentSignResponse:
		 = new(signResponseAgentMsg)
	case agentV1IdentitiesAnswer:
		 = new(agentV1IdentityMsg)
	default:
		return nil, fmt.Errorf("agent: unknown type tag %d", [0])
	}
	if  := ssh.Unmarshal(, );  != nil {
		return nil, 
	}
	return , 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 ( *client) ( interface{},  string,  []byte) error {
	var  []byte
	switch k := .(type) {
	case *rsa.PrivateKey:
		if len(.Primes) != 2 {
			return fmt.Errorf("agent: unsupported RSA key with %d primes", len(.Primes))
		}
		.Precompute()
		 = ssh.Marshal(rsaKeyMsg{
			Type:        ssh.KeyAlgoRSA,
			N:           .N,
			E:           big.NewInt(int64(.E)),
			D:           .D,
			Iqmp:        .Precomputed.Qinv,
			P:           .Primes[0],
			Q:           .Primes[1],
			Comments:    ,
			Constraints: ,
		})
	case *dsa.PrivateKey:
		 = ssh.Marshal(dsaKeyMsg{
			Type:        ssh.KeyAlgoDSA,
			P:           .P,
			Q:           .Q,
			G:           .G,
			Y:           .Y,
			X:           .X,
			Comments:    ,
			Constraints: ,
		})
	case *ecdsa.PrivateKey:
		 := fmt.Sprintf("nistp%d", .Params().BitSize)
		 = ssh.Marshal(ecdsaKeyMsg{
			Type:        "ecdsa-sha2-" + ,
			Curve:       ,
			KeyBytes:    elliptic.Marshal(.Curve, .X, .Y),
			D:           .D,
			Comments:    ,
			Constraints: ,
		})
	case ed25519.PrivateKey:
		 = ssh.Marshal(ed25519KeyMsg{
			Type:        ssh.KeyAlgoED25519,
			Pub:         []byte()[32:],
			Priv:        []byte(),
			Comments:    ,
			Constraints: ,
This function originally supported only *ed25519.PrivateKey, however the general idiom is to pass ed25519.PrivateKey by value, not by pointer. We still support the pointer variant for backwards compatibility.
	case *ed25519.PrivateKey:
		 = ssh.Marshal(ed25519KeyMsg{
			Type:        ssh.KeyAlgoED25519,
			Pub:         []byte(*)[32:],
			Priv:        []byte(*),
			Comments:    ,
			Constraints: ,
		})
	default:
		return fmt.Errorf("agent: unsupported key type %T", )
	}
if constraints are present then the message type needs to be changed.
	if len() != 0 {
		[0] = agentAddIDConstrained
	}

	,  := .call()
	if  != nil {
		return 
	}
	if ,  := .(*successAgentMsg);  {
		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 ( *client) ( AddedKey) error {
	var  []byte

	if  := .LifetimeSecs;  != 0 {
		 = append(, ssh.Marshal(constrainLifetimeAgentMsg{})...)
	}

	if .ConfirmBeforeUse {
		 = append(, agentConstrainConfirm)
	}

	 := .Certificate
	if  == nil {
		return .insertKey(.PrivateKey, .Comment, )
	}
	return .insertCert(.PrivateKey, , .Comment, )
}

func ( *client) ( interface{},  *ssh.Certificate,  string,  []byte) error {
	var  []byte
	switch k := .(type) {
	case *rsa.PrivateKey:
		if len(.Primes) != 2 {
			return fmt.Errorf("agent: unsupported RSA key with %d primes", len(.Primes))
		}
		.Precompute()
		 = ssh.Marshal(rsaCertMsg{
			Type:        .Type(),
			CertBytes:   .Marshal(),
			D:           .D,
			Iqmp:        .Precomputed.Qinv,
			P:           .Primes[0],
			Q:           .Primes[1],
			Comments:    ,
			Constraints: ,
		})
	case *dsa.PrivateKey:
		 = ssh.Marshal(dsaCertMsg{
			Type:        .Type(),
			CertBytes:   .Marshal(),
			X:           .X,
			Comments:    ,
			Constraints: ,
		})
	case *ecdsa.PrivateKey:
		 = ssh.Marshal(ecdsaCertMsg{
			Type:        .Type(),
			CertBytes:   .Marshal(),
			D:           .D,
			Comments:    ,
			Constraints: ,
		})
	case ed25519.PrivateKey:
		 = ssh.Marshal(ed25519CertMsg{
			Type:        .Type(),
			CertBytes:   .Marshal(),
			Pub:         []byte()[32:],
			Priv:        []byte(),
			Comments:    ,
			Constraints: ,
This function originally supported only *ed25519.PrivateKey, however the general idiom is to pass ed25519.PrivateKey by value, not by pointer. We still support the pointer variant for backwards compatibility.
	case *ed25519.PrivateKey:
		 = ssh.Marshal(ed25519CertMsg{
			Type:        .Type(),
			CertBytes:   .Marshal(),
			Pub:         []byte(*)[32:],
			Priv:        []byte(*),
			Comments:    ,
			Constraints: ,
		})
	default:
		return fmt.Errorf("agent: unsupported key type %T", )
	}
if constraints are present then the message type needs to be changed.
	if len() != 0 {
		[0] = agentAddIDConstrained
	}

	,  := ssh.NewSignerFromKey()
	if  != nil {
		return 
	}
	if bytes.Compare(.Key.Marshal(), .PublicKey().Marshal()) != 0 {
		return errors.New("agent: signer and cert have different public key")
	}

	,  := .call()
	if  != nil {
		return 
	}
	if ,  := .(*successAgentMsg);  {
		return nil
	}
	return errors.New("agent: failure")
}
Signers provides a callback for client authentication.
func ( *client) () ([]ssh.Signer, error) {
	,  := .List()
	if  != nil {
		return nil, 
	}

	var  []ssh.Signer
	for ,  := range  {
		 = append(, &agentKeyringSigner{, })
	}
	return , nil
}

type agentKeyringSigner struct {
	agent *client
	pub   ssh.PublicKey
}

func ( *agentKeyringSigner) () ssh.PublicKey {
	return .pub
}

The agent has its own entropy source, so the rand argument is ignored.
	return .agent.Sign(.pub, )
}

func ( *agentKeyringSigner) ( io.Reader,  []byte,  crypto.SignerOpts) (*ssh.Signature, error) {
	var  SignatureFlags
	if  != nil {
		switch .HashFunc() {
		case crypto.SHA256:
			 = SignatureFlagRsaSha256
		case crypto.SHA512:
			 = SignatureFlagRsaSha512
		}
	}
	return .agent.SignWithFlags(.pub, , )
}
Calls an extension method. It is up to the agent implementation as to whether or not any particular extension is supported and may always return an error. Because the type of the response is up to the implementation, this returns the bytes of the response and does not attempt any type of unmarshalling.
func ( *client) ( string,  []byte) ([]byte, error) {
	 := ssh.Marshal(extensionAgentMsg{
		ExtensionType: ,
		Contents:      ,
	})
	,  := .callRaw()
	if  != nil {
		return nil, 
	}
	if len() == 0 {
		return nil, errors.New("agent: failure; empty response")
[PROTOCOL.agent] section 4.7 indicates that an SSH_AGENT_FAILURE message represents an agent that does not support the extension
	if [0] == agentFailure {
		return nil, ErrExtensionUnsupported
	}
	if [0] == agentExtensionFailure {
		return nil, errors.New("agent: generic extension failure")
	}

	return , nil