1#![deny(clippy::all)]
6#![deny(clippy::pedantic)]
7
8use nix::{
9 fcntl,
10 poll::{PollFd, PollFlags, poll},
11};
12use rand::{RngCore, thread_rng};
13use std::{
14 cell::RefCell,
15 fs::{File, OpenOptions},
16 io::{Read, Write},
17 os::fd::{AsFd, AsRawFd},
18 path::{Path, PathBuf},
19 rc::Rc,
20 time::{Duration, Instant},
21};
22
23use core::fmt;
24use tpm2_crypto::TpmHash;
25use tpm2_protocol::{
26 TpmCast, TpmError, TpmField, TpmWriter,
27 basic::{Tpm2b as Tpm2bWire, TpmBuffer, TpmHandle, TpmList, TpmUint16, TpmUint32, TpmUint64},
28 constant::{MAX_HANDLES, TPM_MAX_COMMAND_SIZE},
29 data::{
30 Tpm2bDigest, Tpm2bEccParameter, Tpm2bEncryptedSecret, Tpm2bName, Tpm2bNonce,
31 Tpm2bPublicKeyRsa, Tpm2bSymKey, TpmAlgId, TpmCap, TpmCc, TpmEccCurve, TpmHt, TpmPt, TpmRc,
32 TpmRcBase, TpmRh, TpmSe, TpmSt, TpmaAlgorithm, TpmaCc, TpmaObject, TpmaSession, TpmiYesNo,
33 TpmsAlgProperty, TpmsAuthCommand, TpmsCapabilityData, TpmsContext, TpmsEccParms,
34 TpmsEccPoint, TpmsKeyedhashParms, TpmsPcrSelect, TpmsPcrSelection, TpmsRsaParms,
35 TpmsSchemeHash, TpmsSchemeXor, TpmsSymcipherParms, TpmsTaggedProperty, TpmtEccScheme,
36 TpmtKdfScheme, TpmtKeyedhashScheme, TpmtPublic, TpmtRsaScheme, TpmtSymDefObject,
37 TpmuAsymScheme, TpmuCapabilities, TpmuKdfScheme, TpmuKeyedhashScheme, TpmuPublicId,
38 TpmuPublicParms, TpmuSymKeyBits, TpmuSymMode,
39 },
40 frame::{
41 TpmAuthCommands, TpmCommandValue as TpmCommand, TpmContextLoadCommand,
42 TpmContextSaveCommand, TpmFlushContextCommand, TpmFrame, TpmGetCapabilityCommand,
43 TpmReadPublicCommand, TpmResponse, TpmResponseView, TpmStartAuthSessionCommand,
44 tpm_marshal_command,
45 },
46};
47use tracing::{debug, trace};
48
49#[derive(Debug, strum::AsRefStr)]
54#[strum(serialize_all = "title_case")]
55#[non_exhaustive]
56pub enum TpmDeviceError {
57 AlreadyBorrowed,
59
60 CapabilityMissing(TpmCap),
62
63 Interrupted,
65
66 InvalidCc(tpm2_protocol::data::TpmCc),
68
69 InvalidResponse,
71
72 Io(std::io::Error),
74
75 Marshal(TpmError),
77
78 NotAvailable,
80
81 PcrBanksNotAvailable,
83
84 PcrBankSelectionMismatch,
86
87 ResponseMismatch(TpmCc),
89
90 Timeout,
92
93 TpmRc(TpmRc),
95
96 TrailingData,
98
99 Unmarshal(TpmError),
101
102 UnexpectedEof,
104
105 UnsupportedAlgorithm(TpmAlgId),
107}
108
109impl fmt::Display for TpmDeviceError {
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 write!(f, "{}", self.as_ref().to_lowercase())
112 }
113}
114
115impl std::error::Error for TpmDeviceError {}
116
117impl PartialEq for TpmDeviceError {
118 fn eq(&self, other: &Self) -> bool {
119 match (self, other) {
120 (Self::CapabilityMissing(a), Self::CapabilityMissing(b)) => a == b,
121 (Self::InvalidCc(a), Self::InvalidCc(b))
122 | (Self::ResponseMismatch(a), Self::ResponseMismatch(b)) => a == b,
123 (Self::Io(a), Self::Io(b)) => a.kind() == b.kind(),
124 (Self::Marshal(a), Self::Marshal(b)) | (Self::Unmarshal(a), Self::Unmarshal(b)) => {
125 a == b
126 }
127 (Self::TpmRc(a), Self::TpmRc(b)) => a == b,
128 (Self::UnsupportedAlgorithm(a), Self::UnsupportedAlgorithm(b)) => a == b,
129 (Self::AlreadyBorrowed, Self::AlreadyBorrowed)
130 | (Self::Interrupted, Self::Interrupted)
131 | (Self::InvalidResponse, Self::InvalidResponse)
132 | (Self::NotAvailable, Self::NotAvailable)
133 | (Self::PcrBanksNotAvailable, Self::PcrBanksNotAvailable)
134 | (Self::PcrBankSelectionMismatch, Self::PcrBankSelectionMismatch)
135 | (Self::Timeout, Self::Timeout)
136 | (Self::TrailingData, Self::TrailingData)
137 | (Self::UnexpectedEof, Self::UnexpectedEof) => true,
138 _ => false,
139 }
140 }
141}
142
143impl Eq for TpmDeviceError {}
144
145impl From<TpmRc> for TpmDeviceError {
146 fn from(rc: TpmRc) -> Self {
147 Self::TpmRc(rc)
148 }
149}
150
151impl From<std::io::Error> for TpmDeviceError {
152 fn from(err: std::io::Error) -> Self {
153 Self::Io(err)
154 }
155}
156
157impl From<nix::Error> for TpmDeviceError {
158 fn from(err: nix::Error) -> Self {
159 Self::Io(std::io::Error::from_raw_os_error(err as i32))
160 }
161}
162
163pub fn with_device<F, T, E>(device: Option<&Rc<RefCell<TpmDevice>>>, function: F) -> Result<T, E>
177where
178 F: FnOnce(&mut TpmDevice) -> Result<T, E>,
179 E: From<TpmDeviceError>,
180{
181 let device_rc = device.ok_or(TpmDeviceError::NotAvailable)?;
182 let mut device_guard = device_rc
183 .try_borrow_mut()
184 .map_err(|_| TpmDeviceError::AlreadyBorrowed)?;
185 function(&mut device_guard)
186}
187
188pub struct TpmDeviceBuilder {
190 path: PathBuf,
191 timeout: Duration,
192 interrupted: Box<dyn Fn() -> bool>,
193}
194
195impl Default for TpmDeviceBuilder {
196 fn default() -> Self {
197 Self {
198 path: PathBuf::from("/dev/tpmrm0"),
199 timeout: Duration::from_secs(120),
200 interrupted: Box::new(|| false),
201 }
202 }
203}
204
205impl TpmDeviceBuilder {
206 #[must_use]
208 pub fn with_path<P: AsRef<Path>>(mut self, path: P) -> Self {
209 self.path = path.as_ref().to_path_buf();
210 self
211 }
212
213 #[must_use]
215 pub fn with_timeout(mut self, timeout: Duration) -> Self {
216 self.timeout = timeout;
217 self
218 }
219
220 #[must_use]
222 pub fn with_interrupted<F>(mut self, handler: F) -> Self
223 where
224 F: Fn() -> bool + 'static,
225 {
226 self.interrupted = Box::new(handler);
227 self
228 }
229
230 pub fn build(self) -> Result<TpmDevice, TpmDeviceError> {
237 let file = OpenOptions::new()
238 .read(true)
239 .write(true)
240 .open(&self.path)
241 .map_err(TpmDeviceError::Io)?;
242
243 let fd = file.as_raw_fd();
244 let flags = fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFL)?;
245 let mut oflags = fcntl::OFlag::from_bits_truncate(flags);
246 oflags.insert(fcntl::OFlag::O_NONBLOCK);
247 fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFL(oflags))?;
248
249 Ok(TpmDevice {
250 file,
251 interrupted: self.interrupted,
252 timeout: self.timeout,
253 command: Vec::with_capacity(TPM_MAX_COMMAND_SIZE),
254 response: Vec::with_capacity(TPM_MAX_COMMAND_SIZE),
255 })
256 }
257}
258
259pub struct TpmDevice {
260 file: File,
261 interrupted: Box<dyn Fn() -> bool>,
262 timeout: Duration,
263 command: Vec<u8>,
264 response: Vec<u8>,
265}
266
267impl std::fmt::Debug for TpmDevice {
268 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269 f.debug_struct("Device")
270 .field("file", &self.file)
271 .field("timeout", &self.timeout)
272 .finish_non_exhaustive()
273 }
274}
275
276impl TpmDevice {
277 const NO_SESSIONS: &'static [TpmsAuthCommand] = &[];
278
279 #[allow(clippy::cast_possible_truncation)]
281 const CAPABILITY_PAGE_SIZE: u32 = MAX_HANDLES as u32;
282
283 #[must_use]
285 pub fn builder() -> TpmDeviceBuilder {
286 TpmDeviceBuilder::default()
287 }
288
289 fn receive(&mut self, buf: &mut [u8]) -> Result<usize, TpmDeviceError> {
290 let fd = self.file.as_fd();
291 let mut fds = [PollFd::new(fd, PollFlags::POLLIN)];
292
293 let num_events = match poll(&mut fds, 100u16) {
294 Ok(num) => num,
295 Err(nix::Error::EINTR) => return Ok(0),
296 Err(e) => return Err(e.into()),
297 };
298
299 if num_events == 0 {
300 return Ok(0);
301 }
302
303 let revents = fds[0].revents().unwrap_or(PollFlags::empty());
304
305 if revents.intersects(PollFlags::POLLERR | PollFlags::POLLNVAL) {
306 return Err(TpmDeviceError::UnexpectedEof);
307 }
308
309 if revents.contains(PollFlags::POLLIN) {
310 match self.file.read(buf) {
311 Ok(0) => Err(TpmDeviceError::UnexpectedEof),
312 Ok(n) => Ok(n),
313 Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => Ok(0),
314 Err(e) if e.kind() == std::io::ErrorKind::Interrupted => Ok(0),
315 Err(e) => Err(e.into()),
316 }
317 } else if revents.contains(PollFlags::POLLHUP) {
318 Err(TpmDeviceError::UnexpectedEof)
319 } else {
320 Ok(0)
321 }
322 }
323
324 pub fn transmit<C: TpmFrame>(
342 &mut self,
343 command: &C,
344 sessions: &[TpmsAuthCommand],
345 ) -> Result<&TpmResponse, TpmDeviceError> {
346 self.prepare_command(command, sessions)?;
347 let cc = command.cc();
348
349 self.file.write_all(&self.command)?;
350 self.file.flush()?;
351
352 let start_time = Instant::now();
353 self.response.clear();
354 let mut total_size: Option<usize> = None;
355 let mut temp_buf = [0u8; 1024];
356
357 loop {
358 if (self.interrupted)() {
359 return Err(TpmDeviceError::Interrupted);
360 }
361 if start_time.elapsed() > self.timeout {
362 return Err(TpmDeviceError::Timeout);
363 }
364
365 let n = self.receive(&mut temp_buf)?;
366 if n > 0 {
367 self.response.extend_from_slice(&temp_buf[..n]);
368 }
369
370 if total_size.is_none() && self.response.len() >= 10 {
371 let Ok(size_bytes): Result<[u8; 4], _> = self.response[2..6].try_into() else {
372 return Err(TpmDeviceError::InvalidResponse);
373 };
374 let size = u32::from_be_bytes(size_bytes) as usize;
375 if !(10..={ TPM_MAX_COMMAND_SIZE }).contains(&size) {
376 return Err(TpmDeviceError::InvalidResponse);
377 }
378 total_size = Some(size);
379 }
380
381 if let Some(size) = total_size {
382 if self.response.len() == size {
383 break;
384 }
385 if self.response.len() > size {
386 return Err(TpmDeviceError::TrailingData);
387 }
388 }
389 }
390
391 let response = TpmResponse::cast(&self.response).map_err(TpmDeviceError::Unmarshal)?;
392 let result = TpmResponseView::cast(cc, response).map_err(TpmDeviceError::Unmarshal)?;
393 trace!("{} R: {}", cc, hex::encode(&self.response));
394 result.map(|_| response).map_err(TpmDeviceError::TpmRc)
395 }
396
397 fn prepare_command<C: TpmFrame>(
398 &mut self,
399 command: &C,
400 sessions: &[TpmsAuthCommand],
401 ) -> Result<(), TpmDeviceError> {
402 let cc = command.cc();
403 let tag = if sessions.is_empty() {
404 TpmSt::NoSessions
405 } else {
406 TpmSt::Sessions
407 };
408
409 self.command.resize(TPM_MAX_COMMAND_SIZE, 0);
410
411 let len = {
412 let mut writer = TpmWriter::new(&mut self.command);
413 tpm_marshal_command(command, tag, sessions, &mut writer)
414 .map_err(TpmDeviceError::Marshal)?;
415 writer.len()
416 };
417 self.command.truncate(len);
418
419 trace!("{} C: {}", cc, hex::encode(&self.command));
420 Ok(())
421 }
422
423 fn get_capability<T, F, N>(
433 &mut self,
434 cap: TpmCap,
435 property_start: u32,
436 count: u32,
437 mut extract: F,
438 next_prop: N,
439 ) -> Result<Vec<T>, TpmDeviceError>
440 where
441 T: Copy,
442 F: for<'a> FnMut(&'a TpmuCapabilities) -> Result<&'a [T], TpmDeviceError>,
443 N: Fn(&T) -> u32,
444 {
445 let mut results = Vec::new();
446 let mut prop = property_start;
447 loop {
448 let (more_data, cap_data) =
449 self.get_capability_page(cap, TpmUint32::from(prop), TpmUint32::from(count))?;
450 let items: &[T] = extract(&cap_data.data)?;
451 results.extend_from_slice(items);
452
453 if more_data {
454 if let Some(last) = items.last() {
455 prop = next_prop(last);
456 } else {
457 break;
458 }
459 } else {
460 break;
461 }
462 }
463 Ok(results)
464 }
465
466 pub fn fetch_algorithm_properties(&mut self) -> Result<Vec<TpmsAlgProperty>, TpmDeviceError> {
475 self.get_capability(
476 TpmCap::Algs,
477 0,
478 Self::CAPABILITY_PAGE_SIZE,
479 |caps| match caps {
480 TpmuCapabilities::Algs(algs) => Ok(algs),
481 _ => Err(TpmDeviceError::CapabilityMissing(TpmCap::Algs)),
482 },
483 |last| u32::from(last.alg.value()) + 1,
484 )
485 }
486
487 pub fn fetch_handles(&mut self, class: TpmHt) -> Result<Vec<TpmHandle>, TpmDeviceError> {
496 self.get_capability(
497 TpmCap::Handles,
498 (class as u32) << 24,
499 Self::CAPABILITY_PAGE_SIZE,
500 |caps| match caps {
501 TpmuCapabilities::Handles(handles) => Ok(handles),
502 _ => Err(TpmDeviceError::CapabilityMissing(TpmCap::Handles)),
503 },
504 |last| last.value() + 1,
505 )
506 .map(|handles| handles.into_iter().collect())
507 }
508
509 pub fn fetch_ecc_curves(&mut self) -> Result<Vec<TpmEccCurve>, TpmDeviceError> {
518 self.get_capability(
519 TpmCap::EccCurves,
520 0,
521 Self::CAPABILITY_PAGE_SIZE,
522 |caps| match caps {
523 TpmuCapabilities::EccCurves(curves) => Ok(curves),
524 _ => Err(TpmDeviceError::CapabilityMissing(TpmCap::EccCurves)),
525 },
526 |last| u32::from(last.value()) + 1,
527 )
528 }
529
530 pub fn fetch_pcr_bank_list(
545 &mut self,
546 ) -> Result<(Vec<TpmAlgId>, TpmsPcrSelect), TpmDeviceError> {
547 let pcrs: Vec<TpmsPcrSelection> = self.get_capability(
548 TpmCap::Pcrs,
549 0,
550 Self::CAPABILITY_PAGE_SIZE,
551 |caps| match caps {
552 TpmuCapabilities::Pcrs(pcrs) => Ok(pcrs),
553 _ => Err(TpmDeviceError::CapabilityMissing(TpmCap::Pcrs)),
554 },
555 |last| last.hash as u32 + 1,
556 )?;
557
558 if pcrs.is_empty() {
559 return Err(TpmDeviceError::PcrBanksNotAvailable);
560 }
561
562 let mut common_select: Option<TpmsPcrSelect> = None;
563 let mut algs = Vec::with_capacity(pcrs.len());
564
565 for bank in pcrs {
566 if bank.pcr_select.iter().all(|&b| b == 0) {
567 debug!(
568 "skipping unallocated bank {:?} (mask: {})",
569 bank.hash,
570 hex::encode(&*bank.pcr_select)
571 );
572 continue;
573 }
574
575 if let Some(ref select) = common_select {
576 if bank.pcr_select != *select {
577 return Err(TpmDeviceError::PcrBankSelectionMismatch);
578 }
579 } else {
580 common_select = Some(bank.pcr_select);
581 }
582 algs.push(bank.hash);
583 }
584
585 let select = common_select.ok_or(TpmDeviceError::PcrBanksNotAvailable)?;
586
587 algs.sort();
588 Ok((algs, select))
589 }
590
591 fn get_capability_page(
601 &mut self,
602 cap: TpmCap,
603 property: TpmUint32,
604 property_count: TpmUint32,
605 ) -> Result<(bool, TpmsCapabilityData), TpmDeviceError> {
606 let cmd = TpmGetCapabilityCommand {
607 cap,
608 property,
609 property_count,
610 handles: [],
611 };
612
613 let response = self.transmit(&cmd, Self::NO_SESSIONS)?;
614 let (_, parameters) = response_parts(response, 0)?;
615 let (more_data, parameters) = parse_field_value::<TpmiYesNo>(parameters)?;
616 let (capability_data, rest) = parse_capability_data(parameters)?;
617 ensure_empty(rest)?;
618
619 Ok((more_data.into(), capability_data))
620 }
621
622 pub fn fetch_tpm_property(&mut self, property: TpmPt) -> Result<u32, TpmDeviceError> {
631 let (_, cap_data) = self.get_capability_page(
632 TpmCap::TpmProperties,
633 TpmUint32::from(property as u32),
634 TpmUint32::from(1),
635 )?;
636
637 let TpmuCapabilities::TpmProperties(props) = &cap_data.data else {
638 return Err(TpmDeviceError::CapabilityMissing(TpmCap::TpmProperties));
639 };
640
641 let Some(prop) = props.iter().find(|prop| prop.property == property) else {
642 return Err(TpmDeviceError::CapabilityMissing(TpmCap::TpmProperties));
643 };
644
645 Ok(prop.value.value())
646 }
647
648 pub fn read_public(
657 &mut self,
658 handle: TpmHandle,
659 ) -> Result<(TpmtPublic, Tpm2bName), TpmDeviceError> {
660 let cmd = TpmReadPublicCommand { handles: [handle] };
661 let response = self.transmit(&cmd, Self::NO_SESSIONS)?;
662 let (_, parameters) = response_parts(response, 0)?;
663 let (public, parameters) = parse_tpm2b_public(parameters)?;
664 let (name, parameters): (Tpm2bName, _) = parse_tpm2b_buffer(parameters)?;
665 let (_qualified_name, rest): (Tpm2bName, _) = parse_tpm2b_buffer(parameters)?;
666 ensure_empty(rest)?;
667
668 Ok((public, name))
669 }
670
671 pub fn find_persistent(
680 &mut self,
681 target_name: &Tpm2bName,
682 ) -> Result<Option<TpmHandle>, TpmDeviceError> {
683 for handle in self.fetch_handles(TpmHt::Persistent)? {
684 match self.read_public(handle) {
685 Ok((_, name)) => {
686 if name == *target_name {
687 return Ok(Some(handle));
688 }
689 }
690 Err(TpmDeviceError::TpmRc(rc)) => {
691 let base = rc.base();
692 if base == TpmRcBase::ReferenceH0 || base == TpmRcBase::Handle {
693 continue;
694 }
695 return Err(TpmDeviceError::TpmRc(rc));
696 }
697 Err(e) => return Err(e),
698 }
699 }
700 Ok(None)
701 }
702
703 pub fn save_context(&mut self, save_handle: TpmHandle) -> Result<TpmsContext, TpmDeviceError> {
712 let cmd = TpmContextSaveCommand {
713 handles: [save_handle],
714 };
715 let response = self.transmit(&cmd, Self::NO_SESSIONS)?;
716 let (_, parameters) = response_parts(response, 0)?;
717 let (context, rest) = parse_tpms_context(parameters)?;
718 ensure_empty(rest)?;
719
720 Ok(context)
721 }
722
723 pub fn load_context(&mut self, context: TpmsContext) -> Result<TpmHandle, TpmDeviceError> {
732 let cmd = TpmContextLoadCommand {
733 context,
734 handles: [],
735 };
736 let response = self.transmit(&cmd, Self::NO_SESSIONS)?;
737 let (handles, parameters) = response_parts(response, 1)?;
738 let (handle, rest) = parse_wire_copy::<TpmHandle>(handles)?;
739 ensure_empty(rest)?;
740 ensure_empty(parameters)?;
741
742 Ok(handle)
743 }
744
745 pub fn flush_context(&mut self, handle: TpmHandle) -> Result<(), TpmDeviceError> {
753 let cmd = TpmFlushContextCommand {
754 flush_handle: handle,
755 handles: [],
756 };
757 self.transmit(&cmd, Self::NO_SESSIONS)?;
758 Ok(())
759 }
760
761 pub fn flush_session(&mut self, context: TpmsContext) -> Result<(), TpmDeviceError> {
768 match self.load_context(context) {
769 Ok(handle) => self.flush_context(handle),
770 Err(TpmDeviceError::TpmRc(rc)) => {
771 let base = rc.base();
772 if base == TpmRcBase::ReferenceH0 || base == TpmRcBase::Handle {
773 Ok(())
774 } else {
775 Err(TpmDeviceError::TpmRc(rc))
776 }
777 }
778 Err(e) => Err(e),
779 }
780 }
781}
782
783fn ensure_empty(buf: &[u8]) -> Result<(), TpmDeviceError> {
784 if buf.is_empty() {
785 Ok(())
786 } else {
787 Err(TpmDeviceError::TrailingData)
788 }
789}
790
791fn response_parts(
792 response: &TpmResponse,
793 response_handles: usize,
794) -> Result<(&[u8], &[u8]), TpmDeviceError> {
795 let handle_len = response_handles
796 .checked_mul(core::mem::size_of::<TpmHandle>())
797 .ok_or(TpmDeviceError::InvalidResponse)?;
798 let body = response.body();
799 if body.len() < handle_len {
800 return Err(TpmDeviceError::InvalidResponse);
801 }
802
803 let (handles, after_handles) = body.split_at(handle_len);
804 if response.tag().map_err(TpmDeviceError::Unmarshal)? != TpmSt::Sessions {
805 return Ok((handles, after_handles));
806 }
807
808 let (parameter_size, after_size) = parse_wire_copy::<TpmUint32>(after_handles)?;
809 let parameter_size =
810 usize::try_from(parameter_size.value()).map_err(|_| TpmDeviceError::InvalidResponse)?;
811 if after_size.len() < parameter_size {
812 return Err(TpmDeviceError::InvalidResponse);
813 }
814
815 let (parameters, _auth_area) = after_size.split_at(parameter_size);
816 Ok((handles, parameters))
817}
818
819fn parse_wire_copy<'a, T>(buf: &'a [u8]) -> Result<(T, &'a [u8]), TpmDeviceError>
820where
821 T: TpmCast + Copy + 'a,
822{
823 let (value, rest) = T::cast_prefix(buf).map_err(TpmDeviceError::Unmarshal)?;
824 Ok((*value, rest))
825}
826
827fn parse_field_value<'a, T>(buf: &'a [u8]) -> Result<(T, &'a [u8]), TpmDeviceError>
828where
829 T: TpmField<'a, View = T>,
830{
831 <T as TpmField<'a>>::cast_prefix_field(buf).map_err(TpmDeviceError::Unmarshal)
832}
833
834fn parse_tpm2b_buffer<const CAPACITY: usize>(
835 buf: &[u8],
836) -> Result<(TpmBuffer<CAPACITY>, &[u8]), TpmDeviceError> {
837 let (value, rest) =
838 Tpm2bWire::<CAPACITY>::cast_prefix(buf).map_err(TpmDeviceError::Unmarshal)?;
839 let value = TpmBuffer::<CAPACITY>::try_from(value.data()).map_err(TpmDeviceError::Unmarshal)?;
840
841 Ok((value, rest))
842}
843
844fn parse_tpms_scheme_hash(buf: &[u8]) -> Result<(TpmsSchemeHash, &[u8]), TpmDeviceError> {
845 let (hash_alg, rest) = parse_field_value::<TpmAlgId>(buf)?;
846
847 Ok((TpmsSchemeHash { hash_alg }, rest))
848}
849
850fn parse_tpmt_kdf_scheme(buf: &[u8]) -> Result<(TpmtKdfScheme, &[u8]), TpmDeviceError> {
851 let (scheme, buf) = parse_field_value::<TpmAlgId>(buf)?;
852 let (details, rest) = parse_tpmu_kdf_scheme(scheme, buf)?;
853
854 Ok((TpmtKdfScheme { scheme, details }, rest))
855}
856
857fn parse_tpmu_kdf_scheme(
858 scheme: TpmAlgId,
859 buf: &[u8],
860) -> Result<(TpmuKdfScheme, &[u8]), TpmDeviceError> {
861 match scheme {
862 TpmAlgId::Mgf1 => {
863 let (details, rest) = parse_tpms_scheme_hash(buf)?;
864 Ok((TpmuKdfScheme::Mgf1(details), rest))
865 }
866 TpmAlgId::Kdf1Sp800_56A => {
867 let (details, rest) = parse_tpms_scheme_hash(buf)?;
868 Ok((TpmuKdfScheme::Kdf1Sp800_56a(details), rest))
869 }
870 TpmAlgId::Kdf2 => {
871 let (details, rest) = parse_tpms_scheme_hash(buf)?;
872 Ok((TpmuKdfScheme::Kdf2(details), rest))
873 }
874 TpmAlgId::Kdf1Sp800_108 => {
875 let (details, rest) = parse_tpms_scheme_hash(buf)?;
876 Ok((TpmuKdfScheme::Kdf1Sp800_108(details), rest))
877 }
878 TpmAlgId::Null => Ok((TpmuKdfScheme::Null, buf)),
879 _ => Err(TpmDeviceError::InvalidResponse),
880 }
881}
882
883fn parse_tpms_scheme_xor(buf: &[u8]) -> Result<(TpmsSchemeXor, &[u8]), TpmDeviceError> {
884 let (hash_alg, buf) = parse_field_value::<TpmAlgId>(buf)?;
885 let (kdf, rest) = parse_tpmt_kdf_scheme(buf)?;
886
887 Ok((TpmsSchemeXor { hash_alg, kdf }, rest))
888}
889
890fn parse_tpmu_keyedhash_scheme(
891 scheme: TpmAlgId,
892 buf: &[u8],
893) -> Result<(TpmuKeyedhashScheme, &[u8]), TpmDeviceError> {
894 match scheme {
895 TpmAlgId::Hmac => {
896 let (details, rest) = parse_tpms_scheme_hash(buf)?;
897 Ok((TpmuKeyedhashScheme::Hmac(details), rest))
898 }
899 TpmAlgId::Xor => {
900 let (details, rest) = parse_tpms_scheme_xor(buf)?;
901 Ok((TpmuKeyedhashScheme::Xor(details), rest))
902 }
903 TpmAlgId::Null => Ok((TpmuKeyedhashScheme::Null, buf)),
904 _ => Err(TpmDeviceError::InvalidResponse),
905 }
906}
907
908fn parse_tpmt_keyedhash_scheme(buf: &[u8]) -> Result<(TpmtKeyedhashScheme, &[u8]), TpmDeviceError> {
909 let (scheme, buf) = parse_field_value::<TpmAlgId>(buf)?;
910 let (details, rest) = parse_tpmu_keyedhash_scheme(scheme, buf)?;
911
912 Ok((TpmtKeyedhashScheme { scheme, details }, rest))
913}
914
915fn parse_tpmu_asym_scheme(
916 scheme: TpmAlgId,
917 buf: &[u8],
918) -> Result<(TpmuAsymScheme, &[u8]), TpmDeviceError> {
919 match scheme {
920 TpmAlgId::Rsassa
921 | TpmAlgId::Rsapss
922 | TpmAlgId::Ecdsa
923 | TpmAlgId::Ecdaa
924 | TpmAlgId::Sm2
925 | TpmAlgId::Ecschnorr
926 | TpmAlgId::Oaep
927 | TpmAlgId::Ecdh
928 | TpmAlgId::Ecmqv => {
929 let (details, rest) = parse_tpms_scheme_hash(buf)?;
930 Ok((TpmuAsymScheme::Hash(details), rest))
931 }
932 TpmAlgId::Rsaes | TpmAlgId::Null => Ok((TpmuAsymScheme::Null, buf)),
933 _ => Err(TpmDeviceError::InvalidResponse),
934 }
935}
936
937fn parse_tpmt_rsa_scheme(buf: &[u8]) -> Result<(TpmtRsaScheme, &[u8]), TpmDeviceError> {
938 let (scheme, buf) = parse_field_value::<TpmAlgId>(buf)?;
939 let (details, rest) = parse_tpmu_asym_scheme(scheme, buf)?;
940
941 Ok((TpmtRsaScheme { scheme, details }, rest))
942}
943
944fn parse_tpmt_ecc_scheme(buf: &[u8]) -> Result<(TpmtEccScheme, &[u8]), TpmDeviceError> {
945 let (scheme, buf) = parse_field_value::<TpmAlgId>(buf)?;
946 let (details, rest) = parse_tpmu_asym_scheme(scheme, buf)?;
947
948 Ok((TpmtEccScheme { scheme, details }, rest))
949}
950
951fn parse_tpmu_sym_key_bits(
952 algorithm: TpmAlgId,
953 buf: &[u8],
954) -> Result<(TpmuSymKeyBits, &[u8]), TpmDeviceError> {
955 match algorithm {
956 TpmAlgId::Aes => {
957 let (value, rest) = parse_wire_copy::<TpmUint16>(buf)?;
958 Ok((TpmuSymKeyBits::Aes(value), rest))
959 }
960 TpmAlgId::Sm4 => {
961 let (value, rest) = parse_wire_copy::<TpmUint16>(buf)?;
962 Ok((TpmuSymKeyBits::Sm4(value), rest))
963 }
964 TpmAlgId::Camellia => {
965 let (value, rest) = parse_wire_copy::<TpmUint16>(buf)?;
966 Ok((TpmuSymKeyBits::Camellia(value), rest))
967 }
968 TpmAlgId::Xor => {
969 let (value, rest) = parse_field_value::<TpmAlgId>(buf)?;
970 Ok((TpmuSymKeyBits::Xor(value), rest))
971 }
972 TpmAlgId::Null => Ok((TpmuSymKeyBits::Null, buf)),
973 _ => Err(TpmDeviceError::InvalidResponse),
974 }
975}
976
977fn parse_tpmu_sym_mode(
978 algorithm: TpmAlgId,
979 buf: &[u8],
980) -> Result<(TpmuSymMode, &[u8]), TpmDeviceError> {
981 match algorithm {
982 TpmAlgId::Aes => {
983 let (value, rest) = parse_field_value::<TpmAlgId>(buf)?;
984 Ok((TpmuSymMode::Aes(value), rest))
985 }
986 TpmAlgId::Sm4 => {
987 let (value, rest) = parse_field_value::<TpmAlgId>(buf)?;
988 Ok((TpmuSymMode::Sm4(value), rest))
989 }
990 TpmAlgId::Camellia => {
991 let (value, rest) = parse_field_value::<TpmAlgId>(buf)?;
992 Ok((TpmuSymMode::Camellia(value), rest))
993 }
994 TpmAlgId::Xor => {
995 let (value, rest) = parse_field_value::<TpmAlgId>(buf)?;
996 Ok((TpmuSymMode::Xor(value), rest))
997 }
998 TpmAlgId::Null => Ok((TpmuSymMode::Null, buf)),
999 _ => Err(TpmDeviceError::InvalidResponse),
1000 }
1001}
1002
1003fn parse_tpmt_sym_def(buf: &[u8]) -> Result<(TpmtSymDefObject, &[u8]), TpmDeviceError> {
1004 let (algorithm, buf) = parse_field_value::<TpmAlgId>(buf)?;
1005 if algorithm == TpmAlgId::Null {
1006 return Ok((TpmtSymDefObject::default(), buf));
1007 }
1008
1009 let (key_bits, buf) = parse_tpmu_sym_key_bits(algorithm, buf)?;
1010 let (mode, rest) = parse_tpmu_sym_mode(algorithm, buf)?;
1011
1012 Ok((
1013 TpmtSymDefObject {
1014 algorithm,
1015 key_bits,
1016 mode,
1017 },
1018 rest,
1019 ))
1020}
1021
1022fn parse_tpmu_public_parms(
1023 object_type: TpmAlgId,
1024 buf: &[u8],
1025) -> Result<(TpmuPublicParms, &[u8]), TpmDeviceError> {
1026 match object_type {
1027 TpmAlgId::KeyedHash => {
1028 let (scheme, rest) = parse_tpmt_keyedhash_scheme(buf)?;
1029 Ok((
1030 TpmuPublicParms::KeyedHash(TpmsKeyedhashParms { scheme }),
1031 rest,
1032 ))
1033 }
1034 TpmAlgId::SymCipher => {
1035 let (sym, rest) = parse_tpmt_sym_def(buf)?;
1036 Ok((TpmuPublicParms::SymCipher(TpmsSymcipherParms { sym }), rest))
1037 }
1038 TpmAlgId::Rsa => {
1039 let (symmetric, buf) = parse_tpmt_sym_def(buf)?;
1040 let (scheme, buf) = parse_tpmt_rsa_scheme(buf)?;
1041 let (key_bits, buf) = parse_wire_copy::<TpmUint16>(buf)?;
1042 let (exponent, rest) = parse_wire_copy::<TpmUint32>(buf)?;
1043 Ok((
1044 TpmuPublicParms::Rsa(TpmsRsaParms {
1045 symmetric,
1046 scheme,
1047 key_bits,
1048 exponent,
1049 }),
1050 rest,
1051 ))
1052 }
1053 TpmAlgId::Ecc => {
1054 let (symmetric, buf) = parse_tpmt_sym_def(buf)?;
1055 let (scheme, buf) = parse_tpmt_ecc_scheme(buf)?;
1056 let (curve_id, buf) = parse_field_value::<TpmEccCurve>(buf)?;
1057 let (kdf, rest) = parse_tpmt_kdf_scheme(buf)?;
1058 Ok((
1059 TpmuPublicParms::Ecc(TpmsEccParms {
1060 symmetric,
1061 scheme,
1062 curve_id,
1063 kdf,
1064 }),
1065 rest,
1066 ))
1067 }
1068 TpmAlgId::Null => Ok((TpmuPublicParms::Null, buf)),
1069 _ => Err(TpmDeviceError::InvalidResponse),
1070 }
1071}
1072
1073fn parse_tpms_ecc_point(buf: &[u8]) -> Result<(TpmsEccPoint, &[u8]), TpmDeviceError> {
1074 let (x, buf): (Tpm2bEccParameter, _) = parse_tpm2b_buffer(buf)?;
1075 let (y, rest): (Tpm2bEccParameter, _) = parse_tpm2b_buffer(buf)?;
1076
1077 Ok((TpmsEccPoint { x, y }, rest))
1078}
1079
1080fn parse_tpmu_public_id(
1081 object_type: TpmAlgId,
1082 buf: &[u8],
1083) -> Result<(TpmuPublicId, &[u8]), TpmDeviceError> {
1084 match object_type {
1085 TpmAlgId::KeyedHash => {
1086 let (value, rest): (Tpm2bDigest, _) = parse_tpm2b_buffer(buf)?;
1087 Ok((TpmuPublicId::KeyedHash(value), rest))
1088 }
1089 TpmAlgId::SymCipher => {
1090 let (value, rest): (Tpm2bSymKey, _) = parse_tpm2b_buffer(buf)?;
1091 Ok((TpmuPublicId::SymCipher(value), rest))
1092 }
1093 TpmAlgId::Rsa => {
1094 let (value, rest): (Tpm2bPublicKeyRsa, _) = parse_tpm2b_buffer(buf)?;
1095 Ok((TpmuPublicId::Rsa(value), rest))
1096 }
1097 TpmAlgId::Ecc => {
1098 let (value, rest) = parse_tpms_ecc_point(buf)?;
1099 Ok((TpmuPublicId::Ecc(value), rest))
1100 }
1101 TpmAlgId::Null => Ok((TpmuPublicId::Null, buf)),
1102 _ => Err(TpmDeviceError::InvalidResponse),
1103 }
1104}
1105
1106fn parse_tpmt_public(buf: &[u8]) -> Result<(TpmtPublic, &[u8]), TpmDeviceError> {
1107 let (object_type, buf) = parse_field_value::<TpmAlgId>(buf)?;
1108 let (name_alg, buf) = parse_field_value::<TpmAlgId>(buf)?;
1109 let (object_attributes, buf) = parse_field_value::<TpmaObject>(buf)?;
1110 let (auth_policy, buf): (Tpm2bDigest, _) = parse_tpm2b_buffer(buf)?;
1111 let (parameters, buf) = parse_tpmu_public_parms(object_type, buf)?;
1112 let (unique, rest) = parse_tpmu_public_id(object_type, buf)?;
1113
1114 Ok((
1115 TpmtPublic {
1116 object_type,
1117 name_alg,
1118 object_attributes,
1119 auth_policy,
1120 parameters,
1121 unique,
1122 },
1123 rest,
1124 ))
1125}
1126
1127fn parse_tpm2b_public(buf: &[u8]) -> Result<(TpmtPublic, &[u8]), TpmDeviceError> {
1128 let (size, buf) = parse_wire_copy::<TpmUint16>(buf)?;
1129 let size = usize::from(size.value());
1130 if buf.len() < size {
1131 return Err(TpmDeviceError::InvalidResponse);
1132 }
1133
1134 let (public, rest) = buf.split_at(size);
1135 let (public, public_rest) = parse_tpmt_public(public)?;
1136 ensure_empty(public_rest)?;
1137
1138 Ok((public, rest))
1139}
1140
1141fn parse_tpms_context(buf: &[u8]) -> Result<(TpmsContext, &[u8]), TpmDeviceError> {
1142 let (sequence, buf) = parse_wire_copy::<TpmUint64>(buf)?;
1143 let (saved_handle, buf) = parse_wire_copy::<TpmHandle>(buf)?;
1144 let (hierarchy, buf) = parse_field_value::<TpmRh>(buf)?;
1145 let (context_blob, rest): (TpmBuffer<TPM_MAX_COMMAND_SIZE>, _) = parse_tpm2b_buffer(buf)?;
1146
1147 Ok((
1148 TpmsContext {
1149 sequence,
1150 saved_handle,
1151 hierarchy,
1152 context_blob,
1153 },
1154 rest,
1155 ))
1156}
1157
1158fn parse_list<'a, T, const CAPACITY: usize>(
1159 buf: &'a [u8],
1160 mut parse_item: impl FnMut(&'a [u8]) -> Result<(T, &'a [u8]), TpmDeviceError>,
1161) -> Result<(TpmList<T, CAPACITY>, &'a [u8]), TpmDeviceError>
1162where
1163 T: Copy,
1164{
1165 let (count, mut cursor) = parse_wire_copy::<TpmUint32>(buf)?;
1166 let mut list = TpmList::<T, CAPACITY>::new();
1167
1168 for _ in 0..count.value() {
1169 let (item, rest) = parse_item(cursor)?;
1170 list.try_push(item).map_err(TpmDeviceError::Unmarshal)?;
1171 cursor = rest;
1172 }
1173
1174 Ok((list, cursor))
1175}
1176
1177fn parse_tpms_alg_property(buf: &[u8]) -> Result<(TpmsAlgProperty, &[u8]), TpmDeviceError> {
1178 let (alg, buf) = parse_field_value::<TpmAlgId>(buf)?;
1179 let (alg_properties, rest) = parse_field_value::<TpmaAlgorithm>(buf)?;
1180
1181 Ok((
1182 TpmsAlgProperty {
1183 alg,
1184 alg_properties,
1185 },
1186 rest,
1187 ))
1188}
1189
1190fn parse_tpms_tagged_property(buf: &[u8]) -> Result<(TpmsTaggedProperty, &[u8]), TpmDeviceError> {
1191 let (property, buf) = parse_field_value::<TpmPt>(buf)?;
1192 let (value, rest) = parse_wire_copy::<TpmUint32>(buf)?;
1193
1194 Ok((TpmsTaggedProperty { property, value }, rest))
1195}
1196
1197fn parse_tpms_pcr_selection(buf: &[u8]) -> Result<(TpmsPcrSelection, &[u8]), TpmDeviceError> {
1198 let (hash, buf) = parse_field_value::<TpmAlgId>(buf)?;
1199 let (pcr_select, rest) =
1200 <TpmsPcrSelect as TpmField>::cast_prefix_field(buf).map_err(TpmDeviceError::Unmarshal)?;
1201 let pcr_select = TpmsPcrSelect::try_from(pcr_select).map_err(TpmDeviceError::Unmarshal)?;
1202
1203 Ok((TpmsPcrSelection { hash, pcr_select }, rest))
1204}
1205
1206fn parse_capability_data(buf: &[u8]) -> Result<(TpmsCapabilityData, &[u8]), TpmDeviceError> {
1207 let (capability, buf) = parse_field_value::<TpmCap>(buf)?;
1208 let (data, rest) = match capability {
1209 TpmCap::Algs => {
1210 let (list, rest) = parse_list::<TpmsAlgProperty, 64>(buf, parse_tpms_alg_property)?;
1211 (TpmuCapabilities::Algs(list), rest)
1212 }
1213 TpmCap::Handles => {
1214 let (list, rest) = parse_list::<TpmHandle, 128>(buf, parse_wire_copy::<TpmHandle>)?;
1215 (TpmuCapabilities::Handles(list), rest)
1216 }
1217 TpmCap::Pcrs => {
1218 let (list, rest) = parse_list::<TpmsPcrSelection, 8>(buf, parse_tpms_pcr_selection)?;
1219 (TpmuCapabilities::Pcrs(list), rest)
1220 }
1221 TpmCap::Commands => {
1222 let (list, rest) = parse_list::<TpmaCc, 256>(buf, parse_field_value::<TpmaCc>)?;
1223 (TpmuCapabilities::Commands(list), rest)
1224 }
1225 TpmCap::TpmProperties => {
1226 let (list, rest) =
1227 parse_list::<TpmsTaggedProperty, 64>(buf, parse_tpms_tagged_property)?;
1228 (TpmuCapabilities::TpmProperties(list), rest)
1229 }
1230 TpmCap::EccCurves => {
1231 let (list, rest) =
1232 parse_list::<TpmEccCurve, 64>(buf, parse_field_value::<TpmEccCurve>)?;
1233 (TpmuCapabilities::EccCurves(list), rest)
1234 }
1235 TpmCap::PpCommands | TpmCap::AuditCommands | TpmCap::AuthPolicies | TpmCap::Act => {
1236 return Err(TpmDeviceError::InvalidResponse);
1237 }
1238 };
1239
1240 Ok((TpmsCapabilityData { capability, data }, rest))
1241}
1242
1243pub struct TpmPolicySessionBuilder {
1245 bind: TpmHandle,
1246 tpm_key: TpmHandle,
1247 nonce_caller: Option<Tpm2bNonce>,
1248 encrypted_salt: Option<Tpm2bEncryptedSecret>,
1249 session_type: TpmSe,
1250 symmetric: TpmtSymDefObject,
1251 auth_hash: TpmAlgId,
1252}
1253
1254impl Default for TpmPolicySessionBuilder {
1255 fn default() -> Self {
1256 Self {
1257 bind: (TpmRh::Null as u32).into(),
1258 tpm_key: (TpmRh::Null as u32).into(),
1259 nonce_caller: None,
1260 encrypted_salt: None,
1261 session_type: TpmSe::Policy,
1262 symmetric: TpmtSymDefObject::default(),
1263 auth_hash: TpmAlgId::Sha256,
1264 }
1265 }
1266}
1267
1268impl TpmPolicySessionBuilder {
1269 #[must_use]
1270 pub fn new() -> Self {
1271 Self::default()
1272 }
1273
1274 #[must_use]
1275 pub fn with_bind(mut self, bind: TpmHandle) -> Self {
1276 self.bind = bind;
1277 self
1278 }
1279
1280 #[must_use]
1281 pub fn with_tpm_key(mut self, tpm_key: TpmHandle) -> Self {
1282 self.tpm_key = tpm_key;
1283 self
1284 }
1285
1286 #[must_use]
1287 pub fn with_nonce_caller(mut self, nonce: Tpm2bNonce) -> Self {
1288 self.nonce_caller = Some(nonce);
1289 self
1290 }
1291
1292 #[must_use]
1293 pub fn with_encrypted_salt(mut self, salt: Tpm2bEncryptedSecret) -> Self {
1294 self.encrypted_salt = Some(salt);
1295 self
1296 }
1297
1298 #[must_use]
1299 pub fn with_session_type(mut self, session_type: TpmSe) -> Self {
1300 self.session_type = session_type;
1301 self
1302 }
1303
1304 #[must_use]
1305 pub fn with_symmetric(mut self, symmetric: TpmtSymDefObject) -> Self {
1306 self.symmetric = symmetric;
1307 self
1308 }
1309
1310 #[must_use]
1311 pub fn with_auth_hash(mut self, auth_hash: TpmAlgId) -> Self {
1312 self.auth_hash = auth_hash;
1313 self
1314 }
1315
1316 pub fn open(self, device: &mut TpmDevice) -> Result<TpmPolicySession, TpmDeviceError> {
1327 let nonce_caller = if let Some(nonce) = self.nonce_caller {
1328 nonce
1329 } else {
1330 let digest_len = TpmHash::try_from(self.auth_hash)
1331 .map_err(|_| TpmDeviceError::UnsupportedAlgorithm(self.auth_hash))?
1332 .size();
1333 let mut nonce_bytes = vec![0; digest_len];
1334 thread_rng().fill_bytes(&mut nonce_bytes);
1335 Tpm2bNonce::try_from(nonce_bytes.as_slice()).map_err(TpmDeviceError::Unmarshal)?
1336 };
1337
1338 let cmd = TpmStartAuthSessionCommand {
1339 nonce_caller,
1340 encrypted_salt: self.encrypted_salt.unwrap_or_default(),
1341 session_type: self.session_type,
1342 symmetric: self.symmetric,
1343 auth_hash: self.auth_hash,
1344 handles: [self.tpm_key, self.bind],
1345 };
1346
1347 let response = device.transmit(&cmd, TpmDevice::NO_SESSIONS)?;
1348 let (handles, parameters) = response_parts(response, 1)?;
1349 let (handle, rest) = parse_wire_copy::<TpmHandle>(handles)?;
1350 ensure_empty(rest)?;
1351 let (nonce_tpm, rest): (Tpm2bNonce, _) = parse_tpm2b_buffer(parameters)?;
1352 ensure_empty(rest)?;
1353
1354 Ok(TpmPolicySession {
1355 handle,
1356 attributes: TpmaSession::CONTINUE_SESSION,
1357 hash_alg: self.auth_hash,
1358 nonce_tpm,
1359 })
1360 }
1361}
1362
1363#[derive(Debug, Clone)]
1365pub struct TpmPolicySession {
1366 handle: TpmHandle,
1367 attributes: TpmaSession,
1368 hash_alg: TpmAlgId,
1369 nonce_tpm: Tpm2bNonce,
1370}
1371
1372impl TpmPolicySession {
1373 #[must_use]
1375 pub fn builder() -> TpmPolicySessionBuilder {
1376 TpmPolicySessionBuilder::new()
1377 }
1378
1379 #[must_use]
1381 pub fn handle(&self) -> TpmHandle {
1382 self.handle
1383 }
1384
1385 #[must_use]
1387 pub fn attributes(&self) -> TpmaSession {
1388 self.attributes
1389 }
1390
1391 #[must_use]
1393 pub fn hash_alg(&self) -> TpmAlgId {
1394 self.hash_alg
1395 }
1396
1397 #[must_use]
1399 pub fn nonce_tpm(&self) -> &Tpm2bNonce {
1400 &self.nonce_tpm
1401 }
1402
1403 pub fn run(
1416 &self,
1417 device: &mut TpmDevice,
1418 commands: impl IntoIterator<Item = (TpmCommand, TpmAuthCommands)>,
1419 ) -> Result<(), TpmDeviceError> {
1420 for (mut command_body, auth_sessions) in commands {
1421 match &mut command_body {
1422 TpmCommand::PolicyPcr(cmd) => cmd.handles[0] = self.handle,
1423 TpmCommand::PolicyOr(cmd) => cmd.handles[0] = self.handle,
1424 TpmCommand::PolicyRestart(cmd) => {
1425 cmd.handles[0] = self.handle;
1426 }
1427 TpmCommand::PolicySecret(cmd) => {
1428 cmd.handles[1] = self.handle;
1429 }
1430 _ => {
1431 return Err(TpmDeviceError::InvalidCc(command_body.cc()));
1432 }
1433 }
1434 device.transmit(&command_body, auth_sessions.as_ref())?;
1435 }
1436 Ok(())
1437 }
1438
1439 pub fn flush(&self, device: &mut TpmDevice) -> Result<(), TpmDeviceError> {
1446 device.flush_context(self.handle)
1447 }
1448}