Skip to main content

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 oracle attestation
5
6use borsh::{BorshDeserialize, BorshSerialize};
7use serde::{Deserialize, Serialize};
8
9// Re-export crypto types for backward compatibility
10pub use crate::crypto::{PublicKey, TeeUserData, TEE_USER_DATA_SIZE, X25519_KEY_SIZE};
11
12/// TEE platform attestation evidence
13#[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// TODO: Decouple Cloud provider and TEE types
41// <https://linear.app/subzero-labs/issue/SUB-931/decouple-cloud-provider-from-tee-type-in-core-types>
42#[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            // This is a special TEE type used for testing purposes only.
75            // It should never be included in production.
76            #[cfg(feature = "testing")]
77            TeeType::Mock => write!(f, "Mock TEE"),
78        }
79    }
80}
81
82/// SEV-SNP specific evidence data structure
83///
84/// This structure contains the raw SEV-SNP attestation data that gets
85/// serialized/deserialized from the `evidence_data` field of `AttestationEvidence`.
86#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
87pub struct SevSnpEvidenceData {
88    /// The raw SEV-SNP attestation report
89    pub report: Vec<u8>,
90    /// the VLEK or VCEK certificate
91    pub vek_certificate: Vec<u8>,
92}
93
94/// Azure SEV-SNP specific evidence data structure
95///
96/// This structure contains the raw SEV-SNP attestation data that gets
97/// serialized/deserialized from the `evidence_data` field of `AttestationEvidence`.
98#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
99pub struct AzureSevSnpEvidenceData {
100    /// SEV-SNP attestation report containing user_data
101    pub snp_evidence: SevSnpEvidenceData,
102}
103
104/// AWS Nitro TPM COSE Evidence structure used for attestation verification
105///
106/// This structure contains the AWS Nitro TPM attestation data in COSE format along with
107/// supporting metadata required for verification. The COSE report includes TPM-based
108/// measurements and signatures that prove the identity and state of the AWS Nitro enclave.
109#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
110pub struct AwsNitroCoseEvidence {
111    /// AWS COSE signed report containing TPM attestation data
112    ///
113    /// This report includes Platform Configuration Registers (PCRs)
114    /// and digital signatures required to verify the authenticity and integrity of
115    /// the enclave.
116    pub report: Vec<u8>,
117    /// Cryptographic nonce value used to prevent replay attacks
118    ///
119    /// This nonce is included in the attestation request and must match
120    /// the value embedded in the COSE report to ensure freshness.
121    pub nonce: Vec<u8>,
122    /// Unix timestamp (in seconds) when the COSE report was generated
123    ///
124    /// Used to verify the attestation report's recency and detect
125    /// potential replay attacks.
126    pub time: u64,
127}
128
129/// AWS SEV-SNP specific evidence data structure optimized for AWS Nitro
130///
131/// This simplified structure leverages AWS Nitro's built-in attestation capabilities
132/// and prepares for future AWS COSE signed reports that will include all TPM data.
133/// The user_data contains the oracle digest (32 bytes) that gets embedded in both
134/// the SEV-SNP report and the AWS COSE report for binding.
135#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
136pub struct AwsSevSnpEvidenceData {
137    /// SEV-SNP attestation report containing user_data
138    pub snp_evidence: SevSnpEvidenceData,
139    /// AWS Nitro COSE attestation report
140    pub aws_nitro_cose_evidence: AwsNitroCoseEvidence,
141}
142
143/// Error type for TEE evidence parsing
144#[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
171/// Generic evidence parsing function that validates TEE type and deserializes evidence data
172///
173/// This function provides a unified way to parse evidence data across different TEE types,
174/// validating that the evidence matches one of the expected TEE types before attempting
175/// to deserialize the data into the target type.
176pub 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    // Validate TEE type
184    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    // Parse evidence data
192    serde_json::from_slice(&evidence.evidence_data)
193        .map_err(|e| TeeEvidenceError::InvalidEvidence(format!("Failed to parse evidence: {e}")))
194}