Nitrokey on Windows and WSL2

Hi.
At work I have to use a Windows computer. I need to use the Nitrokey exclusively in WSL2.

Over the years I tried various methods and tricks described online. They kind of worked, but with issues, fiddeling and at some point most of them stopped working completely. (Like today)

And the current state is a mess, so I wanna redo the setup completely.
What method do you recommend? Any stable solutions?

I have been quite successful with the connection to the SSH agent using [wsl2-ssh-agent](https://github.com/mame/wsl2-ssh-agent) (however my PR is needed) and GPG with socat + [npiperelay](https://github.com/jstarks/npiperelay) … I would prefer the socat+npiperelay only. For some reason, the socket connection did not work but I am not at all an expert on socat or npiperelay. On Windows, I am running gpg4win with the SSH agent enabled.

The solution has been working for several months now without the need to further mess with the setup.

So I have downloaded npipelrelay and wsl2-ssh-agent downloaded to ~/.local/bin and then added the following bash rc scripts:

~/.bashrc.d/gpg-npiperelay:

#!/bin/bash

function main(){
  GPGDIR="${HOME}/.gnupg"
  local TMP
  TMP="$(gpgconf.exe --list-dirs agent-socket | sed 's/[\r\x0]//g')"
  WIN_GPG_AGENT_SOCK=${TMP//'\'/'/'}

  #TMP="$(gpgconf.exe --list-dirs agent-ssh-socket | sed 's/[\r\x0]//g')"
  #WIN_GPG_SSH_AGENT_SOCK=${TMP//'\'/'/'}
  WIN_GPG_SSH_AGENT_SOCK='//./pipe/openssh-ssh-agent'

  NPIPERELAY="npiperelay.exe"

  gpgconf --create-socketdir

  export GPG_AGENT_SOCK=$(gpgconf --list-dirs agent-socket)
  #export SSH_AUTH_SOCK="${HOME}/.ssh/gpg-agent.sock"

  echo "$WIN_GPG_SSH_AGENT_SOCK --> $SSH_AUTH_SOCK"
  echo "$WIN_GPG_AGENT_SOCK --> $GPG_AGENT_SOCK"

  GPG_AGENT_PID=$(ps -ef -u ${USER} | awk 'BEGIN{x=1} /[ ]socat.+S.gpg-agent/{x=0; print $2; exit} END{exit x}')
  #SSH_AGENT_PID=$(ps -ef -u ${USER} | awk 'BEGIN{x=1} /[ ]socat.+agent.sock/{x=0; print $2; exit} END{exit x}')

  [ ! -d "${GPGDIR}" ] && mkdir -p ${GPGDIR} && chmod g=,o= ${GPGDIR}

  if [ -z ${GPG_AGENT_PID} ]; then
      echo "starting gpg agent relay."
      rm -rf "$GPG_AGENT_SOCK"
      setsid nohup socat UNIX-LISTEN:"${GPG_AGENT_SOCK},fork" EXEC:"${NPIPERELAY} -ep -ei -s -a '${WIN_GPG_AGENT_SOCK}'",nofork > /dev/null 2>&1 &
  else
      echo "gpg agent relay running ${GPG_AGENT_PID}."
  fi

#  if [ -z ${SSH_AGENT_PID} ]; then
#      echo "starting ssh agent relay."
#      rm -f $SSH_AUTH_SOCK
#      setsid nohup socat UNIX-LISTEN:"${SSH_AUTH_SOCK},fork" EXEC:"${NPIPERELAY} -ei -s '${WIN_GPG_SSH_AGENT_SOCK}'",nofork > /dev/null 2>&1 &
#  else
#      echo "ssh agent relay running ${SSH_AGENT_PID}."
#  fi
}
main
unset -f main

~/bashrc.d/wsl2-ssh-agent

#! /bin/bash

pushd ~/.local/bin &>/dev/null
eval $(wsl2-ssh-agent)
popd &>/dev/null

I hope this helps setting it up…

More or less the same route I went last time.
But if you say it worked for months, I’ll go through it again, closely following your description.

Thanks! I’ll share how it worked out.

Do you install PuTTY on Windows or use Windows’ own SSH client? Because most guides out there, including Yubikey recommend to install PuTTY and enable putty support in GPG4Win. However I’m not sure if this is still up to date.
edit: Okay, as I’ve seen it should also work without PuTTY.

Okay, here’s my notes on what I’ve done:

  1. Install & configure GPG4Win
# %APPDATA%\.gnupg\gpg-agent.conf
enable-ssh-support
enable-win32-openssh-support
use-standard-socket
max-cache-ttl 7200
default-cache-ttl 600
  1. Make sure Windows’ OpenSSH client is installed (Apps > Optional Features)
  2. Install npiprelay to location in PATH on Windows!
  3. Install required packages in wsl:
sudo apt install socat scdaemon
  1. Install wsl2-ssh-agent
wget https://github.com/mame/wsl2-ssh-agent/releases/download/v0.9.2/wsl2-ssh-agent -O ~/.local/bin/wsl2-ssh-agent

chmod +x ~/.local/bin/wsl2-ssh-agent
  1. Fix necessary when using systemd in wsl:
sudo sh -c 'echo :WSLInterop:M::MZ::/init:PF > /usr/lib/binfmt.d/WSLInterop.conf'

sudo systemctl restart systemd-binfmt
wsl --shutdown
  1. bashrc
# SSH
function main(){
  GPGDIR="${HOME}/.gnupg"
  local TMP
  TMP="$(gpgconf.exe --list-dirs agent-socket | sed 's/[\r\x0]//g')"
  WIN_GPG_AGENT_SOCK=${TMP//'\'/'/'}

  #TMP="$(gpgconf.exe --list-dirs agent-ssh-socket | sed 's/[\r\x0]//g')"
  #WIN_GPG_SSH_AGENT_SOCK=${TMP//'\'/'/'}
  WIN_GPG_SSH_AGENT_SOCK='//./pipe/openssh-ssh-agent'

  NPIPERELAY="npiperelay.exe"

  gpgconf --create-socketdir

  export GPG_AGENT_SOCK=$(gpgconf --list-dirs agent-socket)
  #export SSH_AUTH_SOCK="${HOME}/.ssh/gpg-agent.sock"

  echo "$WIN_GPG_SSH_AGENT_SOCK --> $SSH_AUTH_SOCK"
  echo "$WIN_GPG_AGENT_SOCK --> $GPG_AGENT_SOCK"

  GPG_AGENT_PID=$(ps -ef -u ${USER} | awk 'BEGIN{x=1} /[ ]socat.+S.gpg-agent/{x=0; print $2; exit} END{exit x}')
  #SSH_AGENT_PID=$(ps -ef -u ${USER} | awk 'BEGIN{x=1} /[ ]socat.+agent.sock/{x=0; print $2; exit} END{exit x}')

  [ ! -d "${GPGDIR}" ] && mkdir -p ${GPGDIR} && chmod g=,o= ${GPGDIR}

  if [ -z ${GPG_AGENT_PID} ]; then
      echo "starting gpg agent relay."
      rm -rf "$GPG_AGENT_SOCK"
      setsid nohup socat UNIX-LISTEN:"${GPG_AGENT_SOCK},fork" EXEC:"${NPIPERELAY} -ep -ei -s -a '${WIN_GPG_AGENT_SOCK}'",nofork > /dev/null 2>&1 &
  else
      echo "gpg agent relay running ${GPG_AGENT_PID}."
  fi

#  if [ -z ${SSH_AGENT_PID} ]; then
#      echo "starting ssh agent relay."
#      rm -f $SSH_AUTH_SOCK
#      setsid nohup socat UNIX-LISTEN:"${SSH_AUTH_SOCK},fork" EXEC:"${NPIPERELAY} -ei -s '${WIN_GPG_SSH_AGENT_SOCK}'",nofork > /dev/null 2>&1 &
#  else
#      echo "ssh agent relay running ${SSH_AGENT_PID}."
#  fi
}
main
unset -f main

pushd ~/.local/bin &>/dev/null
eval $(wsl2-ssh-agent)
popd &>/dev/null

The results are:
ssh works. connecting to a server from WSL works and brings up the gpg4win pinentry prompt. Works and uses the smartcard. Cool

gpg does not work. I can’t do gpg --card-status on WSL while it works on Windows PowerShell… selecting card failed: No such device. This is using gpg/gnupg installed in WSL. If I use gpg.exe --card-status it works and uses gpg4win. I guess I could just alias gpg to gpg.exe ? Or should I try to somehow get it working with Linux’s gpg command? I thought it would use the shared socket/agent.