Using YubiKey as a Windows SSH Smartcard

A key in a hand
Photo by CMDR Shane on Unsplash.

Some time ago, I got a YubiKey 4. I use it to secure access to a number of web services I use, but also to authenticate myself over SSH. Among its features, it supports being an an OpenPGP smartcard, which means — with some fiddling — it can be used for SSH authentication, so my SSH private key does not actually live on my physical computers.

This page documents the pieces I need to put together in order to get it working on Windows with all of the different SSH interfaces I use: PuTTY, WinSCP, OpenSSH for Windows, and Git. I do this through the Pageant agent.

Software and Requirements

I use SSH in several places in my workflow:

  • Remote shells via PuTTY, MobaXterm, or Windows OpenSSH.
  • Transfer files with WinSCP.
  • Push and pull from GitHub. Most of my local repositories are pulled over HTTPS, but a couple use SSH, and I use SSH (authenticated with a forwarded SSH agent connection) for all my repositories on servers.
  • Visual Studio Code remote sessions.

The first three can all be done with PuTTY, so as long as I can connect PuTTY to the smartcard, I’m good. VS Code, however, only supports Windows OpenSSH for its remote sessions, so I need it to be able to connect as well.

I occasionally use WSL, which induces yet a third set of requirements for connection. I don’t do this very often, though.

History: GPG4Win

Most existing documentation focuses on using the YubiKey with GPG4Win and gpg-agent’s OpenSSH and Pageant compatibility layers.

This works, but I found gpg-agent to be less than reliable, particularly when I inserted and removed my key. I commonly needed to restart the agent in order to make the public keys available again. I wrote a script to do that, but it was annoying. It also required custom editing of the configuration file to actually use my YubiKey.

But since I was using GPG4Win when I started, I used it to initialize the YubiKey’s keys. I therefore cannot provide instructions for setting up the public and private keys without GPG.

Installing: Scoop

I use Scoop to install a lot of my Windows command line (and some GUI) utilities. Most of the software I use here is available with Scoop:

scoop bucket add extras
scoop install putty wsl-ssh-pageant git

The Heart: Pageant

PuTTY (and compatible programs, such as WinSCP and MobaXterm) use the Pageant SSH agent (included with PuTTY). This agent lives in your system tray and handles authentication with your SSH private keys. Before using a YubiKey, I used it as my standard SSH agent on Windows with an on-disk private key, and it worked well.

Dr. Peter Koch has made a smartcard-enabled version of Pageant that Just Works, without configuration, and I have never needed to restart it after inserting my YubiKey.

I have Pageant SC automatically start on startup, and have no problems connecting any of my PuTTY-compatible programs to it. To start it on startup, create a shortcut in the following directory:

%USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

%USERPROFILE% is the path to your user profile directory, that contains all your user folders. For me, it’s usually C:\Users\MichaelEkstrand or something like that.

Connecting Git

By default, Git uses its own bundled version of OpenSSH (which is distinct from Microsoft’s OpenSSH for Windows project). This SSH cannot talk to Pageant.

I fix this by configuring Git to use plink.exe from PuTTY. I set the GIT_SSH environment variable (in the Start menu, search for ‘Edit the environment variables for your account’) to the path to my plink.exe executable. Since PuTTY is installed with Scoop, this path is:

%USERPROFILE%\scoop\apps\putty\current\plink.exe

By using the current path, I avoid needing to change it when I update PuTTY.

Connecting Windows OpenSSH

The last piece is to connect Windows OpenSSH (and if desired, WSL). The wsl-ssh-pageant program does this quite well, and it is available in Scoop.

I created another shortcut in the startup directory to run the following command:

%USERPROFILE%\scoop\apps\wsl-ssh-pageant\current\wsl-ssh-pageant-gui.exe -systray -winssh ssh-pageant

This exports an OpenSSH-compatible agent connection and proxies it Pageant, which in turn hands it off to the YubiKey.

To make OpenSSH use this connection, set the environment variable SSH_AUTH_SOCK to \\.\pipe\ssh-pageant. Running ssh-add -l in PowerShell should show your YubiKey’s keys.

Next Steps & Final Remarks

The WSL/SSH Pageant bridge supports WSL in addition to Windows OpenSSH. I haven’t needed it yet, but once I do and get it working, I’ll update these instructions with the details.

All of this software works without administrator privileges, so this setup is usable in e.g. university computing lab environments.

Alternatives

I have spent some time experimenting with doing everything with Windows OpenSSH, with a per-machine private key stored in each machine’s SSH agent. There are a few drawbacks to this approach, however:

  1. WinSCP and MobaXterm don’t work. File transfer and X11 forwarding are therefore more difficult.
  2. There is no prompting for any kind of PIN or passphrase after enrolling a private key in the Windows OpenSSH agent. It’s therefore possible for authentication attempts to happen without my knowledge, and without any way to stop them. While I am already in substantial trouble if an attacker is running code on my machine, the ability to easily bridge from my machine to another without any notice or plug to pull is troubling.
  3. Managing a different public key for each client machine is cumbersome, as I need to install that public key on several different servers and web accounts. There are at least 4 different places I need to store public keys for regular access.