remote_attestation_verifier/
lib.rs

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