use crate::bindings::*; use crate::error::SgxError; use crate::ioctl::SgxIoctlClient; use lazy_static::lazy_static; use std::fmt::Debug; use std::ops::Deref; use std::sync::Mutex; pub struct Quote { buf: Vec, pub(crate) report_body: *const sgx_report_body_t, } impl TryFrom> for Quote { type Error = SgxError; fn try_from(buf: Vec) -> Result { let report_body_offset = size_of::(); let report_body_size = size_of::(); if buf.len() < report_body_offset + report_body_size { let minimal = report_body_offset + report_body_size; let actual = buf.len(); return Err(SgxError::QuoteError(format!( "Failed to parse DCAP quote, min {minimal}, act {actual}" ))); } let report_body = buf.as_slice()[report_body_offset..].as_ptr() as *const sgx_report_body_t; Ok(Self { buf, report_body }) } } #[repr(C)] struct QuoteHeader { pub version: u16, pub att_key_type: u16, pub att_key_data_0: u32, pub qe_svn: u16, pub pce_svn: u16, pub vendor_id: [u8; 16], pub user_data: [u8; 20], } impl TryFrom<&[u8]> for Quote { type Error = SgxError; fn try_from(buf: &[u8]) -> Result { buf.to_vec().try_into() } } impl TryFrom for Quote { type Error = SgxError; fn try_from(value: ReportData) -> Result { Self::from_report_data(value) } } impl Deref for Quote { type Target = [u8]; fn deref(&self) -> &Self::Target { self.buf.as_ref() } } impl Quote { pub fn from_report_data(data: ReportData) -> Result { IOCTL_CLIENT .lock() .unwrap() .generate_quote(data)? .try_into() } pub fn from_slice(slice: &[u8]) -> Result { slice.try_into() } pub fn as_slice(&self) -> &[u8] { self } pub fn verify(&self) -> Result { IOCTL_CLIENT.lock().unwrap().verify_quote(self.buf.as_ref()) } pub fn isv_family_id(&self) -> sgx_isvfamily_id_t { unsafe { (*self.report_body).isv_family_id } } pub fn isv_ext_prod_id(&self) -> sgx_isvext_prod_id_t { unsafe { (*self.report_body).isv_ext_prod_id } } pub fn config_id(&self) -> sgx_config_id_t { unsafe { (*self.report_body).config_id } } pub fn mrenclave(&self) -> sgx_measurement_t { unsafe { (*self.report_body).mr_enclave } } pub fn mrsigner(&self) -> sgx_measurement_t { unsafe { (*self.report_body).mr_signer } } pub fn product_id(&self) -> sgx_prod_id_t { unsafe { (*self.report_body).isv_prod_id } } pub fn version(&self) -> sgx_isv_svn_t { unsafe { (*self.report_body).isv_svn } } pub fn report_data(&self) -> ReportData { unsafe { (*self.report_body).report_data.into() } } } impl Debug for Quote { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("SGXQuote") .field("mrenclave", &self.mrenclave()) .field("mrsigner", &self.mrsigner()) .field("report_body", &self.report_data()) .field("product_id", &self.product_id()) .field("version", &self.version()) .field("family_id", &self.isv_family_id()) .field("ext_prod_id", &self.isv_ext_prod_id()) .field("config_id", &self.config_id()) .finish() } } lazy_static! { pub static ref IOCTL_CLIENT: Mutex = { let client = SgxIoctlClient::new(); Mutex::new(client) }; } // lazy_static! { // pub static ref STATIC_QUOTE: once_cell::sync::OnceCell = // OnceCell::with_value(Quote::from_report_data([0u8; 64]).unwrap()); // } // unsafe impl Send for Quote {} lazy_static! { pub static ref STATIC_QUOTE: Result = Quote::from_report_data([0u8; 64]); } unsafe impl Sync for Quote {} pub type ReportData = [u8; 64]; #[derive(Debug)] pub enum VerifyResult { Ok, ConfigNeeded, OutOfDate, OutOfDateConfigNeeded, InvalidSignature, Revoked, Unspecified, SwHardeningNeeded, ConfigAndSwHardeningNeeded, } impl From for VerifyResult { fn from(result: sgx_ql_qv_result_t) -> Self { match result { SGX_QL_QV_RESULT_OK => VerifyResult::Ok, SGX_QL_QV_RESULT_CONFIG_NEEDED => VerifyResult::ConfigNeeded, SGX_QL_QV_RESULT_OUT_OF_DATE => VerifyResult::OutOfDate, SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED => VerifyResult::OutOfDateConfigNeeded, SGX_QL_QV_RESULT_INVALID_SIGNATURE => VerifyResult::InvalidSignature, SGX_QL_QV_RESULT_REVOKED => VerifyResult::Revoked, SGX_QL_QV_RESULT_SW_HARDENING_NEEDED => VerifyResult::SwHardeningNeeded, SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED => { VerifyResult::ConfigAndSwHardeningNeeded } //SGX_QL_QV_RESULT_UNSPECIFIED => QuoteVerifyResult::Unspecified, _ => VerifyResult::Unspecified, } } } impl VerifyResult { pub fn is_ok(&self) -> bool { match self { VerifyResult::Ok => true, _ => false, } } pub fn is_negligible(&self) -> bool { match self { VerifyResult::Ok => true, VerifyResult::ConfigNeeded => true, VerifyResult::OutOfDate => true, VerifyResult::OutOfDateConfigNeeded => true, VerifyResult::SwHardeningNeeded => true, VerifyResult::ConfigAndSwHardeningNeeded => true, _ => false, } } }