diff --git a/src/migtd/src/mig_policy.rs b/src/migtd/src/mig_policy.rs index fd6dd7ed..2cb06c33 100644 --- a/src/migtd/src/mig_policy.rs +++ b/src/migtd/src/mig_policy.rs @@ -149,36 +149,12 @@ mod v2 { VERIFIED_POLICY.get() } - pub fn authenticate_remote( - is_src: bool, - quote_peer: &[u8], - policy_peer: &[u8], - event_log_peer: &[u8], - ) -> Result, PolicyError> { - let policy_issuer_chain = get_policy_issuer_chain().ok_or(PolicyError::InvalidParameter)?; - if is_src { - authenticate_migration_dest( - quote_peer, - event_log_peer, - policy_peer, - policy_issuer_chain, - ) - } else { - authenticate_migration_source( - quote_peer, - event_log_peer, - policy_peer, - policy_issuer_chain, - ) - } - } - - fn authenticate_migration_dest( + pub fn authenticate_migration_dest( quote_dst: &[u8], event_log_dst: &[u8], mig_policy_dst: &[u8], - policy_issuer_chain: &[u8], ) -> Result, PolicyError> { + let policy_issuer_chain = get_policy_issuer_chain().ok_or(PolicyError::InvalidParameter)?; let (evaluation_data_dst, verified_policy_dst, suppl_data) = authenticate_remote_common( quote_dst, event_log_dst, @@ -207,26 +183,44 @@ mod v2 { Ok(suppl_data) } - fn authenticate_migration_source( + pub fn authenticate_migration_source( quote_src: &[u8], event_log_src: &[u8], mig_policy_src: &[u8], - policy_issuer_chain: &[u8], + #[cfg(feature = "vmcall-raw")] init_policy: &[u8], + #[cfg(feature = "vmcall-raw")] init_td_report: &[u8], + #[cfg(feature = "vmcall-raw")] init_event_log: &[u8], + #[cfg(feature = "vmcall-raw")] servtd_ext_src: &[u8], ) -> Result, PolicyError> { + let policy_issuer_chain = get_policy_issuer_chain().ok_or(PolicyError::InvalidParameter)?; let (evaluation_data_src, _verified_policy_src, suppl_data) = authenticate_remote_common( quote_src, event_log_src, mig_policy_src, policy_issuer_chain, )?; - let relative_reference = get_local_tcb_evaluation_info()?; - let policy = get_verified_policy().ok_or(PolicyError::InvalidParameter)?; - policy.policy_data.evaluate_policy_backward( - &evaluation_data_src, - &relative_reference, - false, - )?; + #[cfg(feature = "vmcall-raw")] + { + 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 verified_policy_init = verify_policy_and_event_log( + init_event_log, + init_policy, + policy_issuer_chain, + &get_rtmrs_from_tdreport(&init_tdreport)?, + )?; + let relative_reference = + get_init_tcb_evaluation_info(&init_tdreport, &verified_policy_init)?; + let policy = get_verified_policy().ok_or(PolicyError::InvalidParameter)?; + + policy.policy_data.evaluate_policy_backward( + &evaluation_data_src, + &relative_reference, + false, + )?; + } Ok(suppl_data) } diff --git a/src/migtd/src/migration/data.rs b/src/migtd/src/migration/data.rs index e5ccf16a..5f3ee544 100644 --- a/src/migtd/src/migration/data.rs +++ b/src/migtd/src/migration/data.rs @@ -356,9 +356,7 @@ fn create_migration_information( mig_socket_hob: Option<&[u8]>, policy_info_hob: Option<&[u8]>, ) -> Option { - let mig_info = hob_lib::get_guid_data(mig_info_hob?)? - .pread::(0) - .ok()?; + let mig_info = MigtdMigrationInformation::read_from_bytes(mig_info_hob?)?; #[cfg(any(feature = "vmcall-vsock", feature = "virtio-vsock"))] let mig_socket_info = hob_lib::get_guid_data(mig_socket_hob?)? diff --git a/src/migtd/src/migration/mod.rs b/src/migtd/src/migration/mod.rs index 86636eb5..0df70b37 100644 --- a/src/migtd/src/migration/mod.rs +++ b/src/migtd/src/migration/mod.rs @@ -16,6 +16,8 @@ pub mod session; pub mod transport; use crate::driver::ticks::TimeoutError; +#[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] +use crate::migration::rebinding::InitData; use crate::ratls::RatlsError; use crate::ratls::{ INVALID_MIG_POLICY_ERROR, MIG_POLICY_UNSATISFIED_ERROR, MUTUAL_ATTESTATION_ERROR, @@ -79,7 +81,6 @@ pub const STREAM_SOCKET_INFO_HOB_GUID: Guid = Guid::from_fields( ); #[repr(C)] -#[derive(Debug, Pread, Pwrite, Clone, Default)] pub struct MigtdMigrationInformation { // ID for the migration request, which can be used in TDG.VP.VMCALL // @@ -87,7 +88,10 @@ pub struct MigtdMigrationInformation { // If set, current MigTD is MigTD-s else current MigTD is MigTD-d pub migration_source: u8, - _pad: [u8; 7], + + #[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] + // Has init migtd data + pub has_init_data: u8, // UUID of target TD pub target_td_uuid: [u64; 4], @@ -103,6 +107,64 @@ pub struct MigtdMigrationInformation { // Unique identifier for the communication between MigTD and VMM // It can be retrieved from MIGTD_STREAM_SOCKET_INFO HOB pub communication_id: u64, + + #[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] + pub init_migtd_data: Option, +} + +impl MigtdMigrationInformation { + pub fn read_from_bytes(b: &[u8]) -> Option { + let min_len = if cfg!(feature = "vmcall-raw") { 56 } else { 72 }; + + if b.len() < min_len { + return None; + } + + if b[10..16] != [0; 6] { + return None; + } + + let mig_request_id = u64::from_le_bytes(b[..8].try_into().unwrap()); + let migration_source = b[8]; + #[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] + let has_init_data = b[9]; + + let target_td_uuid: [u64; 4] = core::array::from_fn(|i| { + let offset = 16 + i * 8; + u64::from_le_bytes(b[offset..offset + 8].try_into().unwrap()) + }); + + let binding_handle = u64::from_le_bytes(b[48..56].try_into().unwrap()); + + #[cfg(not(feature = "vmcall-raw"))] + let mig_policy_id = u64::from_le_bytes(b[56..64].try_into().unwrap()); + + #[cfg(not(feature = "vmcall-raw"))] + let communication_id = u64::from_le_bytes(b[64..72].try_into().unwrap()); + + #[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] + let mut init_migtd_data = None; + + #[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] + if has_init_data == 1 { + init_migtd_data = Some(InitData::read_from_bytes(&b[56..])?); + } + + Some(Self { + mig_request_id, + migration_source, + #[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] + has_init_data, + target_td_uuid, + binding_handle, + #[cfg(not(feature = "vmcall-raw"))] + mig_policy_id, + #[cfg(not(feature = "vmcall-raw"))] + communication_id, + #[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] + init_migtd_data, + }) + } } #[repr(C)] diff --git a/src/migtd/src/migration/pre_session_data.rs b/src/migtd/src/migration/pre_session_data.rs index 94748abc..6fd0c63d 100644 --- a/src/migtd/src/migration/pre_session_data.rs +++ b/src/migtd/src/migration/pre_session_data.rs @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: BSD-2-Clause-Patent +use crate::{config, migration::transport::TransportType}; + use super::MigrationResult; use alloc::{vec, vec::Vec}; use async_io::{AsyncRead, AsyncWrite}; @@ -318,10 +320,9 @@ pub(super) async fn exchange_hello_packet( .ok_or(MigrationResult::InvalidParameter) } -#[cfg(feature = "policy_v2")] -pub(super) async fn pre_session_data_exchange( - transport: &mut T, - pre_session_data: &[u8], +pub(super) async fn source_pre_session_data_exchange( + transport: &mut TransportType, + #[cfg(feature = "vmcall-raw")] init_policy: &[u8], ) -> Result> { let version = exchange_hello_packet(transport).await.map_err(|e| { log::error!( @@ -332,7 +333,13 @@ pub(super) async fn pre_session_data_exchange })?; log::info!("Pre-Session-Message Version: 0x{:04x}\n", version); - send_pre_session_data_packet(pre_session_data, transport) + let policy = config::get_policy() + .ok_or(MigrationResult::InvalidParameter) + .map_err(|e| { + log::error!("pre_session_data_exchange: get_policy error: {:?}\n", e); + e + })?; + send_pre_session_data_packet(policy, transport) .await .map_err(|e| { log::error!( @@ -351,6 +358,17 @@ pub(super) async fn pre_session_data_exchange e })?; + #[cfg(feature = "vmcall-raw")] + send_pre_session_data_packet(init_policy, transport) + .await + .map_err(|e| { + log::error!( + "pre_session_data_exchange: send_pre_session_data_packet error: {:?}\n", + e + ); + e + })?; + send_start_session_packet(transport).await.map_err(|e| { log::error!( "pre_session_data_exchange: send_start_session_packet error: {:?}\n", @@ -368,3 +386,78 @@ pub(super) async fn pre_session_data_exchange Ok(remote_policy) } + +pub(super) async fn dest_pre_session_data_exchange( + transport: &mut TransportType, +) -> Result> { + let version = exchange_hello_packet(transport).await.map_err(|e| { + log::error!( + "pre_session_data_exchange: exchange_hello_packet error: {:?}\n", + e + ); + e + })?; + log::info!("Pre-Session-Message Version: 0x{:04x}\n", version); + + let policy = config::get_policy() + .ok_or(MigrationResult::InvalidParameter) + .map_err(|e| { + log::error!("pre_session_data_exchange: get_policy error: {:?}\n", e); + e + })?; + send_pre_session_data_packet(policy, transport) + .await + .map_err(|e| { + log::error!( + "pre_session_data_exchange: send_pre_session_data_packet error: {:?}\n", + e + ); + e + })?; + let remote_policy = receive_pre_session_data_packet(transport) + .await + .map_err(|e| { + log::error!( + "pre_session_data_exchange: receive_pre_session_data_packet error: {:?}\n", + e + ); + e + })?; + + #[cfg(feature = "vmcall-raw")] + let init_policy = receive_pre_session_data_packet(transport) + .await + .map_err(|e| { + log::error!( + "pre_session_data_exchange: send_pre_session_data_packet error: {:?}\n", + e + ); + e + })?; + + send_start_session_packet(transport).await.map_err(|e| { + log::error!( + "pre_session_data_exchange: send_start_session_packet error: {:?}\n", + e + ); + e + })?; + receive_start_session_packet(transport).await.map_err(|e| { + log::error!( + "pre_session_data_exchange: receive_start_session_packet error: {:?}\n", + e + ); + e + })?; + + // FIXME: Refactor the TLS verification callback to enable easier access to pre-session data. + 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); + #[cfg(feature = "vmcall-raw")] + policy_buffer.extend_from_slice(&(init_policy.len() as u32).to_le_bytes()); + #[cfg(feature = "vmcall-raw")] + policy_buffer.extend_from_slice(&init_policy); + + Ok(policy_buffer) +} diff --git a/src/migtd/src/migration/rebinding.rs b/src/migtd/src/migration/rebinding.rs index f9d28ed9..cb398007 100644 --- a/src/migtd/src/migration/rebinding.rs +++ b/src/migtd/src/migration/rebinding.rs @@ -6,6 +6,7 @@ use alloc::{boxed::Box, vec::Vec}; use core::mem::MaybeUninit; use core::time::Duration; use crypto::{ + hash::digest_sha384, tls::SecureChannel, x509::{Certificate, Decode}, SHA384_DIGEST_SIZE, @@ -16,17 +17,10 @@ use tdx_tdcall::tdx::{tdcall_servtd_rebind_approve, tdcall_vm_write}; 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, - migration::pre_session_data::{ - exchange_hello_packet, receive_pre_session_data_packet, receive_start_session_packet, - send_pre_session_data_packet, send_start_session_packet, - }, + config, event_log, + migration::{pre_session_data::*, transport::*}, }; - use crate::{ driver::ticks::with_timeout, migration::{ @@ -245,144 +239,6 @@ impl<'a> MigtdDataEntry<'a> { } } -pub(super) async fn rebinding_old_pre_session_data_exchange( - transport: &mut TransportType, - init_policy: &[u8], -) -> Result, MigrationResult> { - let version = exchange_hello_packet(transport).await.map_err(|e| { - log::error!( - "pre_session_data_exchange: exchange_hello_packet error: {:?}\n", - e - ); - e - })?; - log::info!("Pre-Session-Message Version: 0x{:04x}\n", version); - - let policy = config::get_policy() - .ok_or(MigrationResult::InvalidParameter) - .map_err(|e| { - log::error!("pre_session_data_exchange: get_policy error: {:?}\n", e); - e - })?; - send_pre_session_data_packet(policy, transport) - .await - .map_err(|e| { - log::error!( - "pre_session_data_exchange: send_pre_session_data_packet error: {:?}\n", - e - ); - e - })?; - let remote_policy = receive_pre_session_data_packet(transport) - .await - .map_err(|e| { - log::error!( - "pre_session_data_exchange: receive_pre_session_data_packet error: {:?}\n", - e - ); - e - })?; - - send_pre_session_data_packet(init_policy, transport) - .await - .map_err(|e| { - log::error!( - "pre_session_data_exchange: send_pre_session_data_packet error: {:?}\n", - e - ); - e - })?; - - send_start_session_packet(transport).await.map_err(|e| { - log::error!( - "pre_session_data_exchange: send_start_session_packet error: {:?}\n", - e - ); - e - })?; - receive_start_session_packet(transport).await.map_err(|e| { - log::error!( - "pre_session_data_exchange: receive_start_session_packet error: {:?}\n", - e - ); - e - })?; - - Ok(remote_policy) -} - -pub(super) async fn rebinding_new_pre_session_data_exchange( - transport: &mut TransportType, -) -> Result, MigrationResult> { - let version = exchange_hello_packet(transport).await.map_err(|e| { - log::error!( - "pre_session_data_exchange: exchange_hello_packet error: {:?}\n", - e - ); - e - })?; - log::info!("Pre-Session-Message Version: 0x{:04x}\n", version); - - let policy = config::get_policy() - .ok_or(MigrationResult::InvalidParameter) - .map_err(|e| { - log::error!("pre_session_data_exchange: get_policy error: {:?}\n", e); - e - })?; - send_pre_session_data_packet(policy, transport) - .await - .map_err(|e| { - log::error!( - "pre_session_data_exchange: send_pre_session_data_packet error: {:?}\n", - e - ); - e - })?; - let remote_policy = receive_pre_session_data_packet(transport) - .await - .map_err(|e| { - log::error!( - "pre_session_data_exchange: receive_pre_session_data_packet error: {:?}\n", - e - ); - e - })?; - - let init_policy = receive_pre_session_data_packet(transport) - .await - .map_err(|e| { - log::error!( - "pre_session_data_exchange: send_pre_session_data_packet error: {:?}\n", - e - ); - e - })?; - - send_start_session_packet(transport).await.map_err(|e| { - log::error!( - "pre_session_data_exchange: send_start_session_packet error: {:?}\n", - e - ); - e - })?; - receive_start_session_packet(transport).await.map_err(|e| { - log::error!( - "pre_session_data_exchange: receive_start_session_packet error: {:?}\n", - e - ); - e - })?; - - // FIXME: Refactor the TLS verification callback to enable easier access to pre-session data. - 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); - - Ok(policy_buffer) -} - pub async fn start_rebinding( info: &RebindingInfo, data: &mut Vec, @@ -401,19 +257,19 @@ pub async fn start_rebinding( .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), + source_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", + "start_rebinding: source_pre_session_data_exchange timeout error: {:?}\n", e ); e })? .map_err(|e| { log::error!( - "start_rebinding: rebinding_old_pre_session_data_exchange error: {:?}\n", + "start_rebinding: source_pre_session_data_exchange error: {:?}\n", e ); e @@ -446,12 +302,12 @@ pub async fn start_rebinding( } else { let pre_session_data = Box::pin(with_timeout( PRE_SESSION_TIMEOUT, - rebinding_new_pre_session_data_exchange(&mut transport), + dest_pre_session_data_exchange(&mut transport), )) .await .map_err(|e| { log::error!( - "start_rebinding: rebinding_new_pre_session_data_exchange timeout error: {:?}\n", + "start_rebinding: dest_pre_session_data_exchange timeout error: {:?}\n", e ); e diff --git a/src/migtd/src/migration/session.rs b/src/migtd/src/migration/session.rs index 82280a9c..9e884cd3 100644 --- a/src/migtd/src/migration/session.rs +++ b/src/migtd/src/migration/session.rs @@ -3,7 +3,12 @@ // SPDX-License-Identifier: BSD-2-Clause-Patent #[cfg(feature = "policy_v2")] -use crate::migration::pre_session_data::pre_session_data_exchange; +use crate::migration::pre_session_data::{ + dest_pre_session_data_exchange, source_pre_session_data_exchange, +}; +#[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] +use crate::migration::servtd_ext::read_servtd_ext; + #[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] use crate::migration::rebinding::RebindingInfo; use crate::migration::transport::setup_transport; @@ -310,29 +315,19 @@ pub async fn wait_for_request() -> Result { let operation: u8 = data_status_bytes[1]; log::trace!("wait_for_request: Received operation {} with data length {}\n", operation, data_length); if operation == DataStatusOperation::StartMigration as u8 { - // data_length should be MigtdMigrationInformation - let expected_datalength = size_of::(); - if data_length != expected_datalength as u32 { - if data_length >= size_of::() as u32 { - let slice = &data_buffer[reqbufferhdrlen..reqbufferhdrlen + data_length as usize]; - let mig_request_id = u64::from_le_bytes(slice[0..8].try_into().unwrap()); - log::error!(migration_request_id = mig_request_id; "wait_for_request: StartMigration operation incorrect data length - expected {} actual {}\n", expected_datalength, data_length); - } else { - log::error!("wait_for_request: StartMigration operation incorrect data length - expected {} actual {}\n", expected_datalength, data_length); - } - return Poll::Pending; - } let slice = &data_buffer[reqbufferhdrlen..reqbufferhdrlen + data_length as usize]; - let mig_request_id = u64::from_le_bytes(slice[0..8].try_into().unwrap()); - - let wfr_info = MigtdMigrationInformation { - mig_request_id, - migration_source: slice[8], - _pad: slice[9..16].try_into().unwrap(), - target_td_uuid: parse_uuid(&slice[16..48]), - binding_handle: u64::from_le_bytes(slice[48..56].try_into().unwrap()), + let wfr_info = match MigtdMigrationInformation::read_from_bytes(slice) { + Some(info) => info, + None => { + log::error!( + "wait_for_request: StartMigration operation invalid data, len: {}", + data_length + ); + return Poll::Pending; + } }; + let mig_request_id = wfr_info.mig_request_id; let wfr_info = MigrationInformation { mig_info: wfr_info }; try_accept_request(mig_request_id, WaitForRequestResponse::StartMigration(wfr_info)) @@ -755,14 +750,27 @@ async fn migration_src_exchange_msk( exchange_information: &ExchangeInformation, remote_information: &mut ExchangeInformation, #[cfg(feature = "policy_v2")] remote_policy: Vec, + #[cfg(all(feature = "policy_v2", feature = "vmcall-raw"))] init_migtd_data: &InitData, ) -> Result<()> { const TLS_TIMEOUT: Duration = Duration::from_secs(60); // 60 seconds + #[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] + let servtd_ext = read_servtd_ext(info.mig_info.binding_handle, &info.mig_info.target_td_uuid) + .inspect(|_| { + #[cfg(feature = "vmcall-raw")] + log::error!(migration_request_id = info.mig_info.mig_request_id; + "migration_src_exchange_msk(): Failed to get SERVTD_EXT.\n" + ); + })?; // TLS client let mut ratls_client = ratls::client( transport, #[cfg(feature = "policy_v2")] remote_policy, + #[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] + &init_migtd_data, + #[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] + &servtd_ext, ) .map_err(|e| { log::error!(migration_request_id = info.mig_info.mig_request_id; @@ -976,29 +984,6 @@ pub async fn exchange_msk(info: &MigrationInformation) -> Result<()> { // Exchange policy firstly because of the message size limitation of TLS protocol #[cfg(feature = "policy_v2")] const PRE_SESSION_TIMEOUT: Duration = Duration::from_secs(60); // 60 seconds - #[cfg(feature = "policy_v2")] - let policy = crate::config::get_policy() - .ok_or(MigrationResult::InvalidParameter) - .map_err(|e| { - log::error!("pre_session_data_exchange: get_policy error: {:?}\n", e); - e - })?; - #[cfg(feature = "policy_v2")] - let remote_policy = Box::pin(with_timeout( - PRE_SESSION_TIMEOUT, - pre_session_data_exchange(&mut transport, policy), - )) - .await - .map_err(|e| { - log::error!(migration_request_id = info.mig_info.mig_request_id; "exchange_msk: pre_session_data_exchange timeout error: {:?}\n", - e - ); - e - })? - .map_err(|e| { - log::error!(migration_request_id = info.mig_info.mig_request_id; "exchange_msk: pre_session_data_exchange error: {:?}\n", e); - e - })?; #[cfg(not(feature = "spdm_attestation"))] { @@ -1011,6 +996,36 @@ pub async fn exchange_msk(info: &MigrationInformation) -> Result<()> { // Establish TLS layer connection and negotiate the MSK if info.is_src() { + #[cfg(all(feature = "policy_v2", feature = "vmcall-raw"))] + let local_data = + InitData::get_from_local(&[0u8; 64]).ok_or(MigrationResult::InvalidParameter)?; + #[cfg(all(feature = "policy_v2", feature = "vmcall-raw"))] + let init_migtd_data = info + .mig_info + .init_migtd_data + .as_ref() + .or(Some(&local_data)) + .ok_or(MigrationResult::InvalidParameter)?; + #[cfg(feature = "policy_v2")] + let remote_policy = Box::pin(with_timeout( + PRE_SESSION_TIMEOUT, + source_pre_session_data_exchange(&mut transport, + #[cfg(feature = "vmcall-raw")] + &init_migtd_data.init_policy + ), + )) + .await + .map_err(|e| { + log::error!(migration_request_id = info.mig_info.mig_request_id; "exchange_msk: source_pre_session_data_exchange timeout error: {:?}\n", + e + ); + e + })? + .map_err(|e| { + log::error!(migration_request_id = info.mig_info.mig_request_id; "exchange_msk: source_pre_session_data_exchange error: {:?}\n", e); + e + })?; + migration_src_exchange_msk( transport, info, @@ -1018,9 +1033,28 @@ pub async fn exchange_msk(info: &MigrationInformation) -> Result<()> { &mut remote_information, #[cfg(feature = "policy_v2")] remote_policy, + #[cfg(all(feature = "policy_v2", feature = "vmcall-raw"))] + init_migtd_data, ) .await?; } else { + #[cfg(feature = "policy_v2")] + let remote_policy = Box::pin(with_timeout( + PRE_SESSION_TIMEOUT, + dest_pre_session_data_exchange(&mut transport), + )) + .await + .map_err(|e| { + log::error!(migration_request_id = info.mig_info.mig_request_id; "exchange_msk: dest_pre_session_data_exchange timeout error: {:?}\n", + e + ); + e + })? + .map_err(|e| { + log::error!(migration_request_id = info.mig_info.mig_request_id; "exchange_msk: dest_pre_session_data_exchange error: {:?}\n", e); + e + })?; + migration_dst_exchange_msk( transport, info, diff --git a/src/migtd/src/ratls/server_client.rs b/src/migtd/src/ratls/server_client.rs index b805c167..20346534 100644 --- a/src/migtd/src/ratls/server_client.rs +++ b/src/migtd/src/ratls/server_client.rs @@ -18,6 +18,8 @@ use tdx_tdcall::tdreport::TdxReport; use super::*; use crate::event_log::get_event_log; +#[cfg(all(feature = "policy_v2", feature = "vmcall-raw"))] +use crate::migration::rebinding::InitData; #[cfg(feature = "policy_v2")] use crate::{config::get_policy, migration::servtd_ext::ServtdExt}; use verify::*; @@ -116,6 +118,8 @@ pub fn client(stream: T) -> Result( stream: T, remote_policy: Vec, + #[cfg(feature = "vmcall-raw")] init_data: &InitData, + #[cfg(feature = "vmcall-raw")] servtd_ext: &ServtdExt, ) -> Result> { let signing_key = EcdsaPk::new().map_err(|e| { log::error!( @@ -124,7 +128,14 @@ pub fn client( ); e })?; - let (certs, _quote) = create_certificate_for_client(&signing_key).map_err(|e| { + let (certs, _quote) = create_certificate_for_client( + &signing_key, + #[cfg(feature = "vmcall-raw")] + init_data, + #[cfg(feature = "vmcall-raw")] + servtd_ext, + ) + .map_err(|e| { log::error!("client policy_v2 gen_cert() failed with error {:?}\n", e); e })?; @@ -326,7 +337,11 @@ fn create_certificate_for_server(signing_key: &EcdsaPk) -> Result<(Vec, Vec< Ok((x509_cert_der, quote)) } -fn create_certificate_for_client(signing_key: &EcdsaPk) -> Result<(Vec, Vec)> { +fn create_certificate_for_client( + signing_key: &EcdsaPk, + #[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] init_data: &InitData, + #[cfg(all(feature = "vmcall-raw", feature = "policy_v2"))] servtd_ext: &ServtdExt, +) -> Result<(Vec, Vec)> { let pub_key = signing_key.public_key().map_err(|e| { log::error!( "gen_cert signing_key.public_key() failed with error {:?}\n", @@ -354,6 +369,12 @@ fn create_certificate_for_client(signing_key: &EcdsaPk) -> Result<(Vec, Vec< e })?; + #[cfg(all(feature = "policy_v2", feature = "vmcall-raw"))] + let init_policy_hash = digest_sha384(&init_data.init_policy).map_err(|e| { + log::error!("gen_cert digest_sha384() failed with error {:?}\n", e); + e + })?; + let eku = create_eku()?; let key_usage = create_key_usage()?; @@ -401,6 +422,93 @@ fn create_certificate_for_client(signing_key: &EcdsaPk) -> Result<(Vec, Vec< e })?; + #[cfg(all(feature = "policy_v2", feature = "vmcall-raw"))] + let x509_builder = x509_builder + .add_extension( + Extension::new( + EXTNID_MIGTD_SERVTD_EXT, + Some(false), + Some(servtd_ext.as_bytes()), + ) + .map_err(|e| { + log::error!( + "gen_cert policy_v2 add_extension failed with error {:?}.\n", + e + ); + e + })?, + ) + .map_err(|e| { + log::error!( + "gen_cert policy_v2 add_extension for servtd_ext failed with error {:?}.\n", + e + ); + e + })? + .add_extension( + Extension::new( + EXTNID_MIGTD_EVENT_LOG_INIT, + Some(false), + Some(&init_data.init_event_log), + ) + .map_err(|e| { + log::error!( + "gen_cert policy_v2 add_extension failed with error {:?}.\n", + e + ); + e + })?, + ) + .map_err(|e| { + log::error!( + "gen_cert policy_v2 add_extension for event log init failed with error {:?}.\n", + e + ); + e + })? + .add_extension( + Extension::new( + EXTNID_MIGTD_TDREPORT_INIT, + Some(false), + Some(&init_data.init_report), + ) + .map_err(|e| { + log::error!( + "gen_cert policy_v2 add_extension failed with error {:?}.\n", + e + ); + e + })?, + ) + .map_err(|e| { + log::error!( + "gen_cert policy_v2 add_extension for tdreport init failed with error {:?}.\n", + e + ); + e + })? + .add_extension( + Extension::new( + EXTNID_MIGTD_INIT_POLICY_HASH, + Some(false), + Some(&init_policy_hash), + ) + .map_err(|e| { + log::error!( + "gen_cert policy_v2 add_extension failed with error {:?}.\n", + e + ); + e + })?, + ) + .map_err(|e| { + log::error!( + "gen_cert policy_v2 add_extension for init policy hash failed with error {:?}.\n", + e + ); + e + })?; + let x509_cert_der = sign_tls_tbs(x509_builder, &signing_key)?; Ok((x509_cert_der, quote)) } @@ -810,7 +918,7 @@ fn verify_client_cert(cert: &[u8], quote: &[u8]) -> core::result::Result<(), Cry verify_peer_cert(false, cert, quote) } -#[cfg(not(feature = "test_disable_ra_and_accept_all"))] +// #[cfg(not(feature = "test_disable_ra_and_accept_all"))] mod verify { use super::*; use crate::mig_policy; @@ -897,7 +1005,7 @@ mod verify { pub fn verify_peer_cert( is_client: bool, cert: &[u8], - policy: &[u8], + pre_session_data: &[u8], ) -> core::result::Result<(), CryptoError> { let cert = Certificate::from_der(cert).map_err(|_| { log::error!("Failed to parse certificate from DER.\n"); @@ -929,16 +1037,94 @@ mod verify { CryptoError::ParseCertificate })?; - let exact_policy_hash = digest_sha384(policy)?; + let remote_policy_size = u32::from_le_bytes( + pre_session_data + .get(..4) + .ok_or(CryptoError::TlsVerifyPeerCert( + INVALID_MIG_POLICY_ERROR.to_string(), + ))? + .try_into() + .unwrap(), + ) as usize; + let remote_policy = pre_session_data.get(4..4 + remote_policy_size).ok_or( + CryptoError::TlsVerifyPeerCert(INVALID_MIG_POLICY_ERROR.to_string()), + )?; + + let exact_policy_hash = digest_sha384(remote_policy)?; if expected_policy_hash != exact_policy_hash.as_slice() { - log::error!("Invalid migration policy.\n"); + log::error!("Invalid rebinding policy.\n"); return Err(CryptoError::TlsVerifyPeerCert( INVALID_MIG_POLICY_ERROR.to_string(), )); } + + #[cfg(feature = "vmcall-raw")] + let policy_check_result = { + if is_client { + mig_policy::authenticate_migration_dest(quote_report, remote_policy, event_log) + } else { + let init_td_report = find_extension(extensions, &EXTNID_MIGTD_TDREPORT_INIT) + .ok_or_else(|| { + log::error!("Failed to find init tdreport extension.\n"); + CryptoError::ParseCertificate + })?; + let init_event_log = find_extension(extensions, &EXTNID_MIGTD_EVENT_LOG_INIT) + .ok_or_else(|| { + log::error!("Failed to find init event log extension.\n"); + CryptoError::ParseCertificate + })?; + 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"); + CryptoError::ParseCertificate + })?; + let servtd_ext = + find_extension(extensions, &EXTNID_MIGTD_SERVTD_EXT).ok_or_else(|| { + log::error!("Failed to find servtd ext extension.\n"); + CryptoError::ParseCertificate + })?; + + let init_policy_offset = 4 + remote_policy_size; + let init_policy_size = u32::from_le_bytes( + pre_session_data + .get(init_policy_offset..4 + init_policy_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) + .ok_or(CryptoError::TlsVerifyPeerCert( + 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"); + return Err(CryptoError::TlsVerifyPeerCert( + INVALID_MIG_POLICY_ERROR.to_string(), + )); + } + mig_policy::authenticate_migration_source( + quote_report, + remote_policy, + event_log, + init_policy, + init_td_report, + init_event_log, + servtd_ext, + ) + } + }; + // MigTD-src acts as TLS client - let policy_check_result = - mig_policy::authenticate_remote(is_client, quote_report, policy, event_log); + #[cfg(not(feature = "vmcall-raw"))] + let policy_check_result = if is_client { + mig_policy::authenticate_migration_dest(quote_report, remote_policy, event_log) + } else { + mig_policy::authenticate_migration_source(quote_report, remote_policy, event_log) + }; if let Err(e) = &policy_check_result { log::error!("Policy check failed, below is the detail information:\n");