/ Documentation / CLI reference / luksbox migrate-fido2-slot

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

  1. Opens the vault using whatever unlock material --unlock-with provides (typically the FIDO2 slot you're about to migrate).
  2. Verifies that the target slot is a Fido2HmacSecret slot 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.".
  3. 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.
  4. Writes the new V4 slot into the first free index in the vault.
  5. Revokes the original slot (zeroes its wrapped MVK ciphertext, tag, nonce, KDF salt, and cred_id).
  6. 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

After migration

See also