1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//! SGX per-CPU package sealing key accessor.

use sgx_isa::Keypolicy;
use sp800_185::KMac;

#[cfg(target_env = "sgx")]
use sgx_isa::{Keyname, Keyrequest};
#[cfg(target_env = "sgx")]
use tiny_keccak::{Hasher, Sha3};

const SEAL_KDF_CUSTOM: &[u8] = b"Ekiden Expand SGX Seal Key";

cfg_if::cfg_if! {
    if #[cfg(target_env = "sgx")] {
        fn egetkey_impl(key_policy: Keypolicy, context: &[u8]) -> [u8; 16] {
            let mut req = Keyrequest::default();

            req.keyname = Keyname::Seal as u16;
            req.keypolicy = key_policy;

            let mut sha3 = Sha3::v256();
            sha3.update(context);
            let mut k = [0; 32];
            sha3.finalize(&mut k);
            req.keyid = k;

            // Fucking sgx_isa::Attributes doesn't have a -> [u64;2].
            req.attributemask[0] = 1 | 2 | 4; // SGX_FLAGS_INITTED | SGX_FLAGS_DEBUG | SGX_FLAGS_MODE64BIT
            req.attributemask[1] = 3; // SGX_XFRM_LEGACY

            match req.egetkey() {
                Err(e) => panic!("EGETKEY failed: {:?}", e),
                Ok(k) => k,
            }
        }
    } else if #[cfg(feature = "tdx")] {
        fn egetkey_impl(_key_policy: Keypolicy, _context: &[u8]) -> [u8; 16] {
            unimplemented!("EGETKEY not implemented for TDX");
        }
    } else {
        const MOCK_MRENCLAVE_KEY: &[u8] = b"Ekiden Test MRENCLAVE KEY";
        const MOCK_MRSIGNER_KEY: &[u8] = b"Ekiden Test MRSIGNER KEY";
        const MOCK_KDF_CUSTOM: &[u8] = b"Ekiden Extract Test SGX Seal Key";

        fn egetkey_impl(key_policy: Keypolicy, context: &[u8]) -> [u8; 16] {
            let mut k = [0u8; 16];

            // Deterministically generate a test master key from the context.
            let mut kdf = match key_policy {
                Keypolicy::MRENCLAVE => KMac::new_kmac256(MOCK_MRENCLAVE_KEY, MOCK_KDF_CUSTOM),
                Keypolicy::MRSIGNER => KMac::new_kmac256(MOCK_MRSIGNER_KEY, MOCK_KDF_CUSTOM),
                _ => panic!("Invalid key_policy"),
            };
            kdf.update(context);
            kdf.finalize(&mut k);

            k
        }
    }
}

/// egetkey returns a 256 bit key suitable for sealing secrets to the
/// enclave in cold storage, derived from the results of the `EGETKEY`
/// instruction.  The `context` field is a domain separation tag.
///
/// Note: The key can also be used for other things (eg: as an X25519
/// private key).
pub fn egetkey(key_policy: Keypolicy, context: &[u8]) -> [u8; 32] {
    let mut k = [0u8; 32];

    // Obtain the per-CPU package SGX sealing key, with the requested
    // policy.
    let master_secret = egetkey_impl(key_policy, context);

    // Expand the 128 bit EGETKEY result into a 256 bit key, suitable
    // for use with our MRAE primitives.
    let mut kdf = KMac::new_kmac256(&master_secret, SEAL_KDF_CUSTOM);
    kdf.update(context);
    kdf.finalize(&mut k);

    k
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_egetkey() {
        // Ensure key policies works.
        let mr_signer_key = egetkey(Keypolicy::MRSIGNER, b"MRSIGNER");
        assert!(mr_signer_key != [0u8; 32]);
        let mr_enclave_key = egetkey(Keypolicy::MRENCLAVE, b"MRENCLAVE");
        assert!(mr_enclave_key != [0u8; 32]);
        assert!(mr_signer_key != mr_enclave_key);

        // Ensure the context does something.
        let a_key = egetkey(Keypolicy::MRENCLAVE, b"Context A");
        let b_key = egetkey(Keypolicy::MRENCLAVE, b"Context B");
        assert!(a_key != b_key);

        // Ensure determinism.
        let aa_key = egetkey(Keypolicy::MRENCLAVE, b"Context A");
        assert!(a_key == aa_key);
    }
}