YubiKey GPG-Agent Forwarding and Crypt4GH

Written by Dominik Pantůček on 2025-08-28

pgpyubikey

Working on YubiKey support through GnuPG to enable working with Crypt4GH containers protected by private key stored in a trusted device, it seemed like a natural extension to keep the key locally and use it remotely - for example on a high-performance computing server.


Thanks to our previous work on LibAssuan support in oarepo-c4gh package, YubiKey works locally like a charm and all you need to do in order to unlock Crypt4GH containers is to plug it in, have an OpenPGP app enabled on the token and ensure GnuPG installation (at least version 2.4) recognizes it. These requirements are met by default on most LTS operating systems commonly used. The library recognizes the Curve25519 key provided by the appliance and uses it without further ado. If required, the user has to explicitly confirm the key usage by pressing the YubiKey button as they are used to.

The computing power of desktop computers and laptops most people use is limited though and therefore it would be very useful to allow the users to use their private keys in their hardware tokens and perform any computation on the encrypted data remotely on a more performant hardware. Some means of forwarding the connection to the YubiKey token need to be set up in order for this to work without compromising the private key in question.

Luckily as the oarepo-c4gh is using gpg-agent service for communicating with YubiKey and its OpenPGP card application, all that is needed is to forward the controlling socket of this service to the remote host. With the latest versions of OpenSSH, it is pretty damn straightforward:

#!/bin/sh
ssh -R "/run/user/$USERID/gnupg/S.gpg-agent:$(gpgconf --list-dir agent-socket)" "$@"

Given the "$@" argument means that the user can pass on normal SSH arguments such as username and hostname and it will work. However there are some security considerations here. Typically the advice is to always forward only the "extra" socket of gpg-agent. Trouble is that the "extra" socket cannot list the private keys available and therefore requires more setup on the remote host. The main socket allows listing the private keys - without their actual contents, of course. It is obvious that people should use this type of forwarding only with a hardware token like YubiKey and always only for one specific purpose - like here in our case for opening Crypt4GH containers.

The question remains, how do we get the remote user's id? It should be known beforehand which means another SSH connection is to be made, but other than this little inconvenience, it is also very easy:

#!/bin/sh
USERID=`ssh -q "$@" id -u`

There are still some gotchas if you do not read the full documentation, the most imporant ones being:

  • what if the gpg-agent is running on the remote host?
  • what if the socket path already exists (even though the agent is not running)?
  • what if the GnuPG working directories do not exist?

For the first problem, we just ensure the agent gets killed. For the second one, we remove the path in question unconditionally. And for the third one we only need to perform any GnuPG operation - such as listing available keys. Yes, listing available keys where there are none - meaning we are listing an empty set of keys - is enough. That is another one-line script:

#!/bin/sh
ssh "$@" "gpg --list-keys ; gpgconf --kill gpg-agent ; rm -f /run/user/$USERID/gnupg/S.gpg-agent"

And yes, a convenient script can be created by putting all the snippets above into a single script below:

#!/bin/sh
USERID=`ssh -q "$@" id -u`
ssh "$@" "gpg --list-keys ; gpgconf --kill gpg-agent ; rm -f /run/user/$USERID/gnupg/S.gpg-agent"
ssh -R "/run/user/$USERID/gnupg/S.gpg-agent:$(gpgconf --list-dir agent-socket)" "$@"

It opens an interactive session and we can use local keys remotely. As a part of our work on Crypt4GH support, this script is available as gpg-agent-forward.sh in the oarepo-c4gh repository and will get updated as new requirements emerge.

In order to support strictly forwarding of the functionality required by our Crypt4GH implementation a custom network protocol is in the works and when that is released, no agent forwarding will be needed anymore in most scenarios.

Hope you liked our effort to keep your private keys truly private even when working on a remote supercomputer and if you wanna read more, see ya next time!