Development, Tools

Signing your GitHub commits with GPG and YubiKey

7 min read

I got a YubiKey recently and saw a YouTube video where the presenter quickly showed how to sign GitHub commits. I found this a useful thing, as on GitHub, you can just set your name and email in your git config and GitHub will link that it’s from you but when in fact it may not. I saw this with Linus Torvalds, where someone saw he had “made” commits on a repo, but it did not seem to be something he would contribute on. Was it really him? Who knows, but I realized it was time for me to go a little bit beyond the normal security aspect and use my YubiKey for more than just for FIDO2 authentication.

For all developers creating libraries for people to consume, I highly recommend you sign your commits!

For info, I use a YubiKey 5.

What does the end result look like? It looks like this

Image from https://github.blog/2016-04-05-gpg-signature-verification/

This post focuses on the setup on Windows. However, the setup is similar for OSX and Linux. See the reference post for more information.

GPG key and YubiKey setup

First thing you will need is to install GPG4Win.

Once installed, plug in your YubiKey, if not already plugged in, and fire up a command line terminal (CMD or PowerShell).

While you can do the operations in WSL2, the setup is a bit cumbersome as you need to passthrough the device to the sub-system with socat. I reverted back to using GPG4Win directly.
Update 2021-12-13: While I haven’t tried it personally, you may be able to do passthrough of USB devices now with https://github.com/dorssel/usbipd-win into WSL2. See this post for more information.

Creating your keys

You can create your GPG key by issuing the command

gpg --full-gen-key

  1. When prompted to specify the key type, enter 1 (for “RSA and RSA (Default)”).
  2. Specify the size of key you want to generate. Do one of the following:
    • For a YubiKey NEO, enter 2048 and press Enter.
    • For a YubiKey 4 or 5, enter 4096 and press Enter.
  3. Specify the expiration date of the key.
  4. Enter your Real Name. Be sure to enter both your first and last name.
  5. Enter your Email Address. Make sure it is the same one configured in GitHub and in your git config
  6. If desired, enter a Comment about this key. To leave the comment blank, press Enter.
  7. Review the information you entered, make any changes if necessary. If all information is correct, enter O (for Okay).
  8. Enter the passphrase for your key.

By default, the key generated contains Signing [S] and Certifying [C]. Encryption [E] and Authentication [A] is also supported but outside this post. See the reference post for more information on how to do that.

Once you have created your key, it should reside in the keyring, located in C:/Users/<your_username>/AppData/Roaming/gnupg/pubring.kbx

Putting the signing key on the YubiKey

In order to put the signing key on the YubiKey, first check that GPG can see the key. In the same shell, type

gpg --card-status

You should see something along the lines of

If you see this, this is great news, as you are now able to see your key using gpg.

Setting up the key properties

To modify a few of the key properties, type

gpg --edit-card

this will open the gpg shell command.

Verify that the admin status is enabled by typing admin. If you see, as response, Admin commands are allowed, then you are good to go.

Useful commands:

  • passwd: change the user and admin PIN
If you have never set the PIN for GPG, the default PIN is 123456 and the default admin PIN is 12345678.
  • name: change the name of the card holder
  • lang: change the language preference
  • url: URL to retrieve public key
  • sex: change the card holder sex
  • login: change the login data (account name)

see this documentation for more information.

You can also do the same by opening the application that comes with GPG4Win called Kleopatra. Click the Smartcards menu icon, and refresh (F5) the section. You should have access to modify certain information.

Kleopatra

Importing the signing GPG key on the key

Make sure to backup your private key in case you encounter a problem with your YubiKey
gpg --export-secret-keys <keyID> > private.key

Now it’s time to add the signing (private) key to the YubiKey. In a shell type

gpg --list-keys

Grab the keyID from the list in the output. Look for something in the output like

Then issue the command

gpg --edit-key <keyID> 

In the gpg command prompt:

  1. Enter the command: keytocard
  2. When prompted if you really want to move your primary key, enter y (yes).
  3. When prompted where to store the key, select 1 (Signature). This will move the signature subkey to the PGP signature slot of the YubiKey.
  4. Enter the command: quit
  5. When prompted to save your changes, enter y (yes). You have now saved your keyring to your YubiKey.

Git setup

The first thing you need to do is tell git where the GPG executable is located.

git config --global gpg.program 'C:\Program Files (x86)\GnuPG\bin\gpg.exe'

If you installed GPG somewhere else than C:\Program Files (x86)\GnuPG folder, change it in the command above.

Now you have 2 choices. You can setup your signing key and auto-signing globally using the --global parameter or use it on a per repository basis.

Per repository:

Global

If you dont want to use auto-signing, when commiting code, use the -S parameter instead when commit, i.e.

git commit -S -m "My commit message"

To verify that the commit has been signed properly, you can do

git show HEAD --show-signature

GitHub setup

For GitHub to be able to verify you, you need to upload your GPG public key.

First, export your GPG public key by doing

gpg --output public.pgp --armor --export username@email

replace username@email with the email you configured your key. Copy the content of the file.

In GitHub, navigate to your profile and in the SSH and GPG keys section, click the new GPG key button and paste in the textbox the key you copied.

If you are lazy, you can just navigate directly to https://github.com/settings/gpg/new

Unfortunately, this technique does not work for Azure DevOps yet. As I read in this GitHub issue, someone answered: Azure DevOps (VSTS) does have the concept of pushed by which is kind of similar, but I know it is not the same thing. If you want to see this feature implemented, please vote here!

Setting up another workstation

You need to import your public GPG key into your machine.

Export the public from your current machine

gpg --output public.pgp --armor --export KeyID

You can find your keyID. To do so, in a shell (command line), type gpg --card-status
Find the line that says Signature key. Your KeyID is the last 4 blocks of the ID without the spaces. For instance, if the status returns 4867 F230 E32E 4D0F 88DA 1321 7569 0F93 463F 9953, then your KeyID is 75690F93463F9953.

On the other machine, import your public key by typing

gpg --import public.asc

Once imported, you will need to trust your key. To do that, execute the command gpg --edit-key <keyID>. at the prompt, type trust, and then select the option 5 for ultimate trust, confirm y and then quit.

All you need to do afterwards is redo the Git setup section.

But Dom, what if…

So I want to use the touch key on my key instead of using the PIN every time. How can it be done?

You need to install the yubikey manager (ykman). If you installed the Yubikey Manager GUI, navigate to the folder C:\Program Files\Yubico\YubiKey Manager and in a command line type

ykman openpgp keys set-touch -h 

This will open the help on what you can do. For instance, to enable the touch, do

ykman openpgp keys set-touch sig on

You will be able to touch the key after first unlocking it with the PIN. The pin will not be required after that.

For more information, refer to this GitHub repo.

Last notes…

There’s a property, named url, on the YubiKey, for the opengpg section. Since this an asymmetric encryption (private/public keypair), you need the public key in your machines to be able to sign. This is why it can be interesting to drop the key somewhere available on the internet and set the URL of the public key on your key. Like that all you need is to download it and import it.

Happy commit signing!