Skip to content

Commit 776f50b

Browse files
committed
Add spdm attestation flow for rebinding
1 parent 8d25a92 commit 776f50b

8 files changed

Lines changed: 1174 additions & 23 deletions

File tree

src/migtd/src/migration/rebinding.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use tdx_tdcall::tdx::{tdcall_servtd_rebind_approve, tdcall_vm_write};
1515

1616
use crate::migration::servtd_ext::read_servtd_ext;
1717
use crate::{event_log, migration::transport::*};
18+
#[cfg(feature = "spdm_attestation")]
19+
use crate::spdm;
1820
use crypto::hash::digest_sha384;
1921

2022
use crate::{
@@ -392,6 +394,16 @@ pub async fn start_rebinding(
392394
MIGTD_REBIND_OP_FINALIZE => rebinding_old_finalize(info, data).await?,
393395
_ => return Err(MigrationResult::InvalidParameter),
394396
}
397+
398+
#[cfg(feature = "spdm_attestation")]
399+
rebinding_old_spdm(
400+
transport,
401+
info,
402+
data,
403+
#[cfg(feature = "policy_v2")]
404+
remote_policy,
405+
)
406+
.await?;
395407
} else {
396408
let pre_session_data = Box::pin(with_timeout(
397409
PRE_SESSION_TIMEOUT,
@@ -421,6 +433,16 @@ pub async fn start_rebinding(
421433
MIGTD_REBIND_OP_FINALIZE => rebinding_new_finalize(info, data).await?,
422434
_ => return Err(MigrationResult::InvalidParameter),
423435
}
436+
437+
#[cfg(feature = "spdm_attestation")]
438+
rebinding_new_spdm(
439+
transport,
440+
info,
441+
data,
442+
#[cfg(feature = "policy_v2")]
443+
remote_policy,
444+
)
445+
.await?;
424446
}
425447

426448
#[cfg(feature = "vmcall-raw")]
@@ -437,6 +459,87 @@ pub async fn start_rebinding(
437459
Ok(())
438460
}
439461

462+
#[cfg(feature = "spdm_attestation")]
463+
pub async fn rebinding_old_spdm(
464+
transport: TransportType,
465+
info: &RebindingInfo,
466+
_data: &mut Vec<u8>,
467+
#[cfg(feature = "policy_v2")] remote_policy: Vec<u8>,
468+
) -> Result<(), MigrationResult> {
469+
const SPDM_TIMEOUT: Duration = Duration::from_secs(60); // 60 seconds
470+
let mut spdm_requester = spdm::spdm_requester(transport).map_err(|_e| {
471+
log::error!(
472+
"rebinding: Failed in spdm_requester transport. Migration ID: {}\n",
473+
info.mig_request_id
474+
);
475+
MigrationResult::SecureSessionError
476+
})?;
477+
with_timeout(
478+
SPDM_TIMEOUT,
479+
spdm::spdm_requester_rebind_old(
480+
&mut spdm_requester,
481+
info,
482+
#[cfg(feature = "policy_v2")]
483+
remote_policy,
484+
),
485+
)
486+
.await
487+
.map_err(|e| {
488+
log::error!(
489+
"rebinding: spdm_requester_rebind_old timeout error: {:?}\n",
490+
e
491+
);
492+
e
493+
})?
494+
.map_err(|e| {
495+
log::error!("rebinding: spdm_requester_rebind_old error: {:?}\n", e);
496+
e
497+
})?;
498+
log::info!("Rebind completed\n");
499+
Ok(())
500+
}
501+
502+
#[cfg(feature = "spdm_attestation")]
503+
pub async fn rebinding_new_spdm(
504+
transport: TransportType,
505+
info: &RebindingInfo,
506+
_data: &mut Vec<u8>,
507+
#[cfg(feature = "policy_v2")] remote_policy: Vec<u8>,
508+
) -> Result<(), MigrationResult> {
509+
const SPDM_TIMEOUT: Duration = Duration::from_secs(60); // 60 seconds
510+
let mut spdm_responder = spdm::spdm_responder(transport).map_err(|_e| {
511+
log::error!(
512+
"rebinding: Failed in spdm_responder transport. Migration ID: {}\n",
513+
info.mig_request_id
514+
);
515+
MigrationResult::SecureSessionError
516+
})?;
517+
518+
with_timeout(
519+
SPDM_TIMEOUT,
520+
spdm::spdm_responder_rebind_new(
521+
&mut spdm_responder,
522+
&info,
523+
#[cfg(feature = "policy_v2")]
524+
remote_policy,
525+
),
526+
)
527+
.await
528+
.map_err(|e| {
529+
log::error!(
530+
"rebinding: spdm_responder_rebind_new timeout error: {:?}\n",
531+
e
532+
);
533+
e
534+
})?
535+
.map_err(|e| {
536+
log::error!("rebinding: spdm_responder_rebind_new error: {:?}\n", e);
537+
e
538+
})?;
539+
log::info!("Rebind completed\n");
540+
Ok(())
541+
}
542+
440543
pub async fn rebinding_old_prepare(
441544
transport: TransportType,
442545
info: &RebindingInfo<'_>,

src/migtd/src/migration/servtd_ext.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub const TDCS_FIELD_SERVTD_ATTR: u64 = 0x1910000300000202;
2424
pub const TDCS_FIELD_SERVTD_ACCEPT_SERVTD_EXT_HASH: u64 = 0x1910000300000214;
2525

2626
#[repr(C)]
27+
#[derive(Clone, Copy)]
2728
pub struct ServtdExt {
2829
pub init_servtd_info_hash: [u8; 48],
2930
pub init_attr: [u8; 8],

src/migtd/src/ratls/server_client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ fn gen_quote(public_key: &[u8]) -> Result<Vec<u8>> {
251251
})
252252
}
253253

254-
fn gen_tdreport(public_key: &[u8]) -> Result<TdxReport> {
254+
pub fn gen_tdreport(public_key: &[u8]) -> Result<TdxReport> {
255255
let hash = digest_sha384(public_key).map_err(|e| {
256256
log::error!("Failed to compute SHA384 digest: {:?}\n", e);
257257
e

src/migtd/src/spdm/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#![cfg(feature = "spdm_attestation")]
66

7+
#[cfg(feature = "policy_v2")]
8+
mod spdm_rebind;
79
mod spdm_req;
810
mod spdm_rsp;
911
mod spdm_vdm;
@@ -25,6 +27,10 @@ use zeroize::ZeroizeOnDrop;
2527
use async_io::AsyncRead;
2628
use async_io::AsyncWrite;
2729
use crypto::hash::digest_sha384;
30+
#[cfg(feature = "policy_v2")]
31+
pub use spdm_rebind::spdm_requester_rebind_old;
32+
#[cfg(feature = "policy_v2")]
33+
pub use spdm_rebind::spdm_responder_rebind_new;
2834
pub use spdm_req::spdm_requester;
2935
pub use spdm_req::spdm_requester_transfer_msk;
3036
pub use spdm_rsp::spdm_responder;

src/migtd/src/spdm/spdm_rebind.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright (c) 2026 Intel Corporation
2+
//
3+
// SPDX-License-Identifier: BSD-2-Clause-Patent
4+
use crate::{
5+
migration::{rebinding::RebindingInfo, MigtdMigrationInformation},
6+
spdm::{
7+
spdm_req::{
8+
send_and_receive_pub_key, send_and_receive_sdm_rebind_attest_info,
9+
send_and_receive_sdm_rebind_info,
10+
},
11+
spdm_rsp::{rsp_handle_message, ResponderContextEx, ResponderContextExInfo},
12+
PrivateKeyDer, SpdmAppContextData,
13+
},
14+
};
15+
use alloc::boxed::Box;
16+
use alloc::vec::Vec;
17+
use codec::{Codec, Writer};
18+
use spdmlib::{
19+
error::{SpdmStatus, SPDM_STATUS_BUFFER_FULL},
20+
protocol::SpdmMeasurementSummaryHashType,
21+
requester::RequesterContext,
22+
};
23+
use zeroize::Zeroize;
24+
25+
pub async fn spdm_requester_rebind_old(
26+
spdm_requester: &mut RequesterContext,
27+
rebind_info: &RebindingInfo,
28+
remote_policy: Vec<u8>,
29+
) -> Result<(), SpdmStatus> {
30+
Box::pin(spdm_requester.send_receive_spdm_version()).await?;
31+
Box::pin(spdm_requester.send_receive_spdm_capability()).await?;
32+
Box::pin(spdm_requester.send_receive_spdm_algorithm()).await?;
33+
34+
Box::pin(send_and_receive_pub_key(spdm_requester)).await?;
35+
let session_id = Box::pin(spdm_requester.send_receive_spdm_key_exchange(
36+
0xff,
37+
SpdmMeasurementSummaryHashType::SpdmMeasurementSummaryHashTypeNone,
38+
))
39+
.await?;
40+
41+
Box::pin(send_and_receive_sdm_rebind_attest_info(
42+
spdm_requester,
43+
rebind_info,
44+
session_id,
45+
remote_policy,
46+
))
47+
.await?;
48+
49+
Box::pin(spdm_requester.send_receive_spdm_finish(Some(0xff), session_id)).await?;
50+
51+
Box::pin(send_and_receive_sdm_rebind_info(
52+
spdm_requester,
53+
rebind_info,
54+
Some(session_id),
55+
))
56+
.await?;
57+
58+
Box::pin(spdm_requester.send_receive_spdm_end_session(session_id)).await?;
59+
Ok(())
60+
}
61+
62+
pub async fn spdm_responder_rebind_new(
63+
spdm_responder_ex: &mut ResponderContextEx,
64+
rebind_info: &RebindingInfo,
65+
remote_policy: Vec<u8>,
66+
) -> Result<(), SpdmStatus> {
67+
spdm_responder_ex.remote_policy = remote_policy;
68+
spdm_responder_ex.info = ResponderContextExInfo::RebindInformation(rebind_info.clone());
69+
70+
let spdm_responder = &mut spdm_responder_ex.responder_context;
71+
let mut writer = Writer::init(&mut spdm_responder.common.app_context_data_buffer);
72+
73+
let responder_app_context = SpdmAppContextData {
74+
migration_info: MigtdMigrationInformation::default(),
75+
private_key: PrivateKeyDer::default(),
76+
};
77+
responder_app_context
78+
.encode(&mut writer)
79+
.map_err(|_| SPDM_STATUS_BUFFER_FULL)?;
80+
81+
Box::pin(rsp_handle_message(spdm_responder)).await?;
82+
spdm_responder.common.app_context_data_buffer.zeroize();
83+
84+
Ok(())
85+
}

0 commit comments

Comments
 (0)