rialo_types/tee_types.rs
1// Copyright (c) Subzero Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Core TEE types used in REX attestation
5
6use borsh::{BorshDeserialize, BorshSerialize};
7pub use rialo_tee_types::TeeType;
8use serde::{Deserialize, Serialize};
9
10// Re-export crypto types for backward compatibility
11pub use crate::crypto::{PublicKey, TeeUserData, TEE_USER_DATA_SIZE, X25519_KEY_SIZE};
12
13/// TEE platform attestation evidence
14#[derive(
15 Clone, Default, Eq, PartialEq, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
16)]
17pub struct AttestationEvidence {
18 pub tee_type: TeeType,
19 pub evidence_data: Vec<u8>,
20}
21
22impl std::fmt::Debug for AttestationEvidence {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 let truncated_data = if self.evidence_data.len() <= 16 {
25 format!("{:?}", self.evidence_data)
26 } else {
27 format!(
28 "{:?}... (truncated, total: {} bytes)",
29 &self.evidence_data[..16],
30 self.evidence_data.len()
31 )
32 };
33
34 f.debug_struct("AttestationEvidence")
35 .field("tee_type", &self.tee_type)
36 .field("evidence_data", &truncated_data)
37 .finish()
38 }
39}
40
41/// SEV-SNP specific evidence data structure
42///
43/// This structure contains the raw SEV-SNP attestation data that gets
44/// serialized/deserialized from the `evidence_data` field of `AttestationEvidence`.
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
46pub struct SevSnpEvidenceData {
47 /// The raw SEV-SNP attestation report
48 pub report: Vec<u8>,
49 /// the VLEK or VCEK certificate
50 pub vek_certificate: Vec<u8>,
51}
52
53/// Azure Confidential VM vTPM Evidence structure used for attestation verification
54///
55/// The vTPM-AK quote is the analogue of AWS Nitro's COSE-signed attestation document:
56/// it carries PCR values from the Azure CVM's vTPM and a signature by the Attestation Key
57/// (AK) over those PCRs together with a caller-supplied nonce.
58///
59/// Trust binding chain on Azure CVMs:
60/// `user_data` (nonce) → (TPM AK signature) → AK pub → (`SHA256(RuntimeData)` in
61/// `snp.report_data[..32]`) → SNP report → (AMD chain) → AMD root.
62#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
63pub struct AzureSnpVtpmEvidence {
64 /// Serialized `az_snp_vtpm::vtpm::Quote` (bincode-encoded).
65 ///
66 /// Contains the TPM2B_ATTEST blob, the AK signature over it, and the bundled PCR
67 /// digests whose hash matches the quote's `pcrDigest`.
68 pub quote: Vec<u8>,
69 /// Caller-supplied data bound to the quote as its nonce.
70 ///
71 /// On verification, the quote's recovered nonce must equal this value.
72 pub nonce: Vec<u8>,
73}
74
75/// HCL-wrapped SEV-SNP attestation report + VCEK certificate, as produced by Azure
76/// Confidential VMs.
77///
78/// Distinct from [`SevSnpEvidenceData`] (which carries a raw 1184-byte AMD
79/// `AttestationReport` + VLEK) — Azure's `report` is the `az_cvm_vtpm::hcl::HclReport`
80/// wire form and the certificate is a VCEK fetched from AMD KDS, not a VLEK.
81///
82/// HCL wire layout (frozen at `az-cvm-vtpm = 0.7.4`):
83///
84/// ```text
85/// [ 0 .. 32] AttestationHeader (8 × u32)
86/// [ 32 .. 1216] hardware SNP report (MAX_REPORT_SIZE)
87/// [1216 .. 1236] IgvmRequestData fixed part (5 × u32)
88/// [1236 .. ] RuntimeData (JSON, embeds vTPM AK pub)
89/// ```
90///
91/// The verifier parses the HCL wrapper to recover the raw SNP report and the AK pub.
92#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
93pub struct AzureSnpHclEvidence {
94 /// HCL-wrapped SEV-SNP attestation report bytes (NOT a raw `AttestationReport`).
95 pub report: Vec<u8>,
96 /// VCEK certificate (DER), fetched from AMD KDS via `amd_kds::get_vcek`.
97 pub vek_certificate: Vec<u8>,
98}
99
100/// Azure SEV-SNP specific evidence data structure
101///
102/// On Azure Confidential VMs the SNP report's `report_data` is set by the HCL layer to
103/// `SHA256(RuntimeData)`, where `RuntimeData` embeds the vTPM AK public key. User data is
104/// therefore bound through the AK and the vTPM quote (see `AzureSnpVtpmEvidence`).
105#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
106pub struct AzureSevSnpEvidenceData {
107 /// HCL-wrapped SEV-SNP attestation report + VCEK certificate fetched from AMD KDS.
108 pub snp_evidence: AzureSnpHclEvidence,
109 /// vTPM AK quote binding `user_data` (as nonce) and the platform PCR values.
110 pub vtpm_evidence: AzureSnpVtpmEvidence,
111}
112
113/// AWS Nitro TPM COSE Evidence structure used for attestation verification
114///
115/// This structure contains the AWS Nitro TPM attestation data in COSE format along with
116/// supporting metadata required for verification. The COSE report includes TPM-based
117/// measurements and signatures that prove the identity and state of the AWS Nitro enclave.
118#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
119pub struct AwsNitroCoseEvidence {
120 /// AWS COSE signed report containing TPM attestation data
121 ///
122 /// This report includes Platform Configuration Registers (PCRs)
123 /// and digital signatures required to verify the authenticity and integrity of
124 /// the enclave.
125 pub report: Vec<u8>,
126 /// Cryptographic nonce value used to prevent replay attacks
127 ///
128 /// This nonce is included in the attestation request and must match
129 /// the value embedded in the COSE report to ensure freshness.
130 pub nonce: Vec<u8>,
131 /// Unix timestamp (in seconds) when the COSE report was generated
132 ///
133 /// Used to verify the attestation report's recency and detect
134 /// potential replay attacks.
135 pub time: u64,
136}
137
138/// AWS SEV-SNP specific evidence data structure optimized for AWS Nitro
139///
140/// This simplified structure leverages AWS Nitro's built-in attestation capabilities
141/// and prepares for future AWS COSE signed reports that will include all TPM data.
142/// The user_data contains the REX digest (32 bytes) that gets embedded in both
143/// the SEV-SNP report and the AWS COSE report for binding.
144#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
145pub struct AwsSevSnpEvidenceData {
146 /// SEV-SNP attestation report containing user_data
147 pub snp_evidence: SevSnpEvidenceData,
148 /// AWS Nitro COSE attestation report
149 pub aws_nitro_cose_evidence: AwsNitroCoseEvidence,
150}
151
152/// Error type for TEE evidence parsing
153#[derive(Debug, thiserror::Error)]
154pub enum TeeEvidenceError {
155 #[error("Invalid evidence: {0}")]
156 InvalidEvidence(String),
157}
158
159impl TryFrom<&AttestationEvidence> for SevSnpEvidenceData {
160 type Error = TeeEvidenceError;
161 fn try_from(evidence: &AttestationEvidence) -> Result<Self, Self::Error> {
162 parse_evidence(evidence, &[TeeType::SevSnp])
163 }
164}
165
166impl TryFrom<&AttestationEvidence> for AwsSevSnpEvidenceData {
167 type Error = TeeEvidenceError;
168 fn try_from(evidence: &AttestationEvidence) -> Result<Self, Self::Error> {
169 parse_evidence(evidence, &[TeeType::AwsSevSnp])
170 }
171}
172
173impl TryFrom<&AttestationEvidence> for AzureSevSnpEvidenceData {
174 type Error = TeeEvidenceError;
175 fn try_from(evidence: &AttestationEvidence) -> Result<Self, Self::Error> {
176 parse_evidence(evidence, &[TeeType::AzureSevSnp])
177 }
178}
179
180/// Generic evidence parsing function that validates TEE type and deserializes evidence data
181///
182/// This function provides a unified way to parse evidence data across different TEE types,
183/// validating that the evidence matches one of the expected TEE types before attempting
184/// to deserialize the data into the target type.
185pub fn parse_evidence<T>(
186 evidence: &AttestationEvidence,
187 expected_tee_types: &[TeeType],
188) -> Result<T, TeeEvidenceError>
189where
190 T: for<'de> Deserialize<'de>,
191{
192 // Validate TEE type
193 if !expected_tee_types.contains(&evidence.tee_type) {
194 return Err(TeeEvidenceError::InvalidEvidence(format!(
195 "Expected TEE types {:?}, got {:?}",
196 expected_tee_types, evidence.tee_type
197 )));
198 }
199
200 // Parse evidence data
201 serde_json::from_slice(&evidence.evidence_data)
202 .map_err(|e| TeeEvidenceError::InvalidEvidence(format!("Failed to parse evidence: {e}")))
203}