diff --git a/src/migtd/src/mig_policy.rs b/src/migtd/src/mig_policy.rs index f542bdc9..b9e3d958 100644 --- a/src/migtd/src/mig_policy.rs +++ b/src/migtd/src/mig_policy.rs @@ -87,7 +87,6 @@ mod v2 { const SERVTD_ATTR_IGNORE_RTMR3: u64 = 0x200_0000_0000; const SERVTD_TYPE_MIGTD: u16 = 0; - const TD_INFO_OFFSET: usize = 512; lazy_static! { pub static ref LOCAL_TCB_INFO: Once = Once::new(); @@ -136,13 +135,6 @@ mod v2 { .ok_or(PolicyError::InvalidParameter) } - pub fn get_init_tcb_evaluation_info( - init_report: &TdxReport, - init_policy: &VerifiedPolicy, - ) -> Result { - setup_evaluation_data_with_tdreport(init_report, init_policy) - } - /// Get reference to the global verified policy /// Returns None if the policy hasn't been initialized yet pub fn get_verified_policy() -> Option<&'static VerifiedPolicy<'static>> { @@ -263,13 +255,14 @@ mod v2 { } // Authenticate the migtd-old from migtd-new side + // Per GHCI 1.5: init_tdinfo is a TDINFO_STRUCT (not full TDREPORT), + // and there is no separate init_policy JSON blob. pub fn authenticate_rebinding_old( tdreport_src: &[u8], event_log_src: &[u8], mig_policy_src: &[u8], - init_policy: &[u8], + init_tdinfo: &[u8], init_event_log: &[u8], - init_td_report: &[u8], servtd_ext_src: &[u8], ) -> Result, PolicyError> { let policy_issuer_chain = get_policy_issuer_chain().ok_or(PolicyError::InvalidParameter)?; @@ -284,29 +277,30 @@ mod v2 { )?; let policy = get_verified_policy().ok_or(PolicyError::InvalidParameter)?; - // Verify the td report init / event log init / policy init + // Verify the init tdinfo against servtd_ext hash let servtd_ext_src_obj = ServtdExt::read_from_bytes(servtd_ext_src).ok_or(PolicyError::InvalidParameter)?; - let init_tdreport = verify_init_tdreport(init_td_report, &servtd_ext_src_obj)?; + let init_td_info = verify_init_tdinfo(init_tdinfo, &servtd_ext_src_obj)?; let _engine_svn = policy .servtd_tcb_mapping .get_engine_svn_by_measurements(&Measurements::new_from_bytes( - &init_tdreport.td_info.mrtd, - &init_tdreport.td_info.rtmr0, - &init_tdreport.td_info.rtmr1, + &init_td_info.mrtd, + &init_td_info.rtmr0, + &init_td_info.rtmr1, None, None, )) .ok_or(PolicyError::SvnMismatch)?; - let verified_policy_init = verify_policy_and_event_log( + + // Verify init event log integrity against RTMRs from init tdinfo + verify_event_log( init_event_log, - init_policy, - policy_issuer_chain, - &get_rtmrs_from_tdreport(&init_tdreport)?, - )?; + &get_rtmrs_from_tdinfo(&init_td_info)?, + ) + .map_err(|_| PolicyError::InvalidEventLog)?; - let relative_reference = - get_init_tcb_evaluation_info(&init_tdreport, &verified_policy_init)?; + // Use local policy's tcb_mapping with init tdinfo measurements + let relative_reference = setup_evaluation_data_with_tdinfo(&init_td_info, policy)?; policy.policy_data.evaluate_policy_common( &evaluation_data_src, &relative_reference, @@ -456,51 +450,61 @@ mod v2 { Ok(tdx_report) } + /// Per GHCI 1.5: accepts TDINFO_STRUCT bytes directly (not full TDREPORT) fn verify_servtd_hash( - servtd_report: &[u8], + tdinfo_bytes: &[u8], servtd_attr: u64, init_servtd_hash: &[u8], - ) -> Result { - if servtd_report.len() < TD_INFO_OFFSET + size_of::() { + ) -> Result { + if tdinfo_bytes.len() < size_of::() { return Err(PolicyError::InvalidParameter); } - // Extract TdInfo from the report - let mut td_report = - TdxReport::read_from_bytes(servtd_report).ok_or(PolicyError::InvalidTdReport)?; + // Parse TdInfo directly from bytes + let mut td_info = { + let mut uninit = core::mem::MaybeUninit::::uninit(); + unsafe { + core::ptr::copy_nonoverlapping( + tdinfo_bytes.as_ptr(), + uninit.as_mut_ptr() as *mut u8, + size_of::(), + ); + uninit.assume_init() + } + }; if (servtd_attr & SERVTD_ATTR_IGNORE_ATTRIBUTES) != 0 { - td_report.td_info.attributes.fill(0); + td_info.attributes.fill(0); } if (servtd_attr & SERVTD_ATTR_IGNORE_XFAM) != 0 { - td_report.td_info.xfam.fill(0); + td_info.xfam.fill(0); } if (servtd_attr & SERVTD_ATTR_IGNORE_MRTD) != 0 { - td_report.td_info.mrtd.fill(0); + td_info.mrtd.fill(0); } if (servtd_attr & SERVTD_ATTR_IGNORE_MRCONFIGID) != 0 { - td_report.td_info.mrconfig_id.fill(0); + td_info.mrconfig_id.fill(0); } if (servtd_attr & SERVTD_ATTR_IGNORE_MROWNER) != 0 { - td_report.td_info.mrowner.fill(0); + td_info.mrowner.fill(0); } if (servtd_attr & SERVTD_ATTR_IGNORE_MROWNERCONFIG) != 0 { - td_report.td_info.mrownerconfig.fill(0); + td_info.mrownerconfig.fill(0); } if (servtd_attr & SERVTD_ATTR_IGNORE_RTMR0) != 0 { - td_report.td_info.rtmr0.fill(0); + td_info.rtmr0.fill(0); } if (servtd_attr & SERVTD_ATTR_IGNORE_RTMR1) != 0 { - td_report.td_info.rtmr1.fill(0); + td_info.rtmr1.fill(0); } if (servtd_attr & SERVTD_ATTR_IGNORE_RTMR2) != 0 { - td_report.td_info.rtmr2.fill(0); + td_info.rtmr2.fill(0); } if (servtd_attr & SERVTD_ATTR_IGNORE_RTMR3) != 0 { - td_report.td_info.rtmr3.fill(0); + td_info.rtmr3.fill(0); } - let info_hash = digest_sha384(td_report.td_info.as_bytes()) + let info_hash = digest_sha384(td_info.as_bytes()) .map_err(|_| PolicyError::HashCalculation)?; // Calculate ServTD hash: SHA384(info_hash || type || attr) @@ -521,20 +525,62 @@ mod v2 { return Err(PolicyError::InvalidTdReport); } - Ok(td_report) + Ok(td_info) } - fn verify_init_tdreport( - init_report: &[u8], + /// Per GHCI 1.5: verifies TDINFO_STRUCT against servtd_ext hash + fn verify_init_tdinfo( + init_tdinfo: &[u8], servtd_ext: &ServtdExt, - ) -> Result { + ) -> Result { verify_servtd_hash( - init_report, + init_tdinfo, u64::from_le_bytes(servtd_ext.init_attr), &servtd_ext.init_servtd_info_hash, ) } + fn get_rtmrs_from_tdinfo( + td_info: &TdInfo, + ) -> Result<[[u8; SHA384_DIGEST_SIZE]; 4], PolicyError> { + let mut rtmrs = [[0u8; SHA384_DIGEST_SIZE]; 4]; + rtmrs[0].copy_from_slice(&td_info.rtmr0); + rtmrs[1].copy_from_slice(&td_info.rtmr1); + rtmrs[2].copy_from_slice(&td_info.rtmr2); + rtmrs[3].copy_from_slice(&td_info.rtmr3); + Ok(rtmrs) + } + + fn setup_evaluation_data_with_tdinfo( + td_info: &TdInfo, + policy: &VerifiedPolicy, + ) -> Result { + let migtd_svn = policy.servtd_tcb_mapping.get_engine_svn_by_measurements( + &Measurements::new_from_bytes( + &td_info.mrtd, + &td_info.rtmr0, + &td_info.rtmr1, + None, + None, + ), + ); + + let migtd_tcb = migtd_svn.and_then(|svn| policy.servtd_identity.get_tcb_level_by_svn(svn)); + + Ok(PolicyEvaluationInfo { + tee_tcb_svn: None, + tcb_date: None, + tcb_status: None, + tcb_evaluation_number: None, + fmspc: None, + migtd_isvsvn: migtd_svn, + migtd_tcb_date: migtd_tcb.map(|tcb| tcb.tcb_date.clone()), + migtd_tcb_status: migtd_tcb.map(|tcb| tcb.tcb_status.clone()), + pck_crl_num: None, + root_ca_crl_num: None, + }) + } + fn setup_evaluation_data( fmspc: [u8; 6], suppl_data: &[u8], @@ -659,6 +705,121 @@ mod v2 { let iso_date = unix_to_iso8601(timestamp).unwrap(); assert_eq!(iso_date, "2024-01-01T00:00:00Z"); } + + #[test] + fn test_verify_servtd_hash_valid() { + // Build a 512-byte TDINFO_STRUCT with known content + let mut tdinfo_bytes = [0u8; 512]; + tdinfo_bytes[0..8].copy_from_slice(&[0x01; 8]); // attributes + tdinfo_bytes[8..16].copy_from_slice(&[0x02; 8]); // xfam + + // Compute expected hash: SHA384(SHA384(tdinfo) || type(u16) || attr(u64)) + let servtd_attr: u64 = 0; + let info_hash = digest_sha384(&tdinfo_bytes).unwrap(); + let mut buffer = [0u8; SHA384_DIGEST_SIZE + size_of::() + size_of::()]; + buffer[..SHA384_DIGEST_SIZE].copy_from_slice(&info_hash); + buffer[SHA384_DIGEST_SIZE..SHA384_DIGEST_SIZE + 2] + .copy_from_slice(&SERVTD_TYPE_MIGTD.to_le_bytes()); + buffer[SHA384_DIGEST_SIZE + 2..SHA384_DIGEST_SIZE + 10] + .copy_from_slice(&servtd_attr.to_le_bytes()); + let expected_hash = digest_sha384(&buffer).unwrap(); + + let result = verify_servtd_hash(&tdinfo_bytes, servtd_attr, &expected_hash); + assert!(result.is_ok()); + let td_info = result.unwrap(); + assert_eq!(td_info.attributes, [0x01; 8]); + assert_eq!(td_info.xfam, [0x02; 8]); + } + + #[test] + fn test_verify_servtd_hash_wrong_hash() { + let tdinfo_bytes = [0u8; 512]; + let wrong_hash = [0xFFu8; 48]; + let result = verify_servtd_hash(&tdinfo_bytes, 0, &wrong_hash); + assert!(result.is_err()); + } + + #[test] + fn test_verify_servtd_hash_short_input() { + let short = [0u8; 256]; // too small for TdInfo (512 bytes) + let result = verify_servtd_hash(&short, 0, &[0u8; 48]); + assert!(matches!(result, Err(PolicyError::InvalidParameter))); + } + + #[test] + fn test_verify_servtd_hash_with_ignore_attributes() { + // Build TdInfo with non-zero attributes + let mut tdinfo_bytes = [0u8; 512]; + tdinfo_bytes[0..8].copy_from_slice(&[0xFF; 8]); // attributes + + // Compute hash with attributes zeroed (IGNORE_ATTRIBUTES flag) + let servtd_attr = SERVTD_ATTR_IGNORE_ATTRIBUTES; + let mut zeroed = tdinfo_bytes; + zeroed[0..8].fill(0); // zero attributes for hash computation + let info_hash = digest_sha384(&zeroed).unwrap(); + let mut buffer = [0u8; SHA384_DIGEST_SIZE + size_of::() + size_of::()]; + buffer[..SHA384_DIGEST_SIZE].copy_from_slice(&info_hash); + buffer[SHA384_DIGEST_SIZE..SHA384_DIGEST_SIZE + 2] + .copy_from_slice(&SERVTD_TYPE_MIGTD.to_le_bytes()); + buffer[SHA384_DIGEST_SIZE + 2..SHA384_DIGEST_SIZE + 10] + .copy_from_slice(&servtd_attr.to_le_bytes()); + let expected_hash = digest_sha384(&buffer).unwrap(); + + let result = verify_servtd_hash(&tdinfo_bytes, servtd_attr, &expected_hash); + assert!(result.is_ok()); + } + + #[test] + fn test_verify_servtd_hash_with_ignore_mrowner() { + // Build TdInfo with non-zero mrowner at offset 112..160 + let mut tdinfo_bytes = [0u8; 512]; + tdinfo_bytes[112..160].copy_from_slice(&[0xAA; 48]); // mrowner + + // Compute hash with mrowner zeroed (IGNORE_MROWNER flag) + let servtd_attr = SERVTD_ATTR_IGNORE_MROWNER; + let mut zeroed = tdinfo_bytes; + zeroed[112..160].fill(0); + let info_hash = digest_sha384(&zeroed).unwrap(); + let mut buffer = [0u8; SHA384_DIGEST_SIZE + size_of::() + size_of::()]; + buffer[..SHA384_DIGEST_SIZE].copy_from_slice(&info_hash); + buffer[SHA384_DIGEST_SIZE..SHA384_DIGEST_SIZE + 2] + .copy_from_slice(&SERVTD_TYPE_MIGTD.to_le_bytes()); + buffer[SHA384_DIGEST_SIZE + 2..SHA384_DIGEST_SIZE + 10] + .copy_from_slice(&servtd_attr.to_le_bytes()); + let expected_hash = digest_sha384(&buffer).unwrap(); + + let result = verify_servtd_hash(&tdinfo_bytes, servtd_attr, &expected_hash); + assert!(result.is_ok()); + // mrowner should be zeroed in the returned TdInfo + assert_eq!(result.unwrap().mrowner, [0u8; 48]); + } + + #[test] + fn test_get_rtmrs_from_tdinfo() { + use tdx_tdcall::tdreport::TdInfo; + let mut tdinfo_bytes = [0u8; 512]; + // RTMR offsets in TdInfo: rtmr0 at 208, rtmr1 at 256, rtmr2 at 304, rtmr3 at 352 + tdinfo_bytes[208..256].copy_from_slice(&[0x01; 48]); // rtmr0 + tdinfo_bytes[256..304].copy_from_slice(&[0x02; 48]); // rtmr1 + tdinfo_bytes[304..352].copy_from_slice(&[0x03; 48]); // rtmr2 + tdinfo_bytes[352..400].copy_from_slice(&[0x04; 48]); // rtmr3 + + let td_info = unsafe { + let mut uninit = core::mem::MaybeUninit::::uninit(); + core::ptr::copy_nonoverlapping( + tdinfo_bytes.as_ptr(), + uninit.as_mut_ptr() as *mut u8, + size_of::(), + ); + uninit.assume_init() + }; + + let rtmrs = get_rtmrs_from_tdinfo(&td_info).unwrap(); + assert_eq!(rtmrs[0], [0x01; 48]); + assert_eq!(rtmrs[1], [0x02; 48]); + assert_eq!(rtmrs[2], [0x03; 48]); + assert_eq!(rtmrs[3], [0x04; 48]); + } } fn get_rtmrs_from_suppl_data( diff --git a/src/migtd/src/migration/data.rs b/src/migtd/src/migration/data.rs index 9aa0e74c..0db53e4b 100644 --- a/src/migtd/src/migration/data.rs +++ b/src/migtd/src/migration/data.rs @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: BSD-2-Clause-Patent -#[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] +#[cfg(all(feature = "main", feature = "vmcall-raw", feature = "policy_v2"))] use crate::migration::rebinding::RebindingInfo; use super::*; @@ -257,7 +257,7 @@ pub struct RequestDataBuffer<'a> { #[cfg(feature = "vmcall-raw")] pub enum WaitForRequestResponse { StartMigration(MigrationInformation), - #[cfg(feature = "policy_v2")] + #[cfg(all(feature = "main", feature = "policy_v2"))] StartRebinding(RebindingInfo), GetTdReport(ReportInfo), EnableLogArea(EnableLogAreaInfo), diff --git a/src/migtd/src/migration/rebinding.rs b/src/migtd/src/migration/rebinding.rs index 8cf59b9f..9ee5546f 100644 --- a/src/migtd/src/migration/rebinding.rs +++ b/src/migtd/src/migration/rebinding.rs @@ -17,7 +17,6 @@ use crate::migration::servtd_ext::read_servtd_ext; #[cfg(feature = "spdm_attestation")] use crate::spdm; use crate::{event_log, migration::transport::*}; -use crypto::hash::digest_sha384; use crate::{ config, @@ -47,12 +46,7 @@ const TDCS_FIELD_WRITE_MASK: u64 = u64::MAX; const TLS_TIMEOUT: Duration = Duration::from_secs(60); // 60 seconds // FIXME: Need VMM provide socket information const MIGTD_DATA_SIGNATURE: &[u8] = b"MIGTDATA"; -const MIGTD_DATA_TYPE_INIT_MIG_POLICY: u32 = 0; -const MIGTD_DATA_TYPE_INIT_TD_REPORT: u32 = 1; -const MIGTD_DATA_TYPE_INIT_EVENT_LOG: u32 = 2; - -const MIGTD_REBIND_OP_PREPARE: u8 = 0; -const MIGTD_REBIND_OP_FINALIZE: u8 = 1; +const MIGTD_DATA_TYPE_TDINFO: u32 = 0; #[repr(C)] pub struct RebindingToken { @@ -90,7 +84,6 @@ pub struct RebindingInfo { pub mig_request_id: u64, pub rebinding_src: u8, pub has_init_data: u8, - pub operation: u8, pub target_td_uuid: [u64; 4], pub binding_handle: u64, pub init_migtd_data: Option, @@ -98,14 +91,13 @@ pub struct RebindingInfo { impl RebindingInfo { pub fn read_from_bytes(b: &[u8]) -> Option { - // Check the length of input and the reserved fields - if b.len() < 56 || b[11..16] != [0; 5] { + // Check the length of input and the reserved fields (bytes 10-15 per GHCI 1.5) + if b.len() < 56 || b[10..16] != [0; 6] { return None; } let mig_request_id = u64::from_le_bytes(b[..8].try_into().unwrap()); let rebinding_src = b[8]; let has_init_data = b[9]; - let operation = b[10]; let target_td_uuid: [u64; 4] = core::array::from_fn(|i| { let offset = 16 + i * 8; @@ -123,7 +115,6 @@ impl RebindingInfo { mig_request_id, rebinding_src, has_init_data, - operation, target_td_uuid, binding_handle, init_migtd_data, @@ -132,12 +123,29 @@ impl RebindingInfo { } pub struct InitData { - pub init_report: Vec, - pub init_policy: Vec, - pub init_event_log: Vec, + /// The TDINFO_STRUCT of the initial MigTD (per GHCI 1.5, MIGTD_DATA type 0). + pub init_tdinfo: Vec, } impl InitData { + /// TDINFO_STRUCT field offsets and sizes (per TDX Module ABI). + const TDINFO_MROWNER_OFFSET: usize = 112; // attributes(8) + xfam(8) + mrtd(48) + mrconfig_id(48) + const TDINFO_MROWNERCONFIG_OFFSET: usize = 160; // MROWNER_OFFSET + 48 + const TDINFO_FIELD_SIZE: usize = SHA384_DIGEST_SIZE; + const TDINFO_MIN_SIZE: usize = 512; + + /// Extract mrowner from the TDINFO_STRUCT. + /// Per GHCI 1.5: VMM puts migpolicy.policy_key in tdinfo.mrowner. + pub fn mrowner(&self) -> &[u8] { + &self.init_tdinfo[Self::TDINFO_MROWNER_OFFSET..Self::TDINFO_MROWNER_OFFSET + Self::TDINFO_FIELD_SIZE] + } + + /// Extract mrownerconfig from the TDINFO_STRUCT. + /// Per GHCI 1.5: VMM puts migpolicy.policy_svn in tdinfo.mrownerconfig. + pub fn mrownerconfig(&self) -> &[u8] { + &self.init_tdinfo[Self::TDINFO_MROWNERCONFIG_OFFSET..Self::TDINFO_MROWNERCONFIG_OFFSET + Self::TDINFO_FIELD_SIZE] + } + pub fn read_from_bytes(b: &[u8]) -> Option { if b.len() < 20 || &b[..8] != MIGTD_DATA_SIGNATURE { return None; @@ -147,34 +155,22 @@ impl InitData { let length = u32::from_le_bytes(b[12..16].try_into().unwrap()); let num_entries = u32::from_le_bytes(b[16..20].try_into().unwrap()); - if version != 0x00010000 || b.len() < length as usize { + // Per GHCI 1.5: version must be 0x00010000, numberOfEntry must be 1 (tdinfo) + if version != 0x00010000 || b.len() < length as usize || num_entries != 1 { return None; } - let mut offset = 20; - let mut init_report = None; - let mut init_policy = None; - let mut init_event_log = None; - for _ in 0..num_entries { - let entry = MigtdDataEntry::read_from_bytes(&b[offset..])?; - match entry.r#type { - MIGTD_DATA_TYPE_INIT_MIG_POLICY => init_policy = Some(entry.value), - MIGTD_DATA_TYPE_INIT_TD_REPORT => { - if entry.value.len() > 1024 { - return None; - } - init_report = Some(entry.value.to_vec()) - } - MIGTD_DATA_TYPE_INIT_EVENT_LOG => init_event_log = Some(entry.value), - _ => return None, - } - offset += entry.length as usize + 8; + let entry = MigtdDataEntry::read_from_bytes(&b[20..])?; + if entry.r#type != MIGTD_DATA_TYPE_TDINFO { + return None; + } + + if entry.value.len() < Self::TDINFO_MIN_SIZE { + return None; } Some(Self { - init_report: init_report?, - init_policy: init_policy?.to_vec(), - init_event_log: init_event_log?.to_vec(), + init_tdinfo: entry.value.to_vec(), }) } @@ -186,18 +182,12 @@ impl InitData { // Placeholder for length. buf.extend_from_slice(&0u32.to_le_bytes()); - buf.extend_from_slice(&3u32.to_le_bytes()); // num_entries - - // Helper to write entries - let mut write_entry = |type_: u32, value: &[u8]| { - buf.extend_from_slice(&type_.to_le_bytes()); - buf.extend_from_slice(&(value.len() as u32).to_le_bytes()); - buf.extend_from_slice(value); - }; + // Per GHCI 1.5: numberOfEntry = 1, entry type 0 = tdinfo + buf.extend_from_slice(&1u32.to_le_bytes()); // num_entries - write_entry(MIGTD_DATA_TYPE_INIT_MIG_POLICY, &self.init_policy); - write_entry(MIGTD_DATA_TYPE_INIT_TD_REPORT, &self.init_report); - write_entry(MIGTD_DATA_TYPE_INIT_EVENT_LOG, &self.init_event_log); + buf.extend_from_slice(&MIGTD_DATA_TYPE_TDINFO.to_le_bytes()); + buf.extend_from_slice(&(self.init_tdinfo.len() as u32).to_le_bytes()); + buf.extend_from_slice(&self.init_tdinfo); let total_size = (buf.len() - start_len) as u32; @@ -207,13 +197,9 @@ impl InitData { } pub fn get_from_local(report_data: &[u8; 64]) -> Option { + let report = tdx_tdcall::tdreport::tdcall_report(report_data).ok()?; Some(Self { - init_report: tdx_tdcall::tdreport::tdcall_report(report_data) - .ok()? - .as_bytes() - .to_vec(), - init_policy: config::get_policy()?.to_vec(), - init_event_log: event_log::get_event_log()?.to_vec(), + init_tdinfo: report.td_info.as_bytes().to_vec(), }) } } @@ -247,7 +233,7 @@ impl<'a> MigtdDataEntry<'a> { pub(super) async fn rebinding_old_pre_session_data_exchange( transport: &mut TransportType, - init_policy: &[u8], + init_tdinfo: &[u8], ) -> Result, MigrationResult> { let version = exchange_hello_packet(transport).await.map_err(|e| { log::error!( @@ -283,7 +269,7 @@ pub(super) async fn rebinding_old_pre_session_data_exchange( e })?; - send_pre_session_data_packet(init_policy, transport) + send_pre_session_data_packet(init_tdinfo, transport) .await .map_err(|e| { log::error!( @@ -348,11 +334,11 @@ pub(super) async fn rebinding_new_pre_session_data_exchange( e })?; - let init_policy = receive_pre_session_data_packet(transport) + let init_tdinfo = receive_pre_session_data_packet(transport) .await .map_err(|e| { log::error!( - "pre_session_data_exchange: send_pre_session_data_packet error: {:?}\n", + "pre_session_data_exchange: receive init_tdinfo error: {:?}\n", e ); e @@ -377,8 +363,8 @@ pub(super) async fn rebinding_new_pre_session_data_exchange( let mut policy_buffer = Vec::new(); policy_buffer.extend_from_slice(&(remote_policy.len() as u32).to_le_bytes()); policy_buffer.extend_from_slice(&remote_policy); - policy_buffer.extend_from_slice(&(init_policy.len() as u32).to_le_bytes()); - policy_buffer.extend_from_slice(&init_policy); + policy_buffer.extend_from_slice(&(init_tdinfo.len() as u32).to_le_bytes()); + policy_buffer.extend_from_slice(&init_tdinfo); Ok(policy_buffer) } @@ -392,90 +378,77 @@ pub async fn start_rebinding( // Exchange policy firstly because of the message size limitation of TLS protocol const PRE_SESSION_TIMEOUT: Duration = Duration::from_secs(60); // 60 seconds if info.rebinding_src == 1 { - match info.operation { - MIGTD_REBIND_OP_PREPARE => { - let local_data = InitData::get_from_local(&[0u8; 64]) - .ok_or(MigrationResult::InvalidParameter)?; - let init_migtd_data = info - .init_migtd_data - .as_ref() - .or(Some(&local_data)) - .ok_or(MigrationResult::InvalidParameter)?; - let remote_policy = Box::pin(with_timeout( - PRE_SESSION_TIMEOUT, - rebinding_old_pre_session_data_exchange(&mut transport, &init_migtd_data.init_policy), - )) - .await - .map_err(|e| { - log::error!( - "start_rebinding: rebinding_old_pre_session_data_exchange timeout error: {:?}\n", - e - ); - e - })? - .map_err(|e| { - log::error!( - "start_rebinding: rebinding_old_pre_session_data_exchange error: {:?}\n", - e - ); - e - })?; - #[cfg(not(feature = "spdm_attestation"))] - rebinding_old_prepare(transport, info, &init_migtd_data, data, remote_policy) - .await?; - - #[cfg(feature = "spdm_attestation")] - rebinding_old_prepare( - transport, - info, - data, - #[cfg(feature = "policy_v2")] - remote_policy, - ) - .await?; - } - MIGTD_REBIND_OP_FINALIZE => rebinding_old_finalize(info, data).await?, - _ => return Err(MigrationResult::InvalidParameter), - } + let local_data = + InitData::get_from_local(&[0u8; 64]).ok_or(MigrationResult::InvalidParameter)?; + let init_migtd_data = info + .init_migtd_data + .as_ref() + .or(Some(&local_data)) + .ok_or(MigrationResult::InvalidParameter)?; + let remote_policy = Box::pin(with_timeout( + PRE_SESSION_TIMEOUT, + rebinding_old_pre_session_data_exchange(&mut transport, &init_migtd_data.init_tdinfo), + )) + .await + .map_err(|e| { + log::error!( + "start_rebinding: rebinding_old_pre_session_data_exchange timeout error: {:?}\n", + e + ); + e + })? + .map_err(|e| { + log::error!( + "start_rebinding: rebinding_old_pre_session_data_exchange error: {:?}\n", + e + ); + e + })?; + #[cfg(not(feature = "spdm_attestation"))] + rebinding_old_prepare(transport, info, &init_migtd_data, data, remote_policy).await?; + + #[cfg(feature = "spdm_attestation")] + rebinding_old_prepare( + transport, + info, + data, + #[cfg(feature = "policy_v2")] + remote_policy, + ) + .await?; } else { - match info.operation { - MIGTD_REBIND_OP_PREPARE => { - let pre_session_data = Box::pin(with_timeout( - PRE_SESSION_TIMEOUT, - rebinding_new_pre_session_data_exchange(&mut transport), - )) - .await - .map_err(|e| { - log::error!( - "start_rebinding: rebinding_new_pre_session_data_exchange timeout error: {:?}\n", - e - ); - e - })? - .map_err(|e| { - log::error!( - "start_rebinding: rebinding_new_pre_session_data_exchange error: {:?}\n", - e - ); - e - })?; - - #[cfg(not(feature = "spdm_attestation"))] - rebinding_new_prepare(transport, info, data, pre_session_data).await?; - - #[cfg(feature = "spdm_attestation")] - rebinding_new_prepare( - transport, - info, - data, - #[cfg(feature = "policy_v2")] - pre_session_data, - ) - .await?; - } - MIGTD_REBIND_OP_FINALIZE => rebinding_new_finalize(info, data).await?, - _ => return Err(MigrationResult::InvalidParameter), - } + let pre_session_data = Box::pin(with_timeout( + PRE_SESSION_TIMEOUT, + rebinding_new_pre_session_data_exchange(&mut transport), + )) + .await + .map_err(|e| { + log::error!( + "start_rebinding: rebinding_new_pre_session_data_exchange timeout error: {:?}\n", + e + ); + e + })? + .map_err(|e| { + log::error!( + "start_rebinding: rebinding_new_pre_session_data_exchange error: {:?}\n", + e + ); + e + })?; + + #[cfg(not(feature = "spdm_attestation"))] + rebinding_new_prepare(transport, info, data, pre_session_data).await?; + + #[cfg(feature = "spdm_attestation")] + rebinding_new_prepare( + transport, + info, + data, + #[cfg(feature = "policy_v2")] + pre_session_data, + ) + .await?; } #[cfg(feature = "vmcall-raw")] { @@ -593,15 +566,27 @@ async fn rebinding_old_prepare( remote_policy: Vec, ) -> Result<(), MigrationResult> { let servtd_ext = read_servtd_ext(info.binding_handle, &info.target_td_uuid)?; - let init_policy_hash = digest_sha384(&init_migtd_data.init_policy)?; + + // Per GHCI 1.5: init policy key hash is in tdinfo.mrowner. + // Use mrowner directly as the init_policy_hash equivalent. + let init_policy_hash = init_migtd_data.mrowner().to_vec(); + + // Per GHCI 1.5: init_tdinfo replaces the old init_report (full TDREPORT). + // The TDINFO_STRUCT contains all the measurement fields needed for verification. + let init_tdinfo = &init_migtd_data.init_tdinfo; + + // Per GHCI 1.5: init_event_log is no longer part of MIGTD_DATA. + // Use local event log; RATLS cert still carries init_event_log extension + // for responder-side verification of init RTMRs. + let init_event_log = event_log::get_event_log().unwrap_or(&[]); // TLS client let mut ratls_client = ratls::client_rebinding( transport, remote_policy, &init_policy_hash, - &init_migtd_data.init_report, - &init_migtd_data.init_event_log, + init_tdinfo, + init_event_log, &servtd_ext, ) .map_err(|_| { @@ -629,12 +614,7 @@ async fn rebinding_old_prepare( Ok(()) } -pub async fn rebinding_old_finalize( - _info: &RebindingInfo, - _data: &mut Vec, -) -> Result<(), MigrationResult> { - Ok(()) -} + #[cfg(not(feature = "spdm_attestation"))] async fn rebinding_new_prepare( @@ -675,14 +655,7 @@ async fn rebinding_new_prepare( Ok(()) } -async fn rebinding_new_finalize( - _info: &RebindingInfo, - _data: &mut Vec, -) -> Result<(), MigrationResult> { - write_rebinding_session_token(&[0u8; 32])?; - write_approved_servtd_ext_hash(&[0u8; SHA384_DIGEST_SIZE])?; - Ok(()) -} + pub fn write_rebinding_session_token(rebind_token: &[u8]) -> Result<(), MigrationResult> { if rebind_token.len() != 32 { @@ -840,3 +813,185 @@ async fn tls_session_read_exact( } Ok(()) } + +#[cfg(test)] +mod test { + use super::*; + use alloc::vec; + + /// Build a minimal valid MIGTD_DATA blob containing one TDINFO_STRUCT entry. + fn build_migtd_data(tdinfo: &[u8]) -> Vec { + let mut buf = Vec::new(); + buf.extend_from_slice(MIGTD_DATA_SIGNATURE); // "MIGTDATA" + buf.extend_from_slice(&0x00010000u32.to_le_bytes()); // version + buf.extend_from_slice(&0u32.to_le_bytes()); // length placeholder + buf.extend_from_slice(&1u32.to_le_bytes()); // num_entries = 1 + // Entry: type 0 (TDINFO) + buf.extend_from_slice(&MIGTD_DATA_TYPE_TDINFO.to_le_bytes()); + buf.extend_from_slice(&(tdinfo.len() as u32).to_le_bytes()); + buf.extend_from_slice(tdinfo); + // Patch length + let total = buf.len() as u32; + buf[12..16].copy_from_slice(&total.to_le_bytes()); + buf + } + + /// Create a 512-byte TDINFO_STRUCT with known mrowner and mrownerconfig. + fn make_tdinfo(mrowner: &[u8; 48], mrownerconfig: &[u8; 48]) -> Vec { + let mut tdinfo = vec![0u8; 512]; + // mrowner at offset 112..160 + tdinfo[112..160].copy_from_slice(mrowner); + // mrownerconfig at offset 160..208 + tdinfo[160..208].copy_from_slice(mrownerconfig); + tdinfo + } + + // --- InitData tests --- + + #[test] + fn test_initdata_read_write_roundtrip() { + let mrowner = [0xAAu8; 48]; + let mrownerconfig = [0xBBu8; 48]; + let tdinfo = make_tdinfo(&mrowner, &mrownerconfig); + + let data = build_migtd_data(&tdinfo); + let init = InitData::read_from_bytes(&data).expect("should parse valid MIGTD_DATA"); + + assert_eq!(init.init_tdinfo.len(), 512); + assert_eq!(init.init_tdinfo, tdinfo); + + // Round-trip: write back and re-parse + let mut buf = Vec::new(); + init.write_into_bytes(&mut buf); + let init2 = InitData::read_from_bytes(&buf).expect("round-trip should parse"); + assert_eq!(init2.init_tdinfo, tdinfo); + } + + #[test] + fn test_initdata_mrowner_mrownerconfig() { + let mrowner = [0x11u8; 48]; + let mrownerconfig = [0x22u8; 48]; + let tdinfo = make_tdinfo(&mrowner, &mrownerconfig); + let data = build_migtd_data(&tdinfo); + + let init = InitData::read_from_bytes(&data).unwrap(); + assert_eq!(init.mrowner(), &mrowner); + assert_eq!(init.mrownerconfig(), &mrownerconfig); + } + + #[test] + fn test_initdata_rejects_bad_signature() { + let tdinfo = vec![0u8; 512]; + let mut data = build_migtd_data(&tdinfo); + data[0] = b'X'; // corrupt signature + assert!(InitData::read_from_bytes(&data).is_none()); + } + + #[test] + fn test_initdata_rejects_bad_version() { + let tdinfo = vec![0u8; 512]; + let mut data = build_migtd_data(&tdinfo); + data[8..12].copy_from_slice(&0x00020000u32.to_le_bytes()); // wrong version + assert!(InitData::read_from_bytes(&data).is_none()); + } + + #[test] + fn test_initdata_rejects_multiple_entries() { + let tdinfo = vec![0u8; 512]; + let mut data = build_migtd_data(&tdinfo); + data[16..20].copy_from_slice(&2u32.to_le_bytes()); // num_entries = 2 + assert!(InitData::read_from_bytes(&data).is_none()); + } + + #[test] + fn test_initdata_rejects_wrong_type() { + let tdinfo = vec![0u8; 512]; + let mut data = build_migtd_data(&tdinfo); + data[20..24].copy_from_slice(&1u32.to_le_bytes()); // type 1 instead of 0 + assert!(InitData::read_from_bytes(&data).is_none()); + } + + #[test] + fn test_initdata_rejects_short_tdinfo() { + let tdinfo = vec![0u8; 256]; // too small (< 512) + let data = build_migtd_data(&tdinfo); + assert!(InitData::read_from_bytes(&data).is_none()); + } + + #[test] + fn test_initdata_rejects_empty() { + assert!(InitData::read_from_bytes(&[]).is_none()); + assert!(InitData::read_from_bytes(&[0u8; 10]).is_none()); + } + + // --- RebindingInfo tests --- + + /// Build a minimal RebindingInfo byte buffer. + fn build_rebinding_info( + mig_request_id: u64, + rebinding_src: u8, + has_init_data: u8, + uuid: [u64; 4], + binding_handle: u64, + init_data: Option<&[u8]>, + ) -> Vec { + let mut buf = Vec::new(); + buf.extend_from_slice(&mig_request_id.to_le_bytes()); // 0..8 + buf.push(rebinding_src); // 8 + buf.push(has_init_data); // 9 + buf.extend_from_slice(&[0u8; 6]); // 10..16 reserved + for u in &uuid { + buf.extend_from_slice(&u.to_le_bytes()); // 16..48 + } + buf.extend_from_slice(&binding_handle.to_le_bytes()); // 48..56 + if let Some(data) = init_data { + buf.extend_from_slice(data); + } + buf + } + + #[test] + fn test_rebinding_info_no_init_data() { + let buf = build_rebinding_info(42, 1, 0, [1, 2, 3, 4], 99, None); + let info = RebindingInfo::read_from_bytes(&buf).expect("should parse"); + assert_eq!(info.mig_request_id, 42); + assert_eq!(info.rebinding_src, 1); + assert_eq!(info.has_init_data, 0); + assert_eq!(info.target_td_uuid, [1, 2, 3, 4]); + assert_eq!(info.binding_handle, 99); + assert!(info.init_migtd_data.is_none()); + } + + #[test] + fn test_rebinding_info_with_init_data() { + let tdinfo = make_tdinfo(&[0xCAu8; 48], &[0xFEu8; 48]); + let migtd_data = build_migtd_data(&tdinfo); + let buf = build_rebinding_info(7, 0, 1, [10, 20, 30, 40], 55, Some(&migtd_data)); + let info = RebindingInfo::read_from_bytes(&buf).expect("should parse with init data"); + assert_eq!(info.mig_request_id, 7); + assert_eq!(info.has_init_data, 1); + let init = info.init_migtd_data.as_ref().unwrap(); + assert_eq!(init.mrowner(), &[0xCAu8; 48]); + assert_eq!(init.mrownerconfig(), &[0xFEu8; 48]); + } + + #[test] + fn test_rebinding_info_rejects_short_buffer() { + assert!(RebindingInfo::read_from_bytes(&[0u8; 10]).is_none()); + assert!(RebindingInfo::read_from_bytes(&[0u8; 55]).is_none()); // 55 < 56 + } + + #[test] + fn test_rebinding_info_rejects_nonzero_reserved() { + let mut buf = build_rebinding_info(1, 0, 0, [0; 4], 0, None); + buf[10] = 0xFF; // reserved byte not zero + assert!(RebindingInfo::read_from_bytes(&buf).is_none()); + } + + #[test] + fn test_rebinding_info_rejects_has_init_data_without_data() { + // has_init_data=1 but no data bytes following → InitData::read_from_bytes fails + let buf = build_rebinding_info(1, 0, 1, [0; 4], 0, None); + assert!(RebindingInfo::read_from_bytes(&buf).is_none()); + } +} diff --git a/src/migtd/src/ratls/server_client.rs b/src/migtd/src/ratls/server_client.rs index b805c167..29536d00 100644 --- a/src/migtd/src/ratls/server_client.rs +++ b/src/migtd/src/ratls/server_client.rs @@ -184,7 +184,7 @@ pub fn client_rebinding( stream: T, remote_policy: Vec, init_policy_hash: &[u8], - init_td_report: &[u8], + init_tdinfo: &[u8], init_event_log: &[u8], servtd_ext: &ServtdExt, ) -> Result> { @@ -198,7 +198,7 @@ pub fn client_rebinding( let certs = create_certificate_for_rebinding_old( &signing_key, init_policy_hash, - init_td_report, + init_tdinfo, init_event_log, servtd_ext, ) @@ -409,7 +409,7 @@ fn create_certificate_for_client(signing_key: &EcdsaPk) -> Result<(Vec, Vec< fn create_certificate_for_rebinding_old( signing_key: &EcdsaPk, init_policy_hash: &[u8], - init_tdreport: &[u8], + init_tdinfo: &[u8], init_event_log: &[u8], servtd_ext: &ServtdExt, ) -> Result> { @@ -508,7 +508,7 @@ fn create_certificate_for_rebinding_old( Extension::new( EXTNID_MIGTD_TDREPORT_INIT, Some(false), - Some(&init_tdreport), + Some(&init_tdinfo), ) .map_err(|e| { log::error!( @@ -992,9 +992,10 @@ mod verify { log::error!("Failed to find expected policy hash extension.\n"); CryptoError::ParseCertificate })?; - let init_td_report = + // Per GHCI 1.5: init extension now carries TDINFO_STRUCT instead of full TDREPORT + let init_tdinfo = find_extension(extensions, &EXTNID_MIGTD_TDREPORT_INIT).ok_or_else(|| { - log::error!("Failed to find init tdreport extension.\n"); + log::error!("Failed to find init tdinfo extension.\n"); CryptoError::ParseCertificate })?; let init_event_log = @@ -1002,6 +1003,7 @@ mod verify { log::error!("Failed to find init event log extension.\n"); CryptoError::ParseCertificate })?; + // Per GHCI 1.5: init_policy_hash is now mrowner from the initial TDINFO_STRUCT let init_policy_hash = find_extension(extensions, &EXTNID_MIGTD_INIT_POLICY_HASH) .ok_or_else(|| { log::error!("Failed to find init policy hash extension.\n"); @@ -1012,6 +1014,7 @@ mod verify { CryptoError::ParseCertificate })?; + // Parse pre_session_data: [remote_policy_size(4) | remote_policy | init_tdinfo_size(4) | init_tdinfo] let remote_policy_size = u32::from_le_bytes( pre_session_data .get(..4) @@ -1024,18 +1027,19 @@ mod verify { let remote_policy = pre_session_data.get(4..4 + remote_policy_size).ok_or( CryptoError::TlsVerifyPeerCert(INVALID_MIG_POLICY_ERROR.to_string()), )?; - let init_policy_offset = 4 + remote_policy_size; - let init_policy_size = u32::from_le_bytes( + // Per GHCI 1.5: second item is init_tdinfo (was init_policy) + let init_tdinfo_offset = 4 + remote_policy_size; + let init_tdinfo_size = u32::from_le_bytes( pre_session_data - .get(init_policy_offset..4 + init_policy_offset) + .get(init_tdinfo_offset..4 + init_tdinfo_offset) .ok_or(CryptoError::TlsVerifyPeerCert( INVALID_MIG_POLICY_ERROR.to_string(), ))? .try_into() .unwrap(), ) as usize; - let init_policy = pre_session_data - .get(init_policy_offset + 4..init_policy_offset + 4 + init_policy_size) + let _init_tdinfo_from_pre_session = pre_session_data + .get(init_tdinfo_offset + 4..init_tdinfo_offset + 4 + init_tdinfo_size) .ok_or(CryptoError::TlsVerifyPeerCert( INVALID_MIG_POLICY_ERROR.to_string(), ))?; @@ -1046,9 +1050,10 @@ mod verify { INVALID_MIG_POLICY_ERROR.to_string(), )); } - let exact_init_policy_hash = digest_sha384(init_policy)?; - if init_policy_hash != exact_init_policy_hash.as_slice() { - log::error!("Invalid init rebinding policy.\n"); + // Per GHCI 1.5: init_policy_hash is mrowner from TDINFO — compare directly + // (no longer a hash of a policy blob) + if init_policy_hash != init_tdinfo.get(112..160).unwrap_or(&[]) { + log::error!("Invalid init policy hash (mrowner mismatch).\n"); return Err(CryptoError::TlsVerifyPeerCert( INVALID_MIG_POLICY_ERROR.to_string(), )); @@ -1058,9 +1063,8 @@ mod verify { td_report, event_log, remote_policy, - init_policy, + init_tdinfo, init_event_log, - init_td_report, servtd_ext, ); diff --git a/src/migtd/src/spdm/spdm_req.rs b/src/migtd/src/spdm/spdm_req.rs index 164a6c31..eeb627c2 100644 --- a/src/migtd/src/spdm/spdm_req.rs +++ b/src/migtd/src/spdm/spdm_req.rs @@ -959,21 +959,25 @@ pub async fn send_and_receive_sdm_rebind_attest_info( .extend_from_slice(servtd_ext.as_bytes()) .ok_or(SPDM_STATUS_BUFFER_FULL)?; - //TD report init - let tdreport_init = &init_migtd_data.init_report; + //TD info init (per GHCI 1.5: MIGTD_DATA type 0 = TDINFO_STRUCT) + // NOTE: VdmMessageElementType::TdReportInit name retained for wire compatibility; + // payload is now TDINFO_STRUCT, not full TDREPORT. + let tdinfo_init = &init_migtd_data.init_tdinfo; let tdreport_init_element = VdmMessageElement { element_type: VdmMessageElementType::TdReportInit, - length: tdreport_init.len() as u32, + length: tdinfo_init.len() as u32, }; cnt += tdreport_init_element .encode(&mut writer) .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; cnt += writer - .extend_from_slice(tdreport_init) + .extend_from_slice(tdinfo_init) .ok_or(SPDM_STATUS_BUFFER_FULL)?; //event log init - let event_log_init = &init_migtd_data.init_event_log; + // Per GHCI 1.5: init_event_log is no longer in MIGTD_DATA; use local event log. + // NOTE: EventLogInit VDM element retained for wire compatibility with responder. + let event_log_init = crate::event_log::get_event_log().unwrap_or(&[]); let event_log_init_element = VdmMessageElement { element_type: VdmMessageElementType::EventLogInit, length: event_log_init.len() as u32, @@ -986,9 +990,9 @@ pub async fn send_and_receive_sdm_rebind_attest_info( .ok_or(SPDM_STATUS_BUFFER_FULL)?; //mig policy init hash - let mig_policy_init = &init_migtd_data.init_policy; - let mig_policy_init_hash = - digest_sha384(mig_policy_init).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)?; + // Per GHCI 1.5: policy_key is in tdinfo.mrowner; sent as init_policy_hash. + // NOTE: MigPolicyInit VDM element name retained for wire compatibility. + let mig_policy_init_hash = init_migtd_data.mrowner().to_vec(); let mig_policy_init_element = VdmMessageElement { element_type: VdmMessageElementType::MigPolicyInit, length: mig_policy_init_hash.len() as u32, diff --git a/src/migtd/src/spdm/spdm_rsp.rs b/src/migtd/src/spdm/spdm_rsp.rs index 4bed1d68..4b858dfc 100644 --- a/src/migtd/src/spdm/spdm_rsp.rs +++ b/src/migtd/src/spdm/spdm_rsp.rs @@ -1052,16 +1052,17 @@ pub fn handle_exchange_rebind_attest_info_req( let remote_policy = pre_session_data .get(4..4 + remote_policy_size) .ok_or(MigrationResult::InvalidPolicyError)?; - let init_policy_offset = 4 + remote_policy_size; - let init_policy_size = u32::from_le_bytes( + // Per GHCI 1.5: second item in pre_session_data is init_tdinfo (was init_policy) + let init_tdinfo_offset = 4 + remote_policy_size; + let init_tdinfo_size = u32::from_le_bytes( pre_session_data - .get(init_policy_offset..4 + init_policy_offset) + .get(init_tdinfo_offset..4 + init_tdinfo_offset) .ok_or(MigrationResult::InvalidPolicyError)? .try_into() .unwrap(), ) as usize; - let init_policy = pre_session_data - .get(init_policy_offset + 4..init_policy_offset + 4 + init_policy_size) + let _init_tdinfo_from_pre_session = pre_session_data + .get(init_tdinfo_offset + 4..init_tdinfo_offset + 4 + init_tdinfo_size) .ok_or(MigrationResult::InvalidPolicyError)?; let remote_policy_hash = @@ -1073,11 +1074,11 @@ pub fn handle_exchange_rebind_attest_info_req( return Err(SPDM_STATUS_INVALID_MSG_FIELD); } - let mig_policy_init_hash = - digest_sha384(init_policy).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)?; - if mig_policy_init_hash_src != mig_policy_init_hash.as_slice() { + // Per GHCI 1.5: init_policy_hash is mrowner from TDINFO — compare directly + let mrowner = td_report_init_vec.get(112..160).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + if mig_policy_init_hash_src != mrowner { error!( - "The received mig policy init hash does not match the expected init policy hash!\n" + "The received mig policy init hash does not match mrowner from init tdinfo!\n" ); return Err(SPDM_STATUS_INVALID_MSG_FIELD); } @@ -1086,9 +1087,8 @@ pub fn handle_exchange_rebind_attest_info_req( &td_report_src_vec, &event_log_src_vec, remote_policy, - init_policy, - &event_log_init_vec, &td_report_init_vec, + &event_log_init_vec, &servtd_ext_vec, ); if let Err(e) = &policy_check_result {