From 01b0e7527e3a20301a2e6c68182cb39fd5f187c0 Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Fri, 18 Oct 2024 22:46:07 +0800 Subject: [PATCH 1/7] added proptest & impl Arbitrary traits for quote --- Cargo.toml | 1 + src/quote.rs | 380 ++++++++++++++++++++++++++++++++++++++++-- tests/encode_quote.rs | 84 ++++++++++ 3 files changed, 454 insertions(+), 11 deletions(-) create mode 100644 tests/encode_quote.rs diff --git a/Cargo.toml b/Cargo.toml index afdd551..4e276bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ getrandom = { version = "0.2", optional = true, features = ["js"] } serde-wasm-bindgen = { version = "0.4", optional = true} wasm-bindgen = { version = "0.2.95", optional = true } serde_bytes = { version = "0.11" } +proptest = "1.5.0" [dependencies.webpki] version = "0.102.8" diff --git a/src/quote.rs b/src/quote.rs index 02076f5..04f721f 100644 --- a/src/quote.rs +++ b/src/quote.rs @@ -2,12 +2,13 @@ use alloc::string::String; use alloc::vec::Vec; use anyhow::Result; -use scale::{Decode, Input}; +use proptest::prelude::*; +use scale::{Decode, Encode, Input}; use serde::{Deserialize, Serialize}; use crate::{constants::*, utils, Error}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Data { pub data: Vec, _marker: core::marker::PhantomData, @@ -25,7 +26,21 @@ impl> Decode for Data { } } -#[derive(Decode, Debug)] +impl Encode for Data +where + T: Encode + TryFrom, + >::Error: std::fmt::Debug, +{ + fn encode(&self) -> Vec { + let mut encoded = Vec::new(); + let len = T::try_from(self.data.len()).expect("Length conversion failed"); + encoded.extend(len.encode()); + encoded.extend(&self.data); + encoded + } +} + +#[derive(Decode, Encode, PartialEq, Eq, Debug)] pub struct Header { pub version: u16, pub attestation_key_type: u16, @@ -36,13 +51,89 @@ pub struct Header { pub user_data: [u8; 20], } -#[derive(Decode, Debug)] +impl Arbitrary for Header { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + let version_strategy = prop_oneof![Just(3u16), Just(4u16), Just(5u16)]; + + let tee_type_strategy = prop::strategy::Union::new_weighted(vec![ + (1, Just(TEE_TYPE_SGX).boxed()), + (1, Just(TEE_TYPE_TDX).boxed()), + ]); + + ( + version_strategy, + any::(), + tee_type_strategy, + any::(), + any::(), + any::<[u8; 16]>(), + any::<[u8; 20]>(), + any::(), + ) + .prop_flat_map( + |( + version, + attestation_key_type, + tee_type, + qe_svn, + pce_svn, + qe_vendor_id, + user_data, + v5_tee_type, + )| { + let tee_type = match version { + 3 => TEE_TYPE_SGX, + 4 => tee_type, + 5 => v5_tee_type, + _ => unreachable!(), + }; + + ( + Just(version), + Just(attestation_key_type), + Just(tee_type), + Just(qe_svn), + Just(pce_svn), + Just(qe_vendor_id), + Just(user_data), + ) + }, + ) + .prop_map( + |( + version, + attestation_key_type, + tee_type, + qe_svn, + pce_svn, + qe_vendor_id, + user_data, + )| { + Header { + version, + attestation_key_type, + tee_type, + qe_svn, + pce_svn, + qe_vendor_id, + user_data, + } + }, + ) + .boxed() + } +} + +#[derive(Decode, Encode, PartialEq, Eq, Debug)] pub struct Body { pub body_type: u16, pub size: u32, } -#[derive(Serialize, Deserialize, Decode, Debug, Clone)] +#[derive(Serialize, Deserialize, Decode, Encode, PartialEq, Eq, Debug, Clone)] pub struct EnclaveReport { #[serde(with = "serde_bytes")] pub cpu_svn: [u8; 16], @@ -67,7 +158,61 @@ pub struct EnclaveReport { pub report_data: [u8; 64], } -#[derive(Decode, Debug, Clone, Serialize, Deserialize)] +impl Arbitrary for EnclaveReport { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + ( + any::<[u8; 16]>(), + any::(), + any::<[u8; 28]>(), + any::<[u8; 16]>(), + any::<[u8; 32]>(), + any::<[u8; 32]>(), + any::<[u8; 32]>(), + any::<[u8; 96]>(), + any::(), + any::(), + any::<[u8; 60]>(), + any::<[u8; 64]>(), + ) + .prop_map( + |( + cpu_svn, + misc_select, + reserved1, + attributes, + mr_enclave, + reserved2, + mr_signer, + reserved3, + isv_prod_id, + isv_svn, + reserved4, + report_data, + )| { + EnclaveReport { + cpu_svn, + misc_select, + reserved1, + attributes, + mr_enclave, + reserved2, + mr_signer, + reserved3, + isv_prod_id, + isv_svn, + reserved4, + report_data, + } + }, + ) + .boxed() + } +} + +#[derive(Decode, Encode, PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] pub struct TDReport10 { #[serde(with = "serde_bytes")] pub tee_tcb_svn: [u8; 16], @@ -101,7 +246,79 @@ pub struct TDReport10 { pub report_data: [u8; 64], } -#[derive(Decode, Debug, Clone, Serialize, Deserialize)] +impl Arbitrary for TDReport10 { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + let part1 = ( + any::<[u8; 16]>(), + any::<[u8; 48]>(), + any::<[u8; 48]>(), + any::<[u8; 8]>(), + any::<[u8; 8]>(), + any::<[u8; 8]>(), + any::<[u8; 48]>(), + ); + + let part2 = ( + any::<[u8; 48]>(), + any::<[u8; 48]>(), + any::<[u8; 48]>(), + any::<[u8; 48]>(), + any::<[u8; 48]>(), + any::<[u8; 48]>(), + any::<[u8; 48]>(), + any::<[u8; 64]>(), + ); + + (part1, part2) + .prop_map( + |( + ( + tee_tcb_svn, + mr_seam, + mr_signer_seam, + seam_attributes, + td_attributes, + xfam, + mr_td, + ), + ( + mr_config_id, + mr_owner, + mr_owner_config, + rt_mr0, + rt_mr1, + rt_mr2, + rt_mr3, + report_data, + ), + )| { + TDReport10 { + tee_tcb_svn, + mr_seam, + mr_signer_seam, + seam_attributes, + td_attributes, + xfam, + mr_td, + mr_config_id, + mr_owner, + mr_owner_config, + rt_mr0, + rt_mr1, + rt_mr2, + rt_mr3, + report_data, + } + }, + ) + .boxed() + } +} + +#[derive(Decode, Encode, PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] pub struct TDReport15 { pub base: TDReport10, #[serde(with = "serde_bytes")] @@ -110,12 +327,48 @@ pub struct TDReport15 { pub mr_service_td: [u8; 48], } -#[derive(Decode)] +impl Arbitrary for TDReport15 { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + (any::(), any::<[u8; 16]>(), any::<[u8; 48]>()) + .prop_map(|(base, tee_tcb_svn2, mr_service_td)| TDReport15 { + base, + tee_tcb_svn2, + mr_service_td, + }) + .boxed() + } +} + +#[derive(Decode, Encode, PartialEq, Eq)] pub struct CertificationData { pub cert_type: u16, pub body: Data, } +impl Arbitrary for CertificationData { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::() + .prop_map(|cert_type| { + let data = vec![0u8; 10]; + let body = Data { + data, + _marker: core::marker::PhantomData, + }; + CertificationData { + cert_type, + body: body, + } + }) + .boxed() + } +} + impl core::fmt::Debug for CertificationData { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let body_str = String::from_utf8_lossy(&self.body.data); @@ -126,7 +379,7 @@ impl core::fmt::Debug for CertificationData { } } -#[derive(Decode, Debug)] +#[derive(Decode, Encode, PartialEq, Eq, Debug)] pub struct QEReportCertificationData { pub qe_report: [u8; ENCLAVE_REPORT_BYTE_LEN], pub qe_report_signature: [u8; QE_REPORT_SIG_BYTE_LEN], @@ -134,7 +387,34 @@ pub struct QEReportCertificationData { pub certification_data: CertificationData, } -#[derive(Decode, Debug)] +impl Arbitrary for QEReportCertificationData { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + ( + any::<[u8; ENCLAVE_REPORT_BYTE_LEN]>(), + any::<[u8; QE_REPORT_SIG_BYTE_LEN]>(), + any::(), + ) + .prop_map(|(qe_report, qe_report_signature, certification_data)| { + let data = vec![0u8; 10]; + let qe_auth_data = Data { + data, + _marker: core::marker::PhantomData, + }; + QEReportCertificationData { + qe_report, + qe_report_signature, + qe_auth_data, + certification_data, + } + }) + .boxed() + } +} + +#[derive(Decode, Encode, PartialEq, Eq, Debug)] pub struct AuthDataV3 { pub ecdsa_signature: [u8; ECDSA_SIGNATURE_BYTE_LEN], pub ecdsa_attestation_key: [u8; ECDSA_PUBKEY_BYTE_LEN], @@ -144,7 +424,46 @@ pub struct AuthDataV3 { pub certification_data: CertificationData, } -#[derive(Debug)] +impl Arbitrary for AuthDataV3 { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + ( + any::<[u8; ECDSA_SIGNATURE_BYTE_LEN]>(), + any::<[u8; ECDSA_PUBKEY_BYTE_LEN]>(), + any::<[u8; ENCLAVE_REPORT_BYTE_LEN]>(), + any::<[u8; QE_REPORT_SIG_BYTE_LEN]>(), + any::(), + ) + .prop_map( + |( + ecdsa_signature, + ecdsa_attestation_key, + qe_report, + qe_report_signature, + certification_data, + )| { + let data = vec![0u8; 10]; + let qe_auth_data = Data { + data, + _marker: core::marker::PhantomData, + }; + AuthDataV3 { + ecdsa_signature, + ecdsa_attestation_key, + qe_report, + qe_report_signature, + qe_auth_data, + certification_data, + } + }, + ) + .boxed() + } +} + +#[derive(Debug, PartialEq, Eq)] pub struct AuthDataV4 { pub ecdsa_signature: [u8; ECDSA_SIGNATURE_BYTE_LEN], pub ecdsa_attestation_key: [u8; ECDSA_PUBKEY_BYTE_LEN], @@ -152,6 +471,35 @@ pub struct AuthDataV4 { pub qe_report_data: QEReportCertificationData, } +impl Arbitrary for AuthDataV4 { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + ( + any::<[u8; ECDSA_SIGNATURE_BYTE_LEN]>(), + any::<[u8; ECDSA_PUBKEY_BYTE_LEN]>(), + any::(), + ) + .prop_map(|(ecdsa_signature, ecdsa_attestation_key, qe_report_data)| { + let certification_data = CertificationData { + cert_type: 0, + body: Data { + data: qe_report_data.encode(), + _marker: core::marker::PhantomData, + }, + }; + AuthDataV4 { + ecdsa_signature, + ecdsa_attestation_key, + certification_data, + qe_report_data, + } + }) + .boxed() + } +} + impl AuthDataV4 { pub fn into_v3(self) -> AuthDataV3 { AuthDataV3 { @@ -181,6 +529,16 @@ impl Decode for AuthDataV4 { } } +impl Encode for AuthDataV4 { + fn encode(&self) -> Vec { + let mut encoded = Vec::new(); + encoded.extend(self.ecdsa_signature.encode()); + encoded.extend(self.ecdsa_attestation_key.encode()); + encoded.extend(self.certification_data.encode()); + encoded + } +} + #[derive(Debug)] pub enum AuthData { V3(AuthDataV3), diff --git a/tests/encode_quote.rs b/tests/encode_quote.rs new file mode 100644 index 0000000..1f9cc42 --- /dev/null +++ b/tests/encode_quote.rs @@ -0,0 +1,84 @@ +use dcap_qvl::quote::{ + AuthDataV3, AuthDataV4, CertificationData, EnclaveReport, Header, QEReportCertificationData, + TDReport10, TDReport15, +}; +use proptest::prelude::*; +use scale::{Decode, Encode}; + +proptest! { + #[test] + fn test_header_constraints(header: Header) { + prop_assert!(header.version == 3 || header.version == 4 || header.version == 5); + + match header.version { + 3 => prop_assert_eq!(header.tee_type, 0x00000000), + 4 => prop_assert!(header.tee_type == 0x00000000 || header.tee_type == 0x00000081), + 5 => (), + _ => panic!("Unexpected version"), + } + } + + #[test] + fn test_header_encode_decode(header: Header) { + let mut encoded = vec![]; + header.encode_to(&mut encoded); + let decoded = Header::decode(&mut encoded.as_slice()).unwrap(); + prop_assert_eq!(header, decoded); + } + + #[test] + fn test_enclave_report_encode_decode(enclave_report: EnclaveReport) { + let mut encoded = vec![]; + enclave_report.encode_to(&mut encoded); + let decoded = EnclaveReport::decode(&mut encoded.as_slice()).unwrap(); + prop_assert_eq!(enclave_report, decoded); + } + + #[test] + fn test_tdreport10_encode_decode(tdreport10: TDReport10) { + let mut encoded = vec![]; + tdreport10.encode_to(&mut encoded); + let decoded = TDReport10::decode(&mut encoded.as_slice()).unwrap(); + prop_assert_eq!(tdreport10, decoded); + } + + #[test] + fn test_tdreport15_encode_decode(tdreport15: TDReport15) { + let mut encoded = vec![]; + tdreport15.encode_to(&mut encoded); + let decoded = TDReport15::decode(&mut encoded.as_slice()).unwrap(); + prop_assert_eq!(tdreport15, decoded); + } + + #[test] + fn test_certification_data_encode_decode(certification_data: CertificationData) { + let mut encoded = vec![]; + certification_data.encode_to(&mut encoded); + let decoded = CertificationData::decode(&mut encoded.as_slice()).unwrap(); + prop_assert_eq!(certification_data, decoded); + } + + #[test] + fn test_qe_report_certification_data_encode_decode(qe_report_certification_data: QEReportCertificationData) { + let mut encoded = vec![]; + qe_report_certification_data.encode_to(&mut encoded); + let decoded = QEReportCertificationData::decode(&mut encoded.as_slice()).unwrap(); + prop_assert_eq!(qe_report_certification_data, decoded); + } + + #[test] + fn test_auth_data_v3_encode_decode(auth_data_v3: AuthDataV3) { + let mut encoded = vec![]; + auth_data_v3.encode_to(&mut encoded); + let decoded = AuthDataV3::decode(&mut encoded.as_slice()).unwrap(); + prop_assert_eq!(auth_data_v3, decoded); + } + + #[test] + fn test_auth_data_v4_encode_decode(auth_data_v4: AuthDataV4) { + let mut encoded = vec![]; + auth_data_v4.encode_to(&mut encoded); + let decoded = AuthDataV4::decode(&mut encoded.as_slice()).unwrap(); + prop_assert_eq!(auth_data_v4, decoded); + } +} From 113207814e15964a4d7e6266731c935f6ee7f370 Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Sat, 19 Oct 2024 01:05:10 +0800 Subject: [PATCH 2/7] fix: attestation_key_type is an enum --- src/quote.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quote.rs b/src/quote.rs index 04f721f..61531a8 100644 --- a/src/quote.rs +++ b/src/quote.rs @@ -57,7 +57,7 @@ impl Arbitrary for Header { fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { let version_strategy = prop_oneof![Just(3u16), Just(4u16), Just(5u16)]; - + let attestation_key_strategy = prop_oneof![Just(2u16), Just(3u16)]; let tee_type_strategy = prop::strategy::Union::new_weighted(vec![ (1, Just(TEE_TYPE_SGX).boxed()), (1, Just(TEE_TYPE_TDX).boxed()), @@ -65,7 +65,7 @@ impl Arbitrary for Header { ( version_strategy, - any::(), + attestation_key_strategy, tee_type_strategy, any::(), any::(), From a8f20b9b46c98534015797a53b39861ee29962fd Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Wed, 4 Dec 2024 21:28:13 +0800 Subject: [PATCH 3/7] add TdxEventLog & TdxEventLogs --- Cargo.toml | 2 + src/quote.rs | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 4e276bf..f6ab5d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,8 @@ serde-wasm-bindgen = { version = "0.4", optional = true} wasm-bindgen = { version = "0.2.95", optional = true } serde_bytes = { version = "0.11" } proptest = "1.5.0" +sha2 = "0.10.8" +sha3 = "0.10.8" [dependencies.webpki] version = "0.102.8" diff --git a/src/quote.rs b/src/quote.rs index 61531a8..09de8fb 100644 --- a/src/quote.rs +++ b/src/quote.rs @@ -5,9 +5,125 @@ use anyhow::Result; use proptest::prelude::*; use scale::{Decode, Encode, Input}; use serde::{Deserialize, Serialize}; +use sha2::{Sha384,Digest}; use crate::{constants::*, utils, Error}; +#[derive(Decode, Encode, PartialEq, Eq, Debug, Serialize)] +pub struct TdxEventLog { + /// IMR index, starts from 0 + pub imr: u32, + /// Event type + pub event_type: u32, + /// Digest + #[serde(serialize_with = "hex::serialize")] + pub digest: [u8; 48], + /// Event name + pub event: String, + /// Event payload + #[serde(serialize_with = "hex::serialize")] + pub event_payload: Vec, +} + +// Add this helper module for hex serialization +mod hex { + use serde::Serializer; + + pub fn serialize(bytes: T, serializer: S) -> Result + where + S: Serializer, + T: AsRef<[u8]>, + { + serializer.serialize_str(&hex::encode(bytes)) + } +} + +impl Arbitrary for TdxEventLog { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + // Create a strategy for imr that only generates values 0-3 + let imr_strategy = 0..=3u32; + + ( + imr_strategy, + any::(), + any::<[u8; 48]>(), + any::(), + any::>(), + ) + .prop_map(|(imr, event_type, digest, event, event_payload)| { + TdxEventLog { + imr, + event_type, + digest, + event, + event_payload, + } + }) + .boxed() + } +} + +#[derive(Decode, Encode, PartialEq, Eq, Debug, Serialize)] +pub struct TdxEventLogs { + pub logs: Vec, +} + +impl TdxEventLogs { + /// Convert event logs to a vector of RTMR values by accumulating digests with SHA384. + /// Returns a vector of 48-byte arrays representing the RTMR values, + /// where the index corresponds to the IMR index. + pub fn get_rtmr(&self) -> Vec<[u8; 48]> { + let mut rtmrs = vec![[0u8; 48]; 4]; // Initialize with 4 zero-filled RTMRs + + // Process events for each IMR index + for imr_idx in 0..4 { + let mut current_rtmr = [0u8; 48]; + + // Get all events for this IMR index in order + let imr_events: Vec<_> = self.logs.iter() + .filter(|event| event.imr == imr_idx as u32) + .collect(); + + // If we have events for this IMR, calculate the accumulated hash + if !imr_events.is_empty() { + for event in imr_events { + // Create hasher and update with current RTMR + let mut hasher = Sha384::new(); + hasher.update(current_rtmr); + // Update with event digest + hasher.update(event.digest); + // Get the new RTMR value + current_rtmr.copy_from_slice(&hasher.finalize()); + } + } + + rtmrs[imr_idx] = current_rtmr; + } + + rtmrs + } + + /// Convert event logs to a JSON string + pub fn to_json(&self) -> Result { + serde_json::to_string_pretty(self) + } +} + +impl Arbitrary for TdxEventLogs { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + let size = 2..=32usize; + prop::collection::vec(any::(), size) + .prop_map(|logs| TdxEventLogs { logs }) + .boxed() + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct Data { pub data: Vec, From 471fdd0c898ce32c90b5b80e5daaf09c13ba506f Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Wed, 4 Dec 2024 21:44:58 +0800 Subject: [PATCH 4/7] imp: always use blank string as TdxEventLog.event --- src/quote.rs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/quote.rs b/src/quote.rs index 09de8fb..8d5ac09 100644 --- a/src/quote.rs +++ b/src/quote.rs @@ -43,22 +43,21 @@ impl Arbitrary for TdxEventLog { type Strategy = BoxedStrategy; fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { - // Create a strategy for imr that only generates values 0-3 + // Create a strategy for imr that only generates values 0-3, which represent to rtmr0 ~ rtmr3 let imr_strategy = 0..=3u32; ( imr_strategy, any::(), any::<[u8; 48]>(), - any::(), any::>(), ) - .prop_map(|(imr, event_type, digest, event, event_payload)| { + .prop_map(|(imr, event_type, digest, event_payload)| { TdxEventLog { imr, event_type, digest, - event, + event: "".to_string(), event_payload, } }) @@ -77,32 +76,21 @@ impl TdxEventLogs { /// where the index corresponds to the IMR index. pub fn get_rtmr(&self) -> Vec<[u8; 48]> { let mut rtmrs = vec![[0u8; 48]; 4]; // Initialize with 4 zero-filled RTMRs - - // Process events for each IMR index for imr_idx in 0..4 { let mut current_rtmr = [0u8; 48]; - - // Get all events for this IMR index in order let imr_events: Vec<_> = self.logs.iter() .filter(|event| event.imr == imr_idx as u32) .collect(); - - // If we have events for this IMR, calculate the accumulated hash if !imr_events.is_empty() { for event in imr_events { - // Create hasher and update with current RTMR let mut hasher = Sha384::new(); hasher.update(current_rtmr); - // Update with event digest hasher.update(event.digest); - // Get the new RTMR value current_rtmr.copy_from_slice(&hasher.finalize()); } } - rtmrs[imr_idx] = current_rtmr; } - rtmrs } From 75f6b8b80be2284bb0960ebcea5afb63fd7c2d6e Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Wed, 4 Dec 2024 21:48:27 +0800 Subject: [PATCH 5/7] fix: to_json --- src/quote.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quote.rs b/src/quote.rs index 8d5ac09..5473cfd 100644 --- a/src/quote.rs +++ b/src/quote.rs @@ -96,7 +96,7 @@ impl TdxEventLogs { /// Convert event logs to a JSON string pub fn to_json(&self) -> Result { - serde_json::to_string_pretty(self) + serde_json::to_string(&self.logs) } } From cef08877ba97802e797b90f4cea52534a4cc28bd Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Wed, 4 Dec 2024 22:04:14 +0800 Subject: [PATCH 6/7] imp: ensure have event logs for rtmr0~3 --- src/quote.rs | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/quote.rs b/src/quote.rs index 5473cfd..5793d87 100644 --- a/src/quote.rs +++ b/src/quote.rs @@ -105,9 +105,40 @@ impl Arbitrary for TdxEventLogs { type Strategy = BoxedStrategy; fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { - let size = 2..=32usize; - prop::collection::vec(any::(), size) - .prop_map(|logs| TdxEventLogs { logs }) + let imr0_size = 6..=12usize; + let remaining_size = 0..=8usize; + + ( + prop::collection::vec(any::().prop_map(|mut log| { + log.imr = 0; + log + }), imr0_size), + prop::collection::vec(any::().prop_map(|mut log| { + log.imr = 1; + log + }), remaining_size.clone()), + prop::collection::vec(any::().prop_map(|mut log| { + log.imr = 2; + log + }), remaining_size.clone()), + prop::collection::vec(any::().prop_map(|mut log| { + log.imr = 3; + log + }), remaining_size), + ) + .prop_map(|(mut imr0_logs, mut imr1_logs, mut imr2_logs, mut imr3_logs)| { + let mut logs = Vec::new(); + logs.append(&mut imr0_logs); + logs.append(&mut imr1_logs); + logs.append(&mut imr2_logs); + logs.append(&mut imr3_logs); + if logs.len() > 32 { + logs.sort_by_key(|log| log.imr); + logs.truncate(32); + debug_assert!(logs.iter().filter(|log| log.imr == 0).count() >= 6); + } + TdxEventLogs { logs } + }) .boxed() } } From adfa5708c6c1826f6fc648661650a4e6037a236f Mon Sep 17 00:00:00 2001 From: Leechael Yim Date: Wed, 4 Dec 2024 22:29:09 +0800 Subject: [PATCH 7/7] imp: made imr item numbers customizable --- src/quote.rs | 58 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/src/quote.rs b/src/quote.rs index 5793d87..4e8d2e0 100644 --- a/src/quote.rs +++ b/src/quote.rs @@ -65,6 +65,25 @@ impl Arbitrary for TdxEventLog { } } +#[derive(Debug)] +pub struct TdxEventLogsParams { + pub imr0_size: Option, + pub imr1_size: Option, + pub imr2_size: Option, + pub imr3_size: Option, +} + +impl Default for TdxEventLogsParams { + fn default() -> Self { + TdxEventLogsParams { + imr0_size: None, + imr1_size: None, + imr2_size: None, + imr3_size: None, + } + } +} + #[derive(Decode, Encode, PartialEq, Eq, Debug, Serialize)] pub struct TdxEventLogs { pub logs: Vec, @@ -84,9 +103,9 @@ impl TdxEventLogs { if !imr_events.is_empty() { for event in imr_events { let mut hasher = Sha384::new(); - hasher.update(current_rtmr); - hasher.update(event.digest); - current_rtmr.copy_from_slice(&hasher.finalize()); + hasher.update(¤t_rtmr); + hasher.update(&event.digest); + current_rtmr = hasher.finalize().into(); } } rtmrs[imr_idx] = current_rtmr; @@ -101,30 +120,47 @@ impl TdxEventLogs { } impl Arbitrary for TdxEventLogs { - type Parameters = (); + type Parameters = TdxEventLogsParams; type Strategy = BoxedStrategy; - fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { - let imr0_size = 6..=12usize; - let remaining_size = 0..=8usize; + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + let default_imr0_size = 6..=12usize; + let default_remaining_size = 1..=8usize; + + let imr0_strategy = match args.imr0_size { + Some(size) => size..=size, + None => default_imr0_size, + }; + let imr1_strategy = match args.imr1_size { + Some(size) => size..=size, + None => default_remaining_size.clone(), + }; + let imr2_strategy = match args.imr2_size { + Some(size) => size..=size, + None => default_remaining_size.clone(), + }; + let imr3_strategy = match args.imr3_size { + Some(size) => size..=size, + None => default_remaining_size, + }; ( prop::collection::vec(any::().prop_map(|mut log| { log.imr = 0; log - }), imr0_size), + }), imr0_strategy), prop::collection::vec(any::().prop_map(|mut log| { log.imr = 1; log - }), remaining_size.clone()), + }), imr1_strategy), prop::collection::vec(any::().prop_map(|mut log| { log.imr = 2; log - }), remaining_size.clone()), + }), imr2_strategy), prop::collection::vec(any::().prop_map(|mut log| { log.imr = 3; log - }), remaining_size), + }), imr3_strategy), ) .prop_map(|(mut imr0_logs, mut imr1_logs, mut imr2_logs, mut imr3_logs)| { let mut logs = Vec::new();