diff --git a/attestation/src/attestation.rs b/attestation/src/attestation.rs index d2d6a7067..3c79e3e6e 100644 --- a/attestation/src/attestation.rs +++ b/attestation/src/attestation.rs @@ -1,5 +1,6 @@ use crate::key; -use crate::IasReport; +use crate::AttestationConfig; +use crate::EndorsedAttestationReport; use anyhow::Result; use std::prelude::v1::*; use std::time::{self, SystemTime}; @@ -15,12 +16,14 @@ pub struct RemoteAttestation { } impl RemoteAttestation { - pub fn generate_and_endorse(ias_key: &str, ias_spid: &str) -> Result { + pub fn generate_and_endorse(att_config: &AttestationConfig) -> Result { let key_pair = key::Secp256k1KeyPair::new()?; - let report = if cfg!(sgx_sim) { - IasReport::default() - } else { - IasReport::new(key_pair.pub_k, ias_key, ias_spid)? + let report = match att_config { + AttestationConfig::NoAttestation => EndorsedAttestationReport::default(), + AttestationConfig::SgxIas(config) => { + EndorsedAttestationReport::from_ias(key_pair.pub_k, &config.api_key, &config.spid)? + } + AttestationConfig::SgxDcap(_) => unimplemented!(), }; let cert_extension = serde_json::to_vec(&report)?; diff --git a/attestation/src/ias.rs b/attestation/src/ias.rs index bfec65abd..28e90b8ed 100644 --- a/attestation/src/ias.rs +++ b/attestation/src/ias.rs @@ -16,7 +16,7 @@ // under the License. use crate::AttestationError; -use crate::IasReport; +use crate::EndorsedAttestationReport; use anyhow::Error; use anyhow::Result; use anyhow::{anyhow, bail}; @@ -34,18 +34,24 @@ extern "C" { fn ocall_sgx_get_ias_socket(p_retval: *mut i32) -> sgx_status_t; } -impl IasReport { - pub(crate) fn new( +impl EndorsedAttestationReport { + pub(crate) fn from_ias( pub_k: sgx_types::sgx_ec256_public_t, ias_key: &str, - ias_spid: &str, + ias_spid: &sgx_spid_t, ) -> anyhow::Result { use crate::platform; - let (target_info, epid_group_id) = platform::init_sgx_quote()?; let mut ias_client = IasClient::new(ias_key); - let sigrl = ias_client.get_sigrl(u32::from_le_bytes(epid_group_id))?; - let sgx_report = platform::create_sgx_report(pub_k, target_info)?; - let quote = platform::get_sgx_quote(&sigrl, sgx_report, target_info, ias_spid)?; + let (mut ak_id, qe_target_info) = platform::init_sgx_quote()?; + + // For IAS-based attestation, we need to fill our SPID (obtained from Intel) + // into the attestation key id. + const SPID_OFFSET: usize = std::mem::size_of::(); + ak_id.att_key_id[SPID_OFFSET..(SPID_OFFSET + ias_spid.id.len())] + .clone_from_slice(&ias_spid.id); + + let sgx_report = platform::create_sgx_isv_enclave_report(pub_k, qe_target_info)?; + let quote = platform::get_sgx_quote(&ak_id, sgx_report)?; let ias_report = ias_client.get_report("e)?; Ok(ias_report) } @@ -83,51 +89,7 @@ impl IasClient { Ok(stream) } - fn get_sigrl(&mut self, epid_group_id: u32) -> Result> { - let sigrl_uri = format!("/sgx/dev/attestation/v3/sigrl/{:08x}", epid_group_id); - let request = format!( - "GET {} HTTP/1.1\r\n\ - HOST: {}\r\n\ - Ocp-Apim-Subscription-Key: {}\r\n\ - Connection: Close\r\n\r\n", - sigrl_uri, self.ias_hostname, self.ias_key - ); - - let mut stream = self.new_tls_stream()?; - stream.write_all(request.as_bytes())?; - let mut response = Vec::new(); - stream.read_to_end(&mut response)?; - - let mut headers = [httparse::EMPTY_HEADER; 16]; - let mut http_response = httparse::Response::new(&mut headers); - let header_len = match http_response - .parse(&response) - .map_err(|_| Error::new(AttestationError::IasError))? - { - httparse::Status::Complete(s) => s, - _ => bail!(AttestationError::IasError), - }; - - let header_map = parse_headers(&http_response); - - if !header_map.contains_key("Content-Length") - || header_map - .get("Content-Length") - .unwrap() - .parse::() - .unwrap_or(0) - == 0 - { - Ok(Vec::new()) - } else { - let base64 = std::str::from_utf8(&response[header_len..])?; - - let decoded = base64::decode(base64)?; - Ok(decoded) - } - } - - fn get_report(&mut self, quote: &[u8]) -> Result { + fn get_report(&mut self, quote: &[u8]) -> Result { debug!("get_report"); let report_uri = "/sgx/dev/attestation/v3/report"; let encoded_quote = base64::encode(quote); @@ -161,10 +123,10 @@ impl IasClient { debug!("http_response.parse"); let header_len = match http_response .parse(&response) - .map_err(|_| Error::new(AttestationError::IasError))? + .map_err(|_| Error::new(AttestationError::AttestationServiceError))? { httparse::Status::Complete(s) => s, - _ => bail!(AttestationError::IasError), + _ => bail!(AttestationError::AttestationServiceError), }; let header_map = parse_headers(&http_response); @@ -178,19 +140,19 @@ impl IasClient { .unwrap_or(0) == 0 { - bail!(AttestationError::IasError); + bail!(AttestationError::AttestationServiceError); } debug!("get_signature"); let signature = header_map .get("X-IASReport-Signature") - .ok_or_else(|| Error::new(AttestationError::IasError))?; + .ok_or_else(|| Error::new(AttestationError::AttestationServiceError))?; let signature = base64::decode(signature)?; debug!("get_signing_cert"); let signing_cert = { let cert_str = header_map .get("X-IASReport-Signing-Certificate") - .ok_or_else(|| Error::new(AttestationError::IasError))?; + .ok_or_else(|| Error::new(AttestationError::AttestationServiceError))?; let decoded_cert = percent_encoding::percent_decode_str(cert_str).decode_utf8()?; let certs = rustls::internal::pemfile::certs(&mut decoded_cert.as_bytes()) .map_err(|_| anyhow!("pemfile error"))?; @@ -198,7 +160,7 @@ impl IasClient { }; let report = response[header_len..].to_vec(); - Ok(IasReport { + Ok(EndorsedAttestationReport { report, signature, signing_cert, diff --git a/attestation/src/lib.rs b/attestation/src/lib.rs index d9f70e5f5..1c5acdf1f 100644 --- a/attestation/src/lib.rs +++ b/attestation/src/lib.rs @@ -27,18 +27,55 @@ use std::prelude::v1::*; pub enum AttestationError { #[error("OCall error")] OCallError, - #[error("IAS error")] - IasError, + #[error("Attestation Service error")] + AttestationServiceError, #[error("Platform error")] PlatformError, #[error("Report error")] ReportError, } +pub enum AttestationConfig { + NoAttestation, + SgxIas(IasConfig), + SgxDcap(DcapConfig), // not supported yet +} + +pub struct IasConfig { + pub api_key: String, + pub spid: sgx_types::sgx_spid_t, +} + +pub struct DcapConfig {} + +impl AttestationConfig { + pub fn ias(ias_key: &str, ias_spid: &str) -> Self { + if cfg!(sgx_sim) { + Self::NoAttestation + } else { + use core::convert::TryFrom; + + let mut spid = sgx_types::sgx_spid_t::default(); + let hex = hex::decode(ias_spid).expect("Illegal SPID provided"); + spid.id = <[u8; 16]>::try_from(hex.as_slice()).expect("Illegal SPID provided"); + Self::SgxIas(IasConfig { + api_key: ias_key.to_string(), + spid, + }) + } + } +} + +// AttestationReport can be endorsed by either the Intel Attestation Service +// using EPID or Data Center Attestation Service (platform dependent) using +// ECDSA. #[derive(Default, Serialize, Deserialize)] -pub(crate) struct IasReport { +pub(crate) struct EndorsedAttestationReport { + // Attestation report generated by the hardware pub report: Vec, + // Singature of the report pub signature: Vec, + // Certificate matching the signing key of the signature pub signing_cert: Vec, } diff --git a/attestation/src/platform.rs b/attestation/src/platform.rs index f8fe30699..929039652 100644 --- a/attestation/src/platform.rs +++ b/attestation/src/platform.rs @@ -14,47 +14,46 @@ use std::prelude::v1::*; extern "C" { fn ocall_sgx_init_quote( p_retval: *mut sgx_status_t, + p_sgx_att_key_id: *mut sgx_att_key_id_t, p_target_info: *mut sgx_target_info_t, - p_gid: *mut sgx_epid_group_id_t, ) -> sgx_status_t; - fn ocall_sgx_calc_quote_size( + fn ocall_sgx_get_quote_size( p_retval: *mut sgx_status_t, - p_sig_rl: *const u8, - sig_rl_size: u32, + p_sgx_att_key_id: *const sgx_att_key_id_t, p_quote_size: *mut u32, ) -> sgx_status_t; fn ocall_sgx_get_quote( p_retval: *mut sgx_status_t, p_report: *const sgx_report_t, - quote_type: sgx_quote_sign_type_t, - p_spid: *const sgx_spid_t, - p_nonce: *const sgx_quote_nonce_t, - p_sig_rl: *const u8, - sig_rl_size: u32, - p_qe_report: *mut sgx_report_t, + p_sgx_att_key_id: *const sgx_att_key_id_t, + p_qe_report_info: *mut sgx_qe_report_info_t, p_quote: *mut u8, quote_size: u32, ) -> sgx_status_t; } -pub(crate) fn init_sgx_quote() -> Result<(sgx_target_info_t, sgx_epid_group_id_t)> { +pub(crate) fn init_sgx_quote() -> Result<(sgx_att_key_id_t, sgx_target_info_t)> { debug!("init_quote"); - let mut ti: sgx_target_info_t = sgx_target_info_t::default(); - let mut eg: sgx_epid_group_id_t = sgx_epid_group_id_t::default(); - let mut rt: sgx_status_t = sgx_status_t::SGX_ERROR_UNEXPECTED; + let mut ti = sgx_target_info_t::default(); + let mut ak_id = sgx_att_key_id_t::default(); + let mut rt = sgx_status_t::SGX_ERROR_UNEXPECTED; - let res = unsafe { ocall_sgx_init_quote(&mut rt as _, &mut ti as _, &mut eg as _) }; + let res = unsafe { ocall_sgx_init_quote(&mut rt as _, &mut ak_id as _, &mut ti as _) }; - if res != sgx_status_t::SGX_SUCCESS || rt != sgx_status_t::SGX_SUCCESS { + if res != sgx_status_t::SGX_SUCCESS { bail!(AttestationError::OCallError) - } else { - Ok((ti, eg)) } + + if rt != sgx_status_t::SGX_SUCCESS { + bail!(AttestationError::PlatformError) + } + + Ok((ak_id, ti)) } -pub(crate) fn create_sgx_report( +pub(crate) fn create_sgx_isv_enclave_report( pub_k: sgx_ec256_public_t, target_info: sgx_target_info_t, ) -> Result { @@ -67,41 +66,31 @@ pub(crate) fn create_sgx_report( report_data.d[..32].clone_from_slice(&pub_k_gx); report_data.d[32..].clone_from_slice(&pub_k_gy); - rsgx_create_report(&target_info, &report_data) + Ok(rsgx_create_report(&target_info, &report_data) .map_err(|_| Error::new(AttestationError::PlatformError)) + .unwrap()) } -pub(crate) fn get_sgx_quote( - sigrl: &[u8], - report: sgx_report_t, - target_info: sgx_target_info_t, - ias_spid_str: &str, -) -> Result> { +pub(crate) fn get_sgx_quote(ak_id: &sgx_att_key_id_t, report: sgx_report_t) -> Result> { let mut rt: sgx_status_t = sgx_status_t::SGX_ERROR_UNEXPECTED; - let (p_sigrl, sigrl_len) = if sigrl.is_empty() { - (std::ptr::null(), 0) - } else { - (sigrl.as_ptr(), sigrl.len() as u32) - }; let mut quote_len: u32 = 0; - let res = - unsafe { ocall_sgx_calc_quote_size(&mut rt as _, p_sigrl, sigrl_len, &mut quote_len as _) }; + let res = unsafe { ocall_sgx_get_quote_size(&mut rt as _, ak_id as _, &mut quote_len as _) }; - if res != sgx_status_t::SGX_SUCCESS || rt != sgx_status_t::SGX_SUCCESS { + if res != sgx_status_t::SGX_SUCCESS { bail!(AttestationError::OCallError); } - let mut quote_nonce = sgx_quote_nonce_t { rand: [0; 16] }; - let mut rng = SgxRng::new()?; - rng.fill_bytes(&mut quote_nonce.rand); - let mut qe_report = sgx_report_t::default(); + if rt != sgx_status_t::SGX_SUCCESS { + bail!(AttestationError::PlatformError); + } - let quote_type = sgx_quote_sign_type_t::SGX_LINKABLE_SIGNATURE; + let mut qe_report_info = sgx_qe_report_info_t::default(); + let mut quote_nonce = sgx_quote_nonce_t::default(); - let mut spid = sgx_types::sgx_spid_t::default(); - let hex = hex::decode(ias_spid_str)?; - spid.id.copy_from_slice(&hex[..16]); + let mut rng = SgxRng::new()?; + rng.fill_bytes(&mut quote_nonce.rand); + qe_report_info.nonce = quote_nonce; let mut quote = vec![0; quote_len as usize]; @@ -110,12 +99,8 @@ pub(crate) fn get_sgx_quote( ocall_sgx_get_quote( &mut rt as _, &report as _, - quote_type, - &spid as _, - "e_nonce as _, - p_sigrl, - sigrl_len, - &mut qe_report as _, + ak_id as _, + &mut qe_report_info as _, quote.as_mut_ptr(), quote_len, ) @@ -126,16 +111,9 @@ pub(crate) fn get_sgx_quote( } debug!("rsgx_verify_report"); + let qe_report = qe_report_info.qe_report; // Perform a check on qe_report to verify if the qe_report is valid. - rsgx_verify_report(&qe_report).map_err(|_| Error::new(AttestationError::PlatformError))?; - - // Check if the qe_report is produced on the same platform. - if target_info.mr_enclave.m != qe_report.body.mr_enclave.m - || target_info.attributes.flags != qe_report.body.attributes.flags - || target_info.attributes.xfrm != qe_report.body.attributes.xfrm - { - bail!(AttestationError::PlatformError); - } + rsgx_verify_report(&qe_report).unwrap(); //map_err(|_| Error::new(AttestationError::PlatformError)).expect("verify report failed"); // Check qe_report to defend against replay attack. The purpose of // p_qe_report is for the ISV enclave to confirm the QUOTE it received @@ -148,8 +126,9 @@ pub(crate) fn get_sgx_quote( let mut rhs_vec: Vec = quote_nonce.rand.to_vec(); rhs_vec.extend("e); debug!("rsgx_sha256_slice"); - let rhs_hash = - rsgx_sha256_slice(&rhs_vec).map_err(|_| Error::new(AttestationError::PlatformError))?; + let rhs_hash = rsgx_sha256_slice(&rhs_vec) + .map_err(|_| Error::new(AttestationError::PlatformError)) + .expect("sha256 failed"); let lhs_hash = &qe_report.body.report_data.d[..32]; if rhs_hash != lhs_hash { bail!(AttestationError::PlatformError); diff --git a/attestation/src/report.rs b/attestation/src/report.rs index c696fc2bc..b6c7dc32f 100644 --- a/attestation/src/report.rs +++ b/attestation/src/report.rs @@ -20,7 +20,7 @@ use std::prelude::v1::*; use crate::AttestationError; -use crate::IasReport; +use crate::EndorsedAttestationReport; use anyhow::{anyhow, bail, ensure}; use anyhow::{Error, Result}; use chrono::DateTime; @@ -50,7 +50,13 @@ static SUPPORTED_SIG_ALGS: SignatureAlgorithms = &[ &webpki::RSA_PKCS1_3072_8192_SHA384, ]; -pub struct SgxReport { +// Do not confuse SgxEnclaveReport with AttestationReport. +// SgxReport is generated by SGX hardware and endorsed by Quoting Enclave through +// local attestation. The endorsed SgxReport is an SGX quote. The quote is then +// sent to some attestation service (IAS or DCAP-based AS). The endorsed SGX quote +// is an attestation report signed by attestation service private key, aka +// EndorsedAttestationReport +pub struct SgxEnclaveReport { pub cpu_svn: [u8; 16], pub misc_select: u32, pub attributes: [u8; 16], @@ -61,16 +67,91 @@ pub struct SgxReport { pub report_data: [u8; 64], } +impl SgxEnclaveReport { + pub fn parse_from<'a>(bytes: &'a [u8]) -> Result { + let mut pos: usize = 0; + let mut take = |n: usize| -> Result<&'a [u8]> { + if n > 0 && bytes.len() >= pos + n { + let ret = &bytes[pos..pos + n]; + pos += n; + Ok(ret) + } else { + bail!("Quote parsing error.") + } + }; + + // off 48, size 16 + let cpu_svn = <[u8; 16]>::try_from(take(16)?)?; + + // off 64, size 4 + let misc_select = u32::from_le_bytes(<[u8; 4]>::try_from(take(4)?)?); + + // off 68, size 28 + let _reserved = take(28)?; + + // off 96, size 16 + let attributes = <[u8; 16]>::try_from(take(16)?)?; + + // off 112, size 32 + let mr_enclave = <[u8; 32]>::try_from(take(32)?)?; + + // off 144, size 32 + let _reserved = take(32)?; + + // off 176, size 32 + let mr_signer = <[u8; 32]>::try_from(take(32)?)?; + + // off 208, size 96 + let _reserved = take(96)?; + + // off 304, size 2 + let isv_prod_id = u16::from_le_bytes(<[u8; 2]>::try_from(take(2)?)?); + + // off 306, size 2 + let isv_svn = u16::from_le_bytes(<[u8; 2]>::try_from(take(2)?)?); + + // off 308, size 60 + let _reserved = take(60)?; + + // off 368, size 64 + let mut report_data = [0u8; 64]; + let _report_data = take(64)?; + let mut _it = _report_data.iter(); + for i in report_data.iter_mut() { + *i = *_it.next().ok_or_else(|| anyhow!("Quote parsing error."))?; + } + + ensure!(pos == bytes.len(), "Quote parsing error."); + + Ok(SgxEnclaveReport { + cpu_svn, + misc_select, + attributes, + mr_enclave, + mr_signer, + isv_prod_id, + isv_svn, + report_data, + }) + } +} + pub enum SgxQuoteVersion { - V1, - V2, + V1(SgxEpidQuoteSigType), + V2(SgxEpidQuoteSigType), + V3(SgxEcdsaQuoteAkType), } -pub enum SgxQuoteSigType { +pub enum SgxEpidQuoteSigType { Unlinkable, Linkable, } +pub enum SgxEcdsaQuoteAkType { + P256_256, + P384_384, +} + #[derive(PartialEq, Debug)] pub enum SgxQuoteStatus { OK, @@ -90,18 +171,17 @@ impl From<&str> for SgxQuoteStatus { } } -pub struct SgxQuoteBody { +pub struct SgxQuote { pub version: SgxQuoteVersion, - pub signature_type: SgxQuoteSigType, pub gid: u32, pub isv_svn_qe: u16, pub isv_svn_pce: u16, pub qe_vendor_id: Uuid, pub user_data: [u8; 20], - pub report_body: SgxReport, + pub isv_enclave_report: SgxEnclaveReport, } -impl SgxQuoteBody { +impl SgxQuote { fn parse_from<'a>(bytes: &'a [u8]) -> Result { let mut pos: usize = 0; let mut take = |n: usize| -> Result<&'a [u8]> { @@ -114,17 +194,33 @@ impl SgxQuoteBody { } }; - // off 0, size 2 + // off 0, size 2 + 2 let version = match u16::from_le_bytes(<[u8; 2]>::try_from(take(2)?)?) { - 1 => SgxQuoteVersion::V1, - 2 => SgxQuoteVersion::V2, - _ => bail!("Quote parsing error."), - }; - - // off 2, size 2 - let signature_type = match u16::from_le_bytes(<[u8; 2]>::try_from(take(2)?)?) { - 0 => SgxQuoteSigType::Unlinkable, - 1 => SgxQuoteSigType::Linkable, + 1 => { + let signature_type = match u16::from_le_bytes(<[u8; 2]>::try_from(take(2)?)?) { + 0 => SgxEpidQuoteSigType::Unlinkable, + 1 => SgxEpidQuoteSigType::Linkable, + _ => bail!("Quote parsing error."), + }; + SgxQuoteVersion::V1(signature_type) + } + 2 => { + let signature_type = match u16::from_le_bytes(<[u8; 2]>::try_from(take(2)?)?) { + 0 => SgxEpidQuoteSigType::Unlinkable, + 1 => SgxEpidQuoteSigType::Linkable, + _ => bail!("Quote parsing error."), + }; + SgxQuoteVersion::V2(signature_type) + } + 3 => { + let attestation_key_type = match u16::from_le_bytes(<[u8; 2]>::try_from(take(2)?)?) + { + 2 => SgxEcdsaQuoteAkType::P256_256, + 3 => SgxEcdsaQuoteAkType::P384_384, + _ => bail!("Quote parsing error."), + }; + SgxQuoteVersion::V3(attestation_key_type) + } _ => bail!("Quote parsing error."), }; @@ -144,67 +240,19 @@ impl SgxQuoteBody { // off 28, size 20 let user_data = <[u8; 20]>::try_from(take(20)?)?; - // off 48, size 16 - let cpu_svn = <[u8; 16]>::try_from(take(16)?)?; - - // off 64, size 4 - let misc_select = u32::from_le_bytes(<[u8; 4]>::try_from(take(4)?)?); - - // off 68, size 28 - let _reserved = take(28)?; - - // off 96, size 16 - let attributes = <[u8; 16]>::try_from(take(16)?)?; - - // off 112, size 32 - let mr_enclave = <[u8; 32]>::try_from(take(32)?)?; - - // off 144, size 32 - let _reserved = take(32)?; - - // off 176, size 32 - let mr_signer = <[u8; 32]>::try_from(take(32)?)?; - - // off 208, size 96 - let _reserved = take(96)?; - - // off 304, size 2 - let isv_prod_id = u16::from_le_bytes(<[u8; 2]>::try_from(take(2)?)?); - - // off 306, size 2 - let isv_svn = u16::from_le_bytes(<[u8; 2]>::try_from(take(2)?)?); - - // off 308, size 60 - let _reserved = take(60)?; - - // off 368, size 64 - let mut report_data = [0u8; 64]; - let _report_data = take(64)?; - let mut _it = _report_data.iter(); - for i in report_data.iter_mut() { - *i = *_it.next().ok_or_else(|| anyhow!("Quote parsing error."))?; - } + // off 48, size 384 + let isv_enclave_report = SgxEnclaveReport::parse_from(take(384)?)?; ensure!(pos == bytes.len(), "Quote parsing error."); Ok(Self { version, - signature_type, gid, isv_svn_qe, isv_svn_pce, qe_vendor_id, user_data, - report_body: SgxReport { - cpu_svn, - misc_select, - attributes, - mr_enclave, - mr_signer, - isv_prod_id, - isv_svn, - report_data, - }, + isv_enclave_report, }) } } @@ -212,7 +260,7 @@ impl SgxQuoteBody { pub struct AttestationReport { pub freshness: Duration, pub sgx_quote_status: SgxQuoteStatus, - pub sgx_quote_body: SgxQuoteBody, + pub sgx_quote_body: SgxQuote, } impl AttestationReport { @@ -232,7 +280,7 @@ impl AttestationReport { let payload: Vec = ((sgx_ra_cert_ext.0).1).0; - let report: IasReport = serde_json::from_slice(&payload)?; + let report: EndorsedAttestationReport = serde_json::from_slice(&payload)?; let signing_cert = webpki::EndEntityCert::from(&report.signing_cert)?; let mut root_store = rustls::RootCertStore::empty(); @@ -295,7 +343,7 @@ impl AttestationReport { .as_str() .ok_or_else(|| Error::new(AttestationError::ReportError))?; let quote_raw = base64::decode("e_encoded.as_bytes())?; - SgxQuoteBody::parse_from(quote_raw.as_slice())? + SgxQuote::parse_from(quote_raw.as_slice())? }; let raw_pub_k = pub_k.to_bytes(); @@ -311,7 +359,7 @@ impl AttestationReport { // We only accept the uncompressed form here. let is_uncompressed = raw_pub_k[0] == 4; let pub_k = &raw_pub_k.as_slice()[1..]; - if !is_uncompressed || pub_k != &sgx_quote_body.report_body.report_data[..] { + if !is_uncompressed || pub_k != &sgx_quote_body.isv_enclave_report.report_data[..] { bail!(AttestationError::ReportError); } diff --git a/attestation/src/verifier.rs b/attestation/src/verifier.rs index d707f0d3f..8cfac144b 100644 --- a/attestation/src/verifier.rs +++ b/attestation/src/verifier.rs @@ -46,8 +46,14 @@ impl AttestationReportVerifier { fn verify_measures(&self, attestation_report: &AttestationReport) -> bool { debug!("verify measures"); - let this_mr_signer = attestation_report.sgx_quote_body.report_body.mr_signer; - let this_mr_enclave = attestation_report.sgx_quote_body.report_body.mr_enclave; + let this_mr_signer = attestation_report + .sgx_quote_body + .isv_enclave_report + .mr_signer; + let this_mr_enclave = attestation_report + .sgx_quote_body + .isv_enclave_report + .mr_enclave; self.accepted_enclave_attrs.iter().any(|a| { a.measurement.mr_signer == this_mr_signer && a.measurement.mr_enclave == this_mr_enclave diff --git a/binder/Enclave.edl b/binder/Enclave.edl index 16fd41318..371821a48 100644 --- a/binder/Enclave.edl +++ b/binder/Enclave.edl @@ -40,23 +40,18 @@ enclave { include "sgx_quote.h" untrusted { - sgx_status_t ocall_sgx_init_quote([out] sgx_target_info_t *p_target_info, - [out] sgx_epid_group_id_t *p_gid); - int ocall_sgx_get_ias_socket(); - sgx_status_t ocall_sgx_calc_quote_size([in, size=sig_rl_size] uint8_t * p_sig_rl, - uint32_t sig_rl_size, - [out] uint32_t *p_quote_size); + sgx_status_t ocall_sgx_init_quote([out] sgx_att_key_id_t *p_att_key_id, + [out] sgx_target_info_t *p_target_info); + + sgx_status_t ocall_sgx_get_quote_size([in] sgx_att_key_id_t *p_att_key_id, + [out] uint32_t *p_quote_size); sgx_status_t ocall_sgx_get_quote([in] sgx_report_t *p_report, - sgx_quote_sign_type_t quote_type, - [in] sgx_spid_t *p_spid, - [in] sgx_quote_nonce_t *p_nonce, - [in, size=sig_rl_size] uint8_t *p_sig_rl, - uint32_t sig_rl_size, - [out] sgx_report_t *p_qe_report, - [out, size=quote_size] sgx_quote_t *p_quote, + [in] sgx_att_key_id_t *p_att_key_id, + [in, out] sgx_qe_report_info_t *p_qe_report_info, + [out, size=quote_size] uint8_t *p_quote, uint32_t quote_size); }; }; diff --git a/binder/src/ocall.rs b/binder/src/ocall.rs index c3592dc8e..b8785e8e3 100644 --- a/binder/src/ocall.rs +++ b/binder/src/ocall.rs @@ -18,27 +18,30 @@ use sgx_types::*; use std::net::TcpStream; use std::os::unix::io::IntoRawFd; +use std::ptr; -#[link(name = "sgx_uae_service")] +#[link(name = "sgx_quote_ex")] extern "C" { - fn sgx_init_quote( - p_target_info: *mut sgx_target_info_t, - p_gid: *mut sgx_epid_group_id_t, + fn sgx_select_att_key_id( + p_att_key_id_list: *const u8, + att_key_idlist_size: u32, + p_att_key_id: *mut sgx_att_key_id_t, ) -> sgx_status_t; - fn sgx_calc_quote_size( - p_sig_rl: *const u8, - sig_rl_size: u32, + fn sgx_init_quote_ex( + p_att_key_id: *const sgx_att_key_id_t, + p_qe_target_info: *mut sgx_target_info_t, + p_pub_key_id_size: *mut usize, + p_pub_key_id: *mut u8, + ) -> sgx_status_t; + fn sgx_get_quote_size_ex( + p_att_key_id: *const sgx_att_key_id_t, p_quote_size: *mut u32, ) -> sgx_status_t; - fn sgx_get_quote( - p_report: *const sgx_report_t, - quote_type: sgx_quote_sign_type_t, - p_spid: *const sgx_spid_t, - p_nonce: *const sgx_quote_nonce_t, - p_sig_rl: *const u8, - sig_rl_size: u32, - p_qe_report: *mut sgx_report_t, - p_quote: *mut sgx_quote_t, + fn sgx_get_quote_ex( + p_isv_enclave_report: *const sgx_report_t, + p_att_key_id: *const sgx_att_key_id_t, + p_qe_report: *mut sgx_qe_report_info_t, + p_quote: *mut u8, quote_size: u32, ) -> sgx_status_t; } @@ -54,43 +57,65 @@ pub extern "C" fn ocall_sgx_get_ias_socket() -> i32 { #[no_mangle] pub extern "C" fn ocall_sgx_init_quote( - p_target_info: *mut sgx_target_info_t, - p_gid: *mut sgx_epid_group_id_t, + p_att_key_id: *mut sgx_att_key_id_t, + p_qe_target_info: *mut sgx_target_info_t, ) -> sgx_status_t { - unsafe { sgx_init_quote(p_target_info, p_gid) } + let ret = unsafe { sgx_select_att_key_id(ptr::null(), 0, p_att_key_id) }; + + if ret != sgx_status_t::SGX_SUCCESS { + return ret; + } + + // First call to sgx_init_quote_ex to get att_pub_key_id_size + let mut att_pub_key_id_size = 0usize; + let ret = unsafe { + sgx_init_quote_ex( + p_att_key_id, + p_qe_target_info, + &mut att_pub_key_id_size as _, + ptr::null_mut(), + ) + }; + + if ret != sgx_status_t::SGX_SUCCESS { + return ret; + } + + // Second call to sgx_init_quote_ex to get att_pub_key_id + // At this point, it is unknown what att_pub_key_id is used for. + let mut att_pub_key_id: Vec = vec![0u8; att_pub_key_id_size]; + unsafe { + sgx_init_quote_ex( + p_att_key_id, + p_qe_target_info, + &mut att_pub_key_id_size as _, + att_pub_key_id.as_mut_ptr(), + ) + } } #[no_mangle] -pub extern "C" fn ocall_sgx_calc_quote_size( - p_sig_rl: *const u8, - sig_rl_size: u32, +pub extern "C" fn ocall_sgx_get_quote_size( + p_att_key_id: *const sgx_att_key_id_t, p_quote_size: *mut u32, ) -> sgx_status_t { - unsafe { sgx_calc_quote_size(p_sig_rl, sig_rl_size, p_quote_size) } + unsafe { sgx_get_quote_size_ex(p_att_key_id as _, p_quote_size) } } #[no_mangle] pub extern "C" fn ocall_sgx_get_quote( p_report: *const sgx_report_t, - quote_type: sgx_quote_sign_type_t, - p_spid: *const sgx_spid_t, - p_nonce: *const sgx_quote_nonce_t, - p_sig_rl: *const u8, - sig_rl_size: u32, - p_qe_report: *mut sgx_report_t, - p_quote: *mut sgx_quote_t, + p_att_key_id: *const sgx_att_key_id_t, + p_qe_report_info: *mut sgx_qe_report_info_t, + p_quote: *mut u8, quote_size: u32, ) -> sgx_status_t { unsafe { - sgx_get_quote( + sgx_get_quote_ex( p_report, - quote_type, - p_spid, - p_nonce, - p_sig_rl, - sig_rl_size, - p_qe_report, - p_quote, + p_att_key_id, + p_qe_report_info, + p_quote as _, quote_size, ) } diff --git a/services/authentication/enclave/src/lib.rs b/services/authentication/enclave/src/lib.rs index 789fe9c3c..ac77aa1b0 100644 --- a/services/authentication/enclave/src/lib.rs +++ b/services/authentication/enclave/src/lib.rs @@ -28,7 +28,7 @@ use rand::RngCore; use std::prelude::v1::*; use std::sync::Arc; use std::thread; -use teaclave_attestation::RemoteAttestation; +use teaclave_attestation::{AttestationConfig, RemoteAttestation}; use teaclave_ipc::proto::{ ECallCommand, FinalizeEnclaveInput, FinalizeEnclaveOutput, InitEnclaveInput, InitEnclaveOutput, StartServiceInput, StartServiceOutput, @@ -114,7 +114,11 @@ fn handle_start_service(args: &StartServiceInput) -> Result let internal_listen_address = args.config.internal_endpoints.authentication.listen_address; let ias_config = args.config.ias.as_ref().unwrap(); let attestation = Arc::new( - RemoteAttestation::generate_and_endorse(&ias_config.ias_key, &ias_config.ias_spid).unwrap(), + RemoteAttestation::generate_and_endorse(&AttestationConfig::ias( + &ias_config.ias_key, + &ias_config.ias_spid, + )) + .unwrap(), ); let database = user_db::Database::open()?; let mut api_jwt_secret = vec![0; user_info::JWT_SECRET_LEN]; diff --git a/services/database/enclave/src/lib.rs b/services/database/enclave/src/lib.rs index 5d63d8eca..a814e4e2e 100644 --- a/services/database/enclave/src/lib.rs +++ b/services/database/enclave/src/lib.rs @@ -36,7 +36,7 @@ use teaclave_ipc::{handle_ecall, register_ecall_handler}; use teaclave_service_enclave_utils::ServiceEnclave; use rusty_leveldb::DB; -use teaclave_attestation::RemoteAttestation; +use teaclave_attestation::{AttestationConfig, RemoteAttestation}; use teaclave_proto::teaclave_database_service::{ TeaclaveDatabaseRequest, TeaclaveDatabaseResponse, }; @@ -55,8 +55,11 @@ fn handle_start_service(args: &StartServiceInput) -> Result debug!("handle_start_service"); let listen_address = args.config.internal_endpoints.dbs.listen_address; let ias_config = args.config.ias.as_ref().unwrap(); - let attestation = - RemoteAttestation::generate_and_endorse(&ias_config.ias_key, &ias_config.ias_spid).unwrap(); + let attestation = RemoteAttestation::generate_and_endorse(&AttestationConfig::ias( + &ias_config.ias_key, + &ias_config.ias_spid, + )) + .unwrap(); let config = SgxTrustedTlsServerConfig::new_without_verifier( &attestation.cert, &attestation.private_key, diff --git a/services/execution/enclave/src/lib.rs b/services/execution/enclave/src/lib.rs index ebc972145..086c73396 100644 --- a/services/execution/enclave/src/lib.rs +++ b/services/execution/enclave/src/lib.rs @@ -37,7 +37,7 @@ use teaclave_ipc::{handle_ecall, register_ecall_handler}; use teaclave_service_enclave_utils::ServiceEnclave; -use teaclave_attestation::RemoteAttestation; +use teaclave_attestation::{AttestationConfig, RemoteAttestation}; use teaclave_proto::teaclave_execution_service::{ TeaclaveExecutionRequest, TeaclaveExecutionResponse, }; @@ -55,8 +55,11 @@ register_ecall_handler!( fn handle_start_service(args: &StartServiceInput) -> Result { let listen_address = args.config.internal_endpoints.execution.listen_address; let ias_config = args.config.ias.as_ref().unwrap(); - let attestation = - RemoteAttestation::generate_and_endorse(&ias_config.ias_key, &ias_config.ias_spid).unwrap(); + let attestation = RemoteAttestation::generate_and_endorse(&AttestationConfig::ias( + &ias_config.ias_key, + &ias_config.ias_spid, + )) + .unwrap(); let config = SgxTrustedTlsServerConfig::new_without_verifier( &attestation.cert, &attestation.private_key, diff --git a/services/frontend/enclave/src/lib.rs b/services/frontend/enclave/src/lib.rs index f401326ac..f4f630193 100644 --- a/services/frontend/enclave/src/lib.rs +++ b/services/frontend/enclave/src/lib.rs @@ -25,7 +25,7 @@ extern crate log; use anyhow::Result; use std::prelude::v1::*; -use teaclave_attestation::RemoteAttestation; +use teaclave_attestation::{AttestationConfig, RemoteAttestation}; use teaclave_ipc::proto::{ ECallCommand, FinalizeEnclaveInput, FinalizeEnclaveOutput, InitEnclaveInput, InitEnclaveOutput, StartServiceInput, StartServiceOutput, @@ -45,8 +45,11 @@ fn handle_start_service(args: &StartServiceInput) -> Result debug!("handle_start_service"); let listen_address = args.config.api_endpoints.frontend.listen_address; let ias_config = args.config.ias.as_ref().unwrap(); - let attestation = - RemoteAttestation::generate_and_endorse(&ias_config.ias_key, &ias_config.ias_spid).unwrap(); + let attestation = RemoteAttestation::generate_and_endorse(&AttestationConfig::ias( + &ias_config.ias_key, + &ias_config.ias_spid, + )) + .unwrap(); let config = SgxTrustedTlsServerConfig::new_without_verifier( &attestation.cert, &attestation.private_key,