use async_trait::async_trait;
use dcap_qvl::quote::{Quote, Report};
use crate::VerifyError;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TdxMeasurements {
pub report_data: [u8; 64],
pub mr_td: [u8; 48],
pub rtmr0: [u8; 48],
pub rtmr1: [u8; 48],
pub rtmr2: [u8; 48],
pub rtmr3: [u8; 48],
pub td_attributes: [u8; 8],
pub tcb_status: Option<String>,
pub tcb_advisory_ids: Vec<String>,
}
impl TdxMeasurements {
pub fn debug_disabled(&self) -> bool {
self.td_attributes[0] & 0x01 == 0
}
}
fn measurements_from_report(report: &Report) -> Result<TdxMeasurements, VerifyError> {
let td = match report {
Report::TD10(r) => r,
Report::TD15(r) => &r.base,
Report::SgxEnclave(_) => {
return Err(VerifyError::Malformed {
what: "tdx quote",
detail: "expected a TDX (TD10/TD15) quote, got an SGX enclave report".to_string(),
});
}
};
Ok(TdxMeasurements {
report_data: td.report_data,
mr_td: td.mr_td,
rtmr0: td.rt_mr0,
rtmr1: td.rt_mr1,
rtmr2: td.rt_mr2,
rtmr3: td.rt_mr3,
td_attributes: td.td_attributes,
tcb_status: None,
tcb_advisory_ids: Vec::new(),
})
}
pub fn parse_tdx_quote(raw: &[u8]) -> Result<TdxMeasurements, VerifyError> {
let quote = Quote::parse(raw).map_err(|e| VerifyError::Malformed {
what: "tdx quote",
detail: e.to_string(),
})?;
measurements_from_report("e.report)
}
pub const PHALA_PCCS_URL: &str = dcap_qvl::PHALA_PCCS_URL;
pub async fn verify_tdx_quote(
raw: &[u8],
pccs_url: &str,
now_unix: u64,
) -> Result<TdxMeasurements, VerifyError> {
let collateral = dcap_qvl::collateral::get_collateral(pccs_url, raw)
.await
.map_err(|e| VerifyError::Transport {
what: "dcap collateral",
source: e.to_string().into(),
})?;
let verified =
dcap_qvl::verify::rustcrypto::verify(raw, &collateral, now_unix).map_err(|e| {
VerifyError::Malformed {
what: "tdx quote verification",
detail: e.to_string(),
}
})?;
let mut measurements = measurements_from_report(&verified.report)?;
measurements.tcb_status = Some(verified.status);
measurements.tcb_advisory_ids = verified.advisory_ids;
Ok(measurements)
}
#[async_trait]
pub trait QuoteVerifier: Send + Sync {
async fn measurements(
&self,
raw_quote: &[u8],
now_unix: u64,
) -> Result<TdxMeasurements, VerifyError>;
fn is_authenticated(&self) -> bool;
}
pub struct DcapQuoteVerifier {
pub pccs_url: String,
}
impl DcapQuoteVerifier {
pub fn new(pccs_url: impl Into<String>) -> Self {
Self {
pccs_url: pccs_url.into(),
}
}
}
impl Default for DcapQuoteVerifier {
fn default() -> Self {
Self::new(PHALA_PCCS_URL)
}
}
#[async_trait]
impl QuoteVerifier for DcapQuoteVerifier {
async fn measurements(
&self,
raw_quote: &[u8],
now_unix: u64,
) -> Result<TdxMeasurements, VerifyError> {
verify_tdx_quote(raw_quote, &self.pccs_url, now_unix).await
}
fn is_authenticated(&self) -> bool {
true
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::near::report::AttestationReport;
const FIXTURE: &str = include_str!("../../tests/fixtures/near_report.json");
fn fixture_quote() -> Vec<u8> {
let r: AttestationReport = serde_json::from_str(FIXTURE).unwrap();
hex::decode(&r.model_attestations[0].intel_quote).unwrap()
}
#[test]
fn parse_matches_the_reports_self_declared_tcb_info() {
let raw: serde_json::Value = serde_json::from_str(FIXTURE).unwrap();
let ti = &raw["model_attestations"][0]["info"]["tcb_info"];
let m = parse_tdx_quote(&fixture_quote()).expect("fixture quote parses");
assert_eq!(hex::encode(m.mr_td), ti["mrtd"].as_str().unwrap());
assert_eq!(hex::encode(m.rtmr0), ti["rtmr0"].as_str().unwrap());
assert_eq!(hex::encode(m.rtmr1), ti["rtmr1"].as_str().unwrap());
assert_eq!(hex::encode(m.rtmr2), ti["rtmr2"].as_str().unwrap());
assert_eq!(hex::encode(m.rtmr3), ti["rtmr3"].as_str().unwrap());
}
#[test]
fn parse_exposes_report_data_and_debug_off() {
let m = parse_tdx_quote(&fixture_quote()).unwrap();
assert!(hex::encode(m.report_data).starts_with("bb4d2e7ffe98eefcd9690e2139be41e92b95e333"));
assert!(m.debug_disabled());
}
#[test]
fn parse_rejects_garbage_bytes() {
let err = parse_tdx_quote(b"not a quote").unwrap_err();
assert!(matches!(err, VerifyError::Malformed { .. }));
}
#[tokio::test]
#[ignore = "fetches DCAP collateral from a live PCCS; run manually with network"]
async fn full_dcap_verification_against_live_pccs() {
let now = 1_749_800_000; let m = verify_tdx_quote(&fixture_quote(), PHALA_PCCS_URL, now)
.await
.expect("live DCAP verification succeeds");
assert!(m.debug_disabled());
}
}