From 5a114c201e7e26bb81320b7095ddc158cf532b1b Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Thu, 19 Oct 2023 08:15:26 +0200 Subject: [PATCH] Add experimental TDX attester/verifier crate (#35) The az-snp-vtpm crate has been generalized into an az-cvm-vtpm workspace and extended to support attestation workflows on Azure TDX CVMs, which are in limited preview at the moment. The attestation workflow on TDX CVMs has a lot in common with the equivalent process on SEV-SNP CVMs, so in the future we'll probably want to consolidate both into a common az-cvm-vtpm crate. Until TDX CVMs on are generally available on Azure, we'll want to keep both crates seperate, as the offering is still subject to change. Signed-off-by: Magnus Kulke --- .github/workflows/e2e.yaml | 2 +- .github/workflows/rust.yml | 14 ++-- Readme.md | 4 +- {az-snp-vtpm => az-cvm-vtpm}/.gitignore | 1 + az-cvm-vtpm/Cargo.toml | 7 ++ az-cvm-vtpm/README.md | 11 +++ .../az-snp-vtpm}/Cargo.toml | 5 +- .../az-snp-vtpm}/Makefile | 0 .../az-snp-vtpm}/README.md | 14 ++-- .../az-snp-vtpm}/arm/cvm.bicep | 0 .../az-snp-vtpm}/example/Cargo.toml | 2 +- .../az-snp-vtpm}/example/src/main.rs | 0 .../az-snp-vtpm}/src/amd_kds.rs | 0 .../az-snp-vtpm}/src/certs.rs | 0 .../az-snp-vtpm}/src/hcl.rs | 0 .../az-snp-vtpm}/src/imds.rs | 0 .../az-snp-vtpm}/src/lib.rs | 0 .../az-snp-vtpm}/src/main.rs | 0 .../az-snp-vtpm}/src/report.rs | 0 .../az-snp-vtpm}/src/vtpm.rs | 0 .../az-snp-vtpm}/test/akpub.pem | 0 .../az-snp-vtpm}/test/certs.pem | 0 .../az-snp-vtpm}/test/hcl-report.bin | Bin .../az-snp-vtpm}/test/quote_msg | Bin .../az-snp-vtpm}/test/quote_sig | Bin .../az-snp-vtpm}/test/var-data.bin | 0 az-cvm-vtpm/az-tdx-vtpm/Cargo.toml | 35 ++++++++ az-cvm-vtpm/az-tdx-vtpm/README.md | 21 +++++ az-cvm-vtpm/az-tdx-vtpm/src/imds.rs | 44 ++++++++++ az-cvm-vtpm/az-tdx-vtpm/src/lib.rs | 38 +++++++++ az-cvm-vtpm/az-tdx-vtpm/src/main.rs | 20 +++++ az-cvm-vtpm/az-tdx-vtpm/src/tdx.rs | 77 ++++++++++++++++++ az-cvm-vtpm/az-tdx-vtpm/src/verify.rs | 42 ++++++++++ az-cvm-vtpm/az-tdx-vtpm/test/hcl_report.bin | Bin 0 -> 2600 bytes 34 files changed, 312 insertions(+), 25 deletions(-) rename {az-snp-vtpm => az-cvm-vtpm}/.gitignore (82%) create mode 100644 az-cvm-vtpm/Cargo.toml create mode 100644 az-cvm-vtpm/README.md rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/Cargo.toml (95%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/Makefile (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/README.md (96%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/arm/cvm.bicep (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/example/Cargo.toml (90%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/example/src/main.rs (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/src/amd_kds.rs (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/src/certs.rs (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/src/hcl.rs (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/src/imds.rs (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/src/lib.rs (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/src/main.rs (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/src/report.rs (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/src/vtpm.rs (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/test/akpub.pem (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/test/certs.pem (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/test/hcl-report.bin (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/test/quote_msg (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/test/quote_sig (100%) rename {az-snp-vtpm => az-cvm-vtpm/az-snp-vtpm}/test/var-data.bin (100%) create mode 100644 az-cvm-vtpm/az-tdx-vtpm/Cargo.toml create mode 100644 az-cvm-vtpm/az-tdx-vtpm/README.md create mode 100644 az-cvm-vtpm/az-tdx-vtpm/src/imds.rs create mode 100644 az-cvm-vtpm/az-tdx-vtpm/src/lib.rs create mode 100644 az-cvm-vtpm/az-tdx-vtpm/src/main.rs create mode 100644 az-cvm-vtpm/az-tdx-vtpm/src/tdx.rs create mode 100644 az-cvm-vtpm/az-tdx-vtpm/src/verify.rs create mode 100644 az-cvm-vtpm/az-tdx-vtpm/test/hcl_report.bin diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index f2e5446..03f3f55 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -1,7 +1,7 @@ name: e2e on: - pull_request: + push: branches: [ "main" ] jobs: diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 3f879db..1fa9f77 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -11,15 +11,17 @@ env: jobs: build: - runs-on: ubuntu-latest + defaults: + run: + working-directory: az-cvm-vtpm steps: + - uses: actions/checkout@v3 + - name: Install deps run: sudo apt-get update && sudo apt-get install -y libtss2-dev - - uses: actions/checkout@v3 - - uses: actions-rs/toolchain@v1 with: profile: minimal @@ -34,24 +36,18 @@ jobs: - name: Build run: cargo build --verbose --all - working-directory: az-snp-vtpm - name: Check verifier-only run: cargo check --verbose --no-default-features --features=verifier - working-directory: az-snp-vtpm - name: Check attester-only run: cargo check --verbose --no-default-features --features=attester - working-directory: az-snp-vtpm - name: Run tests run: cargo test --verbose --all - working-directory: az-snp-vtpm - name: Format run: cargo fmt --all -- --check - working-directory: az-snp-vtpm - name: Lint run: cargo clippy --all-targets --all-features --all -- -D warnings - working-directory: az-snp-vtpm diff --git a/Readme.md b/Readme.md index 8c5076b..65bc976 100644 --- a/Readme.md +++ b/Readme.md @@ -2,6 +2,6 @@ Assorted tools and libraries to use with [Azure CVMs](https://azure.microsoft.com/en-us/solutions/confidential-compute/). -# vTPM-SNP +## az-cvm-vtpm -Library and CLI to integrate with vTPM on SEV-SNP enabled machines. +Attestation for Azure Confidential Virtual Machines diff --git a/az-snp-vtpm/.gitignore b/az-cvm-vtpm/.gitignore similarity index 82% rename from az-snp-vtpm/.gitignore rename to az-cvm-vtpm/.gitignore index 76127cf..db4322b 100644 --- a/az-snp-vtpm/.gitignore +++ b/az-cvm-vtpm/.gitignore @@ -1,3 +1,4 @@ target arm/*.json Cargo.lock +*.swp diff --git a/az-cvm-vtpm/Cargo.toml b/az-cvm-vtpm/Cargo.toml new file mode 100644 index 0000000..51bbed9 --- /dev/null +++ b/az-cvm-vtpm/Cargo.toml @@ -0,0 +1,7 @@ +[workspace] +members = [ + "az-snp-vtpm", + "az-tdx-vtpm", + "az-snp-vtpm/example", +] +resolver = "2" diff --git a/az-cvm-vtpm/README.md b/az-cvm-vtpm/README.md new file mode 100644 index 0000000..0351d6b --- /dev/null +++ b/az-cvm-vtpm/README.md @@ -0,0 +1,11 @@ +# az-cvm-vtpm + +Attestation for Azure Confidential Virtual Machines + +## az-snp-vtpm + +Attestation Library for Azure AMD SEV-SNP Confidential Virtual Machines. + +## az-tdx-vtpm + +Attestation Library for Azure Intel TDX Confidential Virtual Machines (Limited Preview). diff --git a/az-snp-vtpm/Cargo.toml b/az-cvm-vtpm/az-snp-vtpm/Cargo.toml similarity index 95% rename from az-snp-vtpm/Cargo.toml rename to az-cvm-vtpm/az-snp-vtpm/Cargo.toml index f3a5c57..ac8a411 100644 --- a/az-snp-vtpm/Cargo.toml +++ b/az-cvm-vtpm/az-snp-vtpm/Cargo.toml @@ -29,13 +29,10 @@ sev = "1.2.0" sha2 = "0.10.6" static_assertions = "^1.1.0" thiserror = "1.0.38" -tss-esapi = "7.2" +tss-esapi = "7.4" ureq = { version = "2.6.2", default-features = false, features = ["json"] } [features] default = ["attester", "verifier"] attester = [] verifier = ["openssl", "sev/openssl", "ureq/tls"] - -[workspace] -members = ["example"] diff --git a/az-snp-vtpm/Makefile b/az-cvm-vtpm/az-snp-vtpm/Makefile similarity index 100% rename from az-snp-vtpm/Makefile rename to az-cvm-vtpm/az-snp-vtpm/Makefile diff --git a/az-snp-vtpm/README.md b/az-cvm-vtpm/az-snp-vtpm/README.md similarity index 96% rename from az-snp-vtpm/README.md rename to az-cvm-vtpm/az-snp-vtpm/README.md index 3e08425..4ab38c9 100644 --- a/az-snp-vtpm/README.md +++ b/az-cvm-vtpm/az-snp-vtpm/README.md @@ -1,10 +1,8 @@ -# az-snp-vtpm - [![Rust](https://github.com/kinvolk/azure-cvm-tooling/actions/workflows/rust.yml/badge.svg)](https://github.com/kinvolk/azure-cvm-tooling/actions/workflows/rust.yml) [![Crate](https://img.shields.io/crates/v/az-snp-vtpm.svg)](https://crates.io/crates/az-snp-vtpm) [![Docs](https://docs.rs/rand/badge.svg)](https://docs.rs/az-snp-vtpm) -**vTPM based SEV-SNP attestation for Azure Confidential VMs** +# az-snp-vtpm This library enables guest attestation flows for [SEV-SNP CVMs on Azure](https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-vm-overview). Please refer to the documentation in [this repository](https://github.com/Azure/confidential-computing-cvm-guest-attestation) for details on the attestation procedure. @@ -20,8 +18,8 @@ make deploy ## Build & Install ```bash -cargo b --release -scp target/release/snp-vtpm azureuser@$CONFIDENTIAL_VM: +cargo b --release -p az-snp-vtpm +scp ../target/release/snp-vtpm azureuser@$CONFIDENTIAL_VM: ``` ## Run Binary @@ -37,7 +35,7 @@ sudo ./snp-vtpm -p There is a project in the `./example` folder depicting how the crate can be leveraged in a Remote Attestation flow. **Note:** the code is merely illustrative and doesn't feature exhaustive validation, which would be required in a production scenario. ```bash -cargo b -p example +cargo b -p snp-example ``` ## SEV-SNP Report & vTPM @@ -56,12 +54,12 @@ The vTPM is linked to the SEV-SNP report via the vTPM Attestation Key (AK). The │ └──────────────────────┘ │ │ └────────────────────┘ │ │ │ │ ┌──────────────┐ │ └──────────────────────┬─┘ ─┘ │ │ │ vTPM Quote │ │ ┌────────────────────┐ │ │ - │ │ │ │ │ HCL Report │ │ │ + │ │ │ │ │ HCL Report │ │ │ signs ┌─ ┌─┴────────────┐ │ │ │ │ │ sha256 │ │ │ Message │ │ │ │ ┌────────────────┐ │ │ │ │ │ │ │ │ │ │ │ SEV-SNP Report │ │ │ │ │ │ │ ┌──────────┐ │ │ │ │ │ │ │ │ │ - │ │ │ │ PCR0 │ │ │ │ │ │ ┌──────────────┴─┴─┴─┐ │ + │ │ │ │ PCR0 │ │ │ │ │ │ ┌──────────────┴─┴─┴─┐ │ │ │ │ └──────────┘ │ │ │ │ │ │ Report Data │ ◄───┘ │ │ │ ... │ │ │ │ │ └──────────────┬─┬─┬─┘ │ │ │ ┌──────────┐ │ │ │ │ └────────────────┘ │ │ diff --git a/az-snp-vtpm/arm/cvm.bicep b/az-cvm-vtpm/az-snp-vtpm/arm/cvm.bicep similarity index 100% rename from az-snp-vtpm/arm/cvm.bicep rename to az-cvm-vtpm/az-snp-vtpm/arm/cvm.bicep diff --git a/az-snp-vtpm/example/Cargo.toml b/az-cvm-vtpm/az-snp-vtpm/example/Cargo.toml similarity index 90% rename from az-snp-vtpm/example/Cargo.toml rename to az-cvm-vtpm/az-snp-vtpm/example/Cargo.toml index acd6472..3088086 100644 --- a/az-snp-vtpm/example/Cargo.toml +++ b/az-cvm-vtpm/az-snp-vtpm/example/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "example" +name = "snp-example" version = "0.1.0" edition = "2021" diff --git a/az-snp-vtpm/example/src/main.rs b/az-cvm-vtpm/az-snp-vtpm/example/src/main.rs similarity index 100% rename from az-snp-vtpm/example/src/main.rs rename to az-cvm-vtpm/az-snp-vtpm/example/src/main.rs diff --git a/az-snp-vtpm/src/amd_kds.rs b/az-cvm-vtpm/az-snp-vtpm/src/amd_kds.rs similarity index 100% rename from az-snp-vtpm/src/amd_kds.rs rename to az-cvm-vtpm/az-snp-vtpm/src/amd_kds.rs diff --git a/az-snp-vtpm/src/certs.rs b/az-cvm-vtpm/az-snp-vtpm/src/certs.rs similarity index 100% rename from az-snp-vtpm/src/certs.rs rename to az-cvm-vtpm/az-snp-vtpm/src/certs.rs diff --git a/az-snp-vtpm/src/hcl.rs b/az-cvm-vtpm/az-snp-vtpm/src/hcl.rs similarity index 100% rename from az-snp-vtpm/src/hcl.rs rename to az-cvm-vtpm/az-snp-vtpm/src/hcl.rs diff --git a/az-snp-vtpm/src/imds.rs b/az-cvm-vtpm/az-snp-vtpm/src/imds.rs similarity index 100% rename from az-snp-vtpm/src/imds.rs rename to az-cvm-vtpm/az-snp-vtpm/src/imds.rs diff --git a/az-snp-vtpm/src/lib.rs b/az-cvm-vtpm/az-snp-vtpm/src/lib.rs similarity index 100% rename from az-snp-vtpm/src/lib.rs rename to az-cvm-vtpm/az-snp-vtpm/src/lib.rs diff --git a/az-snp-vtpm/src/main.rs b/az-cvm-vtpm/az-snp-vtpm/src/main.rs similarity index 100% rename from az-snp-vtpm/src/main.rs rename to az-cvm-vtpm/az-snp-vtpm/src/main.rs diff --git a/az-snp-vtpm/src/report.rs b/az-cvm-vtpm/az-snp-vtpm/src/report.rs similarity index 100% rename from az-snp-vtpm/src/report.rs rename to az-cvm-vtpm/az-snp-vtpm/src/report.rs diff --git a/az-snp-vtpm/src/vtpm.rs b/az-cvm-vtpm/az-snp-vtpm/src/vtpm.rs similarity index 100% rename from az-snp-vtpm/src/vtpm.rs rename to az-cvm-vtpm/az-snp-vtpm/src/vtpm.rs diff --git a/az-snp-vtpm/test/akpub.pem b/az-cvm-vtpm/az-snp-vtpm/test/akpub.pem similarity index 100% rename from az-snp-vtpm/test/akpub.pem rename to az-cvm-vtpm/az-snp-vtpm/test/akpub.pem diff --git a/az-snp-vtpm/test/certs.pem b/az-cvm-vtpm/az-snp-vtpm/test/certs.pem similarity index 100% rename from az-snp-vtpm/test/certs.pem rename to az-cvm-vtpm/az-snp-vtpm/test/certs.pem diff --git a/az-snp-vtpm/test/hcl-report.bin b/az-cvm-vtpm/az-snp-vtpm/test/hcl-report.bin similarity index 100% rename from az-snp-vtpm/test/hcl-report.bin rename to az-cvm-vtpm/az-snp-vtpm/test/hcl-report.bin diff --git a/az-snp-vtpm/test/quote_msg b/az-cvm-vtpm/az-snp-vtpm/test/quote_msg similarity index 100% rename from az-snp-vtpm/test/quote_msg rename to az-cvm-vtpm/az-snp-vtpm/test/quote_msg diff --git a/az-snp-vtpm/test/quote_sig b/az-cvm-vtpm/az-snp-vtpm/test/quote_sig similarity index 100% rename from az-snp-vtpm/test/quote_sig rename to az-cvm-vtpm/az-snp-vtpm/test/quote_sig diff --git a/az-snp-vtpm/test/var-data.bin b/az-cvm-vtpm/az-snp-vtpm/test/var-data.bin similarity index 100% rename from az-snp-vtpm/test/var-data.bin rename to az-cvm-vtpm/az-snp-vtpm/test/var-data.bin diff --git a/az-cvm-vtpm/az-tdx-vtpm/Cargo.toml b/az-cvm-vtpm/az-tdx-vtpm/Cargo.toml new file mode 100644 index 0000000..9d69e58 --- /dev/null +++ b/az-cvm-vtpm/az-tdx-vtpm/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "az-tdx-vtpm" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +path = "src/lib.rs" + +[[bin]] +name = "tdx-vtpm" +path = "src/main.rs" + +[dependencies] +anyhow = "1.0.75" +base64-url = "2.0.0" +bincode = "1.3.3" +jsonwebkey = { version = "0.3.5", features = ["pkcs-convert"] } +memoffset = "0.9.0" +serde = { version = "1.0.189", features = ["derive"] } +serde-big-array = "0.5.1" +serde_json = "1.0.107" +sha2 = "0.10.8" +tss-esapi = "7.4" +ureq = { version = "2.6.2", default-features = false, features = ["json"] } +az-snp-vtpm = { path = "../az-snp-vtpm" } +sev = "1.2.0" +thiserror = "1.0.49" +openssl = { version = "0.10", optional = true } + +[features] +default = ["attester", "verifier"] +attester = [] +verifier = ["az-snp-vtpm/verifier", "openssl"] diff --git a/az-cvm-vtpm/az-tdx-vtpm/README.md b/az-cvm-vtpm/az-tdx-vtpm/README.md new file mode 100644 index 0000000..cc5421c --- /dev/null +++ b/az-cvm-vtpm/az-tdx-vtpm/README.md @@ -0,0 +1,21 @@ +# az-tdx-vtpm + +[![Rust](https://github.com/kinvolk/azure-cvm-tooling/actions/workflows/rust.yml/badge.svg)](https://github.com/kinvolk/azure-cvm-tooling/actions/workflows/rust.yml) + +> [!WARNING] +> This library enables guest attestation and verification for [TDX CVMs on Azure](https://learn.microsoft.com/en-us/azure/confidential-computing/tdx-confidential-vm-overview). TDX CVMs are currently in limited preview and hence the library is considered experimental and subject to change. + +## Build & Install + +```bash +cargo b --release -p az-tdx-vtpm +scp ../target/release/tdx-vtpm azureuser@$CONFIDENTIAL_VM: +``` + +## Run Binary + +On the TDX CVM, retrieve a TD Quote and write it to disk: + +```bash +sudo ./tdx-vtpm +``` diff --git a/az-cvm-vtpm/az-tdx-vtpm/src/imds.rs b/az-cvm-vtpm/az-tdx-vtpm/src/imds.rs new file mode 100644 index 0000000..9b70f56 --- /dev/null +++ b/az-cvm-vtpm/az-tdx-vtpm/src/imds.rs @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use serde::Deserialize; +use thiserror::Error; + +const IMDS_QUOTE_URL: &str = "http://169.254.169.254/acc/tdquote"; + +#[derive(Error, Debug)] +pub enum ImdsError { + #[error("http error")] + HttpError(#[from] Box), + #[error("base64 error")] + Base64Error(#[from] base64_url::base64::DecodeError), + #[error("io error")] + IoError(#[from] std::io::Error), +} + +pub struct ReportBody { + report: String, +} + +impl ReportBody { + pub fn new(report_bytes: &[u8]) -> Self { + let report = base64_url::encode(report_bytes); + Self { report } + } +} + +#[derive(Clone, Debug, Deserialize)] +struct QuoteResponse { + quote: String, +} + +pub fn get_td_quote(report_body: ReportBody) -> Result, ImdsError> { + let response: QuoteResponse = ureq::post(IMDS_QUOTE_URL) + .send_json(ureq::json!({ + "report": report_body.report, + })) + .map_err(Box::new)? + .into_json()?; + let quote = base64_url::decode(&response.quote)?; + Ok(quote) +} diff --git a/az-cvm-vtpm/az-tdx-vtpm/src/lib.rs b/az-cvm-vtpm/az-tdx-vtpm/src/lib.rs new file mode 100644 index 0000000..ee22b54 --- /dev/null +++ b/az-cvm-vtpm/az-tdx-vtpm/src/lib.rs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +//! This library enables guest attestation flows for [TDX CVMs on Azure](https://learn.microsoft.com/en-us/azure/confidential-computing/tdx-confidential-vm-overview). TDX CVMs are currently in limited preview and hence the library is considered experimental and subject to change. +//! # +//! ```no_run +//! use az_tdx_vtpm::{imds, hcl, vtpm}; +//! use std::error::Error; +//! +//! fn main() -> Result<(), Box> { +//! let bytes = vtpm::get_report()?; +//! let hcl_report = hcl::HclReport::new(bytes)?; +//! let tdx_report_slice = hcl_report.tdx_report_slice(); +//! let report_body = imds::ReportBody::new(tdx_report_slice); +//! let td_quote_bytes = imds::get_td_quote(report_body)?; +//! let hash = hcl_report.var_data_sha256(); +//! println!("var_data hash: {:x?}", hash); +//! std::fs::write("td_quote.bin", td_quote_bytes)?; +//! Ok(()) +//! } +//! ``` + +pub use az_snp_vtpm::vtpm; + +pub mod hcl; +pub mod imds; +pub mod tdx; +#[cfg(feature = "verifier")] +pub mod verify; + +pub fn is_tdx_cvm() -> Result { + let bytes = vtpm::get_report()?; + let Ok(hcl_report) = hcl::HclReport::new(bytes) else { + return Ok(false); + }; + let is_tdx = hcl_report.report_type() == hcl::ReportType::Tdx; + Ok(is_tdx) +} diff --git a/az-cvm-vtpm/az-tdx-vtpm/src/main.rs b/az-cvm-vtpm/az-tdx-vtpm/src/main.rs new file mode 100644 index 0000000..37f9268 --- /dev/null +++ b/az-cvm-vtpm/az-tdx-vtpm/src/main.rs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use anyhow::Result; +use az_tdx_vtpm::{hcl, imds, vtpm}; + +fn main() -> Result<()> { + let bytes = vtpm::get_report()?; + let hcl_report = hcl::HclReport::new(bytes)?; + + let hash = hcl_report.var_data_sha256(); + println!("var_data hash: {:x?}", hash); + + let tdx_report_slice = hcl_report.tdx_report_slice(); + let report_body = imds::ReportBody::new(tdx_report_slice); + let td_quote_bytes = imds::get_td_quote(report_body)?; + std::fs::write("td_quote.bin", td_quote_bytes)?; + + Ok(()) +} diff --git a/az-cvm-vtpm/az-tdx-vtpm/src/tdx.rs b/az-cvm-vtpm/az-tdx-vtpm/src/tdx.rs new file mode 100644 index 0000000..47f240f --- /dev/null +++ b/az-cvm-vtpm/az-tdx-vtpm/src/tdx.rs @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use serde::{Deserialize, Serialize}; +use serde_big_array::BigArray; + +const TDX_REPORT_DATA_LENGTH: usize = 64; + +#[repr(C)] +#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct TdxReportMac { + pub report_type: u8, + pub report_sub_type: u8, + pub report_version: u8, + pub reserved_type_mbz: u8, + pub reserved_mbz1: [u8; 12], + pub cpu_svn: [u8; 16], + #[serde(with = "BigArray")] + pub tee_tcb_info_hash: [u8; 48], + #[serde(with = "BigArray")] + pub tee_info_hash: [u8; 48], + #[serde(with = "BigArray")] + pub report_data: [u8; TDX_REPORT_DATA_LENGTH], + pub reserved_mbz2: [u8; 32], + pub mac: [u8; 32], +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct TdxTeeTcbInfo { + pub tee_valid: [u8; 8], + pub tee_tcb_svn: [u8; 16], + #[serde(with = "BigArray")] + pub tee_mr_seam: [u8; 48], + #[serde(with = "BigArray")] + pub tee_mr_seam_signer: [u8; 48], + pub tee_attributes: [u8; 8], + pub tee_tcb_svn2: [u8; 16], + #[serde(with = "BigArray")] + pub tee_reserved: [u8; 95], +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct TdxRtmr { + #[serde(with = "BigArray")] + pub register_data: [u8; 48], +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct TdxTdInfo { + pub attributes: [u8; 8], + pub xfam: [u8; 8], + #[serde(with = "BigArray")] + pub mrtd: [u8; 48], + #[serde(with = "BigArray")] + pub mr_config_id: [u8; 48], + #[serde(with = "BigArray")] + pub mr_owner: [u8; 48], + #[serde(with = "BigArray")] + pub mr_owner_config: [u8; 48], + pub rtrm: [TdxRtmr; 4], + #[serde(with = "BigArray")] + pub serv_td: [u8; 48], + #[serde(with = "BigArray")] + pub reserved_mbz: [u8; 64], +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct TdxVmReport { + pub tdx_report_mac: TdxReportMac, + pub tdx_tee_tcb_info: TdxTeeTcbInfo, + pub tdx_reserved: [u8; 17], + pub tdx_td_info: TdxTdInfo, +} diff --git a/az-cvm-vtpm/az-tdx-vtpm/src/verify.rs b/az-cvm-vtpm/az-tdx-vtpm/src/verify.rs new file mode 100644 index 0000000..4c106f9 --- /dev/null +++ b/az-cvm-vtpm/az-tdx-vtpm/src/verify.rs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use az_snp_vtpm::vtpm; +use openssl::hash::MessageDigest; +use openssl::pkey::{PKey, Public}; +use openssl::sign::Verifier; +use thiserror::Error; +use tss_esapi::structures::Attest; +use tss_esapi::traits::UnMarshall; + +#[derive(Error, Debug)] +pub enum VerifyError { + #[error("tss error")] + Tss(#[from] tss_esapi::Error), + #[error("openssl error")] + OpenSsl(#[from] openssl::error::ErrorStack), + #[error("quote is not signed by key")] + SignatureMismatch, + #[error("nonce mismatch")] + NonceMismatch, +} + +pub trait Verify { + fn verify(&self, pub_key: &PKey, nonce: &[u8]) -> Result<(), VerifyError>; +} + +impl Verify for vtpm::Quote { + fn verify(&self, pub_key: &PKey, nonce: &[u8]) -> Result<(), VerifyError> { + let mut verifier = Verifier::new(MessageDigest::sha256(), pub_key)?; + verifier.update(&self.message)?; + let is_verified = verifier.verify(&self.signature)?; + if !is_verified { + return Err(VerifyError::SignatureMismatch); + } + let attest = Attest::unmarshall(&self.message)?; + if nonce != attest.extra_data().as_slice() { + return Err(VerifyError::NonceMismatch); + } + Ok(()) + } +} diff --git a/az-cvm-vtpm/az-tdx-vtpm/test/hcl_report.bin b/az-cvm-vtpm/az-tdx-vtpm/test/hcl_report.bin new file mode 100644 index 0000000000000000000000000000000000000000..a71bad597847fdcfde51e37239416faa00413630 GIT binary patch literal 2600 zcmeHHU8odg7~YeIL!PT55{n4k>Y{RF&+hEbjwCpLyR$p{dv^BsVAK5V?(FQ$?ELP` z+9`j?v{ElL0}~C52st98RA^YHiEzkFrLM#zA?e0SiIU(nClm5?5r$9~emC#?KJWMb zeBb*$ABkmU{*8}E4?OY8^SeHH$~AmcVJ-g>GI(?$P z;J)X6TK$p!7(e{3`H8r4q3}iJ{&SbUJQf+f{Qka)%RhMR)Dvzm=^mn_fG3=ITay@zL$b*%wal+qU-A?K2xr9xBKWui19| z! zWn$0tI(R30aPK4h=2-BsI9jBBQ(xM!{*E?rH`(1Am~#Ush68~iAM?c@@;zT!6_iEK z3@)4S6-fv#3zGgPCl_okxMbGDXuVly(3DzgaHS7fp1)_jg!pdJ*N`HD`l{-yW=qr( zzL~-DI_OminIa;Qa)`p1Tq6y|qe&(ihw4J4+Cke99l|MGO+q1;Mr}CDF|l?Tj@Wpn zB9uL?t<*vT-p)gAOF}4^m-r7i@+JN0X36=-NwR21=dq-yjDO{jBZm9 z%1Uw2MImyG)?G-*Dh4XVWG_=L5ERxX5*p!V^<215vKheO0Tgs;i!d=8YH}$yZWKzb zO08UFvJS1_RR$c$)lgn4i(IEFz<&F>1LVqdc^q*D`LYgmQ;rmkCL3JOOG)iE*+<%` zJ|0Hks$`CLqF^yNx#TaCA^tuYQRNMUB7$fR*`XRZYxPC4lE})6E5`uJ zEV)*3ysPmrUWyke!gkUW>EZPpj&fBr9}Cwq1vWGG!5xN2X;PzjNRyl59(B3`RVbh=ojfH4*>0?ld~ZW-B10x#qRl<~rGqXAG{!eC*H zk)m-emyQTI0nWKe3N;70cNH;VdGab>%!ez!*RJz#ZVvSa&hb3L2 zD6kkMU|N+=Q3E%PFjl)_acm({Y!@MsYtcL)rw2(*bl?sZ>SdYESc&n6<5R*>0A5p@ zQp+}2OVWHQtP1*osdYs_R9UVo`n0kPTU-(}G|d8d(XarkZ7W>QkW|ZOPE2hy)H<8y zK}s(-7|%ff#pV-2J*U}Dx1gqIHJ7cKWETkeTr)-9Hbj8)a|M?**{w+EYq)(I5>v;?=NVZ Wq5%l3#riR!|9Ax_=X`4aL-Tj%Bm#B- literal 0 HcmV?d00001