Secure and Trusted Boot Overview

Just as a quick reference:

Secure boot:  verify and enforce.
Trusted boot: measure and record.

Secure boot seeks to protect system integrity from execution of malicious code during boot. The authenticity and integrity of every code is verified by its predecessor code before it is executed. If the verification fails, the boot process is aborted.

Trusted boot does not perform enforcement. Instead it creates artifacts during system boot to prove that a particular chain of events have happened during boot. Interested parties can subsequently assess the artifacts to check whether or not only trusted events happened and then make security decisions. These artifacts comprise a log of measurements and the digests extended into the TPM PCRs. Platform Configuration Registers (PCRs) are registers in the Trusted Platform Module (TPM) that are shielded from direct access by the CPU.

Trusted boot measures and maintains in an Event Log a record of all boot events that may affect the security state of the platform. A measurement is calculated by hashing the data of a given event. When a new measurement is added to the Event Log, the same measurement is also sent to the TPM, which performs an extend operation to incrementally update the existing digest stored in a PCR.

PCR extend is an operation that uses a hash function to combine a new measurement with the existing digest saved in the PCR. Basically, it concatenates the existing PCR value with the received measurement, and then stores the hash of this string in the PCR.

The TPM may maintain multiple banks of PCRs, where a PCR bank is a collection of PCRs that are extended with the same hash algorithm. TPM 2.0 has a SHA1 bank and a SHA256 bank with 24 PCRs each.

When the system boot is complete, each non-zero PCR value represents one or more events measured during the boot in chronological order. Interested parties can make inferences about the system’s state by using an attestation tool to remotely compare the PCR values of a TPM against known good values, and also identify unexpected events by replaying the Event Log against known good Event Log entries.

Implementation in skiboot

Libstb implements an API for secure and trusted boot, which is used to verify and measure images retrieved from PNOR. The libstb interface is documented in libstb/stb.h

The example below shows how libstb can be used to add secure and trusted boot support for a platform:

stb_init();
    start_preload_resource(RESOURCE_ID_CAPP, 0, capp_ucode_info.lid, &capp_ucode_info.size);
        sb_verify(id, buf, len);
        tb_measure(id, buf, len);
    start_preload_resource(RESOURCE_ID_KERNEL, 0, KERNEL_LOAD_BASE, &kernel_size);
        sb_verify(id, buf, len);
        tb_measure(id, buf, len);
stb_final();

First, stb_init() must be called to initialize libstb. Basically, it reads both secure mode and trusted mode flags and loads drivers accordingly. In P8, secure mode and trusted mode are read from the ibm,secureboot device tree node (see ibm,secureboot).

If either secure mode or trusted mode is on, stb_init() loads a driver (romcode driver) to access the verification and SHA512 functions provided by the code stored in the secure ROM at manufacture time. Both secure boot and trusted boot depends on the romcode driver to access the ROM code. If trusted mode is on, stb_init() loads a TPM device driver compatible with the tpm device tree node and also initializes the existing event log in skiboot. For device tree bindings for the TPM, see Trusted Platform Module (TPM).

Once libstb is initialized in the platform, sb_verify() and tb_measure() can used as shown in the example above to respectively verify and measure images retrieved from PNOR. If a platform claims secure and trusted boot support, then sb_verify() and tb_measure() is called for all images retrieved from PNOR.

sb_verify() and tb_measure() do nothing if libstb is not initialized in the platform since both secure mode and trusted mode are off by default.

Finally, stb_final() must be called when no more images need to be retrieved from PNOR in order to indicate that secure boot and trusted boot have completed in skiboot. When stb_final() is called, basically it records eight EV_SEPARATOR events in the event log (one for each PCR through 0 to 7) and extends the PCR through 0 to 7 of both SHA1 and SHA256 PCR banks with the digest of 0xFFFFFFFF. Additionally, stb_final() also frees resources allocated for secure boot and trusted boot.

Verifying an image

If secure mode is on, sb_verify() verifies the integrity and authenticity of an image by calling the ROM_verify() function from the ROM code via romcode driver. In general terms, this verification will pass only if the following conditions are satisfied. Otherwise the boot process is aborted.

  1. Secure boot header is properly built and attached to the image. When sb_verify() is called, the ROM code verifies all the secure boot header fields, including the keys, hashes and signatures. The secure boot header and the image are also collectively referred to as secure boot container, or just container. As the secure boot header is the container header and the image is the container payload.
  2. The public hardware keys of the container header match with the hw-key-hash read from the device tree. The way that secure boot is designed, this assertion ensures that only images signed by the owner of the hw-key-hash will pass the verification. The hw-key-hash is a hash of three hardware public keys stored in SEEPROM at manufacture time and written to the device tree at boot time.

Measuring an image

tb_measure() measures an image retrieved from PNOR if trusted mode is on, but only if the provided image is included in the resource_map whitelist. This whitelist defines for each expected image to what PCR the measurement must be recorded and extended. tb_measure() returns an error if the provided image is not included in the resource_map whitelist.

For the sake of simplicity we say that tb_measure() measures an image, but calculating the digest of a given image is just one of the steps performed by tb_measure().

Steps performed by tb_measure() if trusted mode is on:

  1. Measure the provided image for each PCR bank: SHA1 and SHA256. If secure mode is on and the image is a container, parse the container header to get the SHA512 hash of the container payload (sw-payload-hash field). Otherwise, call the ROM code via romcode driver to calculate the SHA512 hash of the image at boot time. In both cases, the SHA512 hash is truncated to match the size required by each PCR bank: SHA1 bank PCRs are 20 bytes and SHA256 bank PCRs are 32 bytes.
  2. Record a new event in the event log for the mapped PCR. Call the tpmLogMgr API to generate a new event and record it in the event log. The new event is generated for the mapped PCR and it also contains a digest list with both SHA1 and SHA256 measurements obtained in step 1.
  3. Extend the measurements into the mapped PCR. Call the TCG Software Stack (TSS) API to extend both measurements obtained in step 1 into the mapped PCR number. The SHA1 measurement is extended to the SHA1 PCR bank and the SHA256 measurement is extended to the SHA256 PCR bank. However, they are extended to the same PCR number on each bank. Since this TSS implementation supports multibank, it does the marshalling of both SHA1 and SHA256 measurements into a single TPM extend command and then it sends the command to the TPM device via TPM device driver.

Both TSS and tpmLogMgr APIs are implemented by hostboot, but their source code are added to skiboot. The TSS and tpmLogMgr interfaces are defined in libstb/tss/trustedbootCmds.H and libstb/tss/tpmLogMgr.H, respectively.