diff --git a/Cargo.lock b/Cargo.lock index ce84e44e5..388d09778 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2677,7 +2677,7 @@ dependencies = [ "prost 0.12.6", "rand", "regorus", - "reqwest 0.12.8", + "reqwest 0.12.9", "rsa 0.9.6", "rstest", "scc", @@ -2705,7 +2705,7 @@ dependencies = [ "jwt-simple 0.11.9", "kbs_protocol", "log", - "reqwest 0.12.8", + "reqwest 0.12.9", "serde", "serde_json", "tokio", @@ -2734,7 +2734,7 @@ dependencies = [ "jwt-simple 0.12.9", "kbs-types", "log", - "reqwest 0.12.8", + "reqwest 0.12.9", "resource_uri", "serde", "serde_json", @@ -2762,7 +2762,7 @@ dependencies = [ "p12", "prost 0.11.9", "rand", - "reqwest 0.12.8", + "reqwest 0.12.9", "resource_uri", "ring", "serde", @@ -4172,14 +4172,15 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.8" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64 0.22.1", "bytes", "cookie 0.18.1", "cookie_store", + "futures-channel", "futures-core", "futures-util", "http 1.1.0", @@ -5879,6 +5880,7 @@ dependencies = [ "kbs-types", "log", "openssl", + "reqwest 0.12.9", "rstest", "s390_pv", "scroll 0.11.0", diff --git a/Cargo.toml b/Cargo.toml index 73a7bc4df..f16cf94fa 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 = { version = "0.12", default-features = false, features = ["default-tls"] } +reqwest = { version = "0.12", default-features = false, features = ["default-tls", "blocking"] } rstest = "0.18.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.89" diff --git a/deps/verifier/Cargo.toml b/deps/verifier/Cargo.toml index e65188a51..bbb236b6a 100644 --- a/deps/verifier/Cargo.toml +++ b/deps/verifier/Cargo.toml @@ -49,6 +49,7 @@ strum.workspace = true veraison-apiclient = { git = "https://github.com/chendave/rust-apiclient", branch = "token", optional = true } ear = { git = "https://github.com/veraison/rust-ear", rev = "43f7f480d09ea2ebc03137af8fbcd70fe3df3468", optional = true } x509-parser = { version = "0.14.0", optional = true } +reqwest.workspace = true [build-dependencies] shadow-rs.workspace = true diff --git a/deps/verifier/src/snp/mod.rs b/deps/verifier/src/snp/mod.rs index b5e4276b7..54b8162c3 100644 --- a/deps/verifier/src/snp/mod.rs +++ b/deps/verifier/src/snp/mod.rs @@ -14,6 +14,10 @@ use openssl::{ sha::sha384, x509::{self, X509}, }; +use reqwest::{ + blocking::{get, Response as ReqwestResponse}, + StatusCode, +}; use serde_json::json; use sev::firmware::guest::AttestationReport; use sev::firmware::host::{CertTableEntry, CertType}; @@ -32,6 +36,10 @@ const SNP_SPL_OID: Oid<'static> = oid!(1.3.6 .1 .4 .1 .3704 .1 .3 .3); const TEE_SPL_OID: Oid<'static> = oid!(1.3.6 .1 .4 .1 .3704 .1 .3 .2); const LOADER_SPL_OID: Oid<'static> = oid!(1.3.6 .1 .4 .1 .3704 .1 .3 .1); +// KDS URL parameters +const KDS_CERT_SITE: &str = "https://kdsintf.amd.com"; +const KDS_VCEK: &str = "/vcek/v1"; + #[derive(Debug)] pub struct Snp { vendor_certs: VendorCertificates, @@ -84,8 +92,9 @@ impl Verifier for Snp { cert_chain, } = serde_json::from_slice(evidence).context("Deserialize Quote failed.")?; - let Some(cert_chain) = cert_chain else { - bail!("Cert chain is unset"); + let cert_chain = match cert_chain { + Some(chain) if !chain.is_empty() => chain, + _ => fetch_vcek_from_kds(report)?, }; verify_report_signature(&report, &cert_chain, &self.vendor_certs)?; @@ -307,6 +316,36 @@ fn get_common_name(cert: &x509::X509) -> Result { Ok(e.data().as_utf8()?.to_string()) } +// Function to request vcek from KDS. Return vcek in der format. +fn fetch_vcek_from_kds(att_report: AttestationReport) -> Result> { + // Use attestation report to get data for URL + let hw_id: String = hex::encode(att_report.chip_id); + + let vcek_url: String = format!( + "{KDS_CERT_SITE}{KDS_VCEK}/Milan/\ + {hw_id}?blSPL={:02}&teeSPL={:02}&snpSPL={:02}&ucodeSPL={:02}", + att_report.reported_tcb.bootloader, + att_report.reported_tcb.tee, + att_report.reported_tcb.snp, + att_report.reported_tcb.microcode + ); + // VCEK in DER format + let vcek_rsp: ReqwestResponse = get(vcek_url).context("Unable to send request for VCEK")?; + + match vcek_rsp.status() { + StatusCode::OK => { + let vcek_rsp_bytes: Vec = + vcek_rsp.bytes().context("Unable to parse VCEK")?.to_vec(); + let key = CertTableEntry { + cert_type: CertType::VCEK, + data: vcek_rsp_bytes, + }; + Ok(vec![key]) + } + status => Err(anyhow!("Unable to fetch VCEK from URL: {status:?}")), + } +} + #[cfg(test)] mod tests { use super::*;