From aa7a96ce637ac35c15ed3cd50d4f033a77f80910 Mon Sep 17 00:00:00 2001 From: Larry Dewey Date: Wed, 7 Feb 2024 15:17:29 -0600 Subject: [PATCH] vlek: Adding VLEK support This addds support for handling Version Loaded Endorsement Keys Signed-off-by: Larry Dewey --- src/certs/snp/chain.rs | 41 +++++++++++++++++++++++----------- src/firmware/host/types/snp.rs | 24 +++++++++++++++----- tests/certs.rs | 8 +++---- 3 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/certs/snp/chain.rs b/src/certs/snp/chain.rs index 6f80b119..732185bc 100644 --- a/src/certs/snp/chain.rs +++ b/src/certs/snp/chain.rs @@ -10,8 +10,8 @@ pub struct Chain { /// The Certificate Authority (CA) chain. pub ca: ca::Chain, - /// The Versioned Chip Endorsement Key. - pub vcek: Certificate, + /// The Versioned Chip Endorsement Key or Versioned Loaded Endorsement Key. + pub vek: Certificate, } impl<'a> Verifiable for &'a Chain { @@ -22,9 +22,9 @@ impl<'a> Verifiable for &'a Chain { let ask = self.ca.verify()?; // Verify that ASK signs VCEK. - (ask, &self.vcek).verify()?; + (ask, &self.vek).verify()?; - Ok(&self.vcek) + Ok(&self.vek) } } @@ -56,6 +56,7 @@ impl Chain { let mut ark: Option = None; let mut ask: Option = None; let mut vcek: Option = None; + let mut vlek: Option = None; let other = ErrorKind::Other; @@ -88,6 +89,13 @@ impl Chain { vcek = Some(cert); } + CertType::VLEK => { + if vlek.is_some() { + return Err(Error::new(other, "more than one VLEK certificate found")); + } + + vlek = Some(cert); + } _ => continue, } } @@ -97,32 +105,39 @@ impl Chain { return Err(Error::new(other, "ARK not found")); } else if ask.is_none() { return Err(Error::new(other, "ASK not found")); - } else if vcek.is_none() { - return Err(Error::new(other, "VCEK not found")); + } else if vcek.is_none() && vlek.is_none() { + return Err(Error::new(other, "VCEK/VLEK not found")); } + // Use the VLEK whenever it is present, but use the VCEK when VLEK is missing. + let vek_val = match (vcek, vlek) { + (_, Some(vlek)) => vlek, + (Some(vcek), None) => vcek, + _ => unreachable!(), + }; + Ok(Self { ca: ca::Chain { ark: ark.unwrap(), ask: ask.unwrap(), }, - vcek: vcek.unwrap(), + vek: vek_val, }) } - /// Deserialize a PEM-encoded ARK, ASK, and VCEK to a SEV-SNP chain. - pub fn from_pem(ark: &[u8], ask: &[u8], vcek: &[u8]) -> Result { + /// Deserialize a PEM-encoded ARK, ASK, and VEK to a SEV-SNP chain. + pub fn from_pem(ark: &[u8], ask: &[u8], vek: &[u8]) -> Result { Ok(Self { ca: ca::Chain::from_pem(ark, ask)?, - vcek: Certificate::from_pem(vcek)?, + vek: Certificate::from_pem(vek)?, }) } - /// Deserialize a DER-encoded ARK, ASK, and VCEK to a SEV-SNP chain. - pub fn from_der(ark: &[u8], ask: &[u8], vcek: &[u8]) -> Result { + /// Deserialize a DER-encoded ARK, ASK, and VEK to a SEV-SNP chain. + pub fn from_der(ark: &[u8], ask: &[u8], vek: &[u8]) -> Result { Ok(Self { ca: ca::Chain::from_der(ark, ask)?, - vcek: Certificate::from_der(vcek)?, + vek: Certificate::from_der(vek)?, }) } } diff --git a/src/firmware/host/types/snp.rs b/src/firmware/host/types/snp.rs index 91d6d9db..fe6c4b9e 100644 --- a/src/firmware/host/types/snp.rs +++ b/src/firmware/host/types/snp.rs @@ -32,6 +32,9 @@ bitflags::bitflags! { #[repr(C)] /// Certificates which are accepted for [`CertTableEntry`](self::CertTableEntry) pub enum CertType { + /// Empty or closing entry for the CertTable + Empty, + /// AMD Root Signing Key (ARK) certificate ARK, @@ -41,20 +44,25 @@ pub enum CertType { /// Versioned Chip Endorsement Key (VCEK) certificate VCEK, + /// Versioned Loaded Endorsement Key (VLEK) certificate + VLEK, + + /// Certificate Revocation List (CRLs) certificate(s) + CRL, + /// Other (Specify GUID) OTHER(uuid::Uuid), - - /// Empty or closing entry for the CertTable - Empty, } impl ToString for CertType { fn to_string(&self) -> String { match self { + CertType::Empty => "00000000-0000-0000-0000-000000000000".to_string(), CertType::ARK => "c0b406a4-a803-4952-9743-3fb6014cd0ae".to_string(), CertType::ASK => "4ab7b379-bbac-4fe4-a02f-05aef327c782".to_string(), CertType::VCEK => "63da758d-e664-4564-adc5-f4b93be8accd".to_string(), - CertType::Empty => "00000000-0000-0000-0000-000000000000".to_string(), + CertType::VLEK => "a8074bc2-a25a-483e-aae6-39c045a0b8a1".to_string(), + CertType::CRL => "92f81bc3-5811-4d3d-97ff-d19f88dc67ea".to_string(), CertType::OTHER(guid) => guid.to_string(), } } @@ -64,10 +72,12 @@ impl TryFrom for uuid::Uuid { type Error = uuid::Error; fn try_from(value: CertType) -> Result { match value { + CertType::Empty => uuid::Uuid::parse_str(&CertType::Empty.to_string()), CertType::ARK => uuid::Uuid::parse_str(&CertType::ARK.to_string()), CertType::ASK => uuid::Uuid::parse_str(&CertType::ASK.to_string()), CertType::VCEK => uuid::Uuid::parse_str(&CertType::VCEK.to_string()), - CertType::Empty => uuid::Uuid::parse_str(&CertType::Empty.to_string()), + CertType::VLEK => uuid::Uuid::parse_str(&CertType::VLEK.to_string()), + CertType::CRL => uuid::Uuid::parse_str(&CertType::CRL.to_string()), CertType::OTHER(guid) => Ok(guid), } } @@ -78,10 +88,12 @@ impl TryFrom<&uuid::Uuid> for CertType { fn try_from(value: &uuid::Uuid) -> Result { Ok(match value.to_string().as_str() { + "00000000-0000-0000-0000-000000000000" => CertType::Empty, "c0b406a4-a803-4952-9743-3fb6014cd0ae" => CertType::ARK, "4ab7b379-bbac-4fe4-a02f-05aef327c782" => CertType::ASK, "63da758d-e664-4564-adc5-f4b93be8accd" => CertType::VCEK, - "00000000-0000-0000-0000-000000000000" => CertType::Empty, + "a8074bc2-a25a-483e-aae6-39c045a0b8a1" => CertType::VLEK, + "92f81bc3-5811-4d3d-97ff-d19f88dc67ea" => CertType::CRL, _ => CertType::OTHER(*value), }) } diff --git a/tests/certs.rs b/tests/certs.rs index f193a334..3666430a 100644 --- a/tests/certs.rs +++ b/tests/certs.rs @@ -40,7 +40,7 @@ mod snp { let chain = Chain { ca, - vcek: vcek.clone(), + vek: vcek.clone(), }; assert_eq!(chain.verify().ok(), Some(&vcek)); @@ -58,7 +58,7 @@ mod snp { let ca = ca::Chain { ark, ask }; - let chain = Chain { ca, vcek }; + let chain = Chain { ca, vek: vcek }; assert_eq!(chain.verify().ok(), None); } @@ -73,7 +73,7 @@ mod snp { let ca = ca::Chain { ark, ask }; - let chain = Chain { ca, vcek }; + let chain = Chain { ca, vek: vcek }; let report_bytes = hex::decode(TEST_MILAN_ATTESTATION_REPORT).unwrap(); let report: AttestationReport = @@ -92,7 +92,7 @@ mod snp { let ca = ca::Chain { ark, ask }; - let chain = Chain { ca, vcek }; + let chain = Chain { ca, vek: vcek }; let mut report_bytes = hex::decode(TEST_MILAN_ATTESTATION_REPORT).unwrap(); report_bytes[0] ^= 0x80;