The following is the GNU All-permissive License as recommended in https://www.gnu.org/licenses/license-recommendations.en.html

Copyright (C) 2024 Free Software Foundation sysadmin@fsf.org

Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty.

Contributions are welcome. See https://savannah.gnu.org/maintenance/fsf/.

[[!toc levels=2]]

The following instructions should work for devices like Yubikey or Nitrokey. Note that some packages or settings use the name yubikey but should be vendor-neutral for U2F devices.

Yubikey specific settings

First, configure the key as a OTP/U2F/CCID composite device (mode 6)

ykpersonalize -m6 -y

The integration with LUKS, PAM, and Abrowser requires the device to be set in Challenge/response mode. To set up the yubikey configuration slot 2 for that use, run:

$ ykpersonalize -v -2 -ochal-resp -ochal-hmac -ohmac-lt64 -oserial-api-visible -ochal-btn-trig

This setting makes the key wait for you to touch it before replying to the challenge. Save the output of the command, as the secret can be used to recreate the key if you lose it. Slot 1 is still available to be configured in any other setting you may need (by default, OTP).

You should set the access code to the key, you can do it with these commands:

$ CODE=$(openssl rand -hex 6)
$ echo $CODE
$ ykpersonalize -2 -oaccess=$CODE

Note, save $CODE somewhere safe. If you do this step, you then should add -c $CODE to any future ykpersonalize commands, or you will get a write error.

Integration with LUKS

Mostly taken from https://web.archive.org/web/*/https://www.howtoforge.com/ubuntu-two-factor-authentication-with-yubikey-for-harddisk-encryption-with-luks

This will add a key in slot 7 that requires using a password in combination with the key. You can have other passwords in the other slots that don't require a key, but they should be very strong.

# apt-get install yubikey-luks
# # Edit /usr/bin/yubikey-luks-enroll and set $DISK to the appropriate path
# yubikey-luks-enroll
# update-initramfs -u

If you need to wipe the key in slot 7, you can run cryptsetup luksKillSlot /dev/sdXX 7

You should replace your original slot 1 with a very strong password, write that down and keep it in a safe place, for recovery in case of losing the key. This is the command to change the password:

# cryptsetup luksChangeKey /dev/XXXX

Integration with login (PAM / lightdm / gdm)

Mostly taken from:

  • https://web.archive.org/web/*/https://support.yubico.com/support/solutions/articles/15000011356-ubuntu-linux-login-guide-u2f
  • https://metebalci.com/blog/using-u2f-at-linux-login/

    # apt-get install libpam-u2f pamu2fcfg $ mkdir ~/.config/Yubico -p $ pamu2fcfg -opam://myhostname -ipam://myhostname > .config/Yubico/u2f_keys

When the key begins blinking, touch to confirm.

If you have a backup key, also run this with each key inserted:

pamu2fcfg -opam://myhostname -ipam://mydhostname -n >> .config/Yubico/u2f_keys

Add the following line:

auth required pam_u2f.so  cue nouserok origin=pam://myhostname appid=pam://myhostname

To these files, after “@include common-auth”

  • /etc/pam.d/lightdm
  • /etc/pam.d/sudo
  • /etc/pam.d/login
  • /etc/pam.d/mate-screensaver

Note that it is possible to just add that to /etc/pam.d/common-auth to affect all services, but doing so would prevent remote access to the machine (ssh, cups, samba, etc). This is good practice in a laptop that is intended to never be remotely accessed, but would break things on servers.

To be able to log in if you lose the key, you can either create a user with a very strong password and add it to the sudo group, or set a very strong password for root. Keep the password safe! If the disk is also LUKS encrypted, refer to that section.

Passwordless sudo

If you want to replace your sudo password with touching the key, you can use this line in /etc/pam.d/sudo before "@include common-auth"

auth [success=done new_authtok_reqd=done default=die] pam_u2f.so cue origin=pam://myhostname appid=pam://myhostname

Integration with Abrowser

Go to about:config and make sure that security.webauth.u2f is set to true. This allows for the key to be used for two-factor on sites like Gitlab, nextcloud and many others.

You can now go to https://www.yubico.com/genuine/ to verify the key.

Integration with GPG

https://github.com/drduh/YubiKey-Guide https://www.esev.com/blog/post/2015-01-pgp-ssh-key-on-yubikey-neo/

(Ideally you want to do this in a live Trisquel session.)

# apt-get update
# apt-get install -y \
 curl gnupg2 gnupg-agent \
 cryptsetup scdaemon pcscd \
 yubikey-personalization \
 dirmngr \
 secure-delete \
 hopenpgp-tools \
 pwgen \
 rng-tools

Harden gpg config

$ mkdir .gnupg
cat << EOF >> ~/.gnupg/gpg.conf
# https://github.com/drduh/config/blob/master/gpg.conf
# https://www.gnupg.org/documentation/manuals/gnupg/GPG-Configuration-Options.html
# https://www.gnupg.org/documentation/manuals/gnupg/GPG-Esoteric-Options.html
# Use AES256, 192, or 128 as cipher
personal-cipher-preferences AES256 AES192 AES
# Use SHA512, 384, or 256 as digest
personal-digest-preferences SHA512 SHA384 SHA256
# Use ZLIB, BZIP2, ZIP, or no compression
personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed
# Default preferences for new keys
default-preference-list SHA512 SHA384 SHA256 AES256 AES192 AES ZLIB BZIP2 ZIP Uncompressed
# SHA512 as digest to sign keys
cert-digest-algo SHA512
# SHA512 as digest for symmetric ops
s2k-digest-algo SHA512
# AES256 as cipher for symmetric ops
s2k-cipher-algo AES256
# UTF-8 support for compatibility
charset utf-8
# Show Unix timestamps
fixed-list-mode
# No comments in signature
no-comments
# No version in signature
no-emit-version
# Long hexidecimal key format
keyid-format 0xlong
# Display UID validity
list-options show-uid-validity
verify-options show-uid-validity
# Display all keys and their fingerprints
with-fingerprint
# Display key origins and updates
#with-key-origin
# Cross-certify subkeys are present and valid
require-cross-certification
# Disable putting recipient key IDs into messages
throw-keyids
# Enable smartcard
use-agent
EOF

Preload entropy

sudo rngd -r /dev/urandom

Create a private key, only for certifying subkeys, no expiration. Use a very strong password

gpg2 --expert --full-gen-key
 Select (8) RSA (set your own capabilities)
 Toggle sign and encryption capabilities off, leave certify only
 Set lenght to 4096
 Set the key to not expire
 Use your full real name and last name
 For your main identity, it may be better to use @gnu.org instead of @fsf.org as that email would be kept forever.

Create one key each for signing, encrypting and authenticating (ssh). Set them to expire in a year. 2048 is a good enough size for this and it would have better performance on the yubikey. Use a password you can remember, it will be used in combination with the yubikey

gpg2 --expert --edit-key $KEYID

Select 4 for the signing key, 6 for encryption, and 8 for auth (for this one, toggle capabilities until it only lists authentication)

Verify keys:

gpg2 --list-secret-keys

Add more identities

gpg2 --expert --edit-key $KEYID
> adduid

Export/backup your keys

gpg2 --armor --export-secret-keys $KEYID > ~/.gnupg/mastersub.key
gpg2 --armor --export-secret-subkeys $KEYID > ~/.gnupg/sub.key

Save .gnupg to encrypted storage (LUKS)

dd if=/dev/zero of=encrypted.img bs=1M count=100
cryptsetup luksFormat encrypted.img
cryptsetup luksOpen encrypted.img crypt0
mkfs.xfs /dev/mapper/crypt0
mount /dev/mapper/crypt0 /media
cp .gnupg /media
umount /media
cryptsetup luksClose /dev/mapper/crypt0

Transfer the keys into the yubikey. This may ask for your subkey passphrase. Repeat this for keys 1 to 3

gpg --edit-key $KEYID
key 1
keytocard
1
save
quit

Updating subkeys

Import your secret keys from saved mastersub.key, then change expirations or do any other operations

gpg --import mastersub.key
gpg --edit-key $KEYID
key x
expire
keytocard
save

Integration with SSH

This requires having set the integration with GPG

Add this to your .gnupg/gpg-agent.conf

enable-ssh-support
pinentry-program /usr/bin/pinentry
default-cache-ttl 60
max-cache-ttl 120

Launch agent with

gpgconf --launch gpg-agent

Add this to your .bashrc

export SSH_AUTH_SOCK=$HOME/.gnupg/S.gpg-agent.ssh

After running that command, you can print your public key with command

ssh-add -L

You can now use that public key the usual way with ssh/scp/etc

Integration with OpenVPN

TODO

openssl pkcs12 -export -out cert_key.p12 -inkey ruben3.key -in ruben3.crt -certfile ca.crt -nodes
yubico-piv-tool -s 9c -i cert_key.p12 -K PKCS12 -a import-key -a import-cert