We will generate a master key with only the Certify capability and three subkeys with each of the Sign, Encrypt and Authenticate capabilities. These latter three keys are meant for daily use and will be transferred to an OpenPGP smartcard, which has three corresponding slots. The master private key can then be moved to offline cold storage, or stored on a second smartcard.
We are generating keys on a secure computer instead of on the card, because it allows more flexibility. Ideally this means a machine running Tails or one that is air-gapped and not connected to the internet.
This guide assumes that if you want to sign other peoples keys, then you will require the aforementioned secondary smartcard with your master key stored in its Signature slot, or if you only have one smartcard, then you'll have to fetch the master key out of cold storage. By default, GPG generates a master key with the Certify and Sign capabilities and a subkey with the Encrypt capability. We will override this using expert mode.
First, make sure you're running GnuPG 2.x. This is important because you can't use 4096-bit RSA keys on most smartcards with GnuPG 1.x. A Bash alias will suffice, i.e.alias gpg=gpg2
.
If you use the Enigmail Thunderbird add-on, make sure the GPG path to /usr/bin/gpg2
.
If you're using a YubiKey on Tails, you might need to add udev rules in order to interact with the device. Create a file named 70-yubikey.rules
in /etc/udev/rules.d
with the following contents:
ACTION=="add|change", SUBSYSTEM=="usb", ATTR{idVendor}=="1050", ATTR{idProduct}=="0010|0110|0111|0114|0116|0401|0403|0405|0407|0410", OWNER="amnesia", TAG+="uaccess"
Then run sudo udevadm control --reload-rules
.
For the sake of brevity, this guide assumes that you will always enter passphrases and PINs, and answer Yes by typing y
when prompted.
At some point either before or after you should initialize your new smartcard, setting some of the variables if you so choose (stuff like name, url, login, lang, sex), but most importantly modify the default PIN (123456) and admin PIN (12345678). You can do this by running gpg --card-edit
and typing admin
and then help
to list available commands. Use passwd
to change your PINs. You can also toggle the forcesig
flag to control whether you'd like to require a PIN to be entered every time you sign a message.
Generate the master key
$ gpg --expert --gen-key
Select 8: RSA (set your own capabilities)
Select S, E, and Q so that you're left with only the Certify capability.
Set a 4096 bit key size.
Set the expiration date.
Setup a UID.
Setup a passphrase.
The key is generated.
Add UIDs
$ gpg --expert --edit-key <longid>
Use gpg> adduid
to add as many UIDs or e-mail addresses as you need. Once you're done, toggle to gpg> uid <#>
and use the gpg> primary
command to set the primary UID.
Now we will add subkeys for each capability to be transferred to the main smartcard designated for daily use.
Create the Sign key
gpg> addkey
Select 4: RSA (sign only).
Set a 4096 bit key size.
Set the expiration date.
The key is generated.
Create the Encrypt key
gpg> addkey
Select 6: RSA (encrypt only).
Set a 4096 bit key size.
Set the expiration date.
The key is generated.
Create the Authenticate key
gpg> addkey
Select 8: RSA (set your own capabilities)
Select S and E to toggle off the Sign and Encrypt capabilities.
Select A to toggle on the Authenticate capability and press Q.
Set a 4096 bit key size.
Set the expiration date.
The key is generated.
Set trust level
By the way, you should probably set the public key to the ultimate trust level.
gpg> trust
Select 5 = I trust ultimately.
gpg> save
Add signatures
If you want to sign the new master key with your previous key that you're transitioning from, the time is now.
$ gpg --sign-key <longid>
Generate revocation certificate
While you still have access to the master key with the Certify capability, it's a good idea to create a revocation certificate.
$ gpg --output revoke.asc --gen-revoke <longid>
Backup everything
$ gpg --armor --output privkey.sec --export-secret-key <longid>
$ gpg --armor --output subkeys.sec --export-secret-subkeys <longid>
$ gpg --armor --output pubkey.asc --export <longid>
You can move these private keys plus the revocation certificate someplace safe, like an encrypted partition or offline storage media.
Transfer your master key to a secondary smartcard
If you have two smartcards available, then you can store your master key in the Signature slot of a second smartcard, and use this one for stuff like signing other peoples keys, and making changes to your key, as in the scheme recommended by Tom Lowenthal's guide. After initializing the card and setting new PINs:
$ gpg --expert --edit-key <longid>
gpg> toggle
gpg> keytocard
Answer 'y' to "Really move the primary key?"
Select 1: Signature key.
gpg> save
As mentioned, switching to this smartcard will be required whenever you want to sign somebody else's key or make modifications to your key. Now eject it and put it away somewhere. You may want to create a label so you can tell them apart. Insert the primary smartcard that you've selected for daily use.
Load subkeys onto the smartcard
You can use gpg --card-edit
to initialize your smartcard: set the PINs, and variables like language, sex, your first and last name, or a URL for downloading your key. Now let's load the keys onto it.
$ gpg --expert --edit-key <longid>
gpg> toggle
gpg> key 1
gpg> keytocard
Select 1: Signature key.
Un-toggle key one:gpg> key 1
Toggle key two:gpg> key 2
gpg> keytocard
Select 2: Encryption key.
Un-toggle key two: gpg> key 2
Toggle key three: gpg> key 3
gpg> keytocard
Select 3: Authentication key.
gpg> save`
Now what?
You shouldn't have to delete any secret keys, as they were moved to the smartcard. When you use either keytocard
command or perform key generation on the card, GnuPG places a "stub" in your keyring so that it knows the actual secret key material is located on the smartcard. It looks like you have the secret key on your computer but you actually don't, and you can't decrypt anything without the card. It's just a stub pointing to the smartcard — which is something you do want to keep if you'd like this to be usable.
So what if you deleted the secret keys anyway and lost the stubs? Just run $ gpg --card-status
or open the 'Manage Smartcard' menu in Enigmail in order to instantly re-associate and populate your keyring with the information from your smartcard. However, always keep in mind that you need the corresponding public key in your keyring to work with the smartcard on whatever computer you're using.
After you purposely delete the secret key stubs from your keyring (otherwise it will say the keys are already associated with another card), you can even put these same keys on a different smartcard by repeating part of the process above.
However, you should probably backup or transfer these stubs to your regular computer first, since they're pointing to separate smartcards for different subkeys, and it's very difficult to re-create if you lose them—but it can be done using a tool called gpgsplit. Without all of the correct stubs, GnuPG won't prompt you to insert your other smartcard with a different serial number when you try to certify another key or alter attributes.
$ gpg --armor --output stubs.asc --export-secret-keys <longid>
Transfer this file to your regular, non-airgapped machine and run gpg --import
. This doesn't contain any actual secret key material — that's been migrated to the smartcard(s). Also make sure you transfer and import a copy of your pubkey.asc
for things to work properly.
You now have a working OpenPGP smartcard for use with GPG, Enigmail and more! Now you can let people know about your new key, upload it to keyservers, publish a transition statement, and all of that fun stuff.
Tips
gnome-keyring-daemon has a bad habit of hijacking the GnuPG agent, causing cards and readers to be unrecognized or to behave unpredictably. Many of these issues go away if you disable the ssh & gpg components of gnome-keyring-daemon and let gpg-agent handle them instead. Run gnome-keyring-daemon with only --components=pkcs11,secrets
...
To do this you can rm /etc/xdg/autostart/gnome-keyring-ssh.desktop
and gnome-keyring-gpg.desktop
or just add Hidden=true
plus X-GNOME-Autostart-enabled=false
to those launchers. If you prefer, you can create a new launcher just for starting gpg-agent (more ideally in ~/.config/autostart
).
If you are experiencing "Card not available" or "Card error", then you might want to try killing and restarting gpg-agent.
This resolved many issues and my smartcard now works reliably this way on Debian jessie with GnuPG 2.x.
To make sure your smartcard works in every Bash shell you open, it helps to add the following to ~/.bashrc
:
GPG_TTY=$(tty)
export GPG_TTY
eval $(cat ~/.gnupg/gpg-agent-info)
This assumes the presence of write-env-file ~/.gnupg/gpg-agent-info
in your gpg-agent.conf. Evaluating that file helps make sure you have the correct GPG_AGENT_INFO, SSH_AUTH_SOCK and SSH_AGENT_PID environment variables in each terminal session. While we're at it, here's what my ~/.gnupg/gpg-agent.conf
looks like:
pinentry-program /usr/bin/pinentry-qt4
keep-display
display :0.0
enable-ssh-support
write-env-file ~/.gnupg/gpg-agent-info
default-cache-ttl 300
max-cache-ttl 900
scdaemon-program /usr/lib/gnupg2/scdaemon
sh
debug-level none
homedir ~/.gnupg
This configuration depends on two packages you must install via apt-get, pinentry-qt4
and scdaemon
.
One annoying thing about most pinentry applications is that they don't allow pasting from clipboard, making them hard to use with a password manager. If you want to be able to do this, just grab the latest source of pinentry-qt4 (0.8.4 or greater) and then compile it with this option: ./configure --enable-pinentry-qt4-clipboard=yes
.
Using the smartcard key for SSH authentication
You can use your 4096-bit Authenticate key on the smartcard with SSH. This has the advantage that you can't log in to any servers without possession of the device. It's easiest to do with the latest GnuPG 2.1.x, otherwise you may have to install monkeysphere and use the openpgp2ssh
tool, which we're going to skip. Note: this won't work unless you've set a non-default smartcard PIN of at least 6 digits.
On GnuPG 2.0.x, when you run gpg-agent with enable-ssh-support
so that it takes over for ssh-agent, your smartcard's Authenticate subkey should automatically be recognized as a valid SSH key and become available for the SSH client to use as an identity. But you might have trouble getting it to work, so here are some extra steps which can assist the process:
Add enable-ssh-support
and write-env-file
to ~/.gnupg/gpg-agent.conf
Fetch the keygrip of your master public key with gpg2 --with-keygrip -k
and add these 40 hex digits as a line to~/.gnupg/sshcontrol
.
Make sure gpg-agent --daemon --options ~/.gnupg/gpg-agent.conf
is running in the background. If you run ssh-add -l
it should list an SSH identity corresponding to the RSA key on your smartcard.
Check echo $SSH_AUTH_SOCK
- it should be pointing to gpg-agent's socket instead of ssh-agent. If it's not you have to kill ssh-agent or make sure it doesn't start.
Get the 16-digit long ID of your Authenticate subkey and feed it into gpgkey2ssh
:
$ gpgkey2ssh 00698E823F6DD692 > ssh_id.pub
You can add the contents of ssh_id.pub to ~/.ssh/authorized_keys
on any system you like, or you can try ssh-copy-id
.
Now your SSH agent should be communicating with gpg-agent and the RSA Authenticate key on your smartcard is a valid SSH identity. When you run SSH with your smartcard connected, it will automatically attempt to authenticate using it.
More resources:
https://www.inuits.eu/blog/ssh-authentication-your-pgp-key http://www.bootc.net/archives/2013/06/09/my-perfect-gnupg-ssh-agent-setup/
How to obtain the OpenPGP smartcards and USB readers
I now recommend the YubiKey version 4 instead of the OpenPGP smartcard from g10 code. It's modern hardware, much faster, and has many great features. These devices can be purchased from Amazon.
If you have any questions about the information in this guide, you can reach me on Twitter @ageis, by e-mail to kevin [at] freedom [dot] press (PGP key), or XMPP/Jabber: [email protected].
Still relevant in 2022. 👍
Since GPG UX and conceptual clarity is somewhat bad, I'm interested if GPG private key material on the local machine was deleted (desired) or still remains in the keychain (undesired).
I moved a gpg (2.x) generated key to a Yubikey 5 NFC card with multiple subkeys and generated an encryption subkey on the card to fill the Yubikey encryption slot. Also, I use this Yubikey as one of several 2FA options for Bitwarden where all other service 2FAs are stored rather than in authenticator apps.
Edit: To answer my own question:
~/.gnupg/private-keys-v1.d/*
gpg --card-status
to repopulate~/.gnupg/private-keys-v1.d/*
with shadowed keys~/.gnupg/private-keys-v1.d/*
.Looks good.
Some private keys weren't transferred to the card but there's a key for each function now that can be rolled-over in every use-case. (gpg-agent as ssh-agent needed keys rolled.)
Now: