[systemd-devel] Usage of PCR[7]
Adrian Vovk
adrianvovk at gmail.com
Mon Jun 5 20:37:41 UTC 2023
Hello all,
I'm working on a general-purpose distro modeled after the proposal
made in "Fitting Everything Together". I'm planning to, by default,
seal the data partition's encryption with the following PCRs:
- PCR[7]: If secure boot gets turned off, or keys get replaced -> fail
decryption
- PCR[11]: Wrong UKI / different edition of the OS / different OS ->
fail decryption
- PCR[14]: MOK changed (allow given binary to bypass secure boot, or
allow third-party sysext/kmods, etc) -> fail decryption
Here are some of the things measured into PCR[7]:
- Secure boot mode: user/audit/setup/etc
- PK
- KEKs
- DB (twice, apparently Shim measures it a second time:
https://github.com/rhboot/shim/blob/main/README.tpm#L15)
- DBX (twice, ditto)
- Other less common SB variables: DBT, DBR
- Shim's built-in DB
- Shim's built-in DBX
- Shim's other built-in hashes/certs
- MOK (maybe? uapi-group docs say no, Shim's docs say yes, but
comments from shim devs are conflicting)
- SBAT revocation data
Most of the things measured into PCR[7] align with our intent of
sealing it to the decryption key. If any of the
mode/PK/KEKs/DB/DBT/DBR change, then it becomes possible to circumvent
the OS's chain of trust. However, this does not apply to all
variables:
- Shim's built-in DB: This is controlled completely by the OS and
verified by the firwmare's DB, so it cannot be used to bypass the
chain of trust. A distro may want to swap out their signing keys for
whatever reason
- Shim's other build-in hashes/certs: Ditto
- DBX: Revoking vulnerable boot components does not allow any bypass
of the chain of trust, because it can only take away the permission to
run from a binary that was previously allowed.
- Shim's DBX: Ditto
- SBAT Revocation data: Ditto
This is a problem. Revoking vulnerable binaries should NOT cause the
user to have to dig up their recovery key (IF they even have it: no
matter how hard we beg there's a good chance the user will ignore our
instructions to write it down). I can think of two viable solutions
(and a couple non-viable ones that I listed at the end of this email
for reference):
1. This is basically the approach Windows seems to take with
Bitlocker. If we're about to update DBX or Shim, we temporarily enroll
a new decryption method that's just using PCRs 11+14 (and NOT 7).
Then, on the next boot, we re-enroll the TPM using 7+11+14 so that
it's sealed to the new value of PCR[7]. This should just work, but it
gives an attacker a window of opportunity to undetectably turn off
secure boot and completely break the chain of trust. The window is
pretty small, and Microsoft seems to be OK taking this risk, but its
mere existence is unsettling to me...
2. The alternative approach involves pre-calculating PCR[7] on the
client if we're updating DBX or Shim. Here's how I envision this
going:
- We read the TPM log (which we can trust because we're currently
booted to system verified via the chain of trust) and extract
everything read into PCR[7]
- We clear PCR[16], then start replaying everything from the TPM log
- When we reach the measurement of DBX, we pre-calculate the new value
of DBX and measure that in instead. This would probably need
collaboration w/ fwupd
- When we reach the measurements made by Shim, we use the new values
instead. See https://github.com/rhboot/shim/issues/555
- PCR[16] now contains the future value for PCR[7]. We enroll (into a
new keyslot) TPM decryption. We seal against 16+11+14, but then
configure it to unseal against 7+11+14 (this is the one step I'm iffy
about. Is this possible??)
- It is safe to perform the update now so we do so (it remains atomic:
if the update fails we boot with the old PCR[7] value, and if it
passes we boot with the new one)
- We reboot
- On next boot, the original TPM decryption fails (PCR[7] has
changed!). We try the new decryption and it passes
- We delete the old TPM keyslot
Any thoughts and ideas about any of this?
Thanks,
Adrian Vovk
----
For reference, here are some of my previous possible solutions to this
problem, and why I decided they won't work:
1. Is this even a problem? If secure boot is off then it's possible to
spoof the TPM and make it have whatever values you want in the PCRs.
However, this is a misunderstanding of how TPM works. As far as I can
tell, the values of the PCRs are checked inside of the TPM itself, so
to spoof one of their values the whole TPM needs to be fake. But then
a fake TPM will not have the real TPM's secret keys and thus will be
unable to unseal the decryption key. Thus, yes: it is a problem.
2. We can ask Shim to stop putting SBAT/their DBX and maybe even their
DB into PCR[7]. However, it is highly likely that they would refuse:
it's backwards-incompatible, plus they're measuring these into the PCR
for a reason (not all use-cases for PCR[7] match ours). Plus, this
doesn't fix the problem when (inevitably) the firmware's DBX will need
to be updated
3. Perhaps sd-stub or sd-boot can do its own measurements of
mode/PK/KEKs/DB/DBT/DBR into a new PCR that could be used instead of
PCR[7]. Problem: When secure boot is off, nothing prevents this
measurement from being replaced by something that simply measures in
known-correct values instead of the real ones. Thus, this doesn't work
at all
More information about the systemd-devel
mailing list