Yubikey Configuration¶
OpenPGP¶
Yubikeys are kind of like supercharged house keys, except instead of unlocking a door (which it can do), it helps unlock online accounts and protect sensitive data. It's OpenPGP support means it can be used for encrypting and signing messages securely using a time-tested and trusted system called OpenPGP.
With it, you can encrypt (lock) and digitally sign emails or files to keep them private and tamper-proof. Normally, OpenPGP uses a private key, which is like a secret password that should never be shared. Instead of storing the key on a computer where it could get lost in a harddrive crash or stolen by bad actors, Yubikey stores them safely inside itself. When you neeed to encrypt, decrypt, or sign something, Yubikey does the work for you (using the keys you've loaded) to keep your private key protected.
Once a key has been saved to a Yubikey, you can't get it out again. If you need to replace the key, your only option is to erase it and add a new one.
The most basic explaination is this: Imagine you want to send a secret letter to a friend but you're fresh out of invisible ink. So with your Yubikey, you put your letter into a box that only your friend can open. Better yet, when your friend receives your letter, they can validate that its contents is indeed from you and hasn't been tampered with at any point on it's journey to them.
If you want a little more depth about PGP (you'll also see it referred to as "GPG" - that's not a typo, but for now just think of them as one-and-the-same), see my PGP Primer. You're going to need to have your Keys and Secret Keys handy to successfully store them on your Yubikey.
Getting Started¶
Begin by ensuring that only your new Yubikey is connected to your machine, and execute gpg --card-status
and ykman info
to verify that you're targeting the correct device. Its possible to work with multiple Yubikeys connected at once, but far easier to set them up one at a time if this is your first experience with them.
Though some of the initial steps can be done with the YubiKey Manager GUI app, it doesn't support or include everything you need to configure OpenPGP with your Yubikey, so I recommend sticking with the command-line tools for this setup.
$ gpg --card-status
Reader ...........: Yubico YubiKey OTP FIDO CCID
Application ID ...: D1234567891234567891234567891234
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: 23456789
Name of cardholder: [not set]
Language prefs ...: [not set]
Salutation .......:
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 ......: off
UIF setting ......: Sign=off Decrypt=off Auth=off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
$ ykman info
Device type: YubiKey 5C NFC
Serial number: 23456789
Firmware version: 5.7.1
Form factor: Keychain (USB-C)
Enabled USB interfaces: OTP, FIDO, CCID
NFC transport is enabled
Applications USB NFC
Yubico OTP Enabled Enabled
FIDO U2F Enabled Enabled
FIDO2 Enabled Enabled
OATH Enabled Enabled
PIV Enabled Enabled
OpenPGP Enabled Enabled
YubiHSM Auth Enabled Enabled
Default PINs
If this is a new key and you haven't modified the default PINs, make note of them below. We'll be changing them shortly. I strongly recommend making a note of all of your pins and passphrases in a secure password manager to help ensure you don't lose access to your Yubikey - especially if you won't use them often.
- PIN:
123456
- Admin PIN:
12345678
Update PINs¶
Admin PIN must be set before Reset Code
# Set the OpenPGP PIN (min 6 alphanumeric)
ykman openpgp access change-pin --pin 123456 --new-pin XXXXXX
User PIN has been changed.
# Set the OpenPGP Admin PIN (min 8 alphanumeric)
ykman openpgp access change-admin-pin --admin-pin 12345678 --new-admin-pin 88888888
Admin PIN has been changed.
# Set the OpenPGP Reset Code (min 8 alphanumeric)
ykman openpgp access change-reset-code --admin-pin 88888888 --reset-code 77777777
Reset Code has been changed.
# Set retry count for PIN, Reset Code, and Admin PIN (optional!)
ykman openpgp access set-retries 6 6 6
Enter Admin PIN: 88888888
Set PIN retry counters to: 6 6 6? [y/N]: y
Number of PIN/Reset Code/Admin PIN retries set.
Here, we're changing the default retry / attempt counts from their default 3
to 6
.
Set Operational Settings¶
ykman openpgp keys set-touch --help
Usage: ykman openpgp keys set-touch [OPTIONS] KEY POLICY
Set the touch policy for OpenPGP keys.
The touch policy is used to require user interaction for all operations using the private key on the YubiKey. The touch policy is set individually for each key slot. To see the current touch
policy, run the "openpgp info" subcommand.
Touch policies:
Off (default) no touch required
On touch required
Fixed touch required, can\'t be disabled without deleting the private key
Cached touch required, cached for 15s after use
Cached-Fixed touch required, cached for 15s after use, can't be disabled
without deleting the private key
KEY key slot to set (sig, dec, aut or att)
POLICY touch policy to set (on, off, fixed, cached or cached-fixed)
Options:
-a, --admin-pin TEXT Admin PIN for OpenPGP
-f, --force confirm the action without prompting
-h, --help show this message and exit
# Set touch requirements for signing, decryption, authentication, and attestation
ykman openpgp keys set-touch sig off
Enter Admin PIN:
Set touch policy of SIG key to off? [y/N]: y
Touch policy for slot SIG set.
ykman openpgp keys set-touch dec off
Enter Admin PIN:
Set touch policy of DEC key to off? [y/N]: y
Touch policy for slot DEC set.
ykman openpgp keys set-touch aut off
Enter Admin PIN:
Set touch policy of AUT key to off? [y/N]: y
Touch policy for slot AUT set.
ykman openpgp keys set-touch att cached
Enter Admin PIN:
Set touch policy of ATT key to cached? [y/N]: y
Touch policy for slot ATT set.
In the commands above, I've set the "touch" requirements for signing, encryption (and decryption), and authenticating to off
, but I've set attestation to cached
.
Value | Meaning |
---|---|
Off (default) |
no touch required |
On |
touch required |
Fixed |
touch required, can't be disabled without deleting the private key |
Cached |
touch required, cached for 15s after use |
Cached-Fixed |
touch required, cached for 15s after use, can't be disabled without deleting the private key |
Confirm Touch Settings¶
$ ykman openpgp info
OpenPGP version: 3.4
Application version: 5.7.1
PIN tries remaining: 6
Reset code tries remaining: 6
Admin PIN tries remaining: 6
Require PIN for signature: Once
KDF enabled: False
Touch policies:
Signature key: Off
Encryption key: Off
Authentication key: Off
Attestation key: Cached
Set Yubikey Properties¶
$ gpg --card-edit
Reader ...........: Yubico YubiKey OTP FIDO CCID
Application ID ...: D1234567891234567891234567891234
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: 23456789
Name of cardholder: [not set]
Language prefs ...: [not set]
Salutation .......:
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 : 6 6 6
Signature counter : 0
KDF setting ......: off
UIF setting ......: Sign=off Decrypt=off Auth=off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
gpg/card> help
quit quit this menu
admin show admin commands
help show this help
list list all available data
fetch fetch the key specified in the card URL
passwd menu to change or unblock the PIN
verify verify the PIN and list all data
unblock unblock the PIN using a Reset Code
openpgp switch to the OpenPGP app
gpg/card> admin
Admin commands are allowed
gpg/card> help
quit quit this menu
admin show admin commands
help show this help
list list all available data
name change card holder's name
url change URL to retrieve key
fetch fetch the key specified in the card URL
login change the login name
lang change the language preferences
salutation change card holder's salutation
cafpr change a CA fingerprint
forcesig toggle the signature force PIN flag
generate generate new keys
passwd menu to change or unblock the PIN
verify verify the PIN and list all data
unblock unblock the PIN using a Reset Code
factory-reset destroy all keys and data
kdf-setup setup KDF for PIN authentication (on/single/off)
key-attr change the key attribute
uif change the User Interaction Flag
openpgp switch to the OpenPGP app
gpg/card> name
Cardholder's surname: Dodd
Cardholder's given name: Bryan
gpg/card> lang
Language preferences: en
gpg/card> login
Login data (account name): bryan@dodd.dev
gpg/card> url
URL to retrieve public key: https://keys.openpgp.org/vks/v1/by-fingerprint/74BD90B590F9AA984391707383308CA85B65951C
gpg/card> list
Reader ...........: Yubico YubiKey OTP FIDO CCID
Application ID ...: D1234567891234567891234567891234
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: 23456789
Name of cardholder: Bryan Dodd
Language prefs ...: en
Salutation .......:
URL of public key : https://keys.openpgp.org/vks/v1/by-fingerprint/74BD90B590F9AA984391707383308CA85B65951C
Login data .......: bryan@dodd.dev
Signature PIN ....: not forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 6 6 6
Signature counter : 0
KDF setting ......: off
UIF setting ......: Sign=off Decrypt=off Auth=off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
gpg/card> quit
Not every property is required to be set, but setting as much as you can is helpful in different circumstances.
For example, setting the URL enables use of the --fetch
command to automatically retrieve a copy of your public key.
Loading PGP Keys¶
This is where you need to have a plan before continuing ...
Keys can ONLY be transferred to Yubikey from your GnuPG Keyring.
- If you've previously loaded them to another Yubikey, all you have in your current keyring will be key stubs. This is not sufficient for setting up a new Yubikey, so additional steps will be required.
- If you've got your public / private keys exported to ASCII-armored files, this alone is not sufficient for setting up a new Yubikey.
- Loading keys to Yubikey is a one way operation. Once loaded into Yubikey, you can't export your private key again, so your only option is to delete the keys and upload new ones.
This step is especially important. If you intend to load your OpenPGP keys onto multiple Yubikeys, pay close attention to the order of operations performed here.
To begin, the keys you want to transfer to Yubikey must be loaded to your GnuPG Keyring. If your keys are not currently loaded and accessible from your local keyring, you must first re-load them. The most likely reason you may be in this situation is if you've previously loaded your keys to another Yubikey and are setting up a second or new Yubikey.
When you issue the command to move your keys to Yubikey, the keys are literally moved. There is no option to only "copy" them. The only thing remaining in your local keyring after the transfer process is a stub (pointer to the Yubikey you moved them to), and the process cannot be reversed.
To determine if your keys are physically present on your machine or if they've been moved elsewhere, run gpg --list-secret-keys
. The all-important subkeys will be listed at the bottom as ssb
. If you see the >
symbol, this indicates you only have stubs loaded. You will not be able to transfer your keys to Yubikey in this state.
To remedy this, you must have a previously exported set of your private keys available to you - whether thats on your local filesystem, a USB drive, a network drive, etc. If you followed along with the key generation in my PGP Primer, you should have a copy of your subkeys saved as subkeys.asc
(or similar). We'll need these soon.
$ gpg --list-secret-keys --with-keygrip
[keyboxd]
---------
sec# ed25519 YYYY-MM-DD [C]
74BD90B590F9AA984391707383308CA85B65951C
Keygrip = ...A47E26C0196ED67BD
uid [ultimate] Bryan Dodd <bryan@dodd.dev>
ssb> ed25519 YYYY-MM-DD [S] # Note the ">" indicating that only stubs exist locally.
Keygrip = ...BA272DF1
ssb> cv25519 YYYY-MM-DD [E]
Keygrip = ...CC740E41
ssb> ed25519 YYYY-MM-DD [A]
Keygrip = ...E566D05C
The Keygrip
value from the output indicates where your key stubs are stored locally. Take extra care not to delete the wrong files, delete the keygrip files for the subkeys you previously stubbed: ~/.gnupg/private-keys-v1.d/<keygrip>.key
.
With the keygrip files removed, import the subkeys from your backup .asc
file:
$ gpg --import subkeys.asc
gpg: key 83308CA85B65951C: "Bryan Dodd <bryan@dodd.dev>" not changed
gpg: To migrate 'secring.gpg', with each smartcard, run: gpg --card-status
gpg: key 83308CA85B65951C: secret key imported
gpg: Total number processed: 1
gpg: unchanged: 1
gpg: secret keys read: 1
gpg: secret keys imported: 1
If your master key is passphrase protected, be prepared to enter it during the import process. Once complete, enumerate your secret keys and note that the stub identifier (>
) is no longer present, indicating the key material is indeed present on your local keyring again.
$ gpg --list-secret-keys --with-subkey-fingerprint
[keyboxd]
---------
sec# ed25519 YYYY-MM-DD [C]
74BD90B590F9AA984391707383308CA85B65951C
uid [ultimate] Bryan Dodd <bryan@dodd.dev>
ssb ed25519 YYYY-MM-DD [S] # (1)
ssb cv25519 YYYY-MM-DD [E]
ssb ed25519 YYYY-MM-DD [A]
- The "
>
" is no longer present, signifying that the key material is present on the local keyring once again.
We're now ready to copy the subkeys over to your new Yubikey! Like before, however, this is a one-way operation. Transferring the keys will once again replace the keys in your keyring with stubs. If this is your first time transferring private keys to Yubikey, read through the entire process carefully so you know what to expect.
You're going to need to ...
- select a key
- move it to yubikey
- deselect the key
- select the next key
- etc., etc.
... for each individual key. So pay close attention to where you are in the process to avoid mistakes. The final save
step is necessary to save your work and complete the transfer.
$ gpg --edit-key bryan@dodd.dev
gpg (GnuPG) 2.4.7; Copyright (C) 2024 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret subkeys are available.
pub ed25519/83308CA85B65951C
created: YYYY-MM-DD expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/5B484E245400D8FF
created: YYYY-MM-DD expires: never usage: S
ssb cv25519/FFEAEADFB4C98A69
created: YYYY-MM-DD expires: never usage: E
ssb ed25519/2BA9D97DEB5285E8
created: YYYY-MM-DD expires: never usage: A
[ultimate] (1). Bryan Dodd <bryan@dodd.dev>
gpg> key 1 # (1)
pub ed25519/83308CA85B65951C
created: YYYY-MM-DD expires: never usage: C
trust: ultimate validity: ultimate
ssb* ed25519/5B484E245400D8FF # <== (8)
created: YYYY-MM-DD expires: never usage: S
ssb cv25519/FFEAEADFB4C98A69
created: YYYY-MM-DD expires: never usage: E
ssb ed25519/2BA9D97DEB5285E8
created: YYYY-MM-DD expires: never usage: A
[ultimate] (1). Bryan Dodd <bryan@dodd.dev>
gpg> keytocard
Please select where to store the key:
(1) Signature key
(3) Authentication key
Your selection? 1 # (2)
# You may be prompted to enter your PASSPHRASE (if you set one for your master key)
# as well as your ADMIN PIN for every card action you take.
pub ed25519/83308CA85B65951C
created: YYYY-MM-DD expires: never usage: C
trust: ultimate validity: ultimate
ssb* ed25519/5B484E245400D8FF # <== (9)
created: YYYY-MM-DD expires: never usage: S
ssb cv25519/FFEAEADFB4C98A69
created: YYYY-MM-DD expires: never usage: E
ssb ed25519/2BA9D97DEB5285E8
created: YYYY-MM-DD expires: never usage: A
[ultimate] (1). Bryan Dodd <bryan@dodd.dev>
Note: the local copy of the secret key will only be deleted with "save".
gpg> key 1 # (3)
pub ed25519/83308CA85B65951C
created: YYYY-MM-DD expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/5B484E245400D8FF # <== (13)
created: YYYY-MM-DD expires: never usage: S
ssb cv25519/FFEAEADFB4C98A69
created: YYYY-MM-DD expires: never usage: E
ssb ed25519/2BA9D97DEB5285E8
created: YYYY-MM-DD expires: never usage: A
[ultimate] (1). Bryan Dodd <bryan@dodd.dev>
gpg> key 2 # (4)
pub ed25519/83308CA85B65951C
created: YYYY-MM-DD expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/5B484E245400D8FF
created: YYYY-MM-DD expires: never usage: S
ssb* cv25519/FFEAEADFB4C98A69 # <== (10)
created: YYYY-MM-DD expires: never usage: E
ssb ed25519/2BA9D97DEB5285E8
created: YYYY-MM-DD expires: never usage: A
[ultimate] (1). Bryan Dodd <bryan@dodd.dev>
gpg> keytocard
Please select where to store the key:
(2) Encryption key
Your selection? 2
# Again, be prepared to enter your PASSPHRASE and your ADMIN PIN
pub ed25519/83308CA85B65951C
created: YYYY-MM-DD expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/5B484E245400D8FF
created: YYYY-MM-DD expires: never usage: S
ssb* cv25519/FFEAEADFB4C98A69 # <== (11)
created: YYYY-MM-DD expires: never usage: E
ssb ed25519/2BA9D97DEB5285E8
created: YYYY-MM-DD expires: never usage: A
[ultimate] (1). Bryan Dodd <bryan@dodd.dev>
Note: the local copy of the secret key will only be deleted with "save".
gpg> key 2 # (5)
pub ed25519/83308CA85B65951C
created: YYYY-MM-DD expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/5B484E245400D8FF
created: YYYY-MM-DD expires: never usage: S
ssb cv25519/FFEAEADFB4C98A69 # <== (14)
created: YYYY-MM-DD expires: never usage: E
ssb ed25519/2BA9D97DEB5285E8
created: YYYY-MM-DD expires: never usage: A
[ultimate] (1). Bryan Dodd <bryan@dodd.dev>
gpg> key 3 # (6)
pub ed25519/83308CA85B65951C
created: YYYY-MM-DD expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/5B484E245400D8FF
created: YYYY-MM-DD expires: never usage: S
ssb cv25519/FFEAEADFB4C98A69
created: YYYY-MM-DD expires: never usage: E
ssb* ed25519/2BA9D97DEB5285E8 # <== (12)
created: YYYY-MM-DD expires: never usage: A
[ultimate] (1). Bryan Dodd <bryan@dodd.dev>
gpg> keytocard
Please select where to store the key:
(3) Authentication key
Your selection? 3
# Another prompt to enter your PASSPHRASE and your ADMIN PIN
pub ed25519/83308CA85B65951C
created: YYYY-MM-DD expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/5B484E245400D8FF
created: YYYY-MM-DD expires: never usage: S
ssb cv25519/FFEAEADFB4C98A69
created: YYYY-MM-DD expires: never usage: E
ssb* ed25519/2BA9D97DEB5285E8
created: YYYY-MM-DD expires: never usage: A
[ultimate] (1). Bryan Dodd <bryan@dodd.dev>
Note: the local copy of the secret key will only be deleted with "save".
gpg> save # (7)
- Enter
key 1
to SELECT the first subkey. - The first subkey is our signing subkey, so take care to only select the option for the signature slot.
- You must enter
key 1
again to DESELECT the first subkey... - ... and now enter
key 2
to SELECT the second subkey. - As before, you must enter
key 2
again to DESELECT the second subkey... - ... and enter
key 3
to SELECT the final subkey. - You don't have to deselect the last subkey, but none of your changes will be SAVED until you enter
save
and press enter. - The
*
symbol identifies the subkey you have SELECTED - The
*
symbol identifies the subkey you have SELECTED - The
*
symbol identifies the subkey you have SELECTED - The
*
symbol identifies the subkey you have SELECTED - The
*
symbol identifies the subkey you have SELECTED - The key has been DE-selected.
- The key has been DE-selected.
Final Verification¶
Let's confirm that your keys have once again been REMOVED from your local keyring and replaced with STUBS only:
$ gpg --list-secret-keys
[keyboxd]
---------
sec# ed25519 YYYY-MM-DD [C]
74BD90B590F9AA984391707383308CA85B65951C
uid [ultimate] Bryan Dodd <bryan@dodd.dev>
ssb> ed25519 YYYY-MM-DD [S] ## Note the ">" stub indicator has returned
ssb> cv25519 YYYY-MM-DD [E] ## signifiying that keys have been moved OUT
ssb> ed25519 YYYY-MM-DD [A] ## of the local keyring.
We can also use the --with-subkey-fingerprint
to see the Yubikey serial number associated with our key:
$ gpg --list-secret-keys --with-subkey-fingerprint
[keyboxd]
---------
sec# ed25519 YYYY-MM-DD [C]
74BD90B590F9AA984391707383308CA85B65951C
uid [ultimate] Bryan Dodd <bryan@dodd.dev>
ssb> ed25519 YYYY-MM-DD [S]
................................5400D8FF
Card serial no. = 0006 23456789 ## <==
ssb> cv25519 YYYY-MM-DD [E]
................................B4C98A69
Card serial no. = 0006 23456789 ## <==
ssb> ed25519 YYYY-MM-DD [A]
................................EB5285E8
Card serial no. = 0006 23456789 ## <==
And finally, checking the Yubikey itself:
$ gpg --card-status
Reader ...........: Yubico YubiKey OTP FIDO CCID
Application ID ...: D1234567891234567891234567891234
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: 23456789
Name of cardholder: Bryan Dodd
Language prefs ...: en
Salutation .......:
URL of public key : https://keys.openpgp.org/vks/v1/by-fingerprint/74BD90B590F9AA984391707383308CA85B65951C
Login data .......: bryan@dodd.dev
Signature PIN ....: not forced
Key attributes ...: ed25519 cv25519 ed25519
Max. PIN lengths .: 127 127 127
PIN retry counter : 6 6 6
Signature counter : 0
KDF setting ......: off
UIF setting ......: Sign=off Decrypt=off Auth=off
Signature key ....: xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx 5400 D8FF
created ....: YYYY-MM-DD 16:32:56
Encryption key....: xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx B4C9 8A69
created ....: YYYY-MM-DD 16:36:40
Authentication key: xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx EB52 85E8
created ....: YYYY-MM-DD 16:38:00
General key info..: sub ed25519/5B484E245400D8FF YYYY-MM-DD Bryan Dodd <bryan@dodd.dev>
sec# ed25519/83308CA85B65951C created: YYYY-MM-DD expires: never
ssb> ed25519/5B484E245400D8FF created: YYYY-MM-DD expires: never
card-no: 0006 23456789
ssb> cv25519/FFEAEADFB4C98A69 created: YYYY-MM-DD expires: never
card-no: 0006 23456789
ssb> ed25519/2BA9D97DEB5285E8 created: YYYY-MM-DD expires: never
card-no: 0006 23456789
Saving your keys to multiple Yubikeys ...
If you have multiple Yubikeys that you want to save your OpenPGP keys to, you'll have to repeat the steps on this page, starting with running the gpg --list-secret-keys --with-keygrip
command to get the file path of your local key stubs.
After copying your keys to Yubikey, your local keys will be deleted every time. You must re-import your keys from your backup in order to move them to each Yubikey you want to store them on.
After your final Yubikey has been updated, do not restore your local keys from backup. Let them stay in your keyring as STUBS ONLY. This ensures that you can now only access your keys by having a Yubikey present.
One final note ...¶
If you have multiple Yubikeys that you've configured with identical OpenPGP keys, note that the GnuPG Keyring will only ever remember the last Yubikey used to stub out your keys.
Recall above that we used the --with-subkey-fingerprint
command to get the fingerprints of our subkeys, but also to view the Yubikey serial number the keyring is expecting to find our keys on.
$ gpg --list-secret-keys --with-subkey-fingerprint
[keyboxd]
---------
sec# ed25519 YYYY-MM-DD [C]
74BD90B590F9AA984391707383308CA85B65951C
uid [ultimate] Bryan Dodd <bryan@dodd.dev>
ssb> ed25519 YYYY-MM-DD [S]
................................5400D8FF
Card serial no. = 0006 12345678 ## <==
ssb> cv25519 YYYY-MM-DD [E]
................................B4C98A69
Card serial no. = 0006 12345678 ## <==
ssb> ed25519 YYYY-MM-DD [A]
................................EB5285E8
Card serial no. = 0006 12345678 ## <==
When you change to a different Yubikey on your machine, you'll need to alert GnuPG that your keys need to be remapped to the currently inserted key:
$ gpg-connect-agent "scd serialno" "learn --force" /bye
S SERIALNO D1234567891234567891234567891234
OK
S PROGRESS learncard k 0 0
S PROGRESS learncard k 0 0
S PROGRESS learncard k 0 0
OK