Skip to content

Commit b0610e2

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

8 files changed

Lines changed: 1179 additions & 30 deletions

File tree

src/migtd/src/migration/rebinding.rs

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use ring::rand::{SecureRandom, SystemRandom};
1414
use tdx_tdcall::tdx::{tdcall_servtd_rebind_approve, tdcall_vm_write};
1515

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

@@ -392,6 +394,22 @@ 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+
match info.operation {
400+
MIGTD_REBIND_OP_PREPARE => {
401+
rebinding_old_spdm(
402+
transport,
403+
info,
404+
data,
405+
#[cfg(feature = "policy_v2")]
406+
remote_policy,
407+
)
408+
.await?
409+
}
410+
MIGTD_REBIND_OP_FINALIZE => rebinding_old_finalize(info, data).await?,
411+
_ => return Err(MigrationResult::InvalidParameter),
412+
}
395413
} else {
396414
let pre_session_data = Box::pin(with_timeout(
397415
PRE_SESSION_TIMEOUT,
@@ -421,8 +439,23 @@ pub async fn start_rebinding(
421439
MIGTD_REBIND_OP_FINALIZE => rebinding_new_finalize(info, data).await?,
422440
_ => return Err(MigrationResult::InvalidParameter),
423441
}
424-
}
425442

443+
#[cfg(feature = "spdm_attestation")]
444+
match info.operation {
445+
MIGTD_REBIND_OP_PREPARE => {
446+
rebinding_new_spdm(
447+
transport,
448+
info,
449+
data,
450+
#[cfg(feature = "policy_v2")]
451+
pre_session_data,
452+
)
453+
.await?
454+
}
455+
MIGTD_REBIND_OP_FINALIZE => rebinding_new_finalize(info, data).await?,
456+
_ => return Err(MigrationResult::InvalidParameter),
457+
}
458+
}
426459
#[cfg(feature = "vmcall-raw")]
427460
{
428461
use crate::migration::logging::entrylog;
@@ -437,6 +470,87 @@ pub async fn start_rebinding(
437470
Ok(())
438471
}
439472

473+
#[cfg(feature = "spdm_attestation")]
474+
pub async fn rebinding_old_spdm(
475+
transport: TransportType,
476+
info: &RebindingInfo<'_>,
477+
_data: &mut Vec<u8>,
478+
#[cfg(feature = "policy_v2")] remote_policy: Vec<u8>,
479+
) -> Result<(), MigrationResult> {
480+
const SPDM_TIMEOUT: Duration = Duration::from_secs(60); // 60 seconds
481+
let mut spdm_requester = spdm::spdm_requester(transport).map_err(|_e| {
482+
log::error!(
483+
"rebinding: Failed in spdm_requester transport. Migration ID: {}\n",
484+
info.mig_request_id
485+
);
486+
MigrationResult::SecureSessionError
487+
})?;
488+
with_timeout(
489+
SPDM_TIMEOUT,
490+
spdm::spdm_requester_rebind_old(
491+
&mut spdm_requester,
492+
info,
493+
#[cfg(feature = "policy_v2")]
494+
remote_policy,
495+
),
496+
)
497+
.await
498+
.map_err(|e| {
499+
log::error!(
500+
"rebinding: spdm_requester_rebind_old timeout error: {:?}\n",
501+
e
502+
);
503+
e
504+
})?
505+
.map_err(|e| {
506+
log::error!("rebinding: spdm_requester_rebind_old error: {:?}\n", e);
507+
e
508+
})?;
509+
log::info!("Rebind completed\n");
510+
Ok(())
511+
}
512+
513+
#[cfg(feature = "spdm_attestation")]
514+
pub async fn rebinding_new_spdm(
515+
transport: TransportType,
516+
info: &RebindingInfo<'_>,
517+
_data: &mut Vec<u8>,
518+
#[cfg(feature = "policy_v2")] remote_policy: Vec<u8>,
519+
) -> Result<(), MigrationResult> {
520+
const SPDM_TIMEOUT: Duration = Duration::from_secs(60); // 60 seconds
521+
let mut spdm_responder = spdm::spdm_responder(transport).map_err(|_e| {
522+
log::error!(
523+
"rebinding: Failed in spdm_responder transport. Migration ID: {}\n",
524+
info.mig_request_id
525+
);
526+
MigrationResult::SecureSessionError
527+
})?;
528+
529+
with_timeout(
530+
SPDM_TIMEOUT,
531+
spdm::spdm_responder_rebind_new(
532+
&mut spdm_responder,
533+
info,
534+
#[cfg(feature = "policy_v2")]
535+
remote_policy,
536+
),
537+
)
538+
.await
539+
.map_err(|e| {
540+
log::error!(
541+
"rebinding: spdm_responder_rebind_new timeout error: {:?}\n",
542+
e
543+
);
544+
e
545+
})?
546+
.map_err(|e| {
547+
log::error!("rebinding: spdm_responder_rebind_new error: {:?}\n", e);
548+
e
549+
})?;
550+
log::info!("Rebind completed\n");
551+
Ok(())
552+
}
553+
440554
pub async fn rebinding_old_prepare(
441555
transport: TransportType,
442556
info: &RebindingInfo<'_>,
@@ -594,7 +708,7 @@ fn get_servtd_ext_from_cert(certs: &Option<Vec<&[u8]>>) -> Result<ServtdExt, Mig
594708
}
595709
}
596710

597-
fn create_rebind_token(info: &RebindingInfo) -> Result<RebindingToken, MigrationResult> {
711+
pub fn create_rebind_token(info: &RebindingInfo) -> Result<RebindingToken, MigrationResult> {
598712
let mut token = [0u8; 32];
599713
let rng = SystemRandom::new();
600714
rng.fill(&mut token)

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<'a>(
63+
spdm_responder_ex: &mut ResponderContextEx<'a>,
64+
rebind_info: &'a RebindingInfo<'a>,
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);
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)