1use alloc::vec;
2use core::mem::{self, MaybeUninit};
3use log::warn;
4use uefi::{
5 prelude::BootServices,
6 proto::tcg::{
7 v1::{self, Sha1Digest},
8 v2, EventType, PcrIndex,
9 },
10 table::boot::ScopedProtocol,
11};
12
13fn open_capable_tpm2(boot_services: &BootServices) -> uefi::Result<ScopedProtocol<v2::Tcg>> {
14 let tpm_handle = boot_services.get_handle_for_protocol::<v2::Tcg>()?;
15 let mut tpm_protocol = boot_services.open_protocol_exclusive::<v2::Tcg>(tpm_handle)?;
16
17 let capabilities = tpm_protocol.get_capability()?;
18
19 if !capabilities.tpm_present() {
28 warn!("Capability `TPM present` is not there for the existing TPM TCGv2 protocol");
29 return Err(uefi::Status::UNSUPPORTED.into());
30 }
31
32 Ok(tpm_protocol)
33}
34
35fn open_capable_tpm1(boot_services: &BootServices) -> uefi::Result<ScopedProtocol<v1::Tcg>> {
36 let tpm_handle = boot_services.get_handle_for_protocol::<v1::Tcg>()?;
37 let mut tpm_protocol = boot_services.open_protocol_exclusive::<v1::Tcg>(tpm_handle)?;
38
39 let status_check = tpm_protocol.status_check()?;
40
41 if status_check.protocol_capability.tpm_deactivated()
42 || !status_check.protocol_capability.tpm_present()
43 {
44 warn!("Capability `TPM present` is not there or `TPM deactivated` is there for the existing TPM TCGv1 protocol");
45 return Err(uefi::Status::UNSUPPORTED.into());
46 }
47
48 Ok(tpm_protocol)
49}
50
51pub fn tpm_available(boot_services: &BootServices) -> bool {
52 open_capable_tpm2(boot_services).is_ok() || open_capable_tpm1(boot_services).is_ok()
53}
54
55pub fn tpm_log_event_ascii(
58 boot_services: &BootServices,
59 pcr_index: PcrIndex,
60 buffer: &[u8],
61 description: &str,
62) -> uefi::Result<bool> {
63 if pcr_index.0 == u32::MAX {
64 return Ok(false);
65 }
66 if let Ok(mut tpm2) = open_capable_tpm2(boot_services) {
67 let required_size = mem::size_of::<u32>()
68 + mem::size_of::<u32>() + mem::size_of::<u16>() + mem::size_of::<PcrIndex>() + mem::size_of::<EventType>()
70 + description.len();
71
72 let mut event_buffer = vec![MaybeUninit::<u8>::uninit(); required_size];
73 let event = v2::PcrEventInputs::new_in_buffer(
74 event_buffer.as_mut_slice(),
75 pcr_index,
76 EventType::IPL,
77 description.as_bytes(),
78 )?;
79 tpm2.hash_log_extend_event(Default::default(), buffer, event)?;
81 } else if let Ok(mut tpm1) = open_capable_tpm1(boot_services) {
82 let required_size = mem::size_of::<PcrIndex>()
83 + mem::size_of::<EventType>()
84 + mem::size_of::<Sha1Digest>()
85 + mem::size_of::<u32>()
86 + description.len();
87
88 let mut event_buffer = vec![MaybeUninit::<u8>::uninit(); required_size];
89
90 let mut m = sha1_smol::Sha1::new();
92 m.update(description.as_bytes());
93
94 let event = v1::PcrEvent::new_in_buffer(
95 event_buffer.as_mut_slice(),
96 pcr_index,
97 EventType::IPL,
98 m.digest().bytes(),
99 description.as_bytes(),
100 )?;
101
102 tpm1.hash_log_extend_event(event, Some(buffer))?;
103 }
104
105 Ok(true)
106}