SSH with the gpg-agent and Yubikey

7 minute read

If you have configured an authentication key in your Yubikey’s OpenPGP slot, you can use gpg-agent to SSH with this authentication key. The advantages are :

  • your key is secure: it never leaves your Yubikey
  • your key is always with you
  • you can use “Touch to authenticate”

But there are some inconveniences:

  • You must install and configure gpg-agent on the computer you wish to use the Yubikey
  • The setup was not that easy, and it must be repeated for each computer

This guide is largely based on DrDuh YubiKey Guide.

Create your GPG configuration

We start by creating the gpg configuration if it does not exist already. Paste the following text into a terminal window to create a recommended GPG configuration:

$ cat << EOF > ~/.gnupg/gpg.conf
auto-key-locate keyserver
keyserver hkps://hkps.pool.sks-keyservers.net
keyserver-options no-honor-keyserver-url
keyserver-options ca-cert-file=/etc/sks-keyservers.netCA.pem
keyserver-options no-honor-keyserver-url
keyserver-options debug
keyserver-options verbose
personal-cipher-preferences AES256 AES192 AES CAST5
personal-digest-preferences SHA512 SHA384 SHA256 SHA224
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
cert-digest-algo SHA512
s2k-cipher-algo AES256
s2k-digest-algo SHA512
charset utf-8
fixed-list-mode
no-comments
no-emit-version
keyid-format 0xlong
list-options show-uid-validity
verify-options show-uid-validity
with-fingerprint
use-agent
require-cross-certification
EOF

To install the keyservers CA file:

$ sudo curl -s "https://sks-keyservers.net/sks-keyservers.netCA.pem" -o /etc/sks-keyservers.netCA.pem

Importing the public key

Import the public key from a file with:

$ gpg2 --import < /mnt/public-usb-key/pubkey.txt
gpg: key 0xFF3E7D88647EBCDB: public key "Dr Duh <doc@duh.to>" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)

Or download from a keyserver:

$ gpg --recv 0xFF3E7D88647EBCDB
gpg: requesting key 0xFF3E7D88647EBCDB from hkps server hkps.pool.sks-keyservers.net
[...]
gpg: key 0xFF3E7D88647EBCDB: public key "Dr Duh <doc@duh.to>" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)

You may get an error gpgkeys: HTTP fetch error 1: unsupported protocol – this means you need to install a special version of curl which supports gnupg: sudo apt-get install gnupg-curl

Insert YubiKey

Unplug and replug the Yubikey. Check the card’s status:

$ gpg --card-status
Application ID ...: D2760001240102010006055532110000
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 05553211
Name of cardholder: Dr Duh
Language prefs ...: en
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: doc@duh.to
Signature PIN ....: not forced
Key attributes ...: 4096R 4096R 4096R
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 0
Signature key ....: 07AA 7735 E502 C5EB E09E  B8B0 BECF A3C1 AE19 1D15
      created ....: 2016-05-24 23:22:01
Encryption key....: 6F26 6F46 845B BEB8 BDF3  7E9B 5912 A795 E90D D2CF
      created ....: 2016-05-24 23:29:03
Authentication key: 82BE 7837 6A3F 2E7B E556  5E35 3F29 127E 7964 9A3D
      created ....: 2016-05-24 23:36:40
General key info..: pub  4096R/0xBECFA3C1AE191D15 2016-05-24 Dr Duh <doc@duh.to>
sec#  4096R/0xFF3E7D88647EBCDB  created: 2016-05-24  expires: never
ssb>  4096R/0xBECFA3C1AE191D15  created: 2016-05-24  expires: never
                      card-no: 0006 05553211
ssb>  4096R/0x5912A795E90DD2CF  created: 2016-05-24  expires: never
                      card-no: 0006 05553211
ssb>  4096R/0x3F29127E79649A3D  created: 2016-05-24  expires: never
                      card-no: 0006 05553211

sec# indicates master key is not available (as it should be stored encrypted offline).

Use gpg-agent

Paste the following text into a terminal window to create a recommended GPG agent configuration:

$ cat << EOF > ~/.gnupg/gpg-agent.conf
enable-ssh-support
pinentry-program /usr/bin/pinentry-curses
default-cache-ttl 60
max-cache-ttl 120
write-env-file
use-standard-socket
EOF

If you are using Linux on the desktop, you may want to use /usr/bin/pinentry-gnome3 to use a GUI manager.

Replace ssh-agent with gpg-agent

gpg-agent provides OpenSSH agent emulation. To launch the agent for use by ssh use the gpg-connect-agent /bye or gpgconf --launch gpg-agent commands.

Add these to your shell rc file (~/.zshrc or ~/.bashrc):

alias gpg=gpg2
export GPG_TTY="$(tty)"
export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
gpgconf --kill gpg-agent
gpg-agent --daemon --enable-ssh-support

In Debian, SSH_AUTH_SOCK can be found in ${HOME}/.gnupg/S.gpg-agent.ssh, but if you have gnome-keyring activated it will be in $XDG_RUNTIME_DIR/gnupg/S.gpg-agent.ssh. This is why we use gpgconf to determine where it is automatically.

And source your file:

source ~/.zshrc

Then launch your gpg-agent:

sudo killall gpg-agent
gpg-agent --daemon --enable-ssh-support

About gpg-agent and Gnome-Keyring

There are some known problem about using gpg-agent with the gnome-keyring. Here is what the GnuPG Wiki says about it :

Some versions of Gnome Keyring hijack the connection to GPG Agent (they intercept all the communication between gpg or gpgsm and gpg-agent) by setting the GPG_AGENT_INFO environment variable to point to the Gnome Keyring process. Gnome Keyring then filters all communication with gpg-agent. Unfortunately, Gnome Keyring’s implementation of that internal GnuPG protocol is incomplete. Thus although many operations work, in particular, working with smart cards results in errors

To solve this problem, you can disable gnome-keyring.

Disabling Gnome-Keyring

Copy the original desktop files for GNOME Keyring to ~/.config/autostart

cd /etc/xdg/autostart
cp gnome-keyring-gpg.desktop gnome-keyring-ssh.desktop ~/.config/autostart  

You might not have gnome-keyring-gpg.desktop, in this case you can just create one in ~/.config/autostart. Then append X-GNOME-Autostart-enabled=falseto each of these files :

echo "X-GNOME-Autostart-enabled=false" >> ~/.config/autostart/gnome-keyring-gpg.desktop
echo "X-GNOME-Autostart-enabled=false" >> ~/.config/autostart/gnome-keyring-ssh.desktop

If you want to disable GNOME-Keyring system-wide, you can make the above change directly in the original desktop files (/etc/xdg/autostart/gnome-keyring-*.desktop).

Systemd bug

You might encounter another problem. If you use killall gpg-agent to kill all gpg agents and then try to start another agent manually with gpg-agent, you will see this error message :

gpg-agent --enable-ssh-support --daemon
gpg-agent: a gpg-agent is already running - not starting a new one

This problem is due to systemd managing the gpg-agent and the --enable-ssh-support not working properly.

There is a debian bugs explaining that users who don’t want systemd to manage their gpg-agent in this way for all future sessions should do:

systemctl --user mask --now gpg-agent.service gpg-agent.socket gpg-agent-ssh.socket gpg-agent-extra.socket gpg-agent-browser.socket

Doing this means that gpg-agent will fall back to its manual mode of operation. (This decision can be reversed by the user with “unmask” instead of “mask”)

Some links :

AskUbuntu :

Adding comment as I had the same issue with ed25519 keys. The issue is indeed gnome-keyring

StackExchange

I was generating my ssh keys with ssh-keygen and added an additional argument “-o” which generated the keys in a new format for openSSH. The problem was that my gnome-keyring did not support such keys as the keys had Ed255519 signature scheme. Gnome-keyring does not support that since 3.20. I reverted to RSA and no more problems!.

Xmodulo.com : How to disable gnome-keyring.

Debian Wiki : This link explains how to manually disable the internal gpg-agent and ssh-agent for gnome-keyring version < 3.16.0-3

Use your authentication key with Github or Gitlab

Here we test our setup with Github. We will start by adding our ssh key to our Github account.

To display your ssh key use:

ssh-add -L

If you do not see your ssh key, you might still have ssh-agents running in the background.

Then use the output to add ssh key to your Github account. Once this is done test your connection with:

ssh git@github.com -T
Hi Sammy! You\'ve successfully authenticated, but GitHub does not provide shell access.

Add your new ssh key to your servers

Reactivating ssh

Copy your ssh key if you haven’t already. You might need to restart your ssh-agent and re-add you ssh keys to connect to your server :

sudo killall gpg-agent
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_rsa

You need to add your private key to the agent for it to work.

Adding the keys to the server

First connect to your server :

ssh sammy@server.com

On your server, first as a security precaution, temporarily allow password authentication. If anything goes wrong, you will still have access to your server.

/etc/ssh/sshd_config
PasswordAuthentication yes

Then add your ssh keys in ~/.ssh/authorized_keys.

sudo vim ~/.ssh/authorized_keys

Test the connection

Finally activate your gpg-agent to test your connection.

sudo killall gpg-agent
gpg-agent --daemon --enable-ssh-support
source ~/.zshrc

Connect your security key and test to see its ssh key:

ssh-add -L

Test your connection

ssh sammy@server.com

You will be asked for your security key PIN. This is a good indication that the correct SSH key is used.

If the connection does not work:

sudo killall gpg-agent
gpg-agent --daemon --enable-ssh-support

And retest.

Secure your server

Disable password authentication

/etc/ssh/sshd_config
PasswordAuthentication no

Optionally you could remove your other ssh keys from ~/.ssh/authorized_keys.

Yubikey: requiring touch to authenticate

By default the Yubikey will perform key operations without requiring a touch from the user. To require a touch for every SSH connection, use the Yubikey Manager (you’ll need the Admin PIN):

sudo apt-get install yubikey-manager
ykman openpgp touch aut on

In case you have an error, try removing and reinserting your Yubikey

To require a touch for the signing and encrypting keys as well:

ykman openpgp touch sig on
ykman openpgp touch enc on

The Yubikey will blink when it’s waiting for the touch.