key_vault/fetcher/tpm.rs
1//! [`TpmFetch`] — TPM 2.0 [`KeyFetch`] backend (**detection-only in 1.0**).
2//!
3//! 1.0 ships TPM **detection** via
4//! [`detect_tee_capabilities`](crate::tee::detect_tee_capabilities) — the
5//! CPUID-based probe will tell you whether a TPM-equipped TEE is present
6//! on the host. Full TPM **acquisition** (talking to the TPM, unsealing
7//! keys, attestation) is on the 1.x roadmap and requires deep integration
8//! with `tss-esapi` or equivalent.
9//!
10//! Calling [`TpmFetch::fetch`] in 1.0 always returns
11//! [`Error::Acquisition`](crate::Error::Acquisition) with a documented
12//! message so consumers can fall through to another fetcher in a
13//! composite arrangement without a panic.
14//!
15//! # When this exists despite returning errors
16//!
17//! Code that wants to declare its intended fetcher hierarchy at
18//! configuration time — e.g. "prefer TPM, then keychain, then file" —
19//! can wire `TpmFetch` into its chain and inherit the 1.x upgrade
20//! automatically when full integration ships.
21
22use alloc::borrow::Cow;
23use alloc::string::ToString;
24
25use super::{FetchContext, KeyFetch, RawKey};
26use crate::Result;
27use crate::error::Error;
28
29/// Detection-only TPM 2.0 fetcher.
30///
31/// Always returns
32/// [`Error::Acquisition`](crate::Error::Acquisition) in 1.0. Use the TEE
33/// detection probe ([`detect_tee_capabilities`](crate::tee::detect_tee_capabilities))
34/// to check whether a TPM is present at all.
35///
36/// # Examples
37///
38/// ```
39/// use key_vault::{FetchContext, KeyFetch, TpmFetch};
40///
41/// let fetcher = TpmFetch;
42/// let err = fetcher.fetch(&FetchContext::new("k")).unwrap_err();
43/// // 1.0 ships detection only — full TPM integration is in the 1.x roadmap.
44/// assert!(format!("{err}").contains("TPM"));
45/// ```
46#[derive(Debug, Default, Clone, Copy)]
47pub struct TpmFetch;
48
49impl KeyFetch for TpmFetch {
50 fn fetch(&self, _ctx: &FetchContext) -> Result<RawKey> {
51 Err(Error::Acquisition {
52 source: Cow::Borrowed("tpm"),
53 reason:
54 "TPM 2.0 acquisition is detection-only in 1.0; full integration arrives in the \
55 1.x release line. Use detect_tee_capabilities() to probe for TPM presence."
56 .to_string(),
57 })
58 }
59
60 fn describe(&self) -> Cow<'_, str> {
61 Cow::Borrowed("tpm")
62 }
63}
64
65#[cfg(test)]
66#[allow(clippy::unwrap_used, clippy::expect_used)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn fetch_returns_detection_only_error() {
72 let err = TpmFetch.fetch(&FetchContext::new("k")).unwrap_err();
73 match err {
74 Error::Acquisition { source, reason } => {
75 assert_eq!(source, "tpm");
76 assert!(reason.contains("detection-only"));
77 }
78 other => panic!("expected Acquisition, got {other:?}"),
79 }
80 }
81
82 #[test]
83 fn describe_returns_tpm() {
84 assert_eq!(TpmFetch.describe(), "tpm");
85 }
86}