Elegantly use CanoKey for PGP authentication on WSL 1

Original link: https://blog.rachelt.one/articles/using-canokey-and-gpg-with-wsl-1/

At the beginning of June, the long-awaited CanoKey Pigeon finally launched the second batch. After getting it, I was very excited to use it to bind a lot of 2-step verification 2 Factor Authorization (2FA) of commonly used websites. After tossing for a long time, I found one Question: If there is no need for OpenPGP and PIV, and just use it as a 2FA tool, I don’t seem to be as safe and convenient as using Authy on the Apple Watch directly.

And I have many reasons to reject OpenPGP/PIV. Both require various configurations on different platforms, at least for staunch Windows + WSL users; file-form keys are very inconvenient to back up, especially for security reasons, and multi-media backup + offline condition one-time Operation + master key, three sub-keys, revocation certificate backup, validity period, different usage methods, etc.; various operations require PINs of different lengths and functions. It is good that I can remember more than three PINs. Maybe for many users, the more passwords required, the more likely they will use the same password or weak password; the most important thing is that there is no guarantee of cross-platform availability. If one day, there is a sudden authentication requirement when going out, but only an iOS device is available, it will be completely over; Compared with remembering a password (system) that can be used everywhere, all data and devices will not be lost, it is really fragile and complicated.

But when I was bored sitting in front of the computer and looked at the CanoKey that had been sitting on the table for two weeks, I felt like I could give it a try. Even if you don’t use it as your primary authentication method, at least play around with it. So, after I spent most of the morning generating keys, and then plugging the Windows gpg-agent into the WSL 1 that does not support access to USB devices, let alone CanoKey, I wrote this article as a record so that I can review it at any time later, hopefully can help those in need.

⚠NOTE⚠ : The methods documented in this article are only recommended for use on trusted systems. In any case, the behavior of sharing private keys across systems has a greater security risk. If you have strong security needs, please close this article, do not consider using CanoKey in WSL, and/or install a separate Linux system.

generate key

There is already a lot of information on how to turn CanoKey into a smart card for storing keys, so I won’t go into details in this article. I refer to Editst’s Canokey guide: FIDO2, PGP and PIV , install Gpg4win and win-gpg-agent in Windows, and write three subkeys into CanoKey. If you still have questions about OpenPGP, you can also refer to UlyC’s 2021 tutorial series on using PGP in a more modern way .

Before continuing, please confirm that entering gpg --card-status in Windows PowerShell can normally output the three keys, fingerprint and ID stored in CanoKey for signing, encryption and authentication.

SSH in WSL 1

After starting agent-gui.exe , in PowerShell, enter ssh-add -L , you should be able to see the information shown in the figure:

 PS C:\Users\Rachel> ssh-add -Lssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP5ZT7970edpOEIoZTR7JaPdHNNKxmHG4qrHnz68BzSg cardno:F1D0 XXXXXXXX

The output line is the SSH public key attached to OpenPGP in CanoKey, as mentioned in the Canokey guide: FIDO2, PGP and PIV , put it in the server, GitHub and other places, and enter the PIN whenever the corresponding private key is called. , Touch CanoKey (if OpenPGP’s Touch Policies in CanoKey Management Tool is enabled) to authorize SSH access.

This is under Windows. WSL 1 is not too bad, just pass the SSH authentication to the socket provided by agent-gui.exe :

First, make sure that SSH exists in WSL 1. Generally, it does. If not, sudo apt update && sudo apt install openssh-client (take Debian as an example) can also solve the problem.

Open the Status of agent-gui in the Windows tray bar, there should be an agent-gui AF_UNIX and Cygwin sockets directory, the folder under it is usually % gpg-agent %LocalAppData%\gnupg\agent-gui , there are several gpg-gui for different purposes. gpg-agent , where S.gpg-agent.ssh is the SSH_AUTH_SOCK we are looking for. In my case, my username is Rachel , and the file corresponding to %LocalAppData%\gnupg\agent-gui\S.gpg-agent.ssh is C:\Users\Rachel\AppData\Local\gnupg\agent-gui\S.gpg-agent.ssh , converted to WSL is /mnt/c/Users/Rachel/AppData/Local/gnupg/agent-gui/S.gpg-agent.ssh . Give it a try!

 $ export SSH_AUTH_SOCK=/mnt/c/Users/Rachel/AppData/Local/gnupg/agent-gui/S.gpg-agent.ssh$ ssh-add -Lssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP5ZT7970edpOEIoZTR7JaPdHNNKxmHG4qrHnz68BzSg cardno:F1D0 XXXXXXXX

The output public key is the same as that under Windows, indicating that there is no problem. Now, if you have added this public key to GitHub’s public key repository, you can try it out:

 $ ssh -T [email protected] Rachel! You've successfully authenticated, but GitHub does not provide shell access.

Everything is OK.

GnuPG in WSL 1

Compared with SSH, the configuration of GPG has billions of pits.

Can you help me?

Compared with openssh , gnupg and socat are not necessarily installed on all systems, so we first make sure that they are both: sudo apt update && sudo apt install gnupg socat (take Debian as an example).

GnuPG Needless to say, socat is a multi-purpose relay tool under Linux that can connect to files, devices, pipes, sockets, etc. We need to use it to monitor access to S.gpg-agent under WSL and forward it to agent-gui Provided S.gpg-agent :

 $ [ -f "/home/rachel/.gnupg/S.gpg-agent" ] && echo "Deleting old GPG agent.." && rm "/home/rachel/.gnupg/S.gpg-agent" || [ -d "/home/rachel/.gnupg" ] || mkdir /home/rachel/.gnupg && chmod 700 /home/rachel/.gnupg$ socat UNIX-LISTEN:/home/rachel/.gnupg/S.gpg-agent,fork UNIX-CONNECT:/mnt/c/Users/Rachel/AppData/Local/gnupg/agent-gui/S.gpg-agent &

These two commands, the first sentence is to detect whether there is S.gpg-agent generated by GnuPG in the user directory, if so, delete it (otherwise socat cannot create its own monitor), otherwise detect whether there is a GnuPG directory, if not, create it + Set the corresponding permissions.

The second sentence is to use socat to start monitoring the S.gpg-agent automatically generated by GnuPG under Linux. fork is to monitor multiple accesses, and then UNIX-CONNECT forwards it to the S.gpg-agent created by agent-gui . The & at the end of the line puts socat into a child thread to run asynchronously, preventing blocking of the current shell.

At this point, call gpg in WSL 1 and see:

 $ gpg --card-statusReader ...........: canokeys.org OpenPGP PIV OATH 0(省略一长串CanoKey 信息)

success! But we just read the CanoKey and haven’t imported the key yet. If you git commit -S now, you may be prompted

 $ git commit -Serror: gpg failed to sign the datafatal: failed to write commit object

The solution is also very simple, follow the Canokey guide: FIDO2, PGP and PIV , we update the local keystore, first import the public key:

 $ gpg --import public-key.pubgpg: key XXXXXXXXXXXXXXXX: public key "Rachel T <[email protected]>" imported

Import the private key from CanoKey:

 $ gpg --edit-cardReader ...........: canokeys.org OpenPGP PIV OATH 0(省略一长串CanoKey 信息)gpg/card> fetchgpg/card> q

Next, we use gpg --fingerprint --keyid-format long -K to see the ID of the signature key:

 $ gpg --fingerprint --keyid-format long -K/home/rachel/.gnupg/pubring.kbx-------------------------------sec# ed25519/XXXXXXXXXXXXXXXX 2022-06-26 [C] Key fingerprint = (主密钥指纹)uid [ unknown] Rachel T <[email protected]>ssb> cv25519/EEEEEEEEEEEEEEEE 2022-06-26 [E]ssb> ed25519/AAAAAAAAAAAAAAAA 2022-06-26 [A]ssb> ed25519/SSSSSSSSSSSSSSSS 2022-06-26 [S]

[S] The sixteen characters before ed25519/ are the ID of the signature key, set it as the signature key of git , and then git commit -S to see:

 $ git config --global user.signingkey SSSSSSSSSSSSSSSS$ git commit -S

There should be no problem now.

So simple, what’s the pit?

First of all, due to my poor English and Linux skills, I may not have correctly understood the GitHub README of win-gpg-agent , but I didn’t know socat at first, and I really didn’t find a way to use WSL 1 directly, only in sorelay.exe I saw a socket conversion to socat for WSL 2 under sorelay.exe , which is also the direct reason why I finally found the source of the solution and wrote this article.

Second, as stated in issue #5 of win-gpg-agent , it is theoretically possible to set GNUPGHOME to point to the gnupg folder under %LocalAppData% , or use the softlink ln -s to make ~/.gnupg point to that gnupg , but in In my test, not only did I fail to successfully modify the permissions of .gnupg or GNUPGHOME folders and files due to the limitations of the link and file system, GnuPG kept reporting WARNING, but I also failed to make gpg --card-status one operation. gpg --card-status displays CanoKey information correctly, wastes a lot of time.

Finally, in theory, pinentry under WSL 1 should be pinentry.exe over by pinentry provided by win-gpg-agent , that is, add pinentry-program /(win-gpg-agent 的存放路径)/pinentry.exe in ~/.gnupg/gpg-agent.conf ) pinentry-program /(win-gpg-agent 的存放路径)/pinentry.exe , but after testing, there is no problem even if pinentry is not specified, and a Windows-style PIN input box pops up, so it is probably not a big problem… right?

Finally, some automatic

If there are no problems with the above operations, we can make a series of operations complete automatically.

For agent-gui.exe , we create a shortcut, put the shortcut in the self-starting folder %AppData%\Microsoft\Windows\Start Menu\Programs\Startup , it will start automatically every time it is powered on.

Then, we add the SSH and GPG configurations to the rc file of the WSL shell, such as .bashrc :

 export SSH_AUTH_SOCK=/mnt/c/Users/Rachel/AppData/Local/gnupg/agent-gui/S.gpg-agent.ssh[ -f "/home/rachel/.gnupg/S.gpg-agent" ] && echo "Deleting old GPG agent.." && rm "/home/rachel/.gnupg/S.gpg-agent" || [ -d "/home/rachel/.gnupg" ] || mkdir /home/rachel/.gnupg && chmod 700 /home/rachel/.gnupgsocat UNIX-LISTEN:/home/rachel/.gnupg/S.gpg-agent,fork UNIX-CONNECT:/mnt/c/Users/Rachel/AppData/Local/gnupg/agent-gui/S.gpg-agent &

When copying and pasting, be sure to modify the user folder of the above command line.

Finally, we turn on the default GPG signature for git commit :

 $ git config --global commit.gpgsign true

In this way, we have completed the OpenPGP configuration of CanoKey in the WSL 1 environment.

Reference and thanks

In addition to the several articles mentioned in this article, I have been assisted by the following (and others that may not have been recorded in time) in the process of writing this article, and I would like to express my thanks.

Testing your SSH connection – GitHub

Getting started with socat, a multipurpose relay tool for Linux | Enable Sysadmin

Why is “fork” needed by socat when connecting to a web server?

This article is reprinted from: https://blog.rachelt.one/articles/using-canokey-and-gpg-with-wsl-1/
This site is for inclusion only, and the copyright belongs to the original author.

Leave a Comment