#openpgp-card #ssh-agent #ssh-key #authentication #pin #user #rsa

app openpgp-card-ssh-agent

A simple ssh-agent backed by OpenPGP card authentication keys

16 releases

0.3.2 Apr 23, 2024
0.3.1 Mar 26, 2024
0.2.4 Mar 24, 2024
0.2.0 Feb 28, 2024
0.1.4 Aug 27, 2022

#161 in Cryptography


450 lines

Simple standalone SSH Agent for OpenPGP cards

crates-io-badge status-badge

This is a simple SSH agent that uses keys on OpenPGP cards. Cards are accessed via PC/SC (e.g. via pcscd).

The agent currently supports RSA 2048/4096, NIST P-256/384/521 and Curve 25519 keys.

This agent relies on openpgp-card-state for OpenPGP card User PIN handling.

Development status

This ssh-agent works, and you can use it right now.

However, it's in an early development stage. We might break things temporarily, in the course of development.


You can install the latest openpgp-card-ssh-agent from crates.io by running

$ cargo install openpgp-card-ssh-agent

Or from this repository, by checking out the code and running:

$ cargo install --path .

Persisting your OpenPGP card's User PIN

This ssh-agent uses OpenPGP card hardware to perform private key cryptographic operations. These cards require a User PIN to authorize operations.

This ssh-agent assumes that the User PIN for your card is persisted on your host computer, and that the PIN can be obtained by the ssh-agent. Ideally without requiring any user-interaction.

OpenPGP card User PINs are stored in a platform-specific secrets storage mechanism. Those stores are long-term persistent, so it is typically sufficient to persist a User PIN once per machine.

See openpgp-card-state for more details.

Listing OpenPGP cards

To see which OpenPGP cards are connected to your machine and can be used with the ssh agent, you can use the ssh-add command to obtain a list from the ssh-agent, like this:

$ ssh-add -L
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFKjA9vr4sa4WznatwBo05LrmZ2jogj3fyrQ5hNLYsFT 0000:01234567

The output shows the public key material in your card's authentication key slot (shown in OpenSSH format), and the card's identifier (here: 0000:01234567). You can use that identifier to store the User PIN, as described in the next section (using ssh-add -s 0000:01234567).

Note that this list doesn't indicate if a PIN has been stored for a card, already.

Storing the User PIN with ssh-add

To store a card's User PIN on your system, you can use the ssh-add command and provide the card's "ident" (in this example: 0000:01234567):

$ ssh-add -s 0000:01234567
Enter passphrase for PKCS#11:

The message says that a "passphrase for PKCS#11" should be entered. This is inapplicable and confusing, when using this ssh-agent. However, this string is hard coded in ssh and the wording of this message can be safely ignored.

At this prompt you can enter the User PIN (the default User PIN for many OpenPGP cards is 123456). The PIN will get tested on the card, and persisted if the card accepts it as valid.

Running the ssh agent

$ openpgp-card-ssh-agent -H unix://$XDG_RUNTIME_DIR/ocsa.sock

To debug the operation of the agent, you can view debug output, e.g. by running it like this:

$ RUST_LOG=debug openpgp-card-ssh-agent -H unix://$XDG_RUNTIME_DIR/ocsa.sock

On Windows, use the following format to use a Named Pipe:

$ openpgp-card-ssh-agent -H \\.\pipe\ocsa


To use this ssh-agent, you need to set the SSH_AUTH_SOCK environment variable:

$ export SSH_AUTH_SOCK=$XDG_RUNTIME_DIR/ocsa.sock

Or, on Windows, set the variable to the Named Pipe:

set SSH_AUTH_SOCK=\\.\pipe\ocsa

After that, regular ssh usage will work and automatically use any available OpenPGP cards for authentication:

$ ssh <hostname>

Besides OpenPGP card User PINs, this agent doesn't require any configuration or state. Any card can be plugged in and will be used automatically if the public key material in its authentication key slot is requested for signing by ssh.

Cards that are plugged in after that ssh-agent is started will be automatically found during the next operation.


Problems with access to OpenPGP card devices

GnuPG may lock cards by default. This can prevent other software, like this ssh-agent from accessing a card. Killing the scdaemon process (which handles smart card access for GnuPG) is a simple way to debug problems with card access.

Git for Windows

Git access over SSH on Windows may fail to work with this ssh agent. If so, the cause is typically that Git on Windows comes with a bundled OpenSSH client which does not support Named Pipes.

To resolve this, you should switch to use the "Windows native implementation of OpenSSH" by selecting the appropriate option during installation of Git for Windows.

Notifications for touch confirmation

This SSH agent uses the notify-rust crate to alert the user if the card requires touch confirmation.

To build without the notification mechanism (not recommended), you can use the --no-default-features parameter.


This project is based very heavily on work by Wiktor Kwapisiewicz. Much of the heavy ssh lifting is happening in ssh-agent-lib.


~531K SLoC