I’ve been using a YubiKey as a 2-Factor Authentication key and to sign my Git commits. Until a few days ago I’ve been using a YubiKey 4. Since my current computer doesn’t have any USB-A ports, I’ve been juggling a USB-A-to-USB-C adapters in my backpack and using the key has been a hassle for the last year. That’s why I decided it’s time to move to my “new” YubiKey 5C to gain the benefit of not having to juggle those adapters.
I’ve actually had the key for a while, as I ordered it together with a replacement YubiKey 4 that I got because of the Infineon TPM issue they identified, but only now I decided it’s time to move to the new key.
The other reason to do it now is because my old GPG keys expired and I had to reissue them, so I can use the key to sign my Git commits.
If you’ve dealt with GPG keys in the past (or currently) you know that it can be pretty hard to get it up and running properly and safely for someone who’s never done it before. Keeping master keys offline, shuffling public keys, reissuing keys after they expire, possibly signing them with previous keys to verify them, revoking keys… It’s not easy to follow the best practices even in theory. When it comes to following them in practice, things get extremely complicated.
Most tutorials online refer to using the CLI to generate your keys, navigating menus with a non-common design pattern and are general pain to get them up and running. Most tutorials say use an offline machine like a Raspberry PI and/or generate the master keys and sub-keys while offline and keep the master key off your computer.
I’ve been dealing with this each start of January for the past almost 4 years. I dread the moment when I get the following error, noting that my signing keys have expired.
error: gpg failed to sign the data fatal: failed to write commit object
This year I decided it’s time to try to make this process much easier and to use the in-built certificate generation and avoid the whole hassle with dealing with GPG key generations and such.
YubiKey on-key keys generation
With this we still have to use the CLI UI, but it’s a bit more obvious as it has fewer steps.
First we have to set up our card/device.
gpg --card-status in the terminal and you should see something like this:
Reader ………..: Yubico Yubikey 4 OTP U2F CCID Application ID …: <Serial number> Version ……….: 2.1 Manufacturer …..: Yubico Serial number ….: <Device serial number> Name of cardholder: unspecified Language prefs …: en Sex …………..: unspecified URL of public key : [not set] Login data …….: <e-mail or nothing> Signature PIN ….: not forced Key attributes …: rsa4096 rsa4096 rsa4096 Max. PIN lengths .: 127 127 127 PIN retry counter : 3 0 3 Signature counter : 9
If you see something similar and no errors show up, you should be fine to continue.
You will land in a CLI UI, showing the same information at the start and then a command prompt at the bottom
admin and press return/enter.
You can now type
help to figure out how to change the owner information and PINs for the card.
One thing that you MUST do is change the default PINs for the card. There are two of those. The first one is the PIN key you use to access the keys on the card. The second one is the “Admin” PIN or PUK (Personal Unblocking Code).
To do this type
passwd and you will see a menu:
gpg: OpenPGP card no. <Serial number> detected
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
1 and follow the prompts to update your pin. The default PIN is
After completing that, choose
3 to change the Admin PIN. The default is
After having both pins changed, go back to the main menu to finish updating the key information.
The commands you can use are:
name– to change the cardholder name
login– to change the cardholder e-mail address or login
After that we can move on to the actual key generation.
Now it’s time to actually generate the keys.
To do that, type
You will be asked
Make off-card backup of encryption key? (Y/n), but as mentioned in YubiKey’s documentation, this is only a shim backup and it will not create a full backup of the secret keys, so it doesn’t matter if you reply
No. I reply with
If there are stored keys on the card you will be asked if you want to replace them:
gpg: Note: keys are already stored on the card! Replace existing keys? (y/N)
Make sure you’re not going to replace something important that you don’t have backup of and continue with
Y. If there’s something important, better to quit the whole process with
You will be asked for your card PIN you set earlier.
Then you will have to chose how long the keys will be valid for:
Please specify how long the key should be valid. 0 = key does not expire <n> = key expires in n days <n>w = key expires in n weeks <n>m = key expires in n months <n>y = key expires in n years Key is valid for? (0)
If you want the keys to be valid for only 1 year, type
You will be asked to confirm the expiration date. Check if everything is correct and confirm.
Then you will be asked to enter information about the key owner:
Is this correct? (y/N) y GnuPG needs to construct a user ID to identify your key. Real name: <Your name> Email address: <Your e-mail> Comment: <Comment is optional> You selected this USER-ID: "<Your name> <comment> <your e-mail> Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?
O to confirm if everything seems correct.
Then you will be asked for your Admin PIN or PUK. This is required as it will perform a write action on the card.
Then if everything is correct, the YubiKey will start blinking and continue to do so for a while (for me it takes about five minutes or so).
After it’s done you will see the following message
gpg: key <Short ID> marked as ultimately trusted gpg: revocation certificate stored as '/Users/bisko/.gnupg/openpgp-revocs.d/<LONG ID>.rev' public and secret key created and signed.
Take a note of the
<Short ID> as we’ll be using this later.
At this point you can quit the GPG prompt with
Now it’s time to save the public key, so we can reuse the key on another computer.
To do so, run the following command:
gpg --armor --export <Short ID> > <Short ID>.asc
This will export the public key to a file named
<Short ID>.asc. This will be used in the future if you want to be able to use the YubiKey on another computer or if you lose your GPG configuration.
To restore the public key in your keyring, you need to do:
gpg --import < <Short ID>.asc gpg: key <Short ID>: public key "Your Name <your@email>" imported gpg: Total number processed: 1 gpg: imported: 1
A very important note here. If this is a new GPG install or another computer, GPG won’t recognize the keys on the card by itself. You need to run
gpg --card-status so it can read the card and pick up the keys on the card.
Setting up Git for signing
To set up Git to sign your commits you need to add the following to your
[user] section, you need to add (or update) the following line:
signingkey = 0x<Short ID>
Then if you want to sign all your commits, add the following at the end of the file:
[gpg] program = /usr/local/bin/gpg [commit] gpgsign = true
This will make Git sign all your commits.
To set up GitHub, you need to add your public key to your profile. To do so, go to GitHub -> Settings -> SSH and GPG keys -> New GPG key.
Then you will see a text box, where you need to paste the whole content of the
<Short ID>.asc file we generated above.
If you want to copy the contents of the file (on macOS) you can do:
cat <Short ID>.asc | pbcopy
This will copy the contents of the whole file in the clipboard.
Paste that into the text box on GitHub and click the
Add GPG key button.
After that you can try to commit and push to GitHub and you should see the pretty
Sometimes things don’t work outright. To be able to gather more information you can try the following:
Signing with GPG
First try to sign something with the key:
gpg -s <file>
If this fails, try to figure out why it fails, I’m no expert to help there.
Check out Git’s output
GIT_TRACE=1 git commit -am "test"
This would give you the exact things Git does while it tries to perform the commit and sign it. It would give you a hint why the signing might fail.
From this you can also see that Git executes the following command:
/usr/local/bin/gpg --status-fd=2 -bsau <Key ID>
You can try running this manually to see if it will give you a better error.
Header image from Yubico – https://www.yubico.com/press/images/