How to switch keyslots during boot decryption/unlocking when having a LUKS TPM2-keyslot with PIN?

Note: I configured this on Bazzite, which is “just” based on Fedora. However, as it all is using standard systemd/LUKS etc. components I have strong reasons to assume, the same problem appears on any Fedora or even on any Linux that uses this. Aka this has been originally posted on the Bazzite community.


What I did

I used the ujust setup-luks-tpm-unlock command, which uses the script /usr/libexec/luks-enable-tpm2-autounlock, which in the end also just uses systemd-cryptenroll.

However I added a PIN for the TPM2 for added security. So the command likely is like this:

$ systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7+14 --tpm2-with-pin=yes "$CRYPT_DISK"

I had a password for LUKS setup before, and I want to keep it, also as a recovery path or e.g. for having multiple people to have different unlock methods.

One can also see that both keyslots are still in there:

# systemd-cryptenroll ****
SLOT TYPE    
   0 password
   1 tpm2
# cryptsetup luksDump /dev/disk/by-uuid/****
LUKS header information
Version:        2
Epoch:          5
Metadata area:  16384 [bytes]
Keyslots area:  16744448 [bytes]
UUID:           ******
Label:          (no label)
Subsystem:      (no subsystem)
Flags:          (no flags)

Data segments:
  0: crypt
        offset: 16777216 [bytes]
        length: (whole device)
        cipher: aes-xts-plain64
        sector: 512 [bytes]

Keyslots:
  0: luks2
        Key:        512 bits
        Priority:   normal
        Cipher:     aes-xts-plain64
        Cipher key: 512 bits
        PBKDF:      argon2id
        Time cost:  7
        Memory:     1048576
        Threads:    4
        Salt:       ******
        AF stripes: 4000
        AF hash:    sha256
        Area offset:32768 [bytes]
        Area length:258048 [bytes]
        Digest ID:  0
  1: luks2
        Key:        512 bits
        Priority:   normal
        Cipher:     aes-xts-plain64
        Cipher key: 512 bits
        PBKDF:      pbkdf2
        Hash:       sha512
        Iterations: 1000
        Salt:       ******
        AF stripes: 4000
        AF hash:    sha512
        Area offset:290816 [bytes]
        Area length:258048 [bytes]
        Digest ID:  0
Tokens:
  0: systemd-tpm2
        tpm2-hash-pcrs:   7+14
        tpm2-pcr-bank:    sha256
        tpm2-pubkey:
                    (null)
        tpm2-pubkey-pcrs: 
        tpm2-primary-alg: ecc
        tpm2-pin:         true
        tpm2-pcrlock:     false
        tpm2-salt:        true
        tpm2-srk:         true
        tpm2-pcrlock-nv:  false
        tpm2-policy-hash:
                    ******
        tpm2-blob:  ******
        Keyslot:    1
Digests:
  0: pbkdf2
        Hash:       sha256
        Iterations: 122040
        Salt:     ******
        Digest:   ******

Problem

Now, when booting, one can enter the PIN and TPM-unlock works flawlessly. The problem is: There is no way to still use the passphrase that I can see - despite it being still available as a keyslot.

When booting and I am at the unlock screen, I can press Esc to see all log details. And there you can see it similar to “Requesting PIN for TPM:”.
If one enters the wrong PIN there, the requests just keeps showing up.

Does not this make having a recovery passphrase a moot point? If I cannot switch to it to use it for unlocking in practice.
Say I e.g. forget my TPM PIN. I cannot unlock and boot the device anymore?

Note I know I may be able to unlock it by booting some live system etc. and then maybe remove the tpm keyslot. But really, this is no useful point.

What I would have expected

Maybe to just take the entered “PIN”, which is also just like a “password” (aka it does not have to be numeric at all), and also check it against the passphrase keyslots.
If anyone unlocks that is fine, the user provided the correct one.

Alternatively though IMHO not that sleep: Somehow allow the user to switch authentication methods, at least when entering one does not work.

Another use case: multi-user

Also, to demonstrate a use case here why that may be useful beyond simple recovery is: multi-user setups. Linux is good for multi-users to use and at userland has good user segregation. However to decrypt an encrypted disk at startup, sharing a password would be bad. So either add a new password or TPM-unlock?
That said, people are reasonably weak at choosing passwords and in general, I thought, yeah using TPM2 surely can only increase security here, after all you can couple it with the PIN. The idea was: Unlocking works with the usual password and TPM2 with PIN.

Apparently, that does not work and just because of a “input/password request” problem. Technically, as far as I see, everything is set up for it. And that’s sad.
Or is there anything one can do here?

Docs

I checked multiple LUKS and systemd-cryptenroll docs, but found this special case (TPM with PIN) nowhere to be explained in detail.


Cross-posted in the Fedora community.

Let me check I understand what the problem is.

You cannot get a password prompt, only a PIN prompt?

If you boot a live USB image I’d expect that you can use cryptsetup open and it will prompt for a password. Is that the case?

For a multi-user setup you could enroll a passphrase for each user so long the number of users is less then the number of key slots.

Yes. There is no way to switch between these.

Will check, but I suppose it would, after all cryptsetup luksDump shows shows it has a keyslot.

If you want to use password just remove the pin. Pin takes priority and it is asked first always when setup it that way

But… as explained this defeats the purpose of having multiple unlock methods/a backup method?

Also what do you mean by “setup in that way” - is there a different setup that allows it not to take priority?

At boot with multiple keyslots enrolled, here’s the actual flow:
What happens:
systemd-cryptsetup (via plymouth/console) detects a TPM2-bound keyslot exists and automatically attempts to unlock using the TPM silently checking PCRs in the background
If TPM2 unlock succeeds and you set --tpm2-with-pin=yes, it prompts you for the PIN right away (this is the “first” prompt you see)
If you enter the correct PIN → unlocked, done
If the TPM2+PIN attempt fails (wrong PIN, or TPM/PCR mismatch from a firmware update etc.) → it does not silently retry it falls through to a generic passphrase prompt, where your original password keyslot works
Important nuance: it’s not “type PIN, then type password” as two sequential prompts for the same unlock. It’s one prompt that accepts either:
Correct PIN → satisfies the TPM2 keyslot
Correct full password → satisfies the separate password keyslot
Both prompts usually look identical (just “Please enter passphrase” or similar), so in practice you just type whichever one you remember PIN or full password into the same field, and LUKS tries it against all enrolled keyslots.
Caveat: behavior can differ slightly by initramfs (dracut vs. sd-boot’s own unlock UI) and Fedora version some setups show a distinct “Enter TPM2 PIN” prompt, and only fall to a separate password prompt after PIN attempts are exhausted or you press Escape/skip. If you want, tell me which Fedora variant/bootloader (GRUB+dracut vs UKI/sd-boot) you’re on and I’ll confirm the exact prompt behavior for that path.

Sorry, but I have to ask: Is your answer LLM generated or why is it so contradictory? (Explanation below)

This sounds to me as if the second prompt would be a new prompt? (aka “a generic password prompt”)

Here you say it’s one password prompt though?


Anyway, I tried it again and first thing it shows is (after Esc to show the details):

Please enter LUKS2 token PIN:

When entering the password there, it does not work. No matter, how many times I try.

Indeed, it does…

Is this hallucinated?
Because first of all, Esc just toggles between UI and log (as long as I remember LUKS this has always been the case). Secondly what should “pressing skip” mean? There is just no such thing…
Finally, “PIN attempts are exhausted”? How? Never noticed it. AFAIK TPM just does throttling, so it cannot actually be exhausted? And as said, I tried entering the “wrong” TPM PIN multiple times… without success.

In any case, this also is how it works currently.

It’s Bazzite so basically based on Fedora Atomic Desktops respectively Fedora Kinoite 44 (in this case).

Here the version data:

# grub2-install --version
grub2-install (GRUB) 2.12
# dracut --version
dracut 108-8.fc44

But as far as my research goes, the service actually asking for the password/PIN seems to be systemd-cryptsetup@.service (compare it’s man page) and systemd documents some password request logic here, which I do not quite understand though. That page/doc is rather for devs about how to implement such a password agent, not how the existing agent/behavior works.

So it’s version here, too:

$ systemd-cryptsetup --version
systemd 259 (259.8-1.fc44)
+PAM +AUDIT +SELINUX -APPARMOR +IMA +IPE +SMACK +SECCOMP -GCRYPT +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +KMOD +LIBCRYPTSETUP +LIBCRYPTSETUP_PLUGINS +LIBFDISK +PCRE2 +PWQUALITY +P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD +BPF_FRAMEWORK +BTF +XKBCOMMON +UTMP +SYSVINIT +LIBARCHIVE

Please use and read with caution…A feW years back, maybe 2 but not more than 3 i just used a a kernel flag:

rd.luks.options=tpm2-device=auto,tpm2-with-pin=yes
sudo dracut -f

If the TPM2 check fails (for example hardware change or incorrect PIN), the system will automatically fall back to the standard passphrase prompt.

If you are stuck on the TPM2 PIN prompt and need to bypass it, you can try pressing Ctrl+D or Escape to switch to the console, but this may not always work depending on Plymouth configuration.

If you are locked out, you must boot from a live USB and use cryptsetup to manage keyslots.

But this has been long enough to have another set of eyes on this one to verify.

I’m a tester so encryption is a pain in the backside for me now.

systemd-cryptsetup --version
systemd 262 (262-1.fc45)
+PAM +AUDIT +SELINUX -APPARMOR +IMA +IPE +SMACK +SECCOMP +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 +KMOD +LIBCRYPTSETUP +LIBCRYPTSETUP_PLUGINS +LIBFDISK +PCRE2 +PWQUALITY +P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD +BPF_FRAMEWORK +BTF +XKBCOMMON +UTMP +LIBARCHIVE

My daily Drivers are though:

 df -hT /run/media/me/ca689a88-c9d1-496f-b884-18040ac78054/
Filesystem                                            Type   Size  Used Avail Use% Mounted on
/dev/mapper/luks-c172b757-d7ba-4224-ac77-675a733e83db btrfs  222G   40G  181G  18% /run/media/me/ca689a88-c9d1-496f-b884-18040ac78054

it might be it might not i took from my notes bits here and more there and pasted all i use TPM LUKS autounlock now days always on all devices and servers so no promts at all. i did experiment this 2-3 years ago and sometimes checked again and using tpm with pin/password was never for me better just autounlock LUKS unsing TPM and if need recovery passphrase is needed when firmware updates comes

That configuration would be very interesting. Because by default Fedora, all Esc does – as I explained –, is switch to the console which shows, as I said, “Please enter TPM PIN:”. Nothing to bypass or similar…
Ctrl+D just seems to do the same as if I entered a wrong PIN, it just asks for the same PIN again.

BTW here is how that is shown visually (the image is a little too big as cut-of o the screen but anyway):

There I already pressed Ctrl+D/entered wrong PIN a few times.
As you can see, it explicitly exclusively asks about the PIN.

Hmm the script just uses --arg=tpm2-tss for the initframfs current (PIN or not is already set by systemd-cryptenroll after all).

But I would need to check whether that kernel arg really makes a difference.

Okay, as it uses rpm-ostree apparently, I modify it.

Note that it works/worked without any modification before:

# rpm-ostree kargs
rd.luks.uuid=luks-bd93a1******c10 rhgb quiet root=UUID=7878d4******96d1 rootflags=subvol=root rw ostree=/ostree/boot.1/default/7204eeacb2ecc84fe5153d40f4384522ca9b18a3cac12ec66a04f55d4b71a57a/0 bluetooth.disable_ertm=1 reserve_mem=64K:4096:ramoops pstore.backend=ramoops

Okay so, added as such:

# rpm-ostree kargs --append=rd.luks.options=tpm2-device=auto,tpm2-with-pin=yes

Did not change it though. It always just keeps requesting the PIN, no matter how often I enter a wrong one or press Ctrl+D.

I just tried it my self, and see the same results as you describe…:frowning:

I’m still looking at this though.

EDIT:1
OK don’t kill the messenger, I reached to someone I trust and this is the reply.

On Fedora 44, you cannot dynamically switch between a TPM2 PIN and a LUKS password at the boot prompt because the Plymouth interface does not provide a mechanism to toggle authentication methods.

  • Authentication Logic: The system attempts to authenticate using the TPM2 token if the hardware is present and the PCR values match; it does not fall back to the password keyslot if the PIN is incorrect or if you prefer to use the password instead.
    And a * Workaround: To use the password instead of the TPM PIN, you must either remove the TPM token from the LUKS header using systemd-cryptenroll --wipe-slot tpm2 or disable the TPM unlock configuration in /etc/crypttab.

I guess something like this might work:

sudo systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 --tpm2-with-pin=yes /dev/nvme0n1p1


Not what you asked about I know…

I hope someone can verify this much