Skip to content

Commit

Permalink
attestation-service: add az-tdx-vtpm verifier
Browse files Browse the repository at this point in the history
- Added verification code
- Added tdx fixtures and test cases
- Reorganized snp fixtures
- Added missing dependency for tdx e2e test
- Added entry for e2e test

Co-authored-by: Xynnn_ <[email protected]>

Signed-off-by: Magnus Kulke <[email protected]>
  • Loading branch information
mkulke committed Jan 16, 2024
1 parent 5a4163c commit 360a4eb
Show file tree
Hide file tree
Showing 19 changed files with 176 additions and 13 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ chrono = "0.4.19"
clap = { version = "4", features = ["derive"] }
env_logger = "0.10.0"
hex = "0.4.3"
kbs-types = "0.5"
kbs-types = "0.5.3"
log = "0.4.17"
prost = "0.11.0"
rstest = "0.18.1"
Expand Down
2 changes: 1 addition & 1 deletion attestation-service/attestation-service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ all-verifier = [ "verifier/all-verifier" ]
tdx-verifier = [ "verifier/tdx-verifier" ]
sgx-verifier = [ "verifier/sgx-verifier" ]
az-snp-vtpm-verifier = [ "verifier/az-snp-vtpm-verifier" ]
az-tdx-vtpm-verifier = [ "verifier/az-tdx-vtpm-verifier" ]
snp-verifier = [ "verifier/snp-verifier" ]
csv-verifier = [ "verifier/csv-verifier" ]
cca-verifier = [ "verifier/cca-verifier" ]
Expand Down Expand Up @@ -42,7 +43,6 @@ clap = { workspace = true, optional = true }
env_logger = { workspace = true, optional = true }
futures = "0.3.17"
hex.workspace = true
# TODO: change it to "0.5", once released.
kbs-types.workspace = true
lazy_static = "1.4.0"
log.workspace = true
Expand Down
4 changes: 3 additions & 1 deletion attestation-service/verifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ edition = "2021"

[features]
default = [ "all-verifier" ]
all-verifier = [ "tdx-verifier", "sgx-verifier", "snp-verifier", "az-snp-vtpm-verifier", "csv-verifier", "cca-verifier" ]
all-verifier = [ "tdx-verifier", "sgx-verifier", "snp-verifier", "az-snp-vtpm-verifier", "az-tdx-vtpm-verifier", "csv-verifier", "cca-verifier" ]
tdx-verifier = [ "eventlog-rs", "scroll", "sgx-dcap-quoteverify-rs" ]
sgx-verifier = [ "scroll", "sgx-dcap-quoteverify-rs" ]
az-snp-vtpm-verifier = [ "az-snp-vtpm", "sev", "snp-verifier" ]
az-tdx-vtpm-verifier = [ "az-tdx-vtpm", "openssl", "tdx-verifier" ]
snp-verifier = [ "asn1-rs", "openssl", "sev", "x509-parser" ]
csv-verifier = [ "openssl", "csv-rs", "codicon" ]
cca-verifier = [ "ear", "veraison-apiclient" ]
Expand All @@ -18,6 +19,7 @@ anyhow.workspace = true
asn1-rs = { version = "0.5.1", optional = true }
async-trait.workspace = true
az-snp-vtpm = { version = "0.4", default-features = false, features = ["verifier"], optional = true }
az-tdx-vtpm = { version = "0.4", default-features = false, features = ["verifier"], optional = true }
base64 = "0.21"
bincode = "1.3.3"
byteorder = "1"
Expand Down
12 changes: 6 additions & 6 deletions attestation-service/verifier/src/az_snp_vtpm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,16 +125,16 @@ fn verify_snp_report(
mod tests {
use super::*;

const REPORT: &[u8; 2048] = include_bytes!("../../test_data/az-hcl-data.bin");
const SIGNATURE: &[u8; 256] = include_bytes!("../../test_data/az-vtpm-quote-sig.bin");
const MESSAGE: &[u8; 122] = include_bytes!("../../test_data/az-vtpm-quote-msg.bin");
const REPORT: &[u8; 2048] = include_bytes!("../../test_data/az-snp-vtpm/hcl-report.bin");
const SIGNATURE: &[u8; 256] = include_bytes!("../../test_data/az-snp-vtpm/tpm-quote.sig");
const MESSAGE: &[u8; 122] = include_bytes!("../../test_data/az-snp-vtpm/tpm-quote.msg");
const REPORT_DATA: &[u8] = "challenge".as_bytes();

#[test]
fn test_verify_snp_report() {
let hcl_report = HclReport::new(REPORT.to_vec()).unwrap();
let snp_report = hcl_report.try_into().unwrap();
let vcek = Vcek::from_pem(include_str!("../../test_data/az-vcek.pem")).unwrap();
let vcek = Vcek::from_pem(include_str!("../../test_data/az-snp-vtpm/vcek.pem")).unwrap();
let vendor_certs = load_milan_cert_chain().as_ref().unwrap();
verify_snp_report(&snp_report, &vcek, vendor_certs).unwrap();
}
Expand All @@ -146,7 +146,7 @@ mod tests {
wrong_report[0x00b0] = 0;
let hcl_report = HclReport::new(wrong_report.to_vec()).unwrap();
let snp_report = hcl_report.try_into().unwrap();
let vcek = Vcek::from_pem(include_str!("../../test_data/az-vcek.pem")).unwrap();
let vcek = Vcek::from_pem(include_str!("../../test_data/az-snp-vtpm/vcek.pem")).unwrap();
let vendor_certs = load_milan_cert_chain().as_ref().unwrap();
verify_snp_report(&snp_report, &vcek, vendor_certs).unwrap_err();
}
Expand Down Expand Up @@ -197,7 +197,7 @@ mod tests {
signature: SIGNATURE.to_vec(),
message: MESSAGE.to_vec(),
};
let report = include_bytes!("../../test_data/az-hcl-data.bin");
let report = include_bytes!("../../test_data/az-snp-vtpm/hcl-report.bin");
let hcl_report = HclReport::new(report.to_vec()).unwrap();
let mut report_data = REPORT_DATA.to_vec();
report_data.reverse();
Expand Down
146 changes: 146 additions & 0 deletions attestation-service/verifier/src/az_tdx_vtpm/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Copyright (c) Microsoft Corporation.
//
// SPDX-License-Identifier: Apache-2.0
//

use super::tdx::claims::generate_parsed_claim;
use super::tdx::quote::{ecdsa_quote_verification, parse_tdx_quote, Quote as TdQuote};
use super::{TeeEvidenceParsedClaim, Verifier};
use crate::{regularize_data, InitDataHash, ReportData};
use anyhow::{bail, Context, Result};
use async_trait::async_trait;
use az_tdx_vtpm::hcl::HclReport;
use az_tdx_vtpm::vtpm::Quote as TpmQuote;
use log::{debug, warn};
use openssl::pkey::PKey;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct Evidence {
tpm_quote: TpmQuote,
hcl_report: Vec<u8>,
td_quote: Vec<u8>,
}

#[derive(Default)]
pub struct AzTdxVtpm;

#[async_trait]
impl Verifier for AzTdxVtpm {
/// The following verification steps are performed:
/// 1. TPM Quote has been signed by AK included in the HCL variable data
/// 2. Attestation nonce matches TPM Quote nonce
/// 3. TD Quote is genuine
/// 4. TD Report's report_data field matches hashed HCL variable data
async fn evaluate(
&self,
evidence: &[u8],
expected_report_data: &ReportData,
expected_init_data_hash: &InitDataHash,
) -> Result<TeeEvidenceParsedClaim> {
let ReportData::Value(expected_report_data) = expected_report_data else {
bail!("unexpected empty report data");
};
let expected_report_data =
regularize_data(expected_report_data, 64, "REPORT_DATA", "Azure TDX vTPM");

if let InitDataHash::Value(_) = expected_init_data_hash {
warn!("Azure TDX vTPM verifier does not support verify init data hash, will ignore the input `init_data_hash`");
}

let evidence = serde_json::from_slice::<Evidence>(evidence)
.context("Failed to deserialize Azure vTPM TDX evidence")?;

let hcl_report = HclReport::new(evidence.hcl_report)?;
verify_tpm_quote(&evidence.tpm_quote, &hcl_report, &expected_report_data)?;

ecdsa_quote_verification(&evidence.td_quote).await?;
let td_quote = parse_tdx_quote(&evidence.td_quote)?;

verify_report_data(&hcl_report, &td_quote)?;

let claim = generate_parsed_claim(td_quote, None)?;
Ok(claim)
}
}

fn verify_report_data(hcl_report: &HclReport, td_quote: &TdQuote) -> Result<()> {
let var_data_hash = hcl_report.var_data_sha256();
if var_data_hash != td_quote.report_body.report_data[..32] {
bail!("TDX Quote report data mismatch");
}
debug!("Report data verification completed successfully.");
Ok(())
}

fn verify_tpm_quote(quote: &TpmQuote, hcl_report: &HclReport, report_data: &[u8]) -> Result<()> {
let ak_pub = hcl_report.ak_pub().context("Failed to get AKpub")?;
let der = ak_pub.key.try_to_der()?;
let ak_pub = PKey::public_key_from_der(&der).context("Failed to parse AKpub")?;

quote
.verify(&ak_pub, report_data)
.context("Failed to verify vTPM quote")?;
Ok(())
}

#[cfg(test)]
mod tests {
use super::*;

const REPORT: &[u8; 2600] = include_bytes!("../../test_data/az-tdx-vtpm/hcl-report.bin");
const SIGNATURE: &[u8; 256] = include_bytes!("../../test_data/az-tdx-vtpm/tpm-quote.sig");
const MESSAGE: &[u8; 126] = include_bytes!("../../test_data/az-tdx-vtpm/tpm-quote.msg");
const TD_QUOTE: &[u8; 5006] = include_bytes!("../../test_data/az-tdx-vtpm/td-quote.bin");

#[test]
fn test_verify_report_data() {
let hcl_report = HclReport::new(REPORT.to_vec()).unwrap();
let td_quote = parse_tdx_quote(TD_QUOTE).unwrap();
verify_report_data(&hcl_report, &td_quote).unwrap();
}

#[test]
fn test_verify_report_data_failure() {
let mut wrong_report = REPORT.clone();
wrong_report[0x0880] += 1;
let hcl_report = HclReport::new(wrong_report.to_vec()).unwrap();
let td_quote = parse_tdx_quote(TD_QUOTE).unwrap();
verify_report_data(&hcl_report, &td_quote).unwrap_err();
}

#[test]
fn test_verify_quote() {
let quote = TpmQuote {
signature: SIGNATURE.to_vec(),
message: MESSAGE.to_vec(),
};
let hcl_report = HclReport::new(REPORT.to_vec()).unwrap();
let nonce = "tdx challenge".as_bytes();
verify_tpm_quote(&quote, &hcl_report, nonce).unwrap();
}

#[test]
fn test_verify_quote_signature_failure() {
let mut wrong_message = MESSAGE.clone();
wrong_message.reverse();
let wrong_quote = TpmQuote {
signature: SIGNATURE.to_vec(),
message: wrong_message.to_vec(),
};
let hcl_report = HclReport::new(REPORT.to_vec()).unwrap();
let nonce = "tdx challenge".as_bytes();
verify_tpm_quote(&wrong_quote, &hcl_report, nonce).unwrap_err();
}

#[test]
fn test_verify_quote_nonce_failure() {
let quote = TpmQuote {
signature: SIGNATURE.to_vec(),
message: MESSAGE.to_vec(),
};
let hcl_report = HclReport::new(REPORT.to_vec()).unwrap();
let nonce = "wrong".as_bytes();
verify_tpm_quote(&quote, &hcl_report, nonce).unwrap_err();
}
}
13 changes: 12 additions & 1 deletion attestation-service/verifier/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ pub mod sample;
#[cfg(feature = "az-snp-vtpm-verifier")]
pub mod az_snp_vtpm;

#[cfg(feature = "az-tdx-vtpm-verifier")]
pub mod az_tdx_vtpm;

#[cfg(feature = "snp-verifier")]
pub mod snp;

Expand Down Expand Up @@ -38,6 +41,15 @@ pub fn to_verifier(tee: &Tee) -> Result<Box<dyn Verifier + Send + Sync>> {
}
}
}
Tee::AzTdxVtpm => {
cfg_if::cfg_if! {
if #[cfg(feature = "az-tdx-vtpm-verifier")] {
Ok(Box::<az_tdx_vtpm::AzTdxVtpm>::default() as Box<dyn Verifier + Send + Sync>)
} else {
bail!("feature `az-tdx-vtpm-verifier` is not enabled for `verifier` crate.");
}
}
}
Tee::Tdx => {
cfg_if::cfg_if! {
if #[cfg(feature = "tdx-verifier")] {
Expand Down Expand Up @@ -87,7 +99,6 @@ pub fn to_verifier(tee: &Tee) -> Result<Box<dyn Verifier + Send + Sync>> {
}
}
}
Tee::AzTdxVtpm => todo!(),
}
}

Expand Down
4 changes: 2 additions & 2 deletions attestation-service/verifier/src/tdx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ use eventlog::{CcEventLog, Rtmr};
use quote::{ecdsa_quote_verification, parse_tdx_quote};
use serde::{Deserialize, Serialize};

mod claims;
pub(crate) mod claims;
mod eventlog;
mod quote;
pub(crate) mod quote;

#[derive(Serialize, Deserialize, Debug)]
struct TdxEvidence {
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
3 changes: 2 additions & 1 deletion kbs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ This project relies on the [Attestation-Service (AS)](https://github.com/confide
The following TEE platforms are currently supported:

- AMD SEV-SNP
- Azure SNP vTPM
- Azure SEV-SNP vTPM
- Azure TDX vTPM
- Intel SGX
- Intel TDX

Expand Down
1 change: 1 addition & 0 deletions kbs/src/api/src/attestation/coco/grpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub const COCO_AS_HASH_ALGORITHM: &str = "sha384";
fn to_grpc_tee(tee: Tee) -> GrpcTee {
match tee {
Tee::AzSnpVtpm => GrpcTee::AzSnpVtpm,
Tee::AzTdxVtpm => GrpcTee::AzTdxVtpm,
Tee::Cca => GrpcTee::Cca,
Tee::Csv => GrpcTee::Csv,
Tee::Sample => GrpcTee::Sample,
Expand Down
1 change: 1 addition & 0 deletions kbs/test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ install-dependencies:
sudo apt-get install -y \
build-essential \
clang \
libsgx-dcap-default-qpl \
libsgx-dcap-quote-verify-dev \
libtdx-attest-dev \
libtss2-dev \
Expand Down

0 comments on commit 360a4eb

Please sign in to comment.