agent

package module
v0.0.0-...-7531221 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 20, 2026 License: Unlicense Imports: 20 Imported by: 0

README

Agent V2

Go Reference

Documentation

Overview

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

Index

Constants

View Source
const (
	// RestrictDestinationExtensionName is the identifier for the destination
	// restriction extension.
	RestrictDestinationExtensionName = "[email protected]"
)

Variables

View Source
var ErrAgentChannelClosed = errors.New("agent: channel closed")

ErrAgentChannelClosed is returned by the accept function created by SetupAgentForwarding or SetupRemoteForwarding when the underlying agent channel has been closed.

View Source
var ErrExtensionUnsupported = errors.New("agent: extension unsupported")

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.

Functions

func RequestAgentForwarding

func RequestAgentForwarding(session *ssh.Session) error

RequestAgentForwarding sets up agent forwarding for the session. ForwardToAgent or ForwardToRemote should be called to route the authentication requests.

func ServeAgent

func ServeAgent(agent Agent, c io.ReadWriter) error

ServeAgent serves the Agent protocol on the given connection. It returns when an I/O error occurs.

It supports the "[email protected]" extension, maintaining the state of the connection's session binds and passing them to the underlying Agent implementation for constraint verification.

func SetupAgentForwarding

func SetupAgentForwarding(client *ssh.Client) (func() (ssh.Channel, error), error)

SetupAgentForwarding registers a handler for agent forwarding channels and returns a function that can be called multiple times to accept individual connections.

The returned accept function blocks until a connection is received or an error occurs. When the SSH client disconnects, the accept function will return ErrAgentChannelClosed.

Example usage:

accept, err := SetupAgentForwarding(client)
if err != nil {
    // Handle error
}
for {
    channel, err := accept()
    if err != nil {
        // Handle error (e.g., client disconnected)
        break
    }
    go func(ch ssh.Channel) {
        ServeAgent(agent, ch)
        ch.Close()
    }(channel)
}

This function will return an error if the channel type is already registered.

func SetupRemoteForwarding

func SetupRemoteForwarding(client *ssh.Client, addr string) (func() (ssh.Channel, error), error)

SetupRemoteForwarding registers a handler for agent forwarding channels and returns a function that can be called multiple times to accept individual connections to forward to a remote ssh-agent process.

The returned accept function blocks until a connection is received or an error occurs. When the SSH client disconnects, the accept function will return ErrAgentChannelClosed.

Example usage:

accept, err := SetupRemoteForwarding(client, "/path/to/agent.sock")
if err != nil {
    // Handle error
}
for {
    channel, err := accept()
    if err != nil {
        // Handle error
        break
    }
    go forwardUnixSocket(channel, "/path/to/agent.sock")
}

This function will return an error if the channel type is already registered or if the unix socket cannot be accessed.

Types

type Agent

type Agent interface {
	// List returns the identities known to the agent.
	//
	//
	// If a session is provided, the agent may filter the returned keys based
	// on destination constraints. For example, keys that are not permitted
	// for the current session hops may be hidden to prevent enumeration.
	List(ctx context.Context, session *Session) ([]*Key, error)

	// Sign has the agent sign the data using a protocol 2 key as defined
	// in [PROTOCOL.agent] section 2.6.2.
	//
	// The options parameter allows passing the current Session state. The agent
	// validates the request against the session bindings and the key's
	// constraints before signing.
	Sign(ctx context.Context, key ssh.PublicKey, data []byte, options *SignOptions) (*ssh.Signature, error)

	// Add adds a private key to the agent.
	//
	// If a session is provided, the agent verifies that the operation is
	// permitted within the context of that session.
	Add(ctx context.Context, key InputKey, session *Session) error

	// Remove removes all identities with the given public key.
	//
	// If a session is provided, the agent may refuse to remove a key if the
	// session constraints do not allow visibility of that key (preventing
	// oracle attacks).
	Remove(ctx context.Context, key ssh.PublicKey, session *Session) error

	// RemoveAll removes all identities.
	RemoveAll(ctx context.Context, session *Session) error

	// Lock locks the agent. Sign and Remove will fail, and List will empty an empty list.
	Lock(ctx context.Context, passphrase []byte, session *Session) error

	// Unlock undoes the effect of Lock
	Unlock(ctx context.Context, passphrase []byte, session *Session) 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.
	//
	// The session parameter provides the current session context, which may be
	// relevant for extensions that verify the connection topology or session
	// bindings.
	//
	// 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(ctx context.Context, extensionType string, contents []byte, session *Session) ([]byte, error)
}

Agent represents the server-side implementation of an SSH agent.

This interface defines the capabilities required to manage SSH identities, process signing requests, and handle protocol extensions. All methods accept a context.Context for cancellation and timeout management. Crucially, most methods accept a *Session or *SignOptions, allowing the implementation to enforce granular security policies.

func NewKeyring

func NewKeyring() Agent

NewKeyringV2 returns a new in-memory Agent implementation. It is safe for concurrent use by multiple goroutines.

It supports "[email protected]" constraints and enforces them based on the Session information provided during calls.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a client for an ssh-agent process.

func NewClientFromAgent

func NewClientFromAgent(agent Agent) *Client

NewClientFromAgent returns a Client that communicates with the given Agent implementation over an in-memory connection. This is useful for wrapping an Agent implementation (such as one returned by NewKeyring) to use it through the Client interface.

The returned Client will support all features of the underlying Agent, including extensions like "[email protected]" and constraints like "[email protected]".

func NewClientFromConn

func NewClientFromConn(rw io.ReadWriteCloser) *Client

NewClientFromConn returns an Agent that talks to an ssh-agent process over the given connection.

func (*Client) Add

func (c *Client) Add(key InputKey) error

Add adds a private key to the agent. If a certificate is given, that certificate is added instead as public key.

func (*Client) Close

func (c *Client) Close() error

Close closes the underlying connection

func (*Client) Extension

func (c *Client) Extension(extensionType string, contents []byte) ([]byte, error)

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) List

func (c *Client) List() ([]*Key, error)

List returns the identities known to the agent.

func (*Client) Lock

func (c *Client) Lock(passphrase []byte) error

func (*Client) Remove

func (c *Client) Remove(key ssh.PublicKey) error

func (*Client) RemoveAll

func (c *Client) RemoveAll() error

func (*Client) Sign

func (c *Client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error)

Sign has the agent sign the data using a protocol 2 key as defined in [PROTOCOL.agent] section 2.6.2.

func (*Client) SignWithFlags

func (c *Client) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error)

func (*Client) Signers

func (c *Client) Signers() ([]ssh.Signer, error)

Signers provides a callback for client authentication.

func (*Client) Unlock

func (c *Client) Unlock(passphrase []byte) error

type ConstraintExtension

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 RFC 4251, e.g.  "[email protected]".
	ExtensionName string
	// ExtensionDetails contains the actual content of the extended
	// constraint.
	ExtensionDetails []byte
}

ConstraintExtension describes an optional constraint defined by users.

type DestinationConstraint

type DestinationConstraint struct {
	From HostIdentity
	To   HostIdentity
}

DestinationConstraint defines a single rule allowing a key to be used from a specific source host to a specific destination host.

type HostIdentity

type HostIdentity struct {
	Username string
	Hostname string
	HostKeys []KeySpec
}

HostIdentity represents a host and user specification within a constraint, including the expected host keys.

type InputKey

type InputKey struct {
	// PrivateKey must be a *rsa.PrivateKey, *dsa.PrivateKey,
	// ed25519.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
}

InputKey describes an SSH key to be added to an Agent.

type Key

type Key struct {
	Format  string
	Blob    []byte
	Comment string
}

Key represents a protocol 2 public key as defined in [PROTOCOL.agent], section 2.5.2.

func (*Key) Marshal

func (k *Key) Marshal() []byte

Marshal returns key blob to satisfy the ssh.PublicKey interface.

func (*Key) String

func (k *Key) String() string

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) Type

func (k *Key) Type() string

Type returns the public key type.

func (*Key) Verify

func (k *Key) Verify(data []byte, sig *ssh.Signature) error

Verify satisfies the ssh.PublicKey interface.

type KeySpec

type KeySpec struct {
	Key ssh.PublicKey
	CA  bool
}

KeySpec represents a specific key (and whether it is a CA) allowed for a host in a destination constraint.

type PublicKeyUserAuthRequest

type PublicKeyUserAuthRequest struct {
	User      string
	Service   string
	Method    string
	SessionID []byte
	Algorithm string
	PublicKey ssh.PublicKey
	// HostKey is not nil for [email protected] method.
	HostKey ssh.PublicKey
}

PublicKeyUserAuthRequest represents the parsed fields of an SSH_MSG_USERAUTH_REQUEST packet. See RFC 4252 section 5.

FIXME: this should be added to crypto/ssh.

func ParsePublicKeyUserAuthRequest

func ParsePublicKeyUserAuthRequest(data []byte) (PublicKeyUserAuthRequest, error)

ParsePublicKeyUserAuthRequest parses the payload of an SSH_MSG_USERAUTH_REQUEST packet.

type RestrictDestinationConstraintExtension

type RestrictDestinationConstraintExtension struct {
	Constraints []DestinationConstraint
}

RestrictDestinationConstraintExtension represents the content of the "[email protected]" constraint.

func ParseRestrictDestinationConstraintExtension

func ParseRestrictDestinationConstraintExtension(data []byte) (RestrictDestinationConstraintExtension, error)

ParseRestrictDestinationConstraintExtension parses the constraints blob associated with a key.

type Session

type Session struct {
	// Binds contains the list of hops recorded for this connection.
	Binds []SessionBind
	// BindsAttempted indicates if the client has attempted to send session-bind
	// messages, even if the list is empty.
	BindsAttempted bool
}

Session represents the state of the current connection to the agent, specifically tracking the chain of session binds (hops) established via the "[email protected]" extension.

type SessionBind

type SessionBind struct {
	HostKey    ssh.PublicKey
	SessionID  []byte
	Forwarding bool
}

SessionBind represents a single hop in the agent forwarding chain, as defined by the "[email protected]" extension in [PROTOCOL.agent].

func ParseSessionBind

func ParseSessionBind(data []byte) (SessionBind, error)

ParseSessionBind parses the payload of a "[email protected]" extension message. It verifies the signature within the bind message to ensure the integrity of the hop.

type SignOptions

type SignOptions struct {
	Flags SignatureFlags
	// Session represents the current session state associated with the request.
	Session *Session
}

SignOptions contains additional parameters for the Sign operation.

type SignatureFlags

type SignatureFlags uint32

SignatureFlags represent additional flags that can be passed to the signature requests an defined in [PROTOCOL.agent] section 4.5.1.

const (
	SignatureFlagReserved SignatureFlags = 1 << iota
	SignatureFlagRsaSha256
	SignatureFlagRsaSha512
)

SignatureFlag values as defined in [PROTOCOL.agent] section 5.3.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL