oasis_core_runtime/common/sgx/pcs/
report.rs1use std::convert::TryInto;
3
4use byteorder::{ByteOrder, LittleEndian};
5pub use sgx_isa::Report as SgxReport;
6use tiny_keccak::{Hasher, TupleHash};
7
8use super::{constants::*, utils::*, Error};
9use crate::common::sgx::{EnclaveIdentity, MrEnclave};
10
11#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct TdReport {
14 pub tee_tcb_svn: [u8; 16],
16 pub mr_seam: [u8; 48],
18 pub mr_signer_seam: [u8; 48],
20 pub seam_attributes: [u8; 8],
22 pub td_attributes: TdAttributes,
24 pub xfam: [u8; 8],
26 pub mr_td: [u8; 48],
28 pub mr_config_id: [u8; 48],
31 pub mr_owner: [u8; 48],
33 pub mr_owner_config: [u8; 48],
36 pub rtmr0: [u8; 48],
38 pub rtmr1: [u8; 48],
40 pub rtmr2: [u8; 48],
42 pub rtmr3: [u8; 48],
44 pub report_data: [u8; 64],
46}
47
48impl TdReport {
49 pub fn parse(mut data: &[u8]) -> Result<Self, Error> {
51 if data.len() != TDX_REPORT_BODY_LEN {
52 return Err(Error::MalformedReport);
53 }
54
55 let report = Self {
56 tee_tcb_svn: data
57 .take_prefix(16)
58 .map_err(|_| Error::MalformedReport)?
59 .try_into()
60 .unwrap(),
61 mr_seam: data
62 .take_prefix(48)
63 .map_err(|_| Error::MalformedReport)?
64 .try_into()
65 .unwrap(),
66 mr_signer_seam: data
67 .take_prefix(48)
68 .map_err(|_| Error::MalformedReport)?
69 .try_into()
70 .unwrap(),
71 seam_attributes: data
72 .take_prefix(8)
73 .map_err(|_| Error::MalformedReport)?
74 .try_into()
75 .unwrap(),
76 td_attributes: TdAttributes::parse(
77 data.take_prefix(8).map_err(|_| Error::MalformedReport)?,
78 )?,
79 xfam: data
80 .take_prefix(8)
81 .map_err(|_| Error::MalformedReport)?
82 .try_into()
83 .unwrap(),
84 mr_td: data
85 .take_prefix(48)
86 .map_err(|_| Error::MalformedReport)?
87 .try_into()
88 .unwrap(),
89 mr_config_id: data
90 .take_prefix(48)
91 .map_err(|_| Error::MalformedReport)?
92 .try_into()
93 .unwrap(),
94 mr_owner: data
95 .take_prefix(48)
96 .map_err(|_| Error::MalformedReport)?
97 .try_into()
98 .unwrap(),
99 mr_owner_config: data
100 .take_prefix(48)
101 .map_err(|_| Error::MalformedReport)?
102 .try_into()
103 .unwrap(),
104 rtmr0: data
105 .take_prefix(48)
106 .map_err(|_| Error::MalformedReport)?
107 .try_into()
108 .unwrap(),
109 rtmr1: data
110 .take_prefix(48)
111 .map_err(|_| Error::MalformedReport)?
112 .try_into()
113 .unwrap(),
114 rtmr2: data
115 .take_prefix(48)
116 .map_err(|_| Error::MalformedReport)?
117 .try_into()
118 .unwrap(),
119 rtmr3: data
120 .take_prefix(48)
121 .map_err(|_| Error::MalformedReport)?
122 .try_into()
123 .unwrap(),
124 report_data: data
125 .take_prefix(64)
126 .map_err(|_| Error::MalformedReport)?
127 .try_into()
128 .unwrap(),
129 };
130
131 if report.seam_attributes != [0; 8] {
133 return Err(Error::MalformedReport);
134 }
135
136 Ok(report)
137 }
138
139 pub fn as_enclave_identity(&self) -> EnclaveIdentity {
141 td_enclave_identity(
142 &self.mr_td,
143 &self.rtmr0,
144 &self.rtmr1,
145 &self.rtmr2,
146 &self.rtmr3,
147 )
148 }
149}
150
151pub fn td_enclave_identity(
153 mr_td: &[u8; 48],
154 rtmr0: &[u8; 48],
155 rtmr1: &[u8; 48],
156 rtmr2: &[u8; 48],
157 rtmr3: &[u8; 48],
158) -> EnclaveIdentity {
159 let mut mr_enclave = MrEnclave::default();
170 let mut h = TupleHash::v256(TD_ENCLAVE_IDENTITY_CONTEXT);
171 h.update(mr_td);
172 h.update(rtmr0);
173 h.update(rtmr1);
174 h.update(rtmr2);
175 h.update(rtmr3);
176 h.finalize(&mut mr_enclave.0);
177
178 EnclaveIdentity {
179 mr_signer: Default::default(), mr_enclave,
181 }
182}
183
184pub const TD_ENCLAVE_IDENTITY_CONTEXT: &[u8] = b"oasis-core/tdx: TD enclave identity";
186
187bitflags::bitflags! {
188 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
190 pub struct TdAttributes: u64 {
191 const DEBUG = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000001;
193 const SEPT_VE_DISABLE = 0b00000000_00000000_00000000_00000000_00010000_00000000_00000000_00000000;
198 const PKS = 0b00000000_00000000_00000000_00000000_01000000_00000000_00000000_00000000;
201 const KL = 0b00000000_00000000_00000000_00000000_10000000_00000000_00000000_00000000;
203
204 const PERFMON = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
207 }
208}
209
210impl TdAttributes {
211 pub fn parse(data: &[u8]) -> Result<Self, Error> {
213 if data.len() != 8 {
214 return Err(Error::MalformedReport);
215 }
216
217 let attrs = LittleEndian::read_u64(data);
218
219 Self::from_bits(attrs).ok_or(Error::MalformedReport)
220 }
221}
222
223#[cfg(test)]
224mod test {
225 use super::*;
226
227 #[test]
228 fn test_td_attributes() {
229 let attrs = TdAttributes::DEBUG | TdAttributes::SEPT_VE_DISABLE | TdAttributes::PKS;
230 assert!(attrs.contains(TdAttributes::DEBUG));
231 assert!(attrs.contains(TdAttributes::SEPT_VE_DISABLE));
232 assert!(attrs.contains(TdAttributes::PKS));
233 assert!(attrs.contains(TdAttributes::DEBUG | TdAttributes::SEPT_VE_DISABLE));
234 assert!(!attrs.contains(TdAttributes::KL));
235 assert!(!attrs.contains(TdAttributes::DEBUG | TdAttributes::KL));
236
237 let reserved = vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
238 let result = TdAttributes::parse(&reserved);
239 assert!(matches!(result, Err(Error::MalformedReport)));
240
241 let reserved = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01];
242 let result = TdAttributes::parse(&reserved);
243 assert!(matches!(result, Err(Error::MalformedReport)));
244 }
245}