Skip to content

Commit

Permalink
verifier: combined duplicated dcap implementation
Browse files Browse the repository at this point in the history
Separated duplicated ecdsa quote verification code used for dcap quote data.

Signed-off-by: Pawel Proskurnicki <pawel.proskurnicki@intel.com>
  • Loading branch information
pawelpros authored and Xynnn007 committed Feb 18, 2025
1 parent 3888739 commit 9d86e61
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 330 deletions.
4 changes: 2 additions & 2 deletions deps/verifier/src/az_tdx_vtpm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

use super::az_snp_vtpm::{extend_claim, verify_init_data};
use super::tdx::claims::generate_parsed_claim;
use super::tdx::quote::{ecdsa_quote_verification, parse_tdx_quote, Quote as TdQuote};
use super::tdx::quote::{parse_tdx_quote, Quote as TdQuote};
use super::{TeeEvidenceParsedClaim, Verifier};
use crate::tdx::extend_using_custom_claims;
use crate::intel_dcap::{ecdsa_quote_verification, extend_using_custom_claims};
use crate::{InitDataHash, ReportData};
use anyhow::{bail, Context, Result};
use async_trait::async_trait;
Expand Down
195 changes: 195 additions & 0 deletions deps/verifier/src/intel_dcap/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
use anyhow::{anyhow, bail};
use intel_tee_quote_verification_rs::{
quote3_error_t, sgx_ql_qv_result_t, sgx_ql_qv_supplemental_t, sgx_ql_request_policy_t,
sgx_qv_set_enclave_load_policy, tee_get_supplemental_data_version_and_size,
tee_qv_get_collateral, tee_supp_data_descriptor_t, tee_verify_quote,
};
use log::{debug, warn};
use serde_json::{Map, Value};
use std::ffi::CStr;
use std::mem;
use std::os::raw::c_char;
use std::time::{Duration, SystemTime};
use crate::TeeEvidenceParsedClaim;

pub async fn ecdsa_quote_verification(quote: &[u8]) -> anyhow::Result<Map<String, Value>> {
let mut supp_data: sgx_ql_qv_supplemental_t = Default::default();
let mut supp_data_desc = tee_supp_data_descriptor_t {
major_version: 0,
data_size: 0,
p_data: &mut supp_data as *mut sgx_ql_qv_supplemental_t as *mut u8,
};

// Call DCAP quote verify library to set QvE loading policy to multi-thread
// We only need to set the policy once; otherwise, it will return the error code 0xe00c (SGX_QL_UNSUPPORTED_LOADING_POLICY)
static INIT: std::sync::Once = std::sync::Once::new();
INIT.call_once(|| {
match sgx_qv_set_enclave_load_policy(
sgx_ql_request_policy_t::SGX_QL_PERSISTENT_QVE_MULTI_THREAD,
) {
quote3_error_t::SGX_QL_SUCCESS => {
debug!("Info: sgx_qv_set_enclave_load_policy successfully returned.")
}
err => warn!(
"Error: sgx_qv_set_enclave_load_policy failed: {:#04x}",
err as u32
),
}
});

match tee_get_supplemental_data_version_and_size(quote) {
Ok((supp_ver, supp_size)) => {
if supp_size == mem::size_of::<sgx_ql_qv_supplemental_t>() as u32 {
debug!("tee_get_quote_supplemental_data_version_and_size successfully returned.");
debug!(
"Info: latest supplemental data major version: {}, minor version: {}, size: {}",
u16::from_be_bytes(supp_ver.to_be_bytes()[..2].try_into()?),
u16::from_be_bytes(supp_ver.to_be_bytes()[2..].try_into()?),
supp_size,
);
supp_data_desc.data_size = supp_size;
} else {
warn!("Quote supplemental data size is different between DCAP QVL and QvE, please make sure you installed DCAP QVL and QvE from same release.")
}
}
Err(e) => bail!(
"tee_get_quote_supplemental_data_size failed: {:#04x}",
e as u32
),
}

// get collateral
let collateral = match tee_qv_get_collateral(quote) {
Ok(c) => {
debug!("tee_qv_get_collateral successfully returned.");
Some(c)
}
Err(e) => {
warn!("tee_qv_get_collateral failed: {:#04x}", e as u32);
None
}
};

// set current time. This is only for sample purposes, in production mode a trusted time should be used.
let current_time = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap_or(Duration::ZERO)
.as_secs() as i64;

let p_supplemental_data = match supp_data_desc.data_size {
0 => None,
_ => Some(&mut supp_data_desc),
};

// call DCAP quote verify library for quote verification
let (collateral_expiration_status, quote_verification_result) = tee_verify_quote(
quote,
collateral.as_ref(),
current_time,
None,
p_supplemental_data,
)
.map_err(|e| anyhow!("tee_verify_quote failed: {:#04x}", e as u32))?;

debug!("tee_verify_quote successfully returned.");


match quote_verification_result {
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK
| sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_NEEDED
| sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE
| sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED
| sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED
| sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED => {
let claims_map = prepare_custom_claims_map(
&mut supp_data,
collateral_expiration_status,
quote_verification_result,
);

Ok(claims_map)
}
_ => {
bail!(
"Verification completed with Terminal result: {:x}",
quote_verification_result as u32
);
}
}
}

pub fn extend_using_custom_claims(
claim: &mut TeeEvidenceParsedClaim,
custom: Map<String, Value>,
) -> anyhow::Result<()> {
let Value::Object(ref mut map) = claim else {
bail!("failed to extend the claim, not an object");
};
map.extend(custom);
anyhow::Ok(())
}

fn prepare_custom_claims_map(
supp_data: &mut sgx_ql_qv_supplemental_t,
collateral_expiration_status: u32,
quote_verification_result: sgx_ql_qv_result_t,
) -> Map<String, Value> {
let mut claims_map = Map::new();

let tcb_status_desc = SgxQlQvResultWrapper(quote_verification_result).as_str();

let advisory_ids: Vec<Value> = get_sa_list(&supp_data.sa_list)
.iter()
.map(|s| Value::String(s.to_string()))
.collect();

claims_map.insert(
"tcb_status".to_string(),
Value::String(tcb_status_desc.to_string()),
);
claims_map.insert(
"collateral_expiration_status".to_string(),
Value::String(collateral_expiration_status.to_string()),
);
claims_map.insert("advisory_ids".to_string(), Value::Array(advisory_ids));
claims_map
}

struct SgxQlQvResultWrapper(pub sgx_ql_qv_result_t);

impl SgxQlQvResultWrapper {
pub fn as_str(&self) -> &'static str {
match self.0 {
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK => "OK",
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_MIN => "Min",
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE => "OutOfDate",
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED => {
"OutOfDateConfigurationNeeded"
}
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_INVALID_SIGNATURE => "InvalidSignature",
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_REVOKED => "Revoked",
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_UNSPECIFIED => "Unspecified",
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED => "SoftwareHardeningNeeded",
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED => {
"ConfigurationAndSoftwareHardeningNeeded"
}
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_TD_RELAUNCH_ADVISED => "TdRelaunchAdvised",
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_TD_RELAUNCH_ADVISED_CONFIG_NEEDED => {
"TdRelaunchAdvisedConfigurationNeeded"
}
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_MAX => "Max",
}
}
}

fn get_sa_list(sa_list: &[c_char; 320]) -> Vec<String> {
let c_str = unsafe { CStr::from_ptr(sa_list.as_ptr()) };

let advisory_ids = c_str.to_string_lossy();

if advisory_ids.is_empty() {
return vec![];
}

advisory_ids.split(',').map(|s| s.to_string()).collect()
}
3 changes: 3 additions & 0 deletions deps/verifier/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ pub mod cca;
#[cfg(feature = "se-verifier")]
pub mod se;

#[cfg(any(feature = "az-tdx-vtpm-verifier", feature = "tdx-verifier", feature = "sgx-verifier"))]
pub mod intel_dcap;

pub fn to_verifier(tee: &Tee) -> Result<Box<dyn Verifier + Send + Sync>> {
match tee {
Tee::Sev => todo!(),
Expand Down
137 changes: 7 additions & 130 deletions deps/verifier/src/sgx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,22 @@
// SPDX-License-Identifier: Apache-2.0
//

use std::{
mem,
time::{Duration, SystemTime},
};

use anyhow::*;
use async_trait::async_trait;
use base64::Engine;
use intel_tee_quote_verification_rs::{
quote3_error_t, sgx_ql_qv_result_t, sgx_ql_qv_supplemental_t, sgx_ql_request_policy_t,
sgx_qv_set_enclave_load_policy, tee_get_supplemental_data_version_and_size,
tee_qv_get_collateral, tee_supp_data_descriptor_t, tee_verify_quote,
};
use log::{debug, warn};
use log::debug;
use scroll::Pread;
use serde::{Deserialize, Serialize};

use crate::{regularize_data, InitDataHash, ReportData};

use self::types::sgx_quote3_t;

use super::{TeeEvidenceParsedClaim, Verifier};
use crate::intel_dcap::{ecdsa_quote_verification, extend_using_custom_claims};
use crate::{regularize_data, InitDataHash, ReportData};

#[allow(non_camel_case_types)]
mod types;

mod claims;

pub const QUOTE_SIZE: usize = 436;

#[derive(Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -79,7 +67,7 @@ async fn verify_evidence(

let quote_bin = base64::engine::general_purpose::STANDARD.decode(evidence.quote)?;

ecdsa_quote_verification(&quote_bin)
let custom_claims = ecdsa_quote_verification(&quote_bin)
.await
.context("Evidence's identity verification error.")?;

Expand All @@ -101,121 +89,10 @@ async fn verify_evidence(
}
}

claims::generate_parsed_claims(quote)
}

async fn ecdsa_quote_verification(quote: &[u8]) -> Result<()> {
let mut supp_data: sgx_ql_qv_supplemental_t = Default::default();
let mut supp_data_desc = tee_supp_data_descriptor_t {
major_version: 0,
data_size: 0,
p_data: &mut supp_data as *mut sgx_ql_qv_supplemental_t as *mut u8,
};

// Call DCAP quote verify library to set QvE loading policy to multi-thread
// We only need to set the policy once; otherwise, it will return the error code 0xe00c (SGX_QL_UNSUPPORTED_LOADING_POLICY)
static INIT: std::sync::Once = std::sync::Once::new();
INIT.call_once(|| {
match sgx_qv_set_enclave_load_policy(
sgx_ql_request_policy_t::SGX_QL_PERSISTENT_QVE_MULTI_THREAD,
) {
quote3_error_t::SGX_QL_SUCCESS => {
debug!("Info: sgx_qv_set_enclave_load_policy successfully returned.")
}
err => warn!(
"Error: sgx_qv_set_enclave_load_policy failed: {:#04x}",
err as u32
),
}
});

match tee_get_supplemental_data_version_and_size(quote) {
std::result::Result::Ok((supp_ver, supp_size)) => {
if supp_size == mem::size_of::<sgx_ql_qv_supplemental_t>() as u32 {
debug!("tee_get_quote_supplemental_data_version_and_size successfully returned.");
debug!(
"Info: latest supplemental data major version: {}, minor version: {}, size: {}",
u16::from_be_bytes(supp_ver.to_be_bytes()[..2].try_into()?),
u16::from_be_bytes(supp_ver.to_be_bytes()[2..].try_into()?),
supp_size,
);
supp_data_desc.data_size = supp_size;
} else {
warn!("Quote supplemental data size is different between DCAP QVL and QvE, please make sure you installed DCAP QVL and QvE from same release.")
}
}
Err(e) => bail!(
"tee_get_quote_supplemental_data_size failed: {:#04x}",
e as u32
),
}

// get collateral
let collateral = match tee_qv_get_collateral(quote) {
std::result::Result::Ok(c) => {
debug!("tee_qv_get_collateral successfully returned.");
Some(c)
}
Err(e) => {
warn!("tee_qv_get_collateral failed: {:#04x}", e as u32);
None
}
};

// set current time. This is only for sample purposes, in production mode a trusted time should be used.
//
let current_time = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap_or(Duration::ZERO)
.as_secs() as i64;

let p_supplemental_data = match supp_data_desc.data_size {
0 => None,
_ => Some(&mut supp_data_desc),
};

// call DCAP quote verify library for quote verification
let (collateral_expiration_status, quote_verification_result) = tee_verify_quote(
quote,
collateral.as_ref(),
current_time,
None,
p_supplemental_data,
)
.map_err(|e| anyhow!("tee_verify_quote failed: {:#04x}", e as u32))?;

debug!("tee_verify_quote successfully returned.");

// check verification result
match quote_verification_result {
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK => {
// check verification collateral expiration status
// this value should be considered in your own attestation/verification policy
if collateral_expiration_status == 0 {
debug!("Verification completed successfully.");
} else {
warn!("Verification completed, but collateral is out of date based on 'expiration_check_date' you provided.");
}
}
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_NEEDED
| sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE
| sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED
| sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED
| sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED => {
warn!(
"Verification completed with Non-terminal result: {:x}",
quote_verification_result as u32
);
}
_ => {
bail!(
"Verification completed with Terminal result: {:x}",
quote_verification_result as u32
);
}
}
let mut claim = claims::generate_parsed_claims(quote)?;
extend_using_custom_claims(&mut claim, custom_claims)?;

Ok(())
Ok(claim)
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit 9d86e61

Please sign in to comment.