ttk_server/attestation/
mod.rs1use crate::{AttestationParams, EatClaimsSet};
11use std::fmt;
12
13pub mod eat;
14
15#[cfg(any(feature = "nitro", feature = "mock"))]
16pub mod nitro_doc;
17
18#[cfg(feature = "nitro")]
19pub mod nitro;
20#[cfg(feature = "nitro")]
21pub use nitro::NsmSession;
22
23#[cfg(any(feature = "sev-snp", feature = "tdx"))]
24pub mod tsm;
25
26#[cfg(feature = "sev-snp")]
27pub mod sev_snp;
28
29#[cfg(feature = "tdx")]
30pub mod tdx;
31
32#[cfg(feature = "mock")]
33pub mod mock;
34#[cfg(feature = "mock")]
35pub use mock::MockSession;
36
37pub const PROVIDER_ENV: &str = "TTK_ATTESTATION";
39
40#[derive(Debug)]
42pub enum AttestationError {
43 DeviceOpenFailed(String),
45 Driver(String),
47 UnexpectedResponse(String),
49 InvalidInput(String),
51 DocumentDecodingFailed(String),
53 Unsupported(String),
55 NoProvider,
57 Io(std::io::Error),
59}
60
61impl fmt::Display for AttestationError {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 match self {
66 Self::DeviceOpenFailed(msg) => write!(f, "Failed to open TEE device: {msg}"),
67 Self::Driver(msg) => write!(f, "TEE driver returned an error: {msg}"),
68 Self::UnexpectedResponse(msg) => {
69 write!(f, "Unexpected response from TEE driver: {msg}")
70 }
71 Self::InvalidInput(msg) => write!(f, "Invalid attestation input: {msg}"),
72 Self::DocumentDecodingFailed(msg) => write!(f, "Document decoding failure: {msg}"),
73 Self::Unsupported(msg) => write!(f, "Unsupported attestation provider: {msg}"),
74 Self::NoProvider => write!(f, "No attestation provider matches this hardware"),
75 Self::Io(err) => write!(f, "I/O error: {err}"),
76 }
77 }
78}
79
80impl std::error::Error for AttestationError {}
82
83impl From<std::io::Error> for AttestationError {
85 fn from(err: std::io::Error) -> Self {
87 Self::Io(err)
88 }
89}
90
91pub trait AttestationProvider: Send + Sync {
93 fn name(&self) -> &'static str;
95
96 fn is_available() -> bool
98 where
99 Self: Sized;
100
101 fn generate_document(
103 &self,
104 params: &AttestationParams,
105 ) -> Result<EatClaimsSet, AttestationError>;
106}
107
108pub fn detect() -> Result<Box<dyn AttestationProvider>, AttestationError> {
113 if let Ok(name) = std::env::var(PROVIDER_ENV) {
114 return by_name(&name);
115 }
116
117 #[cfg(feature = "nitro")]
118 if nitro::NsmSession::is_available() {
119 return by_name("aws-nitro");
120 }
121 #[cfg(feature = "sev-snp")]
122 if sev_snp::SevSnpSession::is_available() {
123 return by_name("sev-snp");
124 }
125 #[cfg(feature = "tdx")]
126 if tdx::TdxSession::is_available() {
127 return by_name("tdx");
128 }
129
130 fallback()
131}
132
133#[cfg(feature = "mock")]
135fn fallback() -> Result<Box<dyn AttestationProvider>, AttestationError> {
136 log::warn!("No TEE hardware detected; using MOCK attestation. Evidence is NOT trustworthy.");
137 by_name("mock")
138}
139
140#[cfg(not(feature = "mock"))]
142fn fallback() -> Result<Box<dyn AttestationProvider>, AttestationError> {
143 Err(AttestationError::NoProvider)
144}
145
146pub fn by_name(name: &str) -> Result<Box<dyn AttestationProvider>, AttestationError> {
148 match name {
149 #[cfg(feature = "nitro")]
150 "aws-nitro" => Ok(Box::new(nitro::NsmSession::open()?)),
151 #[cfg(feature = "sev-snp")]
152 "sev-snp" => Ok(Box::new(sev_snp::SevSnpSession::open()?)),
153 #[cfg(feature = "tdx")]
154 "tdx" => Ok(Box::new(tdx::TdxSession::open()?)),
155 #[cfg(feature = "mock")]
156 "mock" => Ok(Box::new(mock::MockSession)),
157 other => Err(AttestationError::Unsupported(format!(
158 "'{other}' is unknown or not compiled into this build"
159 ))),
160 }
161}