Nick Travers

Yubikeys

Commands for setting up a Yubikey, with GPG key, SSH key, and macOS login.

Relies on the following:

GPG

Set up roughly following this guide.

# Insert key ... duh

# Bring up gpg
$ gpg --card-edit

# Enter admin mode
gpg/card> admin

# Set the PIN and admin PIN
gpg/card> passwd

# Generate a key
gpg/card> generate

Set up the agent:

pinentry-program $PATH_TO/pinentry-mac
default-cache-ttl 600
max-cache-ttl 7200

Add the following to your profile:

GPG_TTY="$(tty)"
export GPG_TTY
gpgconf --launch gpg-agent

Seeding local instance

Import keys in RAM (e.g. /dev/shm).

$ gpg --import private.key

Export subkeys.

$ gpg --armor --output subkeys.key --export-secret-subkeys $KEY

Remove all secret keys.

$ gpg --delete-secret-keys $KEY

Re-import subkey secret keys.

$ gpg --import subkeys.key

Update the subkey to point at the Yubikey.

$ gpg --expert --edit-key $KEY

gpg> key $NUM
gpg> keytocard

Select signature key. Enter the passphrases to unlock the key, and then enter the Yubikey admin PIN (12345678).

Save and exit.

List the secret keys, which should show a pointer to the card for the subkey.

$ gpg --list-secret-keys
------------------------------
sec>  ... snip ...
ssb>  ... snip ...

Shred any remaining key material.

$ shred -u $FILE [$FILE ...]

SSH

The simplest way to set up SSH with a YubiKey is using FIDO2 resident keys. This stores the private key directly on the YubiKey, with no need for PIV, OpenSC, or PKCS#11. Requires OpenSSH 8.2+ and a YubiKey with firmware 5.2.3+.

Set a FIDO2 PIN on the key if you haven't already (you'll only need to do this once):

$ ykman fido access change-pin

Generate a resident key on the YubiKey:

# The -O resident flag stores the key on the YubiKey itself, so it can
# be loaded on any machine with ssh-add -K.
# The -O application=ssh:yourname lets you distinguish multiple resident
# keys on the same YubiKey.
$ ssh-keygen -t ed25519-sk -O resident -O application=ssh:yourname

This will create ~/.ssh/id_ed25519_sk and ~/.ssh/id_ed25519_sk.pub. Add the public key to GitHub, servers, etc.

Load the key from the YubiKey into your SSH agent:

$ ssh-add -K

Each SSH operation will require a physical touch of the YubiKey. This is a security feature of FIDO2 and cannot be disabled when loading keys via ssh-add -K.

Confirm the key has been added:

$ ssh-add -L

The nice thing about resident keys is portability. On a new machine, just run ssh-add -K with the YubiKey inserted, and the key is available immediately, with no need to copy key files around.

SSH (legacy PIV method)

Click to expand the older PIV/PKCS#11 approach

The following generates a new SSH keypair that resides on the key using PIV. This method requires opensc and is more complex, but allows disabling the touch requirement. Adapted from the following:

Ensure that opensc and yubico-piv-tool are installed.

Create a volume in memory to use for temporarily storing the key material (see ramdisk).

# Switch into the ramdisk
$ cd /volumes/secure
$ umask 077

# Create a public key.
# Enter the management key when prompted.
# Default: 010203040506070801020304050607080102030405060708
$ yubico-piv-tool \
  -a generate \
  -s 9a \
  -k \
  --pin-policy=once \
  --touch-policy=always \
  --algorithm=ECCP256 \
  -o public.pem

# Create a self-signed certificate
# Enter the PIN when prompted, then tap the key.
$ yubico-piv-tool \
  -a verify-pin \
  -a selfsign-certificate \
  -s 9a \
  -S '/CN=ssh/' \
  --valid-days=365 \
  -i public.pem \
  -o cert.pem

# Import the certificate
# Enter the management key when prompted.
$ yubico-piv-tool -k -a import-certificate -s 9a -i cert.pem

Confirm that the key has been added:

$ yubico-piv-tool -a status

At this point, the SSH key should be loaded on the Yubikey. Fetch the public key:

$ ssh-keygen -D $HOME/.nix-profile/lib/opensc-pkcs11.so -e

Note that the path to the .so file may differ, based on the setup. The above is based on using Nix.

Add the key to the local ssh-agent:

$ _path=$(readlink $HOME/.nix-profile/lib/opensc-pkcs11.so) \
  ssh-add -s "$_path"

Note that the path must match the value that has been whitelisted on the ssh-agent via the -P flag.

Confirm the key has been added:

$ ssh-add -L

macOS Login

You can use the YubiKey's PIV smart card to unlock your Mac at the lock screen. This uses a certificate in PIV slot 9a (Authentication), which is separate from the FIDO2 SSH key above.

Ensure ykman is installed. Generate a key and certificate in PIV slot 9a:

# Generate a key in the authentication slot.
$ ykman piv keys generate --algorithm ECCP256 9a public.pem

# Create a self-signed certificate (10 years to avoid frequent renewal).
# Enter the PIV PIN when prompted (default: 123456).
$ ykman piv certificates generate --subject "CN=yourname" --valid-days 3650 9a public.pem

# Clean up the public key file.
$ rm public.pem

Pair the YubiKey with your macOS user account:

# List unpaired smart card identities. Copy the hash.
$ sc_auth identities

# Pair the key with your user.
$ sudo sc_auth pair -h <hash> -u $(whoami)

Lock your screen (Ctrl+Cmd+Q) and unlock with the YubiKey by entering your PIV PIN. Set up a second YubiKey the same way as a backup.

If your PIV PIN gets blocked (3 wrong attempts), unblock it with the PUK (default: 12345678):

$ ykman piv access unblock-pin

It's a good idea to change the default PIN, PUK, and management key:

$ ykman piv access change-pin
$ ykman piv access change-puk
$ ykman piv access change-management-key