oasis_core_runtime/common/sgx/
egetkey.rs

1//! SGX per-CPU package sealing key accessor.
2
3use sgx_isa::Keypolicy;
4use sp800_185::KMac;
5
6#[cfg(target_env = "sgx")]
7use sgx_isa::{Keyname, Keyrequest};
8#[cfg(target_env = "sgx")]
9use tiny_keccak::{Hasher, Sha3};
10
11const SEAL_KDF_CUSTOM: &[u8] = b"Ekiden Expand SGX Seal Key";
12
13cfg_if::cfg_if! {
14    if #[cfg(target_env = "sgx")] {
15        fn egetkey_impl(key_policy: Keypolicy, context: &[u8]) -> [u8; 16] {
16            let mut req = Keyrequest::default();
17
18            req.keyname = Keyname::Seal as u16;
19            req.keypolicy = key_policy;
20
21            let mut sha3 = Sha3::v256();
22            sha3.update(context);
23            let mut k = [0; 32];
24            sha3.finalize(&mut k);
25            req.keyid = k;
26
27            // Fucking sgx_isa::Attributes doesn't have a -> [u64;2].
28            req.attributemask[0] = 1 | 2 | 4; // SGX_FLAGS_INITTED | SGX_FLAGS_DEBUG | SGX_FLAGS_MODE64BIT
29            req.attributemask[1] = 3; // SGX_XFRM_LEGACY
30
31            match req.egetkey() {
32                Err(e) => panic!("EGETKEY failed: {:?}", e),
33                Ok(k) => k,
34            }
35        }
36    } else if #[cfg(feature = "tdx")] {
37        fn egetkey_impl(_key_policy: Keypolicy, _context: &[u8]) -> [u8; 16] {
38            unimplemented!("EGETKEY not implemented for TDX");
39        }
40    } else {
41        const MOCK_MRENCLAVE_KEY: &[u8] = b"Ekiden Test MRENCLAVE KEY";
42        const MOCK_MRSIGNER_KEY: &[u8] = b"Ekiden Test MRSIGNER KEY";
43        const MOCK_KDF_CUSTOM: &[u8] = b"Ekiden Extract Test SGX Seal Key";
44
45        fn egetkey_impl(key_policy: Keypolicy, context: &[u8]) -> [u8; 16] {
46            let mut k = [0u8; 16];
47
48            // Deterministically generate a test master key from the context.
49            let mut kdf = match key_policy {
50                Keypolicy::MRENCLAVE => KMac::new_kmac256(MOCK_MRENCLAVE_KEY, MOCK_KDF_CUSTOM),
51                Keypolicy::MRSIGNER => KMac::new_kmac256(MOCK_MRSIGNER_KEY, MOCK_KDF_CUSTOM),
52                _ => panic!("Invalid key_policy"),
53            };
54            kdf.update(context);
55            kdf.finalize(&mut k);
56
57            k
58        }
59    }
60}
61
62/// egetkey returns a 256 bit key suitable for sealing secrets to the
63/// enclave in cold storage, derived from the results of the `EGETKEY`
64/// instruction.  The `context` field is a domain separation tag.
65///
66/// Note: The key can also be used for other things (eg: as an X25519
67/// private key).
68pub fn egetkey(key_policy: Keypolicy, context: &[u8]) -> [u8; 32] {
69    let mut k = [0u8; 32];
70
71    // Obtain the per-CPU package SGX sealing key, with the requested
72    // policy.
73    let master_secret = egetkey_impl(key_policy, context);
74
75    // Expand the 128 bit EGETKEY result into a 256 bit key, suitable
76    // for use with our MRAE primitives.
77    let mut kdf = KMac::new_kmac256(&master_secret, SEAL_KDF_CUSTOM);
78    kdf.update(context);
79    kdf.finalize(&mut k);
80
81    k
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn test_egetkey() {
90        // Ensure key policies works.
91        let mr_signer_key = egetkey(Keypolicy::MRSIGNER, b"MRSIGNER");
92        assert!(mr_signer_key != [0u8; 32]);
93        let mr_enclave_key = egetkey(Keypolicy::MRENCLAVE, b"MRENCLAVE");
94        assert!(mr_enclave_key != [0u8; 32]);
95        assert!(mr_signer_key != mr_enclave_key);
96
97        // Ensure the context does something.
98        let a_key = egetkey(Keypolicy::MRENCLAVE, b"Context A");
99        let b_key = egetkey(Keypolicy::MRENCLAVE, b"Context B");
100        assert!(a_key != b_key);
101
102        // Ensure determinism.
103        let aa_key = egetkey(Keypolicy::MRENCLAVE, b"Context A");
104        assert!(a_key == aa_key);
105    }
106}