telekom-mms / sectpmctl

sectpmctl - Secure Boot and TPM2 backed LUKS full disk encryption
GNU General Public License v2.0
13 stars 4 forks source link

PCR7 only? #5

Open hede5562 opened 2 years ago

hede5562 commented 2 years ago

First thanks for the work. Currenty I do not know any simple management solution for LUKS-FDE with TPM+SecureBoot that just works. The one I'm currently using has its own drawbacks.

One question regarding: export PCR_VALUES_TO_USE="7"

It seems you are sealing to PCR7 only? AFAIK other solutions are sealing to more PCRs or at least recommend to do so. (AFAIK even Bitlocker does so)

Without PCR1 the BIOS-password can get reset. Without PCR4/5 the bootloader can get exchanged. And without PCR0 even the full firmware (BIOS/UEFI) can get exchanged. All without changing PCR7 and thus the TPM releasing the key to the attacker.

Are there other measures which do help here? Like for example to wipe the Secure Boot DB if anything of the above happens?

I'm refering to statements like the following, which maybe is outdated nowadays:

PCR0 contains the static root of trust measurement, as well as BIOS code measurements. These measurements cannot be spoofed because they are rooted in hardware. The validity of PCR1–PCR7 rests on the validity of PCR0. That is, PCR1–PCR7 can only be trusted if the PCR0 measurement is known to be good.

-- Futral, W., Greene, J. (2013). Fundamental Principles of Intel® TXT. In: Intel® Trusted Execution Technology for Server Platforms. Apress, Berkeley, CA. https://doi.org/10.1007/978-1-4302-6149-0_2

duxsco commented 2 years ago

IMHO, PCR7 is sufficient and the people from systemd concur (manpage link). I personally use only PCR7 for my Gentoo Linux setup with both clevis and systemd-cryptenroll.

hede5562 commented 2 years ago

It's sufficient if there are other means for protecting the boot process. Therefore I'm asking for that.

For example if only signed firmware updates can get installed (and all signed firmware updates are trustful, of course). And if changing BIOS configuration like removing a pin/password or booting some non-trusted OS means deleting the SecureBoot data. etc. Then it sounds reasonable to only use PCR7.

heikemms commented 2 years ago

First thanks for your interest.

Regarding your question:

It seems you are sealing to PCR7 only?

Actually we are not using PCR 7 only. We use a set of PCR values - you can find them in the code: For default installations these are: 7,8,9,11,14

For (one time) preseed usage these are: 0,8,9,11,14

The first Problem is that only 8 values can be used, we might have to kick PCR 8 and 9. Depending on the use case a recovery key, a reboot followed by another reboot or authorized policies are necessary.

duxsco commented 2 years ago

I wonder what role GRUB plays if you use systemd-boot: https://media.ccc.de/v/froscon2022-2766-sectpmctl_fur_luks_full_disk_encryption_fde#t=318

reitzrobert77 commented 2 years ago

I wonder what role GRUB plays if you use systemd-boot: https://media.ccc.de/v/froscon2022-2766-sectpmctl_fur_luks_full_disk_encryption_fde#t=318

This PCR list originates from analysing the Ubuntu 22.04 default installation which including GRUB as default. That way was one step in front the insight to not wanting to use GRUB as bootloader.

duxsco commented 2 years ago

I didn't clarify enough. @heikemms wrote of PCR8/9, but you use systemd-boot.

reitzrobert77 commented 2 years ago

Ok, I understand now. sectpmctl specifies to not use shim and GRUB, therefor PCR 8, 9 and 14 have to be null. The LUKS key is sealed to this null values as well. Unsealing would not be possible if somehow shim or GRUB is used. Indeed, this is maybe a bit redundand,

The LUKS key is sealed to the following PCR's and values:

PCR value
7 Secureboot state
8 null
9 null
11 LUKS header *
14 null

* PCR 11, the LUKS header, has a special purpose. After unsealing the LUKS key in the initrd, PCR 11 is extended with a random value. That blocks a second unsealing without having to extend a more meaningful PCR like 7.

reitzrobert77 commented 2 years ago

Currently I see five different implementations to support binding to PCR 0 and 7 (including others >7) while also supporting BIOS updates as well. Either way, the user has to signal that a BIOS update will occur next e. g. by executing 'sectpmctl tpm biosupdate'

  1. Ability to foresee the next PCR 0 value
    1. Having three reboots without the recovery key and without authorized policies
      • Enter the biosupdate command. A special update initrd get's installed, reboot.
      • In the initrd the current LUKS key is unsealed and sealed again in a second handle to PCR 0 (with the foreseen value) and PCR7. A message is shown that the user can now update the BIOS.
      • After the BIOS update initrd unseals from either the first handle (BIOS update unsuccessful) or the second one (BIOS update successful). In case of a successful update the unsealed key is sealed to the curent PCR 0 and 7 into the first handle and the second handle is removed. Otherwise the second handle is removed.
    2. Using authorized policies with two reboots and without the recovery key
      • Enter the biosupdate command. A new set of PCR values is authorized (the new foreseen PCR 0 and the current PCR 7), reboot
      • Update the BIOS and reboot. The boot then will succeed with either the first set of PCR values or the new set. In a systemd start script, if the BIOS update succeeded, the first set can be removed, otherwise the second set can be removed.
  2. No ability to foresee the next PCR 0 value
    1. Using the recovery key with two reboots and no authorized policies
      • Enter the biosupdate command. A special update initrd get's installed, reboot.
      • Update the BIOS and reboot. The initrd will show a message that you have to enter the recovery key now to complete the BIOS update. With this key, a new LUKS TPM key is generated and sealed to the already updated PCR 0 and the current PCR 7.
    2. Having three reboots without the recovery key and without authorized policies
      • Enter the biosupdate command. A special update initrd get's installed, reboot.
      • In the initrd the current LUKS key is unsealed and sealed again to PCR 7 without PCR 0. A message is shown that the user can now update the BIOS.
      • Update the BIOS and reboot. The initrd the LUKS can key can be unseal and then sealed again to the already updated PCR 0 and the current PCR 7.
    3. Using authorized policies with two reboots and without the recovery key
      • Enter the biosupdate command. A new set of PCR values is authorized with PCR 7 and without PCR 0, reboot
      • The boot then will succeed with either the first set of PCR values or the new set. If the BIOS update succeeded, both sets will be removed. In a systemd start script a new set is authorized with the already updated PCR 0 and the current PCR 7. If the BIOS update failed, the second set can be removed.

Personally I would prefer 2.iii. Another benefit from using authorized policies is to being able to seal to PCR 0, 4 and 7. Sealing to PCR 4 as well is then very cheap and prevent abusing broken Secure Boot enforcements in internal EFI shells. I have seen a very unfunny demonstration of abusing the internal EFI shell in this QEMU example:

https://github.com/HackingThings/OneBootloaderToLoadThemAll/tree/main/QEMU_UEFI

reitzrobert77 commented 2 years ago

Regarding

... Without PCR4/5 the bootloader can get exchanged. ...

That will not be the case, the bootloader (PCR 4) is signed with the Secure Boot db key and is therefor protected by Secure Boot and verified by PCR 7. Does changing the partition table (PCR 5) cause any harm?

Anyhow, my wish is to also include PCR 4 as written in my last comment.

hede5562 commented 2 years ago

Leaving PCR7 by default is absolutely fine for me as, yes, with SecureBoot and PCR7 there CAN be a trust chain. And even if not, it's maybe still sufficient for several use cases. But some official* optional feature to add additional PCRs (for example within the configuration process) shouldn't do any harm. So thank you for giving it a serious consideration.

Maybe some people want to go the way of a TPM based trust-chain (including the UEFI code itself, via PCM0 and up) just to get rid of the risk of hacked UEFI (which probably is some real risk). Remember: You are favouring PCR7-only indeed just because the UEFI Code can get exchanged completely without breaking PCR7. It's the data that gets extended to PCR7, not the code which is using this data, not the implementation which is responsible for actually using the data which got extended to PCR7.

*) Btw I call it "official" because naturally there is an inofficial option to also include other PCRs already present. The Code is Open, you know. ;-) (think of something like using export PCR_VALUES_TO_USE="1,2,4,5,7"; ... )

reitzrobert77 commented 2 years ago

Thanks for your input. These reasons why to use PCR7 had impressed long time ago even when I didn't know at all how to achieve using PCR7 ;-) I would keep it default and use options for the other PCR values. But, when I read your reference that PCR0 is the root of all trust....

I guess it's not possible in a managed way just to include a string list like "0, 3, 4" or so because each PCR value needs special treatment. So would opt for dedicated options like --pcr-bios --pcr-gpt --pcr-optionrom-config to give a guided process to the user on how to use it.

When you use --pcr-bios and tell the tool that a BIOS update would occour it will generate neccessary helper files for example. The --pcr-bios-config or --pcr-gpt option shouldn't need helper scripts at all. My fear is simply that the TPM doen't open the key and maybe you know why or maybe not. Then the debugging starts to see if it is safe to enter the recovery key or not because e.g. some bad bootloader want to go into the chain.

But all of them are solveable with a dedicated process or by documenting the actual use.

Another thing made be nervous a bit when playing with the QEMU patch.nsh example from the OneBootloaderToLoadThemAll example code. It seems to simply patch the internal UEFI shell by two nm commands to disable Secure Boot. When that happens, someone would find probably a blank untouch PCR7 register which contains:

The missing certificate can then simply measured by the attacker, he would use our db certificate, and can in turn open the LUKS key.

Combining PCR4 together with PCR7 will solve this hole, combined with PCR0 it seems to bring the security a bit further.

Administrative overhead of using PCR4 and PCR7 is relative low when authorized policies are used anyway. After signing the EFI blob with the db key, a new set of authorized policies is created which contain the hash of the EFI blob. These policy authorization files need to be put along side the EFI blob. And with that mechanism a dual boot is enabled to support binding to the BIOS code with PCR0 or not to bind to it when doing the BIOS update, while always binding to at least PCR 4 and 7.

Normal boot: PCR0, 4, 7 BIOS update boot: PCR 4,7

hede5562 commented 2 years ago

But, when I read your reference that PCR0 is the root of all trust....

That's indeed a statement from before the SecureBoot era. If SecureBoot works, is 100% correct implemented, UEFI Updates are signed and circumventing the BIOS/firmware password is either impossible or breaks SecureBoot, then SecureBoot is probably able to replace the TPM in this regard.

The thing is, AFAIK, SecureBoot for securing the UEFI has broken several times but TPMs are rock stable nowadays. The UEFI and its SecureBoot implementation is quite complex, compared to a TPM. Therefore I do trust the TPM a little more. But with a big AFAIK. It's still vague for me.

reitzrobert77 commented 2 years ago

When doing a recovery key-less authorized PCR0 update, it will be even possible to do a unattended PCR7 update to include the latest dbx UEFI DB, even if the dbx DB will and should never be "used" by sectpmctl. Not sure if that would be worth spending time.

reitzrobert77 commented 1 year ago

It is better to split the issue into several parts: