From 6d5211690b0fe3936a9b855c6dcf68fbfd902f2c Mon Sep 17 00:00:00 2001 From: Sun Knudsen Date: Wed, 21 Jul 2021 19:49:22 -0400 Subject: [PATCH] Added first draft of YubiKey PGP guide --- .../README.md | 1182 +++++++++++++++++ 1 file changed, 1182 insertions(+) create mode 100644 how-to-use-yubikey-to-store-pgp-private-keys/README.md diff --git a/how-to-use-yubikey-to-store-pgp-private-keys/README.md b/how-to-use-yubikey-to-store-pgp-private-keys/README.md new file mode 100644 index 0000000..40d91d2 --- /dev/null +++ b/how-to-use-yubikey-to-store-pgp-private-keys/README.md @@ -0,0 +1,1182 @@ + + +# How to use YubiKey to secure PGP private keys + +> Heads-up: guide inspired by https://github.com/drduh/YubiKey-Guide. + +## Requirements + +- [Tails USB flash drive or SD card](../how-to-install-tails-on-usb-flash-drive-or-sd-card-on-macos) with VeraCrypt [installed](../how-to-install-and-use-veracrypt-on-tails) +- YubiKey with [OpenPGP](https://www.yubico.com/us/store/compare/) support (firmware version `5.2.3` or higher) +- Computer running macOS Catalina (should work on Big Sur) + +## Caveats + +- When copy/pasting commands that start with `$`, strip out `$` as this character is not part of the command +- When copy/pasting commands that start with `cat << "EOF"`, select all lines at once (from `cat << "EOF"` to `EOF` inclusively) as they are part of the same (single) command + +## Setup guide (on Tails) + +### Step 1: boot to Tails and set admin password + +> Heads-up: if keyboard layout of computer isn’t “English (US)”, set “Keyboard Layout”. + +Click “+” under ”Additional Settings”, then “Administration Password”, set password, click “Add” and finally “Start Tails”. + +### Step 2: establish network connection using ethernet cable or Wi-Fi and wait for Tor to be ready + +Connected to Tor successfully + +👍 + +### Step 3: import Dennis Fokin’s PGP public key (used to verify downloads below) + +```console +$ gpg --keyserver hkps://keys.openpgp.org --search-keys 9E885C0302F9BB9167529C2D5CBA11E6ADC7BCD1 +gpg: data source: https://keys.openpgp.org:443 +(1) Dennis Fokin + 4096 bit RSA key 0x5CBA11E6ADC7BCD1, created: 2019-09-17 +Keys 1-1 of 1 for "9E885C0302F9BB9167529C2D5CBA11E6ADC7BCD1". Enter number(s), N)ext, or Q)uit > 1 +gpg: key 0x5CBA11E6ADC7BCD1: public key "Dennis Fokin " imported +gpg: Total number processed: 1 +gpg: imported: 1 +``` + +imported: 1 + +👍 + +### Step 4: download [YubiKey Manager](https://www.yubico.com/support/download/yubikey-manager/) AppImage release and associated PGP signature + +```console +$ torsocks curl -L -o ~/Downloads/yubikey-manager-qt.AppImage https://developers.yubico.com/yubikey-manager-qt/Releases/yubikey-manager-qt-latest-linux.AppImage + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 281 100 281 0 0 200 0 0:00:01 0:00:01 --:--:-- 200 +100 81.9M 100 81.9M 0 0 457k 0 0:03:03 0:03:03 --:--:-- 818k + +$ torsocks curl -L -o ~/Downloads/yubikey-manager-qt.AppImage.sig https://developers.yubico.com/yubikey-manager-qt/Releases/yubikey-manager-qt-latest-linux.AppImage.sig + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 285 100 285 0 0 215 0 0:00:01 0:00:01 --:--:-- 215 +100 310 100 310 0 0 184 0 0:00:01 0:00:01 --:--:-- 0 +``` + +### Step 5: verify “YubiKey Manager” AppImage release (learn how [here](../how-to-verify-pgp-digital-signatures-using-gnupg-on-macos)) and make AppImage executable + +```console +$ gpg --verify ~/Downloads/yubikey-manager-qt.AppImage.sig +gpg: assuming signed data in '/home/amnesia/Downloads/yubikey-manager-qt.AppImage' +gpg: Signature made Tue 18 May 2021 07:16:45 AM UTC +gpg: using RSA key D6919FBF48C484F3CB7B71CD870B88256690D8BC +gpg: Good signature from "Dennis Fokin " [unknown] +gpg: WARNING: This key is not certified with a trusted signature! +gpg: There is no indication that the signature belongs to the owner. +Primary key fingerprint: 9E88 5C03 02F9 BB91 6752 9C2D 5CBA 11E6 ADC7 BCD1 + Subkey fingerprint: D691 9FBF 48C4 84F3 CB7B 71CD 870B 8825 6690 D8BC + +$ chmod +x ~/Downloads/yubikey-manager-qt.AppImage +``` + +Good signature + +👍 + +### Step 6 (optional): copy “YubiKey Manager” AppImage to “Persistent” folder (requires Tails “Personal Data” persistence feature to be enabled) + +```shell +cp ~/Downloads/yubikey-manager-qt.AppImage ~/Persistent/ +``` + +### Step 7: extract and patch “YubiKey Manager” AppImage (required to run bundled [ykman](https://support.yubico.com/hc/en-us/articles/360016614940-YubiKey-Manager-CLI-ykman-User-Manual), see [issue](https://github.com/Yubico/yubikey-manager/issues/436) on GitHub) + +> Heads-up: step is not persistent meaning it has to be completed each time one needs to run `ykman` on Tails. + +#### Extract “YubiKey Manager” AppImage + +> Heads-up: replace `Downloads` by `Persistent` if “YubiKey Manager” AppImage has been copied to “Persistent” folder. + +```console +$ cd + +$ ~/Downloads/yubikey-manager-qt.AppImage --appimage-extract +``` + +#### Patch “YubiKey Manager” AppImage + +```console +$ sed -i "s/ykman-gui/ykman/" ~/squashfs-root/AppRun + +$ sed -i -r "s/#\!.*(python[0-9.]+)$/#\!\/home\/amnesia\/squashfs-root\/usr\/bin\/\1/" ~/squashfs-root/usr/bin/ykman +``` + +#### Add and source `ykman` Bash alias + +``` +echo 'alias ykman="/home/amnesia/squashfs-root/AppRun"' >> ~/.bashrc +source ~/.bashrc +``` + +### Step 8: generate master key (used to sign signing, encryption and authentication subkeys) + +When asked for passphrase, create and memorize strong passphrase or use output from `gpg --gen-random --armor 0 24` (and store password in air-gapped password manager). + +```console +$ gpg --expert --full-generate-key +gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc. +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. + +Please select what kind of key you want: + (1) RSA and RSA (default) + (2) DSA and Elgamal + (3) DSA (sign only) + (4) RSA (sign only) + (7) DSA (set your own capabilities) + (8) RSA (set your own capabilities) + (9) ECC and ECC + (10) ECC (sign only) + (11) ECC (set your own capabilities) + (13) Existing key +Your selection? 11 + +Possible actions for a ECDSA/EdDSA key: Sign Certify Authenticate +Current allowed actions: Sign Certify + + (S) Toggle the sign capability + (A) Toggle the authenticate capability + (Q) Finished + +Your selection? S + +Possible actions for a ECDSA/EdDSA key: Sign Certify Authenticate +Current allowed actions: Certify + + (S) Toggle the sign capability + (A) Toggle the authenticate capability + (Q) Finished + +Your selection? Q +Please select which elliptic curve you want: + (1) Curve 25519 + (3) NIST P-256 + (4) NIST P-384 + (5) NIST P-521 + (6) Brainpool P-256 + (7) Brainpool P-384 + (8) Brainpool P-512 + (9) secp256k1 +Your selection? 1 +Please specify how long the key should be valid. + 0 = key does not expire + = key expires in n days + w = key expires in n weeks + m = key expires in n months + y = key expires in n years +Key is valid for? (0) 0 +Key does not expire at all +Is this correct? (y/N) y + +GnuPG needs to construct a user ID to identify your key. + +Real name: John Doe +Email address: john@example.net +Comment: +You selected this USER-ID: + "John Doe " + +Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O +We need to generate a lot of random bytes. It is a good idea to perform +some other action (type on the keyboard, move the mouse, utilize the +disks) during the prime generation; this gives the random number +generator a better chance to gain enough entropy. +gpg: key 0xC2709D13BAB4763C marked as ultimately trusted +gpg: directory '/home/amnesia/.gnupg/openpgp-revocs.d' created +gpg: revocation certificate stored as '/home/amnesia/.gnupg/openpgp-revocs.d/C82270B62BA89271A00A6037C2709D13BAB4763C.rev' +public and secret key created and signed. + +pub ed25519/0xC2709D13BAB4763C 2021-07-21 [C] + Key fingerprint = C822 70B6 2BA8 9271 A00A 6037 C270 9D13 BAB4 763C +uid John Doe +``` + +### Step 9: set master key ID environment variable + +> Heads-up: replace `0xC2709D13BAB4763C` with master key ID. + +```shell +KEY_ID=0xC2709D13BAB4763C +``` + +### Step 10 (optional): sign master key using another master key + +#### Import signing master key (if necessary) + +> Heads-up: replace `/path/to/signing/master.asc` with signing master key path. + +```console +$ gpg --import /path/to/signing/master.asc +gpg: key 0xDFCECB410CE8A745: public key "John Doe " imported +gpg: key 0xDFCECB410CE8A745: secret key imported +gpg: Total number processed: 1 +gpg: imported: 1 +gpg: secret keys read: 1 +gpg: secret keys imported: 1 +``` + +#### Sign master key + +> Heads-up: replace `0xDFCECB410CE8A745` with signing master key ID. + +```console +$ gpg --ask-cert-level --default-key 0xDFCECB410CE8A745 --sign-key $KEY_ID + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: ultimate validity: ultimate +[ultimate] (1). John Doe + +gpg: using "0xDFCECB410CE8A745" as default secret key for signing + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: ultimate validity: ultimate + Primary key fingerprint: C822 70B6 2BA8 9271 A00A 6037 C270 9D13 BAB4 763C + + John Doe + +How carefully have you verified the key you are about to sign actually belongs +to the person named above? If you don't know what to answer, enter "0". + + (0) I will not answer. (default) + (1) I have not checked at all. + (2) I have done casual checking. + (3) I have done very careful checking. + +Your selection? (enter '?' for more information): 3 +Are you sure that you want to sign this key with your +key "John Doe " (0xDFCECB410CE8A745) + +I have checked this key very carefully. + +Really sign? (y/N) y +``` + +### Step 11: create signing, encryption and authentication subkeys + +```console +$ gpg --expert --edit-key $KEY_ID +gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc. +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/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: ultimate validity: ultimate +[ultimate] (1). John Doe + +gpg> addkey +Please select what kind of key you want: + (3) DSA (sign only) + (4) RSA (sign only) + (5) Elgamal (encrypt only) + (6) RSA (encrypt only) + (7) DSA (set your own capabilities) + (8) RSA (set your own capabilities) + (10) ECC (sign only) + (11) ECC (set your own capabilities) + (12) ECC (encrypt only) + (13) Existing key +Your selection? 10 +Please select which elliptic curve you want: + (1) Curve 25519 + (3) NIST P-256 + (4) NIST P-384 + (5) NIST P-521 + (6) Brainpool P-256 + (7) Brainpool P-384 + (8) Brainpool P-512 + (9) secp256k1 +Your selection? 1 +Please specify how long the key should be valid. + 0 = key does not expire + = key expires in n days + w = key expires in n weeks + m = key expires in n months + y = key expires in n years +Key is valid for? (0) 1y +Key expires at Thu 21 Jul 2022 03:21:04 PM UTC +Is this correct? (y/N) y +Really create? (y/N) y +We need to generate a lot of random bytes. It is a good idea to perform +some other action (type on the keyboard, move the mouse, utilize the +disks) during the prime generation; this gives the random number +generator a better chance to gain enough entropy. + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: ultimate validity: ultimate +ssb ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +[ultimate] (1). John Doe + +gpg> addkey +Please select what kind of key you want: + (3) DSA (sign only) + (4) RSA (sign only) + (5) Elgamal (encrypt only) + (6) RSA (encrypt only) + (7) DSA (set your own capabilities) + (8) RSA (set your own capabilities) + (10) ECC (sign only) + (11) ECC (set your own capabilities) + (12) ECC (encrypt only) + (13) Existing key +Your selection? 12 +Please select which elliptic curve you want: + (1) Curve 25519 + (3) NIST P-256 + (4) NIST P-384 + (5) NIST P-521 + (6) Brainpool P-256 + (7) Brainpool P-384 + (8) Brainpool P-512 + (9) secp256k1 +Your selection? 1 +Please specify how long the key should be valid. + 0 = key does not expire + = key expires in n days + w = key expires in n weeks + m = key expires in n months + y = key expires in n years +Key is valid for? (0) 1y +Key expires at Thu 21 Jul 2022 03:21:25 PM UTC +Is this correct? (y/N) y +Really create? (y/N) y +We need to generate a lot of random bytes. It is a good idea to perform +some other action (type on the keyboard, move the mouse, utilize the +disks) during the prime generation; this gives the random number +generator a better chance to gain enough entropy. + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: ultimate validity: ultimate +ssb ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +[ultimate] (1). John Doe + +gpg> addkey +Please select what kind of key you want: + (3) DSA (sign only) + (4) RSA (sign only) + (5) Elgamal (encrypt only) + (6) RSA (encrypt only) + (7) DSA (set your own capabilities) + (8) RSA (set your own capabilities) + (10) ECC (sign only) + (11) ECC (set your own capabilities) + (12) ECC (encrypt only) + (13) Existing key +Your selection? 11 + +Possible actions for a ECDSA/EdDSA key: Sign Authenticate +Current allowed actions: Sign + + (S) Toggle the sign capability + (A) Toggle the authenticate capability + (Q) Finished + +Your selection? S + +Possible actions for a ECDSA/EdDSA key: Sign Authenticate +Current allowed actions: + + (S) Toggle the sign capability + (A) Toggle the authenticate capability + (Q) Finished + +Your selection? A + +Possible actions for a ECDSA/EdDSA key: Sign Authenticate +Current allowed actions: Authenticate + + (S) Toggle the sign capability + (A) Toggle the authenticate capability + (Q) Finished + +Your selection? Q +Please select which elliptic curve you want: + (1) Curve 25519 + (3) NIST P-256 + (4) NIST P-384 + (5) NIST P-521 + (6) Brainpool P-256 + (7) Brainpool P-384 + (8) Brainpool P-512 + (9) secp256k1 +Your selection? 1 +Please specify how long the key should be valid. + 0 = key does not expire + = key expires in n days + w = key expires in n weeks + m = key expires in n months + y = key expires in n years +Key is valid for? (0) 1y +Key expires at Thu 21 Jul 2022 03:21:53 PM UTC +Is this correct? (y/N) y +Really create? (y/N) y +We need to generate a lot of random bytes. It is a good idea to perform +some other action (type on the keyboard, move the mouse, utilize the +disks) during the prime generation; this gives the random number +generator a better chance to gain enough entropy. + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: ultimate validity: ultimate +ssb ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +ssb ed25519/0x1E7B69B238FFA21B + created: 2021-07-21 expires: 2022-07-21 usage: A +[ultimate] (1). John Doe + +gpg> save +``` + +### Step 12: mount backup volume (formatted using exFAT) + +Click “Places”, then “Home”, then backup volume (“Samsung BAR” in example bellow), enter admin password and finally click “Authenticate”. + +### Step 13: set backup volume name environment variable + +```shell +VOLUME_NAME="Samsung BAR" +``` + +### Step 14: create VeraCrypt encrypted volume (used to store master key and subkeys) + +```console +$ /home/amnesia/Persistent/veracrypt --text --create "/media/amnesia/$VOLUME_NAME/tails" +Volume type: + 1) Normal + 2) Hidden +Select [1]: 1 + +Enter volume size (sizeK/size[M]/sizeG): 10M + +Encryption Algorithm: + 1) AES + 2) Serpent + 3) Twofish + 4) Camellia + 5) Kuznyechik + 6) AES(Twofish) + 7) AES(Twofish(Serpent)) + 8) Camellia(Kuznyechik) + 9) Camellia(Serpent) + 10) Kuznyechik(AES) + 11) Kuznyechik(Serpent(Camellia)) + 12) Kuznyechik(Twofish) + 13) Serpent(AES) + 14) Serpent(Twofish(AES)) + 15) Twofish(Serpent) +Select [1]: 7 + +Hash algorithm: + 1) SHA-512 + 2) Whirlpool + 3) SHA-256 + 4) Streebog +Select [1]: 1 + +Filesystem: + 1) None + 2) FAT + 3) Linux Ext2 + 4) Linux Ext3 + 5) Linux Ext4 + 6) NTFS + 7) exFAT + 8) Btrfs +Select [2]: 2 + +Enter password: +Re-enter password: + +Enter PIM: + +Enter keyfile path [none]: + +Please type at least 320 randomly chosen characters and then press Enter: + + +Done: 100.000% Speed: 2.7 MiB/s Left: 0 s + +The VeraCrypt volume has been successfully created. +``` + +The VeraCrypt volume has been successfully created. + +👍 + +### Step 15: mount VeraCrypt encrypted volume + +Click “Applications”, then “Utilities”, then “Unlock VeraCrypt Volumes”, then “Add”, select “tails” file on backup volume, click “Open”, enter password and finally click “Unlock”. + +### Step 16: rename VeraCrypt encrypted volume + +> Heads-up: ignore dirty bit is set error. + +```console +$ sudo fatlabel /dev/mapper/tcrypt-1794 Tails + +We trust you have received the usual lecture from the local System +Administrator. It usually boils down to these three things: + + #1) Respect the privacy of others. + #2) Think before you type. + #3) With great power comes great responsibility. + +[sudo] password for amnesia: +fatlabel: warning - lowercase labels might not work properly with DOS or Windows +0x25: Dirty bit is set. Fs was not properly unmounted and some data may be corrupt. + Automatically removing dirty bit. +``` + +### Step 17: set VeraCrypt encrypted volume name environment variable + +> Heads-up: find name using output of `ls /media/amnesia`. + +```console +$ ls /media/amnesia +3FDC-B4EB LaCie 'Samsung BAR' + +$ ENCRYPTED_VOLUME_NAME="3FDC-B4EB" +``` + +### Step 18: export master key, subkeys and public key to VeraCrypt encrypted volume + +```console +$ gpg --armor --export-secret-keys $KEY_ID > /media/amnesia/$ENCRYPTED_VOLUME_NAME/master.asc + +$ gpg --armor --export-secret-subkeys $KEY_ID > /media/amnesia/$ENCRYPTED_VOLUME_NAME/sub.asc + +$ gpg --armor --export $KEY_ID > /media/amnesia/$ENCRYPTED_VOLUME_NAME/pub.asc +``` + +### Step 19: copy public key to backup volume + +> Heads-up: replace `johndoe` with name associated to master key. + +```shell +cp /media/amnesia/$ENCRYPTED_VOLUME_NAME/pub.asc "/media/amnesia/$VOLUME_NAME/johndoe.asc" +``` + +### Step 20: dismount VeraCrypt encrypted volume + +Click “Applications”, then “Utilities”, then “Unlock VeraCrypt Volumes” and finally click “x”. + +### Step 21: back up `tails` file + +> Heads-up: files stored in `tails` include private keys which, if lost, results in loosing one’s cryptographic identity (safeguard backup mindfully). + +> Heads-up: never unlock `tails` on macOS (or any other computer that isn’t air-gapped and hardened). + +### Step 22: insert and provision YubiKey + +> Heads-up: default user PIN is `123456` and default admin PIN is `12345678`. + +```console +$ gpg --card-edit + +Reader ...........: 1050:0404:X:0 +Application ID ...: D******************************* +Version ..........: 3.4 +Manufacturer .....: Yubico +Serial number ....: 1******* +Name of cardholder: [not set] +Language prefs ...: [not set] +Sex ..............: unspecified +URL of public key : [not set] +Login data .......: [not set] +Signature PIN ....: not forced +Key attributes ...: rsa2048 rsa2048 rsa2048 +Max. PIN lengths .: 127 127 127 +PIN retry counter : 3 0 3 +Signature counter : 0 +KDF setting ......: on +Signature key ....: [none] +Encryption key....: [none] +Authentication key: [none] +General key info..: [none] + +gpg/card> admin +Admin commands are allowed + +gpg/card> passwd +gpg: OpenPGP card no. D******************************* detected + +1 - change PIN +2 - unblock PIN +3 - change Admin PIN +4 - set the Reset Code +Q - quit + +Your selection? 1 +PIN changed. + +1 - change PIN +2 - unblock PIN +3 - change Admin PIN +4 - set the Reset Code +Q - quit + +Your selection? 3 +PIN changed. + +1 - change PIN +2 - unblock PIN +3 - change Admin PIN +4 - set the Reset Code +Q - quit + +Your selection? Q + +gpg/card> name +Cardholder's surname: Doe +Cardholder's given name: John + +gpg/card> lang +Language preferences: en + +gpg/card> login +Login data (account name): john@example.net + +gpg/card> list + +Reader ...........: 1050:0404:X:0 +Application ID ...: D******************************* +Version ..........: 3.4 +Manufacturer .....: Yubico +Serial number ....: 1******* +Name of cardholder: John Doe +Language prefs ...: en +Sex ..............: unspecified +URL of public key : [not set] +Login data .......: john@example.net +Signature PIN ....: not forced +Key attributes ...: rsa2048 rsa2048 rsa2048 +Max. PIN lengths .: 127 127 127 +PIN retry counter : 3 0 3 +Signature counter : 0 +KDF setting ......: on +Signature key ....: [none] +Encryption key....: [none] +Authentication key: [none] +General key info..: [none] + +gpg/card> quit +``` + +### Step 23: move signing, encryption and authentication subkeys to YubiKey + +```console +$ gpg --edit-key $KEY_ID +gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc. +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/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: ultimate validity: ultimate +ssb ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +ssb ed25519/0x1E7B69B238FFA21B + created: 2021-07-21 expires: 2022-07-21 usage: A +[ultimate] (1). John Doe + +gpg> key 1 + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: ultimate validity: ultimate +ssb* ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +ssb ed25519/0x1E7B69B238FFA21B + created: 2021-07-21 expires: 2022-07-21 usage: A +[ultimate] (1). John Doe + +gpg> keytocard +Please select where to store the key: + (1) Signature key + (3) Authentication key +Your selection? 1 + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: ultimate validity: ultimate +ssb* ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +ssb ed25519/0x1E7B69B238FFA21B + created: 2021-07-21 expires: 2022-07-21 usage: A +[ultimate] (1). John Doe + +gpg> key 1 + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: ultimate validity: ultimate +ssb ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +ssb ed25519/0x1E7B69B238FFA21B + created: 2021-07-21 expires: 2022-07-21 usage: A +[ultimate] (1). John Doe + +gpg> key 2 + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: ultimate validity: ultimate +ssb ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb* cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +ssb ed25519/0x1E7B69B238FFA21B + created: 2021-07-21 expires: 2022-07-21 usage: A +[ultimate] (1). John Doe + +gpg> keytocard +Please select where to store the key: + (2) Encryption key +Your selection? 2 + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: ultimate validity: ultimate +ssb ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb* cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +ssb ed25519/0x1E7B69B238FFA21B + created: 2021-07-21 expires: 2022-07-21 usage: A +[ultimate] (1). John Doe + +gpg> key 2 + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: ultimate validity: ultimate +ssb ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +ssb ed25519/0x1E7B69B238FFA21B + created: 2021-07-21 expires: 2022-07-21 usage: A +[ultimate] (1). John Doe + +gpg> key 3 + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: ultimate validity: ultimate +ssb ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +ssb* ed25519/0x1E7B69B238FFA21B + created: 2021-07-21 expires: 2022-07-21 usage: A +[ultimate] (1). John Doe + +gpg> keytocard +Please select where to store the key: + (3) Authentication key +Your selection? 3 + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: ultimate validity: ultimate +ssb ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +ssb* ed25519/0x1E7B69B238FFA21B + created: 2021-07-21 expires: 2022-07-21 usage: A +[ultimate] (1). John Doe + +gpg> save +``` + +### Step 24: require YubiKey user interaction for signing, encryption and authentication operations + +```console +$ ykman openpgp keys set-touch sig on --force +Enter Admin PIN: + +$ ykman openpgp keys set-touch enc on --force +Enter Admin PIN: + +$ ykman openpgp keys set-touch aut on --force +Enter Admin PIN: +``` + +### Step 25 (optional): disable all YubiKey interfaces except for OpenPGP over USB + +> Heads-up: increase `sleep` delay if “Error: No YubiKey detected!” error is thrown. + +```console +$ ykman config usb --enable OPENPGP --force + +$ for interface in FIDO2 HSMAUTH OATH OTP PIV U2F; do ykman config usb --disable $interface --force; sleep 3; done + +$ ykman config nfc --disable-all --force +``` + +### Step 26 (optional): enable YubiKey configuration lock + +> Heads-up: configuration lock prevents configuring YubiKey without entering lock code (store lock code in air-gapped password manager). + +```console +$ ykman config set-lock-code --generate +Using a randomly generated lock code: cce9181f4a97bac00459419986510d40 +Lock configuration with this lock code? [y/N]: y +``` + +### Step 27 (optional): extend expiry date of signing, encryption and authentication subkeys (required once a year) + +#### Mount backup volume (formatted using exFAT) + +Click “Places”, then “Home”, then backup volume (“Samsung BAR” in example bellow), enter admin password and finally click “Authenticate”. + +#### Mount VeraCrypt encrypted volume + +Click “Applications”, then “Utilities”, then “Unlock VeraCrypt Volumes”, then “Add”, select “tails” file on backup volume, click “Open”, enter password and finally click “Unlock”. + +#### Import master key + +```console +$ gpg --import /media/amnesia/Tails/master.asc +gpg: key 0xC2709D13BAB4763C: 1 signature not checked due to a missing key +gpg: key 0xC2709D13BAB4763C: public key "John Doe " imported +gpg: key 0xC2709D13BAB4763C: secret key imported +gpg: Total number processed: 1 +gpg: imported: 1 +gpg: secret keys read: 1 +gpg: secret keys imported: 1 +gpg: no ultimately trusted keys found +``` + +#### Set master key ID environment variable + +```shell +KEY_ID=0xC2709D13BAB4763C +``` + +#### Extend expiry date of signing, encryption and authentication subkeys + +```console +$ gpg --edit-key $KEY_ID +gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc. +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/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: unknown validity: unknown +ssb ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +ssb ed25519/0x1E7B69B238FFA21B + created: 2021-07-21 expires: 2022-07-21 usage: A +[ unknown] (1). John Doe + +gpg> key 1 + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: unknown validity: unknown +ssb* ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +ssb ed25519/0x1E7B69B238FFA21B + created: 2021-07-21 expires: 2022-07-21 usage: A +[ unknown] (1). John Doe + +gpg> key 2 + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: unknown validity: unknown +ssb* ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb* cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +ssb ed25519/0x1E7B69B238FFA21B + created: 2021-07-21 expires: 2022-07-21 usage: A +[ unknown] (1). John Doe + +gpg> key 3 + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: unknown validity: unknown +ssb* ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb* cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +ssb* ed25519/0x1E7B69B238FFA21B + created: 2021-07-21 expires: 2022-07-21 usage: A +[ unknown] (1). John Doe + +gpg> expire +Are you sure you want to change the expiration time for multiple subkeys? (y/N) y +Please specify how long the key should be valid. + 0 = key does not expire + = key expires in n days + w = key expires in n weeks + m = key expires in n months + y = key expires in n years +Key is valid for? (0) 1y +Key expires at Thu 21 Jul 2022 03:32:11 PM UTC +Is this correct? (y/N) y + +sec ed25519/0xC2709D13BAB4763C + created: 2021-07-21 expires: never usage: C + trust: unknown validity: unknown +ssb* ed25519/0x02EDC61B6543509B + created: 2021-07-21 expires: 2022-07-21 usage: S +ssb* cv25519/0xD4634E0D6E2DD8BF + created: 2021-07-21 expires: 2022-07-21 usage: E +ssb* ed25519/0x1E7B69B238FFA21B + created: 2021-07-21 expires: 2022-07-21 usage: A +[ unknown] (1). John Doe + +gpg> save +``` + +#### Export public key to VeraCrypt encrypted volume + +```console +$ gpg --armor --export $KEY_ID > /media/amnesia/Tails/pub.asc +``` + +#### Copy public key to backup volume + +> Heads-up: replace `Samsung BAR` with backup volume name and `johndoe` with name associated to master key. + +```shell +cp /media/amnesia/Tails/pub.asc "/media/amnesia/Samsung BAR/johndoe.asc" +``` + +#### Dismount VeraCrypt encrypted volume + +Click “Applications”, then “Utilities”, then “Unlock VeraCrypt Volumes” and finally click “x”. + +### Step 28: shutdown computer + +👍 + +## Usage guide (on macOS) + +### Step 1: install [Homebrew](https://brew.sh/) + +```shell +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" +``` + +### Step 2: disable Homebrew analytics + +```shell +brew analytics off +``` + +### Step 3: install [GnuPG](https://gnupg.org/) and [pinentry-mac](https://github.com/GPGTools/pinentry) + +```shell +brew install gnupg pinentry-mac +``` + +### Step 4: import public key + +> Heads-up: replace `Samsung BAR` with backup volume name and `johndoe` with name associated to master key. + +```console +$ gpg --keyid-format 0xlong --import "/Volumes/Samsung BAR/johndoe.asc" +gpg: directory '/Users/sunknudsen/.gnupg' created +gpg: keybox '/Users/sunknudsen/.gnupg/pubring.kbx' created +gpg: key 0xC2709D13BAB4763C: 1 signature not checked due to a missing key +gpg: /Users/sunknudsen/.gnupg/trustdb.gpg: trustdb created +gpg: key 0xC2709D13BAB4763C: public key "John Doe " imported +gpg: Total number processed: 1 +gpg: imported: 1 +gpg: no ultimately trusted keys found +``` + +### Step 5: set master key ID environment variable + +> Heads-up: replace `0xC2709D13BAB4763C` with master key ID. + +```shell +KEY_ID=0xC2709D13BAB4763C +``` + +### Step 6: configure GnuPG + +#### Create or override `dirmngr.conf` + +Heads-up: back up current config using `cp ~/.gnupg/dirmngr.conf ~/.gnupg/dirmngr.conf.backup` (if necessary). + +```shell +cat << "EOF" > ~/.gnupg/dirmngr.conf +disable-ipv6 +keyserver hkps://keys.openpgp.org +EOF +``` + +#### Create or override `gpg.conf` + +Heads-up: back up current config using `cp ~/.gnupg/gpg.conf ~/.gnupg/gpg.conf.backup` (if necessary). + +```shell +cat << EOF > ~/.gnupg/gpg.conf +cert-digest-algo SHA512 +charset utf-8 +default-key $KEY_ID +default-preference-list SHA512 SHA384 SHA256 AES256 AES192 AES ZLIB BZIP2 ZIP Uncompressed +fixed-list-mode +keyid-format 0xlong +keyserver hkps://keys.openpgp.org +list-options show-uid-validity +no-comments +no-emit-version +no-symkey-cache +personal-cipher-preferences AES256 AES192 AES +personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed +personal-digest-preferences SHA512 SHA384 SHA256 +require-cross-certification +s2k-cipher-algo AES256 +s2k-digest-algo SHA512 +throw-keyids +use-agent +verify-options show-uid-validity +with-fingerprint +EOF +``` + +#### Back up and overwrite `gpg-agent.conf` + +Heads-up: back up current config using `cp ~/.gnupg/gpg-agent.conf ~/.gnupg/gpg-agent.conf.backup` (if necessary). + +```shell +cat << "EOF" > ~/.gnupg/gpg-agent.conf +default-cache-ttl 60 +default-cache-ttl-ssh 60 +enable-ssh-support +max-cache-ttl 120 +max-cache-ttl-ssh 120 +pinentry-program /usr/local/bin/pinentry-mac +EOF +``` + +### Step 7: configure shell + +> Heads-up: run `echo $SHELL` to find default shell. + +#### Bash (`/bin/bash`) + +```shell +cat << "EOF" >> ~/.bashrc +export GPG_TTY="$(tty)" +export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) +gpgconf --launch gpg-agent +gpg-connect-agent UPDATESTARTUPTTY /bye > /dev/null +EOF +source ~/.bashrc +``` + +#### Z Shell (`/bin/zsh`) + +```shell +cat << "EOF" >> ~/.zshrc +export GPG_TTY="$(tty)" +export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) +gpgconf --launch gpg-agent +gpg-connect-agent UPDATESTARTUPTTY /bye > /dev/null +EOF +source ~/.zshrc +``` + +### Step 8: insert YubiKey and generate SSH public key + +> Heads-up: replace `john@example.net` with email and `johndoe` with name associated to master key. + +```console +$ mkdir -p ~/.ssh + +$ ssh-add -L | awk '{print $1 " " $2 " john@example.net"}' | tee ~/.ssh/johndoe.pub +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ62kuKCXcufbvQeXS8h5D6PW233AMBXHzKpXO0EhmJ6 john@example.net +``` + +ssh-ed25519 AAAAC3Nz… john@example.net + +👍 + +### Step 9: reload `gpg-agent` (required to enable `pinentry-mac`) + +```console +$ gpgconf --kill gpg-agent + +$ gpgconf --launch gpg-agent + +$ gpg-connect-agent UPDATESTARTUPTTY /bye +OK +``` + +OK + +👍 + +### Step 10 (optional): enable Git [signing](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work) + +```shell +git config --global commit.gpgsign true +git config --global gpg.program $(which gpg) +git config --global user.signingkey $KEY_ID +``` + +### Step 11 (optional): publish public key to hkps://keys.openpgp.org + +```console +$ gpg --send-keys $KEY_ID +gpg: sending key 0xC2709D13BAB4763C to hkps://keys.openpgp.org +``` + +gpg: sending key 0xC2709D13BAB4763C to hkps://keys.openpgp.org + +👍