Skip to main content

sgx_keyreq/
ecalls.rs

1//! Low level `ENCLU` calls for extracting key information from the CPU
2
3use crate::ffi;
4use core::fmt;
5use core::mem::MaybeUninit;
6use sgx_isa::{Keyrequest, Report, Targetinfo};
7
8#[repr(align(16))]
9struct Align16<T>(pub T);
10
11#[repr(align(128))]
12struct Align128<T>(pub T);
13
14#[repr(align(512))]
15struct Align512<T>(pub T);
16
17/// The error status of a malformed `ENCLU` call
18#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
19#[repr(u32)]
20pub enum ECallStatus {
21    InvalidAttribute = ffi::STATUS_INVALID_ATTRIBUTE,
22    InvalidCPUSVN = ffi::STATUS_INVALID_CPUSVN,
23    InvalidISVSVN = ffi::STATUS_INVALID_ISVSVN,
24    InvalidKeyname = ffi::STATUS_INVALID_KEYNAME,
25    Unknown = u32::MAX,
26}
27
28impl From<u32> for ECallStatus {
29    fn from(code: u32) -> Self {
30        match code {
31            ffi::STATUS_INVALID_ATTRIBUTE => ECallStatus::InvalidAttribute,
32            ffi::STATUS_INVALID_CPUSVN => ECallStatus::InvalidCPUSVN,
33            ffi::STATUS_INVALID_ISVSVN => ECallStatus::InvalidISVSVN,
34            ffi::STATUS_INVALID_KEYNAME => ECallStatus::InvalidKeyname,
35            _ => ECallStatus::Unknown,
36        }
37    }
38}
39
40impl fmt::Display for ECallStatus {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        match self {
43            ECallStatus::InvalidAttribute => f.write_str("ENCLU error: Invalid attribute"),
44            ECallStatus::InvalidCPUSVN => f.write_str("ENCLU error: Invalid CPUSVN"),
45            ECallStatus::InvalidISVSVN => f.write_str("ENCLU error: Invalid CPUISVN"),
46            ECallStatus::InvalidKeyname => f.write_str("ENCLU error: Invalid Keyname"),
47            ECallStatus::Unknown => f.write_str("ENCLU error: Unknown"),
48        }
49    }
50}
51
52#[cfg(feature = "std")]
53impl std::error::Error for ECallStatus {}
54
55/// Performs an `ENCLU[EGETKEY]` call. See the [x86
56/// instruction](https://www.felixcloutier.com/x86/egetkey) or refer to the SGX SDK docs for more
57/// information
58pub fn egetkey(request: Keyrequest) -> Result<[u8; 16], ECallStatus> {
59    let mut out = MaybeUninit::<Align16<[u8; 16]>>::uninit();
60    unsafe {
61        let error = ffi::do_egetkey(
62            &Align512(request) as *const Align512<_> as *const u8,
63            out.as_mut_ptr() as *mut u8,
64        );
65        match error {
66            ffi::STATUS_SUCCESS => Ok(out.assume_init().0),
67            error => Err(ECallStatus::from(error)),
68        }
69    }
70}
71
72/// Performs an `ENCLU[EREPORT]` call. See the [x86
73/// instruction](https://www.felixcloutier.com/x86/ereport) or refer to the SGX SDK docs for more
74/// information
75pub fn ereport(targetinfo: Targetinfo, reportdata: [u8; 64]) -> Result<Report, ECallStatus> {
76    let mut out = MaybeUninit::<Align512<Report>>::uninit();
77    unsafe {
78        let error = ffi::do_ereport(
79            &Align512(targetinfo) as *const Align512<_> as *const u8,
80            &Align128(reportdata) as *const Align128<_> as *const u8,
81            out.as_mut_ptr() as *mut u8,
82        );
83        match error {
84            ffi::STATUS_SUCCESS => Ok(out.assume_init().0),
85            error => Err(ECallStatus::from(error)),
86        }
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93    use sgx_isa::*;
94
95    #[test]
96    fn empty_seal_key_request() {
97        let request = Keyrequest {
98            keyname: Keyname::Seal as u16,
99            ..Default::default()
100        };
101        assert!(egetkey(request).is_ok())
102    }
103
104    #[test]
105    fn report_for_self() {
106        assert!(ereport(Default::default(), [0; 64]).is_ok())
107    }
108}