UEFI Utility to Read TPM 1.2 PCRs

A Trusted Platform Module (TPM) supports many security functions including a number of special registers called Platform Configuration Registers (PCRs) which can hold data in a shielded location in a manner that prevents tampering or spoofing.

A PCR is a 20-byte register. which incidentally is the length of a SHA-1 (Secure Hash Algorithm) hash. Most modern TPMs have 24 or even more PCRs; older ones have 16 PCRs. The TPM 1.2 specification, developed by the Trusted Computing Group (TCG) only requires 16 PCRs. Typically PCRs are used to store measurements. Measurements can be of code, data structures, configuration, information, or anything that can be loaded into memory with code measurement being the most common use case. The idea is that no code is executed until it has been measured.

Measurements consist of a cryptographic hash using SHA-1. To further protect the integrity of the measurements, hashes are not written directly to PCRs; instead a PCR is extended with a measurement. This means that the TPM takes the current value of the PCR and the measurement to be extended, hashes them together, and replaces the content of the PCR with that hash result. Note that a TPM is not responsible for actually measuring anything; only for securely storing the measurement.

Extend works like this:

New PCR value = SHA-1 hash (Current PCR value || new SHA-I hash)

The TPM retrieves the current value of a PCR, concatenates the new SHA-1 hash to the end of the retrieved value in order to obtain a 40-byte value, calculates the SHA-1 of this 40-byte value to obtain a 20-byte hash and sets the PCR value to this SHA-1.

The result is that the only way to arrive at a particular measurement in a PCR is to extend exactly the same measurements in exactly the same order. Therefore, if any module being measured has been modified, the resulting PCR measurement will be different and thus it is easy to detect if any code, configuration, data, etc. that has been measured was been modified or corrupted as it is computationally infeasible to forge the resulting PCR value.

PCRs can never be arbitrarily overwritten but many can be reset while the platform is powered on to a known value, either all zero bits or all one bits, using the TPM PCR_Reset command. Whether a specific PCR can be reset or not is defined by various platform specifications and requires appropriate permissions. All PCRs can be reset at power on.

Before I go any further, here is the source code for my ShowPCR12 utility:

To assist you in understanding the code I have included a copy of the TPM_PCRRead specification from Part 3 of the TPM 1.2 specification. In UDK2015, the assigned ordinal for TPM_PCRRead is TPM_ORD_PcrRead and that is what you will see in the above code.

I also include a copy of the relevant section of the TPM 1.2 EFI specification detailing the PassThroughToTpm API which is exposed via the EFI_TCG_PROTOCOL_GUID guid.

Note this utility interacts with a TPM at a very low level, i.e. what Will Arthur et al in their excellent book A Practical Guide to TPM 2.0 in Figure 7.1 call the System API (SAPI) layer. Could I have used one of the two other higher levels API layers? Yes, but frankly SAPI is easier for me to use when coding a UEFI shell utility as I am quite familiar with it.

Here is the output of this utility when run against the hardware TPM on my Lenovo T450:

As you can see the first eight PCRs have non-zero values. The Trusted Computing Group only defined a Static Chain of Trust for TPM 1.2 starting from a Static Core Root of Trust for Measurements (S-CRTM) and assigns the following meanings to measurements in the first 8 PCRs:

PCR0 – CRTM, BIOS code, and Platform Extensions

PCR1 – Platform Configuration

PCR2 – Option ROM Code

PCR3 – Option ROM Configuration and Data

PCR4 – IPL (Initial Program Loader) Code

PCR5 – IPL Code Configuration and Data

PCR6 – State Transition and Wake Events

PCR7 – Platform Manufacturer Control

PCRs 8 to 15 are assigned for use by the operating system. For example, a trusted boot loader typically uses PCR8 and PCR9.

The following diagram shows the difference between a Static Chain of Trust which I have discussed and a Dynamic Chain of Trust which I am about to briefly introduce.

TPM 1.2 only supports a Static Chain of Trust. Here, the first thing measured at boot is called the Core Root of Trust for Measurements (CRTM) whereby the firmware (AKA BIOS) boot block will measure the firmware and store the resultant value in PCR0 before executing it. On Intel platforms, it does this by invoking an Intel-supplied chunk of code called Authenticated Code Module (BIOS ACM) which is embedded in the firmware and can authenticate and validate the firmware. Then the firmware will measure the next thing in the boot chain before executing it and store the value in PCR1. This process continues for each component in the boot sequence.

On the other hand, Dynamic Root of Trust for Measurements DRTM) is quite different as you can see from the above diagram. The goal of DRTM is to create a trusted environment from an initially untrusted state. Intel calls their implementation Trusted Execution Technology (TXT) and AMD uses the name Secure Virtual Machine (SVM). A detailed discussion of the differences between SRTM and DRTM is outside the scope of this post. Do a search, SRTM versus DRTM, on StackExchange for more information.

By the way, if you have access to the Intel TXT (Trusted Execution Technology) EFI compliance testing toolkit, the included utility, pcrdump.efi, provides similar functionality to the utility described in this post.

No, (S)uper(V)isor(P)assword. I have an eeprom reader/writer so Iam able to read the eeprom full. Easy way is just to remove the dxe for the password stuff. But that will not clear the svp at all, only the query.

On the older ones (pre t440) it is a 24RF08. I have built an Arduino to reset those old ones, but this will not work with newer ones. For what i know, the svp is stored in the tpm chip on newer models.

Maybe i`am wrong, but i know this is possible. I have seen a bios for the t440 with a manually added dxe driver which clears the svp out.

I have recently begun some additions to our bootloader code that require the use of TPM2.0 and I am having a really hard time. I am getting very lost in a specification that seems to have been designed to do everything and more!

Basically I need to implement the Load, EncryptDecrypt and DA functions. This is probably beyond the scope of the comments system here and maybe beyond the scope of unsolicited advice but any examples, help, or tips would be most appreciated.