From 60628675e2849c609622cc50fccfed9a31d83bda Mon Sep 17 00:00:00 2001 From: DGonzalezVillal Date: Thu, 19 Dec 2024 19:09:39 +0000 Subject: [PATCH] Adding AttestationReport Verification with Certificate only We currently only offer report verification with a full chain being provided. Although it is safest to provide a whole chain to verify the whole root of trust, there are cases people might want to divide the process into individual steps. This allows users to verify the report with what should be an already verified versioned endorsement key. I also renamed the VCEK to VEK since we no offer support for both the VLEK and VCEK. Signed-off-by: DGonzalezVillal --- src/firmware/guest/types/snp.rs | 84 ++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 6 deletions(-) diff --git a/src/firmware/guest/types/snp.rs b/src/firmware/guest/types/snp.rs index 1a9ffbb9..10567d52 100644 --- a/src/firmware/guest/types/snp.rs +++ b/src/firmware/guest/types/snp.rs @@ -3,7 +3,7 @@ use crate::{certs::snp::ecdsa::Signature, firmware::host::TcbVersion, util::hexdump}; #[cfg(any(feature = "openssl", feature = "crypto_nossl"))] -use crate::certs::snp::{Chain, Verifiable}; +use crate::certs::snp::{Certificate, Chain, Verifiable}; use std::fmt::Display; @@ -314,7 +314,7 @@ impl Verifiable for (&Chain, &AttestationReport) { type Output = (); fn verify(self) -> io::Result { - let vcek = self.0.verify()?; + let vek = self.0.verify()?; let sig = EcdsaSig::try_from(&self.1.signature)?; let measurable_bytes: &[u8] = &bincode::serialize(self.1).map_err(|e| { @@ -328,14 +328,46 @@ impl Verifiable for (&Chain, &AttestationReport) { hasher.update(measurable_bytes); let base_digest = hasher.finish(); - let ec = vcek.public_key()?.ec_key()?; + let ec = vek.public_key()?.ec_key()?; let signed = sig.verify(&base_digest, &ec)?; match signed { true => Ok(()), false => Err(Error::new( ErrorKind::Other, - "VCEK does not sign the attestation report", + "VEK does not sign the attestation report", + )), + } + } +} + +#[cfg(feature = "openssl")] +impl Verifiable for (&Certificate, &AttestationReport) { + type Output = (); + + fn verify(self) -> io::Result { + let vek = self.0; + + let sig = EcdsaSig::try_from(&self.1.signature)?; + let measurable_bytes: &[u8] = &bincode::serialize(self.1).map_err(|e| { + Error::new( + ErrorKind::Other, + format!("Unable to serialize bytes: {}", e), + ) + })?[..0x2a0]; + + let mut hasher = Sha384::new(); + hasher.update(measurable_bytes); + let base_digest = hasher.finish(); + + let ec = vek.public_key()?.ec_key()?; + let signed = sig.verify(&base_digest, &ec)?; + + match signed { + true => Ok(()), + false => Err(Error::new( + ErrorKind::Other, + "VEK does not sign the attestation report", )), } } @@ -345,13 +377,53 @@ impl Verifiable for (&Chain, &AttestationReport) { impl Verifiable for (&Chain, &AttestationReport) { type Output = (); + fn verify(self) -> io::Result { + // According to Chapter 3 of the Versioned Chip Endorsement Key (VCEK) Certificate and the Versioned Loaded Endorsement Key (VLEK) + // Certificate specifications, both Versioned Endorsement Key certificates certify an ECDSA public key on curve P-384, + // with the signature hash algorithm being SHA-384. + let vek = self.0.verify()?; + + let sig = p384::ecdsa::Signature::try_from(&self.1.signature)?; + + let measurable_bytes: &[u8] = &bincode::serialize(self.1).map_err(|e| { + Error::new( + ErrorKind::Other, + format!("Unable to serialize bytes: {}", e), + ) + })?[..0x2a0]; + + use sha2::Digest; + let base_digest = sha2::Sha384::new_with_prefix(measurable_bytes); + + let verifying_key = p384::ecdsa::VerifyingKey::from_sec1_bytes(vek.public_key_sec1()) + .map_err(|e| { + io::Error::new( + ErrorKind::Other, + format!("failed to deserialize public key from sec1 bytes: {e:?}"), + ) + })?; + + use p384::ecdsa::signature::DigestVerifier; + verifying_key.verify_digest(base_digest, &sig).map_err(|e| { + io::Error::new( + ErrorKind::Other, + format!("VCEK does not sign the attestation report: {e:?}"), + ) + }) + } +} + +#[cfg(feature = "crypto_nossl")] +impl Verifiable for (&Certificate, &AttestationReport) { + type Output = (); + fn verify(self) -> io::Result { // According to Chapter 3 of the [Versioned Chip Endorsement Key (VCEK) Certificate and // KDS Interface Specification][spec], the VCEK certificate certifies an ECDSA public key on curve P-384, // and the signature hash algorithm is sha384. // [spec]: https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/57230.pdf - let vcek = self.0.verify()?; + let vek = self.0; let sig = p384::ecdsa::Signature::try_from(&self.1.signature)?; @@ -365,7 +437,7 @@ impl Verifiable for (&Chain, &AttestationReport) { use sha2::Digest; let base_digest = sha2::Sha384::new_with_prefix(measurable_bytes); - let verifying_key = p384::ecdsa::VerifyingKey::from_sec1_bytes(vcek.public_key_sec1()) + let verifying_key = p384::ecdsa::VerifyingKey::from_sec1_bytes(vek.public_key_sec1()) .map_err(|e| { io::Error::new( ErrorKind::Other,