Skip to content

Commit 60e7091

Browse files
haitaohuangsgrams
authored andcommitted
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 <haitaohuang@microsoft.com>
1 parent 3b503df commit 60e7091

3 files changed

Lines changed: 60 additions & 2 deletions

File tree

src/migtd/src/spdm/mod.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,39 @@ pub fn verify_report_data_binding(
223223
verify_peer_report_data(supplemental_data, &report_data)
224224
}
225225

226+
/// Verify that a TDREPORT's REPORTDATA is bound to the expected prefix and TH1.
227+
///
228+
/// This is the rebind-path counterpart of [`verify_report_data_binding`], which
229+
/// operates on quote supplemental data. In the rebind flow the peer provides a
230+
/// raw TDREPORT instead of a quote; the REPORTDATA field is accessed via the
231+
/// parsed `TdxReport.report_mac.report_data` struct field.
232+
pub fn verify_tdreport_data_binding(
233+
tdreport_bytes: &[u8],
234+
peer_prefix: &[u8],
235+
th1: &SpdmDigestStruct,
236+
) -> Result<(), MigrationResult> {
237+
use scroll::Pread;
238+
use tdx_tdcall::tdreport::TdxReport;
239+
240+
const REPORT_DATA_HASH_SIZE: usize = 48;
241+
242+
let tdreport: TdxReport = tdreport_bytes.pread(0).map_err(|_| {
243+
error!("Failed to parse TDREPORT\n");
244+
MigrationResult::InvalidParameter
245+
})?;
246+
247+
let expected_report_data =
248+
build_report_data(peer_prefix, th1).map_err(|_| MigrationResult::InvalidParameter)?;
249+
let expected_hash = digest_sha384(&expected_report_data)?;
250+
let actual = &tdreport.report_mac.report_data[..REPORT_DATA_HASH_SIZE];
251+
252+
if actual != expected_hash.as_slice() {
253+
return Err(MigrationResult::InvalidParameter);
254+
}
255+
256+
Ok(())
257+
}
258+
226259
const ECDSA_P384_SHA384_PRIVATE_KEY_LENGTH: usize = 0xb9;
227260

228261
#[derive(Debug, Clone, Zeroize, ZeroizeOnDrop, Eq, PartialEq)]

src/migtd/src/spdm/spdm_req.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ use crate::{
1212
},
1313
spdm::{
1414
build_report_data, gen_quote_spdm, spdm_rsp::SECRET_ASYM_IMPL_INSTANCE, spdm_verify_quote,
15-
verify_report_data_binding, vmcall_msg::VmCallTransportEncap, *,
15+
verify_report_data_binding, verify_tdreport_data_binding, vmcall_msg::VmCallTransportEncap,
16+
*,
1617
},
1718
};
1819
use async_io::{AsyncRead, AsyncWrite};
@@ -1188,6 +1189,18 @@ pub async fn send_and_receive_sdm_rebind_attest_info(
11881189
session.teardown();
11891190
return Err(SPDM_STATUS_INVALID_MSG_FIELD);
11901191
}
1192+
1193+
// Verify that the peer's REPORTDATA is bound to this SPDM session's TH1
1194+
let verified_report_peer = policy_check_result.unwrap();
1195+
if verify_tdreport_data_binding(&verified_report_peer, b"MigTDRsp", &th1).is_err() {
1196+
error!("Rebind peer REPORTDATA does not match expected TH1 binding!\n");
1197+
let session = spdm_requester
1198+
.common
1199+
.get_session_via_id(session_id)
1200+
.ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?;
1201+
session.teardown();
1202+
return Err(SPDM_STATUS_INVALID_MSG_FIELD);
1203+
}
11911204
}
11921205

11931206
let vdm_attest_info_src_hash =

src/migtd/src/spdm/spdm_rsp.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use log::error;
3131

3232
use crate::spdm::{
3333
build_report_data, gen_quote_spdm, spdm_verify_quote, verify_report_data_binding,
34-
vmcall_msg::VmCallTransportEncap, *,
34+
verify_tdreport_data_binding, vmcall_msg::VmCallTransportEncap, *,
3535
};
3636
use spdmlib::{
3737
common::{self, *},
@@ -1145,6 +1145,18 @@ pub fn handle_exchange_rebind_attest_info_req(
11451145
session.teardown();
11461146
return Err(SPDM_STATUS_INVALID_MSG_FIELD);
11471147
}
1148+
1149+
// Verify that the peer's REPORTDATA is bound to this SPDM session's TH1
1150+
let verified_report_peer = policy_check_result.unwrap();
1151+
if verify_tdreport_data_binding(&verified_report_peer, b"MigTDReq", &th1).is_err() {
1152+
error!("Rebind peer REPORTDATA does not match expected TH1 binding!\n");
1153+
let session = responder_context
1154+
.common
1155+
.get_session_via_id(session_id)
1156+
.ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)?;
1157+
session.teardown();
1158+
return Err(SPDM_STATUS_INVALID_MSG_FIELD);
1159+
}
11481160
}
11491161

11501162
unsafe {

0 commit comments

Comments
 (0)