Skip to content

Instantly share code, notes, and snippets.

@Hegi
Forked from Speedy37/gpg-agent-relay.sh
Last active March 4, 2024 18:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Hegi/d7f4a1cdd91a2ae82e6f2abc7c2842ff to your computer and use it in GitHub Desktop.
Save Hegi/d7f4a1cdd91a2ae82e6f2abc7c2842ff to your computer and use it in GitHub Desktop.
WSL2 gpg agent relay (Yubikey)
#!/usr/bin/env bash
# Inspired by https://blog.nimamoh.net/yubi-key-gpg-wsl2/
# and https://justyn.io/blog/using-a-yubikey-for-gpg-in-wsl-windows-subsystem-for-linux-on-windows-10/
# Guide:
# Install GPG on windows & Unix
# Add "enable-putty-support" to gpg-agent.conf
# Download wsl-ssh-pageant and npiperelay and place the executables in "C:\Users\[USER]\AppData\Roaming\" under wsl-ssh-pageant & npiperelay
# https://github.com/benpye/wsl-ssh-pageant/releases/tag/20190513.14
# https://github.com/NZSmartie/npiperelay/releases/tag/v0.1
# Adjust relay() below if you alter those paths
# Place this script in WSL at ~/.local/bin/gpg-agent-relay
# Start it on login by calling it from your .bashrc: "$HOME/.local/bin/gpg-agent-relay start"
# In a newer WSL installation the socket folder changed from the $HOME/.gnupg to the /run/user/1000
# the active folder can be identified with the `gpgconf --list-dirs` command
# GNUPGHOME="$HOME/.gnupg"
export GNUPGHOME="/run/user/1000/gnupg/"
PIDFILE="$GNUPGHOME/gpg-agent-relay.pid"
die() {
# shellcheck disable=SC2059
printf "$1\n" >&2
exit 1
}
main() {
checkdeps
case $1 in
start)
if ! start-stop-daemon --pidfile "$PIDFILE" --background --notify-await --notify-timeout 5 --make-pidfile --exec "$0" --start -- foreground; then
die 'Failed to start. Run `gpg-agent-relay foreground` to see output.'
fi
;;
stop)
start-stop-daemon --pidfile "$PIDFILE" --remove-pidfile --stop ;;
status)
start-stop-daemon --pidfile "$PIDFILE" --status
local result=$?
case $result in
0) printf "gpg-agent-relay is running\n" ;;
1 | 3) printf "gpg-agent-relay is not running\n" ;;
4) printf "unable to determine status\n" ;;
esac
return $result
;;
foreground)
relay ;;
*)
die "Usage:\n gpg-agent-relay start\n gpg-agent-relay stop\n gpg-agent-relay status\n gpg-agent-relay foreground" ;;
esac
}
relay() {
set -e
local winuser
winuser=$(/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe '$env:UserName')
winuser=${winuser//$'\r'}
echo "${winuser}"
local winhome="/mnt/c/Users/$winuser"
local wingnupghome="C:/Users/$winuser/AppData/Local/gnupg"
local npiperelay="$winhome/AppData/Roaming/npiperelay/npiperelay.exe"
local wslsshpageant="$winhome/AppData/Roaming/wsl-ssh-pageant/wsl-ssh-pageant-amd64-gui.exe"
local gpgconnectagent="/mnt/c/Programs/GnuPG/bin/gpg-connect-agent.exe"
local gpgagentsocket="$GNUPGHOME/S.gpg-agent"
local sshagentsocket="$GNUPGHOME/S.gpg-agent.ssh"
killsocket "$gpgagentsocket"
killsocket "$sshagentsocket"
"$gpgconnectagent" /bye
"$wslsshpageant" --systray --winssh ssh-pageant 2>/dev/null &
WSPPID=$!
socat UNIX-LISTEN:"$gpgagentsocket,unlink-close,fork,umask=177" EXEC:"$npiperelay -ep -ei -s -a '${wingnupghome}/S.gpg-agent'",nofork &
GNUPID=$!
# shellcheck disable=SC2064
trap "kill -TERM $GNUPID" EXIT
socat UNIX-LISTEN:"$sshagentsocket,unlink-close,fork,umask=177" EXEC:"$npiperelay /\/\./\pipe/\ssh-pageant" &
SSHPID=$!
set +e
# shellcheck disable=SC2064
trap "kill -TERM $GNUPID; kill -TERM $SSHPID" EXIT
systemd-notify --ready 2>/dev/null
wait $GNUPID $SSHPID
trap - EXIT
}
killsocket() {
local socketpath=$1
if [[ -e $socketpath ]]; then
local socketpid
if socketpid=$(lsof +E -taU -- "$socketpath"); then
timeout .5s tail --pid=$socketpid -f /dev/null &
local timeoutpid=$!
kill "$socketpid"
if ! wait $timeoutpid; then
die "Timed out waiting for pid $socketpid listening at $socketpath"
fi
else
rm "$socketpath"
fi
fi
}
checkdeps() {
local deps=(socat start-stop-daemon lsof timeout)
local dep
local out
for dep in "${deps[@]}"; do
if ! out=$(type "$dep" 2>&1); then
printf -- "Dependency %s not found:\n%s\n" "$dep" "$out"
return 1
fi
done
}
main "$@"
@Hegi
Copy link
Author

Hegi commented Mar 1, 2024

Please note that Gpg4Win has changed the socket folder location from %APPDATA%/gnupg to %LOCALAPPDATA%/gnupg
This means that instead of AppData/Roaming/gnupg you need to use AppData/Local/gnupg

This small change cost me more days than I care to admit. Hopefully this note helps at least one person out there... :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment