Skip to content

Commit 0ffe995

Browse files
committed
chore: using uefi crate to simplify tcg2 protocol
1 parent 6c11690 commit 0ffe995

1 file changed

Lines changed: 34 additions & 111 deletions

File tree

‎src/tpm2.rs‎

Lines changed: 34 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,21 @@
11
//! EFI TCG2 protocol interface for TPM2 PCR measurements.
22
3-
use core::ffi::c_void;
4-
5-
use anyhow::{Context as _, Result, bail};
6-
use uefi::{Guid, Status};
7-
8-
use crate::pe::loader::protocol;
9-
10-
const EFI_TCG2_PROTOCOL_GUID: Guid = Guid::parse_or_panic("607f766c-7455-42be-930b-e4d76db2720f");
3+
use anyhow::{Context as _, Result};
4+
use uefi::Identify as _;
5+
use uefi::boot::{self, ScopedProtocol, SearchType};
6+
use uefi::proto::tcg::v2::{HashLogExtendEventFlags, PcrEventInputs, Tcg};
7+
use uefi::proto::tcg::{EventType, PcrIndex};
118

129
const PCR_INDEX: u32 = 11;
13-
const EV_IPL: u32 = 0x0000_000D;
14-
const TCG2_EVENT_HEADER_SIZE: usize = 28;
15-
16-
type HashLogExtendEventFn = unsafe extern "efiapi" fn(
17-
this: *mut Tcg2Protocol,
18-
flags: u64,
19-
data_to_hash: u64,
20-
data_to_hash_len: u64,
21-
efi_tcg2_event: *const Tcg2Event,
22-
) -> Status;
2310

24-
#[repr(C)]
25-
struct Tcg2Protocol {
26-
get_capability: *const c_void,
27-
get_event_log: *const c_void,
28-
hash_log_extend_event: HashLogExtendEventFn,
29-
submit_command: *const c_void,
30-
get_active_pcr_banks: *const c_void,
31-
set_active_pcr_banks: *const c_void,
32-
get_result_of_set_active_pcr_banks: *const c_void,
33-
}
34-
35-
#[repr(C, packed)]
36-
struct Tcg2Event {
37-
size: u32,
38-
header: Tcg2EventHeader,
39-
}
40-
41-
#[repr(C, packed)]
42-
struct Tcg2EventHeader {
43-
header_size: u32,
44-
header_version: u16,
45-
pcr_index: u32,
46-
event_type: u32,
47-
}
11+
/// Prefix of an `EFI_TCG2_EVENT`: `u32` size field + 14-byte `EFI_TCG2_EVENT_HEADER`.
12+
const PCR_EVENT_PREFIX_LEN: usize = 18;
4813

4914
/// Returns whether the EFI TCG2 protocol is available (TPM2 present).
5015
#[must_use]
5116
pub fn is_available() -> bool {
52-
// SAFETY: firmware-managed pointer valid during boot services.
53-
unsafe { protocol::locate_raw(&EFI_TCG2_PROTOCOL_GUID).is_some() }
17+
boot::locate_handle_buffer(SearchType::ByProtocol(&Tcg::GUID))
18+
.is_ok_and(|handles| !handles.is_empty())
5419
}
5520

5621
/// Measures a UKI section into PCR#11 via the EFI TCG2 protocol.
@@ -59,80 +24,38 @@ pub fn is_available() -> bool {
5924
///
6025
/// Returns an error if the TCG2 protocol is unavailable or measurement fails.
6126
pub fn measure_section(name: &str, data: &[u8]) -> Result<()> {
27+
let mut tcg = open_tcg()?;
28+
6229
let mut name_bytes = name.as_bytes().to_vec();
6330
name_bytes.push(0_u8);
64-
hash_log_extend(name, &name_bytes)?;
65-
hash_log_extend(name, data)?;
31+
hash_log_extend(&mut tcg, name, &name_bytes)?;
32+
hash_log_extend(&mut tcg, name, data)?;
33+
6634
Ok(())
6735
}
6836

69-
/// Performs a single `HashLogExtendEvent` call into PCR#11.
70-
fn hash_log_extend(event_name: &str, data: &[u8]) -> Result<()> {
71-
// SAFETY: firmware-managed pointer valid during boot services; layout matches EFI TCG2 ABI.
72-
let proto = match unsafe { protocol::locate_raw(&EFI_TCG2_PROTOCOL_GUID) } {
73-
Some(protocol) => protocol.cast::<Tcg2Protocol>(),
74-
None => bail!("EFI_TCG2_PROTOCOL not available"),
75-
};
37+
fn open_tcg() -> Result<ScopedProtocol<Tcg>> {
38+
let handles = boot::locate_handle_buffer(SearchType::ByProtocol(&Tcg::GUID))
39+
.context("Failed to search for EFI_TCG2_PROTOCOL handles")?;
40+
let handle = handles.first().context("EFI_TCG2_PROTOCOL not available")?;
41+
42+
boot::open_protocol_exclusive::<Tcg>(*handle).context("Failed to open EFI_TCG2_PROTOCOL")
43+
}
7644

45+
fn hash_log_extend(tcg: &mut Tcg, event_name: &str, data: &[u8]) -> Result<()> {
7746
let event_desc = event_name.as_bytes();
78-
let event_total_size = TCG2_EVENT_HEADER_SIZE
47+
let event_size = PCR_EVENT_PREFIX_LEN
7948
.checked_add(event_desc.len())
8049
.context("TCG2 event size overflow")?;
81-
let event_total_size_u32 = u32::try_from(event_total_size).context("TCG2 event too large")?;
82-
let header_size = u32::try_from(size_of::<Tcg2EventHeader>())
83-
.context("TCG2 event header size exceeds u32")?;
84-
85-
let mut event_buf = vec![0_u8; event_total_size];
86-
write_event_u32(&mut event_buf, 0, event_total_size_u32)?;
87-
write_event_u32(&mut event_buf, 4, header_size)?;
88-
write_event_u16(&mut event_buf, 8, 1)?;
89-
write_event_u32(&mut event_buf, 10, PCR_INDEX)?;
90-
write_event_u32(&mut event_buf, 14, EV_IPL)?;
91-
92-
let event_data_offset = size_of::<Tcg2Event>();
93-
let event_data_end = event_data_offset
94-
.checked_add(event_desc.len())
95-
.context("TCG2 event data bounds overflow")?;
96-
event_buf
97-
.get_mut(event_data_offset..event_data_end)
98-
.context("TCG2 event data range unavailable")?
99-
.copy_from_slice(event_desc);
100-
101-
let data_address =
102-
u64::try_from(data.as_ptr().addr()).context("hash data address exceeds u64")?;
103-
let data_len = u64::try_from(data.len()).context("hash data length exceeds u64")?;
104-
let event = event_buf.as_ptr().cast::<Tcg2Event>();
105-
// SAFETY: `proto` is firmware-provided and valid during boot services.
106-
let hash_log_extend_event = unsafe { (*proto).hash_log_extend_event };
107-
// SAFETY: `proto` and its function pointer are valid firmware-provided values; `data` and
108-
// `event_buf` outlive the call.
109-
let status = unsafe { hash_log_extend_event(proto, 0, data_address, data_len, event) };
110-
111-
if status != Status::SUCCESS {
112-
bail!("HashLogExtendEvent failed for section {event_name}: {status:?}");
113-
}
114-
115-
Ok(())
116-
}
117-
118-
fn write_event_u16(event_buf: &mut [u8], offset: usize, value: u16) -> Result<()> {
119-
let end = offset
120-
.checked_add(size_of::<u16>())
121-
.context("TCG2 u16 field bounds overflow")?;
122-
event_buf
123-
.get_mut(offset..end)
124-
.context("TCG2 u16 field range unavailable")?
125-
.copy_from_slice(&value.to_le_bytes());
126-
Ok(())
127-
}
128-
129-
fn write_event_u32(event_buf: &mut [u8], offset: usize, value: u32) -> Result<()> {
130-
let end = offset
131-
.checked_add(size_of::<u32>())
132-
.context("TCG2 u32 field bounds overflow")?;
133-
event_buf
134-
.get_mut(offset..end)
135-
.context("TCG2 u32 field range unavailable")?
136-
.copy_from_slice(&value.to_le_bytes());
137-
Ok(())
50+
let mut event_buf = vec![0_u8; event_size];
51+
let event = PcrEventInputs::new_in_buffer(
52+
&mut event_buf,
53+
PcrIndex(PCR_INDEX),
54+
EventType::IPL,
55+
event_desc,
56+
)
57+
.context("Failed to build TCG2 event")?;
58+
59+
tcg.hash_log_extend_event(HashLogExtendEventFlags::empty(), data, event)
60+
.with_context(|| format!("HashLogExtendEvent failed for section {event_name}"))
13861
}

0 commit comments

Comments
 (0)