211 lines
5.7 KiB
Rust
211 lines
5.7 KiB
Rust
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<u8>,
|
|
pub(crate) report_body: *const sgx_report_body_t,
|
|
}
|
|
|
|
impl TryFrom<Vec<u8>> for Quote {
|
|
type Error = SgxError;
|
|
fn try_from(buf: Vec<u8>) -> Result<Self, Self::Error> {
|
|
let report_body_offset = size_of::<QuoteHeader>();
|
|
let report_body_size = size_of::<sgx_report_body_t>();
|
|
|
|
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<Self, Self::Error> {
|
|
buf.to_vec().try_into()
|
|
}
|
|
}
|
|
|
|
impl TryFrom<ReportData> for Quote {
|
|
type Error = SgxError;
|
|
|
|
fn try_from(value: ReportData) -> Result<Self, Self::Error> {
|
|
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<Self, SgxError> {
|
|
IOCTL_CLIENT
|
|
.lock()
|
|
.unwrap()
|
|
.generate_quote(data)?
|
|
.try_into()
|
|
}
|
|
|
|
pub fn from_slice(slice: &[u8]) -> Result<Self, SgxError> {
|
|
slice.try_into()
|
|
}
|
|
|
|
pub fn as_slice(&self) -> &[u8] {
|
|
self
|
|
}
|
|
|
|
pub fn verify(&self) -> Result<VerifyResult, SgxError> {
|
|
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<SgxIoctlClient> = {
|
|
let client = SgxIoctlClient::new();
|
|
Mutex::new(client)
|
|
};
|
|
}
|
|
|
|
// lazy_static! {
|
|
// pub static ref STATIC_QUOTE: once_cell::sync::OnceCell<Quote> =
|
|
// OnceCell::with_value(Quote::from_report_data([0u8; 64]).unwrap());
|
|
// }
|
|
// unsafe impl Send for Quote {}
|
|
|
|
lazy_static! {
|
|
pub static ref STATIC_QUOTE: Result<Quote, SgxError> = 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<sgx_ql_qv_result_t> 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,
|
|
}
|
|
}
|
|
}
|