From f9749e9db2823c8637cc4d0fd3a01d2f33d07fa7 Mon Sep 17 00:00:00 2001 From: Arvind Kumar Date: Thu, 14 Aug 2025 21:22:07 +0000 Subject: [PATCH 1/2] verify: verify measurent, host data, and report data attributes from the attestation report. Adding the ability to verify attestation to verify measurement, host data, and report data attributes from the attestation report. Signed-off-by: Arvind Kumar --- .Cargo.toml.un~ | Bin 0 -> 544 bytes Cargo.lock | 1 + Cargo.toml~ | 41 ++++++++++++++++++++ src/verify.rs | 100 +++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 .Cargo.toml.un~ create mode 100644 Cargo.toml~ diff --git a/.Cargo.toml.un~ b/.Cargo.toml.un~ new file mode 100644 index 0000000000000000000000000000000000000000..e94d6c4b15cba58c40f65eec03e9db41fe53065e GIT binary patch literal 544 zcmWH`%$*;a=aT=Ff$4(hq1`KvY*>BN(zPIS`(d5tN!Kf4mb`v+JjpF2$}a9Y0|SEw z5F-OdAP0m&0LBLMGu~!Lu|P!PFF@o`NRX5!OyoZhz>R?kj?z>N0bq1QLZjoW1khYi lJi>w>6cwU*rMbE#MTwau#R|3xN(OpHdWM!trj5^60RZ!)DT4q2 literal 0 HcmV?d00001 diff --git a/Cargo.lock b/Cargo.lock index db15ea1..1047b22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1576,6 +1576,7 @@ dependencies = [ "hex", "msru", "nix", + "num-traits", "openssl", "rand", "reqwest", diff --git a/Cargo.toml~ b/Cargo.toml~ new file mode 100644 index 0000000..ea98327 --- /dev/null +++ b/Cargo.toml~ @@ -0,0 +1,41 @@ +[package] +name = "snpguest" +version = "0.9.2" +authors = ["The VirTEE Project Developers"] +edition = "2021" +license = "Apache-2.0" +homepage = "https://github.com/virtee/snpguest" +repository = "https://github.com/virtee/snpguest" +description = "Navigation utility for AMD SEV-SNP guest environment" +readme = "README.md" +keywords = ["amd", "sev", "sev-snp", "snp"] +exclude = [ ".gitignore", ".github/*" ] +rust-version = "1.86" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +default = [] +hyperv = ["tss-esapi"] + +[dependencies] +clap = { version = "4.5", features = [ "derive" ] } +env_logger = "0.10.0" +anyhow = "1.0.69" +sev = { version = "=7.1.0", default-features = false, features = ['openssl','snp']} +nix = "^0.23" +serde = { version = "1.0", features = ["derive"] } +bincode = "^1.2.1" +openssl = { version = "^0.10", features = ["vendored"]} +reqwest = { version="=0.11.10", features = ["blocking"] } +hex = "0.4" +x509-parser = { version="=0.16.0", features=["verify"] } +asn1-rs = "=0.6.2" +rand = "0.8.5" +tss-esapi = { version = "7.2", optional=true } +msru = "0.2.0" +colorful = "0.2.2" +bitfield = "0.15.0" +clap-num = "1.1.1" +base64 = "0.22.1" +num-traits = "0.2.19" diff --git a/src/verify.rs b/src/verify.rs index bd972e6..f69681e 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -16,6 +16,8 @@ use openssl::{ecdsa::EcdsaSig, sha::Sha384}; use sev::certs::snp::Chain; use sev::parser::ByteParser; +use hex::FromHex; + #[derive(Subcommand)] pub enum VerifyCmd { /// Verify the certificate chain. @@ -201,6 +203,18 @@ mod attestation { /// Run the Signature Verification Exclusively. #[arg(short, long, conflicts_with = "tcb")] pub signature: bool, + + /// Optional measurement string (hex, 48 bytes / 96 chars) + #[arg(short, long, value_name = "measurement")] + pub measurement: Option, + + /// Optional host_data string (hex, 32 bytes / 64 chars) + #[arg(short = 'd', long, value_name = "host_data")] + pub host_data: Option, + + /// Optional report_data string (hex, 64 bytes / 128 chars) + #[arg(short, long, value_name = "report_data")] + pub report_data: Option, } fn verify_attestation_signature( @@ -418,7 +432,7 @@ mod attestation { .context("Could not open attestation report")? }; - let proc_model = if let Some(proc_model) = args.processor_model { + let proc_model = if let Some(proc_model) = args.processor_model.clone() { proc_model } else { let att_report = report::read_report(args.att_report_path.clone()) @@ -447,6 +461,90 @@ mod attestation { verify_attestation_signature(vek, att_report, quiet)?; } + // Verify optional fields if provided + if args.measurement.is_some() || args.host_data.is_some() || args.report_data.is_some() { + verify_report_fields(&args, &att_report, quiet)?; + } + + Ok(()) + } + + fn decode_hex_or_decimal(input: &str) -> Result> { + // Look for "0x" at beginning. If it exists, treat as a hex. + if let Some(hex_str) = input.strip_prefix("0x") { + return Ok(Vec::from_hex(hex_str)?); + } + else { + Ok(input.as_bytes().to_vec()) + } + } + + fn verify_field( + field_name: &str, + expected: &[u8], + provided: &str, + expected_len: usize, + quiet: bool, + ) -> Result<()> { + let actual = decode_hex_or_decimal(provided)?; + + if actual.len() != expected_len { + return Err(anyhow::anyhow!( + "Expected {} characters for {}, got {}", + expected_len, + field_name, + actual.len() + )); + } + + if expected != actual.as_slice() { + return Err(anyhow::anyhow!( + "{} did not match:\n expected {}\n got {}", + field_name, + hex::encode(expected), + hex::encode(actual) + )); + } + if !quiet { + println!("{} verified successfully.", field_name); + } + + Ok(()) + } + + fn verify_report_fields( + args: &Args, + att_report: &AttestationReport, + quiet: bool, + ) -> Result<()> { + if let Some(measure) = &args.measurement { + verify_field( + "Measurement", + att_report.measurement.as_slice(), + measure, + 48, + quiet, + )?; + } + if let Some(host) = &args.host_data { + verify_field( + "Host Data", + att_report.host_data.as_slice(), + host, + 32, + quiet, + )?; + } + if let Some(report) = &args.report_data { + verify_field( + "Report Data", + att_report.report_data.as_slice(), + report, + 64, + quiet, + )?; + } + Ok(()) } From 99b03261b55e6a690b210d342a868ad50ffead80 Mon Sep 17 00:00:00 2001 From: Arvind Kumar Date: Fri, 19 Sep 2025 20:10:05 +0000 Subject: [PATCH 2/2] Docs: Adding verify measure, host-data, report-data to docs Adding instructions and changes to documentation on how to use the optional features measure, host-data, and report-data features added to the verify attestation command. Signed-off-by: Arvind Kumar --- .Cargo.toml.un~ | Bin 544 -> 0 bytes Cargo.lock | 1 - Cargo.toml~ | 41 ----------------------------------------- README.md | 11 ++++++++++- docs/snpguest.1.adoc | 13 +++++++++++++ src/verify.rs | 7 +++---- 6 files changed, 26 insertions(+), 47 deletions(-) delete mode 100644 .Cargo.toml.un~ delete mode 100644 Cargo.toml~ diff --git a/.Cargo.toml.un~ b/.Cargo.toml.un~ deleted file mode 100644 index e94d6c4b15cba58c40f65eec03e9db41fe53065e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 544 zcmWH`%$*;a=aT=Ff$4(hq1`KvY*>BN(zPIS`(d5tN!Kf4mb`v+JjpF2$}a9Y0|SEw z5F-OdAP0m&0LBLMGu~!Lu|P!PFF@o`NRX5!OyoZhz>R?kj?z>N0bq1QLZjoW1khYi lJi>w>6cwU*rMbE#MTwau#R|3xN(OpHdWM!trj5^60RZ!)DT4q2 diff --git a/Cargo.lock b/Cargo.lock index 1047b22..db15ea1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1576,7 +1576,6 @@ dependencies = [ "hex", "msru", "nix", - "num-traits", "openssl", "rand", "reqwest", diff --git a/Cargo.toml~ b/Cargo.toml~ deleted file mode 100644 index ea98327..0000000 --- a/Cargo.toml~ +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "snpguest" -version = "0.9.2" -authors = ["The VirTEE Project Developers"] -edition = "2021" -license = "Apache-2.0" -homepage = "https://github.com/virtee/snpguest" -repository = "https://github.com/virtee/snpguest" -description = "Navigation utility for AMD SEV-SNP guest environment" -readme = "README.md" -keywords = ["amd", "sev", "sev-snp", "snp"] -exclude = [ ".gitignore", ".github/*" ] -rust-version = "1.86" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[features] -default = [] -hyperv = ["tss-esapi"] - -[dependencies] -clap = { version = "4.5", features = [ "derive" ] } -env_logger = "0.10.0" -anyhow = "1.0.69" -sev = { version = "=7.1.0", default-features = false, features = ['openssl','snp']} -nix = "^0.23" -serde = { version = "1.0", features = ["derive"] } -bincode = "^1.2.1" -openssl = { version = "^0.10", features = ["vendored"]} -reqwest = { version="=0.11.10", features = ["blocking"] } -hex = "0.4" -x509-parser = { version="=0.16.0", features=["verify"] } -asn1-rs = "=0.6.2" -rand = "0.8.5" -tss-esapi = { version = "7.2", optional=true } -msru = "0.2.0" -colorful = "0.2.2" -bitfield = "0.15.0" -clap-num = "1.1.1" -base64 = "0.22.1" -num-traits = "0.2.19" diff --git a/README.md b/README.md index 324ebbd..f609861 100644 --- a/README.md +++ b/README.md @@ -306,7 +306,7 @@ snpguest verify **Usage** ```bash - snpguest verify attestation $CERTS_DIR $ATT_REPORT_PATH [-t, --tcb] [-s, --signature] + snpguest verify attestation $CERTS_DIR $ATT_REPORT_PATH [-t, --tcb] [-s, --signature] [-m, --measurement] [-d, --host-data] [-r, --report-data] ``` **Arguments** @@ -318,6 +318,9 @@ snpguest verify - `-t, --tcb`: Verify the Reported TCB section of the report only. - `-s, --signature`: Verify the signature of the report only. + - `-m, --measurement`: Verify the measurement from the attestation report. + - `-d, --host-data`: Verify the host-data from the attestation report. + - `-r, --report-data`: Verify the report-data from the attestation report. **Example** ```bash @@ -327,6 +330,12 @@ snpguest verify snpguest verify attestation ./certs attestation-report.bin --tcb # Verify Attestation Signature only snpguest verify attestation ./certs attestation-report.bin --signature + # Verify Attestation Measurement only + snpguest verify attestation --measurement 0xf28aac58964258d8ae0b2e88a706fc7afd0bb524f6a291ac3eedeccb73f89d7cfcf2e4fb6045e7d5201e41d1726afa02 /home/amd/certs /home/amd/report.bin + # Verify Attestation host-data only + snpguest verify attestation --host-data 0x7e4a3f9c1b82a056d39f0d44e5c8a7b1f02394de6b58ac0d7e3c11af0042bd59 /home/amd/certs /home/amd/report.bin + # Verify Attestation report-data only + snpguest verify attestation --report-data 0x5482c1ffe29145d47cf678f7681e3b64a89909d6cf8ec0104cfacb0b0418f005f564ad14f5c1381c99b74903a780ea340e887c9b445e9c760bf0b74115b26d45 /home/amd/certs /home/amd/report.bin ``` ### Global Options diff --git a/docs/snpguest.1.adoc b/docs/snpguest.1.adoc index 5a68c46..7ffcc34 100644 --- a/docs/snpguest.1.adoc +++ b/docs/snpguest.1.adoc @@ -120,12 +120,25 @@ COMMANDS An error will be raised if the attestation verification fails at any point. The user can use the [-t, --tcb] flag to only validate the tcb contents of the report. The user can use the [-s, --signature] flag to only validate the report signature. + The user can use the [-m, --measurement] flag to verify that the measurement in the attestation + report matches the expected measurement value (prefix with 0x for hex, without prefix it assumes + decimal values). + The user can use the [-d, --host-data] flag to verify that the host-data in the attestation + report matches the expected host-data value (prefix with 0x for hex, without prefix it assumes + decimal values). + The user can use the [-r, --report-data] flag to verify that the report-data in the attestation + report matches the expected report-data value (prefix with 0x for hex, without prefix it assumes + decimal values). + If the optional flags are not passed, just the signature will be verified. options: -h, --help show a help message -p, --processor_model Specify the processor model to use for verification -t, --tcb verify the tcb section of the report only -s, --signature verify the signature of the report only + -m, --measurement provide an expected measurement to verify the measurement field in the attestation report + -d, --host-data provide the expected host-data to verify the host-data field in the attestation report + -r, --report-data provide the expected report-data to verify the report-data in the attestation report *snpguest key*:: usage: snpguest key $KEY_PATH $ROOT_KEY_SELECT [-g, --guest_field_select] [-s, --guest_svn] [-t, --tcb_version] [-v, --vmpl] diff --git a/src/verify.rs b/src/verify.rs index f69681e..0664105 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -472,13 +472,12 @@ mod attestation { fn decode_hex_or_decimal(input: &str) -> Result> { // Look for "0x" at beginning. If it exists, treat as a hex. if let Some(hex_str) = input.strip_prefix("0x") { - return Ok(Vec::from_hex(hex_str)?); - } - else { + Ok(Vec::from_hex(hex_str)?) + } else { Ok(input.as_bytes().to_vec()) } } - + fn verify_field( field_name: &str, expected: &[u8],