OVMF PEIFV TPM Measurement Calculation

Simon Ott

Hi everyone,

For enabling remote attestation, our goal is to provide an open source tool which calculates the expected TPM PCR values of virtual machines given the OVMF, kernel and some parameters as inputs (to the best of our knowlege, nothing like this exists, yet). To finish this, we have to address a last gap in calculating PCR0. We tried this using edk2-stable202205. The TPM Measurements for PCR0 look something like this:

sha256: 96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7
sha256: 822b3557f75c1672a1028010513f752105c1359dcf329a17e570b4aa83d53bf8
description: BlobBase: 0x820000; BlobLength: 0xe0000
sha256: 7c50e9c6922123a1301a23476967a5894fa6ba0674f134b13c92a107c10d62d8
description: BlobBase: 0x900000; BlobLength: 0xc00000
sha256: df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119

The calculation of EV_S_CRTM_VERSION and EV_SEPARATOR is trivial. For calculating the two EV_EFI_PLATFORM_FIRMWARE_BLOBs, we had a look at the layout of the OVMF.fd:

Description Compression type Size
------------------------------ ---------------------- -------
Non-volatile data storage open-coded binary data 128 KB

FVMAIN_COMPACT uncompressed 1712 KB
FV Firmware File System file LZMA compressed
PEIFV uncompressed 896 KB
individual PEI modules uncompressed
DXEFV uncompressed 8192 KB
individual DXE modules uncompressed

SECFV uncompressed 208 KB
SEC driver
reset vector code

We are able to locate FVMAIN_COMPACT and the FFS, do the LZMA extraction and get PEIFV and DXEFV. The second EV_EFI_PLATFORM_FIRMWARE_BLOB digest is the DXEFV (BlobBase: 0x900000; BlobLength: 0xc00000), which we were able to extract, hash and get the correct value.

The first EV_EFI_PLATFORM_FIRMWARE_BLOB digest is the PEIFV. Unfortunately, hashing PEIFV does not result in the first digest. The reason is, that the OVMF PEIFV measurement includes the values of some initialized global variables from the .data section into the TPM Measurement.

We could track down those global variables and their values for our machine:

| Addr | Len | Var | Value |
| ---- | --- | ---------------------- | --------------------------- |
| c480 | 01 | mQemuFwCfgSupported | 01 |
| c481 | 01 | mQemuFwCfgDmaSupported | 01 |
| c488 | 08 | mAddressEncMask | 00 00 00 00 00 00 00 00 |
| c490 | 01 | mAddressEncMaskChecked | 00 |
| c498 | 08 | mTdSharedPageMask | 00 00 00 00 00 00 00 00 |
| c4a0 | 01 | mTdDataReturned | 00 |
| c4a8 | 08 | mFeatureControlValue | 05 00 14 00 00 00 00 00 |
| c4b0 | 08 | mPageTablePool | 00 00 00 00 00 00 00 00 |
| c4c0 | 8a | mPlatformInfoHob | C0 29 00 00 00 00 00 00 ... |

These variables are set in the InitializePlatform() of PEIM 222C386D-5ABC-4FB4-B124-FBB82488ACF4. The TPM Initialization and Measurements then take place afterwards in PEIM 8AD3148F-945F-46B4-8ACD-71469EA73945 and the following PEIMs.

As it is not easy to locate the PEIFV .data section just with the OVMF.fd as input and the variables could be arranged differently during compilation, it is very hard to predict the value of PCR0. Furthermore, such an approach would be very unstable if the code is subject to changes. So our question is, if it is intentional, that the .data section is included in the measurement, and if this could be adjusted to be better predictable for remote attestation.

We have already discussed/tried some approaches, but do not yet fully understand the implications, as we are mainly concerned with remote attestation, and not the OVMF itself.

1. It might be possible to put the global variables on the stack. We successfully did this for mPlatformInfoHob which contains most of the initialized values (I can post a darf-patch if this is a valid approach). However, it might be harder for other variables.

2. It might be possible to first measure the PEIFV, and then do the initializations of the global variables. Either through first initializing the TPM (Calling Tcg2ConfigPei.efi and the following before PlatformPei.efi) or only measuring in PlatformPei.efi and then handing-over the measurement to the TCG-PEIs.

3. Would it be possible, to initialize the TPM in the SECFV and measure the PEIFV there, before transferring control (would seem like the cleaner chain of trust to me)?

Before digging deeper, we kindly wanted to ask, if this matter could be resolved, and what a preferred way could look like.