From 079dae762ba455447bcc42da78ef34ea1a0419a2 Mon Sep 17 00:00:00 2001 From: Larry Dewey Date: Fri, 26 Jul 2024 09:27:20 -0500 Subject: [PATCH] verifier: Use the VirTEE CA Chain This introduces changes into the code to utilize the cert chain provided by the VirTEE sev crate, pushing resposibility for upkeep and maintainership back to the library itself. This also reduces duplication of code and expands functionality for future changes. Review Changes: - Adding whitespace back to Makefile - Updating sev to 4.0.0 - Removed Cargo.toml reformatting - Renamed function per mkulke's comment Signed-off-by: Larry Dewey --- Cargo.lock | 125 +++++++++++++-------------- Cargo.toml | 6 +- deps/verifier/Cargo.toml | 6 +- deps/verifier/src/az_snp_vtpm/mod.rs | 23 +++-- deps/verifier/src/lib.rs | 4 +- deps/verifier/src/snp/mod.rs | 77 +++++++++-------- deps/verifier/src/tdx/eventlog.rs | 1 + 7 files changed, 117 insertions(+), 125 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0dd2bbf1e..0cc732ad0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,7 +40,7 @@ dependencies = [ "encoding_rs", "flate2", "futures-core", - "h2 0.3.26", + "h2", "http 0.2.12", "httparse", "httpdate", @@ -490,12 +490,6 @@ dependencies = [ "syn 2.0.60", ] -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - [[package]] name = "attestation-agent" version = "0.1.0" @@ -573,7 +567,7 @@ dependencies = [ "csv-rs", "hex", "hyper 0.14.28", - "hyper-tls 0.5.0", + "hyper-tls", "kbs-types", "log", "nix", @@ -583,7 +577,7 @@ dependencies = [ "serde", "serde_json", "serde_with", - "sev", + "sev 3.2.0", "sha2", "strum", "tdx-attest-rs", @@ -668,7 +662,7 @@ dependencies = [ "serde", "serde-big-array", "serde_json", - "sev", + "sev 3.2.0", "sha2", "thiserror", "tss-esapi", @@ -688,7 +682,7 @@ dependencies = [ "serde", "serde-big-array", "serde_json", - "sev", + "sev 3.2.0", "sha2", "thiserror", "tss-esapi", @@ -706,7 +700,7 @@ dependencies = [ "clap 4.5.4", "openssl", "serde", - "sev", + "sev 3.2.0", "thiserror", "ureq", ] @@ -721,7 +715,7 @@ dependencies = [ "bincode", "clap 4.5.4", "serde", - "sev", + "sev 3.2.0", "thiserror", "ureq", ] @@ -894,6 +888,12 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" +[[package]] +name = "bitfield" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c821a6e124197eb56d907ccc2188eab1038fb919c914f47976e64dd8dbc855d1" + [[package]] name = "bitflags" version = "1.3.2" @@ -1417,7 +1417,7 @@ dependencies = [ "codicon", "dirs", "hyper 0.14.28", - "hyper-tls 0.5.0", + "hyper-tls", "iocuddle", "libc", "openssl", @@ -2077,25 +2077,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "h2" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http 1.1.0", - "indexmap 2.2.6", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "half" version = "2.4.1" @@ -2295,7 +2276,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.3.26", + "h2", "http 0.2.12", "http-body 0.4.6", "httparse", @@ -2318,7 +2299,6 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", "http 1.1.0", "http-body 1.0.0", "httparse", @@ -2385,22 +2365,6 @@ dependencies = [ "tokio-native-tls", ] -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper 1.3.1", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - [[package]] name = "hyper-util" version = "0.1.5" @@ -4042,6 +4006,15 @@ dependencies = [ "cipher", ] +[[package]] +name = "rdrand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92195228612ac8eed47adbc2ed0f04e513a4ccb98175b6f2bd04d963b533655" +dependencies = [ + "rand_core", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -4168,12 +4141,12 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.3.26", + "h2", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.28", "hyper-rustls 0.24.2", - "hyper-tls 0.5.0", + "hyper-tls", "ipnet", "js-sys", "log", @@ -4211,22 +4184,18 @@ dependencies = [ "bytes", "cookie 0.17.0", "cookie_store", - "encoding_rs", "futures-core", "futures-util", - "h2 0.4.5", "http 1.1.0", "http-body 1.0.0", "http-body-util", "hyper 1.3.1", "hyper-rustls 0.26.0", - "hyper-tls 0.6.0", "hyper-util", "ipnet", "js-sys", "log", "mime", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -4237,9 +4206,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", - "tokio-native-tls", "tokio-rustls 0.25.0", "tower-service", "url", @@ -4868,13 +4835,38 @@ dependencies = [ [[package]] name = "sev" -version = "3.1.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2890179f8ef689340f441ba05f0b268bc14f672ae4b36d629cc2266d0d747ab" +checksum = "35156eab65ff1b63432b5a11a06b770e92120033e2831c7dee064865de5dbbbd" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "bincode", - "bitfield 0.13.2", + "bitfield 0.15.0", + "bitflags 1.3.2", + "byteorder", + "codicon", + "dirs", + "hex", + "iocuddle", + "lazy_static", + "libc", + "openssl", + "serde", + "serde-big-array", + "serde_bytes", + "static_assertions", + "uuid", +] + +[[package]] +name = "sev" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97bd0b2e2d937951add10c8512a2dacc6ad29b39e5c5f26565a3e443329857d" +dependencies = [ + "base64 0.22.1", + "bincode", + "bitfield 0.15.0", "bitflags 1.3.2", "byteorder", "codicon", @@ -4884,6 +4876,7 @@ dependencies = [ "lazy_static", "libc", "openssl", + "rdrand", "serde", "serde-big-array", "serde_bytes", @@ -5511,7 +5504,7 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "h2 0.3.26", + "h2", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.28", @@ -5538,7 +5531,7 @@ dependencies = [ "axum", "base64 0.21.7", "bytes", - "h2 0.3.26", + "h2", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.28", @@ -5927,7 +5920,7 @@ dependencies = [ "serde_json", "serde_with", "serial_test", - "sev", + "sev 4.0.0", "sha2", "shadow-rs", "strum", diff --git a/Cargo.toml b/Cargo.toml index 3d7bd6bbc..c440bfbaa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ jsonwebtoken = { version = "9", default-features = false } log = "0.4.17" prost = "0.12" regorus = { version = "0.1.5", default-features = false, features = ["regex", "base64", "time"] } -reqwest = "0.12" +reqwest = { version = "0.12", default-features = false } rstest = "0.18.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.89" @@ -46,7 +46,7 @@ sha2 = "0.10" shadow-rs = "0.19.0" strum = { version = "0.25", features = ["derive"] } thiserror = "1.0" -tokio = { version = "1", features = ["full"] } +tokio = { version = "1", features = ["full"], default-features = false } tempfile = "3.4.0" tonic = "0.11" -tonic-build = "0.11" \ No newline at end of file +tonic-build = "0.11" diff --git a/deps/verifier/Cargo.toml b/deps/verifier/Cargo.toml index 8f78b6ff4..bab7561ce 100644 --- a/deps/verifier/Cargo.toml +++ b/deps/verifier/Cargo.toml @@ -28,7 +28,7 @@ byteorder = "1" cfg-if = "1.0.0" codicon = { version = "3.0", optional = true } # TODO: change it to "0.1", once released. -csv-rs = { git = "https://github.com/openanolis/csv-rs", rev = "b74aa8c", optional = true } +csv-rs = { version = "=0.1.0", git = "https://github.com/openanolis/csv-rs", rev = "b74aa8c", optional = true } eventlog-rs = { version = "0.1.3", optional = true } hex.workspace = true jsonwebkey = "0.3.5" @@ -41,9 +41,9 @@ scroll = { version = "0.11.0", default-features = false, features = ["derive"], serde.workspace = true serde_json.workspace = true serde_with = { workspace = true, optional = true } -sev = { version = "3.1.1", features = ["openssl", "snp"], optional = true } +sev = { version = "4.0.0", features = ["openssl", "snp"], optional = true } sha2.workspace = true -tokio = { workspace = true, optional = true, default-features = false } +tokio = { workspace = true, optional = true } intel-tee-quote-verification-rs = { git = "https://github.com/intel/SGXDataCenterAttestationPrimitives", tag = "DCAP_1.21", optional = true } strum.workspace = true veraison-apiclient = { git = "https://github.com/chendave/rust-apiclient", branch = "token", optional = true } diff --git a/deps/verifier/src/az_snp_vtpm/mod.rs b/deps/verifier/src/az_snp_vtpm/mod.rs index a1cced4cd..52557b7ce 100644 --- a/deps/verifier/src/az_snp_vtpm/mod.rs +++ b/deps/verifier/src/az_snp_vtpm/mod.rs @@ -4,9 +4,7 @@ // use super::{TeeEvidenceParsedClaim, Verifier}; -use crate::snp::{ - load_milan_cert_chain, parse_tee_evidence, verify_report_signature, VendorCertificates, -}; +use crate::snp::{load_milan_cert_chain, parse_tee_evidence, verify_report_signature}; use crate::{InitDataHash, ReportData}; use anyhow::{bail, Context, Result}; use async_trait::async_trait; @@ -19,6 +17,7 @@ use log::{debug, warn}; use openssl::pkey::PKey; use serde::{Deserialize, Serialize}; use serde_json::Value; +use sev::certs::snp::Chain; use sev::firmware::host::{CertTableEntry, CertType}; use thiserror::Error; @@ -32,7 +31,7 @@ struct Evidence { } pub struct AzSnpVtpm { - vendor_certs: VendorCertificates, + vendor_certs: Chain, } #[derive(Error, Debug)] @@ -54,12 +53,10 @@ pub enum CertError { } impl AzSnpVtpm { - pub fn new() -> Result { - let Result::Ok(vendor_certs) = load_milan_cert_chain() else { - return Err(CertError::LoadMilanCert); - }; - let vendor_certs = vendor_certs.clone(); - Ok(Self { vendor_certs }) + pub fn new() -> Self { + Self { + vendor_certs: load_milan_cert_chain().clone(), + } } } @@ -171,7 +168,7 @@ fn verify_report_data( fn verify_snp_report( snp_report: &AttestationReport, vcek: &Vcek, - vendor_certs: &VendorCertificates, + vendor_certs: &Chain, ) -> Result<(), CertError> { let vcek_data = vcek.0.to_der().context("Failed to get raw VCEK data")?; let cert_chain = [CertTableEntry::new(CertType::VCEK, vcek_data)]; @@ -199,7 +196,7 @@ mod tests { 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-snp-vtpm/vcek.pem")).unwrap(); - let vendor_certs = load_milan_cert_chain().as_ref().unwrap(); + let vendor_certs = load_milan_cert_chain(); verify_snp_report(&snp_report, &vcek, vendor_certs).unwrap(); } @@ -211,7 +208,7 @@ mod tests { 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-snp-vtpm/vcek.pem")).unwrap(); - let vendor_certs = load_milan_cert_chain().as_ref().unwrap(); + let vendor_certs = load_milan_cert_chain(); assert_eq!( verify_snp_report(&snp_report, &vcek, vendor_certs) .unwrap_err() diff --git a/deps/verifier/src/lib.rs b/deps/verifier/src/lib.rs index 40c09d345..85a4a0849 100644 --- a/deps/verifier/src/lib.rs +++ b/deps/verifier/src/lib.rs @@ -39,7 +39,7 @@ pub fn to_verifier(tee: &Tee) -> Result> { Tee::AzSnpVtpm => { cfg_if::cfg_if! { if #[cfg(feature = "az-snp-vtpm-verifier")] { - let verifier = az_snp_vtpm::AzSnpVtpm::new()?; + let verifier = az_snp_vtpm::AzSnpVtpm::new(); Ok(Box::new(verifier) as Box) } else { bail!("feature `az-snp-vtpm-verifier` is not enabled for `verifier` crate.") @@ -67,7 +67,7 @@ pub fn to_verifier(tee: &Tee) -> Result> { Tee::Snp => { cfg_if::cfg_if! { if #[cfg(feature = "snp-verifier")] { - let verifier = snp::Snp::new()?; + let verifier = snp::Snp::new(); Ok(Box::new(verifier) as Box) } else { bail!("feature `snp-verifier` is not enabled for `verifier` crate.") diff --git a/deps/verifier/src/snp/mod.rs b/deps/verifier/src/snp/mod.rs index b5e4276b7..eaeecb53c 100644 --- a/deps/verifier/src/snp/mod.rs +++ b/deps/verifier/src/snp/mod.rs @@ -15,6 +15,7 @@ use openssl::{ x509::{self, X509}, }; use serde_json::json; +use sev::certs::snp::{ca::Chain as CaChain, Certificate, Chain}; use sev::firmware::guest::AttestationReport; use sev::firmware::host::{CertTableEntry, CertType}; use std::sync::OnceLock; @@ -34,43 +35,43 @@ const LOADER_SPL_OID: Oid<'static> = oid!(1.3.6 .1 .4 .1 .3704 .1 .3 .1); #[derive(Debug)] pub struct Snp { - vendor_certs: VendorCertificates, + vendor_certs: Chain, } -pub(crate) fn load_milan_cert_chain() -> &'static Result { - static MILAN_CERT_CHAIN: OnceLock> = OnceLock::new(); - MILAN_CERT_CHAIN.get_or_init(|| { - let certs = X509::stack_from_pem(include_bytes!("milan_ask_ark_asvk.pem"))?; - if certs.len() != 3 { - bail!("Malformed Milan ASK/ARK/ASVK"); +fn link_bytes_from_file() -> Vec { + match X509::stack_from_pem(include_bytes!("milan_ask_ark_asvk.pem")) { + Result::Ok(certs) => { + if certs.len() != 3 { + panic!("Malformed Milan ASK/ARK/ASVK"); + } + return certs; } + Result::Err(err) => panic!("Error reading certificates file: {err}"), + } +} - let vendor_certs = VendorCertificates { - ask: certs[0].clone(), - ark: certs[1].clone(), - asvk: certs[2].clone(), - }; - Ok(vendor_certs) +pub(crate) fn load_milan_cert_chain() -> &'static Chain { + static MILAN_CERT_CHAIN: OnceLock = OnceLock::new(); + MILAN_CERT_CHAIN.get_or_init(|| { + let certs = link_bytes_from_file(); + Chain { + ca: CaChain { + ark: Certificate::from(certs[1].clone()), + ask: Certificate::from(certs[0].clone()), + }, + vek: Certificate::from(certs[2].clone()), + } }) } impl Snp { - pub fn new() -> Result { - let Result::Ok(vendor_certs) = load_milan_cert_chain() else { - bail!("Failed to load Milan cert chain"); - }; - let vendor_certs = vendor_certs.clone(); - Ok(Self { vendor_certs }) + pub fn new() -> Self { + Self { + vendor_certs: load_milan_cert_chain().clone(), + } } } -#[derive(Clone, Debug)] -pub(crate) struct VendorCertificates { - ask: X509, - ark: X509, - asvk: X509, -} - #[async_trait] impl Verifier for Snp { async fn evaluate( @@ -165,10 +166,10 @@ fn get_oid_int(cert: &x509_parser::certificate::TbsCertificate, oid: Oid) -> Res pub(crate) fn verify_report_signature( report: &AttestationReport, cert_chain: &[CertTableEntry], - vendor_certs: &VendorCertificates, + vendor_certs: &Chain, ) -> Result<()> { // check cert chain - let VendorCertificates { ask, ark, asvk } = vendor_certs; + let (ask, ark, asvk): (&X509, &X509, &X509) = vendor_certs.into(); // verify VCEK or VLEK cert chain // the key can be either VCEK or VLEK @@ -322,7 +323,7 @@ mod tests { #[test] fn check_milan_certificates() { - let VendorCertificates { ask, ark, asvk } = load_milan_cert_chain().as_ref().unwrap(); + let (ask, ark, asvk) = load_milan_cert_chain().into(); assert_eq!(get_common_name(ark).unwrap(), "ARK-Milan"); assert_eq!(get_common_name(ask).unwrap(), "SEV-Milan"); assert_eq!(get_common_name(asvk).unwrap(), "SEV-VLEK-Milan"); @@ -393,7 +394,7 @@ mod tests { #[test] fn check_vcek_signature_verification() { let cert_table = vec![CertTableEntry::new(CertType::VCEK, VCEK.to_vec())]; - let VendorCertificates { ask, ark, asvk } = load_milan_cert_chain().as_ref().unwrap(); + let (ask, ark, asvk) = load_milan_cert_chain().into(); verify_cert_chain(&cert_table, ask, ark, asvk).unwrap(); } @@ -406,14 +407,14 @@ mod tests { X509::from_der(&vcek).expect("failed to parse der"); let cert_table = vec![CertTableEntry::new(CertType::VCEK, vcek.to_vec())]; - let VendorCertificates { ask, ark, asvk } = load_milan_cert_chain().as_ref().unwrap(); + let (ask, ark, asvk) = load_milan_cert_chain().into(); verify_cert_chain(&cert_table, ask, ark, asvk).unwrap_err(); } #[test] fn check_vlek_signature_verification() { let cert_table = vec![CertTableEntry::new(CertType::VLEK, VLEK.to_vec())]; - let VendorCertificates { ask, ark, asvk } = load_milan_cert_chain().as_ref().unwrap(); + let (ask, ark, asvk) = load_milan_cert_chain().into(); verify_cert_chain(&cert_table, ask, ark, asvk).unwrap(); } @@ -426,14 +427,14 @@ mod tests { X509::from_der(&vlek).expect("failed to parse der"); let cert_table = vec![CertTableEntry::new(CertType::VLEK, vlek.to_vec())]; - let VendorCertificates { ask, ark, asvk } = load_milan_cert_chain().as_ref().unwrap(); + let (ask, ark, asvk) = load_milan_cert_chain().into(); verify_cert_chain(&cert_table, ask, ark, asvk).unwrap_err(); } #[test] fn check_milan_chain_signature_failure() { let cert_table = vec![CertTableEntry::new(CertType::VCEK, VCEK.to_vec())]; - let VendorCertificates { ask, ark, asvk } = load_milan_cert_chain().as_ref().unwrap(); + let (ask, ark, asvk) = load_milan_cert_chain().into(); // toggle ark <=> ask verify_cert_chain(&cert_table, ark, ask, asvk).unwrap_err(); @@ -444,7 +445,7 @@ mod tests { let attestation_report = bincode::deserialize::(VCEK_REPORT.as_slice()).unwrap(); let cert_chain = vec![CertTableEntry::new(CertType::VCEK, VCEK.to_vec())]; - let vendor_certs = load_milan_cert_chain().as_ref().unwrap(); + let vendor_certs = load_milan_cert_chain(); verify_report_signature(&attestation_report, &cert_chain, vendor_certs).unwrap(); } @@ -453,7 +454,7 @@ mod tests { let attestation_report = bincode::deserialize::(VLEK_REPORT.as_slice()).unwrap(); let cert_chain = vec![CertTableEntry::new(CertType::VLEK, VLEK.to_vec())]; - let vendor_certs = load_milan_cert_chain().as_ref().unwrap(); + let vendor_certs = load_milan_cert_chain(); verify_report_signature(&attestation_report, &cert_chain, vendor_certs).unwrap(); } @@ -466,7 +467,7 @@ mod tests { let attestation_report = bincode::deserialize::(&bytes).unwrap(); let cert_chain = vec![CertTableEntry::new(CertType::VCEK, VCEK.to_vec())]; - let vendor_certs = load_milan_cert_chain().as_ref().unwrap(); + let vendor_certs = load_milan_cert_chain(); verify_report_signature(&attestation_report, &cert_chain, vendor_certs).unwrap_err(); } @@ -479,7 +480,7 @@ mod tests { let attestation_report = bincode::deserialize::(&bytes).unwrap(); let cert_chain = vec![CertTableEntry::new(CertType::VLEK, VLEK.to_vec())]; - let vendor_certs = load_milan_cert_chain().as_ref().unwrap(); + let vendor_certs = load_milan_cert_chain(); verify_report_signature(&attestation_report, &cert_chain, vendor_certs).unwrap_err(); } } diff --git a/deps/verifier/src/tdx/eventlog.rs b/deps/verifier/src/tdx/eventlog.rs index 3278c9e71..bef0436d2 100644 --- a/deps/verifier/src/tdx/eventlog.rs +++ b/deps/verifier/src/tdx/eventlog.rs @@ -124,6 +124,7 @@ impl CcEventLog { /// Defined in TCG PC Client Platform Firmware Profile Specification section /// 'UEFI_PLATFORM_FIRMWARE_BLOB Structure Definition' +#[allow(dead_code)] pub struct ParsedUefiPlatformFirmwareBlob2 { pub desc_len: u8, pub desc: Vec,