Using OpenPGP keys with ssh
ssh
, the command line client for Secure Shell, uses public key cryptography as one method of authentication. For that, a ssh key pair has to be generated and the public part of that pair has to be configured at the server side as an authorized key. ssh
can also use OpenPGP keys for that purpose. A bird's eye view of the configuration looks like:
On the server side nothing changes. The public part of the key has to be configured as authorized key.
On the client side:
ssh
uses anssh-agent
to manage its secrets, here anssh-agent
has to be used which can facilitate OpenPGP keys.- There can be more than one active
ssh-agent
,ssh
can be told to use a specific agent by setting theSSH_AUTH_SOCK
environment variable accordingly. - An agent which can use OpenPGP keys is
gpg-agent
.gpg-agent
has to be configured to- start the
ssh-agent
subsystem - use a specific set of OpenPGP keys in the
ssh-agent
context
- start the
gpg-agent
needs agnupg
compatible backend to access the actual keys. Usingchameleon
for that purpose allows to integrate the keystore ofsq
.
Preparation
Prepare the key
To be used for ssh authentication, a key must have a subkey marked for authentication. Use sq inspect
to identify the subkey:
$ sq inspect --cert 8140AA1A97177805FD263466718AC099BAFDC830
OpenPGP Certificate.
Fingerprint: 8140AA1A97177805FD263466718AC099BAFDC830
Public-key algo: EdDSA
Public-key size: 256 bits
Creation time: 2025-03-19 13:29:31 UTC
Expiration time: 2028-03-19 06:55:52 UTC (creation time + 2years 11months 30days 9h 16m 45s)
Key flags: certification
Subkey: EA495531497101582BFCB0F947E2D1A287003BD9
Public-key algo: EdDSA
Public-key size: 256 bits
Creation time: 2025-03-19 13:29:31 UTC
Expiration time: 2028-03-19 06:55:52 UTC (creation time + 2years 11months 30days 9h 16m 45s)
Key flags: signing
Subkey: A07809FFE01CD7091B9CB6D40B3E57A87C4AFF46
Public-key algo: EdDSA
Public-key size: 256 bits
Creation time: 2025-03-19 13:29:31 UTC
Expiration time: 2028-03-19 06:55:52 UTC (creation time + 2years 11months 30days 9h 16m 45s)
Key flags: authentication
Subkey: DEE6688DA0336013F5E96062812861395DA7428C
Public-key algo: ECDH
Public-key size: 256 bits
Creation time: 2025-03-19 13:29:31 UTC
Expiration time: 2028-03-19 06:55:52 UTC (creation time + 2years 11months 30days 9h 16m 45s)
Key flags: transport encryption, data-at-rest encryption
UserID: <alice@example.com>
Certifications: 2, use --certifications to list
In this example the second subkey listed (Subkey: A07809FFE01CD7091B9CB6D40B3E57A87C4AFF46
) has a key flag authentication
- that is the subkey to use.
There is no necessity for a key to have an authenticating subkey, OpenPGP functionality doesn't use these type of keys. If your key misses such a subkey, you can add one by:
$ sq key subkey add --cert $FINGERPRINT --can-authenticate
With $FINGERPRINT
being the fingerprint of the primary key you want to add the subkey to.
Likewise you can revoke old authenticating subkeys. You can even have several such subkeys in your key - see chapter Adding subkeys.
Prepare the gpg-agent
Ensure that gpg-agent
activates its ssh-agent
subsystem. The configuration gpg-agent.conf
can be found in ~/.gnupg
and has to contain the line
enable-ssh-support
When started with this option, gpg-agent
listens to a unix socket for commands related to its ssh-agent
functionality. The socket can be found by:
$ gpgconf -L
The output has to contain the line
agent-ssh-socket:/home/user/.gnupg/S.gpg-agent.ssh
(your output might look a little different - look for agent-ssh-socket
).
From the example above, /home/user/.gnupg/S.gpg-agent.ssh
is the important bit: this is the value SSH_AUTH_SOCK
has to have in order to use gpg-agent
as ssh-agent
.
Register the key
gpg-agent
has to know which keys to use when authenticating a ssh session. For that purpose, add the keygrip of that key to ~/.gnupg/sshcontrol
on a line of its own.
To get the keygrip, use the chameleon - this example assumes that you installed the chameleon as gpg-sq
.
$ gpg-sq -k --with-keygrip --with-subkey-fingerprints 8140AA1A97177805FD263466718AC099BAFDC830
pub ed25519 2025-03-19 [C] [expires: 2028-03-19]
8140AA1A97177805FD263466718AC099BAFDC830
Keygrip = C7EC53D3635F42437C3C73DE6B34F4577F3FF346
uid [ full ] <alice@example.com>
sub ed25519 2025-03-19 [S] [expires: 2028-03-19]
EA495531497101582BFCB0F947E2D1A287003BD9
Keygrip = 55044CA1ED6232F784CFFF13589801F7027B8175
sub ed25519 2025-03-19 [A] [expires: 2028-03-19]
A07809FFE01CD7091B9CB6D40B3E57A87C4AFF46
Keygrip = FE39C76C0F879E840C1EE9E8E655694C73516437
sub cv25519 2025-03-19 [E] [expires: 2028-03-19]
DEE6688DA0336013F5E96062812861395DA7428C
Keygrip = 27244A6CC8B77ABE34BD54557241744157DC30C9
Again, the second subkey listed is the authentication key - see flag [A]
and the matching fingerprint. Add the keygrip FE39C76C0F879E840C1EE9E8E655694C73516437
to ~/.gnupg/sshcontrol
to use it.
Alternatively you can add keys to the ssh-agent
subsystem by:
$ gpg-connect-agent 'keyattr FE39C76C0F879E840C1EE9E8E655694C73516437 Use-for-ssh: true' /bye
and remove them with:
$ gpg-connect-agent 'keyattr FE39C76C0F879E840C1EE9E8E655694C73516437 Use-for-ssh: false' /bye
Use gpg-sq
The gpg-agent
uses a binary named gpg
to access stored keys. As the gpg
provided by g10code doesn't know about the keystore from Sequoia PGP, that binary has to be exchanged for chameleon
. There are many ways to achieve this. One way is to create a symlink and add the directory where the symlink was created in as first component in your PATH
environment variable:
$ mkdir $HOME/bin
$ ln -s /usr/bin/gpg-sq $HOME/bin/gpg
Adjust the paths accordingly.
Modify $PATH
(for instance in your .bashrc
):
export PATH="$HOME/bin:$PATH"
In a new shell (or after source .bashrc
) which gpg
should point to $HOME/bin/gpg
. You can check by
$ gpg --version
gpg (GnuPG-compatible Sequoia Chameleon) 2.2.40
Sequoia gpg Chameleon 0.13.1
sequoia-openpgp 2.0.0
Copyright (C) 2024 Sequoia PGP
...
Usage
First check if ssh
sees the OpenPGP key:
$ SSH_AUTH_SOCK=/home/user/.gnupg/S.gpg-agent.ssh ssh-add -L
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBvWSboin0MoLpdliKGTDEMx9zMplSbjfacaWxDeqqKq (none)
This gives you the public part of the ssh key pair, which has to be deposited as authenticated key in ~/.ssh/authenticated_keys
on the remote machine.
If you do not see your key in this list, chances are that gpg-agent
still uses g10codes gpg
.
Use
$ SSH_AUTH_SOCK=/home/user/.gnupg/S.gpg-agent.ssh ssh user@remote-host.tld
to connect to the remote server with your OpenPGP key. For convenience, you can set and export SSH_AUTH_SOCK
in your .bashrc
(or equivalent).