How I configured YubiKey to sign and decrypt emails on Mac

18 June 2024

As you see on my "resume" page, I uploaded my public key for encrypting emails back when I was starting this website. However, moving private key from one place to another is never a good option. My YubiKey cost me 55€ and I barely use it for FIDO/U2F. Why not keep the private key in there and have it with me at all times?

Encrypted message

Required software (for Mac)

We need some software on Mac to make this work. The process should be similar on Linux. Assuming you have brew installed, we will install the following packages:

$ brew install gnupg pinentry-mac ykman

I will also use Thunderbird as it integrates with GnuPG directly (with a special cheat code you need to enter in settings). First thing to do is to set up GnuPG to ask for PIN code using a GUI. We will use pinentry-mac as our input program and restart GPG Agent.

$ mkdir -p ~/.gnupg
$ touch ~/.gnupg/gpg-agent.conf
$ PINENTRY=$(which pinentry-mac)
$ echo "pinentry-program $PINENTRY" >> ~/.gnupg/gpg-agent.conf
$ gpgconf --kill gpg-agent
$ gpgagent --daemon

Setting up PIN on YubiKey

Now we can set our PIN codes on YubiKey for OpenPGP. You should do this and not use factory default codes. The default Admin PIN is 12345678 and the default PIN is 123456. Don't forget them!

$ ykman openpgp access change-admin-pin -a 12345678 # Enter your new 8-digit Admin PIN
$ ykman openpgp access change-pin -P 123456 # Enter your new 6-digit PIN

Generating key pair on YubiKey

Now using GnuPG, we can interface with our YubiKey OpenPGP implementation to create a new key pair that will be safely stored on it.

$ gpg --card-edit

You will enter the gpg/card prompt. Issue the following commands to the YubiKey and enter PIN (not-admin) code when asked. Do not back up the key as it is safer that way. Set some expiration date you like. Enter your name, email and comment. Finish by giving the Admin PIN when asked.

gpg/card> admin
gpg/card> generate
Make off-card backup of encryption key? (Y/n) n
Key is valid for? (0) 2y
Real name: John Doe
Email address:
Comment: my yubi pgp key

In case you want to use a different key size, before generate command, type key-attr and select key type you want. Verify with Admin PIN.

Next export the public key to a file using GPG. Assuming that you don't have any other keys in your keyring for the same e-mail address, you can write the following. This will be the key you share with others. Otherwise you can run in card edit mode of GPG list and copy the key ID to export.

$ gpg --armor --export > mypublickey.asc
$ gpg --import mypublickey.asc
$ gpg --list-keys

Look for the key ID you have just imported and save it. We will need it later. It will look something like:

pub   rsa4096 2020-05-04 [SC] [expired: 2024-05-03]
      THIS-IS-KEY-ID 01234ABCDEF01234...
uid           [ultimate] My Name <>

Cross-signing with an old key

This step is optional. In case you have some previous key pair that you used for GPG, you can copy over the new public key to your old keyring and sign it with the old private key. This way, you can have unbroken chain of trust.

$ gpg --import mypublickey.asc
$ gpg --list-keys # Find your old and new key IDs
$ gpg --default-key OLDKEYID --sign-key NEWKEYID
$ gpg --armor --export NEWKEYID > mypublickey-signed.asc

Configuring Thunderbird

By default Thunderbird uses some internal GnuPG storage. We need to ask it to connect to the external GPG agent so that it can connect to our YubiKey.

Open Thunderbird. Add your e-mail account if you didn't already. Click the three lines menu and select Settings. Scroll down to the bottom of the General page and click Config Editor....

Thunderbird Config Editor

Search for mail.openpgp.allow_external_gnupg and double click on it to set it to true. Quit Thunderbird with ⌘Q and open it again.

Right click on the account name in the left panel and select Settings. Select End-to-End Encryption section and click Add key. Select External through GnuPG and enter the key ID. It won't show any confirmation if that is correct, you will have to just try to use it.

External through GnuPG

Try sending encrypted e-mail to yourself with signature. Select Encrypt and OpenPGP at the top. If you see a warning that there's no key to encrypt this email, simply click Resolve and import the public key you exported previously (mypublickey.asc).

Resolve unknown public key

When trying to send or open encrypted e-mail, the PIN dialog should pop up. Type the 6-digit PIN you set for the key.

PIN dialog

The problem with this setup is that sometimes Thunderbird freezes when trying to decrypt or sign the email. I need then to "Force Quit" it in Activity Monitor on Mac. With touch policy enabled (ykman openpgp keys set-touch) it is even more problematic but sometimes it works. Once you enter the PIN for both decryption and signing and don't disconnect the key, don't kill GPG agent and don't quit Thunderbird, it should work smoothly.