diff --git a/Cargo.lock b/Cargo.lock index 4fcde3d19..616a43ee6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2712,6 +2712,7 @@ dependencies = [ "anyhow", "async-trait", "attestation-service", + "az-cvm-vtpm 0.7.0", "base64 0.22.1", "cfg-if", "clap 4.5.4", diff --git a/kbs/Cargo.toml b/kbs/Cargo.toml index b0f2e2976..fc0ae8109 100644 --- a/kbs/Cargo.toml +++ b/kbs/Cargo.toml @@ -34,7 +34,7 @@ coco-as-builtin-no-verifier = ["coco-as", "attestation-service/rvps-builtin"] coco-as-grpc = ["coco-as", "mobc", "tonic", "tonic-build", "prost"] # Use Intel TA as backend attestation service -intel-trust-authority-as = ["as", "reqwest", "resource"] +intel-trust-authority-as = ["as", "reqwest", "resource", "az-cvm-vtpm"] # Use pure rust crypto stack for KBS rustls = ["actix-web/rustls", "dep:rustls", "dep:rustls-pemfile"] @@ -82,6 +82,7 @@ tokio.workspace = true tonic = { workspace = true, optional = true } uuid = { version = "1.2.2", features = ["serde", "v4"] } openssl = { version = "0.10.46", optional = true } +az-cvm-vtpm = { version = "0.7.0", default-features = false, optional = true } [dev-dependencies] tempfile.workspace = true diff --git a/kbs/src/attestation/intel_trust_authority/mod.rs b/kbs/src/attestation/intel_trust_authority/mod.rs index 6ec6289eb..beffc0eb9 100644 --- a/kbs/src/attestation/intel_trust_authority/mod.rs +++ b/kbs/src/attestation/intel_trust_authority/mod.rs @@ -9,23 +9,35 @@ use crate::token::{ }; use anyhow::*; use async_trait::async_trait; +use az_cvm_vtpm::hcl::HclReport; use base64::{engine::general_purpose::STANDARD, Engine}; use kbs_types::{Attestation, Tee}; use reqwest::header::{ACCEPT, CONTENT_TYPE}; use serde::{Deserialize, Serialize}; +use serde_json::from_value; use serde_json::json; +pub const BASE_AS_ADDR: &str = "/appraisal/v1/attest"; + #[derive(Deserialize, Debug)] -struct IntelTrustAuthorityTeeEvidence { +struct ItaTeeEvidence { #[serde(skip)] _cc_eventlog: Option, quote: String, } +#[derive(Deserialize, Debug)] +struct AzItaTeeEvidence { + hcl_report: Vec, + td_quote: Vec, +} + #[derive(Serialize, Debug)] struct AttestReqData { quote: String, runtime_data: String, + #[serde(skip_serializing_if = "Option::is_none")] + user_data: Option, } #[derive(Deserialize, Debug)] @@ -59,15 +71,9 @@ pub struct IntelTrustAuthority { #[async_trait] impl Attest for IntelTrustAuthority { async fn verify(&self, tee: Tee, nonce: &str, attestation: &str) -> Result { - if tee != Tee::Tdx && tee != Tee::Sgx { - bail!("Intel Trust Authority: TEE {tee:?} is not supported."); - } // get quote let attestation = serde_json::from_str::(attestation) .context("Failed to deserialize Attestation request")?; - let evidence = - serde_json::from_value::(attestation.tee_evidence) - .context("Failed to deserialize TEE Evidence")?; let runtime_data = json!({ "tee-pubkey": attestation.tee_pubkey, @@ -75,20 +81,53 @@ impl Attest for IntelTrustAuthority { }) .to_string(); - // construct attest request data - let req_data = AttestReqData { - quote: evidence.quote, - runtime_data: STANDARD.encode(runtime_data), + // construct attest request data and attestation url + let (req_data, att_url) = match tee { + Tee::AzTdxVtpm => { + let att_url = format!("{}{}/azure/tdxvm", &self.config.base_url, BASE_AS_ADDR); + + let evidence = from_value::(attestation.tee_evidence) + .context("Failed to deserialize TEE Evidence")?; + + let hcl_report = HclReport::new(evidence.hcl_report.clone())?; + + let req_data = AttestReqData { + quote: STANDARD.encode(evidence.td_quote), + runtime_data: STANDARD.encode(hcl_report.var_data()), + user_data: Some(STANDARD.encode(runtime_data)), + }; + + (req_data, att_url) + } + Tee::Tdx | Tee::Sgx => { + let att_url = format!("{}{}", &self.config.base_url, BASE_AS_ADDR); + + let evidence = from_value::(attestation.tee_evidence) + .context("Failed to deserialize TEE Evidence")?; + + let req_data = AttestReqData { + quote: evidence.quote, + runtime_data: STANDARD.encode(runtime_data), + user_data: None, + }; + + (req_data, att_url) + } + _ => { + bail!("Intel Trust Authority: TEE {tee:?} is not supported."); + } }; let attest_req_body = serde_json::to_string(&req_data) .context("Failed to serialize attestation request body")?; // send attest request - log::info!("post attestation request ..."); + log::info!("POST attestation request ..."); + log::debug!("Attestation URL: {:?}", &att_url); + let client = reqwest::Client::new(); let resp = client - .post(format!("{}/appraisal/v1/attest", &self.config.base_url)) + .post(att_url) .header(CONTENT_TYPE, "application/json") .header(ACCEPT, "application/json") .header("x-api-key", &self.config.api_key)