Skip to content

Conversation

@bodzhang
Copy link
Contributor

This commit introduces comprehensive Azure CVM emulation capabilities to enable
MigTD development and testing as a standard Rust application inside an Azure TDX CVM,
while exercising almost all MigTDCore code and flows, including RA-TLS/SPDM with TDX Quote
and migration policy enforcement.

Key Features

Emulation Infrastructure:

  • Relevant td-shim interfaces emulation under deps/td-shim-AzCVMEmu/
  • Relevant TDX TDCALL emulation
  • MigTD Quote emulation by Azure TDX CVM virtual FW Quote, or mock TD REPORT and Quote
  • Event logging emulation with CCEL (CC Event Log) interface
  • Interrupt handling emulation
  • File-based policy and root CA configuration loading
  • TCP transport layer for source/destination communication

MigTDCore Integration:

  • Conditional compilation support via AzCVMEmu feature flag
  • Command-line interface with argument parsing and help
  • Standard library (std) support for development workflows

Development and Testing Support:

  • migtdemu.sh runner script with automatic environment detection
  • CI/CD integration with GitHub Actions workflow
  • Documentation in doc/AzCVMEmu.md
  • test_disable_ra_and_accept_all support for mock attestation, enabling build and integration test on generic Linux machine

Usage Modes

Development/Testing (Azure TDX CVM + TPM2-TSS):

cargo build --no-default-features --features "AzCVMEmu" --bin migtd

Development/Testing (any Linux system):

cargo build --no-default-features --features "AzCVMEmu,test_disable_ra_and_accept_all" --bin migtd

This PR enables comprehensive end-to-end testing of MigTD's
RATLS/SPDM flow, v1-policy enforcement, and migration workflows in a broadly available development
environments. An follow-up PR will add emulation support for v2-policy.

Special acknowledgments:

  • src/attestation/fixup-libservtd-attest-lib.sh: Investigation, design and implementation by Mike Brasher [email protected]

Co-authored-by: Haitao Huang [email protected]
Signed-off-by: Bo Zhang (ACC) [email protected]

@bodzhang bodzhang requested a review from jyao1 as a code owner October 30, 2025 00:39
@bodzhang bodzhang force-pushed the azcvmemu-for-upstream branch from a2d7385 to 15b1460 Compare October 30, 2025 00:49
@@ -0,0 +1,136 @@
# TDX TDCALL TCP Emulation for Azure CVM

This crate provides a drop-in replacement for the original `tdx-tdcall` crate that emulates TDX VMCALL operations using TCP transport. This enables MigTD development and testing in non-TDX environments.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am thinking if we should add td-shim-AzCVMEmu to td-shim project, instead of MigTD project.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

td-shim-AzCVMEmu layer does not fully emulate tdshim interface, only the interfaces used by MigTD in vmcall-raw transport mode. In my opinion, adding partial emulation in tdshim project will cause confusion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, that means, if some other projects are using td-shim, it cannot benefit from this?

Please forgive my ignorance, here is a general question:
Can a developer do the emulation by himself/herself, by implementing emulated content? Or he/she must rely on MSFT to implement the emulated content?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A developer can definitely implement his/her own emulation for certain tdshim interfaces. In this PR, the implementation of emulating MigTD REPORT/QUOTE with Azure TDX CVM virtual firmware REPORT/QUOTE utilizes Azure TDX CVM specific vTPM and IMDS (http endpoint) interfaces. The interface definition is published. Emulation of other supported tdshim interfaces in this PR do not have Azure-specific dependency.

Copy link
Contributor

@jyao1 jyao1 Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the contradiction here.
On one hand, you want to use CVM to handle REPORT/QUOTE.
On the other hand, you say that CVM cannot emulate REPORT because REPORTDATA is handled in a different way and you want to skip.

Question: Is this a MUST that we have to use CVM to emulate REPORT/QUOTE and no other way? Why we stick to CVM?
Or, do you think if it is possible to use the same CVM way to verify REPORT, e.g. append something to original REPORTDTA? With this, we do not skip, but use emulation-specific way to verify. The benefit that the original logic can still be validated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Emulating MigTD REPORT/QUOTE with Azure TDX CVM firmware REPORT/QUOTE gives us a simple way to exercise significant portion of MigTD code logic related to Quote generation/verification and Policy enforcement in the emulation environment. Even if the Emulation mode can't support some of the MigTD code logic related to REPORTDATA check or RTMR check, I still see the benefit of excising verify_quote_with_collaterals() code flow and platform tcbdate related Policy enforcement code flow. Adding Azure CVM REPORTDATA specific verification code in emulation mode can be done, but it still does not exercise the HW-mode MigTD code for REPORTDATA verification.

Comment on lines 410 to 411

#[cfg(not(feature = "test_disable_ra_and_accept_all"))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this related to Azure CVM?
Or is it only a bug for test_disable_ra_and_accept_all feature?

If later, I think we need a dedicated PR. Please don't mix all good work in one (big) patch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is required to pass AzCVMEmu mode PR pipeline test when spdm_attestation feature is enabled. AzCVMEmu mode PE pipeline test runs on standard Github Linux VM, using mock REPORT/QUOTE, and requires test_disable_ra_and_accept_all flag. The changes are not general, to enable test_disable_ra_and_accept_all in spdm_attestation, not directly related to AzCVMEmu mode. We can move them to a separate PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the file from this PR

let mut additional_data = [0u8; 64];
additional_data[..hash.len()].copy_from_slice(hash.as_ref());
let td_report = tdx_tdcall::tdreport::tdcall_report(&additional_data)?;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why change this ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likely a missed extra format change. Will remove from the PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the update of the PR.

Comment on lines +280 to +288
if cfg!(feature = "AzCVMEmu") {
// In AzCVMEmu mode, REPORTDATA is constructed differently.
// Bypass public key hash check in this development environment.
log::warn!(
"AzCVMEmu mode: Skipping public key verification in TD report. This is NOT secure for production use.\n"
);
return Ok(());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the comment. Why it is constructed differently?
Why we cannot use the original way?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In AzCVMEmu mode Azure TDX CVM firmware's REPORT/QUOTE are used to simulate MigTD QUOTE. The API to get Azure TDX CVM firmware REPORT does support passing in data to be included in REPORTDATA, but the API automatically append extra data to the passed in data, hash them all together, then set REPORTDATA. As the result, the public key hash check against REPORTDATA of the simulated QUOTE will always fail.

Copy link
Contributor

@jyao1 jyao1 Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My question is why it cannot pass the REPORTDATA, which is a fundamental feature for TDREPORT generation. Or why it has to "automatically append extra data"?

For emulation, I hope to emulate as much as possible to reduce the change the real code.
Otherwise, we must patch here and there. And it is easy broken.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To verify the public key hash with Azure TDX CVM firmware QUOTE, the verification code will be significantly different from the HW-mode code. The verification code would need to get the extra data the Azure TDX CVM API appended to the datablob whose digest is REPORTDATA. The extra data appended to calculate the digest is not part of REPORT/QUOTE. The extra data is part of higher layer lib Azure provides. What's more, the Azure TDX CVM environment does not support extending RTMR, so it's not possible to use the exact same verification code logic in the AzCVMEmu mode as in HW mode.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Then I think the description "MigTD Quote emulation by Azure TDX CVM virtual FW Quote, or mock TD REPORT and Quote" is very confusing.
It seems REPORT and Quote are NOT supported at all, if the right REPORTDATA cannot be passed in.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend to list a set of feature not supported, to remind people the limitation.
Otherwise, people will think a feature is validated, but actually it is NOT.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add a limitation section in the AzCVMEmu doc.

#[cfg(not(feature = "AzCVMEmu"))]
use tdx_tdcall;
#[cfg(feature = "AzCVMEmu")]
use tdx_tdcall_emu as tdx_tdcall;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we merge this into td-shim project and let td-shim project control that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

d-shim-AzCVMEmu layer does not fully emulate tdshim interface, only the interfaces used by MigTD in vmcall-raw transport mode. In my opinion, adding partial emulation in tdshim project will cause confusion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partial interface should be fine. We can document the scope of emulation.
My point is that: the change should be in right place to benefit all consumers.

Comment on lines +16 to +25
#[cfg(not(feature = "AzCVMEmu"))]
use td_payload::acpi::get_acpi_tables;
#[cfg(feature = "AzCVMEmu")]
use td_shim_emu::event_log::{get_acpi_tables, MockCcel as Ccel};
#[cfg(not(feature = "AzCVMEmu"))]
use td_shim_interface::acpi::Ccel;
#[cfg(not(feature = "AzCVMEmu"))]
use tdx_tdcall::tdx;
#[cfg(feature = "AzCVMEmu")]
use tdx_tdcall_emu::tdx;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we merge this into td-shim project and let td-shim project control that?

Comment on lines +7 to +11

#[cfg(not(feature = "AzCVMEmu"))]
use td_shim_interface::td_uefi_pi::{fv, pi};
#[cfg(feature = "AzCVMEmu")]
use td_shim_interface_emu::td_uefi_pi::{fv, pi};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we merge this into td-shim project and let td-shim project control that?


// Conditionally compile collateral for AzCVMEmu mode
#[cfg(feature = "AzCVMEmu")]
mod collateral;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we need collateral for AzCVMEmu?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Azure environment, getting Quote Verification Collateral such as TCBINFO, QEIdentity at run time is not supported. For v1-policy build, this hardcoded Collateral is needed. With v2-policy build, Collateral will be from the v2 Policy file, and hardcoded Collateral is not required.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not clear on this part. Quote verification should be "software only". It is not related to hardware. What prevents the Quote verification in emulation mode?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quote verification process uses the Collateral. For v1-policy build, the HW-mode implementation of MigTD retrieves the Collateral from outside of MigTD. The mechanism is not supported in Azure environment.

Copy link
Contributor

@jyao1 jyao1 Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you worry V1-policy, can we drop V1-policy in emulation mode, and only support V2-policy in emulation mode?
I think we only support test_disable_ra_and_accept_all and raw-data, it is fine to add one more constrain.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once AzCVMEmu emulation support for v2-policy is ready, removing v1-policy support in AzCVMEmu mode to avoid code deviation from HW mode is an option.

AzCVMEmu mode does support exercising QUOTE generation/verification and policy enforcement, which are not exercised in test_disable_ra_and_accept_all. If test_disable_ra_and_accept_all is not enabled in AzCVMEmu mode, the emulation layer will retrieve and return Azure TDX CVM's virtual firmware REPORT/QUOTE to the emulation mode MigTD. MigTD code logic related to Quote generation/verification and Policy enforcement will all be exercised. With test_disable_ra_and_accept_all enabled in AzCVMEmu mode, the emulation mode MigTD skips QUOTE/Policy related code flow and can run on any Linux machine or VM.

@jyao1
Copy link
Contributor

jyao1 commented Oct 30, 2025

I think it is a good feature. Some general comment:

  1. The patch is too big. 61 files change in 1 commit. It is hard for review. I suggest to split the commit.
  • Especially for the one irrelevant to AzCVMEmu, or some pre-work. For example, the fix for test_disable_ra_and_accept_all should be in a dedicated PR. Also some "easy" fixes, such as remove comma, remove space, remove line. Please submit a patch to fix those typo. I think those are easy to review and merge.
  • This PR should only handle AzCVMEmu. Nothing else.
  1. I am wondering if we merge AzCVMEmu feature to td-shim. I assume that can help to enable AzCVMEmu for other project which is using td-shim. No need to duplicate code.
  2. If possible, I recommend we reduce the usage of "feature = "AzCVMEmu". The interface is to allow us hide the implementation detail. If we can figure out a way to use existing API, we should.
  3. license header is required for the new files.

@@ -0,0 +1,16 @@
use interrupt_emu as intr;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need license header

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the update of this PR.

@@ -0,0 +1,30 @@
// Interrupt emulation registry for AzCVMEmu.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need license header.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the update of this PR.

@@ -0,0 +1,23 @@
#![cfg_attr(not(test), no_std)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need license header.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the update of this PR.

@bodzhang bodzhang force-pushed the azcvmemu-for-upstream branch 2 times, most recently from a86f430 to 8b1a590 Compare October 30, 2025 17:14
@jyao1
Copy link
Contributor

jyao1 commented Oct 31, 2025

Hi
Thanks to address the license header comment. However, it should not be addressed in a dedicated commit, such as 4ac741c.
The license header should come together with the original code.

The rule to split the commit should be based on feature, but not how the code is developed.

…testing

This commit introduces comprehensive Azure CVM emulation capabilities to enable
MigTD development and testing as a standard Rust application inside an Azure TDX CVM,
while exercising almost all MigTDCore code and flows, including RA-TLS with TDX Quote
and migration policy enforcement.

**Emulation Infrastructure:**
- Relevant td-shim interfaces emulation under `deps/td-shim-AzCVMEmu/`
- Relevant TDX TDCALL emulation
- MigTD Quote emulation by Azure TDX CVM virtual FW Quote, or mock TD REPORT and Quote
- Event logging emulation with CCEL (CC Event Log) interface
- Interrupt handling emulation
- File-based policy and root CA configuration loading
- TCP transport layer for source/destination communication

**MigTDCore Integration:**
- Conditional compilation support via `AzCVMEmu` feature flag
- Command-line interface with argument parsing and help
- Standard library (std) support for development workflows

**Development and Testing Support:**
- `migtdemu.sh` runner script with automatic environment detection
- CI/CD integration with GitHub Actions workflow
- Documentation in `doc/AzCVMEmu.md`
- `test_disable_ra_and_accept_all` support for mock attestation, enabling build and integration test on generic Linux machine

**Development/Testing (Azure TDX CVM + TPM2-TSS):**
```bash
cargo build --no-default-features --features "AzCVMEmu" --bin migtd
```

**Development/Testing (any Linux system):**
```bash
cargo build --no-default-features --features "AzCVMEmu,test_disable_ra_and_accept_all" --bin migtd
```

This implementation enables comprehensive end-to-end testing of MigTD's
RATLS, policy enforcement, and migration workflows in a broadly available development
environments.

Special acknowledgments:
- src/attestation/fixup-libservtd-attest-lib.sh: Investigation, design and implementation by Mike Brasher <[email protected]>

Co-authored-by: Haitao Huang <[email protected]>
Signed-off-by: Bo Zhang (ACC) <[email protected]>
@bodzhang bodzhang force-pushed the azcvmemu-for-upstream branch from 4ac741c to 51cc38d Compare October 31, 2025 19:31
@bodzhang
Copy link
Contributor Author

Hi Thanks to address the license header comment. However, it should not be addressed in a dedicated commit, such as 4ac741c. The license header should come together with the original code.

The rule to split the commit should be based on feature, but not how the code is developed.

Thanks for pointing out the expectation. The PR is updated, with the second commit squashed with the first one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants