Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 82 additions & 88 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ Cryptographic keys on YubiKey are [non-exportable](https://web.archive.org/web/2
* [Signature](#signature)
* [Configure touch](#configure-touch)
* [SSH](#ssh)
+ [MacOS](#macos)
+ [Windows](#windows)
- [WSL](#wsl)
+ [Replace agents](#replace-agents)
+ [Copy public key](#copy-public-key)
+ [Import SSH keys](#import-ssh-keys)
Expand Down Expand Up @@ -1285,7 +1288,7 @@ wget https://raw.githubusercontent.com/drduh/YubiKey-Guide/master/config/gpg-age
> [!TIP]
> Set `pinentry-program` to `/usr/bin/pinentry-gnome3` for a GUI-based prompt.

**macOS**
### macOS

Install pinentry with `brew install pinentry-mac` or `sudo port install pinentry` then edit `gpg-agent.conf` to set the `pinentry-program` path to:

Expand All @@ -1299,7 +1302,7 @@ To use graphical applications on macOS, [additional setup is required](https://j

Create `$HOME/Library/LaunchAgents/gnupg.gpg-agent.plist` with the following contents:

```
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
Expand Down Expand Up @@ -1327,13 +1330,13 @@ Create `$HOME/Library/LaunchAgents/gnupg.gpg-agent.plist` with the following con

Load it:

```console
```zsh
launchctl load $HOME/Library/LaunchAgents/gnupg.gpg-agent.plist
```

Create `$HOME/Library/LaunchAgents/gnupg.gpg-agent-symlink.plist` with the following contens:

```
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/ProperyList-1.0/dtd">
<plist version="1.0">
Expand All @@ -1354,146 +1357,137 @@ Create `$HOME/Library/LaunchAgents/gnupg.gpg-agent-symlink.plist` with the follo

Load it:

```console
```zsh
launchctl load $HOME/Library/LaunchAgents/gnupg.gpg-agent-symlink.plist
```

Reboot to activate changes.

**Windows**

Windows can already have some virtual smart card readers installed, like the one provided for Windows Hello. To verify YubiKey is the correct one used by scdaemon, add it to its configuration.
### Windows

Find the YubiKey label using PowerShell:
Download and install Gpg4Win.

```powershell
PS C:\WINDOWS\system32> Get-PnpDevice -Class SoftwareDevice | Where-Object {$_.FriendlyName -like "*YubiKey*"} | Select-Object -ExpandProperty FriendlyName
Yubico YubiKey OTP+FIDO+CCID 0
winget install -e --id GnuPG.Gpg4win
```

See [How to setup Signed Git Commits with a YubiKey NEO and GPG and Keybase on Windows (2018)](https://www.hanselman.com/blog/HowToSetupSignedGitCommitsWithAYubiKeyNEOAndGPGAndKeybaseOnWindows.aspx) for more information.
One of the packaged programs is Kleopatra, a GnuGP GUI; opening that will generate some initial configurations.

Edit `%APPDATA%/gnupg/scdaemon.conf` to add:
Windows may already have some virtual smart card readers installed, like the one provided for Windows Hello. To verify YubiKey is the correct one used by scdaemon, add it to its configuration.

```console
reader-port <device name, e.g. Yubico YubiKey OTP+FIDO+CCID 0>
```
Find the YubiKey label using PowerShell:

Edit `%APPDATA%/gnupg/gpg-agent.conf` to add:
```powershell
Get-PnpDevice -Class SoftwareDevice | Where-Object {$_.FriendlyName -like "*YubiKey*"} | Select-Object -ExpandProperty FriendlyName

```console
enable-ssh-support
enable-putty-support
Yubico YubiKey OTP+FIDO+CCID 0
```

Restart the agent:

```console
gpg-connect-agent killagent /bye
Edit `%APPDATA%\gnupg\scdaemon.conf` to add:

gpg-connect-agent /bye
```plaintext
reader-port "Yubico YubiKey OTP+FIDO+CCID 0"
```

Verify YubiKey details:
Edit `%APPDATA%\gnupg\gpg-agent.conf` to add:

```console
gpg --card-status
```plaintext
enable-ssh-support
enable-win32-openssh-support
```

Import the public key and set ultimate trust:
Set a [User Environment Variable](https://www.tenforums.com/tutorials/121855-edit-user-system-environment-variables-windows.html):

```console
gpg --import <path to public key file>
```plaintext
SSH_AUTH_SOCK = \\.\pipe\openssh-ssh-agent
```

Retrieve the public key id:
To avoid `invalid format` and `communication with agent failed` errors, configure GnuPG as the system OpenSSH agent source of truth. In `services.msc`, disable the `OpenSSH Authentication Agent` service so it does not compete with GnuPG for `\\.\pipe\openssh-ssh-agent`.

```console
gpg --list-public-keys
```
Restart gpg-agent:

Export the SSH public key:
```powershell
gpg-connect-agent killagent /bye

```console
gpg --export-ssh-key <public key id>
gpg-connect-agent /bye
```

Copy the public SSH key to a file - it corresponds to the secret key on YubiKey and can be copied to SSH destination hosts.
Verify the SSH agent has identities:

Create a shortcut that points to `gpg-connect-agent /bye` and place it in the startup folder `shell:startup` to make sure the agent starts after reboot. Modify the shortcut properties so it starts in a "Minimized" window.
```powershell
ssh-add -L
```

PuTTY can now be used for public-key SSH authentication. When the server asks for public-key verification, PuTTY will forward the request to GnuPG, which will prompt for a PIN to authorize the operation.
Copy the public SSH key to a file - it corresponds to the secret key on YubiKey and can be copied to SSH destination hosts.

**WSL**
Open the Startup folder (`[Win+R]` and run `shell:startup`) and create a shortcut that points to `gpg-connect-agent /bye` to make sure the agent starts after reboot. Modify the shortcut properties so it starts in a "Minimized" window.

The goal is to configure SSH client inside WSL work together with the Windows agent, such as gpg-agent.exe.
OpenSSH can now be used for public-key SSH authentication. When the server asks for public-key verification, OpenSSH will forward the request to GnuPG, which will prompt for a PIN to authorize the operation.

See the [WSL agent architecture](media/schema_gpg.png) illustration for an overview.
If using Git for Windows, tell it to use the OpenSSH client:

GnuPG forwarding for cryptographic operations is not supported. See [vuori/weasel-pageant](https://github.com/vuori/weasel-pageant) for more information.
```powershell
git config --global core.sshCommand "C:/Windows/System32/OpenSSH/ssh.exe"
```

One way to forward is just `ssh -A` (still need to eval weasel to setup local ssh-agent), and only relies on OpenSSH. In this track, `ForwardAgent` and `AllowAgentForwarding` in ssh/sshd config may be involved. However, when using ssh socket forwarding, do not enable `ForwardAgent` in ssh config. See [SSH Agent Forwarding](#ssh-agent-forwarding) for more information. This requires Ubuntu 16.04 or newer for WSL and Kleopatra.
#### WSL

Download [vuori/weasel-pageant](https://github.com/vuori/weasel-pageant).
The goal is to configure SSH inside WSL to use the Windows-hosted `gpg-agent.exe` through a relay.

Add `eval $(/mnt/c/<path of extraction>/weasel-pageant -r -a /tmp/S.weasel-pageant)` to the shell rc file. Use a named socket here so it can be used in the `RemoteForward` directive of `~/.ssh/config`. Source it with `source ~/.bashrc`.
The following diagram shows how the Windows `gpg-agent` pipe is bridged into WSL:

Display the SSH key with `$ ssh-add -l`
```mermaid
flowchart TD
subgraph Windows["Windows Host"]
YK["YubiKey\n(OpenPGP)"]
GPA["gpg-agent\n(GnuPG 2.4+)\nenable-win32-openssh-support"]
PIPE["Named pipe\n\\.\pipe\openssh-ssh-agent"]
WINCL["Windows OpenSSH / Git clients\n(SSH_AUTH_SOCK=\\.\pipe\openssh-ssh-agent)"]
YK --> GPA --> PIPE --> WINCL
end

Edit `~/.ssh/config` to add the following for each agent forwarding host:
subgraph WSL["WSL Linux"]
RELAY["npiperelay.exe\n(bridges Windows named pipe)"]
SOCAT["socat\n(exposes Unix socket)"]
SOCK["~/.ssh/agent.sock\n(SSH_AUTH_SOCK in WSL)"]
WSLCL["WSL ssh / git clients"]
RELAY --> SOCAT --> SOCK --> WSLCL
end

```console
RemoteForward <remote SSH socket path> /tmp/S.weasel-pageant
PIPE -- "//./pipe/openssh-ssh-agent" --> RELAY
```

The remote SSH socket path can be found with `gpgconf --list-dirs agent-ssh-socket`
WSL cannot natively consume Windows named pipes as Unix sockets, so bridge the Windows OpenSSH pipe into a WSL Unix socket with `socat` + `npiperelay.exe`.

Add the following to the shell rc file:
* In WSL, install `socat`
* In Windows, download [jstarks/npiperelay](https://github.com/jstarks/npiperelay/releases) to a findable path, for example `C:\bin\npiperelay.exe`.

```console
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
```

Add the following to `/etc/ssh/sshd_config`:
In WSL add the following to `~/.bashrc` (update the `NPIPERELAY` path if needed):

```console
StreamLocalBindUnlink yes
```bash
export SSH_AUTH_SOCK=$HOME/.ssh/agent.sock
if ! pgrep -f npiperelay.exe > /dev/null; then
rm -f "$SSH_AUTH_SOCK"
NPIPERELAY="/mnt/c/bin/npiperelay.exe"
(setsid socat UNIX-LISTEN:"$SSH_AUTH_SOCK",fork EXEC:"$NPIPERELAY -ei -s //./pipe/openssh-ssh-agent",nofork &) >/dev/null 2>&1
fi
```

Reload SSH daemon:
Make sure the `.ssh` directory exists and reload your `bashrc` script:

```console
sudo service sshd reload
```bash
mkdir -p $HOME/.ssh
source ~/.bashrc
```

Remove YubiKey and reboot. Log back into Windows, open a WSL console and enter `ssh-add -l` - no output should appear.

Plug in YubiKey, enter the same command to display the ssh key.

Connect to the remote host and use `ssh-add -l` to confirm forwarding works.

Agent forwarding may be chained through multiple hosts. Follow the same [protocol](#remote-host-configuration) to configure each host.

An alternate method is the [usbipd-win](https://github.com/dorssel/usbipd-win) library. If you encounter issues with accessing the YubiKey in WSL after configuring usbipd-win, you may need to add custom polkit rules to ensure proper permissions for the pcscd service. Here's an example configuration using a scard group (the group logic is optional):

Create a new rule file at /etc/polkit-1/rules.d/99-pcscd.rules:
Confirm the relay works:

```bash
polkit.addRule(function(action, subject) {
if (action.id == "org.debian.pcsc-lite.access_card" &&
subject.isInGroup("scard")) {
return polkit.Result.YES;
}
});

polkit.addRule(function(action, subject) {
if (action.id == "org.debian.pcsc-lite.access_pcsc" &&
subject.isInGroup("scard")) {
return polkit.Result.YES;
}
});
ssh-add -l
```

This method allows simultaneous SSH use in PowerShell and WSL without attaching or detaching the YubiKey device between environments.

### Replace agents

To launch `gpg-agent` for use by SSH, use the `gpg-connect-agent /bye` or `gpgconf --launch gpg-agent` commands.
Expand Down
Binary file removed media/schema_gpg.png
Binary file not shown.
Binary file removed media/schema_gpg.pptx
Binary file not shown.