nsm_nitro_enclave_utils/
lib.rs

1//! Wraps [`aws_nitro_enclaves_nsm_api`] to allow you to mock the Nitro Hypervisor locally
2
3pub mod api;
4
5pub mod driver;
6
7pub mod time;
8
9pub mod pcr;
10
11#[cfg(feature = "verify")]
12pub mod verify;
13
14#[derive(Debug)]
15/// Captures errors that can occur during attestation document verification.
16/// `kind` is a high-level categorization of the error that is defined by the library.
17/// `source` is the underlying error that caused the failure. When possible, the source is the error that was returned by the underlying library.
18/// If the error returned from the underlying library does not implement [`std::error::Error`], or the error originated due to this library's own assertions, [`ErrorContext`] is used.
19pub struct Error<T> {
20    kind: T,
21    _backtrace: std::backtrace::Backtrace,
22    _source: Box<dyn std::error::Error + Send + Sync>,
23}
24
25impl<T> Error<T> {
26    fn new<E>(kind: T, err: E) -> Self
27    where
28        E: std::error::Error + Send + Sync + 'static,
29    {
30        Self {
31            kind,
32            _backtrace: std::backtrace::Backtrace::capture(),
33            _source: Box::new(err),
34        }
35    }
36
37    pub fn kind(&self) -> &T {
38        &self.kind
39    }
40}
41
42/// Used by errors to provide additional context if the error returned from the underlying library does not implement [`std::error::Error`],
43/// or the error originated due to this library's own assertions.
44#[derive(Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord)]
45pub struct ErrorContext(pub(crate) &'static str);
46
47impl std::fmt::Display for ErrorContext {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        write!(f, "{}", self.0)
50    }
51}
52
53impl std::error::Error for ErrorContext {}
54
55#[cfg(all(test, target_arch = "wasm32"))]
56/// This test suite is expected to reasonable cover all features that WebAssembly support.
57/// See README for instructions for running these tests.
58mod wasm_tests {
59    use wasm_bindgen_test::*;
60
61    #[cfg(all(feature = "verify", feature = "pki"))]
62    #[wasm_bindgen_test]
63    fn sign_and_verify() {
64        use p384::{ecdsa::SigningKey, pkcs8::DecodePrivateKey};
65
66        use crate::api;
67        use crate::driver::dev::sign::AttestationDocSignerExt;
68        use crate::pcr::Pcrs;
69        use crate::time::Time;
70        use crate::verify::AttestationDocVerifierExt;
71
72        let time = Time::new(Box::new(|| include!("../../test_data/created_at.txt")));
73
74        let root_cert = include_bytes!("../../test_data/root-certificate.der");
75        let int_cert = include_bytes!("../../test_data/int-certificate.der");
76        let end_cert = include_bytes!("../../test_data/end-certificate.der");
77
78        let signing_key =
79            p384::SecretKey::from_pkcs8_der(include_bytes!("../../test_data/end-signing-key.der"))
80                .unwrap();
81        let signing_key: SigningKey = signing_key.into();
82
83        let doc = api::nsm::AttestationDoc {
84            module_id: "".to_string(),
85            digest: api::nsm::Digest::SHA384,
86            timestamp: time.time(),
87            pcrs: Pcrs::default().into(),
88            certificate: end_cert.to_vec().into(),
89            cabundle: vec![int_cert.to_vec().into()],
90            public_key: None,
91            user_data: None,
92            nonce: None,
93        };
94
95        let doc = doc.sign(signing_key).unwrap();
96
97        api::nsm::AttestationDoc::from_cose(&doc, root_cert, time).unwrap();
98    }
99
100    #[cfg(feature = "seed")]
101    #[wasm_bindgen_test]
102    fn seed_is_deterministic() {
103        use crate::pcr::{Pcrs, PCR_INDEXES};
104
105        use std::collections::BTreeMap;
106
107        let mut seed = BTreeMap::new();
108        for index in PCR_INDEXES {
109            seed.insert(index, usize::from(index).to_string());
110        }
111        let a = Pcrs::seed(seed.clone());
112        let b = Pcrs::seed(seed);
113        assert_eq!(a, b);
114
115        let mut alt_seed = BTreeMap::new();
116        for index in PCR_INDEXES {
117            alt_seed.insert(index, (usize::from(index) + 1).to_string());
118        }
119        let c = Pcrs::seed(alt_seed);
120        assert_ne!(a, c);
121    }
122
123    #[cfg(feature = "rand")]
124    #[wasm_bindgen_test]
125    fn rand() {
126        use crate::pcr::Pcrs;
127
128        let a = Pcrs::rand();
129        let b = Pcrs::rand();
130        assert_ne!(a, b);
131    }
132}