diff --git a/common/rust/evidence_api/.gitignore b/common/rust/evidence_api/.gitignore new file mode 100644 index 00000000..4fffb2f8 --- /dev/null +++ b/common/rust/evidence_api/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/common/rust/evidence_api/Cargo.toml b/common/rust/evidence_api/Cargo.toml index a7fe6c5d..784e949d 100644 --- a/common/rust/evidence_api/Cargo.toml +++ b/common/rust/evidence_api/Cargo.toml @@ -20,3 +20,5 @@ sha2 = "0.10" lazy_static = "1.4.0" hashbrown = "0.14" hex = "0.4.3" +scale = { version = "3.6.12", package = "parity-scale-codec", features = ["derive"] } +num_enum = "0.7.3" diff --git a/common/rust/evidence_api/src/eventlog.rs b/common/rust/evidence_api/src/eventlog.rs index bca6b9be..af7561b3 100644 --- a/common/rust/evidence_api/src/eventlog.rs +++ b/common/rust/evidence_api/src/eventlog.rs @@ -1,10 +1,15 @@ +use std::io::Read; + use crate::api_data::ReplayResult; -use crate::binary_blob::*; +use crate::codecs::VecOf; use crate::tcg::*; use anyhow::anyhow; +use anyhow::bail; +use anyhow::Context; use hashbrown::HashMap; use hex; use log::info; +use scale::Decode; use sha1::Sha1; use sha2::{Digest, Sha256, Sha384, Sha512}; @@ -190,49 +195,39 @@ impl EventLogs { Go through all event log data and parse the contents accordingly Save the parsed event logs into EventLogs. */ - fn parse(&mut self) -> Result { + fn parse(&mut self) -> anyhow::Result { if self.boot_time_data.is_empty() { - return Err(anyhow!("[parse] no boot time eventlog provided")); + bail!("[parse] no boot time eventlog provided"); } - let mut index = 0; - while index < self.boot_time_data.len() { - let start = index; - let imr = get_u32(self.boot_time_data[index..index + 4].to_vec()); - index += 4; - let event_type = get_u32(self.boot_time_data[index..index + 4].to_vec()); + // A buffer used as a input reader + let buffer = &mut &self.boot_time_data[..]; + + while !buffer.is_empty() { + // A tmp head_buffer is used to peek the imr and event type + let head_buffer = &mut &buffer[..]; + let imr = u32::decode(head_buffer).context("failed to decode imr")?; if imr == 0xFFFFFFFF { break; } + let event_type = u32::decode(head_buffer).context("failed to decode event type")?; if event_type == EV_NO_ACTION && self.count == 0 { - match self.parse_spec_id_event_log(self.boot_time_data[start..].to_vec()) { - Ok((spec_id_event, event_len)) => { - index = start + event_len as usize; - self.event_logs - .push(spec_id_event.format_event_log(self.parse_format)); - self.count += 1; - } - Err(e) => { - return Err(anyhow!( - "[parse] error in parse_spec_id_event_log function {:?}", - e - )); - } - } + let (spec_id_header, spec_id_event) = Self::parse_spec_id_event_log(buffer) + .context("[parse] error in parse_spec_id_event_log function")?; + let todo = "Assign the rec_num"; + self.event_logs + .push(spec_id_header.format_event_log(self.parse_format)); + self.spec_id_header_event = spec_id_event; } else { - match self.parse_event_log(self.boot_time_data[start..].to_vec()) { - Ok((event_log, event_len)) => { - index = start + event_len as usize; - self.event_logs - .push(event_log.format_event_log(self.parse_format)); - self.count += 1; - } - Err(e) => { - return Err(anyhow!("[parse] error in parse_event_log function {:?}", e)); - } - } + let event_log = self + .parse_event_log(buffer) + .context("[parse] error in parse_event_log function")?; + let todo = "Assign the rec_num"; + self.event_logs + .push(event_log.format_event_log(self.parse_format)); } + self.count += 1; } if !self.run_time_data.is_empty() { @@ -274,95 +269,39 @@ impl EventLogs { An int specifying the event size */ fn parse_spec_id_event_log( - &mut self, - data: Vec, - ) -> Result<(TcgEventLog, u32), anyhow::Error> { - let mut index = 0; - - let imr_index = get_u32(data[index..index + 4].to_vec()); - index += 4; - let header_imr = imr_index - 1; - let header_event_type = get_u32(data[index..index + 4].to_vec()); - index += 4; - - let rec_num = self.get_record_number(header_imr); + input: &mut &[u8], + ) -> anyhow::Result<(TcgEventLog, TcgEfiSpecIdEvent)> { + #[derive(Decode)] + struct Header { + imr_index: u32, + header_event_type: u32, + digest_hash: [u8; 20], + header_event: VecOf, + } - let digest_hash = data[index..index + 20].try_into().unwrap(); - index += 20; - let mut digests: Vec = Vec::new(); - let digest = TcgDigest { + let decoded_header = Header::decode(input).context("failed to decode log_item")?; + // Parse EFI Spec Id Event structure + let spec_id_event = + TcgEfiSpecIdEvent::decode(input).context("failed to decode TcgEfiSpecIdEvent")?; + + let header_imr = decoded_header + .imr_index + .checked_sub(1) + .ok_or(anyhow!("imr_index overflow"))?; + let digests = vec![TcgDigest { algo_id: TPM_ALG_ERROR, - hash: digest_hash, - }; - digests.push(digest); - - let header_event_size = get_u32(data[index..index + 4].to_vec()); - index += 4; - let header_event = data[index..index + header_event_size as usize] - .try_into() - .unwrap(); - let specification_id_header = TcgEventLog { - rec_num, + hash: decoded_header.digest_hash.to_vec(), + }]; + let spec_id_header = TcgEventLog { + rec_num: 0, imr_index: header_imr, - event_type: header_event_type, + event_type: decoded_header.header_event_type, digests, - event_size: header_event_size, - event: header_event, + event_size: decoded_header.header_event.length(), + event: decoded_header.header_event.into_inner(), extra_info: HashMap::new(), }; - - // Parse EFI Spec Id Event structure - let spec_id_signature = data[index..index + 16].try_into().unwrap(); - index += 16; - let spec_id_platform_cls = get_u32(data[index..index + 4].to_vec()); - index += 4; - let spec_id_version_minor = get_u8(data[index..index + 1].to_vec()); - index += 1; - let spec_id_version_major = get_u8(data[index..index + 1].to_vec()); - index += 1; - let spec_id_errata = get_u8(data[index..index + 1].to_vec()); - index += 1; - let spec_id_uint_size = get_u8(data[index..index + 1].to_vec()); - index += 1; - let spec_id_num_of_algo = get_u32(data[index..index + 4].to_vec()); - index += 4; - let mut spec_id_digest_sizes: Vec = Vec::new(); - - for _ in 0..spec_id_num_of_algo { - let algo_id = get_u16(data[index..index + 2].to_vec()); - index += 2; - let digest_size = get_u16(data[index..index + 2].to_vec()); - index += 2; - spec_id_digest_sizes.push(TcgEfiSpecIdEventAlgorithmSize { - algo_id, - digest_size: digest_size.into(), - }); - } - - let spec_id_vendor_size = get_u8(data[index..index + 1].to_vec()); - index += 1; - let mut spec_id_vendor_info = Vec::new(); - if spec_id_vendor_size > 0 { - spec_id_vendor_info = data[index..index + spec_id_vendor_size as usize] - .try_into() - .unwrap(); - } - index += spec_id_vendor_size as usize; - - self.spec_id_header_event = TcgEfiSpecIdEvent { - signature: spec_id_signature, - platform_class: spec_id_platform_cls, - spec_version_minor: spec_id_version_minor, - spec_version_major: spec_id_version_major, - spec_errata: spec_id_errata, - uintn_ize: spec_id_uint_size, - number_of_algorithms: spec_id_num_of_algo, - digest_sizes: spec_id_digest_sizes, - vendor_info_size: spec_id_vendor_size, - vendor_info: spec_id_vendor_info, - }; - - Ok((specification_id_header, index.try_into().unwrap())) + Ok((spec_id_header, spec_id_event)) } /*** @@ -381,46 +320,26 @@ impl EventLogs { A TcgImrEvent containing the event information An int specifying the event size */ - fn parse_event_log(&mut self, data: Vec) -> Result<(TcgEventLog, u32), anyhow::Error> { - let mut index = 0; - - let mut imr_index = get_u32(data[index..index + 4].to_vec()); - index += 4; - imr_index -= 1; - let event_type = get_u32(data[index..index + 4].to_vec()); - index += 4; - - let rec_num = self.get_record_number(imr_index); - + fn parse_event_log(&self, input: &mut &[u8]) -> anyhow::Result { + let mut imr_index = u32::decode(input).context("failed to decode imr_index")?; + imr_index = imr_index.checked_sub(1).context("invalid imr index")?; + let event_type = u32::decode(input).context("failed to decode event_type")?; // Fetch digest count and get each digest and its algorithm - let digest_count = get_u32(data[index..index + 4].to_vec()); - index += 4; + let digest_count = u32::decode(input).context("failed to decode digest_count")?; let mut digests: Vec = Vec::new(); for _ in 0..digest_count { - let alg_id = get_u16(data[index..index + 2].to_vec()); - index += 2; - let mut pos = 0; - - while pos < self.spec_id_header_event.digest_sizes.len() { - if self.spec_id_header_event.digest_sizes[pos].algo_id == alg_id { - break; - } - pos += 1; - } - - if pos == self.spec_id_header_event.digest_sizes.len() { - return Err(anyhow!( - "[parse_event_log] No algorithm with such algo_id {}", - alg_id - )); - } - - let alg = &self.spec_id_header_event.digest_sizes[pos]; + let alg_id = u16::decode(input).context("failed to decode alg_id")?; + let alg = self + .spec_id_header_event + .digest_sizes + .iter() + .find(|&x| x.algo_id == alg_id) + .context("No algorithm with such algo_id")?; let digest_size = alg.digest_size; - let digest_data = data[index..index + digest_size as usize] - .try_into() - .unwrap(); - index += digest_size as usize; + let mut digest_data = vec![0; digest_size as usize]; + input + .read_exact(&mut digest_data) + .context("failed to read digest_data")?; let digest = TcgDigest { algo_id: alg_id, hash: digest_data, @@ -428,23 +347,16 @@ impl EventLogs { digests.push(digest); } - let event_size = get_u32(data[index..index + 4].to_vec()); - index += 4; - let event = data[index..index + event_size as usize].try_into().unwrap(); - index += event_size as usize; - - Ok(( - TcgEventLog { - rec_num, - imr_index, - event_type, - digests, - event_size, - event, - extra_info: HashMap::new(), - }, - index.try_into().unwrap(), - )) + let event = >::decode(input).context("failed to decode event")?; + Ok(TcgEventLog { + rec_num: 0, // TODO: alloc the rec_num outside. + imr_index, + event_type, + digests, + event_size: event.length(), + event: event.into_inner(), + extra_info: HashMap::new(), + }) } /*** diff --git a/common/rust/evidence_api/src/lib.rs b/common/rust/evidence_api/src/lib.rs index c4255190..cc53ce5e 100644 --- a/common/rust/evidence_api/src/lib.rs +++ b/common/rust/evidence_api/src/lib.rs @@ -9,3 +9,60 @@ pub mod eventlog; pub mod tcg; pub mod tdx; pub mod tpm; + +mod codecs { + use std::ops::Deref; + + use scale::{Decode, Input}; + + #[derive(Clone, Debug, PartialEq, Eq)] + pub struct VecOf { + len: I, + inner: Vec, + } + + impl Default for VecOf { + fn default() -> Self { + Self { + len: I::default(), + inner: Vec::default(), + } + } + } + + impl + Copy, T: Decode> Decode for VecOf { + fn decode(input: &mut In) -> Result { + let decoded_len = I::decode(input)?; + let len = decoded_len.into() as usize; + let mut inner = Vec::with_capacity(len); + for _ in 0..len { + inner.push(T::decode(input)?); + } + Ok(Self { + len: decoded_len, + inner, + }) + } + } + + impl VecOf { + pub fn into_inner(self) -> Vec { + self.inner + } + + pub fn length(&self) -> I + where + I: Clone, + { + self.len.clone() + } + } + + impl Deref for VecOf { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.inner + } + } +} diff --git a/common/rust/evidence_api/src/tcg.rs b/common/rust/evidence_api/src/tcg.rs index aedc0c51..ec28adf9 100644 --- a/common/rust/evidence_api/src/tcg.rs +++ b/common/rust/evidence_api/src/tcg.rs @@ -1,4 +1,4 @@ -use crate::binary_blob::dump_data; +use crate::{binary_blob::dump_data, codecs::VecOf}; use hashbrown::HashMap; use log::info; @@ -317,7 +317,7 @@ pub struct TcgPcClientImrEvent { BYTE[VendorInfoSize] vendorInfo; } TCG_EfiSpecIDEventStruct; */ -#[derive(Clone)] +#[derive(Clone, scale::Decode)] pub struct TcgEfiSpecIdEvent { pub signature: [u8; 16], pub platform_class: u32, @@ -325,10 +325,8 @@ pub struct TcgEfiSpecIdEvent { pub spec_version_major: u8, pub spec_errata: u8, pub uintn_ize: u8, - pub number_of_algorithms: u32, - pub digest_sizes: Vec, - pub vendor_info_size: u8, - pub vendor_info: Vec, + pub digest_sizes: VecOf, + pub vendor_info: VecOf, } impl Default for TcgEfiSpecIdEvent { @@ -346,10 +344,8 @@ impl TcgEfiSpecIdEvent { spec_version_major: 0, spec_errata: 0, uintn_ize: 0, - number_of_algorithms: 0, - digest_sizes: Vec::new(), - vendor_info_size: 0, - vendor_info: Vec::new(), + digest_sizes: Default::default(), + vendor_info: Default::default(), } } } @@ -363,10 +359,10 @@ impl TcgEfiSpecIdEvent { UINT16 digestSize; } TCG_EfiSpecIdEventAlgorithmSize; */ -#[derive(Clone)] +#[derive(Clone, scale::Decode)] pub struct TcgEfiSpecIdEventAlgorithmSize { pub algo_id: u16, - pub digest_size: u32, + pub digest_size: u16, } #[derive(Clone)] diff --git a/common/rust/evidence_api/src/tdx/common.rs b/common/rust/evidence_api/src/tdx/common.rs index 10e4f46b..e0243046 100644 --- a/common/rust/evidence_api/src/tdx/common.rs +++ b/common/rust/evidence_api/src/tdx/common.rs @@ -1,6 +1,7 @@ #![allow(non_camel_case_types)] use crate::cc_type::*; use hashbrown::HashMap; +use num_enum::TryFromPrimitive; pub struct Tdx {} @@ -37,19 +38,37 @@ pub const TDX_REPORT_LEN: u32 = 1024; pub const TDX_QUOTE_LEN: usize = 4 * 4096; #[repr(u16)] -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Debug, TryFromPrimitive)] pub enum AttestationKeyType { ECDSA_P256 = 2, ECDSA_P384 = 3, } #[repr(u32)] -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, TryFromPrimitive)] pub enum IntelTeeType { TEE_SGX = 0x00000000, TEE_TDX = 0x00000081, } +macro_rules! impl_decode_for { + ($type: ty) => { + impl scale::Decode for $type { + fn decode(input: &mut In) -> Result { + ::Primitive::decode(input)? + .try_into() + .map_err(|_| { + let err_msg = concat!("failed to decode ", stringify!($type)); + scale::Error::from(err_msg) + }) + } + } + }; +} + +impl_decode_for!(AttestationKeyType); +impl_decode_for!(IntelTeeType); + // QE_VENDOR_INTEL_SGX ID string "939a7233f79c4ca9940a0db3957f0607"; pub const QE_VENDOR_INTEL_SGX: [u8; 16] = [ 0x93, 0x9a, 0x72, 0x33, 0xf7, 0x9c, 0x4c, 0xa9, 0x94, 0x0a, 0x0d, 0xb3, 0x95, 0x7f, 0x06, 0x07, diff --git a/common/rust/evidence_api/src/tdx/quote.rs b/common/rust/evidence_api/src/tdx/quote.rs index c55fcd28..7a5f8e5a 100644 --- a/common/rust/evidence_api/src/tdx/quote.rs +++ b/common/rust/evidence_api/src/tdx/quote.rs @@ -1,10 +1,11 @@ #![allow(non_camel_case_types)] -use anyhow::anyhow; +use anyhow::{anyhow, Context}; use core::mem; use core::mem::transmute; use core::result::Result; use core::result::Result::Ok; use log::*; +use scale::Decode; use crate::api::ParseCcReport; use crate::api_data::CcReport; @@ -86,7 +87,7 @@ impl Tdx { } #[repr(C)] -#[derive(Clone)] +#[derive(Clone, Decode)] pub struct TdxQuoteHeader { /*** TD Quote Header. Attributes: @@ -506,14 +507,10 @@ pub struct TdxQuote { } impl TdxQuote { - pub fn parse_tdx_quote(quote: Vec) -> Result { - let tdx_quote_header: TdxQuoteHeader = unsafe { - transmute::<[u8; 48], TdxQuoteHeader>( - quote[0..48] - .try_into() - .expect("slice with incorrect length"), - ) - }; + pub fn parse_tdx_quote(quote: Vec) -> anyhow::Result { + let buffer = &mut "e[..]; + let tdx_quote_header = + TdxQuoteHeader::decode(buffer).context("failed to decode quote header")?; if tdx_quote_header.version == TDX_QUOTE_VERSION_4 { let tdx_quote_body: TdxQuoteBody = unsafe { transmute::<[u8; 584], TdxQuoteBody>(