1use borsh::{BorshDeserialize, BorshSerialize};
7use serde::{Deserialize, Serialize};
8
9pub use crate::crypto::{PublicKey, TeeUserData, TEE_USER_DATA_SIZE, X25519_KEY_SIZE};
11
12#[derive(
14 Clone, Default, Eq, PartialEq, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
15)]
16pub struct AttestationEvidence {
17 pub tee_type: TeeType,
18 pub evidence_data: Vec<u8>,
19}
20
21impl std::fmt::Debug for AttestationEvidence {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 let truncated_data = if self.evidence_data.len() <= 16 {
24 format!("{:?}", self.evidence_data)
25 } else {
26 format!(
27 "{:?}... (truncated, total: {} bytes)",
28 &self.evidence_data[..16],
29 self.evidence_data.len()
30 )
31 };
32
33 f.debug_struct("AttestationEvidence")
34 .field("tee_type", &self.tee_type)
35 .field("evidence_data", &truncated_data)
36 .finish()
37 }
38}
39
40#[derive(
43 Clone,
44 Copy,
45 Debug,
46 Default,
47 Eq,
48 Hash,
49 PartialEq,
50 Serialize,
51 Deserialize,
52 BorshSerialize,
53 BorshDeserialize,
54)]
55#[borsh(use_discriminant = true)]
56#[non_exhaustive]
57pub enum TeeType {
58 SevSnp = 1,
59 #[default]
60 AwsSevSnp = 2,
61 AzureSevSnp = 3,
62 IntelTdx = 4,
63 #[cfg(feature = "testing")]
64 Mock = 254,
65}
66
67impl std::fmt::Display for TeeType {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 match self {
70 TeeType::AzureSevSnp => write!(f, "Azure SEV-SNP"),
71 TeeType::AwsSevSnp => write!(f, "AWS SEV-SNP EC2 with NitroTPM"),
72 TeeType::SevSnp => write!(f, "Generic SEV-SNP"),
73 TeeType::IntelTdx => write!(f, "Intel TDX"),
74 #[cfg(feature = "testing")]
77 TeeType::Mock => write!(f, "Mock TEE"),
78 }
79 }
80}
81
82#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
87pub struct SevSnpEvidenceData {
88 pub report: Vec<u8>,
90 pub vek_certificate: Vec<u8>,
92}
93
94#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
99pub struct AzureSevSnpEvidenceData {
100 pub snp_evidence: SevSnpEvidenceData,
102}
103
104#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
110pub struct AwsNitroCoseEvidence {
111 pub report: Vec<u8>,
117 pub nonce: Vec<u8>,
122 pub time: u64,
127}
128
129#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
136pub struct AwsSevSnpEvidenceData {
137 pub snp_evidence: SevSnpEvidenceData,
139 pub aws_nitro_cose_evidence: AwsNitroCoseEvidence,
141}
142
143#[derive(Debug, thiserror::Error)]
145pub enum TeeEvidenceError {
146 #[error("Invalid evidence: {0}")]
147 InvalidEvidence(String),
148}
149
150impl TryFrom<&AttestationEvidence> for SevSnpEvidenceData {
151 type Error = TeeEvidenceError;
152 fn try_from(evidence: &AttestationEvidence) -> Result<Self, Self::Error> {
153 parse_evidence(evidence, &[TeeType::SevSnp])
154 }
155}
156
157impl TryFrom<&AttestationEvidence> for AwsSevSnpEvidenceData {
158 type Error = TeeEvidenceError;
159 fn try_from(evidence: &AttestationEvidence) -> Result<Self, Self::Error> {
160 parse_evidence(evidence, &[TeeType::AwsSevSnp])
161 }
162}
163
164impl TryFrom<&AttestationEvidence> for AzureSevSnpEvidenceData {
165 type Error = TeeEvidenceError;
166 fn try_from(evidence: &AttestationEvidence) -> Result<Self, Self::Error> {
167 parse_evidence(evidence, &[TeeType::AzureSevSnp])
168 }
169}
170
171pub fn parse_evidence<T>(
177 evidence: &AttestationEvidence,
178 expected_tee_types: &[TeeType],
179) -> Result<T, TeeEvidenceError>
180where
181 T: for<'de> Deserialize<'de>,
182{
183 if !expected_tee_types.contains(&evidence.tee_type) {
185 return Err(TeeEvidenceError::InvalidEvidence(format!(
186 "Expected TEE types {:?}, got {:?}",
187 expected_tee_types, evidence.tee_type
188 )));
189 }
190
191 serde_json::from_slice(&evidence.evidence_data)
193 .map_err(|e| TeeEvidenceError::InvalidEvidence(format!("Failed to parse evidence: {e}")))
194}