use alloc::vec; use core::mem::{self, MaybeUninit}; use log::warn; use uefi::{ prelude::BootServices, proto::tcg::{v2, EventType, PcrIndex}, table::boot::ScopedProtocol, }; fn open_capable_tpm2(boot_services: &BootServices) -> uefi::Result> { let tpm_handle = boot_services.get_handle_for_protocol::()?; let mut tpm_protocol = boot_services.open_protocol_exclusive::(tpm_handle)?; let capabilities = tpm_protocol.get_capability()?; /* * Here's systemd-stub perform a cast to EFI_TCG_BOOT_SERVICE_CAPABILITY * indicating there could be some quirks to workaround. * It should probably go to uefi-rs? if capabilities.structure_version.major == 1 && capabilities.structure_version.minor == 0 { }*/ if !capabilities.tpm_present() { warn!("Capability `TPM present` is not there for the existing TPM TCGv2 protocol"); return Err(uefi::Status::UNSUPPORTED.into()); } Ok(tpm_protocol) } pub fn tpm_available(boot_services: &BootServices) -> bool { open_capable_tpm2(boot_services).is_ok() } /// Log an event in the TPM with `buffer` as data. /// Returns a boolean whether the measurement has been done or not in case of success. pub fn tpm_log_event_ascii( boot_services: &BootServices, pcr_index: PcrIndex, buffer: &[u8], description: &str, ) -> uefi::Result { if pcr_index.0 == u32::MAX { return Ok(false); } if let Ok(mut tpm2) = open_capable_tpm2(boot_services) { let required_size = mem::size_of::() // EventHeader is privateā€¦ + mem::size_of::() + mem::size_of::() + mem::size_of::() + mem::size_of::() + description.len(); let mut event_buffer = vec![MaybeUninit::::uninit(); required_size]; let event = v2::PcrEventInputs::new_in_buffer( event_buffer.as_mut_slice(), pcr_index, EventType::IPL, description.as_bytes(), )?; // FIXME: what do we want as flags here? tpm2.hash_log_extend_event(Default::default(), buffer, event)?; } Ok(true) }