1#![deny(clippy::all)]
6#![deny(clippy::pedantic)]
7
8use nix::{
9 fcntl,
10 poll::{poll, PollFd, PollFlags},
11};
12use rand::{thread_rng, RngCore};
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 thiserror::Error;
24use tpm2_crypto::TpmHash;
25use tpm2_protocol::{
26 basic::{TpmHandle, TpmUint32},
27 constant::{MAX_HANDLES, TPM_MAX_COMMAND_SIZE},
28 data::{
29 Tpm2bEncryptedSecret, Tpm2bName, Tpm2bNonce, TpmAlgId, TpmCap, TpmCc, TpmEccCurve, TpmHt,
30 TpmPt, TpmRc, TpmRcBase, TpmRh, TpmSe, TpmSt, TpmaSession, TpmsAlgProperty,
31 TpmsAuthCommand, TpmsCapabilityData, TpmsContext, TpmsPcrSelect, TpmsPcrSelection,
32 TpmtPublic, TpmtSymDefObject, TpmuCapabilities,
33 },
34 frame::{
35 tpm_marshal_command, tpm_unmarshal_response, TpmAuthCommands, TpmAuthResponses, TpmCommand,
36 TpmContextLoadCommand, TpmContextSaveCommand, TpmFlushContextCommand, TpmFrame,
37 TpmGetCapabilityCommand, TpmGetCapabilityResponse, TpmReadPublicCommand, TpmResponse,
38 TpmStartAuthSessionCommand,
39 },
40 TpmWriter,
41};
42use tracing::{debug, trace};
43
44#[derive(Debug, Error)]
46pub enum TpmDeviceError {
47 #[error("device is already borrowed")]
49 AlreadyBorrowed,
50
51 #[error("capability not found: {0}")]
53 CapabilityMissing(TpmCap),
54
55 #[error("operation interrupted by user")]
56 Interrupted,
57
58 #[error("invalid CC: {0}")]
60 InvalidCc(tpm2_protocol::data::TpmCc),
61
62 #[error("invalid response")]
64 InvalidResponse,
65
66 #[error("I/O: {0}")]
68 Io(#[from] std::io::Error),
69
70 #[error("marshal: {0}")]
72 Marshal(tpm2_protocol::TpmProtocolError),
73
74 #[error("device not available")]
76 NotAvailable,
77
78 #[error("operation failed")]
80 OperationFailed,
81
82 #[error("PCR banks not available")]
84 PcrBanksNotAvailable,
85
86 #[error("PCR bank selection mismatch")]
88 PcrBankSelectionMismatch,
89
90 #[error("response mismatch: {0}")]
92 ResponseMismatch(TpmCc),
93
94 #[error("TPM command timed out")]
96 Timeout,
97
98 #[error("TPM return code: {0}")]
100 TpmRc(TpmRc),
101
102 #[error("trailing data")]
104 TrailingData,
105
106 #[error("unmarshal: {0}")]
108 Unmarshal(tpm2_protocol::TpmProtocolError),
109
110 #[error("unexpected EOF")]
112 UnexpectedEof,
113}
114
115impl From<TpmRc> for TpmDeviceError {
116 fn from(rc: TpmRc) -> Self {
117 Self::TpmRc(rc)
118 }
119}
120
121impl From<nix::Error> for TpmDeviceError {
122 fn from(err: nix::Error) -> Self {
123 Self::Io(std::io::Error::from_raw_os_error(err as i32))
124 }
125}
126
127pub fn with_device<F, T, E>(device: Option<Rc<RefCell<TpmDevice>>>, function: F) -> Result<T, E>
141where
142 F: FnOnce(&mut TpmDevice) -> Result<T, E>,
143 E: From<TpmDeviceError>,
144{
145 let device_rc = device.ok_or(TpmDeviceError::NotAvailable)?;
146 let mut device_guard = device_rc
147 .try_borrow_mut()
148 .map_err(|_| TpmDeviceError::AlreadyBorrowed)?;
149 function(&mut device_guard)
150}
151
152pub struct TpmDeviceBuilder {
154 path: PathBuf,
155 timeout: Duration,
156 interrupted: Box<dyn Fn() -> bool>,
157}
158
159impl Default for TpmDeviceBuilder {
160 fn default() -> Self {
161 Self {
162 path: PathBuf::from("/dev/tpmrm0"),
163 timeout: Duration::from_secs(120),
164 interrupted: Box::new(|| false),
165 }
166 }
167}
168
169impl TpmDeviceBuilder {
170 #[must_use]
172 pub fn with_path<P: AsRef<Path>>(mut self, path: P) -> Self {
173 self.path = path.as_ref().to_path_buf();
174 self
175 }
176
177 #[must_use]
179 pub fn with_timeout(mut self, timeout: Duration) -> Self {
180 self.timeout = timeout;
181 self
182 }
183
184 #[must_use]
186 pub fn with_interrupted<F>(mut self, handler: F) -> Self
187 where
188 F: Fn() -> bool + 'static,
189 {
190 self.interrupted = Box::new(handler);
191 self
192 }
193
194 pub fn build(self) -> Result<TpmDevice, TpmDeviceError> {
201 let file = OpenOptions::new()
202 .read(true)
203 .write(true)
204 .open(&self.path)
205 .map_err(TpmDeviceError::Io)?;
206
207 let fd = file.as_raw_fd();
208 let flags = fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFL)?;
209 let mut oflags = fcntl::OFlag::from_bits_truncate(flags);
210 oflags.insert(fcntl::OFlag::O_NONBLOCK);
211 fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFL(oflags))?;
212
213 Ok(TpmDevice {
214 file,
215 interrupted: self.interrupted,
216 timeout: self.timeout,
217 command: Vec::with_capacity(TPM_MAX_COMMAND_SIZE),
218 response: Vec::with_capacity(TPM_MAX_COMMAND_SIZE),
219 })
220 }
221}
222
223pub struct TpmDevice {
224 file: File,
225 interrupted: Box<dyn Fn() -> bool>,
226 timeout: Duration,
227 command: Vec<u8>,
228 response: Vec<u8>,
229}
230
231impl std::fmt::Debug for TpmDevice {
232 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233 f.debug_struct("Device")
234 .field("file", &self.file)
235 .field("timeout", &self.timeout)
236 .finish_non_exhaustive()
237 }
238}
239
240impl TpmDevice {
241 const NO_SESSIONS: &'static [TpmsAuthCommand] = &[];
242
243 #[must_use]
245 pub fn builder() -> TpmDeviceBuilder {
246 TpmDeviceBuilder::default()
247 }
248
249 fn receive(&mut self, buf: &mut [u8]) -> Result<usize, TpmDeviceError> {
250 let fd = self.file.as_fd();
251 let mut fds = [PollFd::new(fd, PollFlags::POLLIN)];
252
253 let num_events = match poll(&mut fds, 100u16) {
254 Ok(num) => num,
255 Err(nix::Error::EINTR) => return Ok(0),
256 Err(e) => return Err(e.into()),
257 };
258
259 if num_events == 0 {
260 return Ok(0);
261 }
262
263 let revents = fds[0].revents().unwrap_or(PollFlags::empty());
264
265 if revents.intersects(PollFlags::POLLERR | PollFlags::POLLNVAL) {
266 return Err(TpmDeviceError::UnexpectedEof);
267 }
268
269 if revents.contains(PollFlags::POLLIN) {
270 match self.file.read(buf) {
271 Ok(0) => Err(TpmDeviceError::UnexpectedEof),
272 Ok(n) => Ok(n),
273 Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => Ok(0),
274 Err(e) if e.kind() == std::io::ErrorKind::Interrupted => Ok(0),
275 Err(e) => Err(e.into()),
276 }
277 } else if revents.contains(PollFlags::POLLHUP) {
278 Err(TpmDeviceError::UnexpectedEof)
279 } else {
280 Ok(0)
281 }
282 }
283
284 pub fn transmit<C: TpmFrame>(
302 &mut self,
303 command: &C,
304 sessions: &[TpmsAuthCommand],
305 ) -> Result<(TpmResponse, TpmAuthResponses), TpmDeviceError> {
306 self.prepare_command(command, sessions)?;
307 let cc = command.cc();
308
309 self.file.write_all(&self.command)?;
310 self.file.flush()?;
311
312 let start_time = Instant::now();
313 self.response.clear();
314 let mut total_size: Option<usize> = None;
315 let mut temp_buf = [0u8; 1024];
316
317 loop {
318 if (self.interrupted)() {
319 return Err(TpmDeviceError::Interrupted);
320 }
321 if start_time.elapsed() > self.timeout {
322 return Err(TpmDeviceError::Timeout);
323 }
324
325 let n = self.receive(&mut temp_buf)?;
326 if n > 0 {
327 self.response.extend_from_slice(&temp_buf[..n]);
328 }
329
330 if total_size.is_none() && self.response.len() >= 10 {
331 let Ok(size_bytes): Result<[u8; 4], _> = self.response[2..6].try_into() else {
332 return Err(TpmDeviceError::OperationFailed);
333 };
334 let size = u32::from_be_bytes(size_bytes) as usize;
335 if !(10..={ TPM_MAX_COMMAND_SIZE }).contains(&size) {
336 return Err(TpmDeviceError::OperationFailed);
337 }
338 total_size = Some(size);
339 }
340
341 if let Some(size) = total_size {
342 if self.response.len() == size {
343 break;
344 }
345 if self.response.len() > size {
346 return Err(TpmDeviceError::TrailingData);
347 }
348 }
349 }
350
351 let result = tpm_unmarshal_response(cc, &self.response).map_err(TpmDeviceError::Unmarshal);
352 trace!("{} R: {}", cc, hex::encode(&self.response));
353 Ok(result??)
354 }
355
356 fn prepare_command<C: TpmFrame>(
357 &mut self,
358 command: &C,
359 sessions: &[TpmsAuthCommand],
360 ) -> Result<(), TpmDeviceError> {
361 let cc = command.cc();
362 let tag = if sessions.is_empty() {
363 TpmSt::NoSessions
364 } else {
365 TpmSt::Sessions
366 };
367
368 self.command.resize(TPM_MAX_COMMAND_SIZE, 0);
369
370 let len = {
371 let mut writer = TpmWriter::new(&mut self.command);
372 tpm_marshal_command(command, tag, sessions, &mut writer)
373 .map_err(TpmDeviceError::Marshal)?;
374 writer.len()
375 };
376 self.command.truncate(len);
377
378 trace!("{} C: {}", cc, hex::encode(&self.command));
379 Ok(())
380 }
381
382 fn get_capability<T, F, N>(
392 &mut self,
393 cap: TpmCap,
394 property_start: u32,
395 count: u32,
396 mut extract: F,
397 next_prop: N,
398 ) -> Result<Vec<T>, TpmDeviceError>
399 where
400 T: Copy,
401 F: for<'a> FnMut(&'a TpmuCapabilities) -> Result<&'a [T], TpmDeviceError>,
402 N: Fn(&T) -> u32,
403 {
404 let mut results = Vec::new();
405 let mut prop = property_start;
406 loop {
407 let (more_data, cap_data) =
408 self.get_capability_page(cap, TpmUint32(prop), TpmUint32(count))?;
409 let items: &[T] = extract(&cap_data.data)?;
410 results.extend_from_slice(items);
411
412 if more_data {
413 if let Some(last) = items.last() {
414 prop = next_prop(last);
415 } else {
416 break;
417 }
418 } else {
419 break;
420 }
421 }
422 Ok(results)
423 }
424
425 pub fn fetch_algorithm_properties(&mut self) -> Result<Vec<TpmsAlgProperty>, TpmDeviceError> {
434 self.get_capability(
435 TpmCap::Algs,
436 0,
437 u32::try_from(MAX_HANDLES).map_err(|_| TpmDeviceError::OperationFailed)?,
438 |caps| match caps {
439 TpmuCapabilities::Algs(algs) => Ok(algs),
440 _ => Err(TpmDeviceError::CapabilityMissing(TpmCap::Algs)),
441 },
442 |last| last.alg as u32 + 1,
443 )
444 }
445
446 pub fn fetch_handles(&mut self, class: TpmHt) -> Result<Vec<TpmHandle>, TpmDeviceError> {
455 self.get_capability(
456 TpmCap::Handles,
457 (class as u32) << 24,
458 u32::try_from(MAX_HANDLES).map_err(|_| TpmDeviceError::OperationFailed)?,
459 |caps| match caps {
460 TpmuCapabilities::Handles(handles) => Ok(handles),
461 _ => Err(TpmDeviceError::CapabilityMissing(TpmCap::Handles)),
462 },
463 |last| last.value() + 1,
464 )
465 .map(|handles| handles.into_iter().collect())
466 }
467
468 pub fn fetch_ecc_curves(&mut self) -> Result<Vec<TpmEccCurve>, TpmDeviceError> {
477 self.get_capability(
478 TpmCap::EccCurves,
479 0,
480 u32::try_from(MAX_HANDLES).map_err(|_| TpmDeviceError::OperationFailed)?,
481 |caps| match caps {
482 TpmuCapabilities::EccCurves(curves) => Ok(curves),
483 _ => Err(TpmDeviceError::CapabilityMissing(TpmCap::EccCurves)),
484 },
485 |last| *last as u32 + 1,
486 )
487 }
488
489 pub fn fetch_pcr_bank_list(
504 &mut self,
505 ) -> Result<(Vec<TpmAlgId>, TpmsPcrSelect), TpmDeviceError> {
506 let pcrs: Vec<TpmsPcrSelection> = self.get_capability(
507 TpmCap::Pcrs,
508 0,
509 u32::try_from(MAX_HANDLES).map_err(|_| TpmDeviceError::OperationFailed)?,
510 |caps| match caps {
511 TpmuCapabilities::Pcrs(pcrs) => Ok(pcrs),
512 _ => Err(TpmDeviceError::CapabilityMissing(TpmCap::Pcrs)),
513 },
514 |last| last.hash as u32 + 1,
515 )?;
516
517 if pcrs.is_empty() {
518 return Err(TpmDeviceError::PcrBanksNotAvailable);
519 }
520
521 let mut common_select: Option<TpmsPcrSelect> = None;
522 let mut algs = Vec::with_capacity(pcrs.len());
523
524 for bank in pcrs {
525 if bank.pcr_select.iter().all(|&b| b == 0) {
526 debug!(
527 "skipping unallocated bank {:?} (mask: {})",
528 bank.hash,
529 hex::encode(&*bank.pcr_select)
530 );
531 continue;
532 }
533
534 if let Some(ref select) = common_select {
535 if bank.pcr_select != *select {
536 return Err(TpmDeviceError::PcrBankSelectionMismatch);
537 }
538 } else {
539 common_select = Some(bank.pcr_select);
540 }
541 algs.push(bank.hash);
542 }
543
544 let select = common_select.ok_or(TpmDeviceError::PcrBanksNotAvailable)?;
545
546 algs.sort();
547 Ok((algs, select))
548 }
549
550 fn get_capability_page(
560 &mut self,
561 cap: TpmCap,
562 property: TpmUint32,
563 property_count: TpmUint32,
564 ) -> Result<(bool, TpmsCapabilityData), TpmDeviceError> {
565 let cmd = TpmGetCapabilityCommand {
566 cap,
567 property,
568 property_count,
569 handles: [],
570 };
571
572 let (resp, _) = self.transmit(&cmd, Self::NO_SESSIONS)?;
573 let TpmGetCapabilityResponse {
574 more_data,
575 capability_data,
576 handles: [],
577 } = resp
578 .GetCapability()
579 .map_err(|_| TpmDeviceError::ResponseMismatch(TpmCc::GetCapability))?;
580
581 Ok((more_data.into(), capability_data))
582 }
583
584 pub fn get_tpm_property(&mut self, property: TpmPt) -> Result<TpmUint32, TpmDeviceError> {
593 let (_, cap_data) = self.get_capability_page(
594 TpmCap::TpmProperties,
595 TpmUint32(property as u32),
596 TpmUint32(1),
597 )?;
598
599 let TpmuCapabilities::TpmProperties(props) = &cap_data.data else {
600 return Err(TpmDeviceError::CapabilityMissing(TpmCap::TpmProperties));
601 };
602
603 let Some(prop) = props.iter().find(|prop| prop.property == property) else {
604 return Err(TpmDeviceError::CapabilityMissing(TpmCap::TpmProperties));
605 };
606
607 Ok(prop.value)
608 }
609
610 pub fn read_public(
619 &mut self,
620 handle: TpmHandle,
621 ) -> Result<(TpmtPublic, Tpm2bName), TpmDeviceError> {
622 let cmd = TpmReadPublicCommand { handles: [handle] };
623 let (resp, _) = self.transmit(&cmd, Self::NO_SESSIONS)?;
624 let read_public_resp = resp
625 .ReadPublic()
626 .map_err(|_| TpmDeviceError::ResponseMismatch(TpmCc::ReadPublic))?;
627 let public = read_public_resp.out_public.inner;
628 let name = read_public_resp.name;
629 Ok((public, name))
630 }
631
632 pub fn find_persistent(
641 &mut self,
642 target_name: &Tpm2bName,
643 ) -> Result<Option<TpmHandle>, TpmDeviceError> {
644 for handle in self.fetch_handles(TpmHt::Persistent)? {
645 match self.read_public(handle) {
646 Ok((_, name)) => {
647 if name == *target_name {
648 return Ok(Some(handle));
649 }
650 }
651 Err(TpmDeviceError::TpmRc(rc)) => {
652 let base = rc.base();
653 if base == TpmRcBase::ReferenceH0 || base == TpmRcBase::Handle {
654 continue;
655 }
656 return Err(TpmDeviceError::TpmRc(rc));
657 }
658 Err(e) => return Err(e),
659 }
660 }
661 Ok(None)
662 }
663
664 pub fn save_context(&mut self, save_handle: TpmHandle) -> Result<TpmsContext, TpmDeviceError> {
673 let cmd = TpmContextSaveCommand {
674 handles: [save_handle],
675 };
676 let (resp, _) = self.transmit(&cmd, Self::NO_SESSIONS)?;
677 let save_resp = resp
678 .ContextSave()
679 .map_err(|_| TpmDeviceError::ResponseMismatch(TpmCc::ContextSave))?;
680 Ok(save_resp.context)
681 }
682
683 pub fn load_context(&mut self, context: TpmsContext) -> Result<TpmHandle, TpmDeviceError> {
692 let cmd = TpmContextLoadCommand {
693 context,
694 handles: [],
695 };
696 let (resp, _) = self.transmit(&cmd, Self::NO_SESSIONS)?;
697 let resp_inner = resp
698 .ContextLoad()
699 .map_err(|_| TpmDeviceError::ResponseMismatch(TpmCc::ContextLoad))?;
700 Ok(resp_inner.handles[0])
701 }
702
703 pub fn flush_context(&mut self, handle: TpmHandle) -> Result<(), TpmDeviceError> {
711 let cmd = TpmFlushContextCommand {
712 flush_handle: handle,
713 handles: [],
714 };
715 self.transmit(&cmd, Self::NO_SESSIONS)?;
716 Ok(())
717 }
718
719 pub fn flush_session(&mut self, context: TpmsContext) -> Result<(), TpmDeviceError> {
726 match self.load_context(context) {
727 Ok(handle) => self.flush_context(handle),
728 Err(TpmDeviceError::TpmRc(rc)) => {
729 let base = rc.base();
730 if base == TpmRcBase::ReferenceH0 || base == TpmRcBase::Handle {
731 Ok(())
732 } else {
733 Err(TpmDeviceError::TpmRc(rc))
734 }
735 }
736 Err(e) => Err(e),
737 }
738 }
739}
740
741pub struct TpmPolicySessionBuilder {
743 bind: TpmHandle,
744 tpm_key: TpmHandle,
745 nonce_caller: Option<Tpm2bNonce>,
746 encrypted_salt: Option<Tpm2bEncryptedSecret>,
747 session_type: TpmSe,
748 symmetric: TpmtSymDefObject,
749 auth_hash: TpmAlgId,
750}
751
752impl Default for TpmPolicySessionBuilder {
753 fn default() -> Self {
754 Self {
755 bind: (TpmRh::Null as u32).into(),
756 tpm_key: (TpmRh::Null as u32).into(),
757 nonce_caller: None,
758 encrypted_salt: None,
759 session_type: TpmSe::Policy,
760 symmetric: TpmtSymDefObject::default(),
761 auth_hash: TpmAlgId::Sha256,
762 }
763 }
764}
765
766impl TpmPolicySessionBuilder {
767 #[must_use]
768 pub fn new() -> Self {
769 Self::default()
770 }
771
772 #[must_use]
773 pub fn with_bind(mut self, bind: TpmHandle) -> Self {
774 self.bind = bind;
775 self
776 }
777
778 #[must_use]
779 pub fn with_tpm_key(mut self, tpm_key: TpmHandle) -> Self {
780 self.tpm_key = tpm_key;
781 self
782 }
783
784 #[must_use]
785 pub fn with_nonce_caller(mut self, nonce: Tpm2bNonce) -> Self {
786 self.nonce_caller = Some(nonce);
787 self
788 }
789
790 #[must_use]
791 pub fn with_encrypted_salt(mut self, salt: Tpm2bEncryptedSecret) -> Self {
792 self.encrypted_salt = Some(salt);
793 self
794 }
795
796 #[must_use]
797 pub fn with_session_type(mut self, session_type: TpmSe) -> Self {
798 self.session_type = session_type;
799 self
800 }
801
802 #[must_use]
803 pub fn with_symmetric(mut self, symmetric: TpmtSymDefObject) -> Self {
804 self.symmetric = symmetric;
805 self
806 }
807
808 #[must_use]
809 pub fn with_auth_hash(mut self, auth_hash: TpmAlgId) -> Self {
810 self.auth_hash = auth_hash;
811 self
812 }
813
814 pub fn open(self, device: &mut TpmDevice) -> Result<TpmPolicySession, TpmDeviceError> {
825 let nonce_caller = if let Some(nonce) = self.nonce_caller {
826 nonce
827 } else {
828 let digest_len = TpmHash::from(self.auth_hash).size();
829 let mut nonce_bytes = vec![0; digest_len];
830 thread_rng().fill_bytes(&mut nonce_bytes);
831 Tpm2bNonce::try_from(nonce_bytes.as_slice()).map_err(TpmDeviceError::Unmarshal)?
832 };
833
834 let cmd = TpmStartAuthSessionCommand {
835 nonce_caller,
836 encrypted_salt: self.encrypted_salt.unwrap_or_default(),
837 session_type: self.session_type,
838 symmetric: self.symmetric,
839 auth_hash: self.auth_hash,
840 handles: [self.tpm_key, self.bind],
841 };
842
843 let (resp, _) = device.transmit(&cmd, TpmDevice::NO_SESSIONS)?;
844 let start_resp = resp
845 .StartAuthSession()
846 .map_err(|_| TpmDeviceError::ResponseMismatch(TpmCc::StartAuthSession))?;
847
848 Ok(TpmPolicySession {
849 handle: start_resp.handles[0],
850 attributes: TpmaSession::CONTINUE_SESSION,
851 hash_alg: self.auth_hash,
852 nonce_tpm: start_resp.nonce_tpm,
853 })
854 }
855}
856
857#[derive(Debug, Clone)]
859pub struct TpmPolicySession {
860 handle: TpmHandle,
861 attributes: TpmaSession,
862 hash_alg: TpmAlgId,
863 nonce_tpm: Tpm2bNonce,
864}
865
866impl TpmPolicySession {
867 #[must_use]
869 pub fn builder() -> TpmPolicySessionBuilder {
870 TpmPolicySessionBuilder::new()
871 }
872
873 #[must_use]
875 pub fn handle(&self) -> TpmHandle {
876 self.handle
877 }
878
879 #[must_use]
881 pub fn attributes(&self) -> TpmaSession {
882 self.attributes
883 }
884
885 #[must_use]
887 pub fn hash_alg(&self) -> TpmAlgId {
888 self.hash_alg
889 }
890
891 #[must_use]
893 pub fn nonce_tpm(&self) -> &Tpm2bNonce {
894 &self.nonce_tpm
895 }
896
897 pub fn run(
910 &self,
911 device: &mut TpmDevice,
912 commands: Vec<(TpmCommand, TpmAuthCommands)>,
913 ) -> Result<(), TpmDeviceError> {
914 for (mut command_body, auth_sessions) in commands {
915 match &mut command_body {
916 TpmCommand::PolicyPcr(cmd) => cmd.handles[0] = self.handle,
917 TpmCommand::PolicyOr(cmd) => cmd.handles[0] = self.handle,
918 TpmCommand::PolicyRestart(cmd) => {
919 cmd.handles[0] = self.handle;
920 }
921 TpmCommand::PolicySecret(cmd) => {
922 cmd.handles[1] = self.handle;
923 }
924 _ => {
925 return Err(TpmDeviceError::InvalidCc(command_body.cc()));
926 }
927 }
928 device.transmit(&command_body, auth_sessions.as_ref())?;
929 }
930 Ok(())
931 }
932
933 pub fn flush(&self, device: &mut TpmDevice) -> Result<(), TpmDeviceError> {
940 device.flush_context(self.handle)
941 }
942}