Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verifeir: Add support for TDX quote v5 #354

Merged
merged 2 commits into from
Mar 28, 2024
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
6 changes: 5 additions & 1 deletion attestation-service/docs/parsed_claims.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ The following fields are optional. Whether they appear depends on whether there
- `tdx.ccel.kernel_parameters.*`: different kernel parameter items. For example `console=hvc0` will be parsed into a claim `"tdx.ccel.kernel_parameters.console": "hvc0"`. `rw` will be parsed into a claim `"tdx.ccel.kernel_parameters.rw": null`.

The following fields always exist.
- `tdx.quote.header.version`: for TDX this field is always 4.
- `tdx.quote.header.version`: The quote format version. Now supports 4 and 5.
- `tdx.quote.header.att_key_type`: enum of the algorithm used in signature.
- `tdx.quote.header.tee_type`: TDX is always 0x81.
- `tdx.quote.header.reserved`: reserved.
Expand All @@ -45,6 +45,10 @@ The following fields always exist.
- `tdx.quote.body.rtmr_1`: Runtime measurement register 1.
- `tdx.quote.body.rtmr_2`: Runtime measurement register 2.
- `tdx.quote.body.rtmr_3`: Runtime measurement register 3.
- `tdx.quote.type`: Indicating quote v5 type. 2 means TDX 1.0 quote and 3 means TDX 1.5 quote. Only quote format V5 contains this field.
- `tdx.quote.size`: Quote body length. Only quote format V5 contains this field.
- `tdx.quote.body.tee_tcb_svn2`: Array of TEE TCB SVNs (for TD preserving).
- `tdx.quote.body.mr_servicetd`: If there is one or more bound or pre-bound service TDs, this field is the SHA384 hash of the `TDINFO`s of those service TDs bound. Else, this field is 0.

## Intel SGX

Expand Down
2 changes: 1 addition & 1 deletion attestation-service/verifier/src/az_tdx_vtpm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl Verifier for AzTdxVtpm {

fn verify_hcl_var_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] {
if var_data_hash != td_quote.report_data()[..32] {
bail!("TDX Quote report data mismatch");
}
debug!("Report data verification completed successfully.");
Expand Down
129 changes: 91 additions & 38 deletions attestation-service/verifier/src/tdx/claims.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ use byteorder::{LittleEndian, ReadBytesExt};
use log::{debug, warn};
use serde_json::{Map, Value};

use crate::TeeEvidenceParsedClaim;
use crate::{tdx::quote::QuoteV5Body, TeeEvidenceParsedClaim};

use super::{
eventlog::{CcEventLog, MeasuredEntity},
Expand All @@ -76,41 +76,94 @@ pub fn generate_parsed_claim(
let mut quote_map = Map::new();
let mut quote_body = Map::new();
let mut quote_header = Map::new();
// Claims from TD Quote Header.
parse_claim!(quote_header, "version", quote.header.version);
parse_claim!(quote_header, "att_key_type", quote.header.att_key_type);
parse_claim!(quote_header, "tee_type", quote.header.tee_type);
parse_claim!(quote_header, "reserved", quote.header.reserved);
parse_claim!(quote_header, "vendor_id", quote.header.vendor_id);
parse_claim!(quote_header, "user_data", quote.header.user_data);
// Claims from TD Quote Body. We ignore RTMRs because when verifying the integrity of
// the eventlog (CCEL), they have already been consumed.
parse_claim!(quote_body, "tcb_svn", quote.report_body.tcb_svn);
parse_claim!(quote_body, "mr_seam", quote.report_body.mr_seam);
parse_claim!(quote_body, "mrsigner_seam", quote.report_body.mrsigner_seam);
parse_claim!(
quote_body,
"seam_attributes",
quote.report_body.seam_attributes
);
parse_claim!(quote_body, "td_attributes", quote.report_body.td_attributes);
parse_claim!(quote_body, "xfam", quote.report_body.xfam);
parse_claim!(quote_body, "mr_td", quote.report_body.mr_td);
parse_claim!(quote_body, "mr_config_id", quote.report_body.mr_config_id);
parse_claim!(quote_body, "mr_owner", quote.report_body.mr_owner);
parse_claim!(
quote_body,
"mr_owner_config",
quote.report_body.mr_owner_config
);
parse_claim!(quote_body, "rtmr_0", quote.report_body.rtmr_0);
parse_claim!(quote_body, "rtmr_1", quote.report_body.rtmr_1);
parse_claim!(quote_body, "rtmr_2", quote.report_body.rtmr_2);
parse_claim!(quote_body, "rtmr_3", quote.report_body.rtmr_3);
parse_claim!(quote_body, "report_data", quote.report_body.report_data);

parse_claim!(quote_map, "header", quote_header);
parse_claim!(quote_map, "body", quote_body);

match &quote {
Quote::V4 { header, body } => {
parse_claim!(quote_header, "version", b"\x04\x00");
parse_claim!(quote_header, "att_key_type", header.att_key_type);
parse_claim!(quote_header, "tee_type", header.tee_type);
parse_claim!(quote_header, "reserved", header.reserved);
parse_claim!(quote_header, "vendor_id", header.vendor_id);
parse_claim!(quote_header, "user_data", header.user_data);
parse_claim!(quote_body, "tcb_svn", body.tcb_svn);
parse_claim!(quote_body, "mr_seam", body.mr_seam);
parse_claim!(quote_body, "mrsigner_seam", body.mrsigner_seam);
parse_claim!(quote_body, "seam_attributes", body.seam_attributes);
parse_claim!(quote_body, "td_attributes", body.td_attributes);
parse_claim!(quote_body, "xfam", body.xfam);
parse_claim!(quote_body, "mr_td", body.mr_td);
parse_claim!(quote_body, "mr_config_id", body.mr_config_id);
parse_claim!(quote_body, "mr_owner", body.mr_owner);
parse_claim!(quote_body, "mr_owner_config", body.mr_owner_config);
parse_claim!(quote_body, "rtmr_0", body.rtmr_0);
parse_claim!(quote_body, "rtmr_1", body.rtmr_1);
parse_claim!(quote_body, "rtmr_2", body.rtmr_2);
parse_claim!(quote_body, "rtmr_3", body.rtmr_3);
parse_claim!(quote_body, "report_data", body.report_data);

parse_claim!(quote_map, "header", quote_header);
parse_claim!(quote_map, "body", quote_body);
}
Quote::V5 {
header,
r#type,
size,
body,
} => {
parse_claim!(quote_header, "version", b"\x05\x00");
parse_claim!(quote_header, "att_key_type", header.att_key_type);
parse_claim!(quote_header, "tee_type", header.tee_type);
parse_claim!(quote_header, "reserved", header.reserved);
parse_claim!(quote_header, "vendor_id", header.vendor_id);
parse_claim!(quote_header, "user_data", header.user_data);
parse_claim!(quote_map, "type", r#type.as_bytes());
parse_claim!(quote_map, "size", &size[..]);
match body {
QuoteV5Body::Tdx10(body) => {
parse_claim!(quote_body, "tcb_svn", body.tcb_svn);
parse_claim!(quote_body, "mr_seam", body.mr_seam);
parse_claim!(quote_body, "mrsigner_seam", body.mrsigner_seam);
parse_claim!(quote_body, "seam_attributes", body.seam_attributes);
parse_claim!(quote_body, "td_attributes", body.td_attributes);
parse_claim!(quote_body, "xfam", body.xfam);
parse_claim!(quote_body, "mr_td", body.mr_td);
parse_claim!(quote_body, "mr_config_id", body.mr_config_id);
parse_claim!(quote_body, "mr_owner", body.mr_owner);
parse_claim!(quote_body, "mr_owner_config", body.mr_owner_config);
parse_claim!(quote_body, "rtmr_0", body.rtmr_0);
parse_claim!(quote_body, "rtmr_1", body.rtmr_1);
parse_claim!(quote_body, "rtmr_2", body.rtmr_2);
parse_claim!(quote_body, "rtmr_3", body.rtmr_3);
parse_claim!(quote_body, "report_data", body.report_data);

parse_claim!(quote_map, "header", quote_header);
parse_claim!(quote_map, "body", quote_body);
}
QuoteV5Body::Tdx15(body) => {
parse_claim!(quote_body, "tcb_svn", body.tcb_svn);
parse_claim!(quote_body, "mr_seam", body.mr_seam);
parse_claim!(quote_body, "mrsigner_seam", body.mrsigner_seam);
parse_claim!(quote_body, "seam_attributes", body.seam_attributes);
parse_claim!(quote_body, "td_attributes", body.td_attributes);
parse_claim!(quote_body, "xfam", body.xfam);
parse_claim!(quote_body, "mr_td", body.mr_td);
parse_claim!(quote_body, "mr_config_id", body.mr_config_id);
parse_claim!(quote_body, "mr_owner", body.mr_owner);
parse_claim!(quote_body, "mr_owner_config", body.mr_owner_config);
parse_claim!(quote_body, "rtmr_0", body.rtmr_0);
parse_claim!(quote_body, "rtmr_1", body.rtmr_1);
parse_claim!(quote_body, "rtmr_2", body.rtmr_2);
parse_claim!(quote_body, "rtmr_3", body.rtmr_3);
parse_claim!(quote_body, "report_data", body.report_data);

parse_claim!(quote_body, "tee_tcb_svn2", body.tee_tcb_svn2);
parse_claim!(quote_body, "mr_servicetd", body.mr_servicetd);
parse_claim!(quote_map, "header", quote_header);
parse_claim!(quote_map, "body", quote_body);
}
}
}
}

// Claims from CC EventLog.
let mut ccel_map = Map::new();
Expand All @@ -124,8 +177,8 @@ pub fn generate_parsed_claim(
parse_claim!(claims, "quote", quote_map);
parse_claim!(claims, "ccel", ccel_map);

parse_claim!(claims, "report_data", quote.report_body.report_data);
parse_claim!(claims, "init_data", quote.report_body.mr_config_id);
parse_claim!(claims, "report_data", quote.report_data());
parse_claim!(claims, "init_data", quote.mr_config_id());

log::info!("\nParsed Evidence claims map: \n{:?}\n", &claims);

Expand Down
12 changes: 6 additions & 6 deletions attestation-service/verifier/src/tdx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ async fn verify_evidence(
if let ReportData::Value(expected_report_data) = expected_report_data {
debug!("Check the binding of REPORT_DATA.");
let expected_report_data = regularize_data(expected_report_data, 64, "REPORT_DATA", "TDX");
if expected_report_data != quote.report_body.report_data {
if expected_report_data != quote.report_data() {
bail!("REPORT_DATA is different from that in TDX Quote");
}
}
Expand All @@ -69,7 +69,7 @@ async fn verify_evidence(
debug!("Check the binding of MRCONFIGID.");
let expected_init_data_hash =
regularize_data(expected_init_data_hash, 48, "MRCONFIGID", "TDX");
if expected_init_data_hash != quote.report_body.mr_config_id {
if expected_init_data_hash != quote.mr_config_id() {
bail!("MRCONFIGID is different from that in TDX Quote");
}
}
Expand All @@ -86,10 +86,10 @@ async fn verify_evidence(
log::debug!("Get CC Eventlog. \n{}\n", &ccel.cc_events);

let rtmr_from_quote = Rtmr {
rtmr0: quote.report_body.rtmr_0,
rtmr1: quote.report_body.rtmr_1,
rtmr2: quote.report_body.rtmr_2,
rtmr3: quote.report_body.rtmr_3,
rtmr0: quote.rtmr_0().try_into().expect("must be 48 bytes"),
rtmr1: quote.rtmr_1().try_into().expect("must be 48 bytes"),
rtmr2: quote.rtmr_2().try_into().expect("must be 48 bytes"),
rtmr3: quote.rtmr_3().try_into().expect("must be 48 bytes"),
};

ccel.integrity_check(rtmr_from_quote)?;
Expand Down
Loading
Loading