Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save SuperMarioSF/1264b6965696abe9288243476b92c751 to your computer and use it in GitHub Desktop.
Save SuperMarioSF/1264b6965696abe9288243476b92c751 to your computer and use it in GitHub Desktop.
GPG + Git SSH Authentication and Signing on Windows 10

GPG + Git SSH Authentication and Signing on Windows 10

Edit (2021-10-31, SuperMarioSF):

  • fixed: missing --force for wsl-ssh-pagent, which caused not to able to launch wsl-ssh-pagent when there already file created.
  • fixed: missing guide for WinSSH ssh-add enviornment variable SSH_AUTH_SOCK. (Thanks @landfillbaby for information in original gist comment)

Introduction

This simple Gist will explain how to settup your GPG key to work for SSH authentication (with Git) and Git commit signing on Windows 10. This may seem straightforward on Linux, but there are certain tweaks needed on Windows.

No Cygwin, no MinGW, no Git Bash or any other Linux emulated environment. This works in pure Windows 10.

Software needed

If you prefer chocolately: choco install git gpg4win openssh

If you have the latest version of Windows 10, the OpenSSH is installed in System32/OpenSSH folder.

Make sure that your system's PATH environment variable contains C:\Program Files (x86)\GnuPG\bin.

Create or import a key

You will have to create a new GPG key or import an existing one. There are plenty of tutorials to walk you through it on the internet. You must make sure that your key has signing and authenticating subkeys!

You can import an existing key with gpg --import key.gpg

To list the keys use gpg -k --with-keygrip, example below.

> gpg -k --with-keygrip
C:/Users/Matus/AppData/Roaming/gnupg/pubring.kbx
------------------------------------------------
pub   rsa4096 2019-10-28 [SC] [expires: 2021-10-25]
      9B0069EA5619486EB2A7E44392FC071FF37A93E5
      Keygrip = 496F3C43AB7D195624832E0E3BF4FF9B531D2DB8
uid           [ultimate] Matus Novak <email@matusnovak.com>
sub   rsa4096 2019-10-28 [E] [expires: 2021-10-25]
      Keygrip = EE087ED74ED6F7843D397825CFB7D9EDD79F73BF
sub   rsa4096 2019-10-28 [A] [expires: 2021-10-25]
      Keygrip = 0B60893C664F965058DFDE93F34199566A12C39A
sub   rsa4096 2019-10-28 [S] [expires: 2021-10-25]
      Keygrip = BC0EC1D2E8E8B24405519823D51AFC4A05DF5E05

This key has three subkeys, one for [A]authentication, one for [S]igning, and one for [E]ncryption. We will need the [S] and [A].

Configure GPG

WARNING: Don't use CRLF newlines! You must switch to using LF only!

First, create a file C:\Users\USER\AppData\Roaming\gnupg\gpg.conf with the following contents. No new lines at the end.

> cat C:\Users\USER\AppData\Roaming\gnupg\gpg.conf
use-agent

Next, create another file C:\Users\USER\AppData\Roaming\gnupg\gpg-agent.conf with the following contents. No new lines at the end.

> cat C:\Users\USER\AppData\Roaming\gnupg\gpg-agent.conf
enable-ssh-support
enable-putty-support

SSH control file

There is one more file, the C:\Users\USER\AppData\Roaming\gnupg\sshcontrol. This file may already exist in your gnupg folder. If not, create it.

Add your authenticating subkey (the keygrip ID) into this file. There must be a single newline at the end! You must use LF line endings, not CRLF!. Otherwise the key won't be recognised. Example below.

> cat C:\Users\USER\AppData\Roaming\gnupg\sshcontrol
0B60893C664F965058DFDE93F34199566A12C39A

Restart the agent

Every time you change your configuration, you must restart the agent using the gpg-connect-agent killagent /bye and gpg-connect-agent /bye. Example below.

> gpg-connect-agent killagent /bye
OK closing connection

> gpg-connect-agent /bye
gpg-connect-agent: no running gpg-agent - starting 'C:\Program Files (x86)\Gpg4win\..\GnuPG\bin\gpg-agent.exe'
gpg-connect-agent: waiting for the agent to come up ... (5s)
gpg-connect-agent: connection to agent established

Start the agent on startup

Make sure that the gpg agent starts on the startup. There are multiple ways to do that. The most simple solution is to create a shortcut of C:\Program Files (x86)\GnuPG\bin\gpg-connect-agent.exe inside of C:\Users\USER\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup. Modify the shortcut, so that the "Target" ends with /bye, such as: "C:\Program Files (x86)\GnuPG\bin\gpg-connect-agent.exe" /bye.

The /bye is a necessary argument so that the command starts the agent and exits afterwards.

Setup wsl-ssh-pageant

By default the Gpg4Win does not work with OpenSSH out of the box. It works with Putty, but if you want to use ssh command from your terminal, or use Visual Studio Code remote connection, you must do this step.

Download the wsl-ssh-pageant-amd64-gui.exe from benpye/wsl-ssh-pageant releases. (It's not a GUI, it only acts as one so you don't get a terminal window).

There is no install wizard for this application. Simply create a folder C:\wsl-ssh-pageant and put the wsl-ssh-pageant-amd64-gui.exe inside of it. The location does not matter.

Next, create a shortcut of C:\wsl-ssh-pageant\wsl-ssh-pageant-amd64-gui.exe inside of C:\Users\USER\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup. Modify the shortcut, adding some command line arguments, so that the "Target" looks like the following:

C:\wsl-ssh-pageant\wsl-ssh-pageant-amd64-gui.exe --wsl C:\wsl-ssh-pageant\ssh-agent.sock --winssh ssh-pageant --systray  --force

The --wsl will create a socket for you to use inside of Windows Subsystem for Linux. The --winssh will create a named pipe for OpenSSH on your host (Windows).

Remember add --force at the end, otherwise wsl-ssh-pageant won't able to takeover existing files to control.

Finally, double click the shortcut. You should see a new icon for wsl-ssh-pageant in your system tray.

Setup environment variable

Open Settings - System - About, click Advanced System Settings, click Environment Variables, add a new entry to User variable.

  • Variable: SSH_AUTH_SOCK
  • Value: \\.\pipe\ssh-pageant

Confirm all settings, then restart your terminal to take effects.

Check your SSH keys

Run the following command:

> ssh-add -L
ssh-rsa AAAAB3NzaC1yc2EA[...]

This will print out all of the available keys that can be used by your ssh. You need to double check that one of the printed keys is actually coming from the GPG. Use the gpg --export-ssh-key YOUR_KEY_ID command to print the public part of your ssh key from the GPG. The YOUR_KEY_ID is the ID of your key, not an ID of your subkey! Example below.

> gpg -k
C:/Users/Matus/AppData/Roaming/gnupg/pubring.kbx
------------------------------------------------
pub   rsa4096 2019-10-28 [SC] [expires: 2021-10-25]
      9B0069EA5619486EB2A7E44392FC071FF37A93E5
      [...]

> gpg --export-ssh-key 9B0069EA5619486EB2A7E44392FC071FF37A93E5
ssh-rsa AAAAB3NzaC1yc2EA[...]

If this matches your ssh-add -L then everything works fine for your OpenSSH!.

Use with GitHub (Authentication)

Go to https://github.com/settings/keys and add the exported ssh key (the key from gpg --export-ssh-key).

Finally, test it out by connecting to github.com with -T using ssh as the git user. Example below.

> ssh -T git@github.com
Hi matusnovak! You've successfully authenticated, but GitHub does not provide shell access.

Use with GitHub (Signing)

First, list your GPG key with the long format:

> gpg --list-secret-keys --keyid-format LONG
C:/Users/Matus/AppData/Roaming/gnupg/pubring.kbx
------------------------------------------------
sec#  rsa4096/92FC071FF37A93E5 2019-10-28 [SC] [expires: 2021-10-25]
      9B0069EA5619486EB2A7E44392FC071FF37A93E5
uid                 [ultimate] Matus Novak <email@matusnovak.com>
ssb   rsa4096/272F40FED5170F30 2019-10-28 [E] [expires: 2021-10-25]
ssb   rsa4096/FDB2A5741F89F17B 2019-10-28 [A] [expires: 2021-10-25]
ssb   rsa4096/8DDB99690FB73F0A 2019-10-28 [S] [expires: 2021-10-25]

Next, export the [S]igning key in a readable format.

> gpg --armor --export 8DDB99690FB73F0A
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBF23fjMBEACy3dCCEIM9JxbIBhpciMPullyjiZAnWILbrB9jpLf1mUzo9l5U
[...]
-----END PGP PUBLIC KEY BLOCK-----

Copy the output, including the -----BEGIN ... until the very end. Go to https://github.com/settings/keys and add this public GPG key.

Finally, tell your Git about the signing key. Use the ID of the master secret key, the line that starts with sec (in the long format).

> git config --global user.signingkey 92FC071FF37A93E5

And configure git to auto-sign your commits.

> git config --global commit.gpgsign true

Use with Windows Subsystem for Linux

All you have to do is to add export SSH_AUTH_SOCK=/mnt/c/wsl-ssh-pageant/ssh-agent.sock into your ~/.bashrc file. As long as the wsl-ssh-pageant is running you can use this socket.

Running ssh-add -L will print out the same SSH key as on your host Windows.

@Spaxe
Copy link

Spaxe commented Nov 25, 2021

Just wanted to say that I got all the way to ssh-add -L and it didn't list any identities...
Then I rebooted and everything worked. THANK YOU.

@sabihoshi
Copy link

I have got it working after restarting my PC like @Spaxe says, thank you

When I do ssh-add -L I see my key in there however it shows:
ssh-ed25519 AAAA...aa (none) is there a way to change that (none) to something else? I could not find a way to do it.

@Spaxe
Copy link

Spaxe commented Jun 13, 2022

@sabihoshi that's where the email normally goes. You can try adding an email to your GPG identity.

@sabihoshi
Copy link

@Spaxe ah yeah it already did from the start, the main key has an email, I could not find a way to add it to the subkey, and I don't think you can anyways. I know that the keygrip I added is right, and when I export the SSH key from the subkey, it is the same in authorized_keys, however both in ssh-add -L and when logging in with PuTTy I see Authenticating with public key "(none)" from agent

@Spaxe
Copy link

Spaxe commented Jun 13, 2022

I'm not sure, sorry, I don't use PuTTy :(

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