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
use crate::Error;
use getrandom::getrandom;
use sha2::{Digest, Sha256};
use std::fs;

/// `Gramine`: Gramine is a virtualized runtime used to manage vanilla binaries
/// to execute in an SGX execution environment.  This struct allows access to
/// specific overrides that come out-of-the-box with Gramine.
pub struct Gramine;

impl Gramine {
    /// `Gramine::generate_quote`: This call allows the user to progmatically
    /// create a signature, or "quote" that can prove some piece of data was
    /// generated by a specific enclave. This quote contains a field, "MR_ENCLAVE"
    /// Which holds a measurement of the code that generated the signature.
    ///
    /// # Parameters:
    /// - `user_data`: This is an arbitrary piece of data that can be attached
    /// to the signature for other parties to verify that this data was
    /// produced in an enclave with a MR_ENCLAVE measurement
    ///
    /// # Returns
    /// `Vec<u8>` of a buffer containing the quote/signature
    pub fn generate_quote(user_data: &[u8]) -> std::result::Result<Vec<u8>, Error> {
        match fs::metadata("/dev/attestation/quote") {
            Ok(_) => (),
            Err(_) => return Err(Error::SgxError),
        }
        let mut hasher = Sha256::new();
        hasher.update(user_data);
        let hash_result = &hasher.finalize()[..32];

        let mut data = [0u8; 64];
        data[..32].copy_from_slice(hash_result);

        let user_report_data_path = "/dev/attestation/user_report_data";
        if fs::write(user_report_data_path, &data[..]).is_err() {
            return Err(Error::SgxWriteError);
        }

        fs::read("/dev/attestation/quote").map_err(|_| Error::SgxError)
    }

    /// `read_rand`: Gramine provides convinient accessors to read randomness
    /// that could not be predicted outside the enclave. Gramine will intercept
    /// calls to the getrandom syscall, /dev/random, and /dev/urandom to use
    /// SGX sourced randomness instead.
    ///
    /// # Relavent documentation:
    /// - <https://gramine.readthedocs.io/en/latest/devel/features.html#randomness>
    ///
    /// # Parameters:
    /// - `buf`: the buffer to write the output randomness to.
    ///
    /// # Returns
    /// Error on failure.
    pub fn read_rand(buf: &mut [u8]) -> std::result::Result<(), Error> {
        // https://gramine.readthedocs.io/en/latest/devel/features.html#randomness
        getrandom(buf).map_err(|_| Error::SgxError)
    }
}