Yubikey for SSH on windows with WSL2

Recently I had to re-setup my laptop for some dev work, and unfortinatly most guides appear to be out of date and/or dont cover some issues I encountered along the way.

Note this will not cover generating the keys or saving them to the yubikey.

Windows setup

Step 1 Download and install GPG4Win, for this guide you will need version 4.1.0 or higher.

Step 2 Enable SSH support by editing the gpg-agent.conf file located in the gnupg directory %APPDATA%.gnupg\ on Windows, where the typical path is C:\Users<username>\AppData\Roaming. Add the following lines to it:

enable-ssh-support
To Enable support for PuTTY
enable-putty-support
To Enable support for the native Microsoft OpenSSH binaries (requires gpg 2.4.0 / Gpg4win 4.1.0 or higher)
enable-win32-openssh-support
use-standard-socket
default-cache-ttl 600
max-cache-ttl 7200

Step 3 start (or restart) the gpg agent using the following commands

gpg-connect-agent killagent /bye
gpg-connect-agent /bye

Step 4 set the SSH_AUTH_SOCKET`` Environment variable to \.\pipe\openssh-ssh-agent`, the following powershell can do this for you

[System.Environment]::SetEnvironmentVariable('SSH_AUTH_SOCKET','\\.\pipe\openssh-ssh-agent', 'User')

From here you should be able to see your key when your run ssh-add -L in windows, and see the card status with gpg --card-status

WSL setup

Step 1 download the agent that will provide access in WSL

windows_destination="/mnt/c/Users/Public/Downloads/wsl2-ssh-pageant.exe"
linux_destination="$HOME/.ssh/wsl2-ssh-pageant.exe"
wget -O "$windows_destination" "https://github.com/BlackReloaded/wsl2-ssh-pageant/releases/latest/download/wsl2-ssh-pageant.exe"
# Set the executable bit.
chmod +x "$windows_destination"
# Symlink to linux for ease of use later
ln -s $windows_destination $linux_destination

NOTE: change the windows_destination in the first line to a location that you want the executable stored, this MUST be on your windows drive to run correctly.

Step 2 to enable SSH add the following to your ~/.bashrc file

export SSH_AUTH_SOCK="$HOME/.ssh/agent.sock"
if ! ss -a | grep -q "$SSH_AUTH_SOCK"; then
  rm -f "$SSH_AUTH_SOCK"
  wsl2_ssh_pageant_bin="$HOME/.ssh/wsl2-ssh-pageant.exe"
  if test -x "$wsl2_ssh_pageant_bin"; then
    (setsid nohup socat UNIX-LISTEN:"$SSH_AUTH_SOCK,fork" EXEC:"$wsl2_ssh_pageant_bin" >/dev/null 2>&1 &)
  else
    echo >&2 "WARNING: $wsl2_ssh_pageant_bin is not executable."
  fi
  unset wsl2_ssh_pageant_bin
fi

Step 3 to enable GPG add the following to your ~/.bashrc file

export GPG_AGENT_SOCK="$HOME/.gnupg/S.gpg-agent"
if ! ss -a | grep -q "$GPG_AGENT_SOCK"; then
  rm -rf "$GPG_AGENT_SOCK"
  wsl2_ssh_pageant_bin="$HOME/.ssh/wsl2-ssh-pageant.exe"
  if test -x "$wsl2_ssh_pageant_bin"; then
    (setsid nohup socat UNIX-LISTEN:"$GPG_AGENT_SOCK,fork" EXEC:"$wsl2_ssh_pageant_bin --gpg S.gpg-agent" >/dev/null 2>&1 &)
  else
    echo >&2 "WARNING: $wsl2_ssh_pageant_bin is not executable."
  fi
  unset wsl2_ssh_pageant_bin
fi

After reloading your shell session in wsl both ssh-add -L and gpg --card-status should now work and confirm everything is configured correctly.

Items to note

If you have systemd enabled in your WSL distro it will automaticly start the linux GPG agent and prevent gpg --card-status from working, however ssh will still work. I have not yet found a work around for this.