Skip to content

Commit fc304b2

Browse files
committed
Add spdm attestation flow for rebinding
1 parent c6413e0 commit fc304b2

8 files changed

Lines changed: 1149 additions & 23 deletions

File tree

src/migtd/src/migration/rebinding.rs

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use ring::rand::{SecureRandom, SystemRandom};
1313
use tdx_tdcall::tdx::{tdcall_servtd_rebind_approve, tdcall_vm_write};
1414

1515
use crate::mig_policy::get_init_policy;
16+
#[cfg(feature = "spdm_attestation")]
17+
use crate::spdm;
1618
use crypto::hash::digest_sha384;
1719

1820
use crate::{
@@ -76,6 +78,7 @@ impl RebindingToken {
7678
}
7779
}
7880

81+
#[derive(Clone)]
7982
pub struct RebindingInfo {
8083
pub mig_request_id: u64,
8184
pub rebinding_src: u8,
@@ -326,6 +329,16 @@ pub async fn start_rebinding(
326329
remote_policy,
327330
)
328331
.await?;
332+
333+
#[cfg(feature = "spdm_attestation")]
334+
rebinding_old_spdm(
335+
transport,
336+
info,
337+
data,
338+
#[cfg(feature = "policy_v2")]
339+
remote_policy,
340+
)
341+
.await?;
329342
} else {
330343
let remote_policy = Box::pin(with_timeout(
331344
PRE_SESSION_TIMEOUT,
@@ -356,6 +369,16 @@ pub async fn start_rebinding(
356369
remote_policy,
357370
)
358371
.await?;
372+
373+
#[cfg(feature = "spdm_attestation")]
374+
rebinding_new_spdm(
375+
transport,
376+
info,
377+
data,
378+
#[cfg(feature = "policy_v2")]
379+
remote_policy,
380+
)
381+
.await?;
359382
}
360383

361384
#[cfg(feature = "vmcall-raw")]
@@ -370,6 +393,87 @@ pub async fn start_rebinding(
370393
Ok(())
371394
}
372395

396+
#[cfg(feature = "spdm_attestation")]
397+
pub async fn rebinding_old_spdm(
398+
transport: TransportType,
399+
info: &RebindingInfo,
400+
_data: &mut Vec<u8>,
401+
#[cfg(feature = "policy_v2")] remote_policy: Vec<u8>,
402+
) -> Result<(), MigrationResult> {
403+
const SPDM_TIMEOUT: Duration = Duration::from_secs(60); // 60 seconds
404+
let mut spdm_requester = spdm::spdm_requester(transport).map_err(|_e| {
405+
log::error!(
406+
"rebinding: Failed in spdm_requester transport. Migration ID: {}\n",
407+
info.mig_request_id
408+
);
409+
MigrationResult::SecureSessionError
410+
})?;
411+
with_timeout(
412+
SPDM_TIMEOUT,
413+
spdm::spdm_requester_rebind_old(
414+
&mut spdm_requester,
415+
info,
416+
#[cfg(feature = "policy_v2")]
417+
remote_policy,
418+
),
419+
)
420+
.await
421+
.map_err(|e| {
422+
log::error!(
423+
"rebinding: spdm_requester_rebind_old timeout error: {:?}\n",
424+
e
425+
);
426+
e
427+
})?
428+
.map_err(|e| {
429+
log::error!("rebinding: spdm_requester_rebind_old error: {:?}\n", e);
430+
e
431+
})?;
432+
log::info!("Rebind completed\n");
433+
Ok(())
434+
}
435+
436+
#[cfg(feature = "spdm_attestation")]
437+
pub async fn rebinding_new_spdm(
438+
transport: TransportType,
439+
info: &RebindingInfo,
440+
_data: &mut Vec<u8>,
441+
#[cfg(feature = "policy_v2")] remote_policy: Vec<u8>,
442+
) -> Result<(), MigrationResult> {
443+
const SPDM_TIMEOUT: Duration = Duration::from_secs(60); // 60 seconds
444+
let mut spdm_responder = spdm::spdm_responder(transport).map_err(|_e| {
445+
log::error!(
446+
"rebinding: Failed in spdm_responder transport. Migration ID: {}\n",
447+
info.mig_request_id
448+
);
449+
MigrationResult::SecureSessionError
450+
})?;
451+
452+
with_timeout(
453+
SPDM_TIMEOUT,
454+
spdm::spdm_responder_rebind_new(
455+
&mut spdm_responder,
456+
&info,
457+
#[cfg(feature = "policy_v2")]
458+
remote_policy,
459+
),
460+
)
461+
.await
462+
.map_err(|e| {
463+
log::error!(
464+
"rebinding: spdm_responder_rebind_new timeout error: {:?}\n",
465+
e
466+
);
467+
e
468+
})?
469+
.map_err(|e| {
470+
log::error!("rebinding: spdm_responder_rebind_new error: {:?}\n", e);
471+
e
472+
})?;
473+
log::info!("Rebind completed\n");
474+
Ok(())
475+
}
476+
373477
pub async fn rebinding_old(
374478
transport: TransportType,
375479
info: &RebindingInfo,
@@ -506,7 +610,7 @@ fn get_servtd_ext_from_cert(certs: &Option<Vec<&[u8]>>) -> Result<ServtdExt, Mig
506610
}
507611
}
508612

509-
fn create_token_list(info: &RebindingInfo) -> Result<Vec<RebindingToken>, MigrationResult> {
613+
pub fn create_token_list(info: &RebindingInfo) -> Result<Vec<RebindingToken>, MigrationResult> {
510614
let mut tokens = Vec::new();
511615

512616
for (handle, uuid) in info

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
@@ -247,7 +247,7 @@ fn gen_quote(public_key: &[u8]) -> Result<Vec<u8>> {
247247
})
248248
}
249249

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

src/migtd/src/spdm/mod.rs

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

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

7+
mod spdm_rebind;
78
mod spdm_req;
89
mod spdm_rsp;
910
mod spdm_vdm;
@@ -25,6 +26,8 @@ use zeroize::ZeroizeOnDrop;
2526
use async_io::AsyncRead;
2627
use async_io::AsyncWrite;
2728
use crypto::hash::digest_sha384;
29+
pub use spdm_rebind::spdm_requester_rebind_old;
30+
pub use spdm_rebind::spdm_responder_rebind_new;
2831
pub use spdm_req::spdm_requester;
2932
pub use spdm_req::spdm_requester_transfer_msk;
3033
pub use spdm_rsp::spdm_responder;

src/migtd/src/spdm/spdm_rebind.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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+
#[cfg(feature = "policy_v2")] 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+
#[cfg(feature = "policy_v2")]
46+
remote_policy,
47+
))
48+
.await?;
49+
50+
Box::pin(spdm_requester.send_receive_spdm_finish(Some(0xff), session_id)).await?;
51+
52+
Box::pin(send_and_receive_sdm_rebind_info(
53+
spdm_requester,
54+
rebind_info,
55+
Some(session_id),
56+
))
57+
.await?;
58+
59+
Box::pin(spdm_requester.send_receive_spdm_end_session(session_id)).await?;
60+
Ok(())
61+
}
62+
63+
pub async fn spdm_responder_rebind_new(
64+
spdm_responder_ex: &mut ResponderContextEx,
65+
rebind_info: &RebindingInfo,
66+
#[cfg(feature = "policy_v2")] remote_policy: Vec<u8>,
67+
) -> Result<(), SpdmStatus> {
68+
#[cfg(not(feature = "policy_v2"))]
69+
let remote_policy = Vec::new();
70+
71+
spdm_responder_ex.remote_policy = remote_policy;
72+
spdm_responder_ex.info = ResponderContextExInfo::RebindInformation(rebind_info.clone());
73+
74+
let spdm_responder = &mut spdm_responder_ex.responder_context;
75+
let mut writer = Writer::init(&mut spdm_responder.common.app_context_data_buffer);
76+
77+
let responder_app_context = SpdmAppContextData {
78+
migration_info: MigtdMigrationInformation::default(),
79+
private_key: PrivateKeyDer::default(),
80+
};
81+
responder_app_context
82+
.encode(&mut writer)
83+
.map_err(|_| SPDM_STATUS_BUFFER_FULL)?;
84+
85+
Box::pin(rsp_handle_message(spdm_responder)).await?;
86+
spdm_responder.common.app_context_data_buffer.zeroize();
87+
88+
Ok(())
89+
}

0 commit comments

Comments
 (0)