oasis_core_runtime/common/sgx/
seal.rs

1//! Wrappers for sealing secrets to the enclave in cold storage.
2use anyhow::{format_err, Error};
3use rand::{rngs::OsRng, Rng};
4use sgx_isa::Keypolicy;
5use zeroize::Zeroize;
6
7use crate::common::{
8    crypto::mrae::deoxysii::{DeoxysII, NONCE_SIZE, TAG_SIZE},
9    sgx::egetkey::egetkey,
10};
11
12/// Seal a secret to the enclave.
13///
14/// The `context` field is a domain separation tag.
15pub fn seal(key_policy: Keypolicy, context: &[u8], data: &[u8]) -> Vec<u8> {
16    let mut rng = OsRng {};
17
18    // Encrypt the raw policy.
19    let mut nonce = [0u8; NONCE_SIZE];
20    rng.fill(&mut nonce);
21    let d2 = new_deoxysii(key_policy, context);
22    let mut ciphertext = d2.seal(&nonce, data, vec![]);
23    ciphertext.extend_from_slice(&nonce);
24
25    ciphertext
26}
27
28/// Unseal a previously sealed secret to the enclave.
29///
30/// The `context` field is a domain separation tag.
31pub fn unseal(
32    key_policy: Keypolicy,
33    context: &[u8],
34    ciphertext: &[u8],
35) -> Result<Option<Vec<u8>>, Error> {
36    let ct_len = ciphertext.len();
37    if ct_len == 0 {
38        return Ok(None);
39    }
40    if ct_len < TAG_SIZE + NONCE_SIZE {
41        return Err(format_err!("ciphertext is corrupted: invalid size"));
42    }
43    let ct_len = ct_len - NONCE_SIZE;
44
45    // Split the ciphertext || tag || nonce.
46    let mut nonce = [0u8; NONCE_SIZE];
47    nonce.copy_from_slice(&ciphertext[ct_len..]);
48    let ciphertext = &ciphertext[..ct_len];
49
50    let d2 = new_deoxysii(key_policy, context);
51
52    match d2.open(&nonce, ciphertext.to_vec(), vec![]) {
53        Ok(plaintext) => Ok(Some(plaintext)),
54        Err(_) => Err(format_err!("ciphertext is corrupted")),
55    }
56}
57
58/// Creates a new Deoxys-II instance initialized with an SGX sealing key derived
59/// from the results of the `EGETKEY`instruction.
60///
61/// The `context` field is a domain separation tag.
62pub fn new_deoxysii(key_policy: Keypolicy, context: &[u8]) -> DeoxysII {
63    let mut seal_key = egetkey(key_policy, context);
64    let d2 = DeoxysII::new(&seal_key);
65    seal_key.zeroize();
66
67    d2
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn test_seal_unseal() {
76        // Test different policies.
77        let sealed_a = seal(Keypolicy::MRSIGNER, b"MRSIGNER", b"Mr. Signer");
78        let unsealed_a = unseal(Keypolicy::MRSIGNER, b"MRSIGNER", &sealed_a);
79        assert_eq!(unsealed_a.unwrap(), Some(b"Mr. Signer".to_vec()));
80
81        let sealed_b = seal(Keypolicy::MRENCLAVE, b"MRENCLAVE", b"Mr. Enclave");
82        let unsealed_b = unseal(Keypolicy::MRENCLAVE, b"MRENCLAVE", &sealed_b);
83        assert_eq!(unsealed_b.unwrap(), Some(b"Mr. Enclave".to_vec()));
84
85        // Test zero-length ciphertext.
86        let unsealed_c = unseal(Keypolicy::MRENCLAVE, b"MRENCLAVE", b"");
87        assert_eq!(unsealed_c.unwrap(), None);
88    }
89
90    #[test]
91    fn test_incorrect_context() {
92        // Test incorrect context.
93        let sealed_b = seal(Keypolicy::MRENCLAVE, b"MRENCLAVE1", b"Mr. Enclave");
94        let unsealed_b = unseal(Keypolicy::MRENCLAVE, b"MRENCLAVE2", &sealed_b);
95        assert_eq!(unsealed_b.is_err(), true);
96    }
97
98    #[test]
99    fn test_incorrect_ciphertext_a() {
100        let sealed_b = seal(Keypolicy::MRENCLAVE, b"MRENCLAVE", b"Mr. Enclave");
101        let unsealed_b = unseal(Keypolicy::MRENCLAVE, b"MRENCLAVE", &sealed_b[..2]);
102        assert_eq!(unsealed_b.is_err(), true);
103    }
104
105    #[test]
106    fn test_incorrect_ciphertext_b() {
107        let mut sealed_b = seal(Keypolicy::MRENCLAVE, b"MRENCLAVE", b"Mr. Enclave");
108        sealed_b[0] = sealed_b[0].wrapping_add(1);
109        let unsealed_b = unseal(Keypolicy::MRENCLAVE, b"MRENCLAVE", &sealed_b);
110        assert_eq!(unsealed_b.is_err(), true);
111    }
112}