diff --git a/src/config/loader.rs b/src/config/loader.rs index 6c5342e..7816711 100644 --- a/src/config/loader.rs +++ b/src/config/loader.rs @@ -1,5 +1,6 @@ use crate::config::{RootConfiguration, latest_version}; use crate::options::SproutOptions; +use crate::platform::tpm::PlatformTpm; use crate::utils; use anyhow::{Context, Result, bail}; use log::info; @@ -21,6 +22,11 @@ fn load_raw_config(options: &SproutOptions) -> Result> { // Read the contents of the sprout config file. let content = utils::read_file_contents(Some(&path), &options.config) .context("unable to read sprout config file")?; + + // Measure the sprout.toml into the TPM, if needed and possible. + PlatformTpm::log_event(PlatformTpm::PCR_BOOT_LOADER_CONFIG, &content, "sprout.toml") + .context("unable to measure the sprout.toml file into the TPM")?; + // Return the contents of the sprout config file. Ok(content) } diff --git a/src/platform/tpm.rs b/src/platform/tpm.rs index 9dc04b8..b0c37db 100644 --- a/src/platform/tpm.rs +++ b/src/platform/tpm.rs @@ -1,8 +1,10 @@ use crate::utils; use anyhow::{Context, Result}; use uefi::boot::ScopedProtocol; -use uefi::proto::tcg::v2::Tcg; -use uefi_raw::protocol::tcg::v2::{Tcg2Protocol, Tcg2Version}; +use uefi::proto::tcg::PcrIndex; +use uefi::proto::tcg::v2::{PcrEventInputs, Tcg}; +use uefi_raw::protocol::tcg::EventType; +use uefi_raw::protocol::tcg::v2::{Tcg2HashLogExtendEventFlags, Tcg2Protocol, Tcg2Version}; /// Represents the platform TPM. pub struct PlatformTpm; @@ -33,6 +35,9 @@ impl TpmProtocolHandle { } impl PlatformTpm { + /// The PCR for measuring the bootloader configuration into. + pub const PCR_BOOT_LOADER_CONFIG: PcrIndex = PcrIndex(5); + /// Acquire access to the TPM protocol handle, if possible. /// Returns None if TPM is not available. fn protocol() -> Result> { @@ -93,4 +98,32 @@ impl PlatformTpm { // Return the number of active PCR banks. Ok(banks.bits()) } + + /// Log an event into the TPM pcr `pcr_index` with `buffer` as data. The `description` + /// is used to describe what the event is. + /// + /// If a TPM is not available, this will do nothing. + pub fn log_event(pcr_index: PcrIndex, buffer: &[u8], description: &str) -> Result<()> { + // Acquire access to the TPM protocol handle. + let Some(mut handle) = PlatformTpm::protocol()? else { + return Ok(()); + }; + + // Encode the description as a UTF-16 little endian string. + let description = description + .encode_utf16() + .flat_map(|c| c.to_le_bytes()) + .collect::>(); + + // Construct an event input for the TPM. + let event = PcrEventInputs::new_in_box(pcr_index, EventType::IPL, &description) + .context("unable to construct pcr event inputs")?; + + // Log the event into the TPM. + handle + .protocol() + .hash_log_extend_event(Tcg2HashLogExtendEventFlags::empty(), buffer, &event) + .context("unable to log event to tpm")?; + Ok(()) + } }