Skip to content

Hardening spdm#188

Draft
haitaohuang wants to merge 3 commits into
microsoft:mainfrom
haitaohuang:upstream/pr4-spdm-session-security
Draft

Hardening spdm#188
haitaohuang wants to merge 3 commits into
microsoft:mainfrom
haitaohuang:upstream/pr4-spdm-session-security

Conversation

@haitaohuang
Copy link
Copy Markdown
Collaborator

No description provided.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the MigTD SPDM attestation and rebind flows by enforcing stricter session invalidation on verification failures and adding TH1-bound REPORTDATA checks for TDREPORT-based rebind attestation.

Changes:

  • Tear down SPDM sessions when the migration policy hash bound in the cert doesn’t match the expected peer_data hash (policy_v2 path).
  • Add TDREPORT REPORTDATA binding verification to the SPDM rebind attestation exchange (TH1 binding).
  • Introduce verify_tdreport_data_binding() helper to validate TDREPORT REPORTDATA against SHA384(prefix || TH1).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/migtd/src/spdm/spdm_rsp.rs Adds session teardown on policy hash mismatch and enforces TDREPORT REPORTDATA↔TH1 binding during responder-side rebind attestation.
src/migtd/src/spdm/spdm_req.rs Adds session teardown on policy hash mismatch and enforces TDREPORT REPORTDATA↔TH1 binding during requester-side rebind attestation.
src/migtd/src/spdm/mod.rs Adds a helper to verify TH1 binding inside raw TDREPORT REPORTDATA for the rebind flow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/migtd/src/spdm/mod.rs Outdated
Comment on lines +231 to +253
/// operates on quote supplemental data. In the rebind flow the peer provides a
/// raw TDREPORT instead of a quote; the REPORTDATA field lives at a different
/// offset (128 vs 520).
pub fn verify_tdreport_data_binding(
tdreport_bytes: &[u8],
peer_prefix: &[u8],
th1: &SpdmDigestStruct,
) -> Result<(), MigrationResult> {
// REPORTDATA sits inside ReportMac at offset 128, 64 bytes total;
// the first 48 bytes hold SHA384(prefix || TH1).
const TDREPORT_REPORT_DATA_OFFSET: usize = 128;
const REPORT_DATA_HASH_SIZE: usize = 48;

if tdreport_bytes.len() < TDREPORT_REPORT_DATA_OFFSET + REPORT_DATA_HASH_SIZE {
error!("TDREPORT too short for REPORTDATA extraction\n");
return Err(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_bytes
[TDREPORT_REPORT_DATA_OFFSET..TDREPORT_REPORT_DATA_OFFSET + REPORT_DATA_HASH_SIZE];
Comment thread src/migtd/src/spdm/mod.rs Outdated
Comment thread src/migtd/src/spdm/spdm_rsp.rs
Comment thread src/migtd/src/spdm/spdm_req.rs
@haitaohuang haitaohuang marked this pull request as draft May 28, 2026 22:15
@haitaohuang haitaohuang force-pushed the upstream/pr4-spdm-session-security branch from 2654f0f to adc1c3d Compare May 28, 2026 22:28
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 <haitaohuang@microsoft.com>
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 <haitaohuang@microsoft.com>
@haitaohuang haitaohuang force-pushed the upstream/pr4-spdm-session-security branch from adc1c3d to 9dcc60b Compare May 28, 2026 22:33
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants