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
- Variables
- func RequestAgentForwarding(session *ssh.Session) error
- func ServeAgent(agent Agent, c io.ReadWriter) error
- func SetupAgentForwarding(client *ssh.Client) (func() (ssh.Channel, error), error)
- func SetupRemoteForwarding(client *ssh.Client, addr string) (func() (ssh.Channel, error), error)
- type Agent
- type Client
- func (c *Client) Add(key InputKey) error
- func (c *Client) Close() error
- func (c *Client) Extension(extensionType string, contents []byte) ([]byte, error)
- func (c *Client) List() ([]*Key, error)
- func (c *Client) Lock(passphrase []byte) error
- func (c *Client) Remove(key ssh.PublicKey) error
- func (c *Client) RemoveAll() error
- func (c *Client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error)
- func (c *Client) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error)
- func (c *Client) Signers() ([]ssh.Signer, error)
- func (c *Client) Unlock(passphrase []byte) error
- type ConstraintExtension
- type DestinationConstraint
- type HostIdentity
- type InputKey
- type Key
- type KeySpec
- type PublicKeyUserAuthRequest
- type RestrictDestinationConstraintExtension
- type Session
- type SessionBind
- type SignOptions
- type SignatureFlags
Constants ¶
const ( // RestrictDestinationExtensionName is the identifier for the destination // restriction extension. RestrictDestinationExtensionName = "[email protected]" )
Variables ¶
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.
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
Add adds a private key to the agent. If a certificate is given, that certificate is added instead as public key.
func (*Client) Extension ¶
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) Sign ¶
Sign has the agent sign the data using a protocol 2 key as defined in [PROTOCOL.agent] section 2.6.2.
func (*Client) SignWithFlags ¶
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 ¶
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 ¶
Key represents a protocol 2 public key as defined in [PROTOCOL.agent], section 2.5.2.
type KeySpec ¶
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 ¶
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.