tee_attestation_verifier/
lib.rs1use base64::{engine::general_purpose::STANDARD, Engine};
15use core::convert::TryInto;
16use p384::ecdsa::{Signature, VerifyingKey};
17use rsa::signature::Verifier;
18use rustls::{server::AllowAnyAuthenticatedClient, Certificate, RootCertStore};
19use std::collections::BTreeMap;
20use thiserror::Error;
21use tracing::info;
22
23use x509_cert::der::{Decode, Encode, Error};
24
25#[derive(Debug, Error)]
26pub enum VerificationError {
27 #[error("Invalid nonce")]
28 InvalidNonce,
29 #[error("Invalid PCR {0}")]
30 InvalidPCR(usize),
31 #[error("X509 certificate verification failed: {0}")]
32 X509CertVerificationFailed(String),
33 #[error("Signature verification failed: {0}")]
34 SignatureVerificationFailed(String),
35 #[error("Failed to decode trusted root: {0}")]
36 FailedToDecodeTrustedRoot(base64::DecodeError),
37 #[error("Payload length bytes conversion failed: {0}")]
38 PayloadLengthBytesConversionFailed(core::num::TryFromIntError),
39 #[error("Decode X509 certificate failed: {0}")]
40 DecodeX509CertFailed(String),
41 #[error("Public key DER failed: {0}")]
42 PublicKeyDerFailed(String),
43 #[error("Invalid public key: {0}")]
44 InvalidPublicKey(String),
45 #[error("Failed to add trusted root cert: {0}")]
46 FailedToAddTrustedRootCert(String),
47}
48
49#[derive(Debug, Error)]
50pub enum ParseError {
51 #[error("Parse document failed: {0}")]
52 ParseDocumentFailed(String),
53 #[error("Parse payload failed: {0}")]
54 ParsePayloadFailed(String),
55}
56
57#[derive(Debug, Error)]
58pub enum ParseVerificationError {
59 #[error("Parse error: {0}")]
60 ParseError(ParseError),
61 #[error("Verification error: {0}")]
62 VerificationError(VerificationError),
63}
64
65#[derive(Debug, Clone)]
66pub struct AttestationDocument {
67 pub protected: Vec<u8>,
68 pub signature: Vec<u8>,
69 pub payload: Vec<u8>,
70}
71
72const AWS_TRUSTED_ROOT_CERT: &str = "MIICETCCAZagAwIBAgIRAPkxdWgbkK/hHUbMtOTn+FYwCgYIKoZIzj0EAwMwSTELMAkGA1UEBhMCVVMxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMRswGQYDVQQDDBJhd3Mubml0cm8tZW5jbGF2ZXMwHhcNMTkxMDI4MTMyODA1WhcNNDkxMDI4MTQyODA1WjBJMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGQW1hem9uMQwwCgYDVQQLDANBV1MxGzAZBgNVBAMMEmF3cy5uaXRyby1lbmNsYXZlczB2MBAGByqGSM49AgEGBSuBBAAiA2IABPwCVOumCMHzaHDimtqQvkY4MpJzbolL//Zy2YlES1BR5TSksfbb48C8WBoyt7F2Bw7eEtaaP+ohG2bnUs990d0JX28TcPQXCEPZ3BABIeTPYwEoCWZEh8l5YoQwTcU/9KNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUkCW1DdkFR+eWw5b6cp3PmanfS5YwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYCMQCjfy+Rocm9Xue4YnwWmNJVA44fA0P5W2OpYow9OYCVRaEevL8uO1XYru5xtMPWrfMCMQCi85sWBbJwKKXdS6BptQFuZbT73o/gBh1qUxl/nNr12UO8Yfwr6wPLb+6NIwLz3/Y=";
73
74#[derive(Debug, Clone)]
75pub struct Payload {
76 pub module_id: String,
77 pub timestamp: u64,
78 pub public_key: Vec<u8>,
79 pub certificate: Vec<u8>,
80 pub cabundle: Vec<Vec<u8>>,
81 pub nonce: Vec<u8>,
82 pub user_data: Option<Vec<u8>>,
83 pub digest: String,
84 pub pcrs: Vec<Vec<u8>>,
85}
86
87fn verify_x509_cert(
88 trusted_root: Vec<u8>,
89 cabundle: Vec<Vec<u8>>,
90 certificate: Vec<u8>,
91 unix_time: u64,
92) -> Result<(), VerificationError> {
93 let mut certs: Vec<Certificate> = Vec::new();
94 for this_cert in cabundle.clone().iter().rev() {
95 let cert = Certificate(this_cert.to_vec());
96 certs.push(cert);
97 }
98 let cert = Certificate(certificate.clone());
99 certs.push(cert.clone());
100
101 let mut root_store = RootCertStore::empty();
102 root_store
103 .add(&Certificate(trusted_root.clone()))
104 .map_err(|err| VerificationError::FailedToAddTrustedRootCert(err.to_string()))?;
105
106 let verifier = AllowAnyAuthenticatedClient::new(root_store);
107
108 info!("verifying client cert");
109
110 let duration = std::time::Duration::from_secs(unix_time);
112 let datetime = std::time::UNIX_EPOCH + duration;
113 let _verified = match verifier.verify_client_cert(&cert, &certs, datetime) {
114 Ok(_) => true,
115 Err(err) => {
116 if err.to_string().contains("CertNotValidYet") {
117 return Ok(());
118 }
119 if err.to_string().contains("CertExpired") {
120 return Ok(());
121 }
122 return Err(VerificationError::X509CertVerificationFailed(
123 err.to_string(),
124 ));
125 }
126 };
127 Ok(())
128}
129
130fn verify_remote_attestation_signature(
131 protected: Vec<u8>,
132 signature: Vec<u8>,
133 certificate: Vec<u8>,
134 payload: Vec<u8>,
135) -> Result<(), VerificationError> {
136 let cert = x509_cert::Certificate::from_der(&certificate)
137 .map_err(|err| VerificationError::DecodeX509CertFailed(err.to_string()))?;
138
139 let public_key = cert
140 .tbs_certificate
141 .subject_public_key_info
142 .to_der()
143 .map_err(|err| VerificationError::PublicKeyDerFailed(err.to_string()))?;
144
145 let public_key = &public_key[public_key.len() - 97..];
146 let verifying_key = VerifyingKey::from_sec1_bytes(&public_key)
147 .map_err(|err| VerificationError::InvalidPublicKey(err.to_string()))?;
148
149 let signature = Signature::from_slice(&signature).expect("Invalid signature");
150
151 const HEADER: [u8; 13] = [132, 106, 83, 105, 103, 110, 97, 116, 117, 114, 101, 49, 68];
152
153 let payload_length_bytes: u8 = (payload.len() + 94 - 4446)
154 .try_into()
155 .map_err(|err| VerificationError::PayloadLengthBytesConversionFailed(err))?;
156
157 let filler: [u8; 4] = [64, 89, 17, payload_length_bytes];
158
159 let sign_structure = [
160 HEADER.as_ref(),
161 protected.as_ref(),
162 filler.as_ref(),
163 payload.as_ref(),
164 ]
165 .concat();
166
167 verifying_key
168 .verify(&sign_structure, &signature)
169 .map_err(|err| VerificationError::SignatureVerificationFailed(err.to_string()))?;
170 Ok(())
171}
172
173pub fn verify(
174 attestation_document: AttestationDocument,
175 payload: Payload,
176 nonce: Vec<u8>,
177 trusted_root: Option<Vec<u8>>,
178 unix_time: u64,
179) -> Result<(), VerificationError> {
180 if payload.nonce != nonce {
181 return Err(VerificationError::InvalidNonce);
182 }
183
184 let trusted_root = match trusted_root {
185 Some(root) => root,
186 None => STANDARD
187 .decode(AWS_TRUSTED_ROOT_CERT)
188 .map_err(|err| VerificationError::FailedToDecodeTrustedRoot(err))?,
189 };
190 verify_x509_cert(
191 trusted_root,
192 payload.cabundle,
193 payload.certificate.clone(),
194 unix_time,
195 )
196 .map_err(|err| VerificationError::X509CertVerificationFailed(err.to_string()))?;
197
198 verify_remote_attestation_signature(
199 attestation_document.protected,
200 attestation_document.signature,
201 payload.certificate,
202 attestation_document.payload,
203 )
204 .map_err(|err| VerificationError::SignatureVerificationFailed(err.to_string()))?;
205
206 Ok(())
207}
208
209pub fn parse_document(document_data: &Vec<u8>) -> Result<AttestationDocument, ParseError> {
210 let cbor: serde_cbor::Value = serde_cbor::from_slice(document_data)
211 .map_err(|err| ParseError::ParseDocumentFailed(err.to_string()))?;
212 let elements = match cbor {
213 serde_cbor::Value::Array(elements) => elements,
214 _ => panic!("AttestationVerifier::parse Unknown field cbor:{:?}", cbor),
215 };
216 let protected = match &elements[0] {
217 serde_cbor::Value::Bytes(prot) => prot,
218 _ => panic!(
219 "AttestationVerifier::parse Unknown field protected:{:?}",
220 elements[0]
221 ),
222 };
223 let _unprotected = match &elements[1] {
224 serde_cbor::Value::Map(unprot) => unprot,
225 _ => panic!(
226 "AttestationVerifier::parse Unknown field unprotected:{:?}",
227 elements[1]
228 ),
229 };
230 let payload = match &elements[2] {
231 serde_cbor::Value::Bytes(payld) => payld,
232 _ => panic!(
233 "AttestationVerifier::parse Unknown field payload:{:?}",
234 elements[2]
235 ),
236 };
237 let signature = match &elements[3] {
238 serde_cbor::Value::Bytes(sig) => sig,
239 _ => panic!(
240 "AttestationVerifier::parse Unknown field signature:{:?}",
241 elements[3]
242 ),
243 };
244 Ok(AttestationDocument {
245 protected: protected.to_vec(),
246 payload: payload.to_vec(),
247 signature: signature.to_vec(),
248 })
249}
250
251pub fn parse_payload(payload: &Vec<u8>) -> Result<Payload, ParseError> {
252 let document_data: serde_cbor::Value = serde_cbor::from_slice(payload.as_slice())
253 .map_err(|err| ParseError::ParsePayloadFailed(err.to_string()))?;
254 let document_map: BTreeMap<serde_cbor::Value, serde_cbor::Value> = match document_data {
255 serde_cbor::Value::Map(map) => map,
256 _ => {
257 return Err(ParseError::ParsePayloadFailed(format!(
258 "AttestationVerifier::parse_payload field ain't what it should be:{:?}",
259 document_data
260 )))
261 }
262 };
263 let module_id = match document_map.get(&serde_cbor::Value::Text(
264 "module_id".try_into().expect("module_id_fail"),
265 )) {
266 Some(serde_cbor::Value::Text(val)) => val.to_string(),
267 _ => {
268 return Err(ParseError::ParsePayloadFailed(format!(
269 "AttestationVerifier::parse_payload module_id is wrong type or not present"
270 )))
271 }
272 };
273 let timestamp: i128 = match document_map.get(&serde_cbor::Value::Text("timestamp".to_string()))
274 {
275 Some(serde_cbor::Value::Integer(val)) => *val,
276 _ => {
277 return Err(ParseError::ParsePayloadFailed(format!(
278 "AttestationVerifier::parse_payload timestamp is wrong type or not present"
279 )))
280 }
281 };
282 let timestamp: u64 = timestamp.try_into().map_err(|err| {
283 ParseError::ParsePayloadFailed(format!(
284 "AttestationVerifier::parse_payload failed to convert timestamp to u64:{:?}",
285 err
286 ))
287 })?;
288 let public_key: Vec<u8> =
289 match document_map.get(&serde_cbor::Value::Text("public_key".to_string())) {
290 Some(serde_cbor::Value::Bytes(val)) => val.to_vec(),
291 Some(_null) => vec![],
292 _ => {
293 return Err(ParseError::ParsePayloadFailed(format!(
294 "AttestationVerifier::parse_payload public_key is wrong type or not present"
295 )))
296 }
297 };
298 let certificate: Vec<u8> =
299 match document_map.get(&serde_cbor::Value::Text("certificate".to_string())) {
300 Some(serde_cbor::Value::Bytes(val)) => val.to_vec(),
301 _ => {
302 return Err(ParseError::ParsePayloadFailed(format!(
303 "AttestationVerifier::parse_payload certificate is wrong type or not present"
304 )))
305 }
306 };
307 let pcrs: Vec<Vec<u8>> = match document_map.get(&serde_cbor::Value::Text("pcrs".to_string())) {
308 Some(serde_cbor::Value::Map(map)) => {
309 let mut ret_vec: Vec<Vec<u8>> = Vec::new();
310 let num_entries: i128 = map.len().try_into().map_err(|err| {
311 ParseError::ParsePayloadFailed(format!(
312 "AttestationVerifier::parse_payload failed to convert pcrs len into i128:{:?}",
313 err
314 ))
315 })?;
316 for x in 0..num_entries {
317 match map.get(&serde_cbor::Value::Integer(x)) {
318 Some(serde_cbor::Value::Bytes(inner_vec)) => {
319 ret_vec.push(inner_vec.to_vec());
320 }
321 _ => {
322 }
327 }
328 }
329 ret_vec
330 }
331 _ => {
332 return Err(ParseError::ParsePayloadFailed(format!(
333 "AttestationVerifier::parse_payload pcrs is wrong type or not present"
334 )))
335 }
336 };
337
338 let nonce = vec![0; 20];
348
349 let user_data: Option<Vec<u8>> =
350 match document_map.get(&serde_cbor::Value::Text("user_data".to_string())) {
351 Some(serde_cbor::Value::Bytes(val)) => Some(val.to_vec()),
352 None => None,
353 Some(_null) => None,
354 };
355 let digest: String = match document_map.get(&serde_cbor::Value::Text("digest".to_string())) {
356 Some(serde_cbor::Value::Text(val)) => val.to_string(),
357 _ => {
358 return Err(ParseError::ParsePayloadFailed(format!(
359 "AttestationVerifier::parse_payload digest is wrong type or not present"
360 )))
361 }
362 };
363 let cabundle: Vec<Vec<u8>> =
364 match document_map.get(&serde_cbor::Value::Text("cabundle".to_string())) {
365 Some(serde_cbor::Value::Array(outer_vec)) => {
366 let mut ret_vec: Vec<Vec<u8>> = Vec::new();
367 for this_vec in outer_vec.iter() {
368 match this_vec {
369 serde_cbor::Value::Bytes(inner_vec) => {
370 ret_vec.push(inner_vec.to_vec());
371 }
372 _ => {
373 return Err(ParseError::ParsePayloadFailed(format!(
374 "AttestationVerifier::parse_payload inner_vec is wrong type"
375 )))
376 }
377 }
378 }
379 ret_vec
380 }
381 _ => {
382 return Err(ParseError::ParsePayloadFailed(format!(
383 "AttestationVerifier::parse_payload cabundle is wrong type or not present:{:?}",
384 document_map.get(&serde_cbor::Value::Text("cabundle".to_string()))
385 )))
386 }
387 };
388 Ok(Payload {
389 module_id,
390 timestamp,
391 public_key,
392 certificate,
393 cabundle,
394 nonce,
395 user_data,
396 digest,
397 pcrs,
398 })
399}
400
401pub fn parse_verify_with(
402 document_data: Vec<u8>,
403 nonce: Vec<u8>,
404 unix_time: u64,
405) -> Result<(Payload, AttestationDocument), ParseVerificationError> {
406 let attestation_document =
407 parse_document(&document_data).map_err(ParseVerificationError::ParseError)?;
408
409 let payload =
410 parse_payload(&attestation_document.payload).map_err(ParseVerificationError::ParseError)?;
411
412 verify(
413 attestation_document.clone(),
414 payload.clone(),
415 nonce,
416 None,
417 unix_time,
418 )
419 .map_err(ParseVerificationError::VerificationError)?;
420
421 Ok((payload, attestation_document))
422}
423
424#[cfg(test)]
425mod tests {
426
427 use super::*;
428 use hex;
429 #[test]
430 fn test_verify() {
431 let unix_time = std::time::UNIX_EPOCH.elapsed().unwrap().as_secs();
432 let document_data = STANDARD.decode("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")
435 .expect("decode cbor document failed");
436
437 let nonce =
438 hex::decode("0000000000000000000000000000000000000000").expect("decode nonce failed");
439
440 let document = parse_document(&document_data).expect("parse document failed");
441 let payload = parse_payload(&document.payload).expect("parse payload failed");
442
443 match parse_verify_with(document_data, nonce, unix_time) {
444 Ok((payload, attestation_document)) => {
445 println!("payload {:?}", payload.pcrs);
446 }
447 Err(e) => panic!("parse_verify_with failed: {:?}", e.to_string()),
448 }
449 }
450}