Skip to content

Instantly share code, notes, and snippets.

@fervic
Last active June 21, 2023 04:18
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save fervic/ad30e9f76008eade565be81cef2f8f8c to your computer and use it in GitHub Desktop.
Save fervic/ad30e9f76008eade565be81cef2f8f8c to your computer and use it in GitHub Desktop.
GnuPG offline Master key using a YubiKey (for Arch Linux)

GnuPG offline Master key using a YubiKey (for Arch Linux)

Introduction

This guide is a compilation of four other guides. It instructs how to create a set of GnuPG keys which the master key is offline and the actual subkeys only live inside your YubiKey (acting as a smartcard). What ends up in your (online) daily machine are only the stubs of the subkeys.

Install required software

$ sudo pacman -Syu gnupg pcsc-tools ccid libusb-compat hopenpgp-tools yubikey-personalization

Ideally these steps are performed on an offline machine. Consider creating a live ISO that already has the required packages plus these instructions. In case of creating the live ISO, tmux is also recommended so the steps can be performed in a split pane side by side with these instructions.

Create temporary $GNUPGHOME dir

$ export GNUPGHOME=$(mktemp -d); echo $GNUPGHOME
/tmp/tmp.<some temp value>

Create configuration

Based on this recommended one.

$ cat << EOF > $GNUPGHOME/gpg.conf
use-agent
personal-cipher-preferences AES256 AES192 AES CAST5
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
charset utf-8
fixed-list-mode
no-comments
no-emit-version
keyid-format 0xlong
list-options show-uid-validity
verify-options show-uid-validity
with-fingerprint
EOF

Create Master key

$ gpg --full-generate-key

Values:

  • Kind: 4 - RSA (sign only)
  • Keysize: 4032 - arbitrary number to break the usual power of two key size (recommended here
  • Expiration: 1yr
  • Passphrase: use a strong one you already had in mind or run shuf -n10 /usr/share/dict/cracklib-smallr for generating random words from which you can pick to use as a passphrase. IMPORTANT: you have to memorize this.

Save key ID

$ KEYID=<id shown in the previous step>

Add your photo to the key

$ gpg --edit-key $KEYID
gpg> addphoto

Create revocation certificate

It needs to be stored in a safe place, separate from the Master key itself. It is to be used in case your offline Master key is compromised.

Create $VOLATILE temp location

$ export VOLATILE=$(mktemp -d); echo $VOLATILE
/tmp/tmp.<some temp value>

Generate the certificate

$ gpg --gen-revoke $KEYID > $VOLATILE/<youremail@yourdomain.com>.gpg-revocation-certificate.txt

Values:

  • Reason: 1
  • Description: Generated during key creation, emergency use only.

IMPORTANT: Don't forget to print it or copy it to a safe place; remember $VOLATILE is currently located in memory and it will be lost after system reboot.

Backup master key

Create exports/ folder inside $GNUPGHOME

This is the target folder for saving key exports.

$ mkdir -p $GNUPGHOME/exports

Export the secret keys

$ gpg --export-secret-keys --armor $KEYID > $GNUPGHOME/exports/<youremail@yourdomain.com>.gpg-secret-keys.txt

Create full-gnupghomes/ folder inside $VOLATILE

This is the target folder to which we will save snapshots of $GNUPGHOME.

$ mkdir -p $VOLATILE/full-gnupghomes

Save the $GNUPGHOME snapshot

$ cp -a $GNUPGHOME $VOLATILE/full-gnupghomes/master-only

Create subkeys

These will go into the smartcard. They are not being generated directly into the smartcard for back-up purposes.

$ gpg --expert --edit-key $KEYID

Sign

gpg> addkey

Kind: 4 - RSA (sign only) Size: 4032 Expiration: 1y

Encrypt

gpg> addkey

Kind: 6 - RSA (encrypt only) Size: 4032 Expiration: 1y

Authenticate

gpg> addkey

Kind: 8 - RSA (set your own capabilities) Allowed actions: S, E, A, Q Size: 4032 Expiration: 1y

Save

gpg> save

Verify with OpenPGP key checks

$ gpg --list-secret-keys

And make sure you see one sec and three ssb.

Then use automated key best practice checker

$ gpg --export $KEYID | hokey lint

Everything should be green.

Backup subkeys

Export the secret keys

$ gpg --export-secret-keys --armor $KEYID > $GNUPGHOME/exports/<youremail@yourdomain.com>.gpg-secret-keys.txt
$ gpg --export-secret-subkeys --armor $KEYID > $GNUPGHOME/exports/<youremail@yourdomain.com>.gpg-secret-subkeys.txt

Save the $GNUPGHOME snapshot

$ cp -a $GNUPGHOME $VOLATILE/full-gnupghomes/master-and-subkeys

Configure YubiKey as Smartcard

Configure the machine

Make sure pcscd and gpg-agent services are running.

Make sure the device is in OTP/CCID mode

$ ykpersonalize -m82

You may have to remove and re-insert the YubiKey after this step.

Change PINs

Factory defaults are 123456 for normal user and 12345678 for admin user.

$ gpg --card-edit

gpg/card> admin
gpg/card> passwd

Then 3, 1, Q

Set some information

gpg/card> name
Cardholder's surname: <and type in your surname>
Cardholder's given name: <and type in your name>

gpg/card> login
Login data (account name): <youremail@yourdomain.com>

gpg/card> (Press Enter)
  (Review the information)

gpg/card> quit

Move the keys into the card

$ gpg --edit-key $KEYID

gpg> toggle
gpg> key 1
gpg> keytocard
Your selection? 1

gpg> key 1
gpg> key 2
gpg> keytocard
Your selection? 2

gpg> key 2
gpg> key 3
gpg> keytocard
Your selection? 3

gpg> save

Verify that the keys were moved. Now they should be marked as ssd> indicating they are stubs for a smartcard key.

$ gpg --list-secret-keys

Backup subkey stubs

Export the secret keys

$ gpg --export-secret-keys --armor $KEYID > $GNUPGHOME/exports/<youremail@yourdomain.com>.gpg-secret-keys.txt
$ gpg --export-secret-subkeys --armor $KEYID > $GNUPGHOME/exports/<youremail@yourdomain.com>.gpg-secret-subkeys.txt

Export the public key

$ gpg --export --armor $KEYID > $GNUPGHOME/exports/<youremail@yourdomain.com>.gpg-public-key.txt

Save the $GNUPGHOME snapshot

$ cp -a $GNUPGHOME $VOLATILE/full-gnupghomes/master-and-subkeys

Save contents of $VOLATILE to an encrypted USB vault

Mount your encrypted vault to /mnt/vault

$ sudo cryptsetup luksOpen /dev/sdXN vault
$ sudo mkdir /mnt/vault
$ sudo mount /dev/mapper/vault /mnt/vault

Copy the files

$ sudo mkdir /mnt/vault/gpg-backups
$ sudo cp -a $VOLATILE/full-gnupghomes/* /mnt/vault/gpg-backups/<youremail@yourdomain>

Beware of not copying the revoke certificate which we had placed inside $VOLATILE

Umount your encrypted vault

$ sudo umount /mnt/vault
$ sudo cryptsetup luksClose vault

Transfer to (online) daily machine

If using an offline machine

If you were using an offline machine for doing the previous steps (RECOMMENDED), just transfer the public key $GNUPGHOME/volatile-backups/<youremail@yourdomain.com>.gpg-public-key.txt to your daily machine using a different medium than the vault.

If using daily machine

If you weren't using an offline machine (NOT RECOMMENDED), just copy the public key from the volatile location to your home directory, then securely remove the folder; finally unset the GNUPGHOME environment variable.

$ cp $GNUPGHOME/volatile-backups/<youremail@yourdomain.com>.gpg-public-key.txt ~
$ sudo pacman -Syu srm
$ srm -r $GNUPGHOME
$ unset GNUPGHOME

Use keys (from your online/daily machine)

Create a configuration (for GnuPG > 2.1.x)

$ cat << EOF > ~/.gnupg/gpg.conf
auto-key-locate keyserver
keyserver hkps://hkps.pool.sks-keyservers.net
keyserver-options no-honor-keyserver-url
personal-cipher-preferences AES256 AES192 AES CAST5
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-cipher-algo AES256
s2k-digest-algo SHA512
charset utf-8
fixed-list-mode
no-comments
no-emit-version
keyid-format 0xlong
list-options show-uid-validity
verify-options show-uid-validity
with-fingerprint
use-agent
require-cross-certification
EOF

Then import the public key

$ gpg --import < <youremail@yourdomain.com>.gpg-public-key.txt

Optionally upload it to a public keyserver (so it can be imported from other machines from the web)

$ gpg --send-key <youremail@yourdomain.com>

Insert the YubiKey and generate secret key stubs:

$ gpg --card-status

Now it should show the Master key as not available (sec#).

$ gpg --list-secret-keys <youremail@yourdomain.com>

Mark the key as ultimately trusted

$ gpg --edit-key <youremail@yourdomain.com>
gpg> trust
Your decision? 5
gpg> quit

References

Arch Linux ISO for offline GnuPG key generation

Run as root

It is recommended to perform the following steps as root

$ sudo -i

Install Archiso

# sudo pacman -Syu archiso

Configure

Create target location

# mkdir /tmp/archlive

Copy profile

We choose releng in this case.

# cp -r /usr/share/archiso/configs/releng/* /tmp/archlive

Configure packages to install

# cat <<END_OF_LIST >> /tmp/archlive/packages.both
tmux
gnupg
pcsc-tools
ccid
libusb-compat
hopenpgp-tools
yubikey-personalization
END_OF_LIST

Copy the instructions

We're talking about the guide that sits right next to this guide.

# cp archlinux_gnupg_yubikey_guide.md /tmp/archlive/airootfs/root

Build the ISO

Create the out/ directory

# mkdir /tmp/archlive/out

Build it

# cd /tmp/archlive
# ./build.sh -v

Write ISO to bootable media

Write to USB drive

Find the name of the drive

# lsblk

Write the ISO

YYYY.MM.DD = Date when these guide steps are being run. X in sdX = Drive to be used.

# dd bs=4M if=/tmp/archlive/out/archlinux-YYYY.MM.DD-x86_64.iso of=/dev/sdX status=progress && sync

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment