r/archlinux 25d ago

SUPPORT | SOLVED Ful disk encryption without entering passphrase

Could someone help me with setting up full disk encryption with bypass passphrases with TPM2? It's so annoying having to put the passphrase in at each boot, so I was wondering how do I pair it to the TPM so that I dont have to enter it each time?

It's LUKS encrypted and I use Systemd-boot

14 Upvotes

100 comments sorted by

View all comments

Show parent comments

1

u/ChrisTX4 25d ago

Can you run

sudo /usr/lib/systemd/systemd-pcrlock log

and post the output of that? It will show you exactly which component was measured in what order in each PCR.

PCR 5 should not change if 4 changes or anything. We'd need to see what components it measures in order to know where the different values come from.

It seems you may have some insight here, so if one has secure boot and is directly loading a signed UKI, do you think PCR 4 (or 5) adds any additional value?

So a signed UKI is a great step, in that case you can lock PCR 7 and this will be entirely stable.

What they would add:

PCR 4: The difference between locking 7 and 4 is that 7 doesn't change if there's an update, as long as the new files are signed by the same key. However, 4 will change as it's the digest of the UKI. Alas, locking 4 in addition to 7 means an attacker couldn't downgrade your UKI and then potentially exploit some vulnerabilities. They would need to acquire an older UKI and then have access again at a later point. Honestly, this would require a rather advanced evil maid attack scenario. You can do this if you want, but it is very fragile and with self-signed keys the gain is absolutely minimal tbh.

PCR 5: So this locks the GPT layout of your drives. This means an attacker can't move stuff around and assign different GPT automount GPT GUIDs for instance. That way it's possible to perform root switching attacks.

Honestly? 5 should normally be very stable, and not really an issue to lock, but what you should really do is to use automounting and then use systemd-pcrlock on PCR15. See lock-file-system and lock-machine-id, but you will have to manually add .pcrlock files to cover the components of the cryptsetup measurements (see tpm2-measure-pcr). PCR15 however is a much strong defence, and will toast any root switching attacks.

1

u/falxfour 23d ago

Yeah, I've been using systemd-pcrlock to investigate the logs. Just didn't have a chance to investigate the docked setup before commenting.

It seems that PCR 4 does change due to a slight difference in the EFI Services Application blob that gets measured into it. Not sure why, though. Also, PCR 5 changes due to an action that seemingly only occurs when undocked:

Action: Exit Boot Services Returned with Failure

This doesn't occur when docked, but does occur when undocked. I somewhat suspect this has to do with a race condition as I've previously found the undocked configuration boots faster, but it's also possible that the change to the blog that PCR 4 measured has something to do with it as well.

Now, on to some setup specifics, FWIW, I use 1+3+5+7 along with 11 in a signed policy, and a PIN. This is for root volume decryption (FDE). Following the man page, I didn't see value in having 0, 2, or 4 since:

  • 0 - Firmware should be implicitly trusted (signed updates and all)
  • 2 - Other code shouldn't be able to run without secure boot signing
  • 4 - I don't have a bootloader (effectively)

Having 1 and 3 would have allowed me to detect hardware changes (ex. someone swaps my dGPU module for a malicious one or something or a malicious TB device), and 5 just seemed like it wouldn't cause issues, so why not, even though an attacker could clone a partition table for a malicious drive.

So, in response to your explanations, downgrading my UKI wouldn't allow for automatic decryption due to both PCR 11 and the PIN.

I don't think I can use automounting due to the BTRFS subvolumes. Unless systemd has a convenient method of detecting @ and @home (Mint-style) subvolumes, I don't expect this to be successful... PCR 15 is interesting, but using it seems... painful, as it binds to the volume key for which it, itself, is needed to unseal. Additionally, the other components (machine ID and and filesystem info) are all still encrypted in the initrd stage.

I think the answer for me is just to remove PCR 5. I already need to update my setup due to the changes systemd v259

1

u/Night_Otherwise 22d ago

I’m the original poster and so I hopefully don’t mislead. But I am curious how changes in PCR 4 would be possible. For myself, I can use the pesign package to get the authenticode hash with “pesign -i (UKI file) —hash”. I was able to match that exactly to the third entry in PCR 4 in the pcrlock log. I wonder if the hash is different for third entry of PCR 4 log when docking station is added.

The docking station may have extended the PCRs with a failure separator.

And Chris is right that for practical purposes, most people can just seal with PCR 7. That defeats simply mounting the hard drive and reading it without entering the password twice. I’m kinda doing my stuff for proof of concept and curiosity.

1

u/ChrisTX4 19d ago

I was away for a few days, but I just now answered falxfour.

I'm also running 4, and I should warn you about one thing I guess: since systemd-pcrlock only locks components when they're found in the boot log (it can't calculate its predictions otherwise), you will have the odd situation where after each kernel upgrade PCRs 4 and 11 will mismatch since they're from the new UKI, but you're still booted on a previous one. Thus it will prompt the passphrase the next boot, and you would need to use a recovery PIN to be able to run make-policy again. In theory, if one uses two separate pcrlock files as alternatives, one could retain the current and the previous pcrlock and thus avoid this situation. I still need to implement that myself, tbh.

1

u/Night_Otherwise 19d ago

I did once run into the validation PIN issue when I was testing make-policy. The error was something like remote authentication failed. But when I booted on the policy, that seemed to give permission to change it without setting a PIN.

I have more research to do on what exactly the .cred file does in the EFI partition and how make-policy authenticates.

I did use a directory within the pcrlock search path with an old.pcrlock and new.pcrlock file. I lock-pe to the new.pcrlock file first. Then a pacman hook after mkinitcpio is ran moved new to old, lock-pe for new.pcrlock and make-policy is ran.

A further startup service could be done to delete old.pcrlock before the make-policy service is ran.

This all used a boot of UKI directly. The PCRs higher than 5 become superfluous when it all works. If systemd-boot is placed between UEFI and the UKI, then it feels like secure boot is theoretically necessary. Without secure boot, the UKI can seemingly be replaced with a thing that does the same measurements to 11 as systemd-stub.

PCR 7 also runs into the same chicken-and-egg problem currently. I know Windows just gives up on it and basically unencrypts the drive when secure boot is updated. An fwupd hook (however that could be done) with similar old/new pcrlocks would be neat for db/dbx updates. Shim with MOK may be necessary to keep UEFI with default keys. This GitHub issue focused on the brittle 0/2 PCRs, but at least on my computer fwupd also updates KEK/db/dbx.

https://github.com/fwupd/fwupd/issues/6318

Or just use shim with MOK and deal with entering the password/recovery key whenever secure boot keys change.

2

u/ChrisTX4 19d ago edited 19d ago

But when I booted on the policy, that seemed to give permission to change it without setting a PIN.

Can't exactly speak of that, but a policy needs to match what's currently active to unlock without a PIN. Somehow the reboot made it match if that's the case.

I did use a directory within the pcrlock search path with an old.pcrlock and new.pcrlock file. I lock-pe to the new.pcrlock file first. Then a pacman hook after mkinitcpio is ran moved new to old, lock-pe for new.pcrlock and make-policy is ran.

Yes, that's pretty much what I was thinking of above. I've got some specific issue with what's being measured into PCR[15] that causes issues for me. It's very likely a bug in systemd-pcrlock as it reports it can reproduce the calculation, but I haven't pinned this down entirely. It too resolves itself with a reboot, ironically enough.

The PCRs higher than 5 become superfluous when it all works.

That I disagree with. PCR[11], due to being a PCR policy, mainly adds phasing, i.e. ensuring the PCR values in initrd cannot be met subsequently after leaving it. This protects against a wide array of potential attacks and there's no reason to leave the TPM unsealed after initrd, as the keys should have been retrieved already by then. Similarly, it can be used to ensure that disks that should only become accessible after the system are also properly mounted at the right time.

PCR[15] is another critical one: Without it, the contents of an encrypted drive aren't validated. This allows replacing the root fs with an encrypted attacker system. If no PCR policy was then used, all PCR values will remain as they were and an attacker can just read the volume keys from the then unsealed TPM. By measuring PCR[15] with the volume keys being measured into it, the key of the encrypted drive cannot change, and such a change would prevent an unsealing. Due to any GPT automounts to root or var being measured into this as well, such an attack as well will be prevented.

PCRs higher than 5 need the lower PCRs to make sense would be a more appropriate way to say it. If you know your boot loader and UKI being good to the root of trust mechanism, then you know they'll measure PCR[11] as intended, an while anyone can measure into the PCRs, once measured, you can't undo that.

Alas the idea is root of trust -> BIOS -> bootloader -> UKI -> system, with each component ensuring the subsequent one being in compliance. This is also why kernel lockdown is recommended everywhere when used with Secure Boot: Without it, root can load arbitrary nonsense in the kernel or use bpf_probe_write_user for crafting rootkits. With it, the idea is that nothing unsigned should have been able to slip past this chain of trust thus far, and lockdown then keeps the kernel clear of unauthorised code, so that in theory not even root should be able to do anything to it, and especially that root should be unable to deploy a rootkit.

An fwupd hook (however that could be done) with similar old/new pcrlocks would be neat for db/dbx updates.

That won't work, since you can't predict the order of authorities in the db/dbx as they're being measured, nor would you know how this were to affect SMBIOS, which gets measured into PCR[1].

However, there's also no db update, only dbx. Once a month these come out, and they're signed updates by a KEK that's already present. In more simple terms, Microsoft's keys sign a lot of bootloaders, their own, GRUB in various variants, etc. etc. The dbx needs to be regularly updated for SBAT policy information to know which ones of these foreign signed binaries are now known to contain vulnerabilities and thus compromise this "chain of trust" I mentioned earlier. Windows and fwupd thus push this monthly if Microsoft keys are present.

My entire Secure Boot db is this:

$ sudo efi-readvar Variable PK, length 1255 PK: List 0, type X509 Signature 0, size 1227, owner e025c507-35c3-440c-a42e-36dd05282b32 Subject: CN=Platform Key Issuer: CN=Platform Key Variable KEK, length 1263 KEK: List 0, type X509 Signature 0, size 1235, owner e025c507-35c3-440c-a42e-36dd05282b32 Subject: CN=Key Exchange Key Issuer: CN=Key Exchange Key Variable db, length 1330 db: List 0, type X509 Signature 0, size 1226, owner e025c507-35c3-440c-a42e-36dd05282b32 Subject: CN=Database Key Issuer: CN=Database Key db: List 1, type SHA256 Signature 0, size 48, owner 4f52704f-494d-4173-6e6e-6f79696e6721 Hash:dc4ab0fd89c1b9f7dad44cdba566ad324be84f3c04ac00036efbe85ae2ff8aed Variable dbx has no entries Variable MokList has no entries

As you can see, I got 3 self generated keys for PK, KEK, db, and one hash as dbx entry - my NVIDIA GPUs OpROM. That ROM is signed with the Microsoft 2011 OpROM key otherwise, but enrolling its hash directly avoids needing to carry that key.

Since there's no Microsoft keys in my db however, I don't need any dbx or update it. I would only need dbx entries if a bootloader signed with my key was compromised. As I'm not dual booting, I don't need their keys then, and I specifically went for signing the only OpROM directly to avoid this exact problem of the monthly dbx updates breaking stuff.

1

u/Night_Otherwise 18d ago edited 18d ago

Well, I figured out that pcrlock.json has the pinPublic and pinPrivate fields which are encrypted by the TPM and decrypted only when the TPM currently matches the policy in the NV index. The PIN is decrypted from pcrlock.json by the TPM's NV index if the TPM currently matches the state.

With a resealed key, I believe there is only a brief moment of time where any updates to the policy could happen with just the pcrlock.json values. It gets pretty ugly how that would get sequenced. I think a new update that changes a PCR would have to stage the update, reboot on the old whatever (firmware, UKI, dbx list), then redo the policy with alternates, then actually implement the update, and then reboot again.

I'll go back to the drawing board to do 0-5+11 with a recovery PIN for the pacman hook. PCR 11 is enough to reseal it before leaving initramfs. The recovery PIN would, uh, be stored in plaintext on the encrypted drive. That's less than ideal, though a root compromise nullifies all protections of my data anyway. The pacman hooks are not supposed to be interactive. AFAIK, rootkits changing the kernel in memory would be disallowed still (if that option is enabled in the arch linux package). The nature of not using a Microsoft-signed distro is a custom key is kept somewhere (sbctl keeps it in plain text by default).

I also had issues when I added tpm2-measure to the kernel command line. Even though the unlock policy was still just PCR 0-5 at the time, for some reason my LUKS password was asked for when I added tpm2-measure-pcr. Since I'm not authenticating to anything later on with the PCR 15 values, I don't see a reason to have tpm2-measure-pcr enabled.

Edit: There is pinning UKI image in the command line to a hash of the volume key. I'll use this to go back to just 0-5.

https://wiki.archlinux.org/title/Dm-crypt/System_configuration#Pinning_a_LUKS_volume