diff --git a/src/migtd/src/spdm/mod.rs b/src/migtd/src/spdm/mod.rs index e98cee25..75f33956 100644 --- a/src/migtd/src/spdm/mod.rs +++ b/src/migtd/src/spdm/mod.rs @@ -204,6 +204,36 @@ pub fn spdm_verify_quote(#[allow(unused_variables)] quote: &[u8]) -> SpdmResult< }) } +/// Tear down the SPDM session identified by `session_id` (if it still +/// exists) and return `status` unchanged. +/// +/// Use this on every security-relevant error path that runs after key +/// exchange. Without teardown the keyed session lingers in the +/// `SpdmContext`: +/// * On the responder, `rsp_handle_message` only breaks out of its dispatch +/// loop when the session disappears or the handler returns a +/// `StatusCode::VDM(_)` / `SPDM_STATUS_INVALID_STATE_LOCAL` error. Any +/// other `CORE(_)` status (e.g. `INVALID_MSG_FIELD`, `INVALID_MSG_SIZE`, +/// `BUFFER_FULL`, `CRYPTO_ERROR`) is silently swallowed and the loop +/// keeps polling on the *still-keyed* session. +/// * On the requester, the caller typically drops the context on `Err`, but +/// tearing the session down explicitly zeroes the established secrets +/// immediately and matches the responder convention. +/// +/// The function is a no-op if `session_id` no longer maps to a live +/// session (idempotent), so it is safe to call after another teardown or +/// on pre-keying error paths. +fn fail_with_teardown( + ctx: &mut spdmlib::common::SpdmContext, + session_id: u32, + status: SpdmStatus, +) -> SpdmStatus { + if let Some(s) = ctx.get_session_via_id(session_id) { + s.teardown(); + } + status +} + /// Verify that the peer's REPORTDATA is bound to the expected prefix and TH1. pub fn verify_report_data_binding( supplemental_data: &[u8], @@ -225,6 +255,39 @@ pub fn verify_report_data_binding( verify_peer_report_data(supplemental_data, &report_data) } +/// Verify that a TDREPORT's REPORTDATA is bound to the expected prefix and TH1. +/// +/// This is the rebind-path counterpart of [`verify_report_data_binding`], which +/// operates on quote supplemental data. In the rebind flow the peer provides a +/// raw TDREPORT instead of a quote; the REPORTDATA field is accessed via the +/// parsed `TdxReport.report_mac.report_data` struct field. +pub fn verify_tdreport_data_binding( + tdreport_bytes: &[u8], + peer_prefix: &[u8], + th1: &SpdmDigestStruct, +) -> Result<(), MigrationResult> { + use scroll::Pread; + use tdx_tdcall::tdreport::TdxReport; + + const REPORT_DATA_HASH_SIZE: usize = 48; + + let tdreport: TdxReport = tdreport_bytes.pread(0).map_err(|_| { + error!("Failed to parse TDREPORT\n"); + MigrationResult::InvalidParameter + })?; + + let expected_report_data = + build_report_data(peer_prefix, th1).map_err(|_| MigrationResult::InvalidParameter)?; + let expected_hash = digest_sha384(&expected_report_data)?; + let actual = &tdreport.report_mac.report_data[..REPORT_DATA_HASH_SIZE]; + + if actual != expected_hash.as_slice() { + return Err(MigrationResult::InvalidParameter); + } + + Ok(()) +} + const ECDSA_P384_SHA384_PRIVATE_KEY_LENGTH: usize = 0xb9; #[derive(Debug, Clone, Zeroize, ZeroizeOnDrop, Eq, PartialEq)] diff --git a/src/migtd/src/spdm/spdm_req.rs b/src/migtd/src/spdm/spdm_req.rs index 37b61017..e1dbb18f 100644 --- a/src/migtd/src/spdm/spdm_req.rs +++ b/src/migtd/src/spdm/spdm_req.rs @@ -11,8 +11,9 @@ use crate::{ MigtdMigrationInformation, }, spdm::{ - build_report_data, gen_quote_spdm, spdm_rsp::SECRET_ASYM_IMPL_INSTANCE, spdm_verify_quote, - verify_report_data_binding, vmcall_msg::VmCallTransportEncap, *, + build_report_data, fail_with_teardown, gen_quote_spdm, spdm_rsp::SECRET_ASYM_IMPL_INSTANCE, + spdm_verify_quote, verify_report_data_binding, verify_tdreport_data_binding, + vmcall_msg::VmCallTransportEncap, *, }, }; use async_io::{AsyncRead, AsyncWrite}; @@ -306,7 +307,11 @@ pub async fn send_and_receive_sdm_migration_attest_info( || spdm_requester.common.provision_info.peer_pub_key.is_none() { error!("Cannot transfer attestation info without provisioning my_pub_key.\n"); - return Err(SPDM_STATUS_UNSUPPORTED_CAP); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_UNSUPPORTED_CAP, + )); } let mut vendor_id = [0u8; MAX_SPDM_VENDOR_DEFINED_VENDOR_ID_LEN]; @@ -324,9 +329,13 @@ pub async fn send_and_receive_sdm_migration_attest_info( element_count: VDM_MESSAGE_EXCHANGE_MIGRATION_ATTEST_INFO_REQ_ELEMENT_COUNT, }; - cnt += vdm_exchange_attest_info - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += vdm_exchange_attest_info.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; let th1 = if let Some(s) = spdm_requester.common.get_session_via_id(session_id) { s.get_th1() @@ -335,7 +344,8 @@ pub async fn send_and_receive_sdm_migration_attest_info( return Err(SPDM_STATUS_INVALID_STATE_LOCAL); }; - let report_data = build_report_data(b"MigTDReq", &th1)?; + let report_data = build_report_data(b"MigTDReq", &th1) + .map_err(|e| fail_with_teardown(&mut spdm_requester.common, session_id, e))?; //quote src let quote_src = gen_quote_spdm(&report_data)?; @@ -347,12 +357,11 @@ pub async fn send_and_receive_sdm_migration_attest_info( let res = spdm_verify_quote(quote_src.as_slice()); if res.is_err() { error!("mutual attestation failed, end the session!\n"); - let session = spdm_requester - .common - .get_session_via_id(session_id) - .ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; - session.teardown(); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } res.unwrap() }; @@ -362,12 +371,22 @@ pub async fn send_and_receive_sdm_migration_attest_info( element_type: VdmMessageElementType::QuoteMy, length: quote_src.len() as u32, }; - cnt += quote_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += quote_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; cnt += writer .extend_from_slice(quote_src.as_slice()) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + .ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; //event log src let event_log_src = get_event_log().ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; @@ -375,35 +394,65 @@ pub async fn send_and_receive_sdm_migration_attest_info( element_type: VdmMessageElementType::EventLogMy, length: event_log_src.len() as u32, }; - cnt += event_log_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; - cnt += writer - .extend_from_slice(event_log_src) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + cnt += event_log_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; + cnt += writer.extend_from_slice(event_log_src).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; //mig policy src #[cfg(feature = "policy_v2")] let mig_policy_src_hash = { let blob = local_peer_data().ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; - digest_sha384(&blob).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)? + digest_sha384(&blob).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_CRYPTO_ERROR, + ) + })? }; #[cfg(not(feature = "policy_v2"))] let mig_policy_src_hash = { let mig_policy_src = crate::config::get_policy().ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; - digest_sha384(mig_policy_src).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)? + digest_sha384(mig_policy_src).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_CRYPTO_ERROR, + ) + })? }; let mig_policy_element = VdmMessageElement { element_type: VdmMessageElementType::MigPolicyMy, length: mig_policy_src_hash.len() as u32, }; - cnt += mig_policy_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += mig_policy_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; cnt += writer .extend_from_slice(&mig_policy_src_hash) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + .ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; // SERVTD_EXT: read from target TD via TDG.SERVTD.RD and send to peer { @@ -415,12 +464,22 @@ pub async fn send_and_receive_sdm_migration_attest_info( element_type: VdmMessageElementType::SerVtdExt, length: servtd_ext.as_bytes().len() as u32, }; - cnt += servtd_ext_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += servtd_ext_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; cnt += writer .extend_from_slice(servtd_ext.as_bytes()) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + .ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; } // Init TDINFO: use VMM-provided initMigtdData if available, otherwise local @@ -448,12 +507,20 @@ pub async fn send_and_receive_sdm_migration_attest_info( element_type: VdmMessageElementType::TdReportInit, length: tdinfo_init.len() as u32, }; - cnt += tdinfo_init_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; - cnt += writer - .extend_from_slice(tdinfo_init) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + cnt += tdinfo_init_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; + cnt += writer.extend_from_slice(tdinfo_init).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; } spdm_requester.common.reset_buffer_via_request_code( @@ -474,10 +541,16 @@ pub async fn send_and_receive_sdm_migration_attest_info( req_payload: payload, }; let mut send_used = 0; - send_used += request_header - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; - send_used += request_payload.spdm_encode(&mut spdm_requester.common, &mut writer)?; + send_used += request_header.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; + send_used += request_payload + .spdm_encode(&mut spdm_requester.common, &mut writer) + .map_err(|e| fail_with_teardown(&mut spdm_requester.common, session_id, e))?; let mut receive_buffer = [0u8; config::MAX_SPDM_MSG_SIZE]; let response = spdm_requester @@ -486,85 +559,162 @@ pub async fn send_and_receive_sdm_migration_attest_info( &send_buffer[..send_used], &mut receive_buffer, ) - .await?; + .await + .map_err(|e| fail_with_teardown(&mut spdm_requester.common, session_id, e))?; //Format checks let mut reader = Reader::init(response); - let _response_header = - SpdmMessageHeader::read(&mut reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let _response_header = SpdmMessageHeader::read(&mut reader).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; let response_payload = - SpdmVdmResponsePayload::spdm_read(&mut spdm_requester.common, &mut reader) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + SpdmVdmResponsePayload::spdm_read(&mut spdm_requester.common, &mut reader).ok_or_else( + || { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + }, + )?; let reader = &mut Reader::init(&response_payload.rsp_payload[..response_payload.rsp_length as usize]); - let vdm_message = VdmMessage::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_message = VdmMessage::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_message.major_version != VDM_MESSAGE_MAJOR_VERSION { error!( "Invalid VDM message major_version: {:x?}\n", vdm_message.major_version ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_message.minor_version != VDM_MESSAGE_MINOR_VERSION { error!( "Invalid VDM message minor_version: {:x?}\n", vdm_message.minor_version ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_message.op_code != VdmMessageOpCode::ExchangeMigrationAttestInfoRsp { error!("Invalid VDM message op_code: {:x?}\n", vdm_message.op_code); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_message.element_count != VDM_MESSAGE_EXCHANGE_MIGRATION_ATTEST_INFO_RSP_ELEMENT_COUNT { error!( "Invalid VDM message element_count: {:x?}\n", vdm_message.element_count ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } //quote dst - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::QuoteMy { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let quote_dst = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let quote_dst = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; let quote_dst_vec = quote_dst.to_vec(); //event log dst - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::EventLogMy { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let event_log_dst = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let event_log_dst = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; let event_log_dst_vec = event_log_dst.to_vec(); //mig policy dst - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::MigPolicyMy { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } #[cfg(feature = "policy_v2")] - let mig_policy_hash_dst = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let mig_policy_hash_dst = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; #[cfg(not(feature = "policy_v2"))] let _mig_policy_hash_dst = reader .take(vdm_element.length as usize) @@ -592,16 +742,39 @@ pub async fn send_and_receive_sdm_migration_attest_info( session_id, )?; - let vdm_attest_info_src_hash = - digest_sha384(&send_buffer[..send_used]).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)?; - let vdm_attest_info_dst_hash = digest_sha384(response).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)?; + let vdm_attest_info_src_hash = digest_sha384(&send_buffer[..send_used]).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_CRYPTO_ERROR, + ) + })?; + let vdm_attest_info_dst_hash = digest_sha384(response).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_CRYPTO_ERROR, + ) + })?; let mut transcript_before_finish = ManagedVdmBuffer::default(); transcript_before_finish .append_message(vdm_attest_info_src_hash.as_slice()) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + .ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; transcript_before_finish .append_message(vdm_attest_info_dst_hash.as_slice()) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + .ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; if let Some(s) = spdm_requester.common.get_session_via_id(session_id) { s.runtime_info.vdm_message_transcript_before_finish = Some(transcript_before_finish); } else { @@ -682,10 +855,20 @@ fn verify_peer_attestation_v2( session_id: u32, ) -> SpdmResult { // 1. Verify peer-data hash matches the value bound in the certificate - let peer_data_hash = digest_sha384(peer_data).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)?; + let peer_data_hash = digest_sha384(peer_data).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_CRYPTO_ERROR, + ) + })?; if mig_policy_hash_peer != peer_data_hash.as_slice() { error!("The received mig policy hash does not match the expected peer_data hash!\n"); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } // 2. Authenticate remote (includes quote verification internally) @@ -696,12 +879,11 @@ fn verify_peer_attestation_v2( if let Err(e) = &policy_check_result { error!("Policy v2 check failed, below is the detail information:\n"); error!("{:x?}\n", e); - let session = spdm_requester - .common - .get_session_via_id(session_id) - .ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; - session.teardown(); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } // 3. Verify REPORTDATA binding using supplemental data from authenticate_remote @@ -714,12 +896,11 @@ fn verify_peer_attestation_v2( let verified_report_peer = policy_check_result.unwrap(); if verify_report_data_binding(&verified_report_peer, b"MigTDRsp", th1).is_err() { error!("Peer REPORTDATA does not match expected TH1 binding!\n"); - let session = spdm_requester - .common - .get_session_via_id(session_id) - .ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; - session.teardown(); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } } } @@ -919,7 +1100,11 @@ pub async fn send_and_receive_sdm_rebind_attest_info( || spdm_requester.common.provision_info.peer_pub_key.is_none() { error!("Cannot transfer attestation info without provisioning my_pub_key.\n"); - return Err(SPDM_STATUS_UNSUPPORTED_CAP); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_UNSUPPORTED_CAP, + )); } let mut vendor_id = [0u8; MAX_SPDM_VENDOR_DEFINED_VENDOR_ID_LEN]; @@ -937,9 +1122,13 @@ pub async fn send_and_receive_sdm_rebind_attest_info( element_count: VDM_MESSAGE_EXCHANGE_REBIND_ATTEST_INFO_REQ_WITH_HISTORY_INFO_ELEMENT_COUNT, }; - cnt += vdm_exchange_attest_info - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += vdm_exchange_attest_info.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; let th1 = if let Some(s) = spdm_requester.common.get_session_via_id(session_id) { s.get_th1() @@ -955,7 +1144,11 @@ pub async fn send_and_receive_sdm_rebind_attest_info( // th1 for SHA-384 should be 48 bytes; 8 (prefix) + 48 digest = 56 bytes needed. if th1_len > SPDM_MAX_HASH_SIZE { error!("th1 length is too large: {}\n", th1_len); - return Err(SPDM_STATUS_BUFFER_FULL); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + )); } let mut report_data = [0u8; "MigTDReq".len() + SPDM_MAX_HASH_SIZE]; // Copy prefix @@ -971,12 +1164,22 @@ pub async fn send_and_receive_sdm_rebind_attest_info( element_type: VdmMessageElementType::TdReportMy, length: td_report_src_bytes.len() as u32, }; - cnt += tdreport_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += tdreport_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; cnt += writer .extend_from_slice(td_report_src_bytes) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + .ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; //event log src let event_log_src = get_event_log().ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; @@ -984,29 +1187,53 @@ pub async fn send_and_receive_sdm_rebind_attest_info( element_type: VdmMessageElementType::EventLogMy, length: event_log_src.len() as u32, }; - cnt += event_log_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; - cnt += writer - .extend_from_slice(event_log_src) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + cnt += event_log_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; + cnt += writer.extend_from_slice(event_log_src).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; //mig policy src let mig_policy_src_hash = { let blob = local_peer_data().ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; - digest_sha384(&blob).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)? + digest_sha384(&blob).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_CRYPTO_ERROR, + ) + })? }; let mig_policy_element = VdmMessageElement { element_type: VdmMessageElementType::MigPolicyMy, length: mig_policy_src_hash.len() as u32, }; - cnt += mig_policy_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += mig_policy_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; cnt += writer .extend_from_slice(&mig_policy_src_hash) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + .ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; //SERVTD_EXT let binding_handle = rebind_info.binding_handle; @@ -1022,12 +1249,22 @@ pub async fn send_and_receive_sdm_rebind_attest_info( element_type: VdmMessageElementType::SerVtdExt, length: servtd_ext.as_bytes().len() as u32, }; - cnt += servtd_ext_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += servtd_ext_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; cnt += writer .extend_from_slice(servtd_ext.as_bytes()) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + .ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; //TD info init (per GHCI 1.5: MIGTD_DATA type 0 = TDINFO_STRUCT) // NOTE: VdmMessageElementType::TdReportInit name retained for wire compatibility; @@ -1037,12 +1274,20 @@ pub async fn send_and_receive_sdm_rebind_attest_info( element_type: VdmMessageElementType::TdReportInit, length: tdinfo_init.len() as u32, }; - cnt += tdreport_init_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; - cnt += writer - .extend_from_slice(tdinfo_init) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + cnt += tdreport_init_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; + cnt += writer.extend_from_slice(tdinfo_init).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; //mig policy init hash // Per GHCI 1.5: policy_key is in tdinfo.mrowner; sent as init_policy_hash. @@ -1052,12 +1297,22 @@ pub async fn send_and_receive_sdm_rebind_attest_info( element_type: VdmMessageElementType::MigPolicyInit, length: mig_policy_init_hash.len() as u32, }; - cnt += mig_policy_init_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += mig_policy_init_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; cnt += writer .extend_from_slice(&mig_policy_init_hash) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + .ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; spdm_requester.common.reset_buffer_via_request_code( SpdmRequestResponseCode::SpdmRequestVendorDefinedRequest, @@ -1077,10 +1332,16 @@ pub async fn send_and_receive_sdm_rebind_attest_info( req_payload: payload, }; let mut send_used = 0; - send_used += request_header - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; - send_used += request_payload.spdm_encode(&mut spdm_requester.common, &mut writer)?; + send_used += request_header.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; + send_used += request_payload + .spdm_encode(&mut spdm_requester.common, &mut writer) + .map_err(|e| fail_with_teardown(&mut spdm_requester.common, session_id, e))?; let mut receive_buffer = [0u8; config::MAX_SPDM_MSG_SIZE]; let response = spdm_requester @@ -1089,92 +1350,179 @@ pub async fn send_and_receive_sdm_rebind_attest_info( &send_buffer[..send_used], &mut receive_buffer, ) - .await?; + .await + .map_err(|e| fail_with_teardown(&mut spdm_requester.common, session_id, e))?; //Format checks let mut reader = Reader::init(response); - let _response_header = - SpdmMessageHeader::read(&mut reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let _response_header = SpdmMessageHeader::read(&mut reader).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; let response_payload = - SpdmVdmResponsePayload::spdm_read(&mut spdm_requester.common, &mut reader) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + SpdmVdmResponsePayload::spdm_read(&mut spdm_requester.common, &mut reader).ok_or_else( + || { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + }, + )?; let reader = &mut Reader::init(&response_payload.rsp_payload[..response_payload.rsp_length as usize]); - let vdm_message = VdmMessage::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_message = VdmMessage::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_message.major_version != VDM_MESSAGE_MAJOR_VERSION { error!( "Invalid VDM message major_version: {:x?}\n", vdm_message.major_version ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_message.minor_version != VDM_MESSAGE_MINOR_VERSION { error!( "Invalid VDM message minor_version: {:x?}\n", vdm_message.minor_version ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_message.op_code != VdmMessageOpCode::ExchangeRebindAttestInfoRsp { error!("Invalid VDM message op_code: {:x?}\n", vdm_message.op_code); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_message.element_count != VDM_MESSAGE_EXCHANGE_REBIND_ATTEST_INFO_RSP_ELEMENT_COUNT { error!( "Invalid VDM message element_count: {:x?}\n", vdm_message.element_count ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } //td report dst - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::TdReportMy { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let td_report_dst = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let td_report_dst = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; let td_report_dst_vec = td_report_dst.to_vec(); //event log dst - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::EventLogMy { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let event_log_dst = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let event_log_dst = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; let event_log_dst_vec = event_log_dst.to_vec(); //mig policy dst - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::MigPolicyMy { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let mig_policy_hash_dst = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let mig_policy_hash_dst = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; #[cfg(not(feature = "test_disable_ra_and_accept_all"))] { - let peer_data_hash = digest_sha384(&peer_data).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)?; + let peer_data_hash = digest_sha384(&peer_data).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_CRYPTO_ERROR, + ) + })?; if mig_policy_hash_dst != peer_data_hash.as_slice() { error!("The received mig policy hash does not match the expected peer_data hash!\n"); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } let policy_check_result = mig_policy::authenticate_rebinding_new( @@ -1186,25 +1534,58 @@ pub async fn send_and_receive_sdm_rebind_attest_info( if let Err(e) = &policy_check_result { error!("Policy v2 check failed, below is the detail information:\n"); error!("{:x?}\n", e); - let session = spdm_requester - .common - .get_session_via_id(session_id) - .ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; - session.teardown(); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); + } + + // Verify that the peer's REPORTDATA is bound to this SPDM session's TH1 + let verified_report_peer = policy_check_result.unwrap(); + if verify_tdreport_data_binding(&verified_report_peer, b"MigTDRsp", &th1).is_err() { + error!("Rebind peer REPORTDATA does not match expected TH1 binding!\n"); + return Err(fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } } - let vdm_attest_info_src_hash = - digest_sha384(&send_buffer[..send_used]).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)?; - let vdm_attest_info_dst_hash = digest_sha384(response).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)?; + let vdm_attest_info_src_hash = digest_sha384(&send_buffer[..send_used]).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_CRYPTO_ERROR, + ) + })?; + let vdm_attest_info_dst_hash = digest_sha384(response).map_err(|_| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_CRYPTO_ERROR, + ) + })?; let mut transcript_before_finish = ManagedVdmBuffer::default(); transcript_before_finish .append_message(vdm_attest_info_src_hash.as_slice()) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + .ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; transcript_before_finish .append_message(vdm_attest_info_dst_hash.as_slice()) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + .ok_or_else(|| { + fail_with_teardown( + &mut spdm_requester.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; if let Some(s) = spdm_requester.common.get_session_via_id(session_id) { s.runtime_info.vdm_message_transcript_before_finish = Some(transcript_before_finish); } else { @@ -1245,6 +1626,7 @@ pub async fn send_and_receive_sdm_rebind_info( element_count: VDM_MESSAGE_EXCHANGE_REBIND_INFO_ELEMENT_REQ_COUNT, }; + // Pre-keying buffer encode errors do not need session teardown. cnt += vdm_exchange_migration_info .encode(&mut writer) .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; @@ -1283,7 +1665,18 @@ pub async fn send_and_receive_sdm_rebind_info( send_used += request_header .encode(&mut writer) .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; - send_used += request_payload.spdm_encode(&mut spdm_requester.common, &mut writer)?; + // The send/receive path below operates on the keyed SPDM session, so any + // post-keying error must tear down the session. Resolve a teardown + // session_id once; if no session_id was provided, fall back to the + // SPDM_STATUS_* unchanged (the helper is a no-op when the id is absent). + let teardown_sid = session_id; + let teardown = |ctx: &mut spdmlib::common::SpdmContext, status| match teardown_sid { + Some(sid) => fail_with_teardown(ctx, sid, status), + None => status, + }; + send_used += request_payload + .spdm_encode(&mut spdm_requester.common, &mut writer) + .map_err(|e| teardown(&mut spdm_requester.common, e))?; let mut receive_buffer = [0u8; config::MAX_SPDM_MSG_SIZE]; let response = spdm_requester @@ -1292,46 +1685,61 @@ pub async fn send_and_receive_sdm_rebind_info( &send_buffer[..send_used], &mut receive_buffer, ) - .await?; + .await + .map_err(|e| teardown(&mut spdm_requester.common, e))?; // Format checks let mut reader = Reader::init(response); - let _response_header = - SpdmMessageHeader::read(&mut reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let _response_header = SpdmMessageHeader::read(&mut reader) + .ok_or_else(|| teardown(&mut spdm_requester.common, SPDM_STATUS_INVALID_MSG_SIZE))?; let response_payload = SpdmVdmResponsePayload::spdm_read(&mut spdm_requester.common, &mut reader) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + .ok_or_else(|| teardown(&mut spdm_requester.common, SPDM_STATUS_INVALID_MSG_SIZE))?; let reader = &mut Reader::init(&response_payload.rsp_payload[..response_payload.rsp_length as usize]); - let vdm_message = VdmMessage::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_message = VdmMessage::read(reader) + .ok_or_else(|| teardown(&mut spdm_requester.common, SPDM_STATUS_INVALID_MSG_SIZE))?; if vdm_message.major_version != VDM_MESSAGE_MAJOR_VERSION { error!( "Invalid VDM message major_version: {:x?}\n", vdm_message.major_version ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(teardown( + &mut spdm_requester.common, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_message.minor_version != VDM_MESSAGE_MINOR_VERSION { error!( "Invalid VDM message minor_version: {:x?}\n", vdm_message.minor_version ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(teardown( + &mut spdm_requester.common, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_message.op_code != VdmMessageOpCode::ExchangeRebindInfoRsp { error!("Invalid VDM message op_code: {:x?}\n", vdm_message.op_code); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(teardown( + &mut spdm_requester.common, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_message.element_count != VDM_MESSAGE_EXCHANGE_REBIND_INFO_ELEMENT_RSP_COUNT { error!( "Invalid VDM message element_count: {:x?}\n", vdm_message.element_count ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(teardown( + &mut spdm_requester.common, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - approve_rebinding(rebind_info, &rebind_token).map_err(|_| SPDM_STATUS_INVALID_STATE_LOCAL)?; + approve_rebinding(rebind_info, &rebind_token) + .map_err(|_| teardown(&mut spdm_requester.common, SPDM_STATUS_INVALID_STATE_LOCAL))?; Ok(()) } diff --git a/src/migtd/src/spdm/spdm_rsp.rs b/src/migtd/src/spdm/spdm_rsp.rs index dab15076..4b83f5e8 100644 --- a/src/migtd/src/spdm/spdm_rsp.rs +++ b/src/migtd/src/spdm/spdm_rsp.rs @@ -31,8 +31,8 @@ use crypto::{ecdsa::EcdsaPk, hash::digest_sha384}; use log::error; use crate::spdm::{ - build_report_data, gen_quote_spdm, spdm_verify_quote, verify_report_data_binding, - vmcall_msg::VmCallTransportEncap, *, + build_report_data, fail_with_teardown, gen_quote_spdm, spdm_verify_quote, + verify_report_data_binding, verify_tdreport_data_binding, vmcall_msg::VmCallTransportEncap, *, }; use spdmlib::{ common::{self, *}, @@ -381,6 +381,7 @@ pub fn handle_exchange_mig_attest_info_req( .is_some() { error!("Attestation info has already been exchanged.\n"); + session.teardown(); return Err(SPDM_STATUS_INVALID_STATE_LOCAL); } @@ -392,7 +393,11 @@ pub fn handle_exchange_mig_attest_info_req( .is_none() { error!("Cannot transfer attestation info without provisioning pub_key.\n"); - return Err(SPDM_STATUS_UNSUPPORTED_CAP); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_UNSUPPORTED_CAP, + )); } if vdm_request.major_version != VDM_MESSAGE_MAJOR_VERSION { @@ -400,25 +405,41 @@ pub fn handle_exchange_mig_attest_info_req( "Invalid VDM message major_version: {:x?}\n", vdm_request.major_version ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_request.minor_version != VDM_MESSAGE_MINOR_VERSION { error!( "Invalid VDM message minor_version: {:x?}\n", vdm_request.minor_version ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_request.op_code != VdmMessageOpCode::ExchangeMigrationAttestInfoReq { error!("Invalid VDM message op_code: {:x?}\n", vdm_request.op_code); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_request.element_count != VDM_MESSAGE_EXCHANGE_MIGRATION_ATTEST_INFO_REQ_ELEMENT_COUNT { error!( "Invalid VDM message element_count: {:x?}\n", vdm_request.element_count ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } let th1 = if let Some(s) = responder_context.common.get_session_via_id(session_id) { @@ -428,7 +449,8 @@ pub fn handle_exchange_mig_attest_info_req( return Err(SPDM_STATUS_INVALID_STATE_LOCAL); }; - let report_data = build_report_data(b"MigTDRsp", &th1)?; + let report_data = build_report_data(b"MigTDRsp", &th1) + .map_err(|e| fail_with_teardown(&mut responder_context.common, session_id, e))?; //quote dst let quote_dst = gen_quote_spdm(&report_data)?; @@ -451,46 +473,90 @@ pub fn handle_exchange_mig_attest_info_req( }; //quote src - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::QuoteMy { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let quote_src = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let quote_src = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; let quote_src_vec = quote_src.to_vec(); //event log src - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::EventLogMy { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let event_log_src = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let event_log_src = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; let event_log_src_vec = event_log_src.to_vec(); //mig policy src - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::MigPolicyMy { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } #[cfg(feature = "policy_v2")] let mig_policy_hash_src = reader .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)? + .ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })? .to_vec(); #[cfg(not(feature = "policy_v2"))] let _mig_policy_hash_src = reader @@ -498,17 +564,31 @@ pub fn handle_exchange_mig_attest_info_req( .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; // SERVTD_EXT from src - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::SerVtdExt { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let servtd_ext_bytes = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let servtd_ext_bytes = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; // Store SERVTD_EXT in ResponderContextEx for later use during MSK exchange #[cfg(feature = "policy_v2")] @@ -526,17 +606,31 @@ pub fn handle_exchange_mig_attest_info_req( }; // Init TDINFO from src (used for SERVTD_HASH verification) - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::TdReportInit { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let _td_report_init = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let _td_report_init = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; // Policy-specific verification #[cfg(not(feature = "policy_v2"))] @@ -576,21 +670,35 @@ pub fn handle_exchange_mig_attest_info_req( element_count: VDM_MESSAGE_EXCHANGE_MIGRATION_ATTEST_INFO_RSP_ELEMENT_COUNT, }; - cnt += vdm_exchange_attest_info - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += vdm_exchange_attest_info.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; //quote dst let quote_element = VdmMessageElement { element_type: VdmMessageElementType::QuoteMy, length: quote_dst.len() as u32, }; - cnt += quote_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += quote_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; cnt += writer .extend_from_slice(quote_dst.as_slice()) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + .ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; //event log dst let event_log_dst = get_event_log().ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; @@ -598,34 +706,64 @@ pub fn handle_exchange_mig_attest_info_req( element_type: VdmMessageElementType::EventLogMy, length: event_log_dst.len() as u32, }; - cnt += event_log_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; - cnt += writer - .extend_from_slice(event_log_dst) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + cnt += event_log_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; + cnt += writer.extend_from_slice(event_log_dst).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; //mig policy dst #[cfg(feature = "policy_v2")] let mig_policy_dst_hash = { let blob = local_peer_data().ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; - digest_sha384(&blob).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)? + digest_sha384(&blob).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_CRYPTO_ERROR, + ) + })? }; #[cfg(not(feature = "policy_v2"))] let mig_policy_dst_hash = { let mig_policy_dst = crate::config::get_policy().ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; - digest_sha384(mig_policy_dst).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)? + digest_sha384(mig_policy_dst).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_CRYPTO_ERROR, + ) + })? }; let mig_policy_element = VdmMessageElement { element_type: VdmMessageElementType::MigPolicyMy, length: mig_policy_dst_hash.len() as u32, }; - cnt += mig_policy_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += mig_policy_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; cnt += writer .extend_from_slice(&mig_policy_dst_hash) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + .ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; Ok(cnt) } @@ -700,10 +838,20 @@ fn rsp_verify_peer_attestation_v2( session_id: u32, ) -> SpdmResult { // 1. Verify peer-data hash matches the value bound in the certificate - let peer_data_hash = digest_sha384(peer_data).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)?; + let peer_data_hash = digest_sha384(peer_data).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_CRYPTO_ERROR, + ) + })?; if mig_policy_hash_peer != peer_data_hash.as_slice() { error!("The received mig policy hash does not match the expected peer_data hash!\n"); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } // 2. Authenticate remote (includes quote verification internally) @@ -714,12 +862,11 @@ fn rsp_verify_peer_attestation_v2( if let Err(e) = &policy_check_result { error!("Policy v2 check failed, below is the detail information:\n"); error!("{:x?}\n", e); - let session = responder_context - .common - .get_session_via_id(session_id) - .ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; - session.teardown(); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } // 3. Verify REPORTDATA binding using supplemental data from authenticate_remote @@ -732,12 +879,11 @@ fn rsp_verify_peer_attestation_v2( let verified_report_peer = policy_check_result.unwrap(); if verify_report_data_binding(&verified_report_peer, b"MigTDReq", th1).is_err() { error!("Peer REPORTDATA does not match expected TH1 binding!\n"); - let session = responder_context - .common - .get_session_via_id(session_id) - .ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; - session.teardown(); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } } } @@ -780,59 +926,116 @@ pub fn handle_exchange_mig_info_req( "Invalid VDM message major_version: {:x?}\n", vdm_request.major_version ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_request.minor_version != VDM_MESSAGE_MINOR_VERSION { error!( "Invalid VDM message minor_version: {:x?}\n", vdm_request.minor_version ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_request.op_code != VdmMessageOpCode::ExchangeMigrationInfoReq { error!("Invalid VDM message op_code: {:x?}\n", vdm_request.op_code); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_request.element_count != VDM_MESSAGE_EXCHANGE_MIGRATION_INFO_REQ_ELEMENT_COUNT { error!( "Invalid VDM message element_count: {:x?}\n", vdm_request.element_count ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let mig_export_version_element = - VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let mig_export_version_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if mig_export_version_element.element_type != VdmMessageElementType::MigrationExportVersion || mig_export_version_element.length != VDM_MESSAGE_MIGRATION_EXPORT_VERSION_SIZE { error!("invalid migration info payload!\n"); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let min_export_version = u16::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; - let max_export_version = u16::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let min_export_version = u16::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; + let max_export_version = u16::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; - let forward_mig_session_key_element = - VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let forward_mig_session_key_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if forward_mig_session_key_element.element_type != VdmMessageElementType::ForwardMigrationSessionKey || forward_mig_session_key_element.length != VDM_MESSAGE_FORWARD_MIGRATION_SESSION_KEY_SIZE { error!("invalid forward migration session key!\n"); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } let remote_information = ExchangeInformation { min_ver: min_export_version, max_ver: max_export_version, key: MigrationSessionKey { - fields: <[u64; 4]>::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?, + fields: <[u64; 4]>::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?, }, }; let mut reader = Reader::init(responder_context.common.app_context_data_buffer.as_ref()); - let responder_app_context = - SpdmAppContextData::read(&mut reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let responder_app_context = SpdmAppContextData::read(&mut reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; let exchange_information = exchange_info(&responder_app_context.migration_info, false)?; verify_servtd_attr( @@ -873,9 +1076,13 @@ pub fn handle_exchange_mig_info_req( op_code: VdmMessageOpCode::ExchangeMigrationInfoRsp, element_count: VDM_MESSAGE_EXCHANGE_MIGRATION_INFO_RSP_ELEMENT_COUNT, }; - cnt += vdm_exchange_mig_info - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += vdm_exchange_mig_info.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; //Migration Import Version let mig_import_version_element = VdmMessageElement { @@ -884,13 +1091,27 @@ pub fn handle_exchange_mig_info_req( }; cnt += mig_import_version_element .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; - cnt += min_import_version - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; - cnt += max_import_version - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + .map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; + cnt += min_import_version.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; + cnt += max_import_version.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; //Backward Migration Session Key let backward_mig_session_key_element = VdmMessageElement { @@ -899,10 +1120,20 @@ pub fn handle_exchange_mig_info_req( }; cnt += backward_mig_session_key_element .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; - cnt += writer - .extend_from_slice(&mig_session_key) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + .map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; + cnt += writer.extend_from_slice(&mig_session_key).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; Ok(cnt) } @@ -947,6 +1178,7 @@ pub fn handle_exchange_rebind_attest_info_req( .is_some() { error!("Attestation info has already been exchanged.\n"); + session.teardown(); return Err(SPDM_STATUS_INVALID_STATE_LOCAL); } @@ -958,7 +1190,11 @@ pub fn handle_exchange_rebind_attest_info_req( .is_none() { error!("Cannot transfer attestation info without provisioning pub_key.\n"); - return Err(SPDM_STATUS_UNSUPPORTED_CAP); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_UNSUPPORTED_CAP, + )); } if vdm_request.major_version != VDM_MESSAGE_MAJOR_VERSION { @@ -966,18 +1202,30 @@ pub fn handle_exchange_rebind_attest_info_req( "Invalid VDM message major_version: {:x?}\n", vdm_request.major_version ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_request.minor_version != VDM_MESSAGE_MINOR_VERSION { error!( "Invalid VDM message minor_version: {:x?}\n", vdm_request.minor_version ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_request.op_code != VdmMessageOpCode::ExchangeRebindAttestInfoReq { error!("Invalid VDM message op_code: {:x?}\n", vdm_request.op_code); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_request.element_count != VDM_MESSAGE_EXCHANGE_REBIND_ATTEST_INFO_REQ_WITH_HISTORY_INFO_ELEMENT_COUNT @@ -986,7 +1234,11 @@ pub fn handle_exchange_rebind_attest_info_req( "Invalid VDM message element_count: {:x?}\n", vdm_request.element_count ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } let th1 = if let Some(s) = responder_context.common.get_session_via_id(session_id) { @@ -1003,7 +1255,11 @@ pub fn handle_exchange_rebind_attest_info_req( // th1 for SHA-384 should be 48 bytes; 8 (prefix) + 48 digest = 56 bytes needed. if th1_len > SPDM_MAX_HASH_SIZE { error!("th1 length is too large: {}\n", th1_len); - return Err(SPDM_STATUS_BUFFER_FULL); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + )); } let mut report_data = [0u8; "MigTDRsp".len() + SPDM_MAX_HASH_SIZE]; // Copy prefix @@ -1012,127 +1268,239 @@ pub fn handle_exchange_rebind_attest_info_req( .copy_from_slice(&th1.data[..th1_len]); //TD report src - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::TdReportMy { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let td_report_src = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let td_report_src = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; let td_report_src_vec = td_report_src.to_vec(); //event log src - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::EventLogMy { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let event_log_src = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let event_log_src = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; let event_log_src_vec = event_log_src.to_vec(); //mig policy src - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::MigPolicyMy { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let mig_policy_hash_src = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let mig_policy_hash_src = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; let mig_policy_hash_src_vec = mig_policy_hash_src.to_vec(); // SERVTD_EXT - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::SerVtdExt { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); }; - let servtd_ext = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let servtd_ext = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; let servtd_ext_vec = servtd_ext.to_vec(); // TD report init - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::TdReportInit { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); }; - let td_report_init = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let td_report_init = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; let td_report_init_vec = td_report_init.to_vec(); // mig policy init hash - let vdm_element = VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let vdm_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if vdm_element.element_type != VdmMessageElementType::MigPolicyInit { error!( "Invalid VDM message element_type: {:x?}\n", vdm_element.element_type ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); }; - let mig_policy_init_hash_src = reader - .take(vdm_element.length as usize) - .ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let mig_policy_init_hash_src = reader.take(vdm_element.length as usize).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; // attestation verification #[cfg(not(feature = "test_disable_ra_and_accept_all"))] { - let peer_data = unsafe { + let peer_data: Vec = unsafe { let spdm_responder_ex = upcast_mut(responder_context); - spdm_responder_ex.peer_data.as_slice() + spdm_responder_ex.peer_data.as_slice().to_vec() }; - let peer_data_hash = digest_sha384(peer_data).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)?; + let peer_data_hash = digest_sha384(&peer_data).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_CRYPTO_ERROR, + ) + })?; if mig_policy_hash_src_vec != peer_data_hash { error!("The received mig policy hash does not match the expected peer_data hash!\n"); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } // 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)?; + let mrowner = td_report_init_vec.get(112..160).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if mig_policy_init_hash_src != mrowner { error!("The received mig policy init hash does not match mrowner from init tdinfo!\n"); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } let policy_check_result = mig_policy::authenticate_rebinding_old( &td_report_src_vec, &event_log_src_vec, - peer_data, + &peer_data, &td_report_init_vec, &servtd_ext_vec, ); if let Err(e) = &policy_check_result { error!("Policy v2 check failed, below is the detail information:\n"); error!("{:x?}\n", e); - let session = responder_context - .common - .get_session_via_id(session_id) - .ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; - session.teardown(); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); + } + + // Verify that the peer's REPORTDATA is bound to this SPDM session's TH1 + let verified_report_peer = policy_check_result.unwrap(); + if verify_tdreport_data_binding(&verified_report_peer, b"MigTDReq", &th1).is_err() { + error!("Rebind peer REPORTDATA does not match expected TH1 binding!\n"); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } } @@ -1159,54 +1527,110 @@ pub fn handle_exchange_rebind_attest_info_req( element_count: VDM_MESSAGE_EXCHANGE_REBIND_ATTEST_INFO_RSP_ELEMENT_COUNT, }; - cnt += vdm_exchange_attest_info - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += vdm_exchange_attest_info.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; //TD report dst - let td_report_dst = gen_tdreport(&report_data[..report_data_prefix_len + th1_len]) - .map_err(|_| SPDM_STATUS_INVALID_STATE_LOCAL)?; + let td_report_dst = + gen_tdreport(&report_data[..report_data_prefix_len + th1_len]).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_STATE_LOCAL, + ) + })?; let td_report_dst_bytes = td_report_dst.as_bytes(); let tdreport_element = VdmMessageElement { element_type: VdmMessageElementType::TdReportMy, length: td_report_dst_bytes.len() as u32, }; - cnt += tdreport_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += tdreport_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; cnt += writer .extend_from_slice(td_report_dst_bytes) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + .ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; //event log dst - let event_log_dst = get_event_log().ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; + let event_log_dst = get_event_log().ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_STATE_LOCAL, + ) + })?; let event_log_element = VdmMessageElement { element_type: VdmMessageElementType::EventLogMy, length: event_log_dst.len() as u32, }; - cnt += event_log_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; - cnt += writer - .extend_from_slice(event_log_dst) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + cnt += event_log_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; + cnt += writer.extend_from_slice(event_log_dst).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; //mig policy dst let mig_policy_dst_hash = { - let blob = local_peer_data().ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?; - digest_sha384(&blob).map_err(|_| SPDM_STATUS_CRYPTO_ERROR)? + let blob = local_peer_data().ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_STATE_LOCAL, + ) + })?; + digest_sha384(&blob).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_CRYPTO_ERROR, + ) + })? }; let mig_policy_element = VdmMessageElement { element_type: VdmMessageElementType::MigPolicyMy, length: mig_policy_dst_hash.len() as u32, }; - cnt += mig_policy_element - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += mig_policy_element.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; cnt += writer .extend_from_slice(&mig_policy_dst_hash) - .ok_or(SPDM_STATUS_BUFFER_FULL)?; + .ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; Ok(cnt) } @@ -1257,37 +1681,68 @@ pub fn handle_exchange_rebind_info_req( "Invalid VDM message major_version: {:x?}\n", vdm_request.major_version ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_request.minor_version != VDM_MESSAGE_MINOR_VERSION { error!( "Invalid VDM message minor_version: {:x?}\n", vdm_request.minor_version ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_request.op_code != VdmMessageOpCode::ExchangeRebindInfoReq { error!("Invalid VDM message op_code: {:x?}\n", vdm_request.op_code); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } if vdm_request.element_count != VDM_MESSAGE_EXCHANGE_REBIND_INFO_ELEMENT_REQ_COUNT { error!( "Invalid VDM message element_count: {:x?}\n", vdm_request.element_count ); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let rebind_session_token_element = - VdmMessageElement::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let rebind_session_token_element = VdmMessageElement::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; if rebind_session_token_element.element_type != VdmMessageElementType::RebindSessionToken || rebind_session_token_element.length != VDM_MESSAGE_REBIND_SESSION_TOKEN_SIZE { error!("invalid rebind session token!\n"); - return Err(SPDM_STATUS_INVALID_MSG_FIELD); + return Err(fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_FIELD, + )); } - let mut token = <[u8; 32]>::read(reader).ok_or(SPDM_STATUS_INVALID_MSG_SIZE)?; + let mut token = <[u8; 32]>::read(reader).ok_or_else(|| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_INVALID_MSG_SIZE, + ) + })?; let servtd_ext = unsafe { let spdm_responder_ex = upcast_mut(responder_context); @@ -1309,9 +1764,13 @@ pub fn handle_exchange_rebind_info_req( op_code: VdmMessageOpCode::ExchangeRebindInfoRsp, element_count: VDM_MESSAGE_EXCHANGE_REBIND_INFO_ELEMENT_RSP_COUNT, }; - cnt += vdm_exchange_mig_info - .encode(&mut writer) - .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + cnt += vdm_exchange_mig_info.encode(&mut writer).map_err(|_| { + fail_with_teardown( + &mut responder_context.common, + session_id, + SPDM_STATUS_BUFFER_FULL, + ) + })?; Ok(cnt) }