Skip to content

Commit

Permalink
Sample Verifier: Support Parse TCG Eventlog
Browse files Browse the repository at this point in the history
Signed-off-by: Jiale Zhang <[email protected]>
  • Loading branch information
jialez0 authored and 訫剑 committed Jan 20, 2025
1 parent 4319292 commit 7f54949
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 23 deletions.
2 changes: 1 addition & 1 deletion attestation-service/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fn real_main() -> Result<(), String> {

println!("cargo:rustc-link-lib=python3.11");
println!("cargo:rustc-link-search=native=/usr/lib");

Ok(())
}

Expand Down
6 changes: 3 additions & 3 deletions deps/verifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ edition = "2021"

[features]
default = [ "all-verifier" ]
all-verifier = [ "tdx-verifier", "sgx-verifier", "snp-verifier", "az-snp-vtpm-verifier", "az-tdx-vtpm-verifier", "csv-verifier", "cca-verifier", "se-verifier" ]
tdx-verifier = [ "eventlog-rs", "scroll", "intel-tee-quote-verification-rs" ]
all-verifier = [ "tdx-verifier", "sgx-verifier", "snp-verifier", "cca-verifier", "se-verifier" ]
tdx-verifier = [ "scroll", "intel-tee-quote-verification-rs" ]
sgx-verifier = [ "scroll", "intel-tee-quote-verification-rs" ]
az-snp-vtpm-verifier = [ "az-snp-vtpm", "sev", "snp-verifier" ]
az-tdx-vtpm-verifier = [ "az-tdx-vtpm", "openssl", "tdx-verifier" ]
Expand All @@ -29,7 +29,7 @@ cfg-if = "1.0.0"
codicon = { version = "3.0", optional = true }
# TODO: change it to "0.1", once released.
csv-rs = { git = "https://github.com/openanolis/csv-rs", rev = "b74aa8c", optional = true }
eventlog-rs = { version = "0.1.3", optional = true }
eventlog-rs = { version = "0.1.3" }
hex.workspace = true
jsonwebkey = "0.3.5"
jsonwebtoken = { workspace = true, default-features = false, optional = true }
Expand Down
2 changes: 1 addition & 1 deletion deps/verifier/build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
fn main() {
println!("cargo:rustc-link-lib=python3.11");
println!("cargo:rustc-link-search=native=/usr/lib");
}
}
76 changes: 71 additions & 5 deletions deps/verifier/src/sample/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use self::serde::{Deserialize, Serialize};
use super::*;
use async_trait::async_trait;
use base64::Engine;
use eventlog_rs::Eventlog;
use serde_json::json;

#[derive(Serialize, Deserialize, Debug)]
Expand All @@ -15,6 +16,8 @@ struct SampleTeeEvidence {

#[serde(default = "String::default")]
init_data: String,

tcg_eventlog: Option<String>,
}

#[derive(Debug, Default)]
Expand Down Expand Up @@ -73,14 +76,77 @@ async fn verify_tee_evidence(
Ok(())
}

#[derive(Clone, Serialize, Deserialize)]
struct TCGEvent {
pcr_index: u32,
event_type: String,
digest: String,
data: String,
}

// Dump the TCB status from the quote.
// Example: CPU SVN, RTMR, etc.
#[allow(unused_assignments)]
fn parse_tee_evidence(quote: &SampleTeeEvidence) -> Result<TeeEvidenceParsedClaim> {
let claims_map = json!({
"svn": quote.svn,
"report_data": quote.report_data,
"init_data": quote.init_data,
});
let mut claims_map = json!({});

if let Some(eventlog_data_base64) = &quote.tcg_eventlog {
let eventlog_data = base64::engine::general_purpose::STANDARD
.decode(eventlog_data_base64)
.context("base64 decode TCG Eventlog for sample evidence")?;
let tcg_eventlog =
Eventlog::try_from(eventlog_data).map_err(|e| anyhow!("Parse Eventlog failed: {e}"))?;
log::info!("{}", format!("{}", tcg_eventlog));

let mut parsed_eventlog = vec![];

for event_entry in tcg_eventlog.log.iter() {
let digest = hex::encode(&event_entry.digests[0].digest);
let data = match std::str::from_utf8(&event_entry.event_desc) {
Result::Ok(d) => d.to_string(),
Result::Err(_) => hex::encode(&event_entry.event_desc),
};
let parsed_entry = TCGEvent {
pcr_index: event_entry.target_measurement_registry,
event_type: event_entry.event_type.clone(),
digest,
data,
};
parsed_eventlog.push(parsed_entry);
}

claims_map = json!({
"svn": quote.svn,
"report_data": quote.report_data,
"init_data": quote.init_data,
"tcg_eventlog": parsed_eventlog,
});
} else {
claims_map = json!({
"svn": quote.svn,
"report_data": quote.report_data,
"init_data": quote.init_data,
});
}

Ok(claims_map as TeeEvidenceParsedClaim)
}

#[cfg(test)]
mod tests {
use super::*;
use std::fs;

#[test]
fn test_parse_tee_evidence() {
let sample_evidence_str = &fs::read_to_string("./test_data/sample_evidence.txt").unwrap();
let sample_evidence =
serde_json::from_str::<SampleTeeEvidence>(sample_evidence_str).unwrap();
let parsed_claim = parse_tee_evidence(&sample_evidence).unwrap();

let _ = fs::write(
"test_data/parsed_sample_evidence.txt",
serde_json::to_string(&parsed_claim).unwrap(),
);
}
}
31 changes: 18 additions & 13 deletions deps/verifier/src/tdx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,20 +133,21 @@ async fn verify_evidence(
}
};

let tdx_attestation_claims: serde_json::Value = generate_parsed_claim(quote, ccel_option, aael)? as serde_json::Value;

let tdx_attestation_claims: serde_json::Value =
generate_parsed_claim(quote, ccel_option, aael)? as serde_json::Value;

if let Some(gpu_token) = evidence.gpu_attestation_token {
pyo3::prepare_freethreaded_python();
let gpu_attestation_claims = verify_gpu_evidence(&gpu_token, GPU_POLICY_FILE_PATH)?;
let merged_claims = match (tdx_attestation_claims.clone(), gpu_attestation_claims) {
(Value::Object(mut tdx), Value::Object(gpu)) => {
tdx.extend(gpu);
Value::Object(tdx)
},
}
_ => {
warn!("Merge TDX and GPU evidence claim failed");
tdx_attestation_claims
},
}
};

Ok(merged_claims as TeeEvidenceParsedClaim)
Expand All @@ -163,18 +164,20 @@ fn verify_gpu_evidence(token: &str, policy_file: &str) -> Result<serde_json::Val
let attestation_class = attestation_module.getattr("Attestation")?;
let attestation_instance = attestation_class.call0()?;

let policy_content = std::fs::read_to_string(policy_file)
.context("Failed to read policy file")?;
let result: bool = attestation_instance.call_method1("validate_token", (policy_content, token))?.extract()?;
let policy_content =
std::fs::read_to_string(policy_file).context("Failed to read policy file")?;
let result: bool = attestation_instance
.call_method1("validate_token", (policy_content, token))?
.extract()?;

if result {
let parsed: Vec<serde_json::Value> = serde_json::from_str(&token)?;
let mut claim_token = String::new();
if let Some(claims) = parsed[1].get("LOCAL_GPU_CLAIMS") {
claim_token = claims.to_string();
} else {
bail!("Invalid GPU token format, only support LOCAL_GPU_CLAIMS now");
}
if let Some(claims) = parsed[1].get("LOCAL_GPU_CLAIMS") {
claim_token = claims.to_string();
} else {
bail!("Invalid GPU token format, only support LOCAL_GPU_CLAIMS now");
}
let claims = decode_gpu_attestation_token(&claim_token)?;
Ok(claims)
} else {
Expand All @@ -190,7 +193,8 @@ fn decode_gpu_attestation_token(token: &str) -> Result<serde_json::Value> {
}

let payload = parts[1];
let decoded_payload = base64::engine::general_purpose::STANDARD.decode(payload)
let decoded_payload = base64::engine::general_purpose::STANDARD
.decode(payload)
.context("GPU token: Failed to decode Base64 payload")?;

let claims: serde_json::Value = serde_json::from_slice(&decoded_payload)
Expand Down Expand Up @@ -221,6 +225,7 @@ mod tests {
);
}

#[ignore]
#[test]
fn test_verify_gpu_token() {
pyo3::prepare_freethreaded_python();
Expand Down

0 comments on commit 7f54949

Please sign in to comment.