Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions deps/td-shim-AzCVMEmu/tdx-tdcall/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,15 @@ pub mod tdx {
tdvmcall_wrmsr,
// Re-export types
TdxDigest,
TargetTdUuid,
};

// Export emulated functions
pub use crate::tdx_emu::{
tdcall_extend_rtmr, tdcall_servtd_rd, tdcall_servtd_wr, tdcall_sys_rd, tdcall_sys_wr,
tdvmcall_get_quote, tdvmcall_migtd_receive_sync as tdvmcall_migtd_receive,
tdvmcall_migtd_reportstatus, tdvmcall_migtd_send_sync as tdvmcall_migtd_send,
tdvmcall_migtd_waitforrequest, tdvmcall_setup_event_notify,
tdvmcall_migtd_waitforrequest, tdvmcall_setup_event_notify, tdcall_vm_write, tdcall_servtd_rebind_approve,
};
}

Expand All @@ -87,7 +88,7 @@ pub mod tdreport {

// Re-export some useful constants and types from original
pub use original_tdx_tdcall::tdreport::{
TdxReport, TD_REPORT_ADDITIONAL_DATA_SIZE, TD_REPORT_SIZE,
TdxReport, TD_REPORT_ADDITIONAL_DATA_SIZE, TD_REPORT_SIZE, TdInfo,
};

/// Emulated tdcall_report function for AzCVMEmu mode
Expand Down Expand Up @@ -118,6 +119,12 @@ pub mod tdreport {

Ok(tdx_report)
}

/// Emulated TD Report Verification
pub fn tdcall_verify_report(report_mac: &[u8]) -> Result<(), TdCallError> {
log::warn!("Emulated TD report verification");
Ok(())
}
}

// Add td_call emulation support
Expand Down
16 changes: 12 additions & 4 deletions deps/td-shim-AzCVMEmu/tdx-tdcall/src/tdreport_emu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ pub enum QuoteError {
ConversionError,
}

/// Emulated TD Report Verification
#[cfg(feature = "test_mock_report")]
pub fn tdcall_verify_report(report_mac: &[u8]) -> Result<(), TdCallError> {
info!("Using mock TD report verification for test_mock_report feature");
Ok(())
}

/// Emulated TD report generation using mock report
#[cfg(feature = "test_mock_report")]
pub fn tdcall_report_emulated(_additional_data: &[u8; 64]) -> Result<tdx::TdReport, TdCallError> {
Expand Down Expand Up @@ -423,7 +430,7 @@ fn create_td_report_from_file(quote_file_path: String) -> tdx::TdReport {
}

// Get report body from quote
let (report_body, servtd_hash) = if body_size == QUOTE_V5_BODY_SIZE_15 {
let (report_body, tee_tcb_svn2, servtd_hash) = if body_size == QUOTE_V5_BODY_SIZE_15 {
// v5 with TD Report 1.5 (648 bytes) - includes mr_servicetd
let report_v15 = unsafe {
&*(quote_data[body_offset..body_offset + body_size].as_ptr() as *const SgxReport2BodyV15)
Expand All @@ -445,7 +452,7 @@ fn create_td_report_from_file(quote_file_path: String) -> tdx::TdReport {
rt_mr: report_v15.rt_mr,
report_data: report_v15.report_data,
};
(base_body, report_v15.mr_servicetd)
(base_body, report_v15.tee_tcb_svn2, report_v15.mr_servicetd)
} else {
// v4 or v5 with TD Report 1.0 (584 bytes)
let report = unsafe {
Expand All @@ -468,7 +475,7 @@ fn create_td_report_from_file(quote_file_path: String) -> tdx::TdReport {
rt_mr: report.rt_mr,
report_data: report.report_data,
};
(base_body, [0u8; 48]) // SERVTD_HASH always zero for MigTD
(base_body, [0u8; 16], [0u8; 48]) // SERVTD_HASH always zero for MigTD
};

// Create TD report with values from parsed quote body
Expand All @@ -494,7 +501,8 @@ fn create_td_report_from_file(quote_file_path: String) -> tdx::TdReport {
mrseam: report_body.mr_seam,
mrsigner_seam: report_body.mrsigner_seam,
attributes: report_body.seam_attributes,
reserved: [0u8; 111],
tee_tcb_svn2,
reserved: [0u8; 95],
},
reserved: [0u8; 17],
td_info: TdInfo {
Expand Down
42 changes: 42 additions & 0 deletions deps/td-shim-AzCVMEmu/tdx-tdcall/src/tdx_emu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ lazy_static! {
static ref MSK_FIELDS: Mutex<HashMap<(u64, [u64;4], u64), u64>> = Mutex::new(HashMap::new());
/// Emulated global-scope SYS fields keyed by field_identifier
static ref SYS_FIELDS: Mutex<HashMap<u64, u64>> = Mutex::new(HashMap::new());
/// Emulated td-scope metadata fields keyed by field_identifier
static ref VM_FIELDS: Mutex<HashMap<u64, u64>> = Mutex::new(HashMap::new());
/// Emulated rebind-session-token
static ref REBIND_SESSION_TOKEN: Mutex<HashMap<(u64, [u64; 4]), [u8; 32]>> = Mutex::new(HashMap::new());
/// Event notification vector for GetQuote completion
static ref EVENT_NOTIFY_VECTOR: Mutex<Option<u64>> = Mutex::new(None);
/// Pending receive buffer for large transfers that span multiple GHCI transactions
Expand Down Expand Up @@ -824,6 +828,44 @@ pub fn tdcall_sys_wr(field_identifier: u64, value: u64) -> core::result::Result<
Ok(())
}

/// Emulation for TDG.VM.WR: write a TD-scope metadata field
pub fn tdcall_vm_write(field_identifier: u64, value: u64, mask: u64) -> Result<u64, TdCallError> {
warn!(
"AzCVMEmu: tdcall_vm_write emulated: field=0x{:x} <= 0x{:x}",
field_identifier, value
);
SYS_FIELDS.lock().insert(field_identifier, value);
Ok(field_identifier)
}

/// Emulation for TDG.SERVTD.REBIND.APPROVE: called by the currently bound service TD to approve
/// a new Service TD to be bound to the target TD.
pub fn tdcall_servtd_rebind_approve(
old_binding_handle: u64,
rebind_session_token: &[u8],
target_td_uuid: &[u64],
) -> Result<[u64; 4], TdCallError> {
warn!(
"AzCVMEmu: tdcall_servtd_rebind_approve emulated: old_binding_hanlde=0x{:x} target_td_uuid= 0x{:x?}",
old_binding_handle, target_td_uuid
);
let uuid = [
target_td_uuid[0],
target_td_uuid[1],
target_td_uuid[2],
target_td_uuid[3],
];
let key = (
old_binding_handle,
uuid,
);
let mut value = [0u8; 32];
value.copy_from_slice(&rebind_session_token[..32]);

REBIND_SESSION_TOKEN.lock().insert(key, value);
Ok(uuid)
}

/// Emulation for TDG.VP.VMCALL<GetQuote>: Generate TD-Quote using vTPM or return hardcoded collateral
/// This mimics the exact API signature of tdx_tdcall::tdx::tdvmcall_get_quote
///
Expand Down
25 changes: 24 additions & 1 deletion src/crypto/src/rustls_impl/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ where
pub async fn read(&mut self, data: &mut [u8]) -> Result<usize> {
self.conn.read(data).await
}

pub fn peer_certs(&self) -> Option<Vec<&[u8]>> {
self.conn.peer_certs()
}
}

enum TlsConnection<T: AsyncRead + AsyncWrite + Unpin> {
Expand Down Expand Up @@ -94,6 +98,13 @@ impl<T: AsyncRead + AsyncWrite + Unpin> TlsConnection<T> {
}
}

fn peer_certs(&self) -> Option<Vec<&[u8]>> {
match self {
Self::Server(conn) => conn.peer_certs(),
Self::Client(conn) => conn.peer_certs(),
}
}

fn transport_mut(&mut self) -> &mut T {
match self {
Self::Server(conn) => &mut conn.transport,
Expand Down Expand Up @@ -498,7 +509,7 @@ pub(crate) mod connection {
}

pub struct TlsServerConnection<T: AsyncRead + AsyncWrite + Unpin> {
conn: UnbufferedServerConnection,
pub(super) conn: UnbufferedServerConnection,
input: TlsBuffer,
output: TlsBuffer,
pub transport: T,
Expand All @@ -518,6 +529,12 @@ pub(crate) mod connection {
})
}

pub fn peer_certs(&self) -> Option<Vec<&[u8]>> {
self.conn
.peer_certificates()
.map(|certs| certs.iter().map(|der| der.as_ref()).collect())
}

pub async fn read(&mut self, data: &mut [u8]) -> Result<usize, TlsConnectionError> {
if self.is_handshaking {
self.process_tls_status().await?;
Expand Down Expand Up @@ -776,6 +793,12 @@ pub(crate) mod connection {
})
}

pub fn peer_certs(&self) -> Option<Vec<&[u8]>> {
self.conn
.peer_certificates()
.map(|certs| certs.iter().map(|der| der.as_ref()).collect())
}

pub async fn read(&mut self, data: &mut [u8]) -> Result<usize, TlsConnectionError> {
if self.is_handshaking {
self.process_tls_status().await?;
Expand Down
5 changes: 5 additions & 0 deletions src/migtd/src/bin/migtd/cvmemu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,11 @@ fn handle_pre_mig_emu() -> i32 {
log::trace!(migration_request_id = report_info.mig_request_id; "ReportStatus for get TDREPORT completed.\n");
// Continue to process next request (migration)
}
#[cfg(all(feature = "policy_v2"))]
WaitForRequestResponse::StartRebinding(_)
| WaitForRequestResponse::GetMigtdData(_) => {
unimplemented!();
}
}
}
Err(e) => {
Expand Down
57 changes: 55 additions & 2 deletions src/migtd/src/bin/migtd/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use core::task::Poll;
#[cfg(feature = "policy_v2")]
use alloc::string::String;
use alloc::vec::Vec;
use log::info;
#[cfg(feature = "vmcall-raw")]
use log::{debug, Level};
use log::{info, LevelFilter};
use migtd::event_log::*;
#[cfg(not(feature = "vmcall-raw"))]
use migtd::migration::data::MigrationInformation;
Expand Down Expand Up @@ -101,7 +101,7 @@ pub fn runtime_main() {
{
// Initialize logging with level filter. The actual log level is determined by
// compile-time feature flags.
let _ = td_logger::init(LevelFilter::Trace);
let _ = td_logger::init(log::LevelFilter::Trace);
}

// Create LogArea per vCPU
Expand Down Expand Up @@ -446,6 +446,39 @@ fn handle_pre_mig() {
log::trace!(migration_request_id = wfr_info.mig_info.mig_request_id; "ReportStatus for key exchange completed\n");
REQUESTS.lock().remove(&wfr_info.mig_info.mig_request_id);
}
#[cfg(feature = "policy_v2")]
WaitForRequestResponse::StartRebinding(rebinding_info) => {
use migtd::migration::rebinding::start_rebinding;

let status = start_rebinding(&rebinding_info, &mut data)
.await
.map(|_| MigrationResult::Success)
.unwrap_or_else(|e| e);
if status == MigrationResult::Success {
log::trace!("Successfully completed key exchange\n");
log::trace!(
migration_request_id = rebinding_info.mig_request_id; "Successfully completed rebinding\n",
);
} else {
log::error!(
migration_request_id = rebinding_info.mig_request_id; "Failure during rebinding status code: {:x}\n", status.clone() as u8);
}
let _ =
report_status(status as u8, rebinding_info.mig_request_id, &data)
.await
.map_err(|e| {
log::error!(
migration_request_id = rebinding_info.mig_request_id;
"Failed to report status for StartRebinding: {:?}\n",
e
);
});
log::trace!(
migration_request_id = rebinding_info.mig_request_id;
"ReportStatus for rebinding completed\n"
);
REQUESTS.lock().remove(&rebinding_info.mig_request_id);
}
WaitForRequestResponse::GetTdReport(wfr_info) => {
let status = get_tdreport(
&wfr_info.reportdata,
Expand Down Expand Up @@ -497,6 +530,26 @@ fn handle_pre_mig() {
log::trace!(migration_request_id = wfr_info.mig_request_id; "ReportStatus for Enable LogArea completed\n");
REQUESTS.lock().remove(&wfr_info.mig_request_id);
}
#[cfg(feature = "policy_v2")]
WaitForRequestResponse::GetMigtdData(wfr_info) => {
let status = get_migtd_data(
&wfr_info.reportdata,
&mut data,
wfr_info.mig_request_id,
)
.await
.map(|_| MigrationResult::Success)
.unwrap_or_else(|e| e);
if status == MigrationResult::Success {
log::trace!(migration_request_id = wfr_info.mig_request_id; "Successfully completed get migtd data\n");
} else {
log::error!(migration_request_id = wfr_info.mig_request_id; "Failure during get migtd data status code: {:x}\n", status.clone() as u8);
}
let _ =
report_status(status as u8, wfr_info.mig_request_id, &data).await;
log::trace!(migration_request_id = wfr_info.mig_request_id; "ReportStatus for get migtd data completed.\n");
REQUESTS.lock().remove(&wfr_info.mig_request_id);
}
}
}
#[cfg(any(feature = "test_stack_size", feature = "test_heap_size"))]
Expand Down
26 changes: 14 additions & 12 deletions src/migtd/src/event_log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use cc_measurement::{
};
use core::mem::size_of;
use crypto::hash::digest_sha384;
use policy::{CcEvent, EventName, Report, REPORT_DATA_SIZE};
use policy::{CcEvent, EventName};
use spin::Once;
use td_payload::acpi::get_acpi_tables;
use td_shim::event_log::{
Expand Down Expand Up @@ -218,11 +218,17 @@ pub(crate) fn parse_events(event_log: &[u8]) -> Option<BTreeMap<EventName, CcEve
Some(map)
}

pub fn verify_event_log(event_log: &[u8], report: &[u8]) -> Result<()> {
replay_event_log_with_report(event_log, report)
pub fn verify_event_log(
event_log: &[u8],
report_rtmrs: &[[u8; SHA384_DIGEST_SIZE]; 4],
) -> Result<()> {
replay_event_log_with_report(event_log, report_rtmrs)
}

fn replay_event_log_with_report(event_log: &[u8], report: &[u8]) -> Result<()> {
fn replay_event_log_with_report(
event_log: &[u8],
report_rtmrs: &[[u8; SHA384_DIGEST_SIZE]; 4],
) -> Result<()> {
let mut rtmrs: [[u8; 96]; 4] = [[0; 96]; 4];

let event_log = if let Some(event_log) = CcEventLogReader::new(event_log) {
Expand Down Expand Up @@ -250,14 +256,10 @@ fn replay_event_log_with_report(event_log: &[u8], report: &[u8]) -> Result<()> {
}
}

if report.len() < REPORT_DATA_SIZE {
return Err(anyhow!("Invalid report"));
}

if report[Report::R_MIGTD_RTMR0] == rtmrs[0][0..48]
&& report[Report::R_MIGTD_RTMR1] == rtmrs[1][0..48]
&& report[Report::R_MIGTD_RTMR2] == rtmrs[2][0..48]
&& report[Report::R_MIGTD_RTMR3] == rtmrs[3][0..48]
if report_rtmrs[0] == rtmrs[0][0..48]
&& report_rtmrs[1] == rtmrs[1][0..48]
&& report_rtmrs[2] == rtmrs[2][0..48]
&& report_rtmrs[3] == rtmrs[3][0..48]
{
Ok(())
} else {
Expand Down
Loading
Loading