a3s_box_runtime/tee/
attestation.rs1use serde::{Deserialize, Serialize};
8
9pub const SNP_REPORT_SIZE: usize = 1184;
11
12pub const SNP_USER_DATA_SIZE: usize = 64;
14
15pub const SNP_MEASUREMENT_SIZE: usize = 48;
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct AttestationRequest {
25 pub nonce: Vec<u8>,
29
30 #[serde(default)]
33 pub user_data: Option<Vec<u8>>,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct AttestationReport {
42 pub report: Vec<u8>,
44
45 pub cert_chain: CertificateChain,
47
48 pub platform: PlatformInfo,
50}
51
52#[derive(Debug, Clone, Default, Serialize, Deserialize)]
56pub struct CertificateChain {
57 #[serde(default)]
60 pub vcek: Vec<u8>,
61
62 #[serde(default)]
65 pub ask: Vec<u8>,
66
67 #[serde(default)]
70 pub ark: Vec<u8>,
71}
72
73#[derive(Debug, Clone, Default, Serialize, Deserialize)]
75pub struct PlatformInfo {
76 pub version: u32,
78
79 pub guest_svn: u32,
81
82 pub policy: u64,
84
85 pub measurement: String,
88
89 pub tcb_version: TcbVersion,
91
92 pub chip_id: String,
94}
95
96#[derive(Debug, Clone, Default, Serialize, Deserialize)]
98pub struct TcbVersion {
99 pub boot_loader: u8,
101 pub tee: u8,
103 pub snp: u8,
105 pub microcode: u8,
107}
108
109pub fn parse_platform_info(report: &[u8]) -> Option<PlatformInfo> {
113 if report.len() < SNP_REPORT_SIZE {
114 return None;
115 }
116
117 let version = u32::from_le_bytes(report[0x00..0x04].try_into().ok()?);
118 let guest_svn = u32::from_le_bytes(report[0x04..0x08].try_into().ok()?);
119 let policy = u64::from_le_bytes(report[0x08..0x10].try_into().ok()?);
120
121 let measurement = hex::encode(&report[0x90..0xC0]);
123
124 let tcb = TcbVersion {
126 boot_loader: report[0x38],
127 tee: report[0x39],
128 snp: report[0x3E],
129 microcode: report[0x3F],
130 };
131
132 let chip_id = hex::encode(&report[0x1A0..0x1E0]);
134
135 Some(PlatformInfo {
136 version,
137 guest_svn,
138 policy,
139 measurement,
140 tcb_version: tcb,
141 chip_id,
142 })
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 #[test]
150 fn test_attestation_request_serialization() {
151 let req = AttestationRequest {
152 nonce: vec![1, 2, 3, 4],
153 user_data: Some(vec![5, 6, 7]),
154 };
155 let json = serde_json::to_string(&req).unwrap();
156 let parsed: AttestationRequest = serde_json::from_str(&json).unwrap();
157 assert_eq!(parsed.nonce, vec![1, 2, 3, 4]);
158 assert_eq!(parsed.user_data, Some(vec![5, 6, 7]));
159 }
160
161 #[test]
162 fn test_attestation_request_without_user_data() {
163 let json = r#"{"nonce":[1,2,3]}"#;
164 let req: AttestationRequest = serde_json::from_str(json).unwrap();
165 assert_eq!(req.nonce, vec![1, 2, 3]);
166 assert!(req.user_data.is_none());
167 }
168
169 #[test]
170 fn test_attestation_report_serialization() {
171 let report = AttestationReport {
172 report: vec![0u8; SNP_REPORT_SIZE],
173 cert_chain: CertificateChain::default(),
174 platform: PlatformInfo::default(),
175 };
176 let json = serde_json::to_string(&report).unwrap();
177 let parsed: AttestationReport = serde_json::from_str(&json).unwrap();
178 assert_eq!(parsed.report.len(), SNP_REPORT_SIZE);
179 }
180
181 #[test]
182 fn test_certificate_chain_default() {
183 let chain = CertificateChain::default();
184 assert!(chain.vcek.is_empty());
185 assert!(chain.ask.is_empty());
186 assert!(chain.ark.is_empty());
187 }
188
189 #[test]
190 fn test_tcb_version_default() {
191 let tcb = TcbVersion::default();
192 assert_eq!(tcb.boot_loader, 0);
193 assert_eq!(tcb.tee, 0);
194 assert_eq!(tcb.snp, 0);
195 assert_eq!(tcb.microcode, 0);
196 }
197
198 #[test]
199 fn test_parse_platform_info_valid_report() {
200 let mut report = vec![0u8; SNP_REPORT_SIZE];
201
202 report[0x00] = 2;
204 report[0x04] = 1;
206 report[0x08] = 0x30; report[0x38] = 3; report[0x39] = 0; report[0x3E] = 8; report[0x3F] = 115; report[0x90] = 0xAB;
215 report[0x91] = 0xCD;
216
217 let info = parse_platform_info(&report).unwrap();
218 assert_eq!(info.version, 2);
219 assert_eq!(info.guest_svn, 1);
220 assert_eq!(info.policy, 0x30);
221 assert_eq!(info.tcb_version.boot_loader, 3);
222 assert_eq!(info.tcb_version.snp, 8);
223 assert_eq!(info.tcb_version.microcode, 115);
224 assert!(info.measurement.starts_with("abcd"));
225 }
226
227 #[test]
228 fn test_parse_platform_info_too_short() {
229 let report = vec![0u8; 100]; assert!(parse_platform_info(&report).is_none());
231 }
232
233 #[test]
234 fn test_snp_constants() {
235 assert_eq!(SNP_REPORT_SIZE, 1184);
236 assert_eq!(SNP_USER_DATA_SIZE, 64);
237 assert_eq!(SNP_MEASUREMENT_SIZE, 48);
238 }
239}