Update: Watch my talk at OWASP Ottawa discussing SSH security (gives perspective to this walkthrough). Also if you are looking for a Linux or Chrome OS setup, look here.
At Reliza we are switching to using YubiKeys for our SSH authentication which is possible via PGP encryption. This guide is for Windows and using SSH via PuTTY. I found several nice references on the web (which are listed in the end) but all of them seemed to be missing a thing or two, so I decided this complete walkthrough for my future self and also for anyone interested. Note that I found this guide to be particularly good, but it’s missing few hiccups and description of proper PuTTY integration.
First of all, why do we need this? Answer is simple – Security! Alternatives include storing private keys directly on a workstation – which makes them poorly protected in multitude of attacks directed at workstation, a better option is to use encrypted usb key but this is tedious because leaving inserted and unsealed usb key for a long time is insecure, while inserting it and removing it back and forth all the time is tedious and time consuming.
YubiKey suits much better for this purpose. So let’s start.
1. Compatible hardware:
As listed on the YubiKey website, following products support PGP: YubiKey 4, YubiKey NEO, YubiKey 4 Nano, YubiKey NEO-n, YubiKey 5 NFC (this is what I’m using at the moment), YubiKey 5 Nano, YubiKey 4C, YubiKey 4C Nano, YubiKey 5C, YubiKey 5C Nano
Also it’s highly recommended to verify YubiKey before using it at https://www.yubico.com/genuine/
2. Software you’ll need on Windows:
Cygwin (do not install gnupg packages, but install openssh and ssh-pageant packages)
Install the required software at this step.
3. Prepare the key:
First thing’s first: key comes with some simple factory pins: 123456 regular and 12345678 admin one. Since those are insecure, first we should change them.
For this, insert YubiKey into usb slot, fire up PowerShell and type
This will start gpg/card prompt, where now enter
admin , and then
The menu that appears and shown on the image is self-explanatory. I recommend changing both PIN, admin PIN and setting reset code. Requirements on PINs are as following:
Must be 6 to 8 characters,
Contain characters from three of the following four categories:
- English uppercase characters (A through Z)
- English lowercase characters (a through z)
- Base 10 digits (0 through 9)
- Nonalphanumeric characters (e.g., !, $, #, %)
For storing PIN, a password manager works best, I would particularly recommend hash-based “Master Password”.
4. Set up PGP key on Kleopatra / YubiKey:
There are various methods discussed how to proceed regarding PGP key generation with some authors suggesting generating keys on the host and then exporting to the YubiKey. But I firmly believe that a private key should always be generated on its target medium and not copied or exported around. Caveat – if YubiKey gets lost, key is lost, you’re cut off from the environment. For that purposes, have 2 (or more) YubiKeys, and store them separately. And make sure to have independent keys on each of those YubiKeys. Plus, if we are talking about SSH, there must be more than one admin user per environment. Bottom line – create redundancy, as always in DevOps.
Insert YubiKey into USB slot. In Kleopatra, go to Tools -> Manage Smartcards. This should open “Smartcard Management” screen. In the actions on the bottom click on “Generate new Keys”. Enter name and email and click ok. Choose if you want to backup encryption key (I uncheck it, since I have another YubiKey for redundancy). When promted, enter pin for the card. While generating keys, do mouse movements to generate extra randomness.
Click “Back” on the left of Smartcard Management, which will bring you to the list of certificates and keys. Observe that there is a new certificate now with keys stored on the card.
At this stage, double click this new certificate and click “Export…” on the bottom which will show Public PGP key. This Public key must be backed up and imported to every workstation from which you are going to ssh using YubiKey. Note that it’s possible to publish this certificate to a public URL which makes perfect sense for digital signing case, but I would prefer not to do it for the SSH case and have a separate YubiKey for the signing case.
5. Workaround for Windows custom ssh agent:
Some later versions of Windows 10 include custom ssh agent, which is discussed here. This overwrites ssh-pageant and prevents our stack from working. The workaround is to remove %SYSTEMROOT%\System32\OpenSSH\ from the path.
6. Configure Kleopatra and cygwin to allow SSH support:
In Kleopatra, click on Settings -> Configure Kleopatra. Select GnuPG System and go to Private Keys tab. Check “Enable ssh support” and “Enable putty support” and Apply settings.
In cygwin, add
eval $(/usr/bin/ssh-pageant -r -a "/tmp/.ssh-pageant-$USERNAME")
on startup (i.e. append to the end of ~/.bashrc file)
Note, that there are known glitches on Windows sometimes, for which case restart gpg agent in powershell, using:
gpg-connect-agent killagent /bye gpg-connect-agent /bye
7. Produce public key for authorized keys:
Now, it’s time to establish connection to the server. In cygwin, with YubiKey inserted, type
This will display public key block that should be added into ~/.ssh/authorized_key file on the target server.
8. Using PuTTY with YubiKey:
With inserted YubiKey, PuTTY would work out of the box with default settings, while prompting to enter PIN every first time you SSH after inserting YubiKey into usb.
If it doesn’t work, try the workaround supplied by YubiKey developers (already discussed previously):
gpg-connect-agent killagent /bye gpg-connect-agent /bye
9. Transfering access to another machine:
If you need to transfer access to another machine, make sure to import certificate exported in step 4 to Kleopatra on the new machine using File -> Import.
This will essentially replicate configuration present on the source machine.
Bonus update: if you want to use your YubiKey on Linux or Chromebook via Linux, check my new post here.
11. Bonus update:
Reference comment describing how to export
Thanks for this writeup. I do have a question though.
You mention that you have a separate yubikey for signing. Our use case is two people. We each have two keys. I planned on keeping one key on my keyring for access while out with my laptop and another at my desk for my desk work. After reading your article, I’m now thinking maybe I should have a third for signing and use the one at the desk as a backup instead of daily use. Our use case is a combination of ssh server access and git on github. Thanks again for the writeup, it was a huge help.
Yes, this makes sense. Thanks for the feedback!
Hey Rob. You don’t *need* two different keys for this. A gpg key can have subkeys, meaning you can have multiple subkeys for signing and encrypting. Whether you really need to keep that separate depends entirely on your threat model, that is the first thing you should assess.
I too use GPG with Yubikey for ssh (among other things). I was frustrated about not being able to use GPG ssh for VScode remote editing, I needed to use GPG-agent with the the Windows 10 OpenSSH client…
I came across the wsl-ssh-pageant on GitHub (all credit to author), which creates a link between the pageant-like interface of GPG-agent and a windows Pipe. This means you can set SSH-AUTH-SOCK environment variable to the pipe and use GPG/GPG-Agent with the OpenSSH client!
This has worked really well for me, I made a simple .CMD file to do run the .exe at user login. Haven’t looked back!
Thanks for manual.
Maybe there is no need to install cygwin. If I understand it right, You need it only for displaying gpg public key in ssh format (ssh-add -L).
It can be done by gpg itself:
Thanks for the comment – yes, this would most probably work, although I haven’t tried. I use cygwin pretty much by default on my Windows machines.