luksbox migrate-fido2-slot
Migrate a pre-v0.3.0 FIDO2 keyslot to the cross-platform v0.3.0 (V4) wire convention.
luksbox migrate-fido2-slot [OPTIONS] --slot <N> <PATH>
Migrate a pre-v0.3.0 FIDO2 keyslot (V1 / V2 / V3 wire convention, Linux- and macOS-only) to the v0.3.0 cross-platform V4 convention. After migration the new slot unlocks the vault on Linux, macOS, and Windows alike.
Run on Linux or macOS. The migration needs to unlock the vault through the old slot first, and the old slot only works on libfido2 platforms. Windows can't read pre-v0.3.0 FIDO2 slots at all.
What it does
- Opens the vault using whatever unlock material
--unlock-withprovides (typically the FIDO2 slot you're about to migrate). - Verifies that the target slot is a
Fido2HmacSecretslot and that its on-disk AAD version is less than V4. If the slot is already V4, it refuses with"already V4 (cross-platform). Nothing to migrate.". - Prompts you for the FIDO2 PIN, then asks you to touch the
authenticator twice:
- First touch: register a brand-new credential on the same authenticator. The credential is fresh — the cred_id bytes differ from the original slot's cred_id.
- Second touch: derive the hmac-secret output for the new wrap KEK, using the V4 (prehashed-salt) wire convention.
- Writes the new V4 slot into the first free index in the vault.
- Revokes the original slot (zeroes its wrapped MVK ciphertext, tag, nonce, KDF salt, and cred_id).
- Persists the header (sidecar mirror + live overwrite, same as any other keyslot mutation).
The new slot has a different index from the old one because
revoke happens after enroll. Existing scripts that pin slot 0
will need to point at the new index; run luksbox info after
migration to find it.
Why migration is needed (one-line version)
libfido2 (Linux/macOS) sends the raw hmac-secret salt to the
authenticator. webauthn.dll (Windows) SHA-256 prehashes the same
salt before forwarding it, per the W3C WebAuthn Level 3 PRF spec.
Same authenticator, two different HMAC outputs, two different
wrap KEKs. V4 slots on Linux apply the prehash explicitly, so
both backends converge on HMAC-SHA256(device_secret, SHA-256(salt)).
Examples
Single-slot migration
# On Linux or macOS, with the YubiKey plugged in.
luksbox info my.lbx
# keyslots:
# 0: fido2 (cred_id=fa3b... 64 B)
# compat: V3 Linux/macOS-only -- migrate with `luksbox migrate-fido2-slot my.lbx --slot 0` for cross-platform unlock
luksbox migrate-fido2-slot my.lbx --slot 0
# Enter FIDO2 PIN: ******
# Touch your YubiKey to register a fresh V4 credential to replace slot 0
# Touch your YubiKey again to derive the new keyslot secret
# migrated FIDO2 slot 0 -> slot 1 (V4, cross-platform). Original V3 slot has been revoked.
Now plug the YubiKey into a Windows machine running v0.3.0 and the vault opens.
Multi-slot migration
If the vault has more than one pre-v0.3.0 FIDO2 slot, migrate them one at a time. Each call needs its own pair of touches and burns one free slot index, so a 3-slot vault with 5 FIDO2 slots cannot be fully migrated in place — revoke unused slots first.
for slot in $(luksbox info my.lbx | awk '/^ +[0-9]+: fido2/{print $1+0}' | sort -u); do
luksbox migrate-fido2-slot my.lbx --slot $slot
done
What this does NOT migrate
-
Fido2DerivedMvkslots (--kind fido2-directat create time): the MVK is derived directly from the authenticator output via HKDF, so there's no wrapped MVK to re-wrap. Migration would require recreating the vault with a new MVK and re-encrypting every chunk. Not implemented in v0.3.0. -
Fused TPM + FIDO2 slots (
Tpm2Fido2) and hybrid-PQ-FIDO2 variants: these read the hmac-secret output and mix it into a more complex KEK derivation. Migration is conceptually straightforward (re-enroll with V4 + revoke), but the migration command currently rejects them with"Only wrap-style FIDO2 keyslots can be migrated with this command."Workaround: add a backup passphrase slot, use it from Windows, and migrate these in a follow-up release.
After migration
- The new slot's
compat:line inluksbox infoshowsV4 cross-platform (Linux/macOS/Windows). - The old slot's index becomes
emptyin the table. - Existing v0.2.x backups of the vault are unaffected — they still hold the V3 slot bytes and continue to open under the original convention on Linux/macOS.
- Cross-platform workflow: open the vault on Windows with the same authenticator + PIN; unlock succeeds because the new V4 slot uses the same SHA-256(salt) input on both backends.
See also
enroll— add a fresh keyslot from scratch (the v0.3.0 enroll path always writes V4 slots, so new enrollments don't need migration).info—luksbox infoshows each FIDO2 slot's V_x_ compat status and points at this command for pre-v0.3.0 slots.revoke— what migration does internally to the old slot.