Using Yubi keys for GPG/SSH keys
I've recently replaced my GPG keys with new ones stored on Yubi keys, why? Well...
- To use a master key and sub keys, previously I only had a master key
- To make the keys portable (no need to copy them to all machines)
- To enable SSH compatability
- It was fun
Step 1 - Prepare the system
- Install the yubi ppa for the latest key support and install the personalization tool
sudo add-apt-repository ppa:yubico/stable
sudo apt-get update
sudo apt-get install yubikey-personalization yubikey-personalization-gui
- Install the gpg prequisites
sudo apt-get -y install gnupg2 gnupg-agent pinentry-tty scdaemon
Step 2 - Prepare the yubi keys
- Plug in the yubi key
- Run
ykpersonalize -m 86
to enable OTP/U2F/CCID functionality - Run
gpg2 --card-status
to see the card - Run
gpg2 --card-edit
to edit the card - Enter
admin
to toggle admin commands - Enter
passwd
to enter the password changing options - Choose option 1 and set a new pin
- Choose option 3 and set a new admin pin
- Set the various other options (check the
help
command)
Step 3 Generate the new master key and revocation certificate
Either on a new machine/air gapped machine/live usb whatever your preference is depending on your paranoia run the following:
export GNUPGHOME=$(mktemp -d)
if it's in /tmp (probably) and won't interfere with any existing keys so you can nuke the folder if you make a mistake.
Now run:
cd $GNUPGHOME
export GPG_TTY=$(tty)
cat <<EOT > gpg.conf
keyserver hkps://hkps.pool.sks-keyservers.net
auto-key-locate keyserver
personal-cipher-preferences AES256 AES192 AES CAST5 CAMELLIA256 CAMELLIA192 CAMELLIA128
personal-digest-preferences SHA512 SHA384 SHA256 SHA224
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
cert-digest-algo SHA512
s2k-digest-algo SHA512
s2k-cipher-algo AES256
keyid-format long
EOT
gpg2 --full-gen-key
- Choose option 4 (RSA sign only)
- Choose a key size for the master 4096 isn't a bad idea
- Set an expiration I set mine to 5y, you can update this later
- Add your name/email/comment
- Export the key id to a variable
export KEYID=IdFromAboveCommand
You can add extra uids using gpg2 --edit-key $KEYID
then adduid
once all have been added use
the uid N
replacing N with the uid index you want to be the primary, then run primary
to make
the uid primary, finally run save
To generate a revocation certificate run
gpg --gen-revoke $KEYID > $GNUPGHOME/revoke.txt
Step 4 Generate sub keys
Run gpg2 --expert --edit-key $KEYID
Enter addkey
Choose option 4 for signing keys, option 6 for encryption keys and option 8 followed
by S E A to disable signing and encyrption and enable authentication for keys to be used for SSH.
Yubi keys only support 2048 bit RSA keys which is perfectly fine at the time of writing.
Run the save
command and now you have all your keys ready.
Step 5 Export the secret keys
Export the master and sub keys with gpg2 --armor --export-secret-keys $KEYID > $GNUPGHOME/mastersub.key
Export the sub keys with gpg2 --armor --export-secret-subkeys $KEYID > $GNUPGHOME/sub.key
Step 6 backup the private keys important do this before copying keys to the yubi key
- Create at least two encrypted usb sticks (or some other form of external media)
- Run
cd $GNUPGHOME && tar -cvpf /path/to/encrypted/stick/gpg.tar .
for each stick
Step 7 copy the keys to the card
- Plug the card in
- Run
gpg2 --expert --edit-key $KEYID
- Run the
toggle
command - Use
key N
to select the first key (S/E/A) to send, replacing N with the key index - Use
keytocard
to send the key to the card this will remove the key from your computer
If you want to use the same key on multiple cards you must restore the tar backup you made earlier
tar -xvpf /path/to/encrypted/stick/gpg.tar
Step 8 Export, sign and publish the new key
- Run
gpg2 --export $KEYID > /tmp/gpg.pub
- Now on your normal machine (or if this is your normal machine, in a new terminal without the
$GNUPGPHOME variable set) run
gpg2 --import < /tmp/gpg.pub
- If you have an existing key sign the new one with
gpg2 --default-key OLDKEYID --sign-key $KEYID
(note $KEYID will need setting again) - Send the key to the key servers
gpg2 --send-key $KEYID
Some notes
- This was done using gpg (GnuPG) 2.1.11 on Ubuntu 16.04
- Some distros install both gpg and gpg2 (i.e. Ubuntu 16.04) hence it's important to use gpg2 for all commands
- I have 3 yubi keys, each with the same encryption and signing keys but a unique authentication (ssh) key
- You can have multiple signing and authentication keys (one per yubi key) however you can only have one encryption key, gpg will default to the most recently created when choosing which to use.
- Once set up you can add
default-key $KEYID
to~/.gnupg/gpg.conf
to sign with the new key - gpg will note the card serial when using a key, if you try and use the same key with a different card
it will ask you to insert the old card. To work around this run
gpg2 --with-keygrip -k $KEYID
this will output a line withKeygrip = longstring
the long string is the .key file stored in~/.gnupg/private-keys-v1.d/
which you can delete and now use the new card. To make life easier it's best to try and use the same card with each computer. - If pin entry isn't popping up run
export GPG_TTY=$(tty) && echo 'UPDATESTARTUPTTY' | gpg-connect-agent
- Yubi key pins can be alphanumeric
- You can obtain the ssh public key by running
gpg2 --card-status && ssh-add -L
- If you use a normal SSH key which requires a password to unlock gpg will add this to
~/.gnupg/private-keys-v1.d/
and ask you for a new passphrase to store it as a gpg key. The keys stored in this way are in~/.gnupg/sshcontrol
My gpg.conf looks like this
keyserver hkps://hkps.pool.sks-keyservers.net
auto-key-locate keyserver
personal-cipher-preferences AES256 AES192 AES CAST5 CAMELLIA256 CAMELLIA192 CAMELLIA128
personal-digest-preferences SHA512 SHA384 SHA256 SHA224
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
cert-digest-algo SHA512
s2k-digest-algo SHA512
s2k-cipher-algo AES256
keyid-format long
My gpg-agent.conf looks like this
pinentry-program /usr/bin/pinentry-tty
default-cache-ttl 21600
max-cache-ttl 21600
default-cache-ttl-ssh 1800
max-cache-ttl-ssh 3600
enable-ssh-support
The following in .profile
will set up the GPG tty, allow you to use pinentry over ssh and set up the ssh agent socket
#!/bin/bash
# set the gpg tty
export GPG_TTY=$(tty)
# if the gpg agent is running tell it this window is now the pin entry window
if [ -e ~/.gnupg/S.gpg-agent ]
then
echo 'UPDATESTARTUPTTY' | gpg-connect-agent > /dev/null
fi
# If the ssh auth sock isn't set, set it (note this still allows agent forwarding) and also overrides
# the gnome keychain auth sock
if [ -z "$SSH_AUTH_SOCK" -o "$SSH_AUTH_SOCK" == "/run/user/$(id -u)/keyring/ssh" ]
then
export SSH_AUTH_SOCK="$HOME/.gnupg/S.gpg-agent.ssh"
fi
# sometimes things can get out of whack, run this function to fix them (handy at first login)
function fixgpgssh() {
export GPG_TTY=$(tty)
gpg --card-status > /dev/null
echo 'UPDATESTARTUPTTY' | gpg-connect-agent > /dev/null
export SSH_AUTH_SOCK="$HOME/.gnupg/S.gpg-agent.ssh"
}
References
- https://ocramius.github.io/blog/yubikey-for-ssh-gpg-git-and-local-login/
- https://wiki.debian.org/Subkeys?action=show&redirect=subkeys
- https://developers.yubico.com/PGP/Importing_keys.html
- https://github.com/drduh/YubiKey-Guide
- https://developers.yubico.com/yubikey-personalization/Manuals/ykpersonalize.1.html
- https://unix.stackexchange.com/questions/185393/gpg-agent-doesnt-remove-my-ssh-key-from-the-keyring#185420