From 3891449774cd8a4c90b992e77fb07bf11bb4f27e Mon Sep 17 00:00:00 2001 From: unholyzero <576175933@qq.com> Date: Thu, 19 Dec 2024 14:38:25 +0800 Subject: [PATCH 1/2] Enable the RVPS query function. --- .../attestation-service.patch | 291 +++++----- confidential_container/guest-components.patch | 509 ++++++------------ 2 files changed, 331 insertions(+), 469 deletions(-) diff --git a/confidential_container/attestation-service.patch b/confidential_container/attestation-service.patch index 802806b..a4888aa 100644 --- a/confidential_container/attestation-service.patch +++ b/confidential_container/attestation-service.patch @@ -1,26 +1,25 @@ --- - Cargo.toml | 12 + - as-types/Cargo.toml | 4 +- - attestation-service/Cargo.toml | 18 +- - attestation-service/src/lib.rs | 6 + - attestation-service/src/verifier/mod.rs | 19 + - .../src/verifier/virtcca/ima.rs | 102 ++++ - .../src/verifier/virtcca/mod.rs | 470 ++++++++++++++++++ - bin/grpc-as/src/server.rs | 5 +- + Cargo.toml | 11 + + Makefile | 11 +- + as-types/Cargo.toml | 3 +- + attestation-service/Cargo.toml | 14 +- + attestation-service/src/verifier/mod.rs | 16 + + .../src/verifier/virtcca/ima.rs | 99 ++++ + .../src/verifier/virtcca/mod.rs | 530 ++++++++++++++++++ + bin/grpc-as/src/server.rs | 1 + protos/attestation.proto | 1 + - 9 files changed, 630 insertions(+), 7 deletions(-) + 9 files changed, 681 insertions(+), 5 deletions(-) create mode 100644 attestation-service/src/verifier/virtcca/ima.rs create mode 100644 attestation-service/src/verifier/virtcca/mod.rs diff --git a/Cargo.toml b/Cargo.toml -index 54cdbee..1bbb600 100644 +index 54cdbee..2fa59ff 100644 --- a/Cargo.toml +++ b/Cargo.toml -@@ -33,3 +33,15 @@ shadow-rs = "0.19.0" +@@ -33,3 +33,14 @@ shadow-rs = "0.19.0" tokio = { version = "1.0", features = ["rt-multi-thread", "macros", "fs"] } tonic = "0.8.1" tonic-build = "0.8.0" -+ +cose-rust = "0.1.7" +ciborium = "0.2.2" +hex = "0.4" @@ -32,34 +31,62 @@ index 54cdbee..1bbb600 100644 +thiserror = "1.0" +base64-url = "3.0.0" +jsonwebtoken = "9.3.0" +diff --git a/Makefile b/Makefile +index 0242b93..e07e510 100644 +--- a/Makefile ++++ b/Makefile +@@ -8,6 +8,15 @@ BIN_NAMES := grpc-as + DEBUG ?= + DESTDIR ?= $(PREFIX)/bin + ++VERIFIER ?= ++features ?= ++ ++ifdef VERIFIER ++ features += $(VERIFIER) ++else ++ features += all-verifier ++endif ++ + ifdef DEBUG + release := + TARGET_DIR := $(TARGET_DIR)/debug +@@ -19,7 +28,7 @@ endif + build: grpc-as + + grpc-as: +- cargo build --bin grpc-as $(release) ++ cargo build --bin grpc-as $(release) --features $(features) + + install: + for bin_name in $(BIN_NAMES); do \ diff --git a/as-types/Cargo.toml b/as-types/Cargo.toml -index fcdf2f6..07c928a 100644 +index fcdf2f6..c222330 100644 --- a/as-types/Cargo.toml +++ b/as-types/Cargo.toml -@@ -5,6 +5,8 @@ edition = "2021" +@@ -5,6 +5,7 @@ edition = "2021" [dependencies] # TODO: change it to "0.5", once released. -kbs-types = { git = "https://github.com/virtee/kbs-types", rev = "c90df0e" } -+#kbs-types = { git = "https://github.com/virtee/kbs-types", rev = "c90df0e" } +kbs-types = { path = "../../kbs-types"} + serde.workspace = true serde_json.workspace = true diff --git a/attestation-service/Cargo.toml b/attestation-service/Cargo.toml -index 7f8670b..14897bf 100644 +index 7f8670b..d676f90 100644 --- a/attestation-service/Cargo.toml +++ b/attestation-service/Cargo.toml -@@ -5,13 +5,14 @@ edition = "2021" +@@ -4,14 +4,15 @@ version = "0.1.0" + edition = "2021" [features] - default = [ "rvps-native", "all-verifier" ] +-default = [ "rvps-native", "all-verifier" ] -all-verifier = [ "tdx-verifier", "sgx-verifier", "snp-verifier", "az-snp-vtpm-verifier", "csv-verifier", "cca-verifier" ] --tdx-verifier = [ "eventlog-rs", "scroll", "sgx-dcap-quoteverify-rs" ] --sgx-verifier = [ "scroll", "sgx-dcap-quoteverify-rs" ] ++default = [ "rvps-native" ] +all-verifier = [ "snp-verifier", "az-snp-vtpm-verifier", "csv-verifier", "cca-verifier", "virtcca-verifier" ] -+#tdx-verifier = [ "eventlog-rs", "scroll", "sgx-dcap-quoteverify-rs" ] -+#sgx-verifier = [ "scroll", "sgx-dcap-quoteverify-rs" ] + tdx-verifier = [ "eventlog-rs", "scroll", "sgx-dcap-quoteverify-rs" ] + sgx-verifier = [ "scroll", "sgx-dcap-quoteverify-rs" ] az-snp-vtpm-verifier = [ "az-snp-vtpm", "sev" ] snp-verifier = [ "asn1-rs", "openssl", "sev", "x509-parser" ] csv-verifier = [ "openssl", "csv-rs", "codicon" ] @@ -81,51 +108,18 @@ index 7f8670b..14897bf 100644 as-types = { path = "../as-types" } az-snp-vtpm = { version = "0.3.0", default-features = false, features = ["verifier"], optional = true } base64 = "0.21" -@@ -37,7 +44,9 @@ hex = "0.4.3" +@@ -37,7 +44,8 @@ hex = "0.4.3" jsonwebtoken = "8" jwt = { version = "0.16.0", features = ["openssl"]} # TODO: change it to "0.5", once released. -kbs-types = { git = "https://github.com/virtee/kbs-types", rev = "c90df0e" } -+#kbs-types = { git = "https://github.com/virtee/kbs-types", rev = "c90df0e" } +kbs-types = { path = "../../kbs-types"} + lazy_static = "1.4.0" log.workspace = true openssl = { version = "0.10.55", optional = true } -@@ -65,6 +74,7 @@ veraison-apiclient = { git = "https://github.com/chendave/rust-apiclient", branc - ear = { git = "https://github.com/veraison/rust-ear", rev = "cc6ea53" } - x509-parser = { version = "0.14.0", optional = true } - -+ - [build-dependencies] - shadow-rs.workspace = true - tonic-build.workspace = true -diff --git a/attestation-service/src/lib.rs b/attestation-service/src/lib.rs -index 144b6b4..a5756a5 100644 ---- a/attestation-service/src/lib.rs -+++ b/attestation-service/src/lib.rs -@@ -23,6 +23,9 @@ pub mod verifier; - - use crate::token::AttestationTokenBroker; - -+ -+use log::{debug, info}; -+ - use anyhow::{anyhow, Context, Result}; - use as_types::SetPolicyInput; - use config::Config; -@@ -112,6 +115,9 @@ impl AttestationService { - /// Evaluate Attestation Evidence. - /// Issue an attestation results token which contain TCB status and TEE public key. - pub async fn evaluate(&self, tee: Tee, nonce: &str, attestation: &str) -> Result { -+ // info!("evaluate tee: {}", tee.clone()); -+ info!("evaluate {}", nonce); -+ - let attestation = serde_json::from_str::(attestation) - .context("Failed to deserialize Attestation")?; - let verifier = crate::verifier::to_verifier(&tee)?; diff --git a/attestation-service/src/verifier/mod.rs b/attestation-service/src/verifier/mod.rs -index 1393711..3396630 100644 +index 1393711..95e6e33 100644 --- a/attestation-service/src/verifier/mod.rs +++ b/attestation-service/src/verifier/mod.rs @@ -3,6 +3,8 @@ use as_types::TeeEvidenceParsedClaim; @@ -137,7 +131,7 @@ index 1393711..3396630 100644 pub mod sample; #[cfg(feature = "az-snp-vtpm-verifier")] -@@ -23,8 +25,13 @@ pub mod csv; +@@ -23,6 +25,9 @@ pub mod csv; #[cfg(feature = "cca-verifier")] pub mod cca; @@ -145,24 +139,19 @@ index 1393711..3396630 100644 +pub mod virtcca; + pub(crate) fn to_verifier(tee: &Tee) -> Result> { -+ match tee { -+ Tee::Sev => todo!(), - Tee::AzSnpVtpm => { - cfg_if::cfg_if! { -@@ -83,6 +90,18 @@ pub(crate) fn to_verifier(tee: &Tee) -> Result> +@@ -83,6 +88,17 @@ pub(crate) fn to_verifier(tee: &Tee) -> Result> } } } + -+ + Tee::Virtcca => { + cfg_if::cfg_if! { + if #[cfg(feature = "virtcca-verifier")] { + Ok(Box::::default() as Box) + } else { -+ anyhow::bail!("feature `cca-verifier` is not enabled!"); ++ anyhow::bail!("feature `virtcca-verifier` is not enabled!"); + } + } + } @@ -172,10 +161,10 @@ index 1393711..3396630 100644 diff --git a/attestation-service/src/verifier/virtcca/ima.rs b/attestation-service/src/verifier/virtcca/ima.rs new file mode 100644 -index 0000000..eae1fd1 +index 0000000..aca0489 --- /dev/null +++ b/attestation-service/src/verifier/virtcca/ima.rs -@@ -0,0 +1,102 @@ +@@ -0,0 +1,99 @@ +use anyhow::{Result, bail}; +use ima_measurements::{Event, EventData, Parser}; +use fallible_iterator::FallibleIterator; @@ -185,8 +174,7 @@ index 0000000..eae1fd1 +use rand::Rng; +use serde::Serialize; +use serde::Deserialize; -+// use attester::Evidence; -+// pub use attester::virtcca::VirtccaEvidence; ++ + +#[derive(Debug)] +pub struct ImaVerify { @@ -262,7 +250,6 @@ index 0000000..eae1fd1 + _ => bail!("Inalid event {:?}", event), + }; + let hex_str_digest = hex::encode(file_digest); -+ //log::info!("hex_str_digest {}", hex_str_digest); + let output = Command::new("grep") + .arg("-E") + .arg("-i") @@ -277,13 +264,12 @@ index 0000000..eae1fd1 + Ok(()) + } +} -+ diff --git a/attestation-service/src/verifier/virtcca/mod.rs b/attestation-service/src/verifier/virtcca/mod.rs new file mode 100644 -index 0000000..12558fe +index 0000000..85f8efd --- /dev/null +++ b/attestation-service/src/verifier/virtcca/mod.rs -@@ -0,0 +1,470 @@ +@@ -0,0 +1,530 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. + * secGear is licensed under the Mulan PSL v2. @@ -311,18 +297,21 @@ index 0000000..12558fe +use openssl::pkey::PKey; +use log; +use serde_json::json; -+use kbs_types::TeePubKey; +use serde::Serialize; +use serde::Deserialize; -+use base64::decode; -+// use anyhow::{bail, Context}; ++use sha2::{Sha384,Digest}; ++use crate::rvps::grpc::rvps_api::{ ++ reference_value_provider_service_client::ReferenceValueProviderServiceClient, ++ ReferenceValueQueryRequest, ++}; + +pub mod ima; + +const VIRTCCA_ROOT_CERT: &str = "/etc/attestation/attestation-service/verifier/virtcca/Huawei Equipment Root CA.pem"; +const VIRTCCA_SUB_CERT: &str = "/etc/attestation/attestation-service/verifier/virtcca/Huawei IT Product CA.pem"; + -+const VIRTCCA_REF_VALUE_FILE: &str = "/etc/attestation/attestation-service/verifier/virtcca/ref_value.json"; ++const DEFAULT_RVPS_ADDR: &str = "https://127.0.0.1:50003"; ++const VIRTCCA_RIM_PATH: &str = "virtcca.payload.cvm.rim"; + +#[derive(Debug, Default)] +pub struct VirtCCAVerifier {} @@ -334,7 +323,7 @@ index 0000000..12558fe + nonce: String, + attestation: &Attestation, + ) -> Result { -+ return Evidence::verify(nonce, attestation); ++ return Evidence::verify(nonce, attestation).await; + } +} + @@ -386,39 +375,52 @@ index 0000000..12558fe + } + } + -+ pub fn verify(nonce: String, attestation: &Attestation) -> Result { ++ pub async fn verify(nonce: String, attestation: &Attestation) -> Result { + log::info!("verify virtCCA tee_evidence!"); -+ // 尝试将 attestation.tee_evidence 转换为 &str 类型 ++ // Try to convert attestation.tee_evidence to &str type + let evidence_str = Some(attestation.tee_evidence.as_str()).ok_or_else(|| { + anyhow!("Failed to convert attestation.tee_evidence to &str") + })?; + + log::info!("tee_evidence {}", attestation.tee_evidence.as_str()); -+ // 反序列化 VirtccaEvidence 从 evidence_str ++ // Deserialize VirtccaEvidence from evidence_str + let virtcca_ev: VirtccaEvidence = serde_json::from_str::(evidence_str) + .context("Deserialize VirtccaEvidence failed.")?; + -+ // 从 VirtccaEvidence 中提取 evidence 和 dev_cert ++ // Extract evidence and dev_cert from VirtccaEvidence + let evidence = virtcca_ev.evidence; + let dev_cert = virtcca_ev.dev_cert; + -+ // 将提取出来的 evidence 数据解码为 Evidence 对象 ++ // Decode the extracted evidence data into an Evidence object + let mut evidence = Evidence::decode(evidence) + .context("Failed to decode evidence")?; + -+ // 验证平台证书 ++ // Verify the platform certificate + evidence.verify_platform_token(&dev_cert) + .context("Failed to verify platform token")?; + -+ // 验证 CVM token,包括 nonce 和 evidence 的验证 -+ evidence.verify_cvm_token(nonce.as_bytes()) ++ let mut hasher = Sha384::new(); ++ hasher.update(&nonce); ++ hasher.update(&attestation.tee_pubkey.k_mod); ++ hasher.update(&attestation.tee_pubkey.k_exp); ++ let mut hash_of_nonce_pubkey = hasher.finalize().to_vec(); ++ hash_of_nonce_pubkey.resize(64,0); ++ ++ log::info!( ++ "HASH(nonce||pubkey):\n\t{}\n", ++ hex::encode(&hash_of_nonce_pubkey) ++ ); ++ ++ // Verify the CVM token, including nonce and evidence verification ++ evidence.verify_cvm_token(&hash_of_nonce_pubkey) ++ .await + .context("Failed to verify CVM token")?; + -+ // 从 evidence 中提取并解析 TeeClaim ++ // Extract and parse TeeClaim from evidence + let tee_claim = evidence.parse_claim_from_evidence() + .context("Failed to parse claim from evidence")?; + -+ // 可能需要将 TeeClaim 转换为 TeeEvidenceParsedClaim ++ // May need to convert TeeClaim to TeeEvidenceParsedClaim + Ok(tee_claim as TeeEvidenceParsedClaim) + } + @@ -447,7 +449,6 @@ index 0000000..12558fe + } + fn verify_platform_token(&mut self, dev_cert: &[u8]) -> Result<()> { + // todo verify platform COSE_Sign1 by dev_cert, virtCCA report has no platform token now -+ + // verify dev_cet by cert chain + Evidence::verify_dev_cert_chain(dev_cert)?; + Ok(()) @@ -480,23 +481,22 @@ index 0000000..12558fe + } + Ok(()) + } -+ fn verify_cvm_token(&mut self, challenge: &[u8]) -> Result<()> { ++ async fn verify_cvm_token(&mut self, challenge: &[u8]) -> Result<()> { + -+ let decode_challenge = base64::decode(&challenge).map_err(|e| anyhow!("failed to encode challenge {}", e.to_string()))?; + // verify challenge -+ let len = decode_challenge.len(); ++ let len = challenge.len(); + let token_challenge = &self.cvm_token.challenge[0..len]; -+ log::info!("decode_challenge111 {:?} len{}", decode_challenge, decode_challenge.len()); ++ log::info!("challenge {:?} len{}", challenge, challenge.len()); + -+ if decode_challenge != token_challenge { ++ if challenge != token_challenge { + log::error!( + "verify cvm token challenge error, cvm_token challenge {:?}, input challenge {:?}", -+ token_challenge, decode_challenge ++ token_challenge, challenge + ); + bail!( + "verify cvm token challenge error, cvm_token challenge {:?}, input challenge {:?}", + token_challenge, -+ decode_challenge ++ challenge + ); + } + @@ -512,38 +512,84 @@ index 0000000..12558fe + } + self.cvm_envelop.key(&cose_key).map_err(|err| anyhow!("set cose_key to COSE_Sign1 envelop failed: {err:?}"))?; + self.cvm_envelop.decode(None, None).map_err(|err| anyhow!("verify COSE_Sign1 signature failed:{err:?}"))?; -+ // verify COSE_Sign1 signature end + + // verfiy cvm token with reference value -+ self.compare_with_ref()?; ++ self.compare_with_ref().await?; + + Ok(()) + } + -+ fn compare_with_ref(&mut self) -> Result<()> { -+ let ref_file = std::fs::read(VIRTCCA_REF_VALUE_FILE)?; -+ let js_ref = serde_json::from_slice(&ref_file)?; -+ match js_ref { ++ async fn compare_with_ref(&mut self) -> Result<()> { ++ // Connect to RVPS server ++ let mut client = ReferenceValueProviderServiceClient::connect(DEFAULT_RVPS_ADDR.to_string()) ++ .await ++ .context("Failed to connect to RVPS server")?; ++ ++ log::info!("Successfully connected to RVPS server"); ++ ++ // Create query request with specific path ++ let req = tonic::Request::new(ReferenceValueQueryRequest { ++ name: VIRTCCA_RIM_PATH.to_string(), ++ }); ++ ++ // Send query request and get response ++ let response = client ++ .query_reference_value(req) ++ .await ++ .context("Failed to query reference value")? ++ .into_inner(); ++ ++ log::info!("Received response from RVPS for RIM: {}", response.reference_value_results); ++ ++ // Check if response is empty ++ if response.reference_value_results.is_empty() { ++ log::error!("Received empty reference value results from RVPS"); ++ bail!("No reference values found for {}", VIRTCCA_RIM_PATH); ++ } ++ ++ // Parse returned reference value ++ let ref_value: serde_json::Value = serde_json::from_str(&response.reference_value_results) ++ .context("Failed to parse reference value results")?; ++ ++ log::info!("Parsed reference value for RIM: {:?}", ref_value); ++ ++ // Get current rim value ++ let current_rim = hex::encode(self.cvm_token.rim.clone()); ++ log::info!("Current RIM value: {}", current_rim); ++ ++ // Verify reference value ++ match ref_value { + serde_json::Value::Object(obj) => { -+ for (k, v) in obj { -+ if k == "rim" { -+ let rim_ref = match v { -+ serde_json::Value::String(rim) => rim, -+ _ => bail!("tim ref expecting String"), -+ }; -+ let rim = hex::encode(self.cvm_token.rim.clone()); -+ if rim_ref != rim { -+ log::error!("expecting rim: {}, got: {}", rim_ref, rim); -+ bail!("expecting rim: {}, got: {}", rim_ref, rim); ++ if let Some(hash_values) = obj.get("hash_values") { ++ if let serde_json::Value::Array(values) = hash_values { ++ // Check if current rim value is in hash_values array ++ let rim_found = values.iter().any(|v| { ++ if let serde_json::Value::String(s) = v { ++ s == ¤t_rim ++ } else { ++ false ++ } ++ }); ++ ++ if !rim_found { ++ log::error!("Current RIM value not found in reference values. Current RIM: {}", current_rim); ++ bail!("RIM value not found in reference values: {}", current_rim); + } ++ ++ log::info!("RIM value verification successful - found in reference values"); ++ return Ok(()); + } + } ++ log::error!("Invalid reference value format: missing or invalid hash_values array"); ++ bail!("Invalid reference value format: missing or invalid hash_values array"); ++ } ++ _ => { ++ log::error!("Invalid reference value format: not an object"); ++ bail!("invalid json ref value"); + } -+ _ => bail!("invalid json ref value"), + } -+ -+ Ok(()) + } ++ + fn from_raw_pub_key(raw_pub_key: &[u8]) -> Result { + let pub_key: rsa::Rsa = rsa::Rsa::public_key_from_der(raw_pub_key)?; + let mut cose_key = CoseKey::new(); @@ -755,7 +801,7 @@ index 0000000..12558fe + } +} diff --git a/bin/grpc-as/src/server.rs b/bin/grpc-as/src/server.rs -index a382359..54e8d4f 100644 +index a382359..93982d4 100644 --- a/bin/grpc-as/src/server.rs +++ b/bin/grpc-as/src/server.rs @@ -30,6 +30,7 @@ fn to_kbs_tee(tee: GrpcTee) -> Tee { @@ -766,17 +812,6 @@ index a382359..54e8d4f 100644 GrpcTee::Sample => Tee::Sample, } } -@@ -91,8 +92,8 @@ impl AttestationService for Arc> { - request: Request, - ) -> Result, Status> { - let request: AttestationRequest = request.into_inner(); -- -- debug!("Evidence: {}", &request.evidence); -+ //request.tee -+ debug!("attestation_evaluate: evidence {} ,tee {}, nonce {}", &request.evidence, request.tee, request.nonce); - - let attestation_token = self - .read() diff --git a/protos/attestation.proto b/protos/attestation.proto index 4602f3a..f6070ca 100644 --- a/protos/attestation.proto @@ -790,5 +825,5 @@ index 4602f3a..f6070ca 100644 message AttestationRequest { -- -2.21.0.windows.1 +2.45.1.windows.1 diff --git a/confidential_container/guest-components.patch b/confidential_container/guest-components.patch index ae10536..5bad04a 100644 --- a/confidential_container/guest-components.patch +++ b/confidential_container/guest-components.patch @@ -1,21 +1,15 @@ --- Cargo.toml | 12 +- - attestation-agent/app/Cargo.toml | 6 +- - attestation-agent/attester/Cargo.toml | 9 +- - attestation-agent/attester/src/lib.rs | 14 ++- - attestation-agent/attester/src/virtcca/mod.rs | 105 ++++++++++++++++++ - .../attester/src/virtcca/virtcca.rs | 104 +++++++++++++++++ - attestation-agent/kbc/Cargo.toml | 2 - - attestation-agent/kbs_protocol/Cargo.toml | 2 - - .../kbs_protocol/src/client/rcar_client.rs | 11 +- - attestation-agent/lib/Cargo.toml | 2 - - attestation-agent/test-binaries/Cargo.toml | 2 +- - image-rs/Cargo.toml | 3 - + attestation-agent/app/Cargo.toml | 1 + + attestation-agent/attester/Cargo.toml | 7 +- + attestation-agent/attester/src/lib.rs | 12 +- + attestation-agent/attester/src/virtcca/mod.rs | 162 ++++++++++++++++++ + attestation-agent/kbc/Cargo.toml | 1 + + attestation-agent/kbs_protocol/Cargo.toml | 1 + + attestation-agent/lib/Cargo.toml | 1 + image-rs/src/stream.rs | 2 +- - ocicrypt-rs/Cargo.toml | 2 +- - 14 files changed, 253 insertions(+), 23 deletions(-) + 9 files changed, 194 insertions(+), 5 deletions(-) create mode 100644 attestation-agent/attester/src/virtcca/mod.rs - create mode 100644 attestation-agent/attester/src/virtcca/virtcca.rs diff --git a/Cargo.toml b/Cargo.toml index b10de14..1b5c135 100644 @@ -73,38 +67,19 @@ index b10de14..1b5c135 100644 [patch.crates-io] oci-distribution = { git = "https://github.com/krustlet/oci-distribution.git", rev = "f44124c" } diff --git a/attestation-agent/app/Cargo.toml b/attestation-agent/app/Cargo.toml -index 99da786..3c2ced3 100644 +index 99da786..f8723eb 100644 --- a/attestation-agent/app/Cargo.toml +++ b/attestation-agent/app/Cargo.toml -@@ -9,6 +9,7 @@ edition = "2021" - anyhow.workspace = true - async-trait.workspace = true - attestation_agent = { path = "../lib", default-features = false } -+attester = { path = "../attester", features = ["virtcca-attester"] } - base64.workspace = true - cfg-if.workspace = true - clap = { workspace = true, features = ["derive"] } -@@ -29,7 +30,8 @@ tonic-build = { workspace = true, optional = true } - ttrpc-codegen = { workspace = true, optional = true } - - [features] --default = ["sample_kbc", "ttrpc"] -+default = ["sample_kbc", "ttrpc", "virtcca-attester"] -+virtcca-attester = ["attester/virtcca-attester"] - grpc = ["tonic", "prost", "tonic-build"] - ttrpc = ["dep:ttrpc", "ttrpc-codegen", "protobuf"] - sample_kbc = ["attestation_agent/sample_kbc"] -@@ -37,8 +39,6 @@ cc_kbc = ["attestation_agent/cc_kbc"] - - # attester suites of cc-kbc - cc_kbc_all_attesters = ["cc_kbc", "attestation_agent/all-attesters"] --cc_kbc_tdx = ["cc_kbc", "attestation_agent/tdx-attester"] --cc_kbc_sgx = ["cc_kbc", "attestation_agent/sgx-attester"] +@@ -41,6 +41,7 @@ cc_kbc_tdx = ["cc_kbc", "attestation_agent/tdx-attester"] + cc_kbc_sgx = ["cc_kbc", "attestation_agent/sgx-attester"] cc_kbc_az_snp_vtpm = ["cc_kbc", "attestation_agent/az-snp-vtpm-attester"] cc_kbc_snp = ["cc_kbc", "attestation_agent/snp-attester"] ++cc_kbc_virtcca = ["cc_kbc", "attestation_agent/virtcca-attester"] + eaa_kbc = ["attestation_agent/eaa_kbc"] + offline_fs_kbc = ["attestation_agent/offline_fs_kbc"] diff --git a/attestation-agent/attester/Cargo.toml b/attestation-agent/attester/Cargo.toml -index 91a569f..043512e 100644 +index 91a569f..12c2895 100644 --- a/attestation-agent/attester/Cargo.toml +++ b/attestation-agent/attester/Cargo.toml @@ -16,6 +16,8 @@ nix = {version = "0.26.2", optional = true } @@ -116,7 +91,7 @@ index 91a569f..043512e 100644 sev = { version = "1.2.0", default-features = false, features = ["snp"], optional = true } strum.workspace = true tdx-attest-rs = { git = "https://github.com/intel/SGXDataCenterAttestationPrimitives", tag = "DCAP_1.16", optional = true } -@@ -25,16 +27,15 @@ codicon = { version = "3.0", optional = true } +@@ -25,14 +27,15 @@ codicon = { version = "3.0", optional = true } hyper = { version = "0.14", features = ["full"], optional = true } hyper-tls = { version = "0.5", optional = true } tokio = { version = "1", features = ["full"], optional = true } @@ -129,32 +104,30 @@ index 91a569f..043512e 100644 default = ["all-attesters"] -all-attesters = ["tdx-attester", "sgx-attester", "az-snp-vtpm-attester", "snp-attester", "csv-attester", "cca-attester"] - --tdx-attester = ["tdx-attest-rs"] --sgx-attester = ["occlum_dcap"] -+all-attesters = ["az-snp-vtpm-attester", "snp-attester", "csv-attester", "cca-attester","virtcca-attester"] -+virtcca-attester = [] ++all-attesters = ["tdx-attester", "sgx-attester", "az-snp-vtpm-attester", "snp-attester", "csv-attester", "cca-attester", "virtcca-attester"] ++virtcca-attester = ["nix"] + tdx-attester = ["tdx-attest-rs"] + sgx-attester = ["occlum_dcap"] az-snp-vtpm-attester = ["az-snp-vtpm"] - snp-attester = ["sev"] - csv-attester = ["csv-rs", "codicon", "hyper", "hyper-tls", "tokio"] diff --git a/attestation-agent/attester/src/lib.rs b/attestation-agent/attester/src/lib.rs -index b1ade1f..2e6f1be 100644 +index b1ade1f..72fa8c3 100644 --- a/attestation-agent/attester/src/lib.rs +++ b/attestation-agent/attester/src/lib.rs -@@ -5,7 +5,7 @@ +@@ -5,7 +5,6 @@ use anyhow::*; use kbs_types::Tee; - -+use log::debug; pub mod sample; #[cfg(feature = "az-snp-vtpm-attester")] -@@ -26,6 +26,8 @@ pub mod snp; +@@ -26,6 +25,9 @@ pub mod snp; #[cfg(feature = "csv-attester")] pub mod csv; +#[cfg(feature = "virtcca-attester")] +pub mod virtcca; ++ pub type BoxedAttester = Box; impl TryFrom for BoxedAttester { @@ -167,26 +140,24 @@ index b1ade1f..2e6f1be 100644 _ => bail!("TEE is not supported!"), }; -@@ -97,5 +101,13 @@ pub fn detect_tee_type() -> Option { +@@ -97,5 +101,11 @@ pub fn detect_tee_type() -> Option { return Some(Tee::Cca); } + #[cfg(feature = "virtcca-attester")] + { + if virtcca::detect_platform() { -+ debug!("virtCCA platform detected"); + return Some(Tee::Virtcca); + } + } -+ debug!("No supported TEE platform detected"); None } diff --git a/attestation-agent/attester/src/virtcca/mod.rs b/attestation-agent/attester/src/virtcca/mod.rs new file mode 100644 -index 0000000..8ecb20d +index 0000000..1708459 --- /dev/null +++ b/attestation-agent/attester/src/virtcca/mod.rs -@@ -0,0 +1,105 @@ +@@ -0,0 +1,162 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. + * secGear is licensed under the Mulan PSL v2. @@ -203,35 +174,30 @@ index 0000000..8ecb20d +//! +//! Call the hardware sdk or driver to get the specific evidence + -+use anyhow::{bail, Result}; -+use log::{debug}; ++use super::Attester; ++use anyhow::*; ++use base64::Engine; ++use nix::fcntl::{open, OFlag}; ++use nix::sys::stat::Mode; ++use nix::unistd::close; +use serde::{Deserialize, Serialize}; +use std::path::Path; + -+use self::virtcca::{get_attestation_token, get_dev_cert, tsi_new_ctx}; -+use crate::virtcca::virtcca::tsi_free_ctx; -+use super::Attester; -+use anyhow::Context; ++const VIRTCCA_DEVICE_PATH: &str = "/dev/tsi"; ++const MAX_CHALLENGE_LEN: usize = 64; ++const MAX_DEV_CERT_SIZE: usize = 4096; ++const GRANULE_SIZE: usize = 4096; ++const MAX_TOKEN_GRANULE_COUNT: usize = 2; ++const TSI_MAGIC: u8 = b'T'; ++const IMA_MEASUREMENT_PATH: &str = "/sys/kernel/security/ima/binary_runtime_measurements"; + -+mod virtcca; ++pub fn detect_platform() -> bool { ++ Path::new(VIRTCCA_DEVICE_PATH).exists() ++} + +#[derive(Debug, Default)] +pub struct VirtccaAttester {} + -+#[async_trait::async_trait] -+impl Attester for VirtccaAttester { -+ async fn get_evidence(&self, challenge: Vec) -> Result { -+ let evidence = virtcca_get_token(challenge)?; -+ let evidence = serde_json::to_string(&evidence)?; -+ log::debug!("Exiting get_evidence function with evidence: {}", evidence); -+ Ok(evidence) -+ } -+} -+ -+pub fn detect_platform() -> bool { -+ Path::new("/dev/tsi").exists() -+} -+ +#[derive(Debug, Serialize, Deserialize)] +pub struct VirtccaEvidence { + pub evidence: Vec, @@ -239,284 +205,158 @@ index 0000000..8ecb20d + pub ima_log: Option>, +} + -+pub fn virtcca_get_token(challenge: Vec) -> Result { -+ debug!("Entering virtcca_get_token"); -+ debug!("Challenge: {:?}", challenge); -+ debug!("Challenge length: {}", challenge.len()); -+ debug!("Challenge (hex): {}", hex::encode(&challenge)); -+ unsafe { -+ let ctx = tsi_new_ctx(); -+ println!("tsi_new_ctx called"); -+ -+ let mut challenge = challenge.to_vec(); -+ let p_challenge = challenge.as_mut_ptr() as *mut ::std::os::raw::c_uchar; -+ let challenge_len = challenge.len() as usize; -+ let mut token = Vec::new(); -+ token.resize(4096, b'\0'); -+ let p_token = token.as_mut_ptr() as *mut ::std::os::raw::c_uchar; -+ let mut token_len = token.len(); -+ let p_token_len = &mut token_len as *mut usize; -+ let ret = get_attestation_token(ctx, p_challenge, challenge_len, p_token, p_token_len); -+ println!("get_attestation_token returned: {}", ret); -+ if ret != 0 { -+ log::error!("virtcca get attestation token failed {}", ret); -+ bail!("virtcca get attestation token failed {}", ret); -+ } -+ token.set_len(token_len); -+ log::debug!("Attestation token obtained successfully, token length: {}", token_len); -+ -+ let mut dev_cert = Vec::new(); -+ dev_cert.resize(4096, b'\0'); -+ let p_dev_cert = dev_cert.as_mut_ptr() as *mut ::std::os::raw::c_uchar; -+ let mut dev_cert_len = dev_cert.len(); -+ let p_dev_cert_len = &mut dev_cert_len as *mut usize; -+ let ret = get_dev_cert(ctx, p_dev_cert, p_dev_cert_len); -+ if ret != 0 { -+ log::error!("get dev cert failed {}", ret); -+ bail!("get dev cert failed {}", ret); -+ } -+ dev_cert.set_len(dev_cert_len); -+ log::debug!("Device certificate obtained successfully, cert length: {}", dev_cert_len); -+ -+ let ima_log = { -+ Some(std::fs::read("/sys/kernel/security/ima/binary_runtime_measurements").unwrap()) -+ }; -+ log::debug!("IMA log obtained successfully"); -+ -+ let evidence = VirtccaEvidence { -+ evidence: token, -+ dev_cert: dev_cert, -+ ima_log: ima_log, -+ }; -+ let _ = tsi_free_ctx(ctx); -+ Ok(evidence) -+ } -+} -diff --git a/attestation-agent/attester/src/virtcca/virtcca.rs b/attestation-agent/attester/src/virtcca/virtcca.rs -new file mode 100644 -index 0000000..c2ff474 ---- /dev/null -+++ b/attestation-agent/attester/src/virtcca/virtcca.rs -@@ -0,0 +1,104 @@ -+/* automatically generated by rust-bindgen 0.69.4 */ +#[allow(non_camel_case_types)] -+pub type wchar_t = ::std::os::raw::c_int; +#[repr(C)] -+#[repr(align(16))] -+#[derive(Debug, Copy, Clone)] -+pub struct max_align_t { -+ pub __clang_max_align_nonce1: ::std::os::raw::c_longlong, -+ pub __bindgen_padding_0: u64, -+ pub __clang_max_align_nonce2: u128, -+} -+#[test] -+fn bindgen_test_layout_max_align_t() { -+ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); -+ let ptr = UNINIT.as_ptr(); -+ assert_eq!( -+ ::std::mem::size_of::(), -+ 32usize, -+ concat!("Size of: ", stringify!(max_align_t)) -+ ); -+ assert_eq!( -+ ::std::mem::align_of::(), -+ 16usize, -+ concat!("Alignment of ", stringify!(max_align_t)) -+ ); -+ assert_eq!( -+ unsafe { ::std::ptr::addr_of!((*ptr).__clang_max_align_nonce1) as usize - ptr as usize }, -+ 0usize, -+ concat!( -+ "Offset of field: ", -+ stringify!(max_align_t), -+ "::", -+ stringify!(__clang_max_align_nonce1) -+ ) -+ ); -+ assert_eq!( -+ unsafe { ::std::ptr::addr_of!((*ptr).__clang_max_align_nonce2) as usize - ptr as usize }, -+ 16usize, -+ concat!( -+ "Offset of field: ", -+ stringify!(max_align_t), -+ "::", -+ stringify!(__clang_max_align_nonce2) -+ ) -+ ); ++pub struct cvm_attestation_cmd { ++ challenge: [u8; MAX_CHALLENGE_LEN], ++ token: [u8; GRANULE_SIZE * MAX_TOKEN_GRANULE_COUNT], ++ token_size: u64, +} ++ ++#[allow(non_camel_case_types)] +#[repr(C)] -+#[derive(Debug, Copy, Clone)] -+pub struct tsi_ctx { -+ pub fd: wchar_t, -+} -+#[test] -+fn bindgen_test_layout_tsi_ctx() { -+ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); -+ let ptr = UNINIT.as_ptr(); -+ assert_eq!( -+ ::std::mem::size_of::(), -+ 4usize, -+ concat!("Size of: ", stringify!(tsi_ctx)) -+ ); -+ assert_eq!( -+ ::std::mem::align_of::(), -+ 4usize, -+ concat!("Alignment of ", stringify!(tsi_ctx)) -+ ); -+ assert_eq!( -+ unsafe { ::std::ptr::addr_of!((*ptr).fd) as usize - ptr as usize }, -+ 0usize, -+ concat!( -+ "Offset of field: ", -+ stringify!(tsi_ctx), -+ "::", -+ stringify!(fd) -+ ) -+ ); ++pub struct cca_dev_cert { ++ size: u64, ++ value: [u8; MAX_DEV_CERT_SIZE], +} + -+#[link(name = "vccaattestation")] -+extern "C" { -+ pub fn tsi_new_ctx() -> *mut tsi_ctx; -+} -+extern "C" { -+ pub fn tsi_free_ctx(ctx: *mut tsi_ctx); ++nix::ioctl_readwrite!(tmm_get_attestation_token, TSI_MAGIC, 1, cvm_attestation_cmd); ++nix::ioctl_read!(tmm_get_dev_cert, TSI_MAGIC, 2, cca_dev_cert); ++ ++#[async_trait::async_trait] ++impl Attester for VirtccaAttester { ++ async fn get_evidence(&self, mut challenge: Vec) -> Result { ++ challenge.resize(MAX_CHALLENGE_LEN, 0); ++ let token = virtcca_get_token(challenge)?; ++ let cert = virtcca_get_cert()?; ++ let ima = virtcca_get_ima_log(); ++ let evidence = VirtccaEvidence { evidence: token, dev_cert: cert, ima_log: ima }; ++ let ev = serde_json::to_string(&evidence).context("Serialize virtCCA evidence failed")?; ++ Ok(ev) ++ } +} -+extern "C" { -+ #[allow(dead_code)] -+ pub fn get_version(ctx: *mut tsi_ctx, major: *mut wchar_t, minor: *mut wchar_t) -> wchar_t; ++ ++pub fn virtcca_get_token(challenge: Vec) -> Result, Error> { ++ log::info!("virtcca_test::attestation started"); ++ ++ let challenge = challenge.as_slice().try_into()?; ++ ++ match open(VIRTCCA_DEVICE_PATH, OFlag::empty(), Mode::empty()) { ++ Result::Ok(f) => { ++ log::info!("virtcca_test:: tsi interface opening attestation succeeded"); ++ let mut request = cvm_attestation_cmd { ++ challenge, ++ token: [0u8; GRANULE_SIZE * MAX_TOKEN_GRANULE_COUNT], ++ token_size: 0u64, ++ }; ++ ++ match unsafe { tmm_get_attestation_token(f, &mut request) } { ++ Result::Ok(c) => { ++ log::info!("virtcca_test::attestation ioctl call succeeded ({})", c); ++ log::info!( ++ "virtcca_test::attestation token is {} bytes long", ++ request.token_size ++ ); ++ let base64 = base64::engine::general_purpose::STANDARD ++ .encode(&request.token[0..(request.token_size as usize)]); ++ log::info!("virtcca_test::attestation token = {:x?}", base64); ++ let token = request.token[0..(request.token_size as usize)].to_vec(); ++ close(f)?; ++ Ok(token) ++ } ++ Err(e) => { ++ log::error!("virtcca_test::attestation ioctl failed! {}", e); ++ close(f)?; ++ bail!(e) ++ } ++ } ++ } ++ Err(err) => { ++ log::error!("virtcca_test::tsi inferface opening attestation failed! {}", err); ++ bail!(err) ++ } ++ } +} -+extern "C" { -+ pub fn get_attestation_token( -+ ctx: *mut tsi_ctx, -+ challenge: *mut ::std::os::raw::c_uchar, -+ challenge_len: usize, -+ token: *mut ::std::os::raw::c_uchar, -+ token_len: *mut usize, -+ ) -> wchar_t; ++ ++pub fn virtcca_get_cert() -> Result, Error> { ++ log::info!("virtcca_test::getting certificate started"); ++ ++ match open(VIRTCCA_DEVICE_PATH, OFlag::empty(), Mode::empty()) { ++ Result::Ok(f) => { ++ log::info!("virtcca_test:: tsi inferface opening attestation succeeded"); ++ let mut request = cca_dev_cert { ++ size: 0u64, ++ value: [0u8; MAX_DEV_CERT_SIZE], ++ }; ++ ++ match unsafe { tmm_get_dev_cert(f, &mut request) } { ++ Result::Ok(c) => { ++ log::info!("virtcca_test::getting cert ioctl call succeeded ({})", c); ++ log::info!( ++ "virtcca_test::certificate is {} bytes long", ++ request.size ++ ); ++ let base64 = base64::engine::general_purpose::STANDARD ++ .encode(&request.value[0..(request.size as usize)]); ++ log::info!("virtcca_test::attestation token = {:x?}", base64); ++ let cert = request.value[0..(request.size as usize)].to_vec(); ++ close(f)?; ++ Ok(cert) ++ } ++ Err(e) => { ++ log::error!("virtcca_test::getting cert ioctl failed! {}", e); ++ close(f)?; ++ bail!(e) ++ } ++ } ++ } ++ Err(err) => { ++ log::error!("virtcca_test::tsi inferface opening attestation failed! {}", err); ++ bail!(err) ++ } ++ } +} -+extern "C" { -+ pub fn get_dev_cert( -+ ctx: *mut tsi_ctx, -+ dev_cert: *mut ::std::os::raw::c_uchar, -+ dev_cert_len: *mut usize, -+ ) -> wchar_t; ++ ++pub fn virtcca_get_ima_log() -> Option> { ++ std::fs::read(IMA_MEASUREMENT_PATH).ok() +} +\ No newline at end of file diff --git a/attestation-agent/kbc/Cargo.toml b/attestation-agent/kbc/Cargo.toml -index 591e11d..8fe60d0 100644 +index 591e11d..8830f7d 100644 --- a/attestation-agent/kbc/Cargo.toml +++ b/attestation-agent/kbc/Cargo.toml -@@ -38,8 +38,6 @@ default = ["sample_kbc", "rust-crypto"] - - cc_kbc = ["kbs_protocol/background_check"] - all-attesters = ["kbs_protocol?/all-attesters"] --tdx-attester = ["kbs_protocol/tdx-attester"] --sgx-attester = ["kbs_protocol/sgx-attester"] +@@ -43,6 +43,7 @@ sgx-attester = ["kbs_protocol/sgx-attester"] az-snp-vtpm-attester= ["kbs_protocol/az-snp-vtpm-attester"] snp-attester = ["kbs_protocol/snp-attester"] cca-attester = ["kbs_protocol/cca-attester"] ++virtcca-attester = ["kbs_protocol/virtcca-attester"] + + sample_kbc = [] + eaa_kbc = ["foreign-types"] diff --git a/attestation-agent/kbs_protocol/Cargo.toml b/attestation-agent/kbs_protocol/Cargo.toml -index 6017153..9a506a0 100644 +index 6017153..e08bb16 100644 --- a/attestation-agent/kbs_protocol/Cargo.toml +++ b/attestation-agent/kbs_protocol/Cargo.toml -@@ -45,8 +45,6 @@ aa_token = ["ttrpc-codegen", "passport", "ttrpc/async", "protobuf"] - - background_check = ["tokio/time"] - all-attesters = ["attester/all-attesters"] --tdx-attester = ["attester/tdx-attester"] --sgx-attester = ["attester/sgx-attester"] - az-snp-vtpm-attester = ["attester/az-snp-vtpm-attester"] +@@ -51,6 +51,7 @@ az-snp-vtpm-attester = ["attester/az-snp-vtpm-attester"] snp-attester = ["attester/snp-attester"] csv-attester = ["attester/csv-attester"] -diff --git a/attestation-agent/kbs_protocol/src/client/rcar_client.rs b/attestation-agent/kbs_protocol/src/client/rcar_client.rs -index d4c2bf5..0ef9f7c 100644 ---- a/attestation-agent/kbs_protocol/src/client/rcar_client.rs -+++ b/attestation-agent/kbs_protocol/src/client/rcar_client.rs -@@ -12,6 +12,7 @@ use log::{debug, warn}; - use resource_uri::ResourceUri; - use serde::Deserialize; - use sha2::{Digest, Sha384}; -+use base64::decode; - - use crate::{ - api::KbsClientCapabilities, -@@ -174,8 +175,13 @@ impl KbsClient> { - } - - async fn generate_evidence(&self, nonce: String, key_materials: Vec<&[u8]>) -> Result { -+ debug!("Nonce (Base64): {}", nonce); -+ let nonce_bytes = decode(&nonce).map_err(|e| Error::GetEvidence(e.to_string()))?; -+ debug!("Nonce (decoded): {:?}", nonce_bytes); -+ debug!("Nonce length: {}", nonce_bytes.len()); -+ - let mut hasher = Sha384::new(); -- hasher.update(nonce.as_bytes()); -+ hasher.update(&nonce_bytes); - key_materials - .iter() - .for_each(|key_material| hasher.update(key_material)); -@@ -184,11 +190,12 @@ impl KbsClient> { - - let tee_evidence = self - .provider -- .get_evidence(ehd) -+ .get_evidence(nonce_bytes) - .await - .context("Get TEE evidence failed") - .map_err(|e| Error::GetEvidence(e.to_string()))?; + cca-attester = ["attester/cca-attester"] ++virtcca-attester = ["attester/virtcca-attester"] -+ debug!("TEE evidence length: {}", tee_evidence.len()); - Ok(tee_evidence) - } - } + rust-crypto = ["reqwest/rustls-tls", "crypto/rust-crypto"] + openssl = ["reqwest/native-tls-vendored", "crypto/openssl"] diff --git a/attestation-agent/lib/Cargo.toml b/attestation-agent/lib/Cargo.toml -index fbf9d90..8b2b11c 100644 +index fbf9d90..2c45597 100644 --- a/attestation-agent/lib/Cargo.toml +++ b/attestation-agent/lib/Cargo.toml -@@ -28,8 +28,6 @@ default = ["sample_kbc", "rust-crypto"] - - cc_kbc = ["kbc/cc_kbc", "kbs_protocol/background_check"] - all-attesters = ["kbc/all-attesters", "kbs_protocol?/all-attesters", "attester/all-attesters"] --tdx-attester = ["kbc/tdx-attester", "kbs_protocol/tdx-attester", "attester/tdx-attester"] --sgx-attester = ["kbc/sgx-attester", "kbs_protocol/sgx-attester", "attester/sgx-attester"] +@@ -32,6 +32,7 @@ tdx-attester = ["kbc/tdx-attester", "kbs_protocol/tdx-attester", "attester/tdx-a + sgx-attester = ["kbc/sgx-attester", "kbs_protocol/sgx-attester", "attester/sgx-attester"] az-snp-vtpm-attester = ["kbc/az-snp-vtpm-attester", "kbs_protocol/az-snp-vtpm-attester", "attester/az-snp-vtpm-attester"] snp-attester = ["kbc/snp-attester", "kbs_protocol/snp-attester", "attester/snp-attester"] ++virtcca-attester = ["kbc/virtcca-attester", "kbs_protocol/virtcca-attester", "attester/virtcca-attester"] -diff --git a/attestation-agent/test-binaries/Cargo.toml b/attestation-agent/test-binaries/Cargo.toml -index a5fe042..6dd90f5 100644 ---- a/attestation-agent/test-binaries/Cargo.toml -+++ b/attestation-agent/test-binaries/Cargo.toml -@@ -15,4 +15,4 @@ attester = { path = "../attester", default-features = false, optional = true } - crypto = { path = "../deps/crypto" } - - [features] --occlum = ["attester/sgx-attester"] -+ -diff --git a/image-rs/Cargo.toml b/image-rs/Cargo.toml -index d599bad..9d44184 100644 ---- a/image-rs/Cargo.toml -+++ b/image-rs/Cargo.toml -@@ -82,12 +82,10 @@ default = ["snapshot-overlayfs", "signature-cosign-rustls", "keywrap-grpc", "oci - # This will be based on `ring` dependency - kata-cc-rustls-tls = ["encryption-ring", "keywrap-ttrpc", "snapshot-overlayfs", "signature-cosign-rustls", "signature-simple", "getresource", "oci-distribution/rustls-tls"] - enclave-cc-eaakbc-rustls-tls = ["encryption-ring", "keywrap-native", "eaa-kbc", "snapshot-unionfs", "signature-simple", "getresource", "signature-cosign-rustls", "oci-distribution-rustls"] --enclave-cc-cckbc-rustls-tls = ["encryption-ring", "keywrap-native", "cc-kbc-sgx", "snapshot-unionfs", "signature-simple", "getresource", "signature-cosign-rustls", "oci-distribution-rustls"] - - # This will be based on `openssl` dependency - kata-cc-native-tls = ["encryption-openssl", "keywrap-ttrpc", "snapshot-overlayfs", "signature-cosign-native", "signature-simple", "getresource", "oci-distribution/native-tls"] - enclave-cc-eaakbc-native-tls = ["encryption-openssl", "keywrap-native", "eaa-kbc", "snapshot-unionfs", "signature-simple", "getresource", "signature-cosign-native", "oci-distribution-native"] --enclave-cc-cckbc-native-tls = ["encryption-openssl", "keywrap-native", "cc-kbc-sgx", "snapshot-unionfs", "signature-simple", "getresource", "signature-cosign-native", "oci-distribution-native"] - - encryption = ["ocicrypt-rs/block-cipher"] - encryption-ring = ["ocicrypt-rs/block-cipher-ring", "encryption"] -@@ -102,7 +100,6 @@ keywrap-ttrpc = ["ocicrypt-rs/keywrap-keyprovider-ttrpc", "dep:ttrpc", "dep:prot - keywrap-jwe = ["ocicrypt-rs/keywrap-jwe"] - - eaa-kbc = ["attestation_agent/eaa_kbc", "ocicrypt-rs/eaa_kbc"] --cc-kbc-sgx = ["attestation_agent/cc_kbc", "attestation_agent/sgx-attester", "ocicrypt-rs/cc_kbc_sgx"] - - signature = ["hex"] - signature-cosign = ["signature", "futures"] + sample_kbc = ["kbc/sample_kbc"] + eaa_kbc = ["kbc/eaa_kbc"] diff --git a/image-rs/src/stream.rs b/image-rs/src/stream.rs index 8f2c56c..f79ef73 100644 --- a/image-rs/src/stream.rs @@ -530,19 +370,6 @@ index 8f2c56c..f79ef73 100644 // Wrap a channel with [`Read`](std::io::Read) support. // This can bridge the [`AsyncRead`](tokio::io::AsyncRead) from -diff --git a/ocicrypt-rs/Cargo.toml b/ocicrypt-rs/Cargo.toml -index f473c92..f1bf3e1 100644 ---- a/ocicrypt-rs/Cargo.toml -+++ b/ocicrypt-rs/Cargo.toml -@@ -49,7 +49,7 @@ default = ["block-cipher-openssl", "keywrap-jwe", "keywrap-keyprovider-cmd"] - eaa_kbc = ["keywrap-keyprovider-native", "attestation_agent/eaa_kbc"] - - # Use cc kbc + SGX to request KEK --cc_kbc_sgx = ["keywrap-keyprovider-native", "attestation_agent/cc_kbc", "attestation_agent/sgx-attester"] -+ - - async-io = ["tokio"] - -- -2.39.1.windows.1 +2.45.1.windows.1 -- Gitee From 1703cadac822554d00531178c0bbd8c491b81aff Mon Sep 17 00:00:00 2001 From: unholyzero <576175933@qq.com> Date: Wed, 22 Jan 2025 11:52:41 +0800 Subject: [PATCH 2/2] Adding Cvccaattest Event Log Parsing and Verification --- attestation/cvccaattest/CMakeLists.txt | 41 ++ attestation/cvccaattest/README.md | 122 ++++ attestation/cvccaattest/build.sh | 14 + attestation/cvccaattest/include/binary_blob.h | 25 + attestation/cvccaattest/include/config.h | 14 + attestation/cvccaattest/include/debug.h | 17 + attestation/cvccaattest/include/hash_defs.h | 15 + attestation/cvccaattest/include/rem.h | 19 + .../cvccaattest/include/vcca_event_log.h | 79 +++ attestation/cvccaattest/include/verify.h | 24 + attestation/cvccaattest/run.sh | 27 + attestation/cvccaattest/src/binary_blob.c | 156 +++++ attestation/cvccaattest/src/main.c | 191 ++++++ attestation/cvccaattest/src/rem.c | 24 + attestation/cvccaattest/src/vcca_event_log.c | 593 ++++++++++++++++++ attestation/cvccaattest/src/verify.c | 153 +++++ attestation/cvccaattest/testdata/ccel.bin | Bin 0 -> 56 bytes .../cvccaattest/testdata/event_log.bin | Bin 0 -> 65536 bytes attestation/cvccaattest/testdata/rem.txt | 4 + 19 files changed, 1518 insertions(+) create mode 100644 attestation/cvccaattest/CMakeLists.txt create mode 100644 attestation/cvccaattest/README.md create mode 100644 attestation/cvccaattest/build.sh create mode 100644 attestation/cvccaattest/include/binary_blob.h create mode 100644 attestation/cvccaattest/include/config.h create mode 100644 attestation/cvccaattest/include/debug.h create mode 100644 attestation/cvccaattest/include/hash_defs.h create mode 100644 attestation/cvccaattest/include/rem.h create mode 100644 attestation/cvccaattest/include/vcca_event_log.h create mode 100644 attestation/cvccaattest/include/verify.h create mode 100644 attestation/cvccaattest/run.sh create mode 100644 attestation/cvccaattest/src/binary_blob.c create mode 100644 attestation/cvccaattest/src/main.c create mode 100644 attestation/cvccaattest/src/rem.c create mode 100644 attestation/cvccaattest/src/vcca_event_log.c create mode 100644 attestation/cvccaattest/src/verify.c create mode 100644 attestation/cvccaattest/testdata/ccel.bin create mode 100644 attestation/cvccaattest/testdata/event_log.bin create mode 100644 attestation/cvccaattest/testdata/rem.txt diff --git a/attestation/cvccaattest/CMakeLists.txt b/attestation/cvccaattest/CMakeLists.txt new file mode 100644 index 0000000..f8aab3f --- /dev/null +++ b/attestation/cvccaattest/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.10) +project(cvccaattest C) + +# Setting the C Standard +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) + +# Searching for OpenSSL Packages +find_package(OpenSSL REQUIRED) + +# Add the include directory. +include_directories( + ${PROJECT_SOURCE_DIR}/include + ${OPENSSL_INCLUDE_DIR} +) + +# Source File List +set(SOURCES + src/main.c + src/rem.c + src/binary_blob.c + src/vcca_event_log.c + src/verify.c +) + +# Creating an Executable File +add_executable(vcca_tool ${SOURCES}) + +# Linking the OpenSSL Library +target_link_libraries(vcca_tool PRIVATE OpenSSL::Crypto) + +# Compiler Options +if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") + target_compile_options(vcca_tool PRIVATE + -Wall + -Wextra + -Werror + -Wno-unused-parameter + -Wno-deprecated-declarations + ) +endif() \ No newline at end of file diff --git a/attestation/cvccaattest/README.md b/attestation/cvccaattest/README.md new file mode 100644 index 0000000..30b824d --- /dev/null +++ b/attestation/cvccaattest/README.md @@ -0,0 +1,122 @@ +# VCCA 测试工具 + +VCCA工具用于验证和测试VCCA功能,包括事件日志导出和REM值验证。 + +## 依赖安装 + +### Ubuntu/Debian 系统 +```bash +sudo apt-get update +sudo apt-get install build-essential cmake libssl-dev +``` + +### CentOS/RHEL 系统 +```bash +sudo yum update +sudo yum install gcc gcc-c++ cmake openssl-devel +``` + +## 项目结构 + +``` +cvccaattest/ +├── build.sh # 构建脚本 +├── run.sh # 运行脚本 +├── src/ # 源代码目录 +│ ├── main.c +│ ├── verify.c +│ └── vcca_event_log.c +└── include/ # 头文件目录 +``` + +## 构建说明 + +使用提供的build.sh脚本进行构建: + +```bash +# 添加执行权限 +chmod +x build.sh + +# 执行构建 +./build.sh +``` + +构建完成后,可执行文件将生成在`build/`目录下。 + +## 使用说明 + +该工具提供两个主要功能: +- 导出VCCA事件日志 +- 验证REM值 + +### 运行方法 + +使用`run.sh`脚本来执行程序: + +```bash +# 添加执行权限 +chmod +x run.sh + +# 导出事件日志 +./run.sh -c -e <事件日志文件路径> + +# 验证REM值 +./run.sh -c -e <事件日志文件路径> -r +``` + +### 参数说明 + +- `-c, --ccel`: 指定CCEL文件路径 +- `-e, --eventlog`: 指定事件日志文件路径 +- `-r, --rem`: 指定REM文件路径(仅在验证REM值时需要) + +### 使用示例 + +```bash +# 导出事件日志 +./run.sh -c ./testdata/ccel.bin -e ./testdata/event_log.bin + +# 验证REM值 +./run.sh -c ./testdata/ccel.bin -e ./testdata/event_log.bin -r ./testdata/rem.txt +``` + +## 故障排除 + +### 常见问题 + +1. 编译错误 + - 确保已安装所有必要的依赖 + - 检查系统头文件是否完整 + +2. 运行错误 + - 确保build目录下存在vcca_tool可执行文件 + - 检查输入文件是否存在且有正确的读取权限 + - 验证所有脚本都有执行权限 + +### 权限问题解决 + +如果遇到权限相关的错误,可以执行: + +```bash +chmod +x build.sh run.sh +``` + +### 头文件问题解决 + +如果遇到找不到头文件的错误,请确保: +1. 系统开发包已正确安装 +2. 项目include路径正确设置 +3. CMake配置正确包含了所有必要的头文件目录 + +## 开发说明 + +如需扩展或修改功能,主要关注以下文件: +- `src/main.c`: 主程序入口 +- `src/verify.c`: REM验证相关功能 +- `src/vcca_event_log.c`: 事件日志处理功能 + +## 注意事项 + +- 运行前请确保所有输入文件都存在且有正确的读取权限 +- 建议在使用前先运行测试用例验证工具的正确性 +- 保持输入文件的格式符合规范要求 \ No newline at end of file diff --git a/attestation/cvccaattest/build.sh b/attestation/cvccaattest/build.sh new file mode 100644 index 0000000..5cf5637 --- /dev/null +++ b/attestation/cvccaattest/build.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# Creating a Build Directory +mkdir -p build +cd build + +# Configuring CMake +cmake .. + +# Compiling +make + +# Return to Project Root +cd .. \ No newline at end of file diff --git a/attestation/cvccaattest/include/binary_blob.h b/attestation/cvccaattest/include/binary_blob.h new file mode 100644 index 0000000..60daea2 --- /dev/null +++ b/attestation/cvccaattest/include/binary_blob.h @@ -0,0 +1,25 @@ +#ifndef BINARY_BLOB_H +#define BINARY_BLOB_H + +#include +#include +#include + +#define BYTES_PER_LINE 16 + +typedef struct { + uint8_t* data; + size_t length; + size_t base_address; +} binary_blob_t; + +// 二进制数据操作函数 +bool binary_blob_init(binary_blob_t* blob, uint8_t* data, size_t length, size_t base); +uint16_t binary_blob_get_uint16(const binary_blob_t* blob, size_t* pos); +uint8_t binary_blob_get_uint8(const binary_blob_t* blob, size_t* pos); +uint32_t binary_blob_get_uint32(const binary_blob_t* blob, size_t* pos); +uint64_t binary_blob_get_uint64(const binary_blob_t* blob, size_t* pos); +void binary_blob_get_bytes(const binary_blob_t* blob, size_t* pos, size_t count, uint8_t* out); +void binary_blob_dump(const binary_blob_t* blob); + +#endif // BINARY_BLOB_H \ No newline at end of file diff --git a/attestation/cvccaattest/include/config.h b/attestation/cvccaattest/include/config.h new file mode 100644 index 0000000..75deadc --- /dev/null +++ b/attestation/cvccaattest/include/config.h @@ -0,0 +1,14 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#include + +typedef struct { + const char* ccel_file; // CCEL file path + const char* event_log_file; // Event log file path + const char* rem_file; // REM file path +} config_t; + +extern config_t g_config; + +#endif // CONFIG_H \ No newline at end of file diff --git a/attestation/cvccaattest/include/debug.h b/attestation/cvccaattest/include/debug.h new file mode 100644 index 0000000..0f242bf --- /dev/null +++ b/attestation/cvccaattest/include/debug.h @@ -0,0 +1,17 @@ +#ifndef DEBUG_H +#define DEBUG_H + +#include + +extern FILE* debug_fp; + +static inline bool init_debug_log() { + debug_fp = fopen("event_log_debug.log", "w"); + if (!debug_fp) { + printf("Error: Could not create debug log file\n"); + return false; + } + return true; +} + +#endif // DEBUG_H \ No newline at end of file diff --git a/attestation/cvccaattest/include/hash_defs.h b/attestation/cvccaattest/include/hash_defs.h new file mode 100644 index 0000000..00852e9 --- /dev/null +++ b/attestation/cvccaattest/include/hash_defs.h @@ -0,0 +1,15 @@ +#ifndef HASH_DEFS_H +#define HASH_DEFS_H + +// If the OpenSSL header file is available, use its definition +#ifdef OPENSSL_SHA_H +#include +#else +// Otherwise use our own definition +#define SHA1_DIGEST_LENGTH 20 +#define SHA256_DIGEST_LENGTH 32 +#define SHA384_DIGEST_LENGTH 38 +#define SHA512_DIGEST_LENGTH 64 +#endif + +#endif // HASH_DEFS_H \ No newline at end of file diff --git a/attestation/cvccaattest/include/rem.h b/attestation/cvccaattest/include/rem.h new file mode 100644 index 0000000..4fdc4f2 --- /dev/null +++ b/attestation/cvccaattest/include/rem.h @@ -0,0 +1,19 @@ +#ifndef REM_H +#define REM_H + +#include +#include + +#define REM_COUNT 4 +#define REM_LENGTH_BYTES 32 + +typedef struct { + uint8_t data[REM_LENGTH_BYTES]; +} rem_t; + +// REM operation function +bool rem_init(rem_t* rem); +bool rem_compare(const rem_t* rem1, const rem_t* rem2); +void rem_dump(const rem_t* rem); + +#endif // REM_H \ No newline at end of file diff --git a/attestation/cvccaattest/include/vcca_event_log.h b/attestation/cvccaattest/include/vcca_event_log.h new file mode 100644 index 0000000..bf6a43c --- /dev/null +++ b/attestation/cvccaattest/include/vcca_event_log.h @@ -0,0 +1,79 @@ +#ifndef VCCA_EVENT_LOG_H +#define VCCA_EVENT_LOG_H + +#include +#include "rem.h" +#include "binary_blob.h" +#include "hash_defs.h" + +// SHA256 digest length (32 bytes) +#define SHA256_DIGEST_LENGTH 32 + +// Algorithm information structure +typedef struct { + uint16_t algoid; + uint16_t digestsize; +} algorithm_info_t; + +// Event type definitions +typedef enum { + EV_PREBOOT_CERT = 0x0, + EV_POST_CODE = 0x1, + EV_UNUSED = 0x2, + EV_NO_ACTION = 0x3, + EV_SEPARATOR = 0x4, + EV_ACTION = 0x5, + EV_EVENT_TAG = 0x6, + EV_S_CRTM_CONTENTS = 0x7, + EV_S_CRTM_VERSION = 0x8, + EV_CPU_MICROCODE = 0x9, + EV_PLATFORM_CONFIG_FLAGS = 0xa, + EV_TABLE_OF_DEVICES = 0xb, + EV_COMPACT_HASH = 0xc, + EV_IPL = 0xd, + EV_IPL_PARTITION_DATA = 0xe, + EV_NONHOST_CODE = 0xf, + EV_NONHOST_CONFIG = 0x10, + EV_NONHOST_INFO = 0x11, + EV_OMIT_BOOT_DEVICE_EVENTS = 0x12, + + // TCG EFI Platform Specification For TPM Family 1.1 or 1.2 + EV_EFI_EVENT_BASE = 0x80000000, + EV_EFI_VARIABLE_DRIVER_CONFIG = EV_EFI_EVENT_BASE + 0x1, + EV_EFI_VARIABLE_BOOT = EV_EFI_EVENT_BASE + 0x2, + EV_EFI_BOOT_SERVICES_APPLICATION = EV_EFI_EVENT_BASE + 0x3, + EV_EFI_BOOT_SERVICES_DRIVER = EV_EFI_EVENT_BASE + 0x4, + EV_EFI_RUNTIME_SERVICES_DRIVER = EV_EFI_EVENT_BASE + 0x5, + EV_EFI_GPT_EVENT = EV_EFI_EVENT_BASE + 0x6, + EV_EFI_ACTION = EV_EFI_EVENT_BASE + 0x7, + EV_EFI_PLATFORM_FIRMWARE_BLOB = EV_EFI_EVENT_BASE + 0x8, + EV_EFI_HANDOFF_TABLES = EV_EFI_EVENT_BASE + 0x9, + EV_EFI_VARIABLE_AUTHORITY = EV_EFI_EVENT_BASE + 0xe0 +} vcca_event_type_t; + +typedef struct { + uint32_t rem_index; + uint32_t event_type; + uint32_t digest_count; + uint16_t* alg_ids; // Algorithm ID for each digest + uint8_t* digests; // Data for all digests + uint32_t event_size; + uint8_t* event; + uint32_t algorithms_number; // Number of algorithms + algorithm_info_t* algorithms; // Array of algorithm information +} vcca_event_log_entry_t; + +typedef struct { + binary_blob_t blob; + size_t log_base; + size_t log_length; + rem_t rems[REM_COUNT]; +} vcca_event_log_t; + +// Event log operation functions +bool vcca_event_log_init(vcca_event_log_t* log, size_t base, size_t length); +bool vcca_event_log_process(vcca_event_log_t* log); +bool vcca_event_log_replay(vcca_event_log_t* log); +void vcca_event_log_dump(vcca_event_log_t* log); + +#endif // VCCA_EVENT_LOG_H \ No newline at end of file diff --git a/attestation/cvccaattest/include/verify.h b/attestation/cvccaattest/include/verify.h new file mode 100644 index 0000000..92884c9 --- /dev/null +++ b/attestation/cvccaattest/include/verify.h @@ -0,0 +1,24 @@ +#ifndef VERIFY_H +#define VERIFY_H + +#include +#include "rem.h" +#include "vcca_event_log.h" + +/** + * @brief Verifying REM Values + * + * This function performs the following steps: + * 1. Read the CCEL file + * 2. Obtain the event log area information + * 3. Initialize the event log processor + * 4. Replay the event log and calculate the REM value + * 5. Read the REM value in the token + * 6. Verify that the calculated REM value is consistent with the value in the token + * + * @return true Verification succeeded. + * @return false Verification failed. + */ +bool verify_rem(void); + +#endif // VERIFY_H \ No newline at end of file diff --git a/attestation/cvccaattest/run.sh b/attestation/cvccaattest/run.sh new file mode 100644 index 0000000..87258ea --- /dev/null +++ b/attestation/cvccaattest/run.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Initializing Variables +COMMAND="eventlogs" # Default Commands +ARGS="" + +# Processes all incoming parameters +while [[ $# -gt 0 ]]; do + case $1 in + -r|--rem) + COMMAND="verify" # If the -r parameter exists, run the verify command. + ARGS="$ARGS $1 $2" + shift 2 + ;; + -c|--ccel|-e|--eventlog) + ARGS="$ARGS $1 $2" + shift 2 + ;; + *) + echo "Error: unknown parameter $1" + exit 1 + ;; + esac +done + +# Run the program +./build/vcca_tool $ARGS $COMMAND \ No newline at end of file diff --git a/attestation/cvccaattest/src/binary_blob.c b/attestation/cvccaattest/src/binary_blob.c new file mode 100644 index 0000000..d80da75 --- /dev/null +++ b/attestation/cvccaattest/src/binary_blob.c @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include +#include "binary_blob.h" +#include "debug.h" + +bool binary_blob_init(binary_blob_t* blob, uint8_t* data, size_t length, size_t base) { + if (!blob || !data || length == 0) { + return false; + } + + blob->data = data; + blob->length = length; + blob->base_address = base; + + return true; +} + +static bool check_boundary(const binary_blob_t* blob, size_t* pos, size_t size) { + if (!blob || !pos || *pos + size > blob->length) { + printf("DEBUG: Boundary check failed: pos=%zu, size=%zu, blob_length=%zu\n", + *pos, size, blob ? blob->length : 0); + return false; + } + return true; +} + +uint16_t binary_blob_get_uint16(const binary_blob_t* blob, size_t* pos) { + uint16_t value = 0; + + if (!check_boundary(blob, pos, sizeof(uint16_t))) { + return 0; + } + + // Little-endian read + value = (uint16_t)blob->data[*pos] | + ((uint16_t)blob->data[*pos + 1] << 8); + + *pos += sizeof(uint16_t); + return value; +} + +uint8_t binary_blob_get_uint8(const binary_blob_t* blob, size_t* pos) { + if (!check_boundary(blob, pos, sizeof(uint8_t))) { + return 0; + } + + uint8_t value = blob->data[*pos]; + *pos += sizeof(uint8_t); + return value; +} + +uint32_t binary_blob_get_uint32(const binary_blob_t* blob, size_t* pos) { + uint32_t value = 0; + if (!check_boundary(blob, pos, sizeof(uint32_t))) { + if (debug_fp) { + fprintf(debug_fp, "ERROR: Failed to read uint32 at pos %zu\n", *pos); + } + return 0; + } + + memcpy(&value, &blob->data[*pos], sizeof(uint32_t)); + *pos += sizeof(uint32_t); + + if (debug_fp) { + fprintf(debug_fp, "DEBUG: Read uint32 at pos %zu: 0x%X\n", *pos - sizeof(uint32_t), value); + } + return value; +} + +uint64_t binary_blob_get_uint64(const binary_blob_t* blob, size_t* pos) { + uint64_t value = 0; + + if (!check_boundary(blob, pos, sizeof(uint64_t))) { + return 0; + } + + // Little-endian read + for (int i = 0; i < 8; i++) { + value |= ((uint64_t)blob->data[*pos + i] << (i * 8)); + } + + *pos += sizeof(uint64_t); + return value; +} + +void binary_blob_get_bytes(const binary_blob_t* blob, size_t* pos, size_t count, uint8_t* out) { + if (!check_boundary(blob, pos, count) || !out) { + if (debug_fp) { + fprintf(debug_fp, "ERROR: Failed to read %zu bytes at pos %zu\n", count, *pos); + } + memset(out, 0, count); + return; + } + + if (debug_fp) { + fprintf(debug_fp, "DEBUG: Reading %zu bytes at pos %zu\n", count, *pos); + } + memcpy(out, &blob->data[*pos], count); + *pos += count; +} + +void binary_blob_dump(const binary_blob_t* blob) { + if (!blob || !blob->data) { + return; + } + + printf("Binary Data:\n"); + printf("Base Address: 0x%zX\n", blob->base_address); + printf("Length: %zu bytes\n\n", blob->length); + + char ascii_buf[17] = {0}; + size_t i; + + for (i = 0; i < blob->length; i++) { + // Check if encountered consecutive 0xFF + if (blob->data[i] == 0xFF) { + size_t j; + for (j = i + 1; j < blob->length && j < i + 32; j++) { + if (blob->data[j] != 0xFF) break; + } + if (j == i + 32) { + // Print ASCII part of the last line + if (i % 16 != 0) { + for (size_t k = i % 16; k < 16; k++) { + printf(" "); + } + printf(" %s\n", ascii_buf); + } + printf("\n[Remaining data omitted - all 0xFF]\n"); + return; + } + } + + if (i % 16 == 0) { + if (i > 0) { + printf(" %s\n", ascii_buf); + } + printf("%08zX ", blob->base_address + i); + memset(ascii_buf, 0, sizeof(ascii_buf)); + } + + printf("%02X ", blob->data[i]); + ascii_buf[i % 16] = isprint(blob->data[i]) ? blob->data[i] : '.'; + } + + // Print last line + if (i % 16 != 0) { + for (size_t j = i % 16; j < 16; j++) { + printf(" "); + } + } + printf(" %s\n", ascii_buf); +} \ No newline at end of file diff --git a/attestation/cvccaattest/src/main.c b/attestation/cvccaattest/src/main.c new file mode 100644 index 0000000..dfc0194 --- /dev/null +++ b/attestation/cvccaattest/src/main.c @@ -0,0 +1,191 @@ +#include +#include +#include +#include +#include +#include "verify.h" +#include "vcca_event_log.h" +#include "config.h" + +// Global configuration variable definition +config_t g_config = { + .ccel_file = "ccel.bin", + .event_log_file = "event_log.bin", + .rem_file = "rem.txt" +}; + +static void print_usage(const char* program_name) { + printf("Usage: %s [options] \n", program_name); + printf("\nCommands:\n"); + printf(" eventlogs - Dump VCCA event logs\n"); + printf(" verify - Verify REM values\n"); + printf("\nOptions:\n"); + printf(" -c, --ccel CCEL file path (default: ccel.bin)\n"); + printf(" -e, --eventlog Event log file path (default: event_log.bin)\n"); + printf(" -r, --rem REM file path (default: rem.txt)\n"); + printf(" -h, --help Show this help message\n"); +} + +static int parse_args(int argc, char* argv[]) { + static struct option long_options[] = { + {"ccel", required_argument, 0, 'c'}, + {"eventlog", required_argument, 0, 'e'}, + {"rem", required_argument, 0, 'r'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + int opt; + while ((opt = getopt_long(argc, argv, "c:e:r:h", long_options, NULL)) != -1) { + switch (opt) { + case 'c': + g_config.ccel_file = optarg; + break; + case 'e': + g_config.event_log_file = optarg; + break; + case 'r': + g_config.rem_file = optarg; + break; + case 'h': + print_usage(argv[0]); + return 1; + default: + print_usage(argv[0]); + return -1; + } + } + + if (optind >= argc) { + printf("Error: Command not specified\n"); + print_usage(argv[0]); + return -1; + } + + return optind; +} + +static void print_hex_dump_with_ascii(const uint8_t* data, size_t length) { + char ascii_buf[17] = {0}; + + printf("=> Read CCEL ACPI Table\n"); + for (size_t i = 0; i < length; i++) { + if (i % 16 == 0) { + if (i > 0) printf(" %s\n", ascii_buf); + printf("%08zX ", i); + memset(ascii_buf, 0, sizeof(ascii_buf)); + } + printf("%02X ", data[i]); + ascii_buf[i % 16] = isprint(data[i]) ? data[i] : '.'; + } + + // Process the last line + if (length % 16 != 0) { + // Fill in spaces. + for (size_t i = length % 16; i < 16; i++) { + printf(" "); + } + } + printf(" %s\n", ascii_buf); +} + +static int handle_eventlogs_command(void) { + // 1. Read CCEL file + FILE* fp = fopen(g_config.ccel_file, "rb"); + if (!fp) { + printf("Error: Could not open CCEL file: %s\n", g_config.ccel_file); + return 1; + } + + // Get file size + fseek(fp, 0, SEEK_END); + size_t file_size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + // Read CCEL data + uint8_t* ccel_data = (uint8_t*)malloc(file_size); + if (!ccel_data) { + fclose(fp); + return 1; + } + + if (fread(ccel_data, 1, file_size, fp) != file_size) { + free(ccel_data); + fclose(fp); + return 1; + } + fclose(fp); + + // Verify CCEL signature + if (file_size < 4 || memcmp(ccel_data, "CCEL", 4) != 0) { + printf("Error: Invalid CCEL signature\n"); + free(ccel_data); + return 1; + } + + // Print CCEL content + print_hex_dump_with_ascii(ccel_data, file_size); + + // Parse and print CCEL information + printf("Revision: %d\n", ccel_data[8]); // Offset 8 bytes + printf("Checksum: %02X\n", ccel_data[9]); // Offset 9 bytes + // Print OEM ID (6 bytes, starting from offset 10) + printf("OEM ID: b'"); + for (int i = 0; i < 6; i++) { + printf("%c", ccel_data[10 + i]); + } + printf("'\n"); + + // Read CC Type and Sub-type from CCEL + printf("CC Type: %d\n", ccel_data[36]); // Offset 36 bytes + printf("CC Sub-type: %d\n", ccel_data[37]); // Offset 37 bytes + // Read log area information from CCEL + uint64_t log_length = *(uint64_t*)(ccel_data + 40); // Offset 40 bytes, 64-bit value + uint64_t log_address = *(uint64_t*)(ccel_data + 48); // Offset 48 bytes, 64-bit value + + printf("Log Lenght: 0x%08lX\n", (unsigned long)log_length); + printf("Log Address: 0x%08lX\n", (unsigned long)log_address); + printf("\n"); + + // 3. Initializing the Event Log Processor + vcca_event_log_t event_log; + if (!vcca_event_log_init(&event_log, (size_t)log_address, (size_t)log_length)) { + printf("Error: Failed to initialize event log\n"); + free(ccel_data); + return 1; + } + + // 4. Processes and displays event logs + vcca_event_log_dump(&event_log); + + free(ccel_data); + return 0; +} + +static int handle_verify_command(void) { + if (!verify_rem()) { + printf("REM verification failed\n"); + return 1; + } + return 0; +} + +int main(int argc, char* argv[]) { + int cmd_index = parse_args(argc, argv); + if (cmd_index < 0) { + return 1; + } + if (cmd_index == 1) { + return 0; + } + + if (strcmp(argv[cmd_index], "eventlogs") == 0) { + return handle_eventlogs_command(); + } else if (strcmp(argv[cmd_index], "verify") == 0) { + return handle_verify_command(); + } else { + printf("Error: Unknown command '%s'\n", argv[cmd_index]); + print_usage(argv[0]); + return 1; + } +} \ No newline at end of file diff --git a/attestation/cvccaattest/src/rem.c b/attestation/cvccaattest/src/rem.c new file mode 100644 index 0000000..b72dc50 --- /dev/null +++ b/attestation/cvccaattest/src/rem.c @@ -0,0 +1,24 @@ +#include +#include +#include "rem.h" + +bool rem_init(rem_t* rem) { + if (!rem) return false; + memset(rem->data, 0, REM_LENGTH_BYTES); + return true; +} + +bool rem_compare(const rem_t* rem1, const rem_t* rem2) { + if (!rem1 || !rem2) return false; + return memcmp(rem1->data, rem2->data, REM_LENGTH_BYTES) == 0; +} + +void rem_dump(const rem_t* rem) { + if (!rem) return; + + printf("REM Value: "); + for (int i = 0; i < REM_LENGTH_BYTES; i++) { + printf("%02x", rem->data[i]); + } + printf("\n"); +} \ No newline at end of file diff --git a/attestation/cvccaattest/src/vcca_event_log.c b/attestation/cvccaattest/src/vcca_event_log.c new file mode 100644 index 0000000..57310ed --- /dev/null +++ b/attestation/cvccaattest/src/vcca_event_log.c @@ -0,0 +1,593 @@ +#include +#include +#include +#include +#include +#include +#include "vcca_event_log.h" +#include "config.h" +#include "debug.h" + +// Event log header magic number +#define VCCA_EVENT_LOG_MAGIC 0xFFFFFFFF + +// Add hash algorithm definitions +#define TPM_ALG_ERROR 0x0 +#define TPM_ALG_RSA 0x1 +#define TPM_ALG_SHA1 0x4 +#define TPM_ALG_SHA256 0xB +#define TPM_ALG_SHA384 0xC +#define TPM_ALG_SHA512 0xD +#define TPM_ALG_ECDSA 0x18 + +// Function declarations +static const char* get_event_type_string(uint32_t type); +static void print_hex_dump(const uint8_t* data, size_t length, size_t base_addr); +static void update_rem(rem_t* rem, const uint8_t* digest); +static const char* get_algorithm_string(uint16_t algoid); +static int get_digest_size(uint16_t algoid); + +// Event log entry structure +typedef struct { + uint32_t magic; + uint32_t type; + uint32_t digest_count; + uint8_t* digests; + uint32_t event_size; + uint8_t* event; +} vcca_event_log_header_t; + +// Define global variables +FILE* debug_fp = NULL; + +static bool process_event_log_entry(vcca_event_log_t* log, size_t* pos, + vcca_event_log_entry_t* entry) { + if (!log || !pos || !entry || *pos >= log->blob.length) { + return false; + } + + // Save start position for debugging + size_t start_pos = *pos; + + // Initialize entry + memset(entry, 0, sizeof(vcca_event_log_entry_t)); + + // Read event header + uint32_t register_index = binary_blob_get_uint32(&log->blob, pos); + entry->event_type = binary_blob_get_uint32(&log->blob, pos); + + // Check if reached end of file + if (register_index == VCCA_EVENT_LOG_MAGIC && + entry->event_type == VCCA_EVENT_LOG_MAGIC) { + if (debug_fp) { + fprintf(debug_fp, "Found end marker at pos 0x%zX\n", start_pos); + } + return false; + } + + // Decrease register_index by 1 to ensure REM index starts from 0 + entry->rem_index = register_index > 0 ? register_index - 1 : 0; + + // Read digest count + entry->digest_count = binary_blob_get_uint32(&log->blob, pos); + + // Special handling for EV_NO_ACTION event + if (entry->event_type == EV_NO_ACTION) { + // Skip 20 bytes of digest + *pos += 20; + + // Read Spec ID Event03 string (24 bytes) + uint8_t spec_id[24]; + binary_blob_get_bytes(&log->blob, pos, 24, spec_id); + + // Read algorithm count + entry->algorithms_number = binary_blob_get_uint32(&log->blob, pos); + + // Read algorithm information + entry->algorithms = (algorithm_info_t*)malloc(entry->algorithms_number * sizeof(algorithm_info_t)); + if (!entry->algorithms) { + return false; + } + + for (uint32_t i = 0; i < entry->algorithms_number; i++) { + entry->algorithms[i].algoid = binary_blob_get_uint16(&log->blob, pos); + entry->algorithms[i].digestsize = binary_blob_get_uint16(&log->blob, pos); + } + + // Read vendor information size and skip + uint8_t vendorsize = binary_blob_get_uint8(&log->blob, pos); + *pos += vendorsize; + + // Set event size + entry->event_size = *pos - start_pos; + if (entry->event_size > 0) { + entry->event = (uint8_t*)malloc(entry->event_size); + if (entry->event) { + memcpy(entry->event, log->blob.data + start_pos, entry->event_size); + } + } + + return true; + } + + // Process other type events + + + if (entry->digest_count > 0) { + entry->digests = (uint8_t*)malloc(entry->digest_count * SHA256_DIGEST_LENGTH); + entry->alg_ids = (uint16_t*)malloc(entry->digest_count * sizeof(uint16_t)); + if (!entry->digests || !entry->alg_ids) { + free(entry->digests); + free(entry->alg_ids); + return false; + } + + // Read each digest + for (uint32_t i = 0; i < entry->digest_count; i++) { + // Read algorithm ID + entry->alg_ids[i] = binary_blob_get_uint16(&log->blob, pos); + + // Read digest data + binary_blob_get_bytes(&log->blob, pos, SHA256_DIGEST_LENGTH, + entry->digests + i * SHA256_DIGEST_LENGTH); + } + } + + // Read event data size + uint32_t event_data_size = binary_blob_get_uint32(&log->blob, pos); + + // Read event data + if (event_data_size > 0) { + if (event_data_size > 10240) { + if (debug_fp) { + fprintf(debug_fp, "Invalid event size %u at pos 0x%zX\n", + event_data_size, start_pos); + } + free(entry->digests); + free(entry->alg_ids); + entry->digests = NULL; + entry->alg_ids = NULL; + return false; + } + } + + // Set total event size (including header, digest, and event data) + entry->event_size = *pos - start_pos + event_data_size; + + // Allocate and save complete event data + if (entry->event_size > 0) { + entry->event = (uint8_t*)malloc(entry->event_size); + if (!entry->event) { + free(entry->digests); + free(entry->alg_ids); + entry->digests = NULL; + entry->alg_ids = NULL; + return false; + } + + // Copy header and digest data + memcpy(entry->event, log->blob.data + start_pos, *pos - start_pos); + + // Copy event data + if (event_data_size > 0) { + binary_blob_get_bytes(&log->blob, pos, event_data_size, + entry->event + (*pos - start_pos)); + } + } + + if (debug_fp) { + fprintf(debug_fp, "Event at 0x%zX: rem=%d type=0x%X digests=%d size=%d\n", + start_pos, entry->rem_index, entry->event_type, + entry->digest_count, entry->event_size); + } + + return true; +} + +static void update_rem(rem_t* rem, const uint8_t* digest) { + if (debug_fp) { + fprintf(debug_fp, "DEBUG: Updating REM with digest: "); + for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) { + fprintf(debug_fp, "%02X", digest[i]); + } + fprintf(debug_fp, "\n"); + + fprintf(debug_fp, "DEBUG: Current REM value: "); + for (int i = 0; i < REM_LENGTH_BYTES; i++) { + fprintf(debug_fp, "%02X", rem->data[i]); + } + fprintf(debug_fp, "\n"); + } + + uint8_t hash[SHA256_DIGEST_LENGTH]; + EVP_MD_CTX* ctx = EVP_MD_CTX_new(); + if (!ctx) { + printf("Error: Failed to create EVP context\n"); + return; + } + + if (EVP_DigestInit_ex(ctx, EVP_sha256(), NULL) != 1) { + printf("Error: Failed to initialize SHA256\n"); + EVP_MD_CTX_free(ctx); + return; + } + + // Update REM data + if (EVP_DigestUpdate(ctx, rem->data, REM_LENGTH_BYTES) != 1) { + printf("Error: Failed to update REM data\n"); + EVP_MD_CTX_free(ctx); + return; + } + + // Update digest data + if (EVP_DigestUpdate(ctx, digest, SHA256_DIGEST_LENGTH) != 1) { + printf("Error: Failed to update digest data\n"); + EVP_MD_CTX_free(ctx); + return; + } + + // Get final hash value + unsigned int hash_len; + if (EVP_DigestFinal_ex(ctx, hash, &hash_len) != 1) { + printf("Error: Failed to finalize hash\n"); + EVP_MD_CTX_free(ctx); + return; + } + + // Copy hash value to REM + memcpy(rem->data, hash, REM_LENGTH_BYTES); + + if (debug_fp) { + fprintf(debug_fp, "DEBUG: New REM value: "); + for (int i = 0; i < REM_LENGTH_BYTES; i++) { + fprintf(debug_fp, "%02X", rem->data[i]); + } + fprintf(debug_fp, "\n"); + } + + EVP_MD_CTX_free(ctx); +} + +bool vcca_event_log_init(vcca_event_log_t* log, size_t base, size_t length) { + if (!log) { + return false; + } + + // Read event log data from file + FILE* fp = fopen(g_config.event_log_file, "rb"); + if (!fp) { + printf("Error: Could not open event log file: %s\n", g_config.event_log_file); + return false; + } + + // Get file size + fseek(fp, 0, SEEK_END); + size_t file_size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + printf("Reading event log file: %s (size: %zu bytes)\n", g_config.event_log_file, file_size); + + // Allocate memory and read data + uint8_t* data = (uint8_t*)malloc(file_size); + if (!data) { + printf("Error: Failed to allocate memory for event log data\n"); + fclose(fp); + return false; + } + + if (fread(data, 1, file_size, fp) != file_size) { + printf("Error: Failed to read event log data\n"); + free(data); + fclose(fp); + return false; + } + fclose(fp); + + printf("DEBUG: First 32 bytes of event log:\n"); + for (size_t i = 0; i < 32 && i < file_size; i++) { + if (i % 16 == 0) printf("\n%04zX: ", i); + printf("%02X ", data[i]); + } + printf("\n\n"); + + // Initialize binary blob + if (!binary_blob_init(&log->blob, data, file_size, base)) { + printf("Error: Failed to initialize binary blob\n"); + free(data); + return false; + } + + log->log_base = base; + log->log_length = file_size; + + // Initialize all REM values to 0 + for (int i = 0; i < REM_COUNT; i++) { + rem_init(&log->rems[i]); + } + + return true; +} + +static void print_hex_dump(const uint8_t* data, size_t length, size_t base_addr) { + char ascii_buf[17] = {0}; + + for (size_t i = 0; i < length; i++) { + if (i % 16 == 0) { + if (i > 0) printf(" %s\n", ascii_buf); + if (base_addr) { + printf("%08zX ", base_addr + i); + } else { + printf("%08zX ", i); + } + memset(ascii_buf, 0, sizeof(ascii_buf)); + } + printf("%02X ", data[i]); + ascii_buf[i % 16] = isprint(data[i]) ? data[i] : '.'; + } + + // Process last line + if (length % 16 != 0) { + // Pad with spaces + for (size_t i = length % 16; i < 16; i++) { + printf(" "); + } + } + printf(" %s\n", ascii_buf); +} + +// Move function definitions here +static const char* get_event_type_string(uint32_t type) { + switch (type) { + case EV_PREBOOT_CERT: return "EV_PREBOOT_CERT"; + case EV_POST_CODE: return "EV_POST_CODE"; + case EV_UNUSED: return "EV_UNUSED"; + case EV_NO_ACTION: return "EV_NO_ACTION"; + case EV_SEPARATOR: return "EV_SEPARATOR"; + case EV_ACTION: return "EV_ACTION"; + case EV_EVENT_TAG: return "EV_EVENT_TAG"; + case EV_S_CRTM_CONTENTS: return "EV_S_CRTM_CONTENTS"; + case EV_S_CRTM_VERSION: return "EV_S_CRTM_VERSION"; + case EV_CPU_MICROCODE: return "EV_CPU_MICROCODE"; + case EV_PLATFORM_CONFIG_FLAGS: return "EV_PLATFORM_CONFIG_FLAGS"; + case EV_TABLE_OF_DEVICES: return "EV_TABLE_OF_DEVICES"; + case EV_COMPACT_HASH: return "EV_COMPACT_HASH"; + case EV_IPL: return "EV_IPL"; + case EV_IPL_PARTITION_DATA: return "EV_IPL_PARTITION_DATA"; + case EV_NONHOST_CODE: return "EV_NONHOST_CODE"; + case EV_NONHOST_CONFIG: return "EV_NONHOST_CONFIG"; + case EV_NONHOST_INFO: return "EV_NONHOST_INFO"; + case EV_OMIT_BOOT_DEVICE_EVENTS: return "EV_OMIT_BOOT_DEVICE_EVENTS"; + case EV_EFI_VARIABLE_DRIVER_CONFIG: return "EV_EFI_VARIABLE_DRIVER_CONFIG"; + case EV_EFI_VARIABLE_BOOT: return "EV_EFI_VARIABLE_BOOT"; + case EV_EFI_BOOT_SERVICES_APPLICATION: return "EV_EFI_BOOT_SERVICES_APPLICATION"; + case EV_EFI_BOOT_SERVICES_DRIVER: return "EV_EFI_BOOT_SERVICES_DRIVER"; + case EV_EFI_RUNTIME_SERVICES_DRIVER: return "EV_EFI_RUNTIME_SERVICES_DRIVER"; + case EV_EFI_GPT_EVENT: return "EV_EFI_GPT_EVENT"; + case EV_EFI_ACTION: return "EV_EFI_ACTION"; + case EV_EFI_PLATFORM_FIRMWARE_BLOB: return "EV_EFI_PLATFORM_FIRMWARE_BLOB"; + case EV_EFI_HANDOFF_TABLES: return "EV_EFI_HANDOFF_TABLES"; + case EV_EFI_VARIABLE_AUTHORITY: return "EV_EFI_VARIABLE_AUTHORITY"; + default: return "UNKNOWN"; + } +} + +// Add function to get algorithm name +static const char* get_algorithm_string(uint16_t algoid) { + switch(algoid) { + case TPM_ALG_ERROR: return "TPM_ALG_ERROR"; + case TPM_ALG_RSA: return "TPM_ALG_RSA"; + case TPM_ALG_SHA1: return "TPM_ALG_SHA1"; + case TPM_ALG_SHA256: return "TPM_ALG_SHA256"; + case TPM_ALG_SHA384: return "TPM_ALG_SHA384"; + case TPM_ALG_SHA512: return "TPM_ALG_SHA512"; + case TPM_ALG_ECDSA: return "TPM_ALG_ECDSA"; + default: return "UNKNOWN"; + } +} + +// Add function to get digest length +static int get_digest_size(uint16_t algoid) { + switch(algoid) { + case TPM_ALG_SHA1: return 20; + case TPM_ALG_SHA256: return 32; + case TPM_ALG_SHA384: return 48; + case TPM_ALG_SHA512: return 64; + default: return 0; + } +} + +bool vcca_event_log_process(vcca_event_log_t* log) { + if (!log) { + return false; + } + + printf("=> Read Event Log Data - Address: 0x%zX(0x%zX)\n", + log->log_base, log->log_length); + + size_t pos = 0; + vcca_event_log_entry_t entry = {0}; + int entry_count = 0; + + while (pos < log->blob.length) { + // Record current event start position + size_t event_start = pos; + + if (!process_event_log_entry(log, &pos, &entry)) { + break; + } + + printf("\n==== VCCA Event Log Entry - %d [0x%zX] ====\n", + entry_count, log->log_base + event_start); + // REM index + printf("REM : %d\n", entry.rem_index); + printf("Type : 0x%X (%s)\n", entry.event_type, + get_event_type_string(entry.event_type)); + printf("Length : %d\n", entry.event_size); + + if (entry.event_type == 0x3) { // EV_NO_ACTION + printf("Algorithms Number : %d\n", entry.algorithms_number); + for (uint32_t i = 0; i < entry.algorithms_number; i++) { + printf(" Algorithms[0x%X] Size: %d\n", + entry.algorithms[i].algoid, + entry.algorithms[i].digestsize * 8); + } + } + + if (entry.digest_count > 0) { + printf("Algorithms ID : %d (%s)\n", + entry.alg_ids[0], + get_algorithm_string(entry.alg_ids[0])); + + int digest_size = get_digest_size(entry.alg_ids[0]); + if (digest_size > 0) { + printf("Digest[0] :\n"); + print_hex_dump(entry.digests, digest_size, 0); + } + } + + if (entry.event_size > 0 && entry.event) { + printf("RAW DATA: ----------------------------------------------\n"); + print_hex_dump(entry.event, entry.event_size, + log->log_base + event_start); + printf("RAW DATA: ----------------------------------------------\n"); + } + + // Free memory + if (entry.digests) { + free(entry.digests); + entry.digests = NULL; + } + if (entry.alg_ids) { + free(entry.alg_ids); + entry.alg_ids = NULL; + } + if (entry.event) { + free(entry.event); + entry.event = NULL; + } + if (entry.algorithms) { + free(entry.algorithms); + entry.algorithms = NULL; + } + entry_count++; + } + + return true; +} + +bool vcca_event_log_replay(vcca_event_log_t* log) { + if (!log) { + return false; + } + + init_debug_log(); + + size_t pos = 0; + vcca_event_log_entry_t entry = {0}; + + printf("\n=> Replay Rolling Hash - REM\n"); + + // Initialize all REM values to 0 + for (int i = 0; i < REM_COUNT; i++) { + rem_init(&log->rems[i]); + } + + // First pass: Process EV_NO_ACTION events + while (pos < log->blob.length) { + size_t start_pos = pos; // Record start position + + if (!process_event_log_entry(log, &pos, &entry)) { + break; + } + + // Check if reached end of file + if (entry.rem_index == VCCA_EVENT_LOG_MAGIC && + entry.event_type == VCCA_EVENT_LOG_MAGIC) { + break; + } + + if (entry.event_type == 0x3) { // EV_NO_ACTION + if (entry.rem_index < REM_COUNT && entry.digest_count > 0) { + if (debug_fp) { + fprintf(debug_fp, "Processing EV_NO_ACTION at pos 0x%zX for REM[%d]\n", + start_pos, entry.rem_index); + } + update_rem(&log->rems[entry.rem_index], entry.digests); + } + } + + // Free memory + if (entry.digests) { + free(entry.digests); + entry.digests = NULL; + } + if (entry.event) { + free(entry.event); + entry.event = NULL; + } + } + + // Reset position + pos = 0; + + // Second pass: Process other events + while (pos < log->blob.length) { + size_t start_pos = pos; // Record start position + + if (!process_event_log_entry(log, &pos, &entry)) { + break; + } + + // Check if reached end of file + if (entry.rem_index == VCCA_EVENT_LOG_MAGIC && + entry.event_type == VCCA_EVENT_LOG_MAGIC) { + break; + } + + if (entry.event_type != 0x3) { // Non EV_NO_ACTION + if (entry.rem_index < REM_COUNT && entry.digest_count > 0) { + if (debug_fp) { + fprintf(debug_fp, "Processing event type 0x%X at pos 0x%zX for REM[%d]\n", + entry.event_type, start_pos, entry.rem_index); + } + update_rem(&log->rems[entry.rem_index], entry.digests); + } + } + + // Free memory + if (entry.digests) { + free(entry.digests); + entry.digests = NULL; + } + if (entry.event) { + free(entry.event); + entry.event = NULL; + } + } + + // Print final REM values + for (int i = 0; i < REM_COUNT; i++) { + printf("\n==== REM[%d] ====\n", i); + print_hex_dump(log->rems[i].data, REM_LENGTH_BYTES, 0); + } + + if (debug_fp) { + fclose(debug_fp); + debug_fp = NULL; + } + + return true; +} + +void vcca_event_log_dump(vcca_event_log_t* log) { + if (!log) { + return; + } + + printf("Event log base: 0x%zX, length: 0x%zX\n", log->log_base, log->log_length); + printf("Actual data size: %zu bytes\n\n", log->blob.length); + + vcca_event_log_process(log); + printf("\n"); // Add empty line + vcca_event_log_replay(log); +} \ No newline at end of file diff --git a/attestation/cvccaattest/src/verify.c b/attestation/cvccaattest/src/verify.c new file mode 100644 index 0000000..4d3c14a --- /dev/null +++ b/attestation/cvccaattest/src/verify.c @@ -0,0 +1,153 @@ +#include +#include +#include +#include "verify.h" +#include "config.h" + +// Length of REM value read from rem.txt file (each value is 32 bytes, represented as 64 hex characters) +#define REM_HEX_LENGTH 64 + +static bool hex_to_bytes(const char* hex_str, uint8_t* bytes, size_t length) { + if (!hex_str || !bytes || strlen(hex_str) != length * 2) { + return false; + } + + for (size_t i = 0; i < length; i++) { + char hex[3] = {hex_str[i * 2], hex_str[i * 2 + 1], 0}; + unsigned int value; + if (sscanf(hex, "%02x", &value) != 1) { + return false; + } + bytes[i] = (uint8_t)value; + } + return true; +} + +static bool read_token_rem(rem_t rems[REM_COUNT]) { + FILE* fp = fopen(g_config.rem_file, "r"); + if (!fp) { + printf("Error: Could not open REM file: %s\n", g_config.rem_file); + return false; + } + + char line[256]; + int rem_index = 0; + + while (fgets(line, sizeof(line), fp) && rem_index < REM_COUNT) { + char* pos = strstr(line, "REM["); + if (!pos) { + continue; + } + + // Find the REM value hex string + pos = strchr(line, ':'); + if (!pos) { + continue; + } + pos++; // Skip colon + + // Skip spaces + while (*pos == ' ') { + pos++; + } + + // Remove trailing newline + char* newline = strchr(pos, '\n'); + if (newline) { + *newline = '\0'; + } + + // Convert hex string to byte array + if (!hex_to_bytes(pos, rems[rem_index].data, REM_LENGTH_BYTES)) { + printf("Error: Failed to parse REM[%d] value\n", rem_index); + fclose(fp); + return false; + } + + rem_index++; + } + + fclose(fp); + return rem_index == REM_COUNT; +} + +static void verify_single_rem(int rem_index, const rem_t* rem1, const rem_t* rem2) { + if (!rem1 || !rem2) { + printf("Error: Invalid REM pointers for verification\n"); + return; + } + + if (rem_compare(rem1, rem2)) { + printf("REM[%d] passed the verification.\n", rem_index); + } else { + printf("REM[%d] did not pass the verification\n", rem_index); + printf("Expected: "); + rem_dump(rem1); + printf("Got: "); + rem_dump(rem2); + } +} + +bool verify_rem(void) { + printf("=> Verify REM\n"); + // 1. Read CCEL file + FILE* fp = fopen(g_config.ccel_file, "rb"); + if (!fp) { + printf("Error: Could not open CCEL file: %s\n", g_config.ccel_file); + return false; + } + + // Get file size + fseek(fp, 0, SEEK_END); + size_t file_size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + // Read CCEL data + uint8_t* ccel_data = (uint8_t*)malloc(file_size); + if (!ccel_data) { + fclose(fp); + return false; + } + + if (fread(ccel_data, 1, file_size, fp) != file_size) { + free(ccel_data); + fclose(fp); + return false; + } + fclose(fp); + + // 2. Get the start address and length of event log area from CCEL + // The processing is simplified here. The CCEL structure should be parsed. + size_t log_area_start = 0; // Actually read from CCEL + size_t log_area_length = 0; + + // 3. Initialize event log processor + vcca_event_log_t event_log; + if (!vcca_event_log_init(&event_log, log_area_start, log_area_length)) { + free(ccel_data); + return false; + } + + // 4. Replay event log to calculate REM values + if (!vcca_event_log_replay(&event_log)) { + free(ccel_data); + return false; + } + + // 5. Read REM values from attestation token + rem_t token_rems[REM_COUNT]; + if (!read_token_rem(token_rems)) { + printf("Error: Could not read REM file: %s\n", g_config.rem_file); + free(ccel_data); + return false; + } + + // 6. Verify each REM value + printf("\nVerifying REM values...\n"); + for (int i = 0; i < REM_COUNT; i++) { + verify_single_rem(i, &token_rems[i], &event_log.rems[i]); + } + + free(ccel_data); + return true; +} \ No newline at end of file diff --git a/attestation/cvccaattest/testdata/ccel.bin b/attestation/cvccaattest/testdata/ccel.bin new file mode 100644 index 0000000000000000000000000000000000000000..440bd2537bb56f4ad572a02cec050c0653d6d613 GIT binary patch literal 56 xcmZ>EcJ;AfU|?Xp?@^jqo|@_E;%%e=1WZ6N5G@RpVg|B-6qsaSn6wAP001W|2mt^9 literal 0 HcmV?d00001 diff --git a/attestation/cvccaattest/testdata/event_log.bin b/attestation/cvccaattest/testdata/event_log.bin new file mode 100644 index 0000000000000000000000000000000000000000..5f3baa7d718ab88e9ec38d9f60de2cb7b67521e5 GIT binary patch literal 65536 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 literal 0 HcmV?d00001 diff --git a/attestation/cvccaattest/testdata/rem.txt b/attestation/cvccaattest/testdata/rem.txt new file mode 100644 index 0000000..b648a8d --- /dev/null +++ b/attestation/cvccaattest/testdata/rem.txt @@ -0,0 +1,4 @@ + REM[0]: 18bcc095ddd6c05f7dd585971b26ce4da9f5df16c858473538aa244c53c55aa6 + REM[1]: 53efc45719b8c011454467f95eacc2c489f46aee748a669a44b06960f6948d66 + REM[2]: 984c596c9b120650acffce0e46256ec699a86a7273d48c36ca35f0e7a40892f8 + REM[3]: 0000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file -- Gitee