From 9db9a77dfbaa792a55c2a1b3409a25a3059b8d9a Mon Sep 17 00:00:00 2001 From: Haitao Huang Date: Tue, 19 May 2026 19:00:13 +0000 Subject: [PATCH 1/3] security(spdm): tear down session on policy-hash mismatch Add session.teardown() to the policy-hash mismatch branch in both requester and responder verify_peer_attestation_v2, matching the convention used by all other failure branches. Signed-off-by: Haitao Huang --- src/migtd/src/spdm/spdm_req.rs | 10 ++++++++++ src/migtd/src/spdm/spdm_rsp.rs | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/migtd/src/spdm/spdm_req.rs b/src/migtd/src/spdm/spdm_req.rs index 37b610175..b06e0175a 100644 --- a/src/migtd/src/spdm/spdm_req.rs +++ b/src/migtd/src/spdm/spdm_req.rs @@ -685,6 +685,11 @@ fn verify_peer_attestation_v2( let peer_data_hash = digest_sha384(peer_data).map_err(|_| 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"); + 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); } @@ -1174,6 +1179,11 @@ pub async fn send_and_receive_sdm_rebind_attest_info( let peer_data_hash = digest_sha384(&peer_data).map_err(|_| 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"); + 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); } diff --git a/src/migtd/src/spdm/spdm_rsp.rs b/src/migtd/src/spdm/spdm_rsp.rs index dab15076d..dd82ec61a 100644 --- a/src/migtd/src/spdm/spdm_rsp.rs +++ b/src/migtd/src/spdm/spdm_rsp.rs @@ -703,6 +703,11 @@ fn rsp_verify_peer_attestation_v2( let peer_data_hash = digest_sha384(peer_data).map_err(|_| 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"); + 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); } @@ -1105,6 +1110,11 @@ pub fn handle_exchange_rebind_attest_info_req( let peer_data_hash = digest_sha384(peer_data).map_err(|_| 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"); + 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); } @@ -1114,6 +1124,11 @@ pub fn handle_exchange_rebind_attest_info_req( .ok_or(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"); + 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); } From 9dcc60badae0f3de1802341a0fc19b65fecafd3f Mon Sep 17 00:00:00 2001 From: Haitao Huang Date: Sun, 17 May 2026 08:06:28 -0700 Subject: [PATCH 2/3] security(spdm): bind rebind attestation to SPDM session TH1 Add verify_tdreport_data_binding() to check rebind TDREPORT REPORTDATA equals SHA384(prefix || TH1), preventing replay of attestation from a previous SPDM session. Applied on both requester and responder sides. Signed-off-by: Haitao Huang --- src/migtd/src/spdm/mod.rs | 33 +++++++++++++++++++++++++++++++++ src/migtd/src/spdm/spdm_req.rs | 15 ++++++++++++++- src/migtd/src/spdm/spdm_rsp.rs | 14 +++++++++++++- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/migtd/src/spdm/mod.rs b/src/migtd/src/spdm/mod.rs index e98cee25e..e4852d66f 100644 --- a/src/migtd/src/spdm/mod.rs +++ b/src/migtd/src/spdm/mod.rs @@ -225,6 +225,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 b06e0175a..422815175 100644 --- a/src/migtd/src/spdm/spdm_req.rs +++ b/src/migtd/src/spdm/spdm_req.rs @@ -12,7 +12,8 @@ use crate::{ }, spdm::{ build_report_data, gen_quote_spdm, spdm_rsp::SECRET_ASYM_IMPL_INSTANCE, spdm_verify_quote, - verify_report_data_binding, vmcall_msg::VmCallTransportEncap, *, + verify_report_data_binding, verify_tdreport_data_binding, vmcall_msg::VmCallTransportEncap, + *, }, }; use async_io::{AsyncRead, AsyncWrite}; @@ -1203,6 +1204,18 @@ pub async fn send_and_receive_sdm_rebind_attest_info( session.teardown(); return Err(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"); + 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); + } } let vdm_attest_info_src_hash = diff --git a/src/migtd/src/spdm/spdm_rsp.rs b/src/migtd/src/spdm/spdm_rsp.rs index dd82ec61a..ed533678f 100644 --- a/src/migtd/src/spdm/spdm_rsp.rs +++ b/src/migtd/src/spdm/spdm_rsp.rs @@ -32,7 +32,7 @@ use log::error; use crate::spdm::{ build_report_data, gen_quote_spdm, spdm_verify_quote, verify_report_data_binding, - vmcall_msg::VmCallTransportEncap, *, + verify_tdreport_data_binding, vmcall_msg::VmCallTransportEncap, *, }; use spdmlib::{ common::{self, *}, @@ -1149,6 +1149,18 @@ pub fn handle_exchange_rebind_attest_info_req( session.teardown(); return Err(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"); + 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); + } } unsafe { From e76b3c33d4ca50c70e2129a91f638d53796eb8e6 Mon Sep 17 00:00:00 2001 From: Haitao Huang Date: Thu, 4 Jun 2026 01:48:25 +0000 Subject: [PATCH 3/3] security(spdm): tear down session on every post-keying error path Add a small private helper, fail_with_teardown, in src/migtd/src/spdm/mod.rs and use it on every post-key-exchange error path in the policy_v2 VDM handlers so that the keyed SPDM session is zeroized before the error propagates. Why this matters ---------------- rsp_handle_message in spdm_rsp.rs only breaks out of its dispatch loop when the handler returns a StatusCode::VDM(_) error or SPDM_STATUS_INVALID_STATE_LOCAL, or when the session lookup get_session_via_id returns None. Every other StatusCode::CORE(_) value (INVALID_MSG_FIELD, INVALID_MSG_SIZE, BUFFER_FULL, CRYPTO_ERROR, UNSUPPORTED_CAP, etc.) is silently swallowed and the loop keeps polling the still-keyed session. Without an explicit teardown, an attacker who can drive any of those CORE errors keeps a live, attested session reachable on the responder side after the legitimate flow has already failed. The teardown causes get_session_via_id to return None on the next iteration, which is the loop's correct exit condition. The helper is also applied to the requester side for defense in depth so the caller never inherits a keyed session after a failed exchange. Scope ----- Only the policy_v2 VDM exchange handlers and their shared helpers are swept (the implementation we care about per project direction): handle_exchange_mig_attest_info_req (shared, used in v2) handle_exchange_mig_info_req (shared, used in v2) handle_exchange_rebind_attest_info_req handle_exchange_rebind_info_req rsp_verify_peer_attestation_v2 send_and_receive_sdm_migration_attest_info (shared, used in v2) send_and_receive_sdm_rebind_attest_info send_and_receive_sdm_rebind_info verify_peer_attestation_v2 Pre-key-exchange paths and paths that already return SPDM_STATUS_INVALID_STATE_LOCAL or a VDM-typed status (which the dispatch loop already handles) are intentionally left alone. Verification ------------ * cargo fmt -- --check (clean) * cargo build --release -p migtd --no-default-features --features ... for: - AzCVMEmu,test_disable_ra_and_accept_all,spdm_attestation - AzCVMEmu,policy_v2,test_disable_ra_and_accept_all,spdm_attestation - AzCVMEmu,policy_v2,test_mock_report,spdm_attestation * All three integration-emu.yml SPDM matrix entries pass end-to-end: - SPDM Migration (Skip RA) - SPDM Policy v2 with Mock Report - SPDM Rebind Prepare (Skip RA) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/migtd/src/spdm/mod.rs | 30 ++ src/migtd/src/spdm/spdm_req.rs | 767 ++++++++++++++++++++++-------- src/migtd/src/spdm/spdm_rsp.rs | 828 +++++++++++++++++++++++++-------- 3 files changed, 1236 insertions(+), 389 deletions(-) diff --git a/src/migtd/src/spdm/mod.rs b/src/migtd/src/spdm/mod.rs index e4852d66f..75f33956f 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], diff --git a/src/migtd/src/spdm/spdm_req.rs b/src/migtd/src/spdm/spdm_req.rs index 422815175..e1dbb18fc 100644 --- a/src/migtd/src/spdm/spdm_req.rs +++ b/src/migtd/src/spdm/spdm_req.rs @@ -11,9 +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, verify_tdreport_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}; @@ -307,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]; @@ -325,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() @@ -336,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)?; @@ -348,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() }; @@ -363,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)?; @@ -376,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 { @@ -416,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 @@ -449,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( @@ -475,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 @@ -487,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) @@ -593,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 { @@ -683,15 +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"); - 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, + )); } // 2. Authenticate remote (includes quote verification internally) @@ -702,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 @@ -720,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, + )); } } } @@ -925,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]; @@ -943,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() @@ -961,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 @@ -977,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)?; @@ -990,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; @@ -1028,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; @@ -1043,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. @@ -1058,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, @@ -1083,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 @@ -1095,97 +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"); - 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, + )); } let policy_check_result = mig_policy::authenticate_rebinding_new( @@ -1197,37 +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"); - 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, + )); } } - 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 { @@ -1268,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)?; @@ -1306,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 @@ -1315,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 ed533678f..4b83f5e89 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, - verify_tdreport_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,15 +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"); - 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, + )); } // 2. Authenticate remote (includes quote verification internally) @@ -719,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 @@ -737,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, + )); } } } @@ -785,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( @@ -878,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 { @@ -889,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 { @@ -904,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) } @@ -952,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); } @@ -963,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 { @@ -971,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 @@ -991,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) { @@ -1008,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 @@ -1017,149 +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"); - 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, + )); } // 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"); - 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, + )); } 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"); - 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, + )); } } @@ -1186,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) } @@ -1284,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); @@ -1336,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) }