1 //! [TCG] (Trusted Computing Group) protocol for [TPM] (Trusted Platform
2 //! Module) 2.0.
3 //!
4 //! This protocol is defined in the [TCG EFI Protocol Specification _TPM
5 //! Family 2.0_][spec]. It is generally implemented only for TPM 2.0
6 //! devices, but the spec indicates it can also be used for older TPM
7 //! devices.
8 //!
9 //! [spec]: https://trustedcomputinggroup.org/resource/tcg-efi-protocol-specification/
10 //! [TCG]: https://trustedcomputinggroup.org/
11 //! [TPM]: https://en.wikipedia.org/wiki/Trusted_Platform_Module
12 
13 use super::{v1, AlgorithmId, EventType, HashAlgorithm, PcrIndex};
14 use crate::data_types::{Align, PhysicalAddress, UnalignedSlice};
15 use crate::proto::unsafe_protocol;
16 use crate::util::{ptr_write_unaligned_and_add, usize_from_u32};
17 use crate::{Error, Result, Status, StatusExt};
18 use bitflags::bitflags;
19 use core::fmt::{self, Debug, Formatter};
20 use core::marker::PhantomData;
21 use core::{mem, ptr, slice};
22 use ptr_meta::{Pointee, PtrExt};
23 
24 #[cfg(feature = "alloc")]
25 use {crate::mem::make_boxed, alloc::boxed::Box};
26 
27 #[cfg(all(feature = "unstable", feature = "alloc"))]
28 use alloc::alloc::Global;
29 
30 /// Version information.
31 ///
32 /// Layout compatible with the C type `EFI_TG2_VERSION`.
33 #[repr(C)]
34 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
35 pub struct Version {
36     /// Major version.
37     pub major: u8,
38     /// Minor version.
39     pub minor: u8,
40 }
41 
42 bitflags! {
43     /// Event log formats supported by the firmware.
44     ///
45     /// Corresponds to the C typedef `EFI_TCG2_EVENT_ALGORITHM_BITMAP`.
46     #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
47     #[repr(transparent)]
48     pub struct EventLogFormat: u32 {
49         /// Firmware supports the SHA-1 log format.
50         const TCG_1_2 = 0x0000_0001;
51 
52         /// Firmware supports the crypto-agile log format.
53         const TCG_2 = 0x0000_0002;
54     }
55 }
56 
57 /// Information about the protocol and the TPM device.
58 ///
59 /// Layout compatible with the C type `EFI_TCG2_BOOT_SERVICE_CAPABILITY`.
60 #[repr(C)]
61 #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
62 pub struct BootServiceCapability {
63     size: u8,
64 
65     /// Version of the EFI TCG2 protocol.
66     pub structure_version: Version,
67 
68     /// Version of the EFI TCG2 protocol.
69     pub protocol_version: Version,
70 
71     /// Bitmap of supported hash algorithms.
72     pub hash_algorithm_bitmap: HashAlgorithm,
73 
74     /// Event log formats supported by the firmware.
75     pub supported_event_logs: EventLogFormat,
76 
77     present_flag: u8,
78 
79     /// Maximum size (in bytes) of a command that can be sent to the TPM.
80     pub max_command_size: u16,
81 
82     /// Maximum size (in bytes) of a response that can be provided by the TPM.
83     pub max_response_size: u16,
84 
85     /// Manufacturer ID.
86     ///
87     /// See the [TCG Vendor ID registry].
88     ///
89     /// [TCG Vendor ID registry]: https://trustedcomputinggroup.org/resource/vendor-id-registry/
90     pub manufacturer_id: u32,
91 
92     /// Maximum number of supported PCR banks (hashing algorithms).
93     pub number_of_pcr_banks: u32,
94 
95     /// Bitmap of currently-active PCR banks (hashing algorithms). This
96     /// is a subset of the supported algorithms in [`hash_algorithm_bitmap`].
97     ///
98     /// [`hash_algorithm_bitmap`]: Self::hash_algorithm_bitmap
99     pub active_pcr_banks: HashAlgorithm,
100 }
101 
102 impl Default for BootServiceCapability {
default() -> Self103     fn default() -> Self {
104         // OK to unwrap, the size is less than u8.
105         let struct_size = u8::try_from(mem::size_of::<Self>()).unwrap();
106 
107         Self {
108             size: struct_size,
109             structure_version: Version::default(),
110             protocol_version: Version::default(),
111             hash_algorithm_bitmap: HashAlgorithm::default(),
112             supported_event_logs: EventLogFormat::default(),
113             present_flag: 0,
114             max_command_size: 0,
115             max_response_size: 0,
116             manufacturer_id: 0,
117             number_of_pcr_banks: 0,
118             active_pcr_banks: HashAlgorithm::default(),
119         }
120     }
121 }
122 
123 impl BootServiceCapability {
124     /// Whether the TPM device is present.
125     #[must_use]
tpm_present(&self) -> bool126     pub const fn tpm_present(&self) -> bool {
127         self.present_flag != 0
128     }
129 }
130 
131 bitflags! {
132     /// Flags for the [`Tcg::hash_log_extend_event`] function.
133     #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
134     #[repr(transparent)]
135     pub struct HashLogExtendEventFlags: u64 {
136         /// Extend an event but don't log it.
137         const EFI_TCG2_EXTEND_ONLY = 0x0000_0000_0000_0001;
138 
139         /// Use when measuring a PE/COFF image.
140         const PE_COFF_IMAGE = 0x0000_0000_0000_0010;
141     }
142 }
143 
144 /// Header used in [`PcrEventInputs`].
145 ///
146 /// Layout compatible with the C type `EFI_TCG2_EVENT_HEADER`.
147 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
148 #[repr(C, packed)]
149 struct EventHeader {
150     header_size: u32,
151     header_version: u16,
152     pcr_index: PcrIndex,
153     event_type: EventType,
154 }
155 
156 /// Event type passed to [`Tcg::hash_log_extend_event`].
157 ///
158 /// Layout compatible with the C type `EFI_TCG2_EVENT`.
159 ///
160 /// The TPM v1 spec uses a single generic event type for both creating a
161 /// new event and reading an event from the log. The v2 spec splits this
162 /// into two structs: `EFI_TCG2_EVENT` for creating events, and
163 /// `TCG_PCR_EVENT2` for reading events. To help clarify the usage, our
164 /// API renames these types to `PcrEventInputs` and `PcrEvent`,
165 /// respectively.
166 #[derive(Eq, Pointee)]
167 #[repr(C, packed)]
168 pub struct PcrEventInputs {
169     size: u32,
170     event_header: EventHeader,
171     event: [u8],
172 }
173 
174 impl PcrEventInputs {
175     /// Create a new `PcrEventInputs` using a byte buffer for storage.
176     ///
177     /// # Errors
178     ///
179     /// Returns [`Status::BUFFER_TOO_SMALL`] if the `buffer` is not large
180     /// enough. The required size will be returned in the error data.
181     ///
182     /// Returns [`Status::INVALID_PARAMETER`] if the `event_data` size is too
183     /// large.
new_in_buffer<'buf>( buffer: &'buf mut [u8], pcr_index: PcrIndex, event_type: EventType, event_data: &[u8], ) -> Result<&'buf mut Self, Option<usize>>184     pub fn new_in_buffer<'buf>(
185         buffer: &'buf mut [u8],
186         pcr_index: PcrIndex,
187         event_type: EventType,
188         event_data: &[u8],
189     ) -> Result<&'buf mut Self, Option<usize>> {
190         let required_size =
191             mem::size_of::<u32>() + mem::size_of::<EventHeader>() + event_data.len();
192 
193         if buffer.len() < required_size {
194             return Err(Error::new(Status::BUFFER_TOO_SMALL, Some(required_size)));
195         }
196         let size_field = u32::try_from(required_size)
197             .map_err(|_| Error::new(Status::INVALID_PARAMETER, None))?;
198 
199         let mut ptr: *mut u8 = buffer.as_mut_ptr().cast();
200 
201         unsafe {
202             ptr_write_unaligned_and_add(&mut ptr, size_field);
203             ptr_write_unaligned_and_add(
204                 &mut ptr,
205                 EventHeader {
206                     header_size: u32::try_from(mem::size_of::<EventHeader>()).unwrap(),
207                     header_version: 1,
208                     pcr_index,
209                     event_type,
210                 },
211             );
212             ptr::copy(event_data.as_ptr(), ptr, event_data.len());
213 
214             let ptr: *mut Self =
215                 ptr_meta::from_raw_parts_mut(buffer.as_mut_ptr().cast(), event_data.len());
216             Ok(&mut *ptr)
217         }
218     }
219 
220     /// Create a new `PcrEventInputs` in a [`Box`].
221     ///
222     /// # Errors
223     ///
224     /// Returns [`Status::INVALID_PARAMETER`] if the `event_data` size is too
225     /// large.
226     #[cfg(feature = "alloc")]
new_in_box( pcr_index: PcrIndex, event_type: EventType, event_data: &[u8], ) -> Result<Box<Self>>227     pub fn new_in_box(
228         pcr_index: PcrIndex,
229         event_type: EventType,
230         event_data: &[u8],
231     ) -> Result<Box<Self>> {
232         #[cfg(not(feature = "unstable"))]
233         {
234             make_boxed(|buf| Self::new_in_buffer(buf, pcr_index, event_type, event_data))
235         }
236         #[cfg(feature = "unstable")]
237         {
238             make_boxed(
239                 |buf| Self::new_in_buffer(buf, pcr_index, event_type, event_data),
240                 Global,
241             )
242         }
243     }
244 }
245 
246 impl Align for PcrEventInputs {
alignment() -> usize247     fn alignment() -> usize {
248         1
249     }
250 }
251 
252 impl Debug for PcrEventInputs {
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result253     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
254         f.debug_struct("PcrEventInputs")
255             .field("size", &{ self.size })
256             .field("event_header", &self.event_header)
257             .field("event", &"<binary data>")
258             .finish()
259     }
260 }
261 
262 // Manual `PartialEq` implementation since it can't be derived for a packed DST.
263 impl PartialEq for PcrEventInputs {
eq(&self, other: &Self) -> bool264     fn eq(&self, other: &Self) -> bool {
265         self.size == other.size
266             && self.event_header == other.event_header
267             && self.event == other.event
268     }
269 }
270 
271 #[repr(C, packed)]
272 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
273 struct AlgorithmDigestSize {
274     algorithm_id: AlgorithmId,
275     digest_size: u16,
276 }
277 
278 #[derive(Clone, Debug)]
279 struct AlgorithmDigestSizes<'a>(UnalignedSlice<'a, AlgorithmDigestSize>);
280 
281 impl<'a> AlgorithmDigestSizes<'a> {
get_size(&self, alg: AlgorithmId) -> Option<u16>282     fn get_size(&self, alg: AlgorithmId) -> Option<u16> {
283         self.0.iter().find_map(|elem| {
284             if { elem.algorithm_id } == alg {
285                 Some(elem.digest_size)
286             } else {
287                 None
288             }
289         })
290     }
291 }
292 
u32_le_from_bytes_at_offset(bytes: &[u8], offset: usize) -> Option<u32>293 fn u32_le_from_bytes_at_offset(bytes: &[u8], offset: usize) -> Option<u32> {
294     let bytes = bytes.get(offset..offset + 4)?;
295     // OK to unwrap: we know `bytes` is now of length 4.
296     let val = u32::from_le_bytes(bytes.try_into().unwrap());
297     Some(val)
298 }
299 
300 /// Header stored at the beginning of the event log.
301 ///
302 /// Layout compatible with the C type `TCG_EfiSpecIDEventStruct`.
303 #[derive(Clone, Debug)]
304 #[allow(unused)] // We don't current access most of the fields.
305 struct EventLogHeader<'a> {
306     platform_class: u32,
307     // major, minor, errata
308     spec_version: (u8, u8, u8),
309     uintn_size: u8,
310     algorithm_digest_sizes: AlgorithmDigestSizes<'a>,
311     vendor_info: &'a [u8],
312     // Size of the whole header event, in bytes.
313     size_in_bytes: usize,
314 }
315 
316 impl<'a> EventLogHeader<'a> {
new(event: &'a v1::PcrEvent) -> Option<Self>317     fn new(event: &'a v1::PcrEvent) -> Option<Self> {
318         if event.pcr_index() != PcrIndex(0) {
319             return None;
320         }
321         if { event.event_type() } != EventType::NO_ACTION {
322             return None;
323         }
324         if event.digest() != [0; 20] {
325             return None;
326         }
327 
328         let event = &event.event_data();
329         if event.get(..16)? != *b"Spec ID Event03\0" {
330             return None;
331         }
332         let platform_class = u32_le_from_bytes_at_offset(event, 16)?;
333         let version_minor = *event.get(20)?;
334         let version_major = *event.get(21)?;
335         let version_errata = *event.get(22)?;
336         let uintn_size = *event.get(23)?;
337         let number_of_algorithms = usize_from_u32(u32_le_from_bytes_at_offset(event, 24)?);
338         let vendor_info_size_byte_offset =
339             28 + (number_of_algorithms * mem::size_of::<AlgorithmDigestSize>());
340         let vendor_info_size = usize::from(*event.get(vendor_info_size_byte_offset)?);
341 
342         // Safety: we know the slice is big enough because we just
343         // safely got the field after the slice (`vendor_info_size`).
344         let algorithm_digest_sizes = unsafe {
345             let ptr: *const AlgorithmDigestSize = event.as_ptr().add(28).cast();
346             AlgorithmDigestSizes(UnalignedSlice::new(ptr, number_of_algorithms))
347         };
348 
349         let vendor_info_byte_offset = vendor_info_size_byte_offset + 1;
350         let vendor_info =
351             event.get(vendor_info_byte_offset..vendor_info_byte_offset + vendor_info_size)?;
352 
353         // 32 is the size of PcrEventV1 excluding the event data.
354         let size_in_bytes = 32 + vendor_info_byte_offset + vendor_info_size;
355 
356         Some(Self {
357             platform_class,
358             spec_version: (version_major, version_minor, version_errata),
359             uintn_size,
360             algorithm_digest_sizes,
361             vendor_info,
362             size_in_bytes,
363         })
364     }
365 }
366 
367 /// TPM event log as returned by [`Tcg::get_event_log_v2`].
368 ///
369 /// This type of event log can contain multiple hash types (e.g. SHA-1, SHA-256,
370 /// SHA-512, etc).
371 #[derive(Debug)]
372 pub struct EventLog<'a> {
373     // Tie the lifetime to the protocol, and by extension, boot services.
374     _lifetime: PhantomData<&'a Tcg>,
375 
376     location: *const u8,
377     last_entry: *const u8,
378 
379     is_truncated: bool,
380 }
381 
382 impl<'a> EventLog<'a> {
383     /// Iterator of events in the log.
384     #[must_use]
iter(&self) -> EventLogIter385     pub fn iter(&self) -> EventLogIter {
386         if let Some(header) = self.header() {
387             // Advance past the header
388             let location = unsafe { self.location.add(header.size_in_bytes) };
389 
390             EventLogIter {
391                 log: self,
392                 location,
393                 header: self.header(),
394             }
395         } else {
396             EventLogIter {
397                 log: self,
398                 location: ptr::null(),
399                 header: None,
400             }
401         }
402     }
403 
404     /// Header at the beginning of the event log.
header(&self) -> Option<EventLogHeader>405     fn header(&self) -> Option<EventLogHeader> {
406         // The spec is unclear if the header is present when there are
407         // no entries, so lets assume that `self.location` will be null
408         // if there's no header, and otherwise valid.
409         if self.location.is_null() {
410             None
411         } else {
412             // Safety: we trust that the protocol has given us a valid range
413             // of memory to read from.
414             let event = unsafe { v1::PcrEvent::from_ptr(self.location) };
415             EventLogHeader::new(event)
416         }
417     }
418 
419     /// Whether the event log is truncated due to not enough space in the log to
420     /// contain some events.
421     #[must_use]
is_truncated(&self) -> bool422     pub const fn is_truncated(&self) -> bool {
423         self.is_truncated
424     }
425 }
426 
427 /// Digests in a PCR event.
428 #[derive(Clone)]
429 pub struct PcrEventDigests<'a> {
430     data: &'a [u8],
431     algorithm_digest_sizes: AlgorithmDigestSizes<'a>,
432 }
433 
434 impl<'a> Debug for PcrEventDigests<'a> {
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result435     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
436         f.debug_list().entries(self.clone()).finish()
437     }
438 }
439 
440 impl<'a> IntoIterator for PcrEventDigests<'a> {
441     type Item = (AlgorithmId, &'a [u8]);
442     type IntoIter = PcrEventDigestIter<'a>;
443 
into_iter(self) -> Self::IntoIter444     fn into_iter(self) -> Self::IntoIter {
445         PcrEventDigestIter {
446             digests: self,
447             offset: 0,
448         }
449     }
450 }
451 
452 /// Iterator over a list of digests.
453 #[derive(Debug)]
454 pub struct PcrEventDigestIter<'a> {
455     digests: PcrEventDigests<'a>,
456     offset: usize,
457 }
458 
459 impl<'a> Iterator for PcrEventDigestIter<'a> {
460     type Item = (AlgorithmId, &'a [u8]);
461 
next(&mut self) -> Option<Self::Item>462     fn next(&mut self) -> Option<Self::Item> {
463         let data = &self.digests.data[self.offset..];
464         let alg = data.get(..2)?;
465         let alg = AlgorithmId(u16::from_le_bytes([alg[0], alg[1]]));
466         let digest_size = usize::from(self.digests.algorithm_digest_sizes.get_size(alg)?);
467         let digest = data.get(2..2 + digest_size)?;
468         self.offset += 2 + digest_size;
469         Some((alg, digest))
470     }
471 }
472 
473 /// PCR event from an [`EventLog`].
474 ///
475 /// This roughly corresponds to the C type `TCG_PCR_EVENT2`, but is not layout
476 /// compatible.
477 ///
478 /// The TPM v1 spec uses a single generic event type for both creating a
479 /// new event and reading an event from the log. The v2 spec splits this
480 /// into two structs: `EFI_TCG2_EVENT` for creating events, and
481 /// `TCG_PCR_EVENT2` for reading events. To help clarify the usage, our
482 /// API renames these types to `PcrEventInputs` and `PcrEvent`,
483 /// respectively.
484 #[derive(Debug)]
485 pub struct PcrEvent<'a> {
486     pcr_index: PcrIndex,
487     event_type: EventType,
488     digests: &'a [u8],
489     event_data: &'a [u8],
490 
491     // Precalculate the pointer to the next event.
492     next: *const u8,
493 
494     // This data from the v2 log header is needed to parse the digest data.
495     algorithm_digest_sizes: AlgorithmDigestSizes<'a>,
496 }
497 
498 impl<'a> PcrEvent<'a> {
from_ptr(ptr: *const u8, header: EventLogHeader<'a>) -> Option<Self>499     unsafe fn from_ptr(ptr: *const u8, header: EventLogHeader<'a>) -> Option<Self> {
500         let ptr_u32: *const u32 = ptr.cast();
501         let pcr_index = PcrIndex(ptr_u32.read_unaligned());
502         let event_type = EventType(ptr_u32.add(1).read_unaligned());
503         let digests_count = ptr_u32.add(2).read_unaligned();
504         let digests_ptr: *const u8 = ptr.add(12);
505 
506         // Get the byte size of the digests so that the digests iterator
507         // can be safe code.
508         let mut digests_byte_size = 0;
509         let mut elem_ptr = digests_ptr;
510         for _ in 0..digests_count {
511             let algorithm_id = AlgorithmId(elem_ptr.cast::<u16>().read_unaligned());
512             let alg_and_digest_size = mem::size_of::<AlgorithmId>()
513                 + usize::from(header.algorithm_digest_sizes.get_size(algorithm_id)?);
514             digests_byte_size += alg_and_digest_size;
515             elem_ptr = elem_ptr.add(alg_and_digest_size);
516         }
517 
518         let digests = slice::from_raw_parts(digests_ptr, digests_byte_size);
519         let event_size_ptr = digests_ptr.add(digests_byte_size);
520         let event_size = usize_from_u32(event_size_ptr.cast::<u32>().read_unaligned());
521         let event_data_ptr = event_size_ptr.add(4);
522         let event_data = slice::from_raw_parts(event_data_ptr, event_size);
523 
524         Some(Self {
525             pcr_index,
526             event_type,
527             digests,
528             event_data,
529             next: event_data_ptr.add(event_size),
530             algorithm_digest_sizes: header.algorithm_digest_sizes,
531         })
532     }
533 
534     /// PCR index for the event.
535     #[must_use]
pcr_index(&self) -> PcrIndex536     pub const fn pcr_index(&self) -> PcrIndex {
537         self.pcr_index
538     }
539 
540     /// Type of event, indicating what type of data is stored in [`event_data`].
541     ///
542     /// [`event_data`]: Self::event_data
543     #[must_use]
event_type(&self) -> EventType544     pub const fn event_type(&self) -> EventType {
545         self.event_type
546     }
547 
548     /// Raw event data. The meaning of this data can be determined from
549     /// the [`event_type`].
550     ///
551     /// Note that this data is independent of what is hashed in [`digests`].
552     ///
553     /// [`digests`]: Self::digests
554     /// [`event_type`]: Self::event_type
555     #[must_use]
event_data(&self) -> &[u8]556     pub const fn event_data(&self) -> &[u8] {
557         self.event_data
558     }
559 
560     /// Digests of the data hashed for this event.
561     #[must_use]
digests(&self) -> PcrEventDigests562     pub fn digests(&self) -> PcrEventDigests {
563         PcrEventDigests {
564             data: self.digests,
565             algorithm_digest_sizes: self.algorithm_digest_sizes.clone(),
566         }
567     }
568 }
569 
570 /// Iterator for events in [`EventLog`].
571 #[derive(Debug)]
572 pub struct EventLogIter<'a> {
573     log: &'a EventLog<'a>,
574     header: Option<EventLogHeader<'a>>,
575     location: *const u8,
576 }
577 
578 impl<'a> Iterator for EventLogIter<'a> {
579     type Item = PcrEvent<'a>;
580 
next(&mut self) -> Option<Self::Item>581     fn next(&mut self) -> Option<Self::Item> {
582         // The spec says that `last_entry` will be null if there are no
583         // events. Presumably `location` will be null as well, but check
584         // both just to be safe.
585         if self.location.is_null() || self.log.last_entry.is_null() {
586             return None;
587         }
588 
589         // Safety: we trust that the protocol has given us a valid range
590         // of memory to read from.
591         let event = unsafe { PcrEvent::from_ptr(self.location, self.header.clone()?)? };
592 
593         // If this is the last entry, set the location to null so that
594         // future calls to `next()` return `None`.
595         if self.location == self.log.last_entry {
596             self.location = ptr::null();
597         } else {
598             self.location = event.next;
599         }
600 
601         Some(event)
602     }
603 }
604 
605 /// Protocol for interacting with TPM devices.
606 ///
607 /// This protocol can be used for interacting with older TPM 1.1/1.2
608 /// devices, but most firmware only uses it for TPM 2.0.
609 ///
610 /// The corresponding C type is `EFI_TCG2_PROTOCOL`.
611 #[derive(Debug)]
612 #[repr(C)]
613 #[unsafe_protocol("607f766c-7455-42be-930b-e4d76db2720f")]
614 pub struct Tcg {
615     get_capability: unsafe extern "efiapi" fn(
616         this: *mut Tcg,
617         protocol_capability: *mut BootServiceCapability,
618     ) -> Status,
619 
620     get_event_log: unsafe extern "efiapi" fn(
621         this: *mut Tcg,
622         event_log_format: EventLogFormat,
623         event_log_location: *mut PhysicalAddress,
624         event_log_last_entry: *mut PhysicalAddress,
625         event_log_truncated: *mut u8,
626     ) -> Status,
627 
628     hash_log_extend_event: unsafe extern "efiapi" fn(
629         this: *mut Tcg,
630         flags: HashLogExtendEventFlags,
631         data_to_hash: PhysicalAddress,
632         data_to_hash_len: u64,
633         // Use `()` here rather than `PcrEventInputs` so that it's a
634         // thin pointer.
635         event: *const (),
636     ) -> Status,
637 
638     submit_command: unsafe extern "efiapi" fn(
639         this: *mut Tcg,
640         input_parameter_block_size: u32,
641         input_parameter_block: *const u8,
642         output_parameter_block_size: u32,
643         output_parameter_block: *mut u8,
644     ) -> Status,
645 
646     get_active_pcr_banks:
647         unsafe extern "efiapi" fn(this: *mut Tcg, active_pcr_banks: *mut HashAlgorithm) -> Status,
648 
649     set_active_pcr_banks:
650         unsafe extern "efiapi" fn(this: *mut Tcg, active_pcr_banks: HashAlgorithm) -> Status,
651 
652     get_result_of_set_active_pcr_banks: unsafe extern "efiapi" fn(
653         this: *mut Tcg,
654         operation_present: *mut u32,
655         response: *mut u32,
656     ) -> Status,
657 }
658 
659 impl Tcg {
660     /// Get information about the protocol and TPM device.
get_capability(&mut self) -> Result<BootServiceCapability>661     pub fn get_capability(&mut self) -> Result<BootServiceCapability> {
662         let mut capability = BootServiceCapability::default();
663         unsafe { (self.get_capability)(self, &mut capability).to_result_with_val(|| capability) }
664     }
665 
666     /// Get the V1 event log. This provides events in the same format as a V1
667     /// TPM, so all events use SHA-1 hashes.
get_event_log_v1(&mut self) -> Result<v1::EventLog>668     pub fn get_event_log_v1(&mut self) -> Result<v1::EventLog> {
669         let mut location = 0;
670         let mut last_entry = 0;
671         let mut truncated = 0;
672 
673         let status = unsafe {
674             (self.get_event_log)(
675                 self,
676                 EventLogFormat::TCG_1_2,
677                 &mut location,
678                 &mut last_entry,
679                 &mut truncated,
680             )
681         };
682 
683         if status.is_success() {
684             let is_truncated = truncated != 0;
685 
686             let log = unsafe {
687                 v1::EventLog::new(location as *const u8, last_entry as *const u8, is_truncated)
688             };
689 
690             Ok(log)
691         } else {
692             Err(status.into())
693         }
694     }
695 
696     /// Get the V2 event log. This format allows for a flexible list of hash types.
get_event_log_v2(&mut self) -> Result<EventLog>697     pub fn get_event_log_v2(&mut self) -> Result<EventLog> {
698         let mut location = 0;
699         let mut last_entry = 0;
700         let mut truncated = 0;
701 
702         let status = unsafe {
703             (self.get_event_log)(
704                 self,
705                 EventLogFormat::TCG_2,
706                 &mut location,
707                 &mut last_entry,
708                 &mut truncated,
709             )
710         };
711 
712         if status.is_success() {
713             let is_truncated = truncated != 0;
714 
715             let log = EventLog {
716                 _lifetime: PhantomData,
717                 location: location as *const u8,
718                 last_entry: last_entry as *const u8,
719                 is_truncated,
720             };
721 
722             Ok(log)
723         } else {
724             Err(status.into())
725         }
726     }
727 
728     /// Extend a PCR and add an entry to the event log.
hash_log_extend_event( &mut self, flags: HashLogExtendEventFlags, data_to_hash: &[u8], event: &PcrEventInputs, ) -> Result729     pub fn hash_log_extend_event(
730         &mut self,
731         flags: HashLogExtendEventFlags,
732         data_to_hash: &[u8],
733         event: &PcrEventInputs,
734     ) -> Result {
735         let event: *const PcrEventInputs = event;
736         let (event, _event_size) = PtrExt::to_raw_parts(event);
737         unsafe {
738             (self.hash_log_extend_event)(
739                 self,
740                 flags,
741                 data_to_hash.as_ptr() as PhysicalAddress,
742                 // OK to unwrap, usize fits in u64.
743                 u64::try_from(data_to_hash.len()).unwrap(),
744                 event,
745             )
746             .to_result()
747         }
748     }
749 
750     /// Send a command directly to the TPM.
751     ///
752     /// Constructing the input block and parsing the output block are outside
753     /// the scope of this crate. See the [TPM 2.0 Specification][spec], in
754     /// particular Part 2 (Structures) and Part 3 (Commands).
755     ///
756     /// Note that TPM structures are big endian.
757     ///
758     /// [spec]: https://trustedcomputinggroup.org/resource/tpm-library-specification/
submit_command( &mut self, input_parameter_block: &[u8], output_parameter_block: &mut [u8], ) -> Result759     pub fn submit_command(
760         &mut self,
761         input_parameter_block: &[u8],
762         output_parameter_block: &mut [u8],
763     ) -> Result {
764         let input_parameter_block_len = u32::try_from(input_parameter_block.len())
765             .map_err(|_| Error::from(Status::BAD_BUFFER_SIZE))?;
766         let output_parameter_block_len = u32::try_from(output_parameter_block.len())
767             .map_err(|_| Error::from(Status::BAD_BUFFER_SIZE))?;
768 
769         unsafe {
770             (self.submit_command)(
771                 self,
772                 input_parameter_block_len,
773                 input_parameter_block.as_ptr(),
774                 output_parameter_block_len,
775                 output_parameter_block.as_mut_ptr(),
776             )
777             .to_result()
778         }
779     }
780 
781     /// Get a bitmap of the active PCR banks. Each bank corresponds to a hash
782     /// algorithm.
get_active_pcr_banks(&mut self) -> Result<HashAlgorithm>783     pub fn get_active_pcr_banks(&mut self) -> Result<HashAlgorithm> {
784         let mut active_pcr_banks = HashAlgorithm::empty();
785 
786         let status = unsafe { (self.get_active_pcr_banks)(self, &mut active_pcr_banks) };
787 
788         status.to_result_with_val(|| active_pcr_banks)
789     }
790 
791     /// Set the active PCR banks. Each bank corresponds to a hash
792     /// algorithm. This change will not take effect until the system is
793     /// rebooted twice.
set_active_pcr_banks(&mut self, active_pcr_banks: HashAlgorithm) -> Result794     pub fn set_active_pcr_banks(&mut self, active_pcr_banks: HashAlgorithm) -> Result {
795         unsafe { (self.set_active_pcr_banks)(self, active_pcr_banks) }.to_result()
796     }
797 
798     /// Get the stored result of calling [`Tcg::set_active_pcr_banks`] in a
799     /// previous boot.
800     ///
801     /// If there was no attempt to set the active PCR banks in a previous boot,
802     /// this returns `None`. Otherwise, it returns a numeric response code:
803     /// * `0x00000000`: Success
804     /// * `0x00000001..=0x00000FFF`: TPM error code
805     /// * `0xfffffff0`: The operation was canceled by the user or timed out
806     /// * `0xfffffff1`: Firmware error
get_result_of_set_active_pcr_banks(&mut self) -> Result<Option<u32>>807     pub fn get_result_of_set_active_pcr_banks(&mut self) -> Result<Option<u32>> {
808         let mut operation_present = 0;
809         let mut response = 0;
810 
811         let status = unsafe {
812             (self.get_result_of_set_active_pcr_banks)(self, &mut operation_present, &mut response)
813         };
814 
815         status.to_result_with_val(|| {
816             if operation_present == 0 {
817                 None
818             } else {
819                 Some(response)
820             }
821         })
822     }
823 }
824 
825 #[cfg(test)]
826 mod tests {
827     use super::*;
828     use alloc::vec::Vec;
829     use core::slice;
830 
831     #[test]
test_new_event()832     fn test_new_event() {
833         let mut buf = [0; 22];
834         let event_data = [0x12, 0x13, 0x14, 0x15];
835         let event =
836             PcrEventInputs::new_in_buffer(&mut buf, PcrIndex(4), EventType::IPL, &event_data)
837                 .unwrap();
838 
839         assert_eq!({ event.size }, 22);
840         assert_eq!(
841             event.event_header,
842             EventHeader {
843                 header_size: 14,
844                 header_version: 1,
845                 pcr_index: PcrIndex(4),
846                 event_type: EventType::IPL,
847             }
848         );
849 
850         // Cast to a byte slice to check the data is exactly as expected.
851         let event_ptr: *const PcrEventInputs = event;
852         let event_ptr: *const u8 = event_ptr.cast();
853         let event_bytes = unsafe { slice::from_raw_parts(event_ptr, mem::size_of_val(event)) };
854 
855         #[rustfmt::skip]
856         assert_eq!(event_bytes, [
857             // Size
858             0x16, 0x00, 0x00, 0x00,
859 
860             // Header
861             // Header size
862             0x0e, 0x00, 0x00, 0x00,
863             // Header version
864             0x01, 0x00,
865             // PCR index
866             0x04, 0x00, 0x00, 0x00,
867             // Event type
868             0x0d, 0x00, 0x00, 0x00,
869             // Event data
870             0x12, 0x13, 0x14, 0x15,
871         ]);
872 
873         // Check that `new_in_box` gives the same value.
874         assert_eq!(
875             event,
876             &*PcrEventInputs::new_in_box(PcrIndex(4), EventType::IPL, &event_data).unwrap()
877         );
878     }
879 
880     #[test]
test_event_log_v2()881     fn test_event_log_v2() {
882         // This data comes from dumping the TPM event log in a VM
883         // (truncated to just two entries after the header).
884         #[rustfmt::skip]
885         let bytes = [
886             // Header event
887             // PCR index
888             0x00, 0x00, 0x00, 0x00,
889             // Event type
890             0x03, 0x00, 0x00, 0x00,
891             // SHA1 digest
892             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
893             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
894             // Event data size
895             0x2d, 0x00, 0x00, 0x00,
896             // Spec ID event data
897             // Signature
898             0x53, 0x70, 0x65, 0x63,
899             0x20, 0x49, 0x44, 0x20,
900             0x45, 0x76, 0x65, 0x6e,
901             0x74, 0x30, 0x33, 0x00,
902             // Platform class
903             0x00, 0x00, 0x00, 0x00,
904             // Spec version (minor, major, errata) (yes the order is weird)
905             0x00, 0x02, 0x00,
906             // Uintn size
907             0x02,
908             // Number of algorithms
909             0x04, 0x00, 0x00, 0x00,
910             // Digest sizes
911             // SHA1, size
912             0x04, 0x00,
913             0x14, 0x00,
914             // SHA256, size
915             0x0b, 0x00,
916             0x20, 0x00,
917             // SHA384, size
918             0x0c, 0x00,
919             0x30, 0x00,
920             // SHA512, size
921             0x0d, 0x00,
922             0x40, 0x00,
923             // Vendor info size
924             0x00,
925 
926             // Event 1
927             // PCR index
928             0x00, 0x00, 0x00, 0x00,
929             // Event type
930             0x08, 0x00, 0x00, 0x00,
931             // Digest count
932             0x04, 0x00, 0x00, 0x00,
933             // Digests
934             // SHA1
935             0x04, 0x00,
936             0x14, 0x89, 0xf9, 0x23, 0xc4, 0xdc, 0xa7, 0x29, 0x17, 0x8b,
937             0x3e, 0x32, 0x33, 0x45, 0x85, 0x50, 0xd8, 0xdd, 0xdf, 0x29,
938             // SHA256
939             0x0b, 0x00,
940             0x96, 0xa2, 0x96, 0xd2, 0x24, 0xf2, 0x85, 0xc6,
941             0x7b, 0xee, 0x93, 0xc3, 0x0f, 0x8a, 0x30, 0x91,
942             0x57, 0xf0, 0xda, 0xa3, 0x5d, 0xc5, 0xb8, 0x7e,
943             0x41, 0x0b, 0x78, 0x63, 0x0a, 0x09, 0xcf, 0xc7,
944             // SHA384
945             0x0c, 0x00,
946             0x1d, 0xd6, 0xf7, 0xb4, 0x57, 0xad, 0x88, 0x0d,
947             0x84, 0x0d, 0x41, 0xc9, 0x61, 0x28, 0x3b, 0xab,
948             0x68, 0x8e, 0x94, 0xe4, 0xb5, 0x93, 0x59, 0xea,
949             0x45, 0x68, 0x65, 0x81, 0xe9, 0x0f, 0xec, 0xce,
950             0xa3, 0xc6, 0x24, 0xb1, 0x22, 0x61, 0x13, 0xf8,
951             0x24, 0xf3, 0x15, 0xeb, 0x60, 0xae, 0x0a, 0x7c,
952             // SHA512
953             0x0d, 0x00,
954             0x5e, 0xa7, 0x1d, 0xc6, 0xd0, 0xb4, 0xf5, 0x7b,
955             0xf3, 0x9a, 0xad, 0xd0, 0x7c, 0x20, 0x8c, 0x35,
956             0xf0, 0x6c, 0xd2, 0xba, 0xc5, 0xfd, 0xe2, 0x10,
957             0x39, 0x7f, 0x70, 0xde, 0x11, 0xd4, 0x39, 0xc6,
958             0x2e, 0xc1, 0xcd, 0xf3, 0x18, 0x37, 0x58, 0x86,
959             0x5f, 0xd3, 0x87, 0xfc, 0xea, 0x0b, 0xad, 0xa2,
960             0xf6, 0xc3, 0x7a, 0x4a, 0x17, 0x85, 0x1d, 0xd1,
961             0xd7, 0x8f, 0xef, 0xe6, 0xf2, 0x04, 0xee, 0x54,
962             // Event size
963             0x02, 0x00, 0x00, 0x00,
964             // Event data
965             0x00, 0x00,
966 
967             // Event 2
968             // PCR index
969             0x00, 0x00, 0x00, 0x00,
970             // Event type
971             0x08, 0x00, 0x00, 0x80,
972             // Digest count
973             0x04, 0x00, 0x00, 0x00,
974             // SHA1
975             0x04, 0x00,
976             0xc7, 0x06, 0xe7, 0xdd, 0x36, 0x39, 0x29, 0x84, 0xeb, 0x06,
977             0xaa, 0xa0, 0x8f, 0xf3, 0x36, 0x84, 0x40, 0x77, 0xb3, 0xed,
978             // SHA256
979             0x0b, 0x00,
980             0x3a, 0x30, 0x8e, 0x95, 0x87, 0x84, 0xbf, 0xd0,
981             0xf6, 0xe3, 0xf1, 0xbd, 0x4d, 0x42, 0x14, 0xd3,
982             0x0a, 0x4c, 0x55, 0x00, 0xa4, 0x5b, 0x06, 0xda,
983             0x96, 0xfc, 0x90, 0x33, 0x8f, 0x69, 0xb3, 0x61,
984             // SHA384
985             0x0c, 0x00,
986             0xc0, 0xd0, 0x75, 0x96, 0xc5, 0x9a, 0x90, 0x7b,
987             0x79, 0x71, 0x6f, 0xc9, 0xf3, 0x6a, 0xad, 0x8f,
988             0x0f, 0x26, 0xf2, 0x02, 0x67, 0x5b, 0x42, 0x5a,
989             0x52, 0x3f, 0x72, 0xec, 0xb6, 0xf2, 0x53, 0x99,
990             0x57, 0xf0, 0xd9, 0x2c, 0x0a, 0x7d, 0xce, 0xaa,
991             0xf9, 0x9e, 0x60, 0x0e, 0x54, 0x18, 0xf1, 0xdc,
992             // SHA512
993             0x0d, 0x00,
994             0x9a, 0xe9, 0x25, 0xdc, 0x9c, 0xd2, 0x9d, 0xf0,
995             0xe5, 0x80, 0x54, 0x35, 0xa5, 0x99, 0x06, 0x1f,
996             0xcf, 0x32, 0x98, 0xcc, 0x2a, 0x15, 0xe4, 0x87,
997             0x99, 0xa2, 0x0c, 0x9c, 0xe5, 0x6c, 0x8f, 0xe5,
998             0x84, 0x09, 0x75, 0xaf, 0xf0, 0xe1, 0xb6, 0x98,
999             0x20, 0x07, 0x5e, 0xe4, 0x29, 0x79, 0x8b, 0x5d,
1000             0xbb, 0xe5, 0xd1, 0xa2, 0x74, 0x36, 0xab, 0x49,
1001             0xf1, 0x9b, 0x7a, 0x04, 0x11, 0xd2, 0x96, 0x2c,
1002             // Event size
1003             0x10, 0x00, 0x00, 0x00,
1004             // Event data
1005             0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00,
1006             0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
1007         ];
1008 
1009         let log = EventLog {
1010             _lifetime: PhantomData,
1011             location: bytes.as_ptr(),
1012             last_entry: unsafe { bytes.as_ptr().add(267) },
1013             is_truncated: false,
1014         };
1015 
1016         let header = log.header().unwrap();
1017         assert_eq!(header.platform_class, 0);
1018         assert_eq!(header.spec_version, (2, 0, 0));
1019         assert_eq!(header.uintn_size, 2);
1020         assert_eq!(
1021             header.algorithm_digest_sizes.0.to_vec(),
1022             [
1023                 AlgorithmDigestSize {
1024                     algorithm_id: AlgorithmId::SHA1,
1025                     digest_size: 20,
1026                 },
1027                 AlgorithmDigestSize {
1028                     algorithm_id: AlgorithmId::SHA256,
1029                     digest_size: 32,
1030                 },
1031                 AlgorithmDigestSize {
1032                     algorithm_id: AlgorithmId::SHA384,
1033                     digest_size: 48,
1034                 },
1035                 AlgorithmDigestSize {
1036                     algorithm_id: AlgorithmId::SHA512,
1037                     digest_size: 64,
1038                 },
1039             ]
1040         );
1041         assert_eq!(header.vendor_info, []);
1042 
1043         let mut iter = log.iter();
1044 
1045         // Entry 1
1046         let entry = iter.next().unwrap();
1047         assert_eq!(entry.pcr_index, PcrIndex(0));
1048         assert_eq!(entry.event_type, EventType::CRTM_VERSION);
1049         #[rustfmt::skip]
1050         assert_eq!(
1051             entry.digests().into_iter().collect::<Vec<_>>(),
1052             [
1053                 (AlgorithmId::SHA1, [
1054                     0x14, 0x89, 0xf9, 0x23, 0xc4, 0xdc, 0xa7, 0x29, 0x17, 0x8b,
1055                     0x3e, 0x32, 0x33, 0x45, 0x85, 0x50, 0xd8, 0xdd, 0xdf, 0x29,
1056                 ].as_slice()),
1057                 (AlgorithmId::SHA256, [
1058                     0x96, 0xa2, 0x96, 0xd2, 0x24, 0xf2, 0x85, 0xc6,
1059                     0x7b, 0xee, 0x93, 0xc3, 0x0f, 0x8a, 0x30, 0x91,
1060                     0x57, 0xf0, 0xda, 0xa3, 0x5d, 0xc5, 0xb8, 0x7e,
1061                     0x41, 0x0b, 0x78, 0x63, 0x0a, 0x09, 0xcf, 0xc7,
1062                 ].as_slice()),
1063                 (AlgorithmId::SHA384, [
1064                     0x1d, 0xd6, 0xf7, 0xb4, 0x57, 0xad, 0x88, 0x0d,
1065                     0x84, 0x0d, 0x41, 0xc9, 0x61, 0x28, 0x3b, 0xab,
1066                     0x68, 0x8e, 0x94, 0xe4, 0xb5, 0x93, 0x59, 0xea,
1067                     0x45, 0x68, 0x65, 0x81, 0xe9, 0x0f, 0xec, 0xce,
1068                     0xa3, 0xc6, 0x24, 0xb1, 0x22, 0x61, 0x13, 0xf8,
1069                     0x24, 0xf3, 0x15, 0xeb, 0x60, 0xae, 0x0a, 0x7c,
1070                 ].as_slice()),
1071                 (AlgorithmId::SHA512, [
1072                     0x5e, 0xa7, 0x1d, 0xc6, 0xd0, 0xb4, 0xf5, 0x7b,
1073                     0xf3, 0x9a, 0xad, 0xd0, 0x7c, 0x20, 0x8c, 0x35,
1074                     0xf0, 0x6c, 0xd2, 0xba, 0xc5, 0xfd, 0xe2, 0x10,
1075                     0x39, 0x7f, 0x70, 0xde, 0x11, 0xd4, 0x39, 0xc6,
1076                     0x2e, 0xc1, 0xcd, 0xf3, 0x18, 0x37, 0x58, 0x86,
1077                     0x5f, 0xd3, 0x87, 0xfc, 0xea, 0x0b, 0xad, 0xa2,
1078                     0xf6, 0xc3, 0x7a, 0x4a, 0x17, 0x85, 0x1d, 0xd1,
1079                     0xd7, 0x8f, 0xef, 0xe6, 0xf2, 0x04, 0xee, 0x54,
1080                 ].as_slice()),
1081             ]
1082         );
1083         assert_eq!(entry.event_data, [0, 0]);
1084 
1085         // Entry 2
1086         let entry = iter.next().unwrap();
1087         assert_eq!(entry.pcr_index, PcrIndex(0));
1088         assert_eq!(entry.event_type, EventType::EFI_PLATFORM_FIRMWARE_BLOB);
1089         #[rustfmt::skip]
1090         assert_eq!(
1091             entry.digests().into_iter().collect::<Vec<_>>(),
1092             [
1093                 (AlgorithmId::SHA1, [
1094                     0xc7, 0x06, 0xe7, 0xdd, 0x36, 0x39, 0x29, 0x84, 0xeb, 0x06,
1095                     0xaa, 0xa0, 0x8f, 0xf3, 0x36, 0x84, 0x40, 0x77, 0xb3, 0xed,
1096                 ].as_slice()),
1097                 (AlgorithmId::SHA256, [
1098                     0x3a, 0x30, 0x8e, 0x95, 0x87, 0x84, 0xbf, 0xd0,
1099                     0xf6, 0xe3, 0xf1, 0xbd, 0x4d, 0x42, 0x14, 0xd3,
1100                     0x0a, 0x4c, 0x55, 0x00, 0xa4, 0x5b, 0x06, 0xda,
1101                     0x96, 0xfc, 0x90, 0x33, 0x8f, 0x69, 0xb3, 0x61,
1102                 ].as_slice()),
1103                 (AlgorithmId::SHA384, [
1104                     0xc0, 0xd0, 0x75, 0x96, 0xc5, 0x9a, 0x90, 0x7b,
1105                     0x79, 0x71, 0x6f, 0xc9, 0xf3, 0x6a, 0xad, 0x8f,
1106                     0x0f, 0x26, 0xf2, 0x02, 0x67, 0x5b, 0x42, 0x5a,
1107                     0x52, 0x3f, 0x72, 0xec, 0xb6, 0xf2, 0x53, 0x99,
1108                     0x57, 0xf0, 0xd9, 0x2c, 0x0a, 0x7d, 0xce, 0xaa,
1109                     0xf9, 0x9e, 0x60, 0x0e, 0x54, 0x18, 0xf1, 0xdc,
1110                 ].as_slice()),
1111                 (AlgorithmId::SHA512, [
1112                     0x9a, 0xe9, 0x25, 0xdc, 0x9c, 0xd2, 0x9d, 0xf0,
1113                     0xe5, 0x80, 0x54, 0x35, 0xa5, 0x99, 0x06, 0x1f,
1114                     0xcf, 0x32, 0x98, 0xcc, 0x2a, 0x15, 0xe4, 0x87,
1115                     0x99, 0xa2, 0x0c, 0x9c, 0xe5, 0x6c, 0x8f, 0xe5,
1116                     0x84, 0x09, 0x75, 0xaf, 0xf0, 0xe1, 0xb6, 0x98,
1117                     0x20, 0x07, 0x5e, 0xe4, 0x29, 0x79, 0x8b, 0x5d,
1118                     0xbb, 0xe5, 0xd1, 0xa2, 0x74, 0x36, 0xab, 0x49,
1119                     0xf1, 0x9b, 0x7a, 0x04, 0x11, 0xd2, 0x96, 0x2c,
1120                 ].as_slice()),
1121             ]
1122         );
1123         #[rustfmt::skip]
1124         assert_eq!(entry.event_data, [
1125             0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00,
1126             0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
1127         ]);
1128 
1129         assert!(iter.next().is_none());
1130     }
1131 }
1132