Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 130 additions & 2 deletions src/migtd/src/migration/rebinding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use ring::rand::{SecureRandom, SystemRandom};
use tdx_tdcall::tdx::{tdcall_servtd_rebind_approve, tdcall_vm_write};

use crate::migration::servtd_ext::read_servtd_ext;
#[cfg(feature = "spdm_attestation")]
use crate::spdm;
use crate::{event_log, migration::transport::*};
use crypto::hash::digest_sha384;

Expand Down Expand Up @@ -421,6 +423,22 @@ pub async fn start_rebinding(
MIGTD_REBIND_OP_FINALIZE => rebinding_old_finalize(info, data).await?,
_ => return Err(MigrationResult::InvalidParameter),
}

#[cfg(feature = "spdm_attestation")]
match info.operation {
MIGTD_REBIND_OP_PREPARE => {
rebinding_old_prepare(
transport,
info,
data,
#[cfg(feature = "policy_v2")]
remote_policy,
)
.await?
}
MIGTD_REBIND_OP_FINALIZE => rebinding_old_finalize(info, data).await?,
_ => return Err(MigrationResult::InvalidParameter),
}
} else {
let pre_session_data = Box::pin(with_timeout(
PRE_SESSION_TIMEOUT,
Expand Down Expand Up @@ -450,8 +468,23 @@ pub async fn start_rebinding(
MIGTD_REBIND_OP_FINALIZE => rebinding_new_finalize(info, data).await?,
_ => return Err(MigrationResult::InvalidParameter),
}
}

#[cfg(feature = "spdm_attestation")]
match info.operation {
MIGTD_REBIND_OP_PREPARE => {
rebinding_new_prepare(
transport,
info,
data,
#[cfg(feature = "policy_v2")]
pre_session_data,
)
.await?
}
MIGTD_REBIND_OP_FINALIZE => rebinding_new_finalize(info, data).await?,
_ => return Err(MigrationResult::InvalidParameter),
}
}
#[cfg(feature = "vmcall-raw")]
{
use crate::migration::logging::entrylog;
Expand All @@ -466,7 +499,101 @@ pub async fn start_rebinding(
Ok(())
}

#[cfg(feature = "spdm_attestation")]
pub async fn rebinding_old_prepare(
transport: TransportType,
info: &RebindingInfo,
_data: &mut Vec<u8>,
#[cfg(feature = "policy_v2")] remote_policy: Vec<u8>,
) -> Result<(), MigrationResult> {
use core::ops::DerefMut;

const SPDM_TIMEOUT: Duration = Duration::from_secs(60); // 60 seconds
let (mut spdm_requester, device_io_ref) = spdm::spdm_requester(transport).map_err(|_e| {
log::error!(
"rebinding: Failed in spdm_requester transport. Migration ID: {}\n",
info.mig_request_id
);
MigrationResult::SecureSessionError
})?;
with_timeout(
SPDM_TIMEOUT,
spdm::spdm_requester_rebind_old(
&mut spdm_requester,
info,
#[cfg(feature = "policy_v2")]
remote_policy,
),
)
.await
.map_err(|e| {
log::error!(
"rebinding: spdm_requester_rebind_old timeout error: {:?}\n",
e
);
e
})?
.map_err(|e| {
log::error!("rebinding: spdm_requester_rebind_old error: {:?}\n", e);
e
})?;
log::info!("Rebind completed\n");

let mut transport_lock = device_io_ref.lock();
let transport = transport_lock.deref_mut();
shutdown_transport(&mut transport.transport, info.mig_request_id).await?;
Ok(())
}

#[cfg(feature = "spdm_attestation")]
pub async fn rebinding_new_prepare(
transport: TransportType,
info: &RebindingInfo,
_data: &mut Vec<u8>,
#[cfg(feature = "policy_v2")] remote_policy: Vec<u8>,
) -> Result<(), MigrationResult> {
use core::ops::DerefMut;

const SPDM_TIMEOUT: Duration = Duration::from_secs(60); // 60 seconds
let (mut spdm_responder, device_io_ref) = spdm::spdm_responder(transport).map_err(|_e| {
log::error!(
"rebinding: Failed in spdm_responder transport. Migration ID: {}\n",
info.mig_request_id
);
MigrationResult::SecureSessionError
})?;

with_timeout(
SPDM_TIMEOUT,
spdm::spdm_responder_rebind_new(
&mut spdm_responder,
info,
#[cfg(feature = "policy_v2")]
remote_policy,
),
)
.await
.map_err(|e| {
log::error!(
"rebinding: spdm_responder_rebind_new timeout error: {:?}\n",
e
);
e
})?
.map_err(|e| {
log::error!("rebinding: spdm_responder_rebind_new error: {:?}\n", e);
e
})?;
log::info!("Rebind completed\n");

let mut transport_lock = device_io_ref.lock();
let transport = transport_lock.deref_mut();
shutdown_transport(&mut transport.transport, info.mig_request_id).await?;
Ok(())
}

#[cfg(not(feature = "spdm_attestation"))]
async fn rebinding_old_prepare(
transport: TransportType,
info: &RebindingInfo,
init_migtd_data: &InitData,
Expand Down Expand Up @@ -517,6 +644,7 @@ pub async fn rebinding_old_finalize(
Ok(())
}

#[cfg(not(feature = "spdm_attestation"))]
async fn rebinding_new_prepare(
transport: TransportType,
info: &RebindingInfo,
Expand Down Expand Up @@ -623,7 +751,7 @@ fn get_servtd_ext_from_cert(certs: &Option<Vec<&[u8]>>) -> Result<ServtdExt, Mig
}
}

fn create_rebind_token(info: &RebindingInfo) -> Result<RebindingToken, MigrationResult> {
pub fn create_rebind_token(info: &RebindingInfo) -> Result<RebindingToken, MigrationResult> {
let mut token = [0u8; 32];
let rng = SystemRandom::new();
rng.fill(&mut token)
Expand Down
1 change: 1 addition & 0 deletions src/migtd/src/migration/servtd_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
pub const TDCS_FIELD_SERVTD_ACCEPT_SERVTD_EXT_HASH: u64 = 0x1910000300000214;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct ServtdExt {
pub init_servtd_info_hash: [u8; 48],
pub init_attr: [u8; 8],
Expand Down Expand Up @@ -140,7 +141,7 @@
}

mod test {
use super::ServtdExt;

Check warning on line 144 in src/migtd/src/migration/servtd_ext.rs

View workflow job for this annotation

GitHub Actions / Format

unused import: `super::ServtdExt`

Check warning on line 144 in src/migtd/src/migration/servtd_ext.rs

View workflow job for this annotation

GitHub Actions / Format

unused import: `super::ServtdExt`

#[test]
fn test_structure_sizes() {
Expand Down
2 changes: 1 addition & 1 deletion src/migtd/src/ratls/server_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ fn gen_quote(public_key: &[u8]) -> Result<Vec<u8>> {
})
}

fn gen_tdreport(public_key: &[u8]) -> Result<TdxReport> {
pub fn gen_tdreport(public_key: &[u8]) -> Result<TdxReport> {
let hash = digest_sha384(public_key).map_err(|e| {
log::error!("Failed to compute SHA384 digest: {:?}\n", e);
e
Expand Down
6 changes: 6 additions & 0 deletions src/migtd/src/spdm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

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

#[cfg(all(feature = "main", feature = "policy_v2", feature = "vmcall-raw"))]
mod spdm_rebind;
mod spdm_req;
mod spdm_rsp;
mod spdm_vdm;
Expand All @@ -25,6 +27,10 @@ use zeroize::ZeroizeOnDrop;
use async_io::AsyncRead;
use async_io::AsyncWrite;
use crypto::hash::digest_sha384;
#[cfg(all(feature = "main", feature = "policy_v2", feature = "vmcall-raw"))]
pub use spdm_rebind::spdm_requester_rebind_old;
#[cfg(all(feature = "main", feature = "policy_v2", feature = "vmcall-raw"))]
pub use spdm_rebind::spdm_responder_rebind_new;
pub use spdm_req::spdm_requester;
pub use spdm_req::spdm_requester_transfer_msk;
pub use spdm_rsp::spdm_responder;
Expand Down
85 changes: 85 additions & 0 deletions src/migtd/src/spdm/spdm_rebind.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (c) 2026 Intel Corporation
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
use crate::{
migration::{rebinding::RebindingInfo, MigtdMigrationInformation},
spdm::{
spdm_req::{
send_and_receive_pub_key, send_and_receive_sdm_rebind_attest_info,
send_and_receive_sdm_rebind_info,
},
spdm_rsp::{rsp_handle_message, ResponderContextEx, ResponderContextExInfo},
PrivateKeyDer, SpdmAppContextData,
},
};
use alloc::boxed::Box;
use alloc::vec::Vec;
use codec::{Codec, Writer};
use spdmlib::{
error::{SpdmStatus, SPDM_STATUS_BUFFER_FULL},
protocol::SpdmMeasurementSummaryHashType,
requester::RequesterContext,
};
use zeroize::Zeroize;

pub async fn spdm_requester_rebind_old(
spdm_requester: &mut RequesterContext,
rebind_info: &RebindingInfo,
remote_policy: Vec<u8>,
) -> Result<(), SpdmStatus> {
Box::pin(spdm_requester.send_receive_spdm_version()).await?;
Box::pin(spdm_requester.send_receive_spdm_capability()).await?;
Box::pin(spdm_requester.send_receive_spdm_algorithm()).await?;

Box::pin(send_and_receive_pub_key(spdm_requester)).await?;
let session_id = Box::pin(spdm_requester.send_receive_spdm_key_exchange(
0xff,
SpdmMeasurementSummaryHashType::SpdmMeasurementSummaryHashTypeNone,
))
.await?;

Box::pin(send_and_receive_sdm_rebind_attest_info(
spdm_requester,
rebind_info,
session_id,
remote_policy,
))
.await?;

Box::pin(spdm_requester.send_receive_spdm_finish(Some(0xff), session_id)).await?;

Box::pin(send_and_receive_sdm_rebind_info(
spdm_requester,
rebind_info,
Some(session_id),
))
.await?;

Box::pin(spdm_requester.send_receive_spdm_end_session(session_id)).await?;
Ok(())
}

pub async fn spdm_responder_rebind_new<'a>(
spdm_responder_ex: &mut ResponderContextEx<'a>,
rebind_info: &'a RebindingInfo,
remote_policy: Vec<u8>,
) -> Result<(), SpdmStatus> {
spdm_responder_ex.remote_policy = remote_policy;
spdm_responder_ex.info = ResponderContextExInfo::RebindInformation(rebind_info);

let spdm_responder = &mut spdm_responder_ex.responder_context;
let mut writer = Writer::init(&mut spdm_responder.common.app_context_data_buffer);

let responder_app_context = SpdmAppContextData {
migration_info: MigtdMigrationInformation::default(),
private_key: PrivateKeyDer::default(),
};
responder_app_context
.encode(&mut writer)
.map_err(|_| SPDM_STATUS_BUFFER_FULL)?;

Box::pin(rsp_handle_message(spdm_responder)).await?;
spdm_responder.common.app_context_data_buffer.zeroize();

Ok(())
}
Loading
Loading