diff --git a/common/rust/cctrusted_base/Cargo.toml b/common/rust/cctrusted_base/Cargo.toml index 745c2719..caf1ee50 100644 --- a/common/rust/cctrusted_base/Cargo.toml +++ b/common/rust/cctrusted_base/Cargo.toml @@ -15,6 +15,7 @@ path = "src/lib.rs" anyhow = "1.0" base64 = "0.13.0" log = "0.4.20" +sha1 = "0.10.6" sha2 = "0.10" lazy_static = "1.4.0" hashbrown = "0.14" diff --git a/common/rust/cctrusted_base/src/api.rs b/common/rust/cctrusted_base/src/api.rs index 41f2dfac..d367025c 100644 --- a/common/rust/cctrusted_base/src/api.rs +++ b/common/rust/cctrusted_base/src/api.rs @@ -97,6 +97,26 @@ pub trait CCTrustedApi { */ fn get_default_algorithm() -> Result; + + /*** + Replay event logs based on data provided. + TCG event logs can be replayed against IMR measurements to prove the integrity of + the event logs. + Args: + event_logs(Eventlogs): the ``Eventlogs`` object to replay + Returns: + A struct containing the replay result arranged by IMR index and hash algorithm. + Layer 1 key of the struct is the IMR index, the value is another dict which using the + hash algorithm as the key and the replayed measurement as value. + Sample value: + [ + 0: [{ 4: },{ 12: },] + 1: { 12: }, + ] + */ + fn replay_cc_eventlog( + eventlogs: Vec, + ) -> Result, anyhow::Error>; } /*** diff --git a/common/rust/cctrusted_base/src/api_data.rs b/common/rust/cctrusted_base/src/api_data.rs index 87432e49..37f5e36d 100644 --- a/common/rust/cctrusted_base/src/api_data.rs +++ b/common/rust/cctrusted_base/src/api_data.rs @@ -1,4 +1,5 @@ use crate::cc_type::TeeType; +use crate::tcg::TcgDigest; /*** ************************************ @@ -53,3 +54,21 @@ pub struct Algorithm { */ // the return data structure is defined in cctrusted_base as: // cctrusted_base::tcg::TcgDigest + +/*** + ******************************************** + * API get_cc_eventlog() related data * + ******************************************** + */ +// the return data structure is defined in cctrusted_base as: +// crate::tcg::EventLogEntry + +/*** + ******************************************** + * API replay_eventlog() related data * + ******************************************** + */ +pub struct ReplayResult { + pub imr_index: u32, + pub digests: Vec, +} diff --git a/common/rust/cctrusted_base/src/eventlog.rs b/common/rust/cctrusted_base/src/eventlog.rs index 4d5beff0..5dfc3949 100644 --- a/common/rust/cctrusted_base/src/eventlog.rs +++ b/common/rust/cctrusted_base/src/eventlog.rs @@ -1,8 +1,12 @@ +use crate::api_data::ReplayResult; use crate::binary_blob::*; use crate::tcg::*; use anyhow::anyhow; use hashbrown::HashMap; use hex; +use log::info; +use sha1::Sha1; +use sha2::{Digest, Sha256, Sha384, Sha512}; /*** * This is the common struct for tcg event logs to be delivered in different formats. @@ -63,6 +67,22 @@ impl TcgEventLog { fn to_tcg_canonical_format(&self) -> EventLogEntry { todo!() } + + pub fn show(&self) { + info!(" --------------------TcgEventLog--------------------------"); + info!("rec_num = {}", self.rec_num); + info!("imr_index = {}", self.imr_index); + info!("event_type = {}", self.event_type); + for index in 0..self.digests.len() { + info!( + "digest[{}] = {}", + self.digests[index].algo_id, + String::from_utf8_lossy(&self.digests[index].hash) + ); + } + info!("event_size = {}", self.event_size); + info!("event = {}", String::from_utf8_lossy(&self.event)); + } } /*** @@ -452,7 +472,7 @@ impl EventLogs { let algo_id = TcgDigest::get_algorithm_id_from_digest_size(digest_size.try_into().unwrap()); let digest = TcgDigest { algo_id, - hash: hex::decode(elements[1]).expect("Decoding failed"), + hash: hex::decode(elements[1]).expect("Decoding hash string from IMA record failed"), }; digests.push(digest); @@ -469,4 +489,109 @@ impl EventLogs { extra_info, }) } + /*** + Replay event logs by IMR index. + Returns: + A struct containing the replay result arranged by IMR index and hash algorithm. + Layer 1 key of the struct is the IMR index, the value is another dict which using the + hash algorithm as the key and the replayed measurement as value. + Sample results: + [ + 0: [{ 4: },{ 12: },] + 1: { 12: }, + ] + */ + pub fn replay(eventlogs: Vec) -> Result, anyhow::Error> { + let mut replay_results: Vec = Vec::new(); + + for event_log in eventlogs { + match event_log { + EventLogEntry::TcgImrEvent(tcg_imr_event) => { + let imr_index = tcg_imr_event.imr_index; + for digest in tcg_imr_event.digests { + let algo_id = digest.algo_id; + let hash = digest.hash; + let digest_size = TcgDigest::get_digest_size_from_algorithm_id(algo_id); + + let mut imr_pos = usize::MAX; + let mut algo_pos = usize::MAX; + for index1 in 0..replay_results.len() { + if replay_results[index1].imr_index == imr_index { + imr_pos = index1; + } + } + + if imr_pos == usize::MAX { + replay_results.push(ReplayResult { + imr_index, + digests: Vec::new(), + }); + imr_pos = replay_results.len() - 1; + } else { + for index2 in 0..replay_results[imr_pos].digests.len() { + if digest.algo_id == algo_id { + algo_pos = index2; + } + } + } + + if algo_pos == usize::MAX { + replay_results[imr_pos].digests.push(TcgDigest { + algo_id, + hash: vec![0; digest_size.into()], + }); + algo_pos = replay_results[imr_pos].digests.len() - 1; + } + + let hash_input_data = + [replay_results[imr_pos].digests[algo_pos].hash.clone(), hash].concat(); + + match algo_id { + TPM_ALG_SHA1 => { + let mut algo_hasher = Sha1::new(); + algo_hasher.update(hash_input_data); + replay_results[imr_pos].digests[algo_pos].hash = + algo_hasher.finalize().to_vec(); + } + TPM_ALG_SHA256 => { + let mut algo_hasher = Sha256::new(); + algo_hasher.update(hash_input_data); + replay_results[imr_pos].digests[algo_pos].hash = + algo_hasher.finalize().to_vec(); + } + TPM_ALG_SHA384 => { + let mut algo_hasher = Sha384::new(); + algo_hasher.update(hash_input_data); + replay_results[imr_pos].digests[algo_pos].hash = + algo_hasher.finalize().to_vec(); + } + TPM_ALG_SHA512 => { + let mut algo_hasher = Sha512::new(); + algo_hasher.update(hash_input_data); + replay_results[imr_pos].digests[algo_pos].hash = + algo_hasher.finalize().to_vec(); + } + 0_u16..=3_u16 | 5_u16..=10_u16 | 14_u16..=u16::MAX => (), + } + } + } + EventLogEntry::TcgPcClientImrEvent(_) => (), // Skip TcgPcClientImrEvent during replay + EventLogEntry::TcgCanonicalEvent(_) => todo!(), + } + } + Ok(replay_results) + } +} + +impl ReplayResult { + pub fn show(&self) { + info!( + "-------------------------------Replay Result of IMR[{}]-----------------------------", + self.imr_index + ); + for digest in &self.digests { + info!("Algorithm: {}", digest.get_algorithm_id_str()); + info!("Digest: {:02X?}", digest.hash); + } + } } diff --git a/common/rust/cctrusted_base/src/tcg.rs b/common/rust/cctrusted_base/src/tcg.rs index c87744b2..1e5fc34b 100644 --- a/common/rust/cctrusted_base/src/tcg.rs +++ b/common/rust/cctrusted_base/src/tcg.rs @@ -39,6 +39,17 @@ lazy_static! { }; } +lazy_static! { + pub static ref TPM_HASH_ALG_DIGEST_SIZE_MAP: HashMap = { + let mut map: HashMap = HashMap::new(); + map.insert(TPM_ALG_SHA1, 20); + map.insert(TPM_ALG_SHA256, 32); + map.insert(TPM_ALG_SHA384, 48); + map.insert(TPM_ALG_SHA512, 64); + map + }; +} + // this trait retrieve tcg standard algorithm name in string pub trait TcgAlgorithmRegistry { fn get_algorithm_id(&self) -> u16; @@ -72,6 +83,13 @@ impl TcgDigest { None => TPM_ALG_ERROR, } } + + pub fn get_digest_size_from_algorithm_id(algo_id: u16) -> u8 { + match TPM_HASH_ALG_DIGEST_SIZE_MAP.get(&algo_id) { + Some(digest_size) => *digest_size, + None => 0, + } + } } impl TcgAlgorithmRegistry for TcgDigest { diff --git a/vmsdk/rust/cctrusted_vm/src/cvm.rs b/vmsdk/rust/cctrusted_vm/src/cvm.rs index 549eebfe..3b3a11ba 100644 --- a/vmsdk/rust/cctrusted_vm/src/cvm.rs +++ b/vmsdk/rust/cctrusted_vm/src/cvm.rs @@ -1,5 +1,6 @@ use crate::tdvm::TdxVM; use anyhow::*; +use cctrusted_base::api_data::ReplayResult; use cctrusted_base::cc_type::*; use cctrusted_base::tcg::EventLogEntry; use cctrusted_base::tcg::{TcgAlgorithmRegistry, TcgDigest}; @@ -61,6 +62,25 @@ pub trait CVM { count: Option, ) -> Result, anyhow::Error>; + /*** + replay retrived CVM eventlogs + Args: + array of eventlogs + Returns: + A struct containing the replay result arranged by IMR index and hash algorithm. + Layer 1 key of the struct is the IMR index, the value is another dict which using the + hash algorithm as the key and the replayed measurement as value. + Sample value: + [ + 0: [{ 4: },{ 12: },] + 1: { 12: }, + ] + */ + fn replay_eventlog( + &self, + eventlogs: Vec, + ) -> Result, anyhow::Error>; + /*** retrive CVM type diff --git a/vmsdk/rust/cctrusted_vm/src/sdk.rs b/vmsdk/rust/cctrusted_vm/src/sdk.rs index 1e38f9db..a6fe4bb9 100644 --- a/vmsdk/rust/cctrusted_vm/src/sdk.rs +++ b/vmsdk/rust/cctrusted_vm/src/sdk.rs @@ -68,6 +68,16 @@ impl CCTrustedApi for API { } } + // CCTrustedApi trait function: replay eventlogs of a CVM + fn replay_cc_eventlog( + eventlogs: Vec, + ) -> Result, anyhow::Error> { + match build_cvm() { + Ok(cvm) => cvm.replay_eventlog(eventlogs), + Err(e) => Err(anyhow!("[replay_cc_eventlog] error create cvm: {:?}", e)), + } + } + // CCTrustedApi trait function: get default algorithm of a CVM fn get_default_algorithm() -> Result { match build_cvm() { diff --git a/vmsdk/rust/cctrusted_vm/src/tdvm.rs b/vmsdk/rust/cctrusted_vm/src/tdvm.rs index 5a89b4f6..a155987d 100644 --- a/vmsdk/rust/cctrusted_vm/src/tdvm.rs +++ b/vmsdk/rust/cctrusted_vm/src/tdvm.rs @@ -2,6 +2,7 @@ use crate::cvm::*; use anyhow::*; +use cctrusted_base::api_data::ReplayResult; use cctrusted_base::cc_type::*; use cctrusted_base::eventlog::EventLogs; use cctrusted_base::tcg::EventLogEntry; @@ -433,6 +434,13 @@ impl CVM for TdxVM { eventlogs.select(start, count) } + fn replay_eventlog( + &self, + eventlogs: Vec, + ) -> Result, anyhow::Error> { + EventLogs::replay(eventlogs) + } + // CVM trait function: retrive CVM type fn get_cc_type(&self) -> CcType { self.cc_type.clone() diff --git a/vmsdk/rust/sample/src/cc-sample-eventlog.rs b/vmsdk/rust/sample/src/cc-sample-eventlog.rs index efafdebf..979895c1 100644 --- a/vmsdk/rust/sample/src/cc-sample-eventlog.rs +++ b/vmsdk/rust/sample/src/cc-sample-eventlog.rs @@ -7,7 +7,7 @@ fn main() { env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); // retrieve cc eventlog with API "get_cc_eventlog" - let event_logs = match API::get_cc_eventlog(Some(1), Some(10)) { + let eventlogs = match API::get_cc_eventlog(Some(1), None) { Ok(q) => q, Err(e) => { error!("error getting TDX report: {:?}", e); @@ -15,8 +15,22 @@ fn main() { } }; - info!("event log count: {}", event_logs.len()); - for event_log in event_logs { - event_log.show(); + info!("event log count: {}", eventlogs.len()); + // for eventlog in &eventlogs { + // eventlog.show(); + // } + + // replay cc eventlog with API "replay_cc_eventlog" + let replay_results = match API::replay_cc_eventlog(eventlogs) { + Ok(q) => q, + Err(e) => { + error!("error replay eventlog: {:?}", e); + return; + } + }; + + // show replay results + for replay_result in replay_results { + replay_result.show(); } }