GPG Keys with Multiple Yubikey
"One yubikey is no yubikey" (an old proverb).
TL;DR:
I use this key as of March 2026. My key Key ID/Fingerprint: 74FEDBB2 or 01B157D574FEDBB2 or 645FA10143EFBE17108030F801B157D574FEDBB2
Who is this for
Mostly myself, so I remember what I did.
What are we trying to solve.
I recently bought 3 yubikeys, mainly to use with passphrases. But I also decided to store my "GPG key" on them. The problem I am trying to solve is that I want to be able to use 3 yubikeys for redundancy. One to always keep at home.
Two that I take with me for travel so that, if I loose one I can always continue doing business on the trip. I also want to make sure that when I loose a key, I do not have to revoke my master Identity.
GPG and subkeys
When you generate a PGP key it will by default create an a 'Signing and Certification' [SC] and a 'Encryption' [E].
Idealy one would want to generate multiple Encryption subkeys, one for each yubikey. But, that will lead to drama because if Alice wants to send you something encrypted she has to know wich encryption subkey you have available at the time. So we equip all our yubikeys with the same encryption key. Which makes that if you loose one, you still have to revoke the whole lot.
The workflow
generate keys
We follow the recipee here that creates a certiv
Generate a GPG key. We do this not on the yubikey but on a machine. We want to be able to backup the generated key.
export KEY_TYPE=Ed25519 # while we are at it we use a modern curve.
export IDENTITY="Olaf M. Kolkman <olaf@xolx.nl>"
export CERTIFY_PASS="<redacted-certfication-password>"
export EXPIRATION=9y # I have my reasons
Generate the Certificate:
echo "$CERTIFY_PASS" | \
gpg --batch --passphrase-fd 0 \
--quick-generate-key "$IDENTITY" "$KEY_TYPE" cert never
Make note of the stored revocation certificate. follow the recipee to set and view the fingerprints and keyid
export KEYID=$(gpg -k --with-colons "$IDENTITY" | \
awk -F: '/^pub:/ { print $5; exit }')
export KEYFP=$(gpg -k --with-colons "$IDENTITY" | \
awk -F: '/^fpr:/ { print $10; exit }')
printf "\nKey ID/Fingerprint: %20s\n%s\n\n" "$KEYID" "$KEYFP"
Key ID/Fingerprint: 01B157D574FEDBB2
645FA10143EFBE17108030F801B157D574FEDBB2
Now first eddit the key to add additional Identifiers and create an encryption ey
gpg --expert --edit-key 01B157D574FEDBB2
...
gpg> adduid
...
gpg> sign
gpg> addkey
<select ECC encrypt only (12)>
And generate 3 sets of signing and authentication subkeys
for i in {0..2}; do
echo creating signing key $i:
echo "$CERTIFY_PASS" | \
gpg --batch --pinentry-mode=loopback --passphrase-fd 0 \
--quick-add-key "$KEYFP" "${KEYTYPE}" sign "$EXPIRATION"
echo creating authentication key $i:
echo "$CERTIFY_PASS" | \
gpg --batch --pinentry-mode=loopback --passphrase-fd 0 \
--quick-add-key "$KEYFP" "${KEYTYPE}" auth "$EXPIRATION"
done
Now check what we generated
> gpg -k ${KEYFP}
pub ed25519 2026-03-10 [C]
645FA10143EFBE17108030F801B157D574FEDBB2
uid [ultimate] Olaf M. Kolkman <kolkman@isoc.org>
uid [ultimate] Olaf M. Kolkman <olaf@xolx.nl>
uid [ultimate] Olaf M. Kolkman <olaf@dacht.net>
sub cv25519 2026-03-10 [E] [expires: 2035-03-08]
sub ed25519 2026-03-10 [S] [expires: 2035-03-08]
sub ed25519 2026-03-10 [A] [expires: 2035-03-08]
sub ed25519 2026-03-10 [S] [expires: 2035-03-08]
sub ed25519 2026-03-10 [A] [expires: 2035-03-08]
sub ed25519 2026-03-10 [S] [expires: 2035-03-08]
sub ed25519 2026-03-10 [A] [expires: 2035-03-08]
Backup the key:
gpg --export-secret-key --armor 645FA10143EFBE17108030F801B157D574FEDBB2
store output safely.
Transfer to the yubikey
You will need the ykman cli tool for this.
First make sure your yubikey is set up. For each of your yubikey do the following. (Note on macOSX if the tool doesn't respond to return, use ctr-j as return char)
ykman openpgp reset
...
ykman openpgp access change-admin-pin
...
ykman openpgp access change-pin
...
ykman openpgp access set-retries 5 5 5
After preparing the yubikeys copy the encryption key [E] to all yubikeys and one unique signing [S] and Authorization keys [A] to each yubikey. So we do now follow the yubikey recipee to the letter, since we do not export the primary keys signature key.
Carfully select the appropriate key by toggling key <keyno>. And choose the appropriate slots.
Validate with ykman openpgp info if you transfered the correct keys.
The resulting keys have been transfered like so:
Yubikey type SUBKey IO
--------------------------------------------------------
35775013 S ECCE B28A 6E5F EE99 D17A 8663 A20F 6458 99FA 4923
35775013 E 85B2 FBDA E6DC E92A 0676 07D7 9C82 2115 2E48 E8BE
35775013 A 3FC6 049C FC4C A286 C919 86B1 1B7F 003F 881B 9F3B
36431751 S E540 031A 32A2 B74A 45D0 7AFC FA69 0576 F726 C4C7
36431751 E 85B2 FBDA E6DC E92A 0676 07D7 9C82 2115 2E48 E8BE
36431751 A D464 A0DE 003C 561B 6677 6665 085A 93EB 5D85 EE54
36431811 S 80E1 9313 13F8 734F 10A4 92B7 D426 4719 8122 395F
36431811 E 85B2 FBDA E6DC E92A 0676 07D7 9C82 2115 2E48 E8BE
36431811 A B395 CE5B C4C3 759D C859 B68A EDFF 356F B975 5D1A
--------------------------------------------------------
Transfer from the Yubikey
Now comes the scary bit: Delete the secret key. And immediatly reimport it from the yubikey:
gpg --delete-secret-keys ${KEYID}
gpg --card-edit fetch
That results in a table where one can see which keys are now available.
sub ed25519/A20F645899FA4923 2026-03-10 Olaf M. Kolkman <kolkman@isoc.org>
sec# ed25519/01B157D574FEDBB2 created: 2026-03-10 expires: never
ssb> cv25519/9C8221152E48E8BE created: 2026-03-10 expires: 2035-03-08
card-no: 0006 35775013
ssb# ed25519/D42647198122395F created: 2026-03-10 expires: 2035-03-08
ssb# ed25519/EDFF356FB9755D1A created: 2026-03-10 expires: 2035-03-08
ssb> ed25519/A20F645899FA4923 created: 2026-03-10 expires: 2035-03-08
card-no: 0006 35775013
ssb> ed25519/1B7F003F881B9F3B created: 2026-03-10 expires: 2035-03-08
card-no: 0006 35775013
ssb# ed25519/FA690576F726C4C7 created: 2026-03-10 expires: 2035-03-08
ssb# ed25519/085A93EB5D85EE54 created: 2026-03-10 expires: 2035-03-08
Any time you change the yubikey you use you have to delete (gpg --delete-key), refetch the key (gpg --card-edit fetch), and set the trust to full (gpg --edit-key 01B157D574FEDBB2 and then put ultimate trust in the key)