Using a Yubikey 5+ and ed25519 SSH key for authentication and signing of git commits

September 21, 2022

This guide is for Linux/WSL. I don’t have a Mac to test with, but I suspect most of the principles apply. You will need to be running OpenSSH 8.2 or later (released 2020-02-14).

Modern Yubikeys (5.2.3+) can perform ed25519 operations onboard. This includes keeping the private key onboard, which is really what we’re after. There are other guides describing how to do this, but they’re all missing some key ingredient, or they add extra steps that I don’t need.

If you follow these steps:

  1. Your git commits will be cryptographically signed, and GitHub will show this.
  2. All authenticated GitHub operations (push/pull) will require a touch to your Yubikey.
  3. Your private key never leaves your Yubikey.
  4. You won’t need to learn GPG or have to maintain GPG keys.
  5. If your Yubikey is lost or stolen, your key is protected by a PIN.

1. Install ykman

ykman is a Yubikey CLI tool we’ll use for some initial setup. Download ykman

2. Create a PIN for FIDO operations

This PIN will protect you if your key is stolen or lost. You’ll need to memorize this PIN, because every time you reboot your computer, you’ll need to enter it before performing any crypto operations. The PIN is mandatory.

ykman fido access change-pin --new-pin

You should probably write your PIN down somewhere on paper.

3. Create a new ed25519 key

ssh-keygen -t ed25519-sk -C ben@mars.sk1 -O user=ben@mars.sk1 -O resident

The email addresses that you specify to ssh-keygen don’t have any effect on signing or identify verification, which is why I use them merely to help identify my keys. I use the “sk1” suffix to tell me that this is my security key #1. My second Yubikey will use “sk2”, etc. “Mars” is the hostname where I generated the key.

The -O user option will cause that string to be written into the key data on the Yubikey, which helps identify it, if you have multiple keys on one device (I only have one).

The -O resident option tells ssh-keygen that the private key is going to live on the hardware device.

The -sk in ed25519-sk stands for Security Key, and if you want more details about all this, see the OpenSSH 8.2 Release Notes

4. Make sure the new key is on your Yubikey

ykman fido credentials list

My output looks like this:

ssh: 62656e406d6172732e736b310000000000000000000000000000000000000000 openssh

The long string ending in 00000 is the hex encoding of the identifier that you specified in “-O user”, padded with zeroes.

5. Delete the private key off your hard drive

rm ~/.ssh/id_ed25519_sk

Note however, that we leave the public key file, because we’ll need it for signing git commits.

6. Tell ssh-agent about your hardware key

Add keys from hardware devices into your local store:

ssh-add -K

My output is:

Resident identity added: ED25519-SK SHA256:7vuh0DJyNjehHIEZnDEQ7ZafWp/o2Eed+tNKtps6l9g

This does not copy the private key into memory. You’ll still need to touch your Yubikey whenever the private key is needed. But ssh-add -K is necessary for informing ssh-agent that this key exists.

Note that every time you reboot, you’ll need to run ssh-add -K before using your key, and this operation requires your PIN.

7. Add your key to Github

You can use this command to list your public keys:

ssh-add -L

My output looks like this: AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIE7Isiad1PJ/pusAKFtiPYg617QxeFcDJcbuFPJ+L8nPAAAABHNzaDo=

Go to your Github profile, and under SSH and GPG keys, add this new key.

You’ll have to add it twice. Once as an Authentication key, and once as a Signing key.

8. Configure git to sign with your new key

git config --global commit.gpgsign true
git config --global gpg.format ssh
git config --global user.signingkey "~/.ssh/"

9. Make a test commit

In order to complete the creation of your commit, you’ll need to touch your Yubikey. It should flash, indicating that it wants to be touched.

git push will also require a touch.

10. Verify on GitHub

Any commit that you make from now on, should show up on Github with the green Verified badge, and if you click on it, GitHub will show you the person associated with that commit.

If you click on the Verified button on GitHub, it will show you the SHA256 hash of the key that signed this commit, which should match the hash that you’ll see when doing ssh-add -K.

11. Verify locally

Unfortunately, I don’t know how to verify signatures locally. I think this is because GPG doesn’t understand the key format. The following procedure might work in future, but it doesn’t work for me now.

git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers
cat ~/.ssh/ >> ~/.ssh/allowed_signers
git show --show-signature


This guide was based on the following sources:

  5. OpenSSH 8.2 Release Notes