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, TpmResponseOutcome, TpmResponseView,
44 TpmStartAuthSessionCommand, 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 trait TpmTransport {
195 fn send(&mut self, frame: &[u8]) -> Result<(), TpmDeviceError>;
201
202 fn recv(&mut self, buf: &mut Vec<u8>) -> Result<(), TpmDeviceError>;
214}
215
216const TPM_HEADER_SIZE: usize = 10;
217
218fn frame_size(header: &[u8]) -> Result<usize, TpmDeviceError> {
226 let Some(size_bytes) = header.get(2..6) else {
227 return Err(TpmDeviceError::InvalidResponse);
228 };
229 let Ok(size_bytes): Result<[u8; 4], _> = size_bytes.try_into() else {
230 return Err(TpmDeviceError::InvalidResponse);
231 };
232 let size = u32::from_be_bytes(size_bytes) as usize;
233 if !(TPM_HEADER_SIZE..=TPM_MAX_COMMAND_SIZE).contains(&size) {
234 return Err(TpmDeviceError::InvalidResponse);
235 }
236 Ok(size)
237}
238
239fn fill_exact<R: Read>(reader: &mut R, buf: &mut [u8]) -> Result<(), TpmDeviceError> {
240 match reader.read_exact(buf) {
241 Ok(()) => Ok(()),
242 Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
243 Err(TpmDeviceError::UnexpectedEof)
244 }
245 Err(e) => Err(TpmDeviceError::Io(e)),
246 }
247}
248
249pub fn read_frame<R: Read>(reader: &mut R, buf: &mut Vec<u8>) -> Result<(), TpmDeviceError> {
264 buf.clear();
265 buf.resize(TPM_HEADER_SIZE, 0);
266 fill_exact(reader, buf)?;
267
268 let size = frame_size(buf)?;
269 buf.resize(size, 0);
270 fill_exact(reader, &mut buf[TPM_HEADER_SIZE..])?;
271
272 Ok(())
273}
274
275pub fn write_frame<W: Write>(writer: &mut W, frame: &[u8]) -> Result<(), TpmDeviceError> {
281 writer.write_all(frame).map_err(TpmDeviceError::Io)?;
282 writer.flush().map_err(TpmDeviceError::Io)?;
283 Ok(())
284}
285
286pub struct TpmStreamTransport<S: Read + Write> {
291 stream: S,
292}
293
294impl<S: Read + Write> TpmStreamTransport<S> {
295 #[must_use]
297 pub fn new(stream: S) -> Self {
298 Self { stream }
299 }
300
301 #[must_use]
303 pub fn into_inner(self) -> S {
304 self.stream
305 }
306}
307
308impl<S: Read + Write> TpmTransport for TpmStreamTransport<S> {
309 fn send(&mut self, frame: &[u8]) -> Result<(), TpmDeviceError> {
310 write_frame(&mut self.stream, frame)
311 }
312
313 fn recv(&mut self, buf: &mut Vec<u8>) -> Result<(), TpmDeviceError> {
314 read_frame(&mut self.stream, buf)
315 }
316}
317
318pub struct TpmPosixDevice {
320 file: File,
321 interrupted: Box<dyn Fn() -> bool>,
322 timeout: Duration,
323}
324
325impl TpmPosixDevice {
326 #[must_use]
328 pub fn builder() -> TpmPosixDeviceBuilder {
329 TpmPosixDeviceBuilder::default()
330 }
331
332 fn receive(&mut self, buf: &mut [u8]) -> Result<usize, TpmDeviceError> {
333 let fd = self.file.as_fd();
334 let mut fds = [PollFd::new(fd, PollFlags::POLLIN)];
335
336 let num_events = match poll(&mut fds, 100u16) {
337 Ok(num) => num,
338 Err(nix::Error::EINTR) => return Ok(0),
339 Err(e) => return Err(e.into()),
340 };
341
342 if num_events == 0 {
343 return Ok(0);
344 }
345
346 let revents = fds[0].revents().unwrap_or(PollFlags::empty());
347
348 if revents.intersects(PollFlags::POLLERR | PollFlags::POLLNVAL) {
349 return Err(TpmDeviceError::UnexpectedEof);
350 }
351
352 if revents.contains(PollFlags::POLLIN) {
353 match self.file.read(buf) {
354 Ok(0) => Err(TpmDeviceError::UnexpectedEof),
355 Ok(n) => Ok(n),
356 Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => Ok(0),
357 Err(e) if e.kind() == std::io::ErrorKind::Interrupted => Ok(0),
358 Err(e) => Err(e.into()),
359 }
360 } else if revents.contains(PollFlags::POLLHUP) {
361 Err(TpmDeviceError::UnexpectedEof)
362 } else {
363 Ok(0)
364 }
365 }
366}
367
368impl TpmTransport for TpmPosixDevice {
369 fn send(&mut self, frame: &[u8]) -> Result<(), TpmDeviceError> {
370 self.file.write_all(frame)?;
371 self.file.flush()?;
372 Ok(())
373 }
374
375 fn recv(&mut self, buf: &mut Vec<u8>) -> Result<(), TpmDeviceError> {
376 buf.clear();
377 let start_time = Instant::now();
378 let mut total_size: Option<usize> = None;
379 let mut temp_buf = [0u8; 1024];
380
381 loop {
382 if (self.interrupted)() {
383 return Err(TpmDeviceError::Interrupted);
384 }
385 if start_time.elapsed() > self.timeout {
386 return Err(TpmDeviceError::Timeout);
387 }
388
389 let n = self.receive(&mut temp_buf)?;
390 if n > 0 {
391 buf.extend_from_slice(&temp_buf[..n]);
392 }
393
394 if total_size.is_none() && buf.len() >= TPM_HEADER_SIZE {
395 total_size = Some(frame_size(buf)?);
396 }
397
398 if let Some(size) = total_size {
399 if buf.len() == size {
400 break;
401 }
402 if buf.len() > size {
403 return Err(TpmDeviceError::TrailingData);
404 }
405 }
406 }
407
408 Ok(())
409 }
410}
411
412pub struct TpmPosixDeviceBuilder {
414 path: PathBuf,
415 timeout: Duration,
416 interrupted: Box<dyn Fn() -> bool>,
417}
418
419impl Default for TpmPosixDeviceBuilder {
420 fn default() -> Self {
421 Self {
422 path: PathBuf::from("/dev/tpmrm0"),
423 timeout: Duration::from_secs(120),
424 interrupted: Box::new(|| false),
425 }
426 }
427}
428
429impl TpmPosixDeviceBuilder {
430 #[must_use]
432 pub fn with_path<P: AsRef<Path>>(mut self, path: P) -> Self {
433 self.path = path.as_ref().to_path_buf();
434 self
435 }
436
437 #[must_use]
439 pub fn with_timeout(mut self, timeout: Duration) -> Self {
440 self.timeout = timeout;
441 self
442 }
443
444 #[must_use]
446 pub fn with_interrupted<F>(mut self, handler: F) -> Self
447 where
448 F: Fn() -> bool + 'static,
449 {
450 self.interrupted = Box::new(handler);
451 self
452 }
453
454 pub fn build(self) -> Result<TpmPosixDevice, TpmDeviceError> {
461 let file = OpenOptions::new()
462 .read(true)
463 .write(true)
464 .open(&self.path)
465 .map_err(TpmDeviceError::Io)?;
466
467 let fd = file.as_raw_fd();
468 let flags = fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFL)?;
469 let mut oflags = fcntl::OFlag::from_bits_truncate(flags);
470 oflags.insert(fcntl::OFlag::O_NONBLOCK);
471 fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFL(oflags))?;
472
473 Ok(TpmPosixDevice {
474 file,
475 interrupted: self.interrupted,
476 timeout: self.timeout,
477 })
478 }
479}
480
481pub struct TpmDevice {
482 transport: Box<dyn TpmTransport>,
483 command: Vec<u8>,
484 response: Vec<u8>,
485}
486
487impl std::fmt::Debug for TpmDevice {
488 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
489 f.debug_struct("TpmDevice").finish_non_exhaustive()
490 }
491}
492
493impl TpmDevice {
494 const NO_SESSIONS: &'static [TpmsAuthCommand] = &[];
495
496 #[allow(clippy::cast_possible_truncation)]
498 const CAPABILITY_PAGE_SIZE: u32 = MAX_HANDLES as u32;
499
500 #[must_use]
502 pub fn new(transport: Box<dyn TpmTransport>) -> Self {
503 Self {
504 transport,
505 command: Vec::with_capacity(TPM_MAX_COMMAND_SIZE),
506 response: Vec::with_capacity(TPM_MAX_COMMAND_SIZE),
507 }
508 }
509
510 pub fn transmit<C: TpmFrame>(
528 &mut self,
529 command: &C,
530 sessions: &[TpmsAuthCommand],
531 ) -> Result<&TpmResponse, TpmDeviceError> {
532 self.prepare_command(command, sessions)?;
533 let cc = command.cc();
534
535 self.transport.send(&self.command)?;
536 self.transport.recv(&mut self.response)?;
537
538 let response = TpmResponse::cast(&self.response).map_err(TpmDeviceError::Unmarshal)?;
539 let outcome = TpmResponseView::cast(cc, response).map_err(TpmDeviceError::Unmarshal)?;
540 trace!("{} R: {}", cc, hex::encode(&self.response));
541 match outcome {
542 TpmResponseOutcome::Dispatched(_) => Ok(response),
543 TpmResponseOutcome::Rejected(rc) => Err(TpmDeviceError::TpmRc(rc)),
544 }
545 }
546
547 fn prepare_command<C: TpmFrame>(
548 &mut self,
549 command: &C,
550 sessions: &[TpmsAuthCommand],
551 ) -> Result<(), TpmDeviceError> {
552 let cc = command.cc();
553 let tag = if sessions.is_empty() {
554 TpmSt::NoSessions
555 } else {
556 TpmSt::Sessions
557 };
558
559 self.command.resize(TPM_MAX_COMMAND_SIZE, 0);
560
561 let len = {
562 let mut writer = TpmWriter::new(&mut self.command);
563 tpm_marshal_command(command, tag, sessions, &mut writer)
564 .map_err(TpmDeviceError::Marshal)?;
565 writer.len()
566 };
567 self.command.truncate(len);
568
569 trace!("{} C: {}", cc, hex::encode(&self.command));
570 Ok(())
571 }
572
573 fn get_capability<T, F, N>(
583 &mut self,
584 cap: TpmCap,
585 property_start: u32,
586 count: u32,
587 mut extract: F,
588 next_prop: N,
589 ) -> Result<Vec<T>, TpmDeviceError>
590 where
591 T: Copy,
592 F: for<'a> FnMut(&'a TpmuCapabilities) -> Result<&'a [T], TpmDeviceError>,
593 N: Fn(&T) -> u32,
594 {
595 let mut results = Vec::new();
596 let mut prop = property_start;
597 loop {
598 let (more_data, cap_data) =
599 self.get_capability_page(cap, TpmUint32::from(prop), TpmUint32::from(count))?;
600 let items: &[T] = extract(&cap_data.data)?;
601 results.extend_from_slice(items);
602
603 if more_data {
604 if let Some(last) = items.last() {
605 prop = next_prop(last);
606 } else {
607 break;
608 }
609 } else {
610 break;
611 }
612 }
613 Ok(results)
614 }
615
616 pub fn fetch_algorithm_properties(&mut self) -> Result<Vec<TpmsAlgProperty>, TpmDeviceError> {
625 self.get_capability(
626 TpmCap::Algs,
627 0,
628 Self::CAPABILITY_PAGE_SIZE,
629 |caps| match caps {
630 TpmuCapabilities::Algs(algs) => Ok(algs),
631 _ => Err(TpmDeviceError::CapabilityMissing(TpmCap::Algs)),
632 },
633 |last| u32::from(last.alg.value()) + 1,
634 )
635 }
636
637 pub fn fetch_handles(&mut self, class: TpmHt) -> Result<Vec<TpmHandle>, TpmDeviceError> {
646 self.get_capability(
647 TpmCap::Handles,
648 (class as u32) << 24,
649 Self::CAPABILITY_PAGE_SIZE,
650 |caps| match caps {
651 TpmuCapabilities::Handles(handles) => Ok(handles),
652 _ => Err(TpmDeviceError::CapabilityMissing(TpmCap::Handles)),
653 },
654 |last| last.value() + 1,
655 )
656 .map(|handles| handles.into_iter().collect())
657 }
658
659 pub fn fetch_ecc_curves(&mut self) -> Result<Vec<TpmEccCurve>, TpmDeviceError> {
668 self.get_capability(
669 TpmCap::EccCurves,
670 0,
671 Self::CAPABILITY_PAGE_SIZE,
672 |caps| match caps {
673 TpmuCapabilities::EccCurves(curves) => Ok(curves),
674 _ => Err(TpmDeviceError::CapabilityMissing(TpmCap::EccCurves)),
675 },
676 |last| u32::from(last.value()) + 1,
677 )
678 }
679
680 pub fn fetch_pcr_bank_list(
695 &mut self,
696 ) -> Result<(Vec<TpmAlgId>, TpmsPcrSelect), TpmDeviceError> {
697 let pcrs: Vec<TpmsPcrSelection> = self.get_capability(
698 TpmCap::Pcrs,
699 0,
700 Self::CAPABILITY_PAGE_SIZE,
701 |caps| match caps {
702 TpmuCapabilities::Pcrs(pcrs) => Ok(pcrs),
703 _ => Err(TpmDeviceError::CapabilityMissing(TpmCap::Pcrs)),
704 },
705 |last| last.hash as u32 + 1,
706 )?;
707
708 if pcrs.is_empty() {
709 return Err(TpmDeviceError::PcrBanksNotAvailable);
710 }
711
712 let mut common_select: Option<TpmsPcrSelect> = None;
713 let mut algs = Vec::with_capacity(pcrs.len());
714
715 for bank in pcrs {
716 if bank.pcr_select.iter().all(|&b| b == 0) {
717 debug!(
718 "skipping unallocated bank {:?} (mask: {})",
719 bank.hash,
720 hex::encode(&*bank.pcr_select)
721 );
722 continue;
723 }
724
725 if let Some(ref select) = common_select {
726 if bank.pcr_select != *select {
727 return Err(TpmDeviceError::PcrBankSelectionMismatch);
728 }
729 } else {
730 common_select = Some(bank.pcr_select);
731 }
732 algs.push(bank.hash);
733 }
734
735 let select = common_select.ok_or(TpmDeviceError::PcrBanksNotAvailable)?;
736
737 algs.sort();
738 Ok((algs, select))
739 }
740
741 fn get_capability_page(
751 &mut self,
752 cap: TpmCap,
753 property: TpmUint32,
754 property_count: TpmUint32,
755 ) -> Result<(bool, TpmsCapabilityData), TpmDeviceError> {
756 let cmd = TpmGetCapabilityCommand {
757 cap,
758 property,
759 property_count,
760 handles: [],
761 };
762
763 let response = self.transmit(&cmd, Self::NO_SESSIONS)?;
764 let (_, parameters) = response_parts(response, 0)?;
765 let (more_data, parameters) = parse_field_value::<TpmiYesNo>(parameters)?;
766 let (capability_data, rest) = parse_capability_data(parameters)?;
767 ensure_empty(rest)?;
768
769 Ok((more_data.into(), capability_data))
770 }
771
772 pub fn fetch_tpm_property(&mut self, property: TpmPt) -> Result<u32, TpmDeviceError> {
781 let (_, cap_data) = self.get_capability_page(
782 TpmCap::TpmProperties,
783 TpmUint32::from(property as u32),
784 TpmUint32::from(1),
785 )?;
786
787 let TpmuCapabilities::TpmProperties(props) = &cap_data.data else {
788 return Err(TpmDeviceError::CapabilityMissing(TpmCap::TpmProperties));
789 };
790
791 let Some(prop) = props.iter().find(|prop| prop.property == property) else {
792 return Err(TpmDeviceError::CapabilityMissing(TpmCap::TpmProperties));
793 };
794
795 Ok(prop.value.value())
796 }
797
798 pub fn read_public(
807 &mut self,
808 handle: TpmHandle,
809 ) -> Result<(TpmtPublic, Tpm2bName), TpmDeviceError> {
810 let cmd = TpmReadPublicCommand { handles: [handle] };
811 let response = self.transmit(&cmd, Self::NO_SESSIONS)?;
812 let (_, parameters) = response_parts(response, 0)?;
813 let (public, parameters) = parse_tpm2b_public(parameters)?;
814 let (name, parameters): (Tpm2bName, _) = parse_tpm2b_buffer(parameters)?;
815 let (_qualified_name, rest): (Tpm2bName, _) = parse_tpm2b_buffer(parameters)?;
816 ensure_empty(rest)?;
817
818 Ok((public, name))
819 }
820
821 pub fn find_persistent(
830 &mut self,
831 target_name: &Tpm2bName,
832 ) -> Result<Option<TpmHandle>, TpmDeviceError> {
833 for handle in self.fetch_handles(TpmHt::Persistent)? {
834 match self.read_public(handle) {
835 Ok((_, name)) => {
836 if name == *target_name {
837 return Ok(Some(handle));
838 }
839 }
840 Err(TpmDeviceError::TpmRc(rc)) => {
841 let base = rc.base();
842 if base == TpmRcBase::ReferenceH0 || base == TpmRcBase::Handle {
843 continue;
844 }
845 return Err(TpmDeviceError::TpmRc(rc));
846 }
847 Err(e) => return Err(e),
848 }
849 }
850 Ok(None)
851 }
852
853 pub fn save_context(&mut self, save_handle: TpmHandle) -> Result<TpmsContext, TpmDeviceError> {
862 let cmd = TpmContextSaveCommand {
863 handles: [save_handle],
864 };
865 let response = self.transmit(&cmd, Self::NO_SESSIONS)?;
866 let (_, parameters) = response_parts(response, 0)?;
867 let (context, rest) = parse_tpms_context(parameters)?;
868 ensure_empty(rest)?;
869
870 Ok(context)
871 }
872
873 pub fn load_context(&mut self, context: TpmsContext) -> Result<TpmHandle, TpmDeviceError> {
882 let cmd = TpmContextLoadCommand {
883 context,
884 handles: [],
885 };
886 let response = self.transmit(&cmd, Self::NO_SESSIONS)?;
887 let (handles, parameters) = response_parts(response, 1)?;
888 let (handle, rest) = parse_wire_copy::<TpmHandle>(handles)?;
889 ensure_empty(rest)?;
890 ensure_empty(parameters)?;
891
892 Ok(handle)
893 }
894
895 pub fn flush_context(&mut self, handle: TpmHandle) -> Result<(), TpmDeviceError> {
903 let cmd = TpmFlushContextCommand {
904 flush_handle: handle,
905 handles: [],
906 };
907 self.transmit(&cmd, Self::NO_SESSIONS)?;
908 Ok(())
909 }
910
911 pub fn flush_session(&mut self, context: TpmsContext) -> Result<(), TpmDeviceError> {
918 match self.load_context(context) {
919 Ok(handle) => self.flush_context(handle),
920 Err(TpmDeviceError::TpmRc(rc)) => {
921 let base = rc.base();
922 if base == TpmRcBase::ReferenceH0 || base == TpmRcBase::Handle {
923 Ok(())
924 } else {
925 Err(TpmDeviceError::TpmRc(rc))
926 }
927 }
928 Err(e) => Err(e),
929 }
930 }
931}
932
933pub struct TpmResponder {
943 transport: Box<dyn TpmTransport>,
944 command: Vec<u8>,
945}
946
947impl std::fmt::Debug for TpmResponder {
948 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
949 f.debug_struct("TpmResponder").finish_non_exhaustive()
950 }
951}
952
953impl TpmResponder {
954 #[must_use]
956 pub fn new(transport: Box<dyn TpmTransport>) -> Self {
957 Self {
958 transport,
959 command: Vec::with_capacity(TPM_MAX_COMMAND_SIZE),
960 }
961 }
962
963 pub fn recv_command(&mut self) -> Result<&[u8], TpmDeviceError> {
971 self.transport.recv(&mut self.command)?;
972 Ok(&self.command)
973 }
974
975 pub fn send_response(&mut self, frame: &[u8]) -> Result<(), TpmDeviceError> {
982 self.transport.send(frame)
983 }
984
985 pub fn serve<H>(&mut self, mut handler: H) -> Result<(), TpmDeviceError>
997 where
998 H: FnMut(&[u8]) -> Vec<u8>,
999 {
1000 loop {
1001 match self.transport.recv(&mut self.command) {
1002 Ok(()) => {}
1003 Err(TpmDeviceError::UnexpectedEof) => return Ok(()),
1004 Err(e) => return Err(e),
1005 }
1006 let response = handler(&self.command);
1007 self.transport.send(&response)?;
1008 }
1009 }
1010}
1011
1012fn ensure_empty(buf: &[u8]) -> Result<(), TpmDeviceError> {
1013 if buf.is_empty() {
1014 Ok(())
1015 } else {
1016 Err(TpmDeviceError::TrailingData)
1017 }
1018}
1019
1020fn response_parts(
1021 response: &TpmResponse,
1022 response_handles: usize,
1023) -> Result<(&[u8], &[u8]), TpmDeviceError> {
1024 let handle_len = response_handles
1025 .checked_mul(core::mem::size_of::<TpmHandle>())
1026 .ok_or(TpmDeviceError::InvalidResponse)?;
1027 let body = response.body();
1028 if body.len() < handle_len {
1029 return Err(TpmDeviceError::InvalidResponse);
1030 }
1031
1032 let (handles, after_handles) = body.split_at(handle_len);
1033 if response.tag().map_err(TpmDeviceError::Unmarshal)? != TpmSt::Sessions {
1034 return Ok((handles, after_handles));
1035 }
1036
1037 let (parameter_size, after_size) = parse_wire_copy::<TpmUint32>(after_handles)?;
1038 let parameter_size =
1039 usize::try_from(parameter_size.value()).map_err(|_| TpmDeviceError::InvalidResponse)?;
1040 if after_size.len() < parameter_size {
1041 return Err(TpmDeviceError::InvalidResponse);
1042 }
1043
1044 let (parameters, _auth_area) = after_size.split_at(parameter_size);
1045 Ok((handles, parameters))
1046}
1047
1048fn parse_wire_copy<'a, T>(buf: &'a [u8]) -> Result<(T, &'a [u8]), TpmDeviceError>
1049where
1050 T: TpmCast + Copy + 'a,
1051{
1052 let (value, rest) = T::cast_prefix(buf).map_err(TpmDeviceError::Unmarshal)?;
1053 Ok((*value, rest))
1054}
1055
1056fn parse_field_value<'a, T>(buf: &'a [u8]) -> Result<(T, &'a [u8]), TpmDeviceError>
1057where
1058 T: TpmField<'a, View = T>,
1059{
1060 <T as TpmField<'a>>::cast_prefix_field(buf).map_err(TpmDeviceError::Unmarshal)
1061}
1062
1063fn parse_tpm2b_buffer<const CAPACITY: usize>(
1064 buf: &[u8],
1065) -> Result<(TpmBuffer<CAPACITY>, &[u8]), TpmDeviceError> {
1066 let (value, rest) =
1067 Tpm2bWire::<CAPACITY>::cast_prefix(buf).map_err(TpmDeviceError::Unmarshal)?;
1068 let value = TpmBuffer::<CAPACITY>::try_from(value.data()).map_err(TpmDeviceError::Unmarshal)?;
1069
1070 Ok((value, rest))
1071}
1072
1073fn parse_tpms_scheme_hash(buf: &[u8]) -> Result<(TpmsSchemeHash, &[u8]), TpmDeviceError> {
1074 let (hash_alg, rest) = parse_field_value::<TpmAlgId>(buf)?;
1075
1076 Ok((TpmsSchemeHash { hash_alg }, rest))
1077}
1078
1079fn parse_tpmt_kdf_scheme(buf: &[u8]) -> Result<(TpmtKdfScheme, &[u8]), TpmDeviceError> {
1080 let (scheme, buf) = parse_field_value::<TpmAlgId>(buf)?;
1081 let (details, rest) = parse_tpmu_kdf_scheme(scheme, buf)?;
1082
1083 Ok((TpmtKdfScheme { scheme, details }, rest))
1084}
1085
1086fn parse_tpmu_kdf_scheme(
1087 scheme: TpmAlgId,
1088 buf: &[u8],
1089) -> Result<(TpmuKdfScheme, &[u8]), TpmDeviceError> {
1090 match scheme {
1091 TpmAlgId::Mgf1 => {
1092 let (details, rest) = parse_tpms_scheme_hash(buf)?;
1093 Ok((TpmuKdfScheme::Mgf1(details), rest))
1094 }
1095 TpmAlgId::Kdf1Sp800_56A => {
1096 let (details, rest) = parse_tpms_scheme_hash(buf)?;
1097 Ok((TpmuKdfScheme::Kdf1Sp800_56a(details), rest))
1098 }
1099 TpmAlgId::Kdf2 => {
1100 let (details, rest) = parse_tpms_scheme_hash(buf)?;
1101 Ok((TpmuKdfScheme::Kdf2(details), rest))
1102 }
1103 TpmAlgId::Kdf1Sp800_108 => {
1104 let (details, rest) = parse_tpms_scheme_hash(buf)?;
1105 Ok((TpmuKdfScheme::Kdf1Sp800_108(details), rest))
1106 }
1107 TpmAlgId::Null => Ok((TpmuKdfScheme::Null, buf)),
1108 _ => Err(TpmDeviceError::InvalidResponse),
1109 }
1110}
1111
1112fn parse_tpms_scheme_xor(buf: &[u8]) -> Result<(TpmsSchemeXor, &[u8]), TpmDeviceError> {
1113 let (hash_alg, buf) = parse_field_value::<TpmAlgId>(buf)?;
1114 let (kdf, rest) = parse_tpmt_kdf_scheme(buf)?;
1115
1116 Ok((TpmsSchemeXor { hash_alg, kdf }, rest))
1117}
1118
1119fn parse_tpmu_keyedhash_scheme(
1120 scheme: TpmAlgId,
1121 buf: &[u8],
1122) -> Result<(TpmuKeyedhashScheme, &[u8]), TpmDeviceError> {
1123 match scheme {
1124 TpmAlgId::Hmac => {
1125 let (details, rest) = parse_tpms_scheme_hash(buf)?;
1126 Ok((TpmuKeyedhashScheme::Hmac(details), rest))
1127 }
1128 TpmAlgId::Xor => {
1129 let (details, rest) = parse_tpms_scheme_xor(buf)?;
1130 Ok((TpmuKeyedhashScheme::Xor(details), rest))
1131 }
1132 TpmAlgId::Null => Ok((TpmuKeyedhashScheme::Null, buf)),
1133 _ => Err(TpmDeviceError::InvalidResponse),
1134 }
1135}
1136
1137fn parse_tpmt_keyedhash_scheme(buf: &[u8]) -> Result<(TpmtKeyedhashScheme, &[u8]), TpmDeviceError> {
1138 let (scheme, buf) = parse_field_value::<TpmAlgId>(buf)?;
1139 let (details, rest) = parse_tpmu_keyedhash_scheme(scheme, buf)?;
1140
1141 Ok((TpmtKeyedhashScheme { scheme, details }, rest))
1142}
1143
1144fn parse_tpmu_asym_scheme(
1145 scheme: TpmAlgId,
1146 buf: &[u8],
1147) -> Result<(TpmuAsymScheme, &[u8]), TpmDeviceError> {
1148 match scheme {
1149 TpmAlgId::Rsassa
1150 | TpmAlgId::Rsapss
1151 | TpmAlgId::Ecdsa
1152 | TpmAlgId::Ecdaa
1153 | TpmAlgId::Sm2
1154 | TpmAlgId::Ecschnorr
1155 | TpmAlgId::Oaep
1156 | TpmAlgId::Ecdh
1157 | TpmAlgId::Ecmqv => {
1158 let (details, rest) = parse_tpms_scheme_hash(buf)?;
1159 Ok((TpmuAsymScheme::Hash(details), rest))
1160 }
1161 TpmAlgId::Rsaes | TpmAlgId::Null => Ok((TpmuAsymScheme::Null, buf)),
1162 _ => Err(TpmDeviceError::InvalidResponse),
1163 }
1164}
1165
1166fn parse_tpmt_rsa_scheme(buf: &[u8]) -> Result<(TpmtRsaScheme, &[u8]), TpmDeviceError> {
1167 let (scheme, buf) = parse_field_value::<TpmAlgId>(buf)?;
1168 let (details, rest) = parse_tpmu_asym_scheme(scheme, buf)?;
1169
1170 Ok((TpmtRsaScheme { scheme, details }, rest))
1171}
1172
1173fn parse_tpmt_ecc_scheme(buf: &[u8]) -> Result<(TpmtEccScheme, &[u8]), TpmDeviceError> {
1174 let (scheme, buf) = parse_field_value::<TpmAlgId>(buf)?;
1175 let (details, rest) = parse_tpmu_asym_scheme(scheme, buf)?;
1176
1177 Ok((TpmtEccScheme { scheme, details }, rest))
1178}
1179
1180fn parse_tpmu_sym_key_bits(
1181 algorithm: TpmAlgId,
1182 buf: &[u8],
1183) -> Result<(TpmuSymKeyBits, &[u8]), TpmDeviceError> {
1184 match algorithm {
1185 TpmAlgId::Aes => {
1186 let (value, rest) = parse_wire_copy::<TpmUint16>(buf)?;
1187 Ok((TpmuSymKeyBits::Aes(value), rest))
1188 }
1189 TpmAlgId::Sm4 => {
1190 let (value, rest) = parse_wire_copy::<TpmUint16>(buf)?;
1191 Ok((TpmuSymKeyBits::Sm4(value), rest))
1192 }
1193 TpmAlgId::Camellia => {
1194 let (value, rest) = parse_wire_copy::<TpmUint16>(buf)?;
1195 Ok((TpmuSymKeyBits::Camellia(value), rest))
1196 }
1197 TpmAlgId::Xor => {
1198 let (value, rest) = parse_field_value::<TpmAlgId>(buf)?;
1199 Ok((TpmuSymKeyBits::Xor(value), rest))
1200 }
1201 TpmAlgId::Null => Ok((TpmuSymKeyBits::Null, buf)),
1202 _ => Err(TpmDeviceError::InvalidResponse),
1203 }
1204}
1205
1206fn parse_tpmu_sym_mode(
1207 algorithm: TpmAlgId,
1208 buf: &[u8],
1209) -> Result<(TpmuSymMode, &[u8]), TpmDeviceError> {
1210 match algorithm {
1211 TpmAlgId::Aes => {
1212 let (value, rest) = parse_field_value::<TpmAlgId>(buf)?;
1213 Ok((TpmuSymMode::Aes(value), rest))
1214 }
1215 TpmAlgId::Sm4 => {
1216 let (value, rest) = parse_field_value::<TpmAlgId>(buf)?;
1217 Ok((TpmuSymMode::Sm4(value), rest))
1218 }
1219 TpmAlgId::Camellia => {
1220 let (value, rest) = parse_field_value::<TpmAlgId>(buf)?;
1221 Ok((TpmuSymMode::Camellia(value), rest))
1222 }
1223 TpmAlgId::Xor => {
1224 let (value, rest) = parse_field_value::<TpmAlgId>(buf)?;
1225 Ok((TpmuSymMode::Xor(value), rest))
1226 }
1227 TpmAlgId::Null => Ok((TpmuSymMode::Null, buf)),
1228 _ => Err(TpmDeviceError::InvalidResponse),
1229 }
1230}
1231
1232fn parse_tpmt_sym_def(buf: &[u8]) -> Result<(TpmtSymDefObject, &[u8]), TpmDeviceError> {
1233 let (algorithm, buf) = parse_field_value::<TpmAlgId>(buf)?;
1234 if algorithm == TpmAlgId::Null {
1235 return Ok((TpmtSymDefObject::default(), buf));
1236 }
1237
1238 let (key_bits, buf) = parse_tpmu_sym_key_bits(algorithm, buf)?;
1239 let (mode, rest) = parse_tpmu_sym_mode(algorithm, buf)?;
1240
1241 Ok((
1242 TpmtSymDefObject {
1243 algorithm,
1244 key_bits,
1245 mode,
1246 },
1247 rest,
1248 ))
1249}
1250
1251fn parse_tpmu_public_parms(
1252 object_type: TpmAlgId,
1253 buf: &[u8],
1254) -> Result<(TpmuPublicParms, &[u8]), TpmDeviceError> {
1255 match object_type {
1256 TpmAlgId::KeyedHash => {
1257 let (scheme, rest) = parse_tpmt_keyedhash_scheme(buf)?;
1258 Ok((
1259 TpmuPublicParms::KeyedHash(TpmsKeyedhashParms { scheme }),
1260 rest,
1261 ))
1262 }
1263 TpmAlgId::SymCipher => {
1264 let (sym, rest) = parse_tpmt_sym_def(buf)?;
1265 Ok((TpmuPublicParms::SymCipher(TpmsSymcipherParms { sym }), rest))
1266 }
1267 TpmAlgId::Rsa => {
1268 let (symmetric, buf) = parse_tpmt_sym_def(buf)?;
1269 let (scheme, buf) = parse_tpmt_rsa_scheme(buf)?;
1270 let (key_bits, buf) = parse_wire_copy::<TpmUint16>(buf)?;
1271 let (exponent, rest) = parse_wire_copy::<TpmUint32>(buf)?;
1272 Ok((
1273 TpmuPublicParms::Rsa(TpmsRsaParms {
1274 symmetric,
1275 scheme,
1276 key_bits,
1277 exponent,
1278 }),
1279 rest,
1280 ))
1281 }
1282 TpmAlgId::Ecc => {
1283 let (symmetric, buf) = parse_tpmt_sym_def(buf)?;
1284 let (scheme, buf) = parse_tpmt_ecc_scheme(buf)?;
1285 let (curve_id, buf) = parse_field_value::<TpmEccCurve>(buf)?;
1286 let (kdf, rest) = parse_tpmt_kdf_scheme(buf)?;
1287 Ok((
1288 TpmuPublicParms::Ecc(TpmsEccParms {
1289 symmetric,
1290 scheme,
1291 curve_id,
1292 kdf,
1293 }),
1294 rest,
1295 ))
1296 }
1297 TpmAlgId::Null => Ok((TpmuPublicParms::Null, buf)),
1298 _ => Err(TpmDeviceError::InvalidResponse),
1299 }
1300}
1301
1302fn parse_tpms_ecc_point(buf: &[u8]) -> Result<(TpmsEccPoint, &[u8]), TpmDeviceError> {
1303 let (x, buf): (Tpm2bEccParameter, _) = parse_tpm2b_buffer(buf)?;
1304 let (y, rest): (Tpm2bEccParameter, _) = parse_tpm2b_buffer(buf)?;
1305
1306 Ok((TpmsEccPoint { x, y }, rest))
1307}
1308
1309fn parse_tpmu_public_id(
1310 object_type: TpmAlgId,
1311 buf: &[u8],
1312) -> Result<(TpmuPublicId, &[u8]), TpmDeviceError> {
1313 match object_type {
1314 TpmAlgId::KeyedHash => {
1315 let (value, rest): (Tpm2bDigest, _) = parse_tpm2b_buffer(buf)?;
1316 Ok((TpmuPublicId::KeyedHash(value), rest))
1317 }
1318 TpmAlgId::SymCipher => {
1319 let (value, rest): (Tpm2bSymKey, _) = parse_tpm2b_buffer(buf)?;
1320 Ok((TpmuPublicId::SymCipher(value), rest))
1321 }
1322 TpmAlgId::Rsa => {
1323 let (value, rest): (Tpm2bPublicKeyRsa, _) = parse_tpm2b_buffer(buf)?;
1324 Ok((TpmuPublicId::Rsa(value), rest))
1325 }
1326 TpmAlgId::Ecc => {
1327 let (value, rest) = parse_tpms_ecc_point(buf)?;
1328 Ok((TpmuPublicId::Ecc(value), rest))
1329 }
1330 TpmAlgId::Null => Ok((TpmuPublicId::Null, buf)),
1331 _ => Err(TpmDeviceError::InvalidResponse),
1332 }
1333}
1334
1335fn parse_tpmt_public(buf: &[u8]) -> Result<(TpmtPublic, &[u8]), TpmDeviceError> {
1336 let (object_type, buf) = parse_field_value::<TpmAlgId>(buf)?;
1337 let (name_alg, buf) = parse_field_value::<TpmAlgId>(buf)?;
1338 let (object_attributes, buf) = parse_field_value::<TpmaObject>(buf)?;
1339 let (auth_policy, buf): (Tpm2bDigest, _) = parse_tpm2b_buffer(buf)?;
1340 let (parameters, buf) = parse_tpmu_public_parms(object_type, buf)?;
1341 let (unique, rest) = parse_tpmu_public_id(object_type, buf)?;
1342
1343 Ok((
1344 TpmtPublic {
1345 object_type,
1346 name_alg,
1347 object_attributes,
1348 auth_policy,
1349 parameters,
1350 unique,
1351 },
1352 rest,
1353 ))
1354}
1355
1356fn parse_tpm2b_public(buf: &[u8]) -> Result<(TpmtPublic, &[u8]), TpmDeviceError> {
1357 let (size, buf) = parse_wire_copy::<TpmUint16>(buf)?;
1358 let size = usize::from(size.value());
1359 if buf.len() < size {
1360 return Err(TpmDeviceError::InvalidResponse);
1361 }
1362
1363 let (public, rest) = buf.split_at(size);
1364 let (public, public_rest) = parse_tpmt_public(public)?;
1365 ensure_empty(public_rest)?;
1366
1367 Ok((public, rest))
1368}
1369
1370fn parse_tpms_context(buf: &[u8]) -> Result<(TpmsContext, &[u8]), TpmDeviceError> {
1371 let (sequence, buf) = parse_wire_copy::<TpmUint64>(buf)?;
1372 let (saved_handle, buf) = parse_wire_copy::<TpmHandle>(buf)?;
1373 let (hierarchy, buf) = parse_field_value::<TpmRh>(buf)?;
1374 let (context_blob, rest): (TpmBuffer<TPM_MAX_COMMAND_SIZE>, _) = parse_tpm2b_buffer(buf)?;
1375
1376 Ok((
1377 TpmsContext {
1378 sequence,
1379 saved_handle,
1380 hierarchy,
1381 context_blob,
1382 },
1383 rest,
1384 ))
1385}
1386
1387fn parse_list<'a, T, const CAPACITY: usize>(
1388 buf: &'a [u8],
1389 mut parse_item: impl FnMut(&'a [u8]) -> Result<(T, &'a [u8]), TpmDeviceError>,
1390) -> Result<(TpmList<T, CAPACITY>, &'a [u8]), TpmDeviceError>
1391where
1392 T: Copy,
1393{
1394 let (count, mut cursor) = parse_wire_copy::<TpmUint32>(buf)?;
1395 let mut list = TpmList::<T, CAPACITY>::new();
1396
1397 for _ in 0..count.value() {
1398 let (item, rest) = parse_item(cursor)?;
1399 list.try_push(item).map_err(TpmDeviceError::Unmarshal)?;
1400 cursor = rest;
1401 }
1402
1403 Ok((list, cursor))
1404}
1405
1406fn parse_tpms_alg_property(buf: &[u8]) -> Result<(TpmsAlgProperty, &[u8]), TpmDeviceError> {
1407 let (alg, buf) = parse_field_value::<TpmAlgId>(buf)?;
1408 let (alg_properties, rest) = parse_field_value::<TpmaAlgorithm>(buf)?;
1409
1410 Ok((
1411 TpmsAlgProperty {
1412 alg,
1413 alg_properties,
1414 },
1415 rest,
1416 ))
1417}
1418
1419fn parse_tpms_tagged_property(buf: &[u8]) -> Result<(TpmsTaggedProperty, &[u8]), TpmDeviceError> {
1420 let (property, buf) = parse_field_value::<TpmPt>(buf)?;
1421 let (value, rest) = parse_wire_copy::<TpmUint32>(buf)?;
1422
1423 Ok((TpmsTaggedProperty { property, value }, rest))
1424}
1425
1426fn parse_tpms_pcr_selection(buf: &[u8]) -> Result<(TpmsPcrSelection, &[u8]), TpmDeviceError> {
1427 let (hash, buf) = parse_field_value::<TpmAlgId>(buf)?;
1428 let (pcr_select, rest) =
1429 <TpmsPcrSelect as TpmField>::cast_prefix_field(buf).map_err(TpmDeviceError::Unmarshal)?;
1430 let pcr_select = TpmsPcrSelect::try_from(pcr_select).map_err(TpmDeviceError::Unmarshal)?;
1431
1432 Ok((TpmsPcrSelection { hash, pcr_select }, rest))
1433}
1434
1435fn parse_capability_data(buf: &[u8]) -> Result<(TpmsCapabilityData, &[u8]), TpmDeviceError> {
1436 let (capability, buf) = parse_field_value::<TpmCap>(buf)?;
1437 let (data, rest) = match capability {
1438 TpmCap::Algs => {
1439 let (list, rest) = parse_list::<TpmsAlgProperty, 64>(buf, parse_tpms_alg_property)?;
1440 (TpmuCapabilities::Algs(list), rest)
1441 }
1442 TpmCap::Handles => {
1443 let (list, rest) = parse_list::<TpmHandle, 128>(buf, parse_wire_copy::<TpmHandle>)?;
1444 (TpmuCapabilities::Handles(list), rest)
1445 }
1446 TpmCap::Pcrs => {
1447 let (list, rest) = parse_list::<TpmsPcrSelection, 8>(buf, parse_tpms_pcr_selection)?;
1448 (TpmuCapabilities::Pcrs(list), rest)
1449 }
1450 TpmCap::Commands => {
1451 let (list, rest) = parse_list::<TpmaCc, 256>(buf, parse_field_value::<TpmaCc>)?;
1452 (TpmuCapabilities::Commands(list), rest)
1453 }
1454 TpmCap::TpmProperties => {
1455 let (list, rest) =
1456 parse_list::<TpmsTaggedProperty, 64>(buf, parse_tpms_tagged_property)?;
1457 (TpmuCapabilities::TpmProperties(list), rest)
1458 }
1459 TpmCap::EccCurves => {
1460 let (list, rest) =
1461 parse_list::<TpmEccCurve, 64>(buf, parse_field_value::<TpmEccCurve>)?;
1462 (TpmuCapabilities::EccCurves(list), rest)
1463 }
1464 TpmCap::PpCommands | TpmCap::AuditCommands | TpmCap::AuthPolicies | TpmCap::Act => {
1465 return Err(TpmDeviceError::InvalidResponse);
1466 }
1467 _ => return Err(TpmDeviceError::InvalidResponse),
1468 };
1469
1470 Ok((TpmsCapabilityData { capability, data }, rest))
1471}
1472
1473pub struct TpmPolicySessionBuilder {
1475 bind: TpmHandle,
1476 tpm_key: TpmHandle,
1477 nonce_caller: Option<Tpm2bNonce>,
1478 encrypted_salt: Option<Tpm2bEncryptedSecret>,
1479 session_type: TpmSe,
1480 symmetric: TpmtSymDefObject,
1481 auth_hash: TpmAlgId,
1482}
1483
1484impl Default for TpmPolicySessionBuilder {
1485 fn default() -> Self {
1486 Self {
1487 bind: (TpmRh::Null as u32).into(),
1488 tpm_key: (TpmRh::Null as u32).into(),
1489 nonce_caller: None,
1490 encrypted_salt: None,
1491 session_type: TpmSe::Policy,
1492 symmetric: TpmtSymDefObject::default(),
1493 auth_hash: TpmAlgId::Sha256,
1494 }
1495 }
1496}
1497
1498impl TpmPolicySessionBuilder {
1499 #[must_use]
1500 pub fn new() -> Self {
1501 Self::default()
1502 }
1503
1504 #[must_use]
1505 pub fn with_bind(mut self, bind: TpmHandle) -> Self {
1506 self.bind = bind;
1507 self
1508 }
1509
1510 #[must_use]
1511 pub fn with_tpm_key(mut self, tpm_key: TpmHandle) -> Self {
1512 self.tpm_key = tpm_key;
1513 self
1514 }
1515
1516 #[must_use]
1517 pub fn with_nonce_caller(mut self, nonce: Tpm2bNonce) -> Self {
1518 self.nonce_caller = Some(nonce);
1519 self
1520 }
1521
1522 #[must_use]
1523 pub fn with_encrypted_salt(mut self, salt: Tpm2bEncryptedSecret) -> Self {
1524 self.encrypted_salt = Some(salt);
1525 self
1526 }
1527
1528 #[must_use]
1529 pub fn with_session_type(mut self, session_type: TpmSe) -> Self {
1530 self.session_type = session_type;
1531 self
1532 }
1533
1534 #[must_use]
1535 pub fn with_symmetric(mut self, symmetric: TpmtSymDefObject) -> Self {
1536 self.symmetric = symmetric;
1537 self
1538 }
1539
1540 #[must_use]
1541 pub fn with_auth_hash(mut self, auth_hash: TpmAlgId) -> Self {
1542 self.auth_hash = auth_hash;
1543 self
1544 }
1545
1546 pub fn open(self, device: &mut TpmDevice) -> Result<TpmPolicySession, TpmDeviceError> {
1557 let nonce_caller = if let Some(nonce) = self.nonce_caller {
1558 nonce
1559 } else {
1560 let digest_len = TpmHash::try_from(self.auth_hash)
1561 .map_err(|_| TpmDeviceError::UnsupportedAlgorithm(self.auth_hash))?
1562 .size();
1563 let mut nonce_bytes = vec![0; digest_len];
1564 thread_rng().fill_bytes(&mut nonce_bytes);
1565 Tpm2bNonce::try_from(nonce_bytes.as_slice()).map_err(TpmDeviceError::Unmarshal)?
1566 };
1567
1568 let cmd = TpmStartAuthSessionCommand {
1569 nonce_caller,
1570 encrypted_salt: self.encrypted_salt.unwrap_or_default(),
1571 session_type: self.session_type,
1572 symmetric: self.symmetric,
1573 auth_hash: self.auth_hash,
1574 handles: [self.tpm_key, self.bind],
1575 };
1576
1577 let response = device.transmit(&cmd, TpmDevice::NO_SESSIONS)?;
1578 let (handles, parameters) = response_parts(response, 1)?;
1579 let (handle, rest) = parse_wire_copy::<TpmHandle>(handles)?;
1580 ensure_empty(rest)?;
1581 let (nonce_tpm, rest): (Tpm2bNonce, _) = parse_tpm2b_buffer(parameters)?;
1582 ensure_empty(rest)?;
1583
1584 Ok(TpmPolicySession {
1585 handle,
1586 attributes: TpmaSession::CONTINUE_SESSION,
1587 hash_alg: self.auth_hash,
1588 nonce_tpm,
1589 })
1590 }
1591}
1592
1593#[derive(Debug, Clone)]
1595pub struct TpmPolicySession {
1596 handle: TpmHandle,
1597 attributes: TpmaSession,
1598 hash_alg: TpmAlgId,
1599 nonce_tpm: Tpm2bNonce,
1600}
1601
1602impl TpmPolicySession {
1603 #[must_use]
1605 pub fn builder() -> TpmPolicySessionBuilder {
1606 TpmPolicySessionBuilder::new()
1607 }
1608
1609 #[must_use]
1611 pub fn handle(&self) -> TpmHandle {
1612 self.handle
1613 }
1614
1615 #[must_use]
1617 pub fn attributes(&self) -> TpmaSession {
1618 self.attributes
1619 }
1620
1621 #[must_use]
1623 pub fn hash_alg(&self) -> TpmAlgId {
1624 self.hash_alg
1625 }
1626
1627 #[must_use]
1629 pub fn nonce_tpm(&self) -> &Tpm2bNonce {
1630 &self.nonce_tpm
1631 }
1632
1633 pub fn run(
1646 &self,
1647 device: &mut TpmDevice,
1648 commands: impl IntoIterator<Item = (TpmCommand, TpmAuthCommands)>,
1649 ) -> Result<(), TpmDeviceError> {
1650 for (mut command_body, auth_sessions) in commands {
1651 match &mut command_body {
1652 TpmCommand::PolicyPcr(cmd) => cmd.handles[0] = self.handle,
1653 TpmCommand::PolicyOr(cmd) => cmd.handles[0] = self.handle,
1654 TpmCommand::PolicyRestart(cmd) => {
1655 cmd.handles[0] = self.handle;
1656 }
1657 TpmCommand::PolicySecret(cmd) => {
1658 cmd.handles[1] = self.handle;
1659 }
1660 _ => {
1661 return Err(TpmDeviceError::InvalidCc(command_body.cc()));
1662 }
1663 }
1664 device.transmit(&command_body, auth_sessions.as_ref())?;
1665 }
1666 Ok(())
1667 }
1668
1669 pub fn flush(&self, device: &mut TpmDevice) -> Result<(), TpmDeviceError> {
1676 device.flush_context(self.handle)
1677 }
1678}
1679
1680#[cfg(test)]
1681mod tests {
1682 use super::*;
1683 use std::cell::RefCell;
1684 use std::io::Cursor;
1685 use std::rc::Rc;
1686
1687 struct Duplex {
1688 input: Cursor<Vec<u8>>,
1689 output: Rc<RefCell<Vec<u8>>>,
1690 }
1691
1692 impl Read for Duplex {
1693 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
1694 self.input.read(buf)
1695 }
1696 }
1697
1698 impl Write for Duplex {
1699 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
1700 self.output.borrow_mut().extend_from_slice(buf);
1701 Ok(buf.len())
1702 }
1703
1704 fn flush(&mut self) -> std::io::Result<()> {
1705 Ok(())
1706 }
1707 }
1708
1709 fn frame(body: &[u8]) -> Vec<u8> {
1710 let size = u32::try_from(TPM_HEADER_SIZE + body.len()).unwrap();
1711 let mut frame = vec![0x80, 0x01];
1712 frame.extend_from_slice(&size.to_be_bytes());
1713 frame.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]);
1714 frame.extend_from_slice(body);
1715 frame
1716 }
1717
1718 #[test]
1719 fn read_frame_reads_exactly_one_frame() {
1720 let first = frame(&[0xAA, 0xBB]);
1721 let mut bytes = first.clone();
1722 bytes.extend_from_slice(&frame(&[0xCC]));
1723 let mut reader = Cursor::new(bytes);
1724
1725 let mut buf = Vec::new();
1726 read_frame(&mut reader, &mut buf).unwrap();
1727
1728 assert_eq!(buf, first);
1729 }
1730
1731 #[test]
1732 fn write_then_read_round_trips() {
1733 let expected = frame(&[1, 2, 3, 4]);
1734 let mut stream = Cursor::new(Vec::new());
1735 write_frame(&mut stream, &expected).unwrap();
1736 stream.set_position(0);
1737
1738 let mut buf = Vec::new();
1739 read_frame(&mut stream, &mut buf).unwrap();
1740
1741 assert_eq!(buf, expected);
1742 }
1743
1744 #[test]
1745 fn stream_transport_sends_and_receives() {
1746 let response = frame(&[0x11, 0x22]);
1747 let command = frame(&[0x33]);
1748 let output = Rc::new(RefCell::new(Vec::new()));
1749 let mut transport = TpmStreamTransport::new(Duplex {
1750 input: Cursor::new(response.clone()),
1751 output: Rc::clone(&output),
1752 });
1753
1754 transport.send(&command).unwrap();
1755 let mut buf = Vec::new();
1756 transport.recv(&mut buf).unwrap();
1757
1758 assert_eq!(buf, response);
1759 assert_eq!(*output.borrow(), command);
1760 }
1761
1762 #[test]
1763 fn responder_serves_commands_until_disconnect() {
1764 let command = frame(&[0x01]);
1765 let response = frame(&[0x02, 0x03]);
1766 let output = Rc::new(RefCell::new(Vec::new()));
1767 let transport = TpmStreamTransport::new(Duplex {
1768 input: Cursor::new(command.clone()),
1769 output: Rc::clone(&output),
1770 });
1771 let mut responder = TpmResponder::new(Box::new(transport));
1772
1773 let reply = response.clone();
1774 let mut served = 0;
1775 responder
1776 .serve(|cmd| {
1777 assert_eq!(cmd, command.as_slice());
1778 served += 1;
1779 reply.clone()
1780 })
1781 .unwrap();
1782
1783 assert_eq!(served, 1);
1784 assert_eq!(*output.borrow(), response);
1785 }
1786
1787 #[test]
1788 fn frame_size_rejects_short_header() {
1789 assert!(frame_size(&[0x80, 0x01, 0x00]).is_err());
1790 }
1791
1792 #[test]
1793 fn read_frame_reports_unexpected_eof_on_truncation() {
1794 let mut reader = Cursor::new(vec![0x80, 0x01]);
1795 let mut buf = Vec::new();
1796 assert_eq!(
1797 read_frame(&mut reader, &mut buf),
1798 Err(TpmDeviceError::UnexpectedEof)
1799 );
1800 }
1801}