Skip to content

Commit

Permalink
this commit add replay_cc_eventlog API in rust VM SDK: (#69)
Browse files Browse the repository at this point in the history
- replay of retrieved eventlogs via get_cc_eventlog
- return replayed measurements per IMR index and IMR algorithm
  • Loading branch information
hairongchen authored Jan 26, 2024
1 parent 033a0c1 commit 965409a
Show file tree
Hide file tree
Showing 9 changed files with 240 additions and 5 deletions.
1 change: 1 addition & 0 deletions common/rust/cctrusted_base/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
20 changes: 20 additions & 0 deletions common/rust/cctrusted_base/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,26 @@ pub trait CCTrustedApi {
*/
fn get_default_algorithm() -> Result<Algorithm, anyhow::Error>;

/***
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: <measurement_replayed>},{ 12: <measurement_replayed>},]
1: { 12: <measurement_replayed>},
]
*/
fn replay_cc_eventlog(
eventlogs: Vec<EventLogEntry>,
) -> Result<Vec<ReplayResult>, anyhow::Error>;
}

/***
Expand Down
19 changes: 19 additions & 0 deletions common/rust/cctrusted_base/src/api_data.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::cc_type::TeeType;
use crate::tcg::TcgDigest;

/***
************************************
Expand Down Expand Up @@ -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<TcgDigest>,
}
127 changes: 126 additions & 1 deletion common/rust/cctrusted_base/src/eventlog.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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));
}
}

/***
Expand Down Expand Up @@ -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);

Expand All @@ -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: <measurement_replayed>},{ 12: <measurement_replayed>},]
1: { 12: <measurement_replayed>},
]
*/
pub fn replay(eventlogs: Vec<EventLogEntry>) -> Result<Vec<ReplayResult>, anyhow::Error> {
let mut replay_results: Vec<ReplayResult> = 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);
}
}
}
18 changes: 18 additions & 0 deletions common/rust/cctrusted_base/src/tcg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ lazy_static! {
};
}

lazy_static! {
pub static ref TPM_HASH_ALG_DIGEST_SIZE_MAP: HashMap<u16, u8> = {
let mut map: HashMap<u16, u8> = 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;
Expand Down Expand Up @@ -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 {
Expand Down
20 changes: 20 additions & 0 deletions vmsdk/rust/cctrusted_vm/src/cvm.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -61,6 +62,25 @@ pub trait CVM {
count: Option<u32>,
) -> Result<Vec<EventLogEntry>, 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: <measurement_replayed>},{ 12: <measurement_replayed>},]
1: { 12: <measurement_replayed>},
]
*/
fn replay_eventlog(
&self,
eventlogs: Vec<EventLogEntry>,
) -> Result<Vec<ReplayResult>, anyhow::Error>;

/***
retrive CVM type
Expand Down
10 changes: 10 additions & 0 deletions vmsdk/rust/cctrusted_vm/src/sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ impl CCTrustedApi for API {
}
}

// CCTrustedApi trait function: replay eventlogs of a CVM
fn replay_cc_eventlog(
eventlogs: Vec<EventLogEntry>,
) -> Result<Vec<ReplayResult>, 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<Algorithm, anyhow::Error> {
match build_cvm() {
Expand Down
8 changes: 8 additions & 0 deletions vmsdk/rust/cctrusted_vm/src/tdvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -433,6 +434,13 @@ impl CVM for TdxVM {
eventlogs.select(start, count)
}

fn replay_eventlog(
&self,
eventlogs: Vec<EventLogEntry>,
) -> Result<Vec<ReplayResult>, anyhow::Error> {
EventLogs::replay(eventlogs)
}

// CVM trait function: retrive CVM type
fn get_cc_type(&self) -> CcType {
self.cc_type.clone()
Expand Down
22 changes: 18 additions & 4 deletions vmsdk/rust/sample/src/cc-sample-eventlog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,30 @@ 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);
return;
}
};

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();
}
}

0 comments on commit 965409a

Please sign in to comment.