title: YubiKey documentation
YubiKeys are rugged security keys that can do FIDO2 two-factor authentication (2FA), PKCS and OpenPGP operations, all inside a small USB form factor.
- Tutorial
-
How to
- Getting a security key
- Form factors
- YubiKey training
- SSH authentication in FIDO2 mode
- SSH RSA authentication in PIV mode
- SSH authentication in OpenPGP mode
-
OpenPGP operations
- Why OpenPGP
- Why GnuPG, ECC, or air-gapped systems
- Implementation details
- Assertions
- Special considerations for storing encryption keys
- Install software and preparation
- Key generation
- Export to backup
- Moving to key
- Touch policy
- Making a second YubiKey copy
- Using the YubiKey on a new computer
- Agent setup
- Exporting SSH public keys from GnuPG
- Signed Git commit messages
- Preliminary performance evaluation
- Troubleshooting
-
FAQ
- I don't have usb-c in my laptop, would i need an adaptor then?
- Who should use this?
- I do my work from Tails, do I need a Yubikey?
- Can I use the USB port during my work session, or i need to have the YubiKey plugged all the time?
- Any reason why we pick a Yubikey and not a tool with a open design like a NitroKey?
- My Yubikey squirts out an OTP code when I accidentally touch it
- Pager playbook
- Disaster recovery
- Reference
- Discussion
Tutorial
How to
Getting a security key
There is a wild variety of security keys out there. This guide focuses on the YubiKey, but there are alternatives as well.
You may order a YubiKey directly from their store. You can also ask TPA if they have any remaining keys although at the time of writing, the whole stock was depleted at the 2023 Costa Rica meeting.
Form factors
YubiKeys come mainly in two form factor axis:
- USB-C or USB-A
- "normal" or "nano"
The decision on USB-C vs USB-A should be relatively simple:
-
if you have older computers that do not have USB-C, or are worried about backwards-compatibility, use USB-A.
-
if you want to go USB-C only, use USB-C, but be aware there's been anecdotal reports of the USB-C form factor being more fragile than the USB-A form (the connector can apparently get dented, although other reports claim this has been fixed)
The decision between "normal" and "nano" depends mostly on how big you like the key, but also how sturdy you expect it to be.
The author of this guide (@anarcat), has been wearing a YubiKey NEO for over 8 years on his keyring. It has been dropped in water, slush, sand, probably been in a laundry at least once, and has been worn out quite significantly, up to the point that the connector is round instead of square. It still works relatively reliably.
Another example is a YubiKey 5 "nano" that has had a part of it's plastic case uncapped after only a few months of active use.
So it seems the sturdy one is the "normal" form factor, and that the "nano" is designed to be stuck in a USB port and stay there.
Finally, also note that the USB-C "nano" form factor doesn't have a hole to hook on a wire or keyring. The USB-A "nano" form factor does have such a ring and Yubico sells a lanyard to hook it up to your keyring. The lanyard is 0.18" thick, so presumably any wire of that gauge (AWG ~5 or SWG 6-7) would fit as well. Note that a metal wire might wear out faster, consider a fishing line (e.g. Nylon).
YubiKey training
This section holds the notes to the YubiKey training given in Costa Rica in April 2023.
Introduction
-
what is a YubiKey? it's a 2FA token with extra capabilities
-
why is it called a YubiKey? "Yubico's explanation of the name "YubiKey" is that it derives from the phrase "your ubiquitous key", and that "yubi" is the Japanese word for finger." (Wikipedia, source)
-
what is 2FA? two-factor authentication
-
why do we need 2FA?
- to make hacking your account more difficult,
- ... and because people are not great at remembering good passwords
- it's required by GitHub and our Nextcloud instance
-
why do we need a Yubikey? it's better than typical 2FA, it can protect against:
- phishing attacks (and say why)
- shoulder surfing and surveillance cameras
-
it cannot protect against:
- malware on your computer (as they can control the YubiKey or steal your session cookie)
- successful HTTPS MITM
-
what are we going to do today? 2FA only
"There's all sorts of pitfalls and challenges in deploying 2FA and YubiKeys (e.g. "I lost my YubiKey" or "OMG GnuPG is hell"), we're not going to immediately solve all of those issues. We're going to get hardware into people's hands and hopefully train them with U2F/FIDO2 web 2FA, and maybe be able to explore the SSH/OpenPGP side of things as well."
Unpacking and authenticating a YubiKey
- check blister packaging
- login to https://www.yubico.com/genuine/
Setting up 2FA in Nextcloud
We can either follow the upstream guide or our own tutorial. Here's a copy of the latter with only the U2F instructions:
- In NextCloud, select Settings -> Security. The link to your settings can be found by clicking on your "user icon" in the top right corner. Direct link: Settings -> Security.
- Pick either the U2F device as an "second factor".
- Click the "Add U2F device" button under the "U2F device" section
- Insert the token and press the button when prompted by your web browser
- Enter a name for the device and click "Add"
- Click "Generate Backup codes" in the Two-Factor Authentication section of that page.
- Save your backup codes to a password manager of your choice. These will be needed to regain access to your NextCloud account if you ever lose your 2FA token/application.
- Log out and log in again, to verify that you got two factor authentication working.
Setting up 2FA in GitLab
-
In gitlab, select "Preferences" and then in the left-hand column, "Account"
-
In section "Register a WebAuthn Device" find the "Set Up a New Device" button
-
IF you are using yubikey-agent for ssh, you need to stop that temporarily (otherwise the setup fails) systemctl --user stop yubikey-agent.service
-
Now click the "Set Up a New Device Button"
-
Touch the Yubikey button to confirm
-
Give the device a reference name so you can identify it
-
IF necessary, restart the yubikey-agent.service
-
If you have not already done so, generate and save the 2FA backup codes.
-
Log out and log back in again, to verify the yubikey 2FA works.
SSH authentication in FIDO2 mode
Recent YubiKeys like the YubiKey 5 ship a "FIDO2" applet that is generally used for two-factor authentication. But SSH also supports using that to store SSH keys, which can therefore be used to authenticate against servers.
This Yubico guide shows you how to configure such keys,
recognizable from their -sk
suffix (e.g. ed25519-sk
). See also
this GitHub guide.
This is the recommended method for users who want to use their YubiKeys for SSH connections to GitLab, GitHub, Debian servers, etc.
It should be noted that the -sk
SSH keys are relatively new, and as such are
often not supported by old devices and servers. Users who would like to to use
their YubiKey to secure connections to such older SSH servers may use one of
the modes below, in addition to native FIDO2 keys.
In particular, -sk
keys are currently not supported by our
LDAP configuration, see this ticket for details.
SSH RSA authentication in PIV mode
This guide should be followed if you want to use SSH without depending on OpenPGP or FIDO2.
YubiKey 5-series tokens, which support the FIPS 201 standard also known as PIV, can be used as a convenient second factor to for ssh public key authentication.
While the YubiKey supports either RSA or ECC certificates for this, we'll use
RSA since it's the most compatible across all SSH servers. For example, some BMC
only support ssh-rsa
keys. This has also been observed on Pantheon.io, a DevOps
platform for websites. For modern SSH servers, the ed25519-sk
key type is
preferred.
WARNING: because yubikey-agent
requires exclusive access to the yubikey, this
method is only practical when the yubikey's OpenPGP interface is not used.
Otherwise, the more practical solution is to use the OpenPGP interface with an
authentication subkey that can be used as an SSH key pair.
Token setup
First, one must install yubikey-manager.
On Debian 11 (bullseye), a simple apt install yubikey-manager
is sufficient. On
older versions of Debian, one should install it via pip3
in order to have a
sufficiently recent version of the tool.
- Reset all PIV config/data on the token:
ykman piv reset
- Define new PIN (the default is
123456
):ykman piv change-pin
- The PIN must be between 6 and 8 characters long, and supports any type of alphanumeric characters. For cross-platform compatibility, numeric digits are recommended.
- Define new PUK (Personal Unblocking Key, used when PIN retries have been
exceeded):
ykman piv change-puk
- Define a management key:
piv change-management-key -pt
- Generate RSA key:
ykman piv keys generate --algorithm RSA2048 --pin-policy ONCE --touch-policy CACHED 9a pubkey.pem
- Generate certificate:
ykman piv certificates generate --valid-days 3650 --subject "CN=ssh" 9a pubkey.pem
- Verify with
ykman piv info
This will create a 2048-bits RSA certificate in slot 9a of the PIV token device.
The PIN will be required only once per-session (--pin-policy ONCE
) but touch
will be required at every use and remembered for 15 seconds afterwards
(--touch-policy CACHED
).
The next step is to install and start yubikey-agent which is a small daemon written in Go that act as an ssh-agent for the YubiKey. Installation instructions which work with Debian can be found here:
https://github.com/FiloSottile/yubikey-agent/blob/main/systemd.md
The yubikey-agent -setup
step can be skipped, as we've already set up the
token with the above. yubikey-agent
's own setup routine makes different,
hard-coded choices with regard to the PIN and PUK (identical), certificate type
(ECC) and other small things.
Once the agent is setup and running in the background, the SSH public key can be
retrieved from the token using the following command: ssh-add -L
.
At this point it may be useful to install the libnotify-bin
package on Debian
which allows the agent to send a desktop notification when the token needs to be
touched to perform an authentication operation. This is especially useful when
the token LED, which flashes when touch is requested, isn't well into view.
These instructions are spinned off from those found at: https://eta.st/2021/03/06/yubikey-5-piv.html
Configure SSH
If not done already, now is a good time to setup the ssh configuration for the TPO jump host, see ssh-jump-host for these instructions.
To have the ssh
command use yubikey-agent
when connecting to TPO hosts, add
this line in ~/.ssh/config
under Host *.torproject.org
:
IdentityAgent /run/user/1000/yubikey-agent/yubikey-agent.sock
If you also want to use ed25519_sk
-type keys based on the modern FIDO2
protocol for non-TPO hosts, you may add this at the end of ~./ssh/config
:
Host *
IdentityAgent /dev/null
IdentityFile ~/.ssh/id_ed25519_sk
SSH authentication in OpenPGP mode
See below.
OpenPGP operations
The YubiKeys also ship with an "OpenPGP smartcard applet" that allows you to store cryptographic keys. The YubikKey 5 in particular supports ECC keys.
Why OpenPGP
We use OpenPGP here because it's still the "standard" (e.g. specified in RFCs) way to do interoperable offline cryptographic operations in various locations. It's also heavily used at Tor and, until further notice, a requirement to get a working email account.
Finally, the OpenPGP applet provides a way to use SSH with YubiKeys
that is somewhat clunky, but doesn't suffer from backwards
compatibility problems that the SSH sk-
keys suffer from.
That said, there are serious issues with using OpenPGP here:
- it's awfully complicated
- it's brittle
- it doesn't support "touch detection" (i.e. there is no user feedback when the device requires a touch, other than the device itself blinking, something that the FIDO2 applet solves, see this discussion and this tool for a workaround)
Why GnuPG, ECC, or air-gapped systems
See our OpenPGP docs for that discussion.
Implementation details
The stack we going to setup is as follows:
- YubiKey (hardware)
- USB connection (or other), bus, CPU, etc (hardware)
-
scdaemon
(GnuPG software that interacts with "smart cards" like the YubiKey) -
gpg-agent
(GnuPG software that holds private keys or passphrases) - GnuPG or SSH commands that interact with the agent
Assertions
This guide assumes the following:
-
a lot of familiarity with the command-line
-
a Debian system, but should be easy to adapt to other operating systems, some hints are provided for Mac OS
-
enough entropy; failing that, this can feed entropy from the YK (from drduh's guide):
echo "SCD RANDOM 512" | gpg-connect-agent | sudo tee /dev/random | hexdump -C
-
a trusted device that was not previously compromised; we explicitly do not explain how to do this from an "air-gapped" device, for example, as this is considered an implementation detail (and possibly overkill, a full discussion of those trade-offs would be irrelevant here)
-
the YubiKey has been obtained from trusted channels and verified (see Unpacking and authenticating a YubiKey
Special considerations for storing encryption keys
Here we are storing a full OpenPGP secret keyring on the YubiKey. This implies that encryption keys end up stored on the device. Therefore, special care need to be taken as the loss of a YubiKey could be catastrophic: in such a case, while the encryption key can be revoked, that doesn't allow the operator to recover past material encrypted with the key. This can lead to severe data loss.
Encryption keys, therefore, must not be generated on the YubiKey as they MUST be backed up. They therefore MUST be generated on another device.
The general strategy here is to have three copies of the encryption key:
-
main key
: a first YubiKey used for daily operation -
backup key
: a second YubiKey available as a backup -
backup disk
: a copy of the encryption key material stored on a normal disk, encrypted with itself
The rationale here is that if the main key
is lost, the backup key
and backup disk
can be combined to create a new main key
.
If the backup disk
did not exist, it would be impossible to recreate
a new main key
and, when the backup key
is eventually lost or
destroyed, the encrypted contents will not be readable anymore.
This is the strategy taken in this guide.
Install software and preparation
You will need to install GnuPG, its scdaemon
component and a
yubikey-manager, a "command line tool for configuring a YubiKey".
apt install gnupg scdaemon yubikey-manager
If you're on a Mac, you'll also need to explicitly install
pinentry-mac
, see the Ultimate Yubikey Setup Guide with ed25519!
If you're on Windows, good luck, maybe this section of drduh's guide can help you.
Make sure the key is detected:
ykman list
This should show your key, for example this is with a recent YubiKey 5 NFC (USB-A):
$ ykman list
YubiKey 5 NFC (5.4.3) [OTP+FIDO+CCID] Serial: [REDACTED]
$
In the above, you can see the string [OTP+FIDO+CCID]
which basically
tells you that you can use the token for "OTP" (One-Time
Passwords in general, but in this particular case it's actually
TOTP, AKA "Google Authenticator"), FIDO2, and CCID, the
"chip card interface device" protocol.
Those are all different "applications" shipped with the YubiKey that can be enabled or disabled independently. OpenPGP operations rely on the latter (CCID), so it needs to be listed in the above output.
If it isn't, use this to enable it (and, in this example, also FIDO2):
ykman config mode FIDO+CCID
You may want to disable NFC if you are not going to use it:
ykman config nfc --disable-all
The end result should look something like this:
anarcat@angela:~$ ykman info
Device type: YubiKey 5 NFC
Serial number: [REDACTED]
Firmware version: 5.4.3
Form factor: Keychain (USB-A)
Enabled USB interfaces: FIDO, CCID
NFC transport is enabled.
Applications USB NFC
FIDO2 Enabled Disabled
OTP Disabled Disabled
FIDO U2F Enabled Disabled
OATH Enabled Disabled
YubiHSM Auth Disabled Disabled
OpenPGP Enabled Disabled
PIV Enabled Disabled
Note that "You must remove and re-insert your YubiKey for this change to take effect", as indicated.
Finally, you should really set a new PIN and admin PIN on the
key. This is easily done with GnuPG itself, first enter the magic
card-edit
shell with:
gpg --card-edit
That will show you the following prompt:
gpg/card>
There you need to type the admin
and passwd
commands to change the
first PIN:
gpg/card> admin
Admin commands are allowed
gpg/card> passwd
gpg: OpenPGP card no. [REDACTED] detected
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
Your selection? 1
This will prompt you for the current PIN. The factory default is
123456
(yes, just like the combination on someone's luggage).
You will want to also set the Admin PIN, but the default is slightly different
from the previous one, it is 12345678
:
gpg/card> passwd
gpg: OpenPGP card no. [REDACTED] detected
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
Your selection? 3
[... pinentry prompt ...]
PIN changed.
I typically set both to the same value since the basic PIN basically allows any operation I'm worried about (short of changing the keys) anyway. Furthermore, if they would be different, I would very likely forget the admin PIN and wouldn't be able to reset the normal PIN after too many failed attempts.
You may also want to enable the KDF feature on newer
YubiKeys. This allows the YubiKey to store the PIN as a hashed
value instead of cleartext, and makes it harder to bruteforce as the
caller needs to run the KDF function. This was implemented in
2017 and is not necessarily supported by all clients. It's also
irreversible, so beware. To turn it on, simply call kdf-setup
on the
gpg/card>
prompt.
Details about reset, admin, and PIN
The OpenPGP applet has three different PINs:
-
the normal PIN: used in normal operation, when you need to unlock the card to do a cryptographic operation
-
the Admin PIN: used to unlock the card if the above "normal PIN" gets input incorrectly too many times, or configure card (e.g. add/remove keys, change name, etc)
-
the reset PIN: used to only unlock the card (e.g. like the Admin PIN except it cannot do the other things)
By default, the reset PIN is not used in YubiKeys and, indeed, it might not make sense for a single-user case. According to this comment it's designed for enterprise setups where administrators configure keys for users and do not want to let them change their own keys. See also drduh's guide for a discussion on this.
Key generation
At this point, if you don't already have a key pair to put on the YubiKey, you should generate a new OpenPGP key. Follow the procedure to Generate a Curve25519 key.
If you are rotating keys, do not publish the revocation certificate for the old key just yet, in case the procedure below fails.
Note that we're not generating the keys on the YubiKey itself. There are two reasons for this:
-
we need access to the private key to clone the key and particularly recover the encryption key from backups (see Special considerations for storing encryption keys
-
entropy sources on security keys have been known to be flawed in the past, including on Yubikeys, see for example the infineon vulnerability
Export to backup
At this point, we have an OpenPGP key pair we're ready to put on the security key. But before we do that, we need to make a backup, because the procedure moves the keys onto the security key, which makes it inaccessible.
Follow the procedure in the OpenPGP guide.
After this step, it's assumed you have
$BACKUP_DIR/openpgp-backup-$FINGERPRINT.tar.pgp
and
$BACKUP_DIR/openpgp-backup-public-$FINGERPRINT.key
files available.
Moving to key
WARNING: this MOVES the key to the security card, make sure you have backups as explained above.
Now we're going to do the sensitive step of moving the secret keys onto the YubiKey. First, edit the key:
gpg --edit-key $FINGERPRINT
Then, to move the primary key, simply call:
keytocard
This will ask you where to store the key, select (1) Signature key
.
Then move the two subkeys:
key 1
keytocard
key 1
key 2
keytocard
The double key 1
above is not an error: it deselects the first
subkey to only select the second subkey.
Here's an example run:
anarcat@angela:~$ gpg --edit-key $FINGERPRINT
gpg (GnuPG) 2.2.40; Copyright (C) 2022 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
sec ed25519/02293A6FA4E53473
created: 2023-05-30 expires: 2024-05-29 usage: SC
trust: unknown validity: unknown
ssb cv25519/9456BA69685EAFFB
created: 2023-05-30 expires: never usage: E
ssb ed25519/9FF21704D101630D
created: 2023-05-30 expires: never usage: A
[ unknown] (1). Antoine Beaupré <anarcat@anarc.at>
gpg> keytocard
Really move the primary key? (y/N) y
Please select where to store the key:
(1) Signature key
(3) Authentication key
Your selection? 1
sec ed25519/02293A6FA4E53473
created: 2023-05-30 expires: 2024-05-29 usage: SC
trust: unknown validity: unknown
ssb cv25519/9456BA69685EAFFB
created: 2023-05-30 expires: never usage: E
ssb ed25519/9FF21704D101630D
created: 2023-05-30 expires: never usage: A
[ unknown] (1). Antoine Beaupré <anarcat@anarc.at>
gpg> key 1
sec ed25519/02293A6FA4E53473
created: 2023-05-30 expires: 2024-05-29 usage: SC
trust: unknown validity: unknown
ssb* cv25519/9456BA69685EAFFB
created: 2023-05-30 expires: never usage: E
ssb ed25519/9FF21704D101630D
created: 2023-05-30 expires: never usage: A
[ unknown] (1). Antoine Beaupré <anarcat@anarc.at>
gpg> keytocard
Please select where to store the key:
(2) Encryption key
Your selection? 2
sec ed25519/02293A6FA4E53473
created: 2023-05-30 expires: 2024-05-29 usage: SC
card-no: 0006 REDACTED
trust: unknown validity: unknown
ssb* cv25519/9456BA69685EAFFB
created: 2023-05-30 expires: never usage: E
ssb ed25519/9FF21704D101630D
created: 2023-05-30 expires: never usage: A
[ unknown] (1). Antoine Beaupré <anarcat@anarc.at>
gpg> key 1
sec ed25519/02293A6FA4E53473
created: 2023-05-30 expires: 2024-05-29 usage: SC
card-no: 0006 REDACTED
trust: unknown validity: unknown
ssb cv25519/9456BA69685EAFFB
created: 2023-05-30 expires: never usage: E
ssb ed25519/9FF21704D101630D
created: 2023-05-30 expires: never usage: A
[ unknown] (1). Antoine Beaupré <anarcat@anarc.at>
gpg> key 2
sec ed25519/02293A6FA4E53473
created: 2023-05-30 expires: 2024-05-29 usage: SC
card-no: 0006 REDACTED
trust: unknown validity: unknown
ssb cv25519/9456BA69685EAFFB
created: 2023-05-30 expires: never usage: E
ssb* ed25519/9FF21704D101630D
created: 2023-05-30 expires: never usage: A
[ unknown] (1). Antoine Beaupré <anarcat@anarc.at>
gpg> keytocard
Please select where to store the key:
(3) Authentication key
Your selection? 3
sec ed25519/02293A6FA4E53473
created: 2023-05-30 expires: 2024-05-29 usage: SC
card-no: 0006 REDACTED
trust: unknown validity: unknown
ssb cv25519/9456BA69685EAFFB
created: 2023-05-30 expires: never usage: E
card-no: 0006 REDACTED
ssb* ed25519/9FF21704D101630D
created: 2023-05-30 expires: never usage: A
[ unknown] (1). Antoine Beaupré <anarcat@anarc.at>
gpg> save
Then keys should not be present in the keyring:
anarcat@angela:1000$ gpg --list-secret-keys
/run/user/1000/.gnupg/pubring.kbx
---------------------------------
sec> ed25519 2023-05-30 [SC] [expires: 2024-05-29]
BBB6CD4C98D74E1358A752A602293A6FA4E53473
Card serial no. = 0006 23638206
uid [ultimate] Antoine Beaupré <anarcat@anarc.at>
ssb> cv25519 2023-05-30 [E]
ssb> ed25519 2023-05-30 [A]
In the above, we can see the secret keys are not present because they
are marked sec>
and ssb>
, not sec
and ssb
.
Touch policy
This is optional.
You may want to change the touch policy. This requires you to touch the YubiKey to consent to cryptographic operation. Here's one policy, for example:
ykman openpgp keys set-touch sig on
ykman openpgp keys set-touch enc on
ykman openpgp keys set-touch aut cached
NOTE: the above didn't work before the OpenPGP keys were created, that is normal.
That means:
- touch is required to confirm signatures
- touch is required to confirm decryption
- touch is required to confirm authentication, but is cached 15 seconds
The latter merits some explanation. I operate a lot of servers, and sometimes run batch commands on many of them at once. Tapping for every one of those would lead to alert fatigue and be extremely annoying. The 15 seconds delay is a good compromise.
You can see the current policies with ykman openpgp info
, for
example:
$ ykman openpgp info
OpenPGP version: 3.4
Application version: 5.4.3
PIN tries remaining: 3
Reset code tries remaining: 0
Admin PIN tries remaining: 3
Touch policies
Signature key On
Encryption key On
Authentication key Cached
Attestation key Off
If you get an error running the info
command, maybe try to
disconnect and reconnect the YubiKey.
The default is to not require touch confirmations.
Do note that touch confirmation is a little counter-intuitive: the operation (sign, authenticate, decrypt) will hang without warning until the button is touched. The only indication is the blinking LED, there's no other warning from the user interface.
Also note that the PIN itself is cached by the YubiKey, not the
agent. There is a wishlist item on GnuPG to expire the password
after a delay, respecting the default-cache-ttl
and max-cache-ttl
settings from gpg-agent.conf
, but alas this do not currently take
effect.
Ultimately, I ended up setting all to cached
:
ykman openpgp keys set-touch sig cached
ykman openpgp keys set-touch enc cached
ykman openpgp keys set-touch aut cached
The rationale is this:
-
sig on
is absolutely painful if you go through a large rebase and need to re-sign a lot of commits -
enc on
is similarly hard if you are decrypting a large thread of multiple messages -
aut
is mentioned above, and in fact I sometimes just flip backaut off
for some batches that take longer than 15 seconds
It should be noted that the cache
setting is a 15 seconds delay
total: it does not reset when a new operation is done. This means
that the entirety of the job needs to take less than 15 seconds, which
is why I sometimes completely disable it for larger runs.
Making a second YubiKey copy
At this point, we have a backup of the keyring that is encrypted with itself. We obviously can't recover this if we lose the YubiKey, so let's exercise that disaster recovery by making a new key, completely from the backups.
-
first, go through the preparation steps above, namely setting the CCID mode, disabling NFC, setting a PIN and so on
-
create a fresh new GnuPG home:
export GNUPGHOME=${XDG_RUNTIME_DIR:-/nonexistent}/.gnupg-restore mkdir $GNUPGHOME
-
make sure you kill
gpg-agent
and related daemons, they can get confused when multiple home directories are involved:killall scdaemon gpg-agent
-
restore the public key:
gpg --import $BACKUP_DIR/public.key
-
confirm GnuPG can not see any secret keys:
gpg --list-secret-keys
you should not see any result from this command.
-
then, crucial step, restore the private key and subkeys:
gpg --decrypt $BACKUP_DIR/gnupg-backup.tar.pgp | tar -x -f - --to-stdout | gpg --import
-
confirm GnuPG can see the secret keys: you should not see any
Card serial no.
,sec>
, orssb>
in there. If so, it might be because GnuPG got confused and still thinks the old key is plugged in. -
then go through the
keytocard
process again, which is basically:gpg --edit-key $FINGERPRINT
then:
keytocard 1 key 1 keytocard key 2 keytocard
At this point the new key should be a good copy of the previous YubiKey. If you are following this procedure because you have lost your previous YubiKey, you should actually make another copy of the YubiKey at this stage, to be able to recover when this key is lost.
Using the YubiKey on a new computer
One of the beauties of using a YubiKey is that you can somewhat easily use the same secret key material material across multiple machines without having to copy the secrets around.
This procedure should be enough to get you started on a new machine.
-
install the required software:
apt install gnupg scdaemon
-
restore the public key:
gpg --import $BACKUP_DIR/public.key
Note: this assumes you have a backup of that public key in
$BACKUP_DIR
. If that is not the case, you can also fetch the key from key servers or another location, but you must have a copy of the public key for this to work.If you have lost even the public key, you may want to read this guide: recovering lost GPG public keys from your YubiKey – Nicholas Sherlock create, untested.
-
confirm GnuPG can see the secret keys:
gpg --list-secret-keys
you should not see any
Card serial no.
,sec>
, orssb>
in there. If so, it might be because GnuPG got confused and still thinks the old key is plugged in. -
set the trust of the new key to
ultimate
:gpg --edit-key $FINGERPRINT
Then, in the
gpg>
shell, call:trust
Then type
5
for "I trust ultimately". -
test signing and decrypting a message:
gpg --clearsign < /dev/null gpg --encrypt -r $FINGERPRINT < /dev/null | gpg --decrypt
Agent setup
At this point, GnuPG is likely working well enough for OpenPGP
operations. If you want to use it for OpenSSH as well, however, you'll
need to replace the built-in SSH agent with gpg-agent
.
The right configuration for this is tricky, and may vary wildly depending on your operating system, graphical and desktop environment.
The Ultimate Yubikey Setup Guide with ed25519! suggests adding this to your environment:
export "GPG_TTY=$(tty)"
export "SSH_AUTH_SOCK=${HOME}/.gnupg/S.gpg-agent.ssh"
... and this in ~/.gnupg/gpg-agent.conf
:
enable-ssh-support
If you are running a version before GnuPG 2.1 (and you really shouldn't), you will also need:
use-standard-socket
Then you can restart gpg-agent
with:
gpgconf --kill gpg-agent
gpgconf --launch gpg-agent
If you're on a Mac, you'll also need:
pinentry-program /usr/local/bin/pinentry-mac
In GNOME, there's a keyring agent which also includes an SSH agent, see this guide for how to turn it off.
At this point, SSH should be able to see the key:
ssh-add -L
If not, make sure SSH_AUTH_SOCK
is pointing at the GnuPG agent.
Exporting SSH public keys from GnuPG
Newer GnuPG has this:
gpg --export-ssh-key $FINGERPRINT
You can also use the more idiomatic:
ssh-add -L
... assuming the key has been used at least once.
Signed Git commit messages
To sign Git commits with OpenPGP, you can use the following configuration:
git config --global user.signingkey $FINGERPRINT
git config --global commit.gpgsign true
Git should be able to find GnuPG and will transparently use the YubiKey to sign commits
Preliminary performance evaluation
Preparation:
dd if=/dev/zero count=1400 | gpg --encrypt --recipient 8DC901CE64146C048AD50FBB792152527B75921E > /tmp/test-rsa.pgp
dd if=/dev/zero count=1400 | gpg --encrypt --recipient BBB6CD4C98D74E1358A752A602293A6FA4E53473 > /tmp/test-ecc.pgp
RSA native (non-Yubikey) performance:
$ time gpg --decrypt < /tmp/test-rsa.pgp
gpg: encrypted with 4096-bit RSA key, ID A51D5B109C5A5581, created 2009-05-29
"Antoine Beaupré <anarcat@orangeseeds.org>"
0.00user 0.00system 0:00.03elapsed 18%CPU (0avgtext+0avgdata 6516maxresident)k
0inputs+8outputs (0major+674minor)pagefaults 0swaps
ECC security key (YubiKey 5) performance:
$ time gpg --decrypt < /tmp/test-ecc.pgp
gpg: encrypted with 255-bit ECDH key, ID 9456BA69685EAFFB, created 2023-05-30
"Antoine Beaupré <anarcat@torproject.org>"
0.00user 0.03system 0:00.12elapsed 30%CPU (0avgtext+0avgdata 7672maxresident)k
0inputs+8outputs (0major+1834minor)pagefaults 0swaps
That is, 120ms vs 30ms, the YubiKey is 4 times slower than the normal configuration. An acceptable compromise, perhaps.
Troubleshooting
If an operation fails, check if GnuPG can see the card with:
gpg --card-status
You can also try this incantation, which should output the key's firmware version:
gpg-connect-agent --hex "scd apdu 00 f1 00 00" /bye
For example, this is the output when successfully connecting to an old Yubikey NEO running the 1.10 firmware:
gpg-connect-agent --hex "scd apdu 00 f1 00 00" /bye
D[0000] 01 00 10 90 00 .....
OK
The OK
means it can talk to the key correctly. Here's an example
with a Yubikey 5:
$ gpg-connect-agent --hex "scd apdu 00 f1 00 00" /bye
D[0000] 05 04 03 90 00 .....
OK
A possible error is:
ERR 100663404 Card error <SCD>
That could be because of a permission error. Normally, udev
rules
are in place to keep this from happening.
If everything goes south and you locked yourself out of your key, you can completely wipe the OpenPGP applet with:
ykman openpgp reset
WARNING: that will WIPE all the keys on the device, make sure you have a backup or that the keys are revoked!
If GnuPG doesn't pop up a dialog prompting you for a password, you
might have an incorrect TTY
variable. Try to kick gpg-agent
with:
gpg-connect-agent updatestartuptty /bye
See also drduh's troubleshooting guide.
FAQ
I don't have usb-c in my laptop, would i need an adaptor then?
If you get a USB-A key, yes, but you can get a USB-C key!
Who should use this?
Everyone! If you're using a service like Nextcloud, the Discourse forum, GitLab, you should enable 2FA and preferably with a cryptographic token. That's not yet official policy, but it's probably going to hit the security policy in some shape or form in the future.
I do my work from Tails, do I need a Yubikey?
Yes, because Tails doesn't necessarily protect you against phishing attacks.
Can I use the USB port during my work session, or i need to have the YubiKey plugged all the time?
You don't need to have it plugged in all the time.
One interesting aspect of the YubiKey is that you can unplug it and decide "nope, authentication doesn't happen here anymore".
It's a clear way to secure that cryptographic material, physically.
Any reason why we pick a Yubikey and not a tool with a open design like a NitroKey?
anarcat made a review of the Nitrokey in 2017 and found that their form factor was less reliable than the YubiKey.
The Solokey was also considered but is not quite ready for prime time yet. See also this review. Google's Titan key was also an option but only supports 2FA (not OpenPGP or SSH), see the other alternatives section for more details.
My Yubikey squirts out an OTP code when I accidentally touch it
There are several ways to deal with this issue. Since we don't use Yubico OTP in Tor, the easiest solution is to simply disable the OTP app on the USB interface.
First, ensure the Yubikey is inserted in one of your USB ports.
On the command-line, you can install the yubikey-manager
package and run the
command below:
ykman config usb --disable otp
This program is also available with a GUI, installed with yubikey-manager-qt
on Debian-based systems. Installers for other platforms such as Windows and
MacOS can be downloaded from the Yubico website download page.
The procedure with the Yubikey Manager GUI is to open the program, click the
Interfaces
tab, and under USB
, uncheck OTP
and click Save interfaces
.
Once this is done, OTP will remain disabled until it's manually re-enabled.
If you want to conserve the ability to generate Yubico OTP codes, there are two
options: either disable sending the <Enter>
character using ykman otp settings --no-enter 1
, or swap the OTP to slot 2, which requires a sustained
2-second touch to activate, with ykman otp swap
.
Pager playbook
Disaster recovery
Reference
Installation
When you receive your YubiKey, you need to first inspect the "blister" package to see if it has been tampered with.
Then, open the package, connect the key to a computer and visit this page in a web browser:
https://www.yubico.com/genuine/
This will guide you through verifying the key's integrity.
Out of the box, the key should work for two-factor authentication with FIDO2 on most websites. It is imperative that you keep a copy of the backup or "scratch" codes that are usually provided when you setup 2FA on the site, as you may lose the key and that is the only way to recover from that.
For other setups, see the following how-to guides:
Upgrades
YubiKeys cannot be upgraded, the firmware is read-only.
SLA
N/A