Using OpenPGP Keys with YubiKeys
We’re now ready to use the OpenPGP keys we transferred to the YubiKeys.
Hardened Configuration
Before proceeding with using the YubiKeys that contain the OpenPGP keys with our daily driver, i.e., the internet connected device that you perform numerous tasks from, you should first make sure you’re using a hardened GnuPG configuration on the daily driver.
You can take a look at the Hardened GPG Configuration post for a recommended hardened configuration as well as links to other hardened configurations.
After setting up a hardened configuration, you can now insert your YubiKey into your daily driver.
Resolve YubiKey Insertion Prompt Issue
If you’re experiencing an issue with GnuPG repeatedly prompting for you to insert a YubiKey which who have already inserted, then you can create the following file in your .gnupg
directory:
touch scdaemon.conf
You can then open the scdaemon.conf
file and add the following content:
disable-ccid
Install Required Packages
Make sure you have installed all the required packages on your device needed to allow the usage of YubiKeys with GnuPG.
On Debian and Ubuntu you can install the required packages by running the following command:
sudo apt install gnupg gnupg-agent gnupg-curl scdaemon pcscd
Import the Public Key
After installing the required packages, you can import your OpenPGP public key onto your daily driver. You should have backed up the public key onto, e.g., a USB when generating the OpenPGP keys which you can now use to copy the public key onto your daily driver or you can import the public key directly from the USB.
After copying the public key to the device, you can navigate to the directory containing the public key and then import the public key into your keyring by running the following command:
gpg --import public_key
Determine the Key ID
We’ll be using the key ID when editing the key as well as when testing the encryption and signing functionality of the keys which you can determine by running the following command:
gpg -k your-email@example.com
The output should contain your key and should look similar to the following:
pub rsa4096/0x46B680BB17A6BD07 2024-07-23 [C] [expires: 2027-07-23]
Key fingerprint = 0512 CEFB 5478 FEB9 032F FB6C 46B6 80BB 17A6 BD07
uid [ unknown] your-name <your-email@example.com>
uid [ unknown] [jpeg image of size 5143]
sub rsa4096/0x4288AC227E259D0F 2024-07-23 [S] [expires: 2025-07-23]
sub rsa4096/0xC5AB9F2897890EFF 2024-07-23 [E] [expires: 2025-07-23]
sub rsa4096/0xE13FEA1C7ABD419E 2024-07-23 [A] [expires: 2025-07-23]
The key ID for the primary key is located on the first line after the rsa4096
text, i.e., 0x46B680BB17A6BD07
.
Assign Ultimate Trust
After importing the public key into your keyring and determining the key ID, you can now assign an ultimate trust value to the key.
First, enter the following command to edit the key:
gpg --expert --edit-key KEYID
You should see output similar to the following:
Secret subkeys are available.
pub rsa4096/0x46B680BB17A6BD07
created: 2024-07-23 expires: 2027-07-23 usage: C
trust: unknown validity: unknown
ssb rsa4096/0x4288AC227E259D0F
created: 2024-07-23 expires: 2025-07-23 usage: S
card-no: 0006 12345678
ssb rsa4096/0xC5AB9F2897890EFF
created: 2024-07-23 expires: 2025-07-23 usage: E
card-no: 0006 12345678
ssb rsa4096/0xE13FEA1C7ABD419E
created: 2024-07-23 expires: 2025-07-23 usage: A
card-no: 0006 12345678
[ unknown] (1). your-name <your-email@example.com>
[ unknown] (2) [jpeg image of size 5143]
Be sure to replace KEYID
with your primary key ID.
You can now enter the following command to set the trust value:
trust
You should now be prompted to input a trust value which should look similar to the following:
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?
To set the trust value to ultimate you need to input the following then press Enter:
5
You’ll then be prompted to confirm the ultimate trust of the key:
Do you really want to set this key to ultimate trust? (y/N)
To confirm the operation type y
then press Enter.
You can then save the changes by typing save
and pressing Enter.
The trust value should now be updated which you can view by editing the key again:
gpg --expert --edit-key KEYID
You should see output similar to the following:
pub rsa4096/0x46B680BB17A6BD07
created: 2024-07-23 expires: 2027-07-23 usage: C
trust: ultimate validity: ultimate
ssb rsa4096/0x4288AC227E259D0F
created: 2024-07-23 expires: 2025-07-23 usage: S
card-no: 0006 12345678
ssb rsa4096/0xC5AB9F2897890EFF
created: 2024-07-23 expires: 2025-07-23 usage: E
card-no: 0006 12345678
ssb rsa4096/0xE13FEA1C7ABD419E
created: 2024-07-23 expires: 2025-07-23 usage: A
card-no: 0006 12345678
[ultimate] (1). your-name <your-email@example.com>
[ultimate] (2) [jpeg image of size 5143]
Be sure to replace KEYID
with your primary key ID.
If you set the trust-model
in your gpg.conf
file to be tofu+pgp
, then the image will have a trust value of never
instead of ultimate
.
If the YubiKey isn’t being recognized after setting the trust value, then remove and insert the YubiKey again.
Check YubiKey Status
To check the YubiKey is ready to be used you can run the following command to check the OpenPGP card status:
gpg --card-status
You should see output that looks similar to the following:
Reader ...........: Yubico Yubikey OTP FIDO CCID 00 00
Application ID ...: D2760001240103040006123456780000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: 12345678
Name of cardholder: your-name
Language prefs ...: en
Salutation .......:
URL of public key : hkps://keys.opengpg.org:443/pks/lookup?op=get&search=0x46B680BB17A6BD07
Login data .......: your-email@example.com
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: on
Signature key ....: CDE0 E421 0BAC 729A F132 1321 4288 AC22 7E25 9D0F
created ....: 2024-07-23 12:00:00
Encryption key....: DC43 E578 FFE1 BC03 74EF 6EFD C5AB 9F28 9789 0EFF
created ....: 2024-07-23 12:00:00
Authentication key: DE21 FFE5 3279 F457 843E 89BD E13F EA1C 7ABD 419E
created ....: 2024-07-23 12:00:00
General key info..: sub rsa4096/0x4288AC227E259D0F 2024-07-23 your-name <your-email@example.com>
sec# rsa4096/0x46B680BB17A6BD07 created: 2024-07-23 expires: 2027-07-23
ssb> rsa4096/0x4288AC227E259D0F created: 2024-07-23 expires: 2025-07-23
card-no: 0006 12345678
ssb> rsa4096/0xC5AB9F2897890EFF created: 2024-07-23 expires: 2025-07-23
card-no: 0006 12345678
ssb> rsa4096/0xE13FEA1C7ABD419E created: 2024-07-23 expires: 2025-07-23
card-no: 0006 12345678
Test Encryption
We’re now going to test the ability to encrypt a file using the encryption subkey we transferred to the OpenPGP card on the YubiKey.
To test the encryption we’re going to create the following file:
touch file-to-encrypt.txt
You can now open the file-to-encrypt.txt
file and add the following text:
This text will be encrypted then decrypted
After saving the file, you can run the following command to encrypt the file:
gpg --output encrypted-file.gpg --local-user KEYID --encrypt --armor --recipient KEYID file-to-encrypt.txt
In the command above we’re encrypting the file-to-encrypt.txt
file using the primary key ID, i.e., KEYID
which we specified using the —local-user
option. Then we set the recipient of the encrypted file to be ourselves using the primary key ID, i.e., KEYID
in the recipient
option. Finally, we set the output to be the encrypted file encrypted-file.gpg
.
Be sure to replace KEYID
with your primary key ID.
To decrypt the file, you can run the following command:
gpg --decrypt --armor encrypted-file.gpg
After executing the command above, enter the user PIN for the OpenPGP card stored on the YubiKey.
You should see output that contains the text we added to the file-to-encrypt.txt
file:
This text will be encrypted then decrypted
Test Signing
We’re now going to test the ability to sign a file using the signature subkey we transferred to the OpenPGP card on the YubiKey.
To test the signing we’re going to run the following command:
echo "This file will be signed" | gpg --local-user KEYID --armor --clearsign > signed-file.txt
In the command above we’re adding the text “This file will be signed“
to the signed-file.txt
file. Then, we’re clear signing the signed-file.txt
file using the primary key ID, i.e., KEYID
which we specified using the —local-user
option.
Be sure to replace KEYID
with your primary key ID.
After executing the command above, enter the user PIN for the OpenPGP card stored on the YubiKey.
To verify the signature, you can run the following command:
gpg --verify signed-file.txt
You should see output that looks similar to the following:
gpg: Signature made Wed 31 Jul 2024 05:35:33 PM UTC
gpg: using RSA key CDE0E4210BAC729AF13213214288AC227E259D0F
gpg: Good signature from "your-name <your-email@example.com>" [ultimate]
gpg: aka "[jpeg image of size 5143]" [ultimate]
Primary key fingerprint: 0512 CEFB 5478 FEB9 032F FB6C 46B6 80BB 17A6 BD07
Subkey fingerprint: CDE0 E421 0BAC 729A F132 1321 4288 AC22 7E25 9D0F
Configure Touch
The YubiKey by default doesn’t require any action from the user when performing cryptographic operations after the key has been unlocked once using the PIN.
To increase the security of the cryptographic operations being performed, the YubiKey can be configured to require a touch for each cryptographic operation.
Installation
To configure the YubiKey to require a touch for each cryptographic operation, the YubiKey Manager CLI package is required. Installation instructions can be found in the link.
To install the YubiKey Manager CLI on Arch Linux you can run the following command:
sudo pacman -S yubikey-manager
After installing the YubiKey Manager CLI on Arch Linux, you’ll need to enable the pcscd.service
which you can do by running the following command:
sudo systemctl enable pcscd.service
To start the pcscd.service
you can run the following command:
sudo systemctl start pcscd.service
Once the installation and enabling of any required services is done, you’re now ready to configure the YubiKey using the ykman
CLI tool.
If there are any issues or errors when configuring the YubiKey using ykman
, then try removing and inserting the YubiKey.
Encryption
To enable encryption to always require a touch, you can run the following command:
ykman openpgp keys set-touch dec on
You’ll then be prompted to provide the admin PIN for the OpenPGP card on the YubiKey:
Enter Admin PIN:
Type the admin PIN then press Enter.
You’ll then be prompted to confirm the touch policy for encryption:
Set touch policy of DEC key to on? [y/N]:
Type y
then press Enter to confirm the touch policy.
Signing
To enable signing to always require a touch, you can run the following command:
ykman openpgp keys set-touch sig on
You’ll then be prompted to provide the admin PIN for the OpenPGP card on the YubiKey:
Enter Admin PIN:
Type the admin PIN then press Enter.
You’ll then be prompted to confirm the touch policy for signing:
Set touch policy of SIG key to on? [y/N]:
Type y
then press Enter to confirm the touch policy.
Authentication
To enable authentication to always require a touch, you can run the following command:
ykman openpgp keys set-touch aut on
You’ll then be prompted to provide the admin PIN for the OpenPGP card on the YubiKey:
Enter Admin PIN:
Type the admin PIN then press Enter.
You’ll then be prompted to confirm the touch policy for authentication:
Set touch policy of AUT key to on? [y/N]:
Type y
then press Enter to confirm the touch policy.
Verify the Touch Status
To verify the YubiKey has been successfully configured to require a touch for each cryptographic operation you can run the following command:
gpg --card-status
You should see output that looks similar to the following:
Reader ...........: Yubico Yubikey OTP FIDO CCID 00 00
Application ID ...: D2760001240103040006123456780000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: 12345678
Name of cardholder: your-name
Language prefs ...: en
Salutation .......:
URL of public key : hkps://keys.opengpg.org:443/pks/lookup?op=get&search=0x46B680BB17A6BD07
Login data .......: your-email@example.com
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: on
UIF setting ......: Sign=on Decrypt=on Auth=on
Signature key ....: CDE0 E421 0BAC 729A F132 1321 4288 AC22 7E25 9D0F
created ....: 2024-07-23 12:00:00
Encryption key....: DC43 E578 FFE1 BC03 74EF 6EFD C5AB 9F28 9789 0EFF
created ....: 2024-07-23 12:00:00
Authentication key: DE21 FFE5 3279 F457 843E 89BD E13F EA1C 7ABD 419E
created ....: 2024-07-23 12:00:00
General key info..: sub rsa4096/0x4288AC227E259D0F 2024-07-23 your-name <your-email@example.com>
sec# rsa4096/0x46B680BB17A6BD07 created: 2024-07-23 expires: 2027-07-23
ssb> rsa4096/0x4288AC227E259D0F created: 2024-07-23 expires: 2025-07-23
card-no: 0006 12345678
ssb> rsa4096/0xC5AB9F2897890EFF created: 2024-07-23 expires: 2025-07-23
card-no: 0006 12345678
ssb> rsa4096/0xE13FEA1C7ABD419E created: 2024-07-23 expires: 2025-07-23
card-no: 0006 12345678
Under the KDF setting
you should now see the following line:
UIF setting ......: Sign=on Decrypt=on Auth=on
If you see Sign=on Decrypt=on Auth=on
, then the YubiKey has been successfully configured to require a touch each time a cryptographic operation is performed.