Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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.

At this point you can try removing the key to confirm that the secret key is not available, for example with the command:

gpg --clear-sign < /dev/null

This should ask you to insert the key. Inserting the key should GnuPG to output a valid signature.

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 is a full touch policy:

ykman openpgp keys set-touch sig cached
ykman openpgp keys set-touch enc cached
ykman openpgp keys set-touch aut cached

NOTE: the above didn't work before the OpenPGP keys were created, that is normal.

The above means that touch is required to confirm signature, encryption and authentication operations, but is cached 15 seconds. 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 crucial when running batch jobs on multiple servers, as tapping for every one of those would lead to alert fatigue, and in fact I sometimes just flip back aut off for some batches that take longer than 15 seconds

Another policy could be:

ykman openpgp keys set-touch sig on
ykman openpgp keys set-touch enc on
ykman openpgp keys set-touch aut cached

That means:

  1. touch is required to confirm signatures
  2. touch is required to confirm decryption
  3. touch is required to confirm authentication, but is cached 15 seconds

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.

It should also 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.

  1. first, go through the preparation steps above, namely setting the CCID mode, disabling NFC, setting a PIN and so on. you also should have a backup of your secret keys at this point, if not (and you still have a copy of your secret keys in some other keyring), follow the OpenPGP guide to export a backup that we assume to be present in$BACKUP_DIR.

  2. create a fresh new GnuPG home:

    OTHER_GNUPGHOME=${XDG_RUNTIME_DIR:-/nonexistent}/.gnupg-restore
    ( umask 0077 && mkdir OTHER_GNUPGHOME )
    
  3. make sure you kill gpg-agent and related daemons, they can get confused when multiple home directories are involved:

    killall scdaemon gpg-agent
    
  4. restore the public key:

    gpg --homedir=$OTHER_GNUPGHOME --import $BACKUP_DIR/openpgp-backup-public-$FINGERPRINT.key
    
  5. confirm GnuPG can not see any secret keys:

    gpg --homedir=$OTHER_GNUPGHOME --list-secret-keys
    

    you should not see any result from this command.

  6. then, crucial step, restore the private key and subkeys:

    gpg --decrypt $BACKUP_DIR/openpgp-backup-$FINGERPRINT.tar.pgp | tar -x -f - --to-stdout | gpg --homedir $OTHER_GNUPGHOME --import
    

    You need the first, main key to perform this operation.

  7. confirm GnuPG can see the secret keys: you should not see any Card serial no., sec>, or ssb> in there. If so, it might be because GnuPG got confused and still thinks the old key is plugged in.

  8. then go through the keytocard process again, which is basically:

    gpg --homedir $OTHER_GNUPGHOME --edit-key $FINGERPRINT
    

    then remove the main key and plug in the backup yubikey to move the keys to that key:

    keytocard
    1
    key 1
    keytocard
    2
    key 1
    key 2
    keytocard
    3
    save
    

    If that fails with "No such device", you might need to kill gpg-agent again as it's very likely confused:

    killall scdaemon gpg-agent
    

    Or you might need to plug the key out and back in again.

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.

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 is present.

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

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.

  1. install the required software:

    apt install gnupg scdaemon
    
  2. 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.

  3. confirm GnuPG can see the secret keys:

    gpg --list-secret-keys
    

    you should not see any Card serial no., sec>, or ssb> in there. If so, it might be because GnuPG got confused and still thinks the old key is plugged in.

  4. 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".

  5. test signing and decrypting a message:

    gpg --clearsign < /dev/null
    gpg --encrypt -r $FINGERPRINT < /dev/null | gpg --decrypt
    

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.

See also drduh's troubleshooting guide.

Resetting a YubiKey

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!

Incorrect TTY

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

Incorrect key grip

If you somehow inserted your backup key and now GnuPG absolutely wants nothing to do with your normal key, it's because GnuPG silently replaced your "key grips". Those are little text files that it uses to know which physical key has a copy of your private key.

You can see the key grip identifiers in GnuPG's output with:

gpg -K --with-keygrip

They look like key fingerprint, but for some reason (WHY!?) are not. You can then move those files out of the way with:

cd ~/.gnupg/private-keys-v1.d
mkdir ../private-keys-v1.d.old
mv 23E56A5F9B45CEFE89C20CD244DCB93B0CAFFC73.key 74D517AB0466CDF3F27D118A8CD3D9018BA72819.key 9826CAB421E15C852DBDD2AB15A866CD0E81D68C.key ../private-keys-v1.d.old
gpg --card-status

You might need to run that --card-status a few times.

We're not instructing you to delete those files because, if you get the identifier wrong, you can destroy precious private key material here. But if you're confident those are actual key grips, you can remove them as well. They should look something like this:

Token: [...] OPENPGP.2 - [SERIAL]
Key: (shadowed-private-key [...]

As opposed to private keys, which start with something like this:

(11:private-key[...]

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

Design and architecture

A YubiKey is an integrated circuit that performs cryptographic operations on behalf of a host. In a sense, it is a tiny air-gapped computer that you connect to a host, typically over USB but Yubikeys can also operate over NFC.

Services

N/A

Storage

The YubiKeys keep private cryptographic information embedded in the key, for example RSA keys for the SSH authentication mechanism. Those keys are supposed to be impossible to extract from the YubiKey, which means they are also impossible to backup.

Queues

N/A

Interfaces

YubiKeys use a few standards for communication:

  • FIDO2 for 2FA
  • PIV for SSH authentication
  • OpenPGP "smart card" applet for OpenPGP signatures, authentication and encryption

Authentication

It's possible to verify the integrity of a key by visiting:

https://www.yubico.com/genuine/

Implementation

The firmware on YubiKeys is proprietary and closed source, a major downside to this platform.

YubiKeys can be used to authenticate with the following services:

ServiceAuthentication type
Discourse2FA
GitLab2FA, SSH
Nextcloud2FA

Issues

There is no issue tracker specifically for this project, File or search for issues in the team issue tracker with the label ~Foo.

Maintainer

anarcat worked on getting a bunch of YubiKeys shipped to a Tor meeting in 2023, and is generally the go-to person for this, with a fallback on TPA.

Users

All tor-internal people are expected to have access to a YubiKey and know how to use it.

Upstream

YubiKeys are manufactured by Yubico, a company headquartered in Palo Alto in California, but with Swedish origins. It has merged with a holding company from Stockholm in April 2023.

Monitoring and metrics

N/A

Tests

N/A

Logs

N/A

Backups

YubiKeys backups are complicated by the fact that you can't actually extract the secret key from a YubiKey.

FIDO2 keys

For 2FA, there's no way around it: the secret is generated on the key and stays on the key. The mitigation is to keep a copy of the backup codes in your password manager.

OpenPGP keys

For OpenPGP, you may want to generate the key outside the YubiKey and copy it in, that way you can backup the private key somewhere. A robust and secure backup system for this would be made in three parts:

  1. the main YubiKey, which you use every day
  2. a backup YubiKey, which you can switch to if you lose the first one
  3. a copy of the OpenPGP secret key material, encrypted with itself, so you can create a second key when you lose a key

The idea of the last backup is that you can recover the key material from the first key with the second key and make a new key that way. It may seem strange to encrypt a key with itself, but it is actually relevant in this specific use case, because another copy of the secret key material is available on the backup YubiKey.

Other documentation

Discussion

While we still have to make an all-encompassing security policy (TPA-RFC-18), we have decided in April 2023 to train our folks to use YubiKeys as security keys, see TPA-RFC-53 and discussion ticket. This was done following a survey posted to tor-internal, the results of which are available in this GitLab comment.

Requirements

The requirements checklist was:

  • FIDO2/U2F/whatever this is called now
  • physical confirmation button (ideally "touch")
  • OpenPGP applet should be available as an option
  • USB A or USB-C?
  • RSA, and ed5519 or equivalent?

It should cover the following use cases:

  • SSH (through the SK stuff or gpg-agent + openpgp auth keys)
  • OpenPGP
  • web browsers (e.g. gitlab, discourse, nextcloud, etc)

Security and risk assessment

Background

TPA (Tor Project system Administrators) is looking at strengthening our security by making sure we have stronger two-factor authentication (2FA) everywhere. We have mandatory 2FA on some services, but this can often take the form of phone-based 2FA which is prone to social engineering attacks.

This is important because some high profile organizations like ours were compromised by hacking into key people's accounts and destroying critical data or introducing vulnerabilities in their software. Those organisations had 2FA enabled, but attackers were able to bypass that security by hijacking their phones, which is why having a cryptographic token like a YubiKey is important.

We also don't necessarily provide people with the means to more securely store their (e.g. SSH) private keys, used commonly by developers to push and sign code. So we are considering buying a bunch of YubiKeys, bringing them to the next Tor meeting, and training people to use them.

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.

Threat model

The main threat model is phishing, but there's another threat actor to take into account: powerful state-level adversaries. Those have the power to intercept and manipulate packages as they ship for example. For that reason, we were careful in how the devices were shipped, and they were handed out in person at an in-person meeting.

Users are also encouraged to authenticate their YubiKey using the Yubico website, which should provide a reliable attestation that the key was really made by Yubico.

That assumes trust in the corporation, of course. The rationale there is the reputation cost for YubiKey would be too high if they allowed backdoors in their services, but it is of course a possibility that a rogue employee (or Yubico itself) could leverage those devices to successfully attack the Tor project.

Future work

Ideally, there would be a rugged and open-hardware device that could simultaneously offer the tamper-resistance of the YubiKey while at the same time providing an auditable hardware platform.

Technical debt and next steps

At this point, we need to train users on how to use those devices, and factor this in a broader security policy (TPA-RFC-18).

Proposed Solution

This was adopted in TPA-RFC-53, see also the discussion ticket.

Other alternatives

  • tillitis.se: not ready for end-user adoption yet
  • Passkeys are promising, but have their own pitfalls. They certainly do not provide "2FA" in the sense that they do not add an extra authentication mechanism on top of your already existing passwords. Maybe that's okay? It's still early to tell how well passkeys will be adopted and whether they will displace traditional mechanisms or not.
  • Nitrokey: not rugged enough
  • Solokey: 2FA only, see also the tomu family
  • FST-01: EOL, hard to find, gniibe is working on a smartcard reader
  • Titan keys: FIDO2 only, but ships built-in with Pixel phones
  • Trezor Safe 3: Crypto coin cold wallet, with built-in security key support. With a screen on the device to display verify what site is actually being logging in to, this device is more safe in the way that it does not require blind sign thus reducing the need to trust the host device is not compromised when the key is used. It comes with some usability issue such as the need to input pin on device before any usage, and when more than one key is inserted at the same time, it is unable to assist the discovery of the security key associated with key handle provided, making it necessary to insert and insert only the right security key when authentication happens. More suitable to be used in unowned and unverified device like someone else's computer or device running proprietary(someone else's) software.

The New York Times Wirecutters recommend the Yubikey, for what it's worth.