Skip to main content

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