Skip to content

Commit afc650f

Browse files
committed
feat(tpm): implement basic measurement of the bootloader configuration
1 parent 81cf331 commit afc650f

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

src/config/loader.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::config::{RootConfiguration, latest_version};
22
use crate::options::SproutOptions;
3+
use crate::platform::tpm::PlatformTpm;
34
use crate::utils;
45
use anyhow::{Context, Result, bail};
56
use log::info;
@@ -21,6 +22,11 @@ fn load_raw_config(options: &SproutOptions) -> Result<Vec<u8>> {
2122
// Read the contents of the sprout config file.
2223
let content = utils::read_file_contents(Some(&path), &options.config)
2324
.context("unable to read sprout config file")?;
25+
26+
// Measure the sprout.toml into the TPM, if needed and possible.
27+
PlatformTpm::log_event(PlatformTpm::PCR_BOOT_LOADER_CONFIG, &content, "sprout.toml")
28+
.context("unable to measure the sprout.toml file into the TPM")?;
29+
2430
// Return the contents of the sprout config file.
2531
Ok(content)
2632
}

src/platform/tpm.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use crate::utils;
22
use anyhow::{Context, Result};
33
use uefi::boot::ScopedProtocol;
4-
use uefi::proto::tcg::v2::Tcg;
5-
use uefi_raw::protocol::tcg::v2::{Tcg2Protocol, Tcg2Version};
4+
use uefi::proto::tcg::PcrIndex;
5+
use uefi::proto::tcg::v2::{PcrEventInputs, Tcg};
6+
use uefi_raw::protocol::tcg::EventType;
7+
use uefi_raw::protocol::tcg::v2::{Tcg2HashLogExtendEventFlags, Tcg2Protocol, Tcg2Version};
68

79
/// Represents the platform TPM.
810
pub struct PlatformTpm;
@@ -33,6 +35,9 @@ impl TpmProtocolHandle {
3335
}
3436

3537
impl PlatformTpm {
38+
/// The PCR for measuring the bootloader configuration into.
39+
pub const PCR_BOOT_LOADER_CONFIG: PcrIndex = PcrIndex(5);
40+
3641
/// Acquire access to the TPM protocol handle, if possible.
3742
/// Returns None if TPM is not available.
3843
fn protocol() -> Result<Option<TpmProtocolHandle>> {
@@ -93,4 +98,32 @@ impl PlatformTpm {
9398
// Return the number of active PCR banks.
9499
Ok(banks.bits())
95100
}
101+
102+
/// Log an event into the TPM pcr `pcr_index` with `buffer` as data. The `description`
103+
/// is used to describe what the event is.
104+
///
105+
/// If a TPM is not available, this will do nothing.
106+
pub fn log_event(pcr_index: PcrIndex, buffer: &[u8], description: &str) -> Result<()> {
107+
// Acquire access to the TPM protocol handle.
108+
let Some(mut handle) = PlatformTpm::protocol()? else {
109+
return Ok(());
110+
};
111+
112+
// Encode the description as a UTF-16 little endian string.
113+
let description = description
114+
.encode_utf16()
115+
.flat_map(|c| c.to_le_bytes())
116+
.collect::<Vec<u8>>();
117+
118+
// Construct an event input for the TPM.
119+
let event = PcrEventInputs::new_in_box(pcr_index, EventType::IPL, &description)
120+
.context("unable to construct pcr event inputs")?;
121+
122+
// Log the event into the TPM.
123+
handle
124+
.protocol()
125+
.hash_log_extend_event(Tcg2HashLogExtendEventFlags::empty(), buffer, &event)
126+
.context("unable to log event to tpm")?;
127+
Ok(())
128+
}
96129
}

0 commit comments

Comments
 (0)