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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// SPDX-License-Identifier: Apache-2.0

//! Intel SGX Enclave report structures.

use core::{intrinsics::transmute, mem::size_of};

use crate::parameters::{Attributes, Features, MiscSelect, Xfrm};

/// The enclave report body.
///
/// For more information see the following documents:
///
/// [Intel® Software Guard Extensions (Intel® SGX) Data Center Attestation Primitives: ECDSA Quote Library API](https://download.01.org/intel-sgx/dcap-1.0/docs/SGX_ECDSA_QuoteGenReference_DCAP_API_Linux_1.0.pdf)
///
/// Table 5, A.4. Quote Format
///
/// [Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3 (3A, 3B, 3C & 3D): System Programming Guide](https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-3d-part-4-manual.html)
///
/// Table 38-21. Layout of REPORT
#[derive(Clone, Debug)]
#[repr(C)]
pub struct ReportBody {
    pub cpusvn: [u8; 16],
    miscselect: [u8; 4],
    reserved1: [u8; 28],
    features: [u8; 8],
    xfrm: [u8; 8],
    pub mrenclave: [u8; 32],
    reserved2: [u8; 32],
    pub mrsigner: [u8; 32],
    reserved3: [u8; 96],
    isv_prodid: [u8; 2],
    isv_svn: [u8; 2],
    reserved4: [u8; 60],
    pub reportdata: [u8; 64],
}

// SAFETY: This is safe because `ReportBody` has 1-byte alignment.
impl From<[u8; size_of::<ReportBody>()]> for ReportBody {
    fn from(value: [u8; size_of::<ReportBody>()]) -> Self {
        unsafe { transmute(value) }
    }
}

// SAFETY: This is safe because `ReportBody` has 1-byte alignment.
impl From<ReportBody> for [u8; size_of::<ReportBody>()] {
    fn from(value: ReportBody) -> Self {
        unsafe { transmute(value) }
    }
}

// SAFETY: This is safe because `ReportBody` has 1-byte alignment.
impl<'a> From<&'a [u8; size_of::<ReportBody>()]> for &'a ReportBody {
    fn from(value: &'a [u8; size_of::<ReportBody>()]) -> Self {
        unsafe { transmute(value) }
    }
}

// SAFETY: This is safe because `ReportBody` has 1-byte alignment.
impl AsRef<[u8]> for ReportBody {
    fn as_ref(&self) -> &[u8] {
        unsafe { transmute::<&Self, &[u8; size_of::<Self>()]>(self) }
    }
}

impl ReportBody {
    /// Bit vector specifying which extended features are saved to the MISC region of the
    /// SSA frame when an AEX occurs.
    ///
    /// If it cannot be parsed the raw little endian bytes will be returned instead.
    pub fn misc_select(&self) -> MiscSelect {
        MiscSelect::from_bits_truncate(u32::from_le_bytes(self.miscselect))
    }

    /// Set of flags describing attributes of the enclave.
    ///
    /// If it cannot be parsed the raw little endian bytes will be returned instead.
    ///
    /// The raw bytes returned are the 64 bit features and xfrm respectively.
    pub fn attributes(&self) -> Attributes {
        let features = Features::from_bits_truncate(u64::from_le_bytes(self.features));
        let xfrm = Xfrm::from_bits_truncate(u64::from_le_bytes(self.xfrm));
        Attributes::new(features, xfrm)
    }

    /// ISV assigned Product ID of the enclave.
    pub fn enclave_product_id(&self) -> u16 {
        u16::from_le_bytes(self.isv_prodid)
    }

    /// ISV assigned SVN (security version number) of the enclave.
    pub fn enclave_security_version(&self) -> u16 {
        u16::from_le_bytes(self.isv_svn)
    }
}

/// The REPORT structure is the output of the EREPORT instruction, and must be 512-Byte aligned.
///
/// For more information see:
///
/// [Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3 (3A, 3B, 3C & 3D): System Programming Guide](https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-3d-part-4-manual.html)
///
/// Table 38-21. Layout of REPORT
#[derive(Clone, Debug)]
#[repr(C, align(512))]
pub struct Report {
    pub body: ReportBody,
    pub keyid: [u8; 32],
    pub mac: [u8; 16],
}

#[cfg(test)]
mod test {
    use super::{Report, ReportBody};
    use testaso::testaso;

    testaso! {
        struct ReportBody: 1, 384 => {
            cpusvn: 0,
            miscselect: 16,
            reserved1: 20,
            features: 48,
            xfrm: 56,
            mrenclave: 64,
            reserved2: 96,
            mrsigner: 128,
            reserved3: 160,
            isv_prodid: 256,
            isv_svn: 258,
            reserved4: 260,
            reportdata: 320
        }

        struct Report: 512, 512 => {
            body: 0,
            keyid: 384,
            mac: 416
        }
    }
}