Hardware Keys Guide
Storing Oversight recipient keys on PIV-compatible hardware tokens
Vendor-neutral guide for storing Oversight recipient private keys on a hardware
device (YubiKey, OnlyKey, Nitrokey) rather than a disk file. The canonical
source is
docs/HARDWARE_KEYS.md;
this page mirrors it for readability and adds an implementation-status
footnote so visitors know what is shipped versus what is documented as
forward design.
KeyProvider trait and the
OSGT-HW-P256-v1 suite are implemented end-to-end in
oversight-rust/oversight-crypto, with a software reference
provider (SoftwareP256KeyProvider) so the new suite can be
seal/open round-tripped today. The oversight-container
crate recognizes suite_id = 3 and ships
seal_hw_p256 + open_sealed_with_provider.
The PivKeyProvider (PKCS#11 binding) and the
oversight CLI flags described below are the next bounded
follow-up; until they ship, hardware-backed Oversight is real at the
protocol layer but is software-tested rather than token-tested. See the
v0.4.10 release post
for the design rationale.
Why
When a recipient's .key file lives on disk, full compromise
of that recipient's laptop gives an attacker the private key forever.
That attacker can decrypt every sealed file addressed to that recipient,
past and future, with no way to tell the issuer it happened.
A hardware-backed key eliminates this. The private key is generated inside the device's secure element and never leaves it. All ECDH (P-256) and signing (Ed25519) operations happen on-device. The host OS gets ECDH outputs, never the raw key. To decrypt, an adversary needs physical possession of the device and typically a touch, PIN, or biometric.
This does not give you enclave-grade guarantees. A compromised client running while the YubiKey is plugged in can still open files via the device. What it does give you:
- Vendor-neutral. Any FIDO2 / PIV device works.
- Theft is discrete. Physical device loss is noticeable; disk theft may not be.
- Revocation is simple. Deauthorize the device's pubkey in the registry.
- Works offline. No cloud service.
- No recurring cost. $50–$80 once.
Supported devices
Any device exposing PIV (Personal Identity Verification, PKCS#11-compatible) slots works. Tested:
| Device | Cost (USD) | PIV slots | Notes |
|---|---|---|---|
| YubiKey 5C NFC | ~$75 | yes | Most tested; widely available |
| YubiKey 5 NFC | ~$55 | yes | USB-A version |
| YubiKey Security Key NFC | ~$29 | FIDO2 only | Cheapest but limited |
| Nitrokey 3 NFC | ~$80 | yes | Fully open-source firmware |
| OnlyKey | ~$50 | yes | Open hardware + firmware |
Recommendation: YubiKey 5C NFC for most users (best tooling), Nitrokey 3 if firmware openness matters more than ecosystem support.
First-time setup
1. Install the tooling
# Debian / Ubuntu
sudo apt install yubikey-manager pcscd opensc
sudo systemctl enable --now pcscd
# macOS
brew install yubikey-manager opensc
# Arch
sudo pacman -S yubikey-manager opensc ccid
2. Verify the device is seen
ykman info
# Should print serial, firmware version, and enabled applications.
pkcs11-tool --list-slots --module /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
# Should list the YubiKey as slot 0.
3. Set a PIN and management key
Do not skip this. The factory defaults (PIN 123456, PUK 12345678) are publicly known. Change both now.
# PIV PIN (6-8 digits)
ykman piv access change-pin
# PIV PUK (used to unblock if you lock yourself out)
ykman piv access change-puk
# Management key (used for admin ops; 24-byte hex)
ykman piv access change-management-key --generate --protect
# --protect stashes the new key in PIV slot so you don't need to manage it
4. Generate an Oversight recipient key on-device
PIV has four main slots. Use slot 9d (Key Management) for Oversight. It is meant for decryption operations and does not require a PIN on every use (only first use per session, via cached auth).
# Generate an ECC P-256 key in slot 9d
ykman piv keys generate 9d --algorithm ECCP256 -
# Note: P-256, not Curve25519. See "Curve choice" below.
# Self-sign a cert so PIV treats the slot as initialized
ykman piv certificates generate 9d \
--subject "CN=oversight-recipient" \
--valid-days 3650 -
5. Export the public key in Oversight format
Oversight identities are JSON. We need to convert the PIV slot's public key to the format Oversight uses.
# Export the cert, extract the pubkey
ykman piv certificates export 9d - | \
openssl x509 -pubkey -noout -in - | \
openssl ec -pubin -text -noout
Write the resulting pubkey hex into an Oversight identity file with a
hardware: true marker:
{
"hardware": true,
"provider": "piv",
"piv_slot": "9d",
"p256_pub": "<hex of SEC1 uncompressed P-256 pubkey, 65 bytes>",
"ed25519_pub": null,
"device_serial": "<yubikey-serial>"
}
The p256_pub field corresponds to
Recipient.p256_pub in the manifest schema (see
SPEC.md § 4.1.3).
A hardware recipient leaves x25519_pub empty in the manifest;
classic recipients leave p256_pub absent.
Curve choice: why P-256 for hardware-backed recipients
The default Oversight suite uses X25519 for key agreement. PIV-compatible hardware devices historically only supported P-256 and P-384 for PIV slots. YubiKey 5.7+ firmware does support Curve25519 via a dedicated OpenPGP applet, but PIV itself does not.
To stay compatible with the broadest set of devices (Nitrokey, OnlyKey,
older YubiKeys), Oversight uses P-256 ECDH for
hardware-backed recipients. The suite identifier in the manifest becomes
OSGT-HW-P256-v1 instead of OSGT-CLASSIC-v1.
The crypto is just as strong: P-256 ECDH is NIST-standardized,
FIPS 140-3 compliant, and battle-tested.
Open clients that want to decrypt for hardware-backed recipients must support both suites. The default file-backed provider stays on X25519.
Opening a sealed file with a hardware-backed key (CLI)
# Insert YubiKey. You may be prompted for PIN.
oversight open --input secret.sealed --output secret.txt \
--recipient-hw piv:9d
# First op prompts for PIN; subsequent ops within the session don't.
Under the hood, this calls PKCS#11 C_DeriveKey to run ECDH
against the on-device private key, then runs the standard Oversight
HKDF + AEAD decrypt on the host. The raw private key never leaves the
device.
Status: the trait and the protocol-level decrypt path are
implemented in oversight-rust/oversight-crypto and
oversight-rust/oversight-container as of v0.4.10. The
--recipient-hw CLI flag and the underlying
PivKeyProvider are the next follow-up.
Revocation
If a device is lost, stolen, or retired:
- POST to the registry:
POST /recipients/{recipient_id}/revoke Authorization: Bearer <issuer_token> {"reason": "device_lost", "replaced_by": "<new_pubkey_hex>"} - The registry appends a revocation event to the tlog with a qualified RFC 3161 timestamp. Anyone verifying future sealed files addressed to the old pubkey will see the revocation in the event history and reject the file.
- Issue new sealed files to the recipient's new pubkey.
Note: the revocation does not un-seal already-delivered ciphertext. Any file the lost device opened before it was lost is already out. Revocation protects against future misuse of the device.
Threat model for hardware-backed keys
What hardware keys defend against
- Recipient laptop fully compromised, attacker has root, keylogger running: attacker cannot exfiltrate the private key. Can only ECDH while the device is plugged in. Discrete events.
- Recipient's encrypted laptop is stolen while powered off. Attacker brute-forces disk. Gets nothing useful because the PIV key is on the YubiKey.
- Malware on recipient's machine installs a background decryption job. Hardware-backed means each ECDH requires the device to be plugged in and (optionally) a touch. Attacker cannot do it passively.
What hardware keys do NOT defend against
- Recipient's laptop compromised while the YubiKey is
plugged in. Attacker can call PKCS#11 to do ECDH against any file the
legitimate client could.
Mitigation: require touch-to-decrypt (YubiKey PIV policy
always-require). - Physical theft of both laptop and YubiKey. Attacker has everything needed. Mitigation: strong PIN; device auto-locks after N wrong PINs.
- A supply-chain-compromised YubiKey. Vendor-independence is the only mitigation, and is why Oversight supports Nitrokey / OnlyKey alongside.
Known hardware caveats
- PIV key operations count against the device's attempt counter. YubiKey PIV defaults to 3 attempts before locking. Set a reasonable limit and keep a PUK to recover.
- Touch policy trade-off.
always-require-touchis more secure but requires user interaction on every open.cachedtouches (one per session) is the usual compromise. - No post-quantum yet. Current hardware keys do not
support ML-KEM / ML-DSA. Hardware-backed recipients are
OSGT-HW-P256-v1only for now. For PQ protection, use a file-backed recipient with the hybrid suite, or wait for hardware-native ML-KEM support (YubiKey and Nitrokey have hinted at late-2026 / 2027 firmware).
Checklist before deploying to real recipients
- ☐ PIN and PUK changed from factory defaults.
- ☐ Management key rotated.
- ☐ Touch policy decided (always vs cached vs never).
- ☐ Device serial recorded in a separate, encrypted inventory.
- ☐ Recovery procedure documented (if device lost, who is notified and how).
- ☐ Backup strategy: issue each recipient TWO devices (primary + backup), register BOTH pubkeys, seal to both, store backup in a safe.
- ☐ Revocation playbook tested end-to-end on a test recipient.
Further reading
- YubiKey PIV documentation: developers.yubico.com/PIV/
- NIST SP 800-73-4 (PIV Interfaces): csrc.nist.gov/pubs/sp/800/73/4
- Nitrokey 3 PIV: docs.nitrokey.com/nitrokey3
- Oversight protocol spec, § 4.1.3
OSGT-HW-P256-v1: SPEC.md - v0.4.10 release notes: v0.4.10: A Trait for Hardware Keys, and Why P-256