Today I discovered you absolutely can import an externally generated age key into one or more YubiKeys, allowing you to have backups of it. Since I replaced GnuPG with age, this has been my only gripe: I want a backup of my key, both as additional YubiKeys but also as a paper printout.
I was told you are not supposed to do this. "Just have multiple keys and age-encrypt to all of them". People are probably right, but I have evaluated the risks for myself and know how to use an airgapped device. I'm not telling you, you should do this, but other people seem to want this too, so here is how - do with this information what you want.
Certificate Format
age-plugin-yubikey looks for certificates in the "retired slots" (82-95, also
called slots 1-20) with:
Subject DN: CN=<name>,OU=<version>,O=age-plugin-yubikey
The plugin also reads PIN and touch policies from a certificate extension with OID
1.3.6.1.4.1.41482.3.8. The value is two bytes encoded as DER:XX:YY where the
first byte is the PIN policy and the second is the touch policy:
| Policy | PIN | Touch |
|---|---|---|
| Never | 01 | 01 |
| Once | 02 | - |
| Always | 03 | 02 |
| Cached | - | 03 |
For example, DER:01:01 means PIN=Never, Touch=Never. If this extension is
missing, the plugin may not correctly detect the policy requirements.
Generating the Key
Generate P-256 key externally using openssl, then import it to slot 82 (retired slot 1):
openssl ecparam -name prime256v1 -genkey -noout -out age-key.pem
openssl ec -in age-key.pem -pubout -out age-key.pub
ykman piv keys import 82 age-key.pemGenerating the Certificate
We also need a certificate in the expected format with the OID extension for PIN/touch policy. Use openssl to create a self-signed certificate (this example uses PIN=Never, Touch=Never):
openssl req -new -x509 -key age-key.pem \
-subj '/CN=My Backup Key/OU=0.5.0/O=age-plugin-yubikey/' \
-days 3650 \
-addext '1.3.6.1.4.1.41482.3.8=DER:01:01' \
-out age-cert.pem
Then import it to the YubiKey:
ykman piv certificates import 82 age-cert.pemTest Encryption/Decryption
Export the identity file and verify you can encrypt and decrypt correctly:
age-plugin-yubikey --list
age-plugin-yubikey --identity --serial 22412951 --slot 1 > age-yubikey-identity.txt
echo "test secret" | age -r age1yubikey1xxxxxxxxxxxxxxxxx -o test.age
age -d -i age-yubikey-identity.txt test.ageAdditional YubiKeys
For any additional keys, import the same key and the same certificate:
ykman piv keys import 82 age-key.pem
ykman piv certificates import 82 age-cert.pem
You will have multiple age identities with a common recipient. If you encrypt to that recipient, you will be able to decrypt with any of the keys. The identities differ because each YubiKey has a unique serial number.
You can concatenate both identity files, so that any key works for decryption later. If you don't do this, it will ask you for "Key with serial XXXX" on decryption.
Backup
Store age-key.pem and age-cert.pem securely - these two files are all you
need to restore the identity to a new YubiKey.