Skip to content

Add SshAgentServer for hosting keys over the agent protocol - #52

Open
darinkes wants to merge 1 commit into
mainfrom
feat/agent-server
Open

Add SshAgentServer for hosting keys over the agent protocol#52
darinkes wants to merge 1 commit into
mainfrom
feat/agent-server

Conversation

@darinkes

Copy link
Copy Markdown
Owner

Summary

Adds SshAgentServer, a minimal in-process ssh-agent. It holds SSH.NET keys and answers the agent protocol — identity listing and signing — over a unix domain socket (off Windows) or a Windows named pipe, so any SSH client (this library's own SshAgent, ssh, git, …) can use keys hosted by a .NET process. Because signing is done in-process with the loaded keys, the key material can come from anywhere the process can reach: a file, a freshly generated key, or an HSM/Key Vault wrapper.

This turns the library from an agent client into a small agent toolkit, and is the building block for Key Vault-backed agents, Pageant replacements and WSL↔Windows bridges.

API

var server = new SshAgentServer(params IPrivateKeySource[] keys);
server.Add(IPrivateKeySource key);
server.Remove(IPrivateKeySource key);
server.Start(string endpoint);   // socket path off Windows, pipe name on Windows
server.Dispose();                // stops listening
string? server.Endpoint { get; }

Protocol coverage

  • SSH2_AGENTC_REQUEST_IDENTITIES → lists the held keys (empty while locked)
  • SSH2_AGENTC_SIGN_REQUEST → signs with the matching key, honouring the RFC 8332 RSA sha2 sign flags
  • SSH2_AGENTC_REMOVE_IDENTITY / REMOVE_ALL_IDENTITIES
  • SSH_AGENTC_LOCK / UNLOCK
  • other requests (including ADD_IDENTITY) → SSH_AGENT_FAILURE

Keys are managed through the .NET API; pushing a key in over the protocol (ssh-add) is intentionally out of scope for now. Unix domain sockets need the netstandard2.1 or .NET build (same as the client).

Tests

SshAgentServerTests drives the server through the library's own SshAgent client over a real socket/pipe:

  • identity listing returns the right blob and comment
  • signing round-trips and the signature verifies against the public key for RSA, ECDSA (nistp256) and Ed25519
  • lock hides identities until unlocked; wrong passphrase is rejected
  • remove and remove-all

Full suite: 53 passed, 18 environment-skipped (Docker / Pageant / OS agent), 0 failed. All target frameworks build.

SshAgentServer holds SSH.NET keys and answers the agent protocol
(list and sign) over a unix domain socket or a Windows named pipe,
so any SSH client can use in-process keys. Signing uses the loaded
keys, honouring the RFC 8332 RSA sha2 sign flags. Supports list,
sign, remove, remove-all, lock and unlock; adding keys over the
protocol is refused. Keys are managed through the .NET API.

The endpoint is a signing authority, so it is restricted to the
current user: the unix socket is created owner-only (0600) on .NET 7+
and removed on dispose, and the Windows named pipe is created with a
current-user-only ACL. Tested through the library's own client
(list, sign/verify for RSA, ECDSA and Ed25519, lock, remove) and
end-to-end against a real SSH server.
@darinkes
darinkes force-pushed the feat/agent-server branch from dc4914e to b3d4238 Compare July 20, 2026 08:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant