Store OpenPGP keys on a YubiKey
This article is the second of a serie dealing with privacy on the Internet. I strongly recommend that you do the first part of this serie of articles (if you haven’t already done so) otherwise you will have a hard time following it. Technically it is not impossible but throughout these articles, the keys used will be the same (among others) and if you don’t have the same structure, it will be a real headache.
By following this part you will configure a YubiKey as a smart card for storing GPG encryption, signing and authentication keys. Keys stored on YubiKey are non-exportable (as opposed to file-based keys that are stored on disk) and are convenient for everyday use. Instead of having to remember and enter passphrases to unlock SSH/GPG keys, YubiKey only needs a physical touch (or not) after being unlocked with a PIN. All signing and encryption operations happen on the card, rather than in OS memory.
Information and requirements
These elements are to be taken into consideration to follow this article:
- Tools are installed and executed on Arch Linux.
- The network has been disabled for obvious security reasons.
Purchase
Buy a key that fits your requirement in terms of size, interface (USB-A, USB-C, NFC…). I bought the YubiKey 5 NFC.
Check that your key is genuine
To verify a YubiKey is genuine, open a browser with U2F support and move to the YubiKey verification page. Insert your security key, click Verify Device
and follow the instructions. If you see Verification Complete
, your device is authentic!
This website verifies YubiKey device attestation certificates has been signed by a set of Yubico certificate authorities, and helps mitigate supply chain attacks.
Configure smart card
Plug in a YubiKey and use GPG to configure it as a smartcard.
gpg --card-edit
Reader ...........: 1050:0407:X:0
Application ID ...: D2760001240103040006120735540000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
[...]
If the card is locked
The card is locked when entering the wrong PIN and Admin PIN multiple times. So you must reset and set up again using the encrypted backup.
First option
Copy the following script into a file named reset.hex
.
/hex
scd serialno
scd apdu 00 20 00 81 08 40 40 40 40 40 40 40 40
scd apdu 00 20 00 81 08 40 40 40 40 40 40 40 40
scd apdu 00 20 00 81 08 40 40 40 40 40 40 40 40
scd apdu 00 20 00 81 08 40 40 40 40 40 40 40 40
scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40
scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40
scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40
scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40
scd apdu 00 e6 00 00
scd apdu 00 44 00 00
/echo Card has been successfully reset.
Run gpg-connect-agent --run reset.hex
to lock and terminate the card. Then re-insert YubiKey to reset.
Second option
Use ykman
. It’s Python library and command-line tool for configuring a YubiKey over an USB connection.
yay -S yubikey-manager
sudo systemctl start pcscd
ykman openpgp reset
WARNING! This will delete all stored OpenPGP keys and data and restore factory settings? [y/N]: y
Resetting OpenPGP data, don't remove your YubiKey...
Success! All data has been cleared and default PINs are set.
PIN: 123456
Reset code: NOT SET
Admin PIN: 12345678
These two procedures are available here.
PINs
The default PIN is 123456
and default Admin PIN (PUK) is 12345678
. Chip Card Interface Device (CCID) PINs can be up to 127 ASCII characters. They must contain at least 6 (PIN) or 8 (PUK) ASCII characters.
The Admin PIN is required for some card operations and to unblock a PIN that has been entered incorrectly more than three times. See the GnuPG documentation on Managing PINs for details.
gpg --card-edit
gpg/card> admin
Admin commands are allowed
gpg/card> passwd
gpg: OpenPGP card no. D2760001240103040006120735540000 detected
Admin PIN (PUK)
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
Your selection? 3
PIN changed.
PIN
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? Q
Set information
You can add some attributes to your smart card.
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.doe@example.com
gpg/card> list
Reader ...........: 1050:0407:X:0
Application ID ...: D2760001240103040006120735540000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Name of cardholder: John Doe
Language prefs ...: en
Login data .......: john.doe@example.com
[...]
gpg/card> quit
Touch feature
If your YubiKey has the touch functionnality (the YubiKey 5 NFC has it), you can configure it to request a touch to validate a process (signature, encryption and authentication). This functionnality adds extra physical security.
List actual configuration
ykman openpgp info
OpenPGP version: 3.4
Application version: 5.2.4
PIN tries remaining: 3
Reset code tries remaining: 0
Admin PIN tries remaining: 3
Touch policies
Signature key Off
Encryption key Off
Authentication key Off
Attestation key Off
As you can see inside the Touch policies
section, all touch features are disabled (Off
).
Enable signature touch
If you enable this feature, when you are about to sign something, you will need to touch the YubiKey to complete the signing process.
ykman openpgp keys set-touch SIG On
Enter admin PIN:
Set touch policy of signature key to on? [y/N]: y
Enable encryption touch
If you enable this feature, when you are about to encrypt something, you will need to touch the YubiKey to complete the encryption process.
ykman openpgp keys set-touch ENC On
Enter admin PIN:
Set touch policy of encryption key to on? [y/N]: y
Enable authentication touch
If you enable this feature, when you are about to authenticate, you will need to touch the YubiKey to complete the authentication process.
ykman openpgp keys set-touch AUT On
Enter admin PIN:
Set touch policy of authentication key to on? [y/N]: y
Additional notes
Previously, we set touch policy to ON
but available options are: Off
, On
, Fixed
, Cached
and Cached-Fixed
. In accordance with the documentation, here is the explanation of these different policies:
Off
: no touch required.On
: touch required.Fixed
: touch required and can’t be disabled without a full reset.Cached
: touch required and cached for 15 seconds after use.Cached-Fixed
: touch required, cached for 15 seconds after use and can’t be disabled without a full reset.
Modify this option according to your needs.
Transfer keys
Transferring keys to YubiKey using keytocard
is a destructive, one-way operation only. Make sure you’ve made a backup before proceeding: keytocard
converts the local on-disk key into a stub, which means the on-disk copy is no longer usable to transfer to subsequent security key devices or mint additional keys.
gpg --edit-key $KEYID
Secret key is available.
sec ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
ssb cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
ssb ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ultimate] (1). John Doe <john.doe@example.com>
Signing subkey
You will be prompted for the master key passphrase and Admin PIN. Select and transfer the signature key.
gpg> key 1
sec ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: ultimate validity: ultimate
ssb* ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
ssb cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
ssb ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ultimate] (1). John Doe <john.doe@example.com>
gpg> keytocard
Please select where to store the key:
(1) Signature key
(3) Authentication key
Your selection? 1
sec ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: ultimate validity: ultimate
ssb* ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
ssb cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
ssb ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ultimate] (1). John Doe <john.doe@example.com>
Encrypting subkey
Type key 1
again to de-select and key 2
to select the next key.
gpg> key 1
sec ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
ssb cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
ssb ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ultimate] (1). John Doe <john.doe@example.com>
gpg> key 2
sec ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
ssb* cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
ssb ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ultimate] (1). John Doe <john.doe@example.com>
gpg> keytocard
Please select where to store the key:
(2) Encryption key
Your selection? 2
sec ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
ssb* cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
ssb ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ultimate] (1). John Doe <john.doe@example.com>
Authenticating subkey
Type key 2
again to deselect and key 3
to select the last key.
gpg> key 2
sec ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
ssb cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
ssb ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ultimate] (1). John Doe <john.doe@example.com>
gpg> key 3
sec ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
ssb cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
ssb* ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ultimate] (1). John Doe <john.doe@example.com>
gpg> keytocard
Please select where to store the key:
(3) Authentication key
Your selection? 3
sec ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
ssb cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
ssb* ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ultimate] (1). John Doe <john.doe@example.com>
Save and quit
gpg> save
Verify smart card
Verify the subkeys have been moved to YubiKey as indicated by ssb>
.
gpg -K
/tmp/tmp.EOmP2zbviM/pubring.kbx
-------------------------------
sec ed25519/0xB52326F13324098C 2020-10-11 [C]
Key fingerprint = 0ED8 F486 1E57 693E C1E3 4EBE B523 26F1 3324 098C
uid [ultimate] John Doe <john.doe@example.com>
ssb> ed25519/0x9B76AA52AF00EFEF 2020-10-11 [S] [expires: 2021-10-11]
ssb> cv25519/0xE3AC01686E511A38 2020-10-11 [E] [expires: 2021-10-11]
ssb> ed25519/0x2BA042FD767F18C1 2020-10-11 [A] [expires: 2021-10-11]
Multiple YubiKeys (optional)
To provision additional security keys, restore the master key backup and repeat the Configure smart card
procedure.
mv -vi $GNUPGHOME $GNUPGHOME.1
renamed '/tmp/tmp.EOmP2zbviM' -> '/tmp/tmp.EOmP2zbviM.1'
cp -aiv /mnt/encrypted-storage/tmp.EOmP2zbviM/ $GNUPGHOME
'/mnt/encrypted-storage/tmp.EOmP2zbviM' -> '/tmp/tmp.EOmP2zbviM'
Cleanup
Make sure you have:
- Saved encryption, signing and authentication subkeys to YubiKey (
gpg -K
should showssb>
for subkeys). - Saved the YubiKey user and admin PINs which you changed from defaults.
- Saved the password to the GPG master key.
- Saved a copy of the master key, subkeys and revocation certificate on an encrypted volume, to be stored offline.
- Saved the password to that encrypted volume in a separate location.
- Saved a copy of the public key somewhere easily accessible for later.
Reboot or securely delete (via srm
) $GNUPGHOME
and remove the secret keys from the GPG keyring.
yay -S srm
srm -r $GNUPGHOME || rm -rf $GNUPGHOME
gpg --delete-secret-key $KEYID
set -e KEYID
Close the terminal used to generate things. This action will erase the environment variables we have created. Finally, make sure you have securely erased all generated keys and revocation certificates if an ephemeral enviroment was not used.
Using keys
Strengthen the configuration
Copy the following snippet into ~/.gnupg/gpg.conf
.
personal-cipher-preferences AES256 AES192 AES
personal-digest-preferences SHA512 SHA384 SHA256
personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed
default-preference-list SHA512 SHA384 SHA256 AES256 AES192 AES 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
no-greeting
keyid-format 0xlong
list-options show-uid-validity
verify-options show-uid-validity
with-fingerprint
require-cross-certification
no-symkey-cache
throw-keyids
Set the correction permission
chmod 600 ~/.gnupg/gpg.conf
Install required tool
yay -S gnupg
Mount the non-encrypted volume created earlier
sudo mount /dev/sda2 /mnt/public/
Import the public key
gpg --import /mnt/public/gpg-0xB52326F13324098C-2020-10-11.key
gpg: key 0xB52326F13324098C: public key "John Doe <john.doe@example.com>" imported
gpg: Total number processed: 1
gpg: imported: 1
Trust the key
set KEYID 0xB52326F13324098C
Edit the master key to assign it ultimate trust by selecting trust
and 5
.
gpg --edit-key $KEYID
pub ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: unknown validity: unknown
sub ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
sub cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
sub ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ unknown] (1). John Doe <john.doe@example.com>
gpg> trust
pub ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: unknown validity: unknown
sub ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
sub cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
sub ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ unknown] (1). John Doe <john.doe@example.com>
Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)
1 = I don't know or won't say
2 = I do NOT trust
3 = I trust marginally
4 = I trust fully
5 = I trust ultimately
m = back to the main menu
Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y
pub ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: ultimate validity: unknown
sub ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
sub cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
sub ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ unknown] (1). John Doe <john.doe@example.com>
Please note that the shown key validity is not necessarily correct
unless you restart the program.
gpg> save
Remove and re-insert YubiKey and check the status (some information has been removed).
gpg --card-status
Reader ...........: 1050:0407:X:0
Application ID ...: D2760001240103040006120735540000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Name of cardholder: John Doe
Language prefs ...: en
Login data .......: john.doe@example.com
Key attributes ...: ed25519 cv25519 ed25519
Signature key ....: 49B1 F362 745A AEB6 5EEF 5E71 9B76 AA52 AF00 EFEF
created ....: 2020-10-11 13:34:13
Encryption key....: 7BC2 2D5E 82CB A5B8 965A FF86 E3AC 0168 6E51 1A38
created ....: 2020-10-11 13:35:38
Authentication key: 7296 3EBE 99CD 050F 936C 1E4E 2BA0 42FD 767F 18C1
created ....: 2020-10-11 13:37:34
General key info..: sub ed25519/0x9B76AA52AF00EFEF 2020-10-11 John Doe <john.doe@example.com>
sec# ed25519/0xB52326F13324098C created: 2020-10-11 expires: never
ssb> ed25519/0x9B76AA52AF00EFEF created: 2020-10-11 expires: 2021-10-11
card-no: 0006 12073554
ssb> cv25519/0xE3AC01686E511A38 created: 2020-10-11 expires: 2021-10-11
card-no: 0006 12073554
ssb> ed25519/0x2BA042FD767F18C1 created: 2020-10-11 expires: 2021-10-11
card-no: 0006 12073554
Note that sec#
indicates master key is not available (as it should be stored encrypted offline). If you see General key info..: [none]
in the output instead - go back and import the public key using the previous step.
Encryption
Encrypt a message to your own key
echo "Sensitive information" >> password.txt
gpg --encrypt --default-recipient-self password.txt
You can also encrypt to multiple recipients (or to multiple keys).
gpg --encrypt --recipient $KEYID_0 --recipient $KEYID_1 --recipient $KEYID_2 password.txt
Decrypt the previous message
If you have configured the key for encryption, your YubiKey will blink. Touch it to complete the process.
gpg --decrypt password.txt.pgp
gpg: anonymous recipient; trying secret key 0xE3AC01686E511A38 ...
gpg: okay, we are the anonymous recipient.
gpg: encrypted with ECDH key, ID 0x0000000000000000
Sensitive information
If your YubiKey is not connected, GPG will ask you to insert it. Otherwise you will be asked for the PIN and then, the message will be decrypted.
Signature
If you have configured the key for signing, your YubiKey will blink. Touch it to complete the process.
Make a detached signature
gpg --detach-sign password.txt
Make a clear text signature
The --clearsign
flag makes a cleartext signature. The content in a cleartext signature is readable without any special software. OpenPGP software is only needed to verify the signature. Cleartext signatures may modify end-of-line whitespace for platform independence and are not intended to be reversible. The signing key is chosen by default or can be set explicitly using the --local-user
and --default-key
options.
gpg --clearsign password.txt
Verify the signature
gpg --verify signed.txt.sig
gpg: assuming signed data in 'password.txt'
gpg: Signature made Sun 11 Oct 2020 05:10:17 PM CEST
gpg: using EDDSA key 49B1F362745AAEB65EEF5E719B76AA52AF00EFEF
gpg: Good signature from "John Doe <john.doe@example.com>" [ultimate]
Primary key fingerprint: 0ED8 F486 1E57 693E C1E3 4EBE B523 26F1 3324 098C
Subkey fingerprint: 49B1 F362 745A AEB6 5EEF 5E71 9B76 AA52 AF00 EFEF
Encrypt and sign
The conventional extension for a signed and encrypted message is .gpg
and the resulting file will contain bot the encrypted message as well as the signature. The following example will create a signed and encrypted .gpg
file.
gpg --sign --encrypt --default-recipient-self password.txt
To verify, only --decrypt
must be used.
gpg --decrypt password.txt.gpg
gpg: anonymous recipient; trying secret key 0xE3AC01686E511A38 ...
gpg: okay, we are the anonymous recipient.
gpg: encrypted with ECDH key, ID 0x0000000000000000
Sensitive information
gpg: Signature made Sun 11 Oct 2020 05:10:17 PM CEST
gpg: using EDDSA key 49B1F362745AAEB65EEF5E719B76AA52AF00EFEF
gpg: Good signature from "John Doe <john.doe@example.com>" [ultimate]
Primary key fingerprint: 0ED8 F486 1E57 693E C1E3 4EBE B523 26F1 3324 098C
Subkey fingerprint: 49B1 F362 745A AEB6 5EEF 5E71 9B76 AA52 AF00 EFEF
Rotating keys
PGP does not provide forward secrecy - a compromised key may be used to decrypt all past messages. Although keys stored on YubiKey are difficult to steal, it is not impossible - the key and PIN could be taken, or a vulnerability may be discovered in key hardware or random number generator used to create them, for example. Therefore, it is good practice to occassionally rotate subkeys.
When a subkey expires, it can either be renewed or replaced. Both actions require access to the offline master key. Renewing subkeys by updating their expiration date indicates you are still in possession of the offline master key and is more convenient.
Replacing keys, on the other hand, is less convenient but more secure: the new subkeys will not be able to decrypt previous messages, authenticate with SSH, etc. Contacts will need to receive the updated public key and any encrypted secrets need to be decrypted and re-encrypted to new subkeys to be usable. This process is functionally equivalent to “losing” the YubiKey and provisioning a new one. However, you will always be able to decrypt previous messages using the offline encrypted backup of the original keys.
Neither rotation method is superior and it’s up to personal philosophy on identity management and individual threat model to decide which one to use, or whether to expire subkeys at all. Ideally, subkeys would be ephemeral: used only once for each encryption, signing and authentication event, however in practice that is not really feasible or worthwhile with YubiKey. Advanced users may want to dedicate an offline device for more frequent key rotations and ease of provisioning.
Set up environment
To renew or rotate subkeys, follow the same process as generating keys: boot to a secure environment, install required software and disconnect networking.
Connect the offline secret storage device with the master keys and identify the disk label.
sudo dmesg
sd 5:0:0:0: [sda] 7866368 512-byte logical blocks: (4.03 GB/3.75 GiB)
Decrypt and mount the offline volume.
sudo cryptsetup open /dev/sda1 secret
Enter passphrase for /dev/sda1:
sudo mount /dev/mapper/secret /mnt/encrypted-storage
Import the master key and configuration to a temporary working directory.
set -x GNUPGHOME (mktemp -d)
gpg --import /mnt/encrypted-storage/tmp.EOmP2zbviM/mastersub.key
gpg: keybox '/tmp/tmp.UtNncYzruW/pubring.kbx' created
gpg: /tmp/tmp.UtNncYzruW/trustdb.gpg: trustdb created
gpg: key B52326F13324098C: public key "John Doe <john.doe@example.com>" imported
gpg: key B52326F13324098C: secret key imported
gpg: Total number processed: 1
gpg: imported: 1
gpg: secret keys read: 1
gpg: secret keys imported: 1
Copy the configuration file.
cp -v /mnt/encrypted-storage/tmp.EOmP2zbviM/gpg.conf $GNUPGHOME
'/mnt/encrypted-storage/tmp.EOmP2zbviM/gpg.conf' -> '/tmp/tmp.UtNncYzruW/gpg.conf'
Export the master key ID.
set KEYID 0xB52326F13324098C
Renewing subkeys
Renewing subkeys is simple: you do not need to generate new keys, move keys to the YubiKey, or update any SSH public keys linked to the GPG key. All you need to do is to change the expiry time associated with the public key (which requires access to the master key you have just loaded) and then to export that public key and import it on any computer where you wish to use the GPG (as distinct from the SSH) key.
To change the expiration date of all subkeys, start by selecting all keys.
gpg --edit-key $KEYID
Secret key is available.
sec ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: unknown validity: unknown
ssb ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
ssb cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
ssb ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ unknown] (1). John Doe <john.doe@example.com>
gpg> key 1
sec ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: unknown validity: unknown
ssb* ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
ssb cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
ssb ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ unknown] (1). John Doe <john.doe@example.com>
gpg> key 2
sec ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: unknown validity: unknown
ssb* ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
ssb* cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
ssb ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ unknown] (1). John Doe <john.doe@example.com>
gpg> key 3
sec ed25519/0xB52326F13324098C
created: 2020-10-11 expires: never usage: C
trust: unknown validity: unknown
ssb* ed25519/0x9B76AA52AF00EFEF
created: 2020-10-11 expires: 2021-10-11 usage: S
ssb* cv25519/0xE3AC01686E511A38
created: 2020-10-11 expires: 2021-10-11 usage: E
ssb* ed25519/0x2BA042FD767F18C1
created: 2020-10-11 expires: 2021-10-11 usage: A
[ unknown] (1). John Doe <john.doe@example.com>
Then, use the expire
command to set a new expiration date. Despite the name, it will not cause currently valid keys to become expired.
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
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
Follow these prompts to set a new expiration date, then save
to save your changes.
Next, export your public key.
gpg --export $KEYID > pubkey.gpg
Transfer that public key to the computer from which you use your GPG key, and then import it with.
gpg --import pubkey.gpg
This will extend the validity of your GPG key and will allow you to use it for SSH authorization. Note that you do not need to update the SSH public key located on remote servers.
Rotating keys
Rotating keys is a bit more involved. First, follow the original steps to generate each subkey. Previous subkeys may be kept or deleted from the identity.
Finish by exporting new keys.
gpg --armor --export-secret-keys $KEYID > $GNUPGHOME/mastersub.key
gpg --armor --export-secret-subkeys $KEYID > $GNUPGHOME/sub.key
Copy the new temporary working directory to encrypted offline storage, which should still be mounted.
sudo cp -avi $GNUPGHOME /mnt/encrypted-storage
[...]
'/tmp/tmp.UtNncYzruW/pubring.kbx~' -> '/mnt/encrypted-storage/tmp.UtNncYzruW/pubring.kbx~'
There should now be at least two versions of the master and subkeys backed up.
ls /mnt/encrypted-storage/
lost+found/ tmp.EOmP2zbviM/ tmp.UtNncYzruW/
Unmount and close the encrypted volume.
sudo umount /mnt/encrypted-storage
sudo cryptsetup close /dev/mapper/secret
Export the updated public key.
sudo mkdir /mnt/public
sudo mount /dev/sda2 /mnt/public
gpg --armor --export $KEYID | sudo tee /mnt/public/$KEYID-(date +%F).txt
sudo umount /mnt/public
Disconnect the storage device and follow the original steps to transfer new keys (4, 5 and 6) to YubiKey, replacing existing ones. Reboot or securely erase the GPG temporary working directory.
The second part is done. Now, we will see how to use a YubiKey for SSH connections.