diff --git a/crates/attestation/src/crypto/cert.rs b/crates/attestation/src/crypto/cert.rs index a1d05b02..b268a1a1 100644 --- a/crates/attestation/src/crypto/cert.rs +++ b/crates/attestation/src/crypto/cert.rs @@ -5,12 +5,13 @@ use super::*; use std::time::SystemTime; -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, bail, Result}; use const_oid::db::rfc5280::{ID_CE_BASIC_CONSTRAINTS, ID_CE_KEY_USAGE}; use der::asn1::BitStringRef; use der::{Decode, Encode}; use sec1::pkcs8::{AlgorithmIdentifier, ObjectIdentifier, PrivateKeyInfo}; -use x509::ext::pkix::{BasicConstraints, KeyUsage, KeyUsages}; +use x509::ext::pkix::name::{DistributionPointName, GeneralName}; +use x509::ext::pkix::{BasicConstraints, CrlDistributionPoints, KeyUsage, KeyUsages}; use x509::ext::Extension; use x509::{Certificate, TbsCertificate}; @@ -56,6 +57,9 @@ pub trait TbsCertificateExt<'a> { /// child of the parent certificate. This includes additional field /// validation as well as default extension validation. fn verify_crt<'r, 'c>(&self, cert: &'r Certificate<'c>) -> Result<&'r TbsCertificate<'c>>; + + /// Parse the `TbsCertificate` and get the URLs for the CRL(s), if any. + fn get_crl_urls(&self) -> Result>; } impl<'a> TbsCertificateExt<'a> for TbsCertificate<'a> { @@ -202,4 +206,40 @@ impl<'a> TbsCertificateExt<'a> for TbsCertificate<'a> { Ok(&cert.tbs_certificate) } + + fn get_crl_urls(&self) -> Result> { + const CRL_EXTN: ObjectIdentifier = const_oid::db::rfc5912::ID_CE_CRL_DISTRIBUTION_POINTS; + let mut urls_vec: Vec = Vec::new(); + + if let Some(extensions) = self.extensions.as_ref() { + for ext in extensions.iter() { + if ext.extn_id == CRL_EXTN { + let urls = CrlDistributionPoints::from_der(ext.extn_value)?; + for url in urls.0 { + if let Some(dist_pt) = url.distribution_point { + match dist_pt { + DistributionPointName::FullName(names) => { + for name in names { + match name { + GeneralName::UniformResourceIdentifier(uri) => { + urls_vec.push(uri.to_string()); + } + x => { + bail!("unsupported {:?}", x); + } + } + } + } + x => { + bail!("unsupported {:?}", x); + } + } + } + } + } + } + } + + Ok(urls_vec) + } } diff --git a/crates/attestation/src/crypto/crl.rs b/crates/attestation/src/crypto/crl.rs new file mode 100644 index 00000000..20ee2768 --- /dev/null +++ b/crates/attestation/src/crypto/crl.rs @@ -0,0 +1,417 @@ +// SPDX-FileCopyrightText: 2022 Profian Inc. +// SPDX-License-Identifier: AGPL-3.0-only + +use crate::crypto::{SubjectPublicKeyInfoExt, TbsCertificateExt}; + +use anyhow::{bail, Result}; +use der::{Encode, Sequence}; +use x509::crl::CertificateList; +use x509::PkiPath; + +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +pub struct CrlPair<'a> { + pub url: String, + pub crl: CertificateList<'a>, +} + +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +pub struct CachedCrl<'a> { + pub crls: Vec>, +} + +impl<'a> CachedCrl<'a> { + fn get_crl_for_url(&self, url: &str) -> Option<&CertificateList> { + for pair in &self.crls { + if pair.url == url { + return Some(&pair.crl); + } + } + None + } +} + +pub trait PkiPathCRLCheck<'a> { + fn check_crl(&self, pairs: &CachedCrl<'a>) -> Result<()>; +} + +impl<'a> PkiPathCRLCheck<'a> for PkiPath<'a> { + fn check_crl(&self, pairs: &CachedCrl<'a>) -> Result<()> { + // We want to ensure that a valid CRL was passed, so we make sure at least one of the CRLs + // is valid for this `PkiPath`, otherwise, no valid CRLs were received, and that's not okay. + let mut found = false; + let mut iter = self.iter().peekable(); + loop { + let cert = iter.next(); + let next = iter.peek(); + if cert.is_none() || next.is_none() { + break; + } + let cert = cert.unwrap(); + let next = next.unwrap(); + + let crls = { + let urls = cert.tbs_certificate.get_crl_urls()?; + let mut crls = vec![]; + for url in urls { + if let Some(crl) = pairs.get_crl_for_url(&url) { + crls.push(crl); + } + } + crls + }; + + for crl in crls { + if crl.signature_algorithm.oid != cert.signature_algorithm.oid { + // Must not be the correct Certificate-CRL match, go to the next Certificate + // since the signature algorithm on the CRL should match the algorithm + // type of the signing CA, right? + continue; + } + + // Don't check CRL expiration in unit tests + #[cfg(not(debug_assertions))] + if let Some(next_update) = crl.tbs_cert_list.next_update { + if next_update.to_system_time() <= std::time::SystemTime::now() { + bail!("CRL expired"); + } + } + + let raw_bytes = crl.tbs_cert_list.to_vec().unwrap(); + match cert.tbs_certificate.subject_public_key_info.verify( + &raw_bytes, + cert.signature_algorithm, + crl.signature.raw_bytes(), + ) { + Ok(_) => { + if let Some(revocations) = crl.tbs_cert_list.revoked_certificates.as_ref() { + for revoked in revocations { + if revoked.serial_number == next.tbs_certificate.serial_number { + bail!("revoked!"); + } + } + } + found = true; + } + Err(_) => { + // Not the correct Certificate-CRL match, go to the next. + continue; + } + } + } + } + if found { + return Ok(()); + } + Err(anyhow::Error::msg("no valid CRL was provided")) + } +} + +#[cfg(test)] +mod tests { + use super::super::{PrivateKeyInfoExt, TbsCertificateExt}; + use super::*; + + use crate::crypto::PkiPathCRLCheck; + use const_oid::db::rfc5280::{ID_CE_BASIC_CONSTRAINTS, ID_CE_KEY_USAGE}; + use const_oid::db::rfc5912::SECP_256_R_1 as P256; + use der::asn1::{BitStringRef, GeneralizedTime, Ia5StringRef, UIntRef}; + use der::Decode; + use sec1::pkcs8::PrivateKeyInfo; + use std::time::{Duration, SystemTime}; + use x509::crl::{RevokedCert, TbsCertList}; + use x509::ext::pkix::crl::dp::DistributionPoint; + use x509::ext::pkix::crl::CrlDistributionPoints; + use x509::ext::pkix::name::{DistributionPointName, GeneralName}; + use x509::ext::pkix::{BasicConstraints, KeyUsage, KeyUsages}; + use x509::name::RdnSequence; + use x509::time::{Time, Validity}; + use x509::{Certificate, TbsCertificate}; + use zeroize::Zeroizing; + + const REVOKED_SERIAL: u32 = 99; + const TEST_URL: &str = "https://pki.example.com/crl.der"; + + fn create_ca() -> (Zeroizing>, Vec) { + // Generate the private key. + let key = PrivateKeyInfo::generate(P256).unwrap(); + let pki = PrivateKeyInfo::from_der(key.as_ref()).unwrap(); + + // Create a relative distinguished name. + let rdns = RdnSequence::encode_from_string(&"CN=localhost").unwrap(); + let rdns = RdnSequence::from_der(&rdns).unwrap(); + + // Create the extensions. + let ku = KeyUsage((KeyUsages::KeyCertSign | KeyUsages::CRLSign).into()) + .to_vec() + .unwrap(); + let bc = BasicConstraints { + ca: true, + path_len_constraint: Some(0), + } + .to_vec() + .unwrap(); + + // Create the certificate duration. + let now = SystemTime::now(); + let dur = Duration::from_secs(60 * 60); + let validity = Validity { + not_before: Time::GeneralTime(GeneralizedTime::from_system_time(now).unwrap()), + not_after: Time::GeneralTime(GeneralizedTime::from_system_time(now + dur).unwrap()), + }; + + let crl_dist = CrlDistributionPoints { + 0: vec![DistributionPoint { + distribution_point: Some(DistributionPointName::FullName(vec![ + GeneralName::UniformResourceIdentifier(Ia5StringRef::new(TEST_URL).unwrap()), + ])), + reasons: None, + crl_issuer: None, + }], + }; + + let crl_dist = crl_dist.to_vec().unwrap(); + + // Create the certificate body. + let tbs = TbsCertificate { + version: x509::Version::V3, + serial_number: UIntRef::new(&[0u8]).unwrap(), + signature: pki.signs_with().unwrap(), + issuer: rdns.clone(), + validity, + subject: rdns, + subject_public_key_info: pki.public_key().unwrap(), + issuer_unique_id: None, + subject_unique_id: None, + extensions: Some(vec![ + x509::ext::Extension { + extn_id: ID_CE_KEY_USAGE, + critical: true, + extn_value: &ku, + }, + x509::ext::Extension { + extn_id: ID_CE_BASIC_CONSTRAINTS, + critical: true, + extn_value: &bc, + }, + x509::ext::Extension { + extn_id: const_oid::db::rfc5912::ID_CE_CRL_DISTRIBUTION_POINTS, + critical: true, + extn_value: &crl_dist, + }, + ]), + }; + + // Self-sign the certificate. + let crt = tbs.sign(&pki).unwrap(); + + (key, crt) + } + + fn create_cert( + ca_key: &Zeroizing>, + cert_serial: &UIntRef, + ) -> (Zeroizing>, Vec) { + let ca_pki = PrivateKeyInfo::from_der(ca_key.as_ref()).unwrap(); + + // Generate the private key. + let key = PrivateKeyInfo::generate(P256).unwrap(); + let pki = PrivateKeyInfo::from_der(key.as_ref()).unwrap(); + + // Create the extensions. + let ku = KeyUsage(KeyUsages::EncipherOnly.into()).to_vec().unwrap(); + let bc = BasicConstraints { + ca: false, + path_len_constraint: None, + } + .to_vec() + .unwrap(); + + // Create a relative distinguished name. + let rdns = RdnSequence::encode_from_string(&"CN=localhost").unwrap(); + let rdns = RdnSequence::from_der(&rdns).unwrap(); + + // Create the certificate duration. + let now = SystemTime::now(); + let dur = Duration::from_secs(60 * 60); + let validity = Validity { + not_before: Time::GeneralTime(GeneralizedTime::from_system_time(now).unwrap()), + not_after: Time::GeneralTime(GeneralizedTime::from_system_time(now + dur).unwrap()), + }; + + // Create the certificate body. + let tbs = TbsCertificate { + version: x509::Version::V3, + serial_number: cert_serial.clone(), + signature: pki.signs_with().unwrap(), + issuer: rdns.clone(), + validity, + subject: rdns, + subject_public_key_info: pki.public_key().unwrap(), + issuer_unique_id: None, + subject_unique_id: None, + extensions: Some(vec![ + x509::ext::Extension { + extn_id: ID_CE_KEY_USAGE, + critical: true, + extn_value: &ku, + }, + x509::ext::Extension { + extn_id: ID_CE_BASIC_CONSTRAINTS, + critical: true, + extn_value: &bc, + }, + ]), + }; + + // Self-sign the certificate. + let crt = tbs.sign(&ca_pki).unwrap(); + + (key, crt) + } + + fn create_crl( + ca_key: &Zeroizing>, + ca_cert: &Certificate, + cert_serial: Option, + ) -> Vec { + let ca_pki = PrivateKeyInfo::from_der(ca_key.as_ref()).unwrap(); + + let now = SystemTime::now(); + let dur = Duration::from_secs(60 * 60 * 24); + let yesterday = Time::GeneralTime(GeneralizedTime::from_system_time(now - dur).unwrap()); + + let revoked = if let Some(serial) = cert_serial { + Some(vec![RevokedCert { + serial_number: serial, + revocation_date: yesterday, + crl_entry_extensions: None, + }]) + } else { + None + }; + + let tbs_cert = TbsCertList { + version: Default::default(), + signature: ca_cert.signature_algorithm.clone(), + issuer: Default::default(), + this_update: yesterday, + next_update: None, + revoked_certificates: revoked, + crl_extensions: None, + }; + + let signature = ca_pki + .sign( + &tbs_cert.to_vec().unwrap(), + ca_cert.signature_algorithm.clone(), + ) + .unwrap(); + + let crl = CertificateList { + tbs_cert_list: tbs_cert, + signature_algorithm: ca_cert.signature_algorithm.clone(), + signature: BitStringRef::from_bytes(&signature).unwrap(), + }; + + crl.to_vec().unwrap() + } + + #[test] + fn not_revoked() { + let revoked_serial = REVOKED_SERIAL.to_be_bytes(); + let revoked_serial = UIntRef::new(&revoked_serial).unwrap(); + + // Create a Certificate Authority + let (ca_pki, ca_cert) = create_ca(); + let ca_cert = Certificate::from_der(&ca_cert).unwrap(); + + // Create an end Certificate + let (_end_pki, end_cert) = create_cert(&ca_pki, &revoked_serial); + let end_cert = Certificate::from_der(&end_cert).unwrap(); + + // Create a empty Certificate Revocation List + let crl = create_crl(&ca_pki, &ca_cert, None); + let crl = CertificateList::from_der(&crl).unwrap(); + + // Check the PKI path (CA and end Certificates) + let path = PkiPath::from([ca_cert, end_cert]); + + let crl_pair = CachedCrl { + crls: vec![CrlPair { + url: TEST_URL.into(), + crl, + }], + }; + + // Should be okay + assert!(path.check_crl(&crl_pair).is_ok()); + } + + #[test] + fn revoked() { + let revoked_serial = REVOKED_SERIAL.to_be_bytes(); + let revoked_serial = UIntRef::new(&revoked_serial).unwrap(); + + // Create a Certificate Authority + let (ca_pki, ca_cert) = create_ca(); + let ca_cert = Certificate::from_der(&ca_cert).unwrap(); + + // Create an end Certificate + let (_end_pki, end_cert) = create_cert(&ca_pki, &revoked_serial); + let end_cert = Certificate::from_der(&end_cert).unwrap(); + + // Create a Certificate Revocation List + let crl = create_crl(&ca_pki, &ca_cert, Some(revoked_serial)); + let crl = CertificateList::from_der(&crl).unwrap(); + + // Check the PKI path (CA and end Certificates) + let path = PkiPath::from([ca_cert, end_cert]); + + let crl_pair = CachedCrl { + crls: vec![CrlPair { + url: TEST_URL.into(), + crl, + }], + }; + + // Should be revoked! + let err = path.check_crl(&crl_pair).err().unwrap(); + assert_eq!(err.to_string(), "revoked!"); + } + + #[test] + fn wrong_crl() { + let revoked_serial = REVOKED_SERIAL.to_be_bytes(); + let revoked_serial = UIntRef::new(&revoked_serial).unwrap(); + + // Create a Certificate Authority + let (ca_pki1, ca_cert1) = create_ca(); + let ca_cert1 = Certificate::from_der(&ca_cert1).unwrap(); + + // Create a second Certificate Authority + let (ca_pki2, ca_cert2) = create_ca(); + let ca_cert2 = Certificate::from_der(&ca_cert2).unwrap(); + + // Create an end Certificate + let (_end_pki, end_cert) = create_cert(&ca_pki1, &revoked_serial); + let end_cert = Certificate::from_der(&end_cert).unwrap(); + + // Create an empty Certificate Revocation List from second Certificate Authority + let empty_crl = create_crl(&ca_pki2, &ca_cert2, None); + let empty_crl = CertificateList::from_der(&empty_crl).unwrap(); + + // Check the PKI path (CA and end Certificates) + let path = PkiPath::from([ca_cert1, end_cert]); + + let crl_pair = CachedCrl { + crls: vec![CrlPair { + url: TEST_URL.into(), + crl: empty_crl, + }], + }; + + // Should fail as the provided CRL isn't for this Certificate chain + let err = path.check_crl(&crl_pair).err().unwrap(); + assert_eq!(err.to_string(), "no valid CRL was provided"); + } +} diff --git a/crates/attestation/src/crypto/mod.rs b/crates/attestation/src/crypto/mod.rs index a1a98822..2cd9c2e2 100644 --- a/crates/attestation/src/crypto/mod.rs +++ b/crates/attestation/src/crypto/mod.rs @@ -3,10 +3,12 @@ mod cert; mod certreq; +mod crl; mod pki; mod spki; pub use self::cert::TbsCertificateExt; pub use self::certreq::{CertReqExt, CertReqInfoExt}; +pub use self::crl::{CachedCrl, CrlPair, PkiPathCRLCheck}; pub use self::pki::PrivateKeyInfoExt; pub use self::spki::SubjectPublicKeyInfoExt; diff --git a/crates/attestation/src/sgx/icelake.signed.crl.csr b/crates/attestation/src/sgx/icelake.signed.crl.csr new file mode 100644 index 00000000..849080af Binary files /dev/null and b/crates/attestation/src/sgx/icelake.signed.crl.csr differ diff --git a/crates/attestation/src/sgx/icelake.signed.csr b/crates/attestation/src/sgx/icelake.signed.csr deleted file mode 100644 index e6bb2502..00000000 Binary files a/crates/attestation/src/sgx/icelake.signed.csr and /dev/null differ diff --git a/crates/attestation/src/sgx/mod.rs b/crates/attestation/src/sgx/mod.rs index f273fbfa..d502181a 100644 --- a/crates/attestation/src/sgx/mod.rs +++ b/crates/attestation/src/sgx/mod.rs @@ -14,7 +14,7 @@ use anyhow::{bail, ensure, Result}; use const_oid::ObjectIdentifier; use der::{Decode, Encode}; use sha2::{Digest, Sha256}; -use x509::{ext::Extension, request::CertReqInfo, Certificate, TbsCertificate}; +use x509::{ext::Extension, request::CertReqInfo, Certificate, PkiPath, TbsCertificate}; #[derive(Clone, Debug)] pub struct Sgx([Certificate<'static>; 1]); @@ -30,12 +30,18 @@ impl Sgx { pub const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.4.1.58270.1.2"); pub const ATT: bool = true; - pub fn trusted<'c>(&'c self, chain: &'c [Certificate<'c>]) -> Result<&'c TbsCertificate<'c>> { + pub fn trusted<'c>( + &'c self, + chain: &'c [Certificate<'c>], + crls: &'c CachedCrl<'c>, + ) -> Result<&'c TbsCertificate<'c>> { let mut signer = &self.0[0].tbs_certificate; for cert in self.0.iter().chain(chain.iter()) { signer = signer.verify_crt(cert)?; } + PkiPath::from(chain).check_crl(crls)?; + Ok(signer) } @@ -60,7 +66,7 @@ impl Sgx { .collect::, _>>()?; // Validate the report. - let pck = self.trusted(&chain)?; + let pck = self.trusted(&chain, "e.crls)?; let rpt = quote.verify(pck)?; // Force certs to have the same key type as the PCK. diff --git a/crates/attestation/src/sgx/quote.icelake b/crates/attestation/src/sgx/quote.icelake deleted file mode 100644 index 908c43a0..00000000 Binary files a/crates/attestation/src/sgx/quote.icelake and /dev/null differ diff --git a/crates/attestation/src/sgx/quote.unknown b/crates/attestation/src/sgx/quote.unknown deleted file mode 100644 index 869978dd..00000000 Binary files a/crates/attestation/src/sgx/quote.unknown and /dev/null differ diff --git a/crates/attestation/src/sgx/quote/mod.rs b/crates/attestation/src/sgx/quote/mod.rs index 15eca175..e4d49fcf 100644 --- a/crates/attestation/src/sgx/quote/mod.rs +++ b/crates/attestation/src/sgx/quote/mod.rs @@ -15,27 +15,37 @@ pub mod es256; pub mod qe; pub mod traits; -use super::super::crypto::TbsCertificateExt; +use super::super::crypto::{CachedCrl, TbsCertificateExt}; use body::Body; use traits::{FromBytes, ParseBytes, Steal}; use anyhow::anyhow; -use der::Encode; +use der::{Decode, Encode, Sequence}; use p256::ecdsa::signature::Verifier; use sgx::ReportBody; use sha2::{digest::DynDigest, Sha256}; use x509::TbsCertificate; +#[derive(Sequence)] +struct SgxEvidence<'a> { + #[asn1(type = "OCTET STRING")] + quote: &'a [u8], + crl: CachedCrl<'a>, +} + pub struct Quote<'a> { body: &'a Body, sign: es256::SignatureData<'a>, + pub crls: CachedCrl<'a>, } impl<'a> FromBytes<'a> for Quote<'a> { type Error = anyhow::Error; fn from_bytes(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), Self::Error> { - let (body, bytes): (&Body, _) = bytes.parse()?; + let evidence = SgxEvidence::from_der(bytes)?; + + let (body, bytes): (&Body, _) = evidence.quote.parse()?; if body.version() != 3 { return Err(anyhow!("unsupported quote version")); @@ -50,8 +60,9 @@ impl<'a> FromBytes<'a> for Quote<'a> { } let (sign, bytes) = bytes.parse()?; + let crls = evidence.crl; - Ok((Quote { body, sign }, bytes)) + Ok((Quote { body, sign, crls }, bytes)) } } diff --git a/crates/attestation/src/snp/milan.rprt b/crates/attestation/src/snp/milan.rprt deleted file mode 100644 index be1b2902..00000000 Binary files a/crates/attestation/src/snp/milan.rprt and /dev/null differ diff --git a/crates/attestation/src/snp/milan.signed.crl.csr b/crates/attestation/src/snp/milan.signed.crl.csr new file mode 100644 index 00000000..b197a2f1 Binary files /dev/null and b/crates/attestation/src/snp/milan.signed.crl.csr differ diff --git a/crates/attestation/src/snp/milan.signed.csr b/crates/attestation/src/snp/milan.signed.csr deleted file mode 100644 index f3c30c26..00000000 Binary files a/crates/attestation/src/snp/milan.signed.csr and /dev/null differ diff --git a/crates/attestation/src/snp/milan.vcek b/crates/attestation/src/snp/milan.vcek deleted file mode 100644 index 8a45abf1..00000000 Binary files a/crates/attestation/src/snp/milan.vcek and /dev/null differ diff --git a/crates/attestation/src/snp/mod.rs b/crates/attestation/src/snp/mod.rs index 35e2a00d..36f91ad6 100644 --- a/crates/attestation/src/snp/mod.rs +++ b/crates/attestation/src/snp/mod.rs @@ -4,7 +4,7 @@ pub mod config; use self::config::Config; -use super::crypto::TbsCertificateExt; +use super::crypto::{CachedCrl, PkiPathCRLCheck, TbsCertificateExt}; use std::{fmt::Debug, mem::size_of}; @@ -23,8 +23,14 @@ use x509::{request::CertReqInfo, Certificate}; use x509::{PkiPath, TbsCertificate}; #[derive(Clone, Debug, PartialEq, Eq, Sequence)] -pub struct Evidence<'a> { +pub struct Certificates<'a> { pub vcek: Certificate<'a>, + pub crl: CachedCrl<'a>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Sequence)] +pub struct Evidence<'a> { + pub crts: Certificates<'a>, #[asn1(type = "OCTET STRING")] pub report: &'a [u8], @@ -234,9 +240,10 @@ impl Snp { pub const ATT: bool = true; // This ensures that the supplied vcek is rooted in one of our trusted chains. - fn is_trusted<'c>(&self, vcek: &'c Certificate<'c>) -> Result<&'c TbsCertificate<'c>> { + fn is_trusted<'c>(&self, certs: &'c Certificates<'c>) -> Result<&'c TbsCertificate<'c>> { for root in Self::ROOTS { let path = PkiPath::from_der(root)?; + let vcek = &certs.vcek; let mut signer = Some(&path[0].tbs_certificate); for cert in path.iter().chain([vcek].into_iter()) { @@ -245,6 +252,9 @@ impl Snp { if let Some(signer) = signer { if signer == &vcek.tbs_certificate { + let mut path = path; + path.push(vcek.clone()); + path.check_crl(&certs.crl)?; return Ok(&vcek.tbs_certificate); } } @@ -266,7 +276,7 @@ impl Snp { let evidence = Evidence::from_der(ext.extn_value)?; // Validate the VCEK. - let vcek = self.is_trusted(&evidence.vcek)?; + let vcek = self.is_trusted(&evidence.crts)?; // Force certs to have the same key type as the VCEK. // diff --git a/crates/server/src/lib.rs b/crates/server/src/lib.rs index 05dc5079..c460ad95 100644 --- a/crates/server/src/lib.rs +++ b/crates/server/src/lib.rs @@ -444,9 +444,7 @@ mod tests { use super::{init_tracing, TRACING}; use attestation::crypto::{CertReqInfoExt, PrivateKeyInfoExt, TbsCertificateExt}; - use attestation::sgx::Sgx; - use attestation::snp::{Evidence, Snp}; - use const_oid::db::rfc5912::{ID_EXTENSION_REQ, SECP_256_R_1, SECP_384_R_1}; + use const_oid::db::rfc5912::{ID_EXTENSION_REQ, SECP_256_R_1}; use const_oid::ObjectIdentifier; use der::{AnyRef, Decode, Encode}; use x509::attr::Attribute; @@ -553,6 +551,7 @@ mod tests { #[case(BUNDLE, true)] #[tokio::test] async fn kvm_certs(#[case] header: &str, #[case] multi: bool) { + TRACING.call_once(init_tracing); let ext = Extension { extn_id: Kvm::OID, critical: false, @@ -576,6 +575,7 @@ mod tests { #[case(BUNDLE, true)] #[tokio::test] async fn kvm_hostname(#[case] header: &str, #[case] multi: bool) { + TRACING.call_once(init_tracing); let ext = Extension { extn_id: Kvm::OID, critical: false, @@ -599,6 +599,7 @@ mod tests { // actually sends many CSRs, versus an array of just one CSR. #[tokio::test] async fn kvm_hostname_many_certs() { + TRACING.call_once(init_tracing); let ext = Extension { extn_id: Kvm::OID, critical: false, @@ -634,135 +635,12 @@ mod tests { assert_eq!(output.issued.len(), five_crs.len()); } - #[rstest] - #[case(PKCS10, false)] - #[case(BUNDLE, true)] - #[tokio::test] - async fn sgx_certs(#[case] header: &str, #[case] multi: bool) { - TRACING.call_once(init_tracing); - for quote in [ - include_bytes!("../../attestation/src/sgx/quote.unknown").as_slice(), - include_bytes!("../../attestation/src/sgx/quote.icelake").as_slice(), - ] { - let ext = Extension { - extn_id: Sgx::OID, - critical: false, - extn_value: quote, - }; - - let request = Request::builder() - .method("POST") - .uri("/") - .header(CONTENT_TYPE, header) - .body(Body::from(cr(SECP_256_R_1, vec![ext], multi))) - .unwrap(); - - let response = app(certificates_state()).oneshot(request).await.unwrap(); - assert_eq!(response.status(), StatusCode::OK); - attest_response(certificates_state(), response, multi).await; - } - } - - #[rstest] - #[case(PKCS10, false)] - #[case(BUNDLE, true)] - #[tokio::test] - async fn sgx_hostname(#[case] header: &str, #[case] multi: bool) { - TRACING.call_once(init_tracing); - for quote in [ - include_bytes!("../../attestation/src/sgx/quote.unknown").as_slice(), - include_bytes!("../../attestation/src/sgx/quote.icelake").as_slice(), - ] { - let ext = Extension { - extn_id: Sgx::OID, - critical: false, - extn_value: quote, - }; - - let request = Request::builder() - .method("POST") - .uri("/") - .header(CONTENT_TYPE, header) - .body(Body::from(cr(SECP_256_R_1, vec![ext], multi))) - .unwrap(); - - let state = hostname_state(); - let response = app(state.clone()).oneshot(request).await.unwrap(); - assert_eq!(response.status(), StatusCode::OK); - attest_response(state, response, multi).await; - } - } - - #[rstest] - #[case(PKCS10, false)] - #[case(BUNDLE, true)] - #[tokio::test] - async fn snp_certs(#[case] header: &str, #[case] multi: bool) { - TRACING.call_once(init_tracing); - let evidence = Evidence { - vcek: Certificate::from_der(include_bytes!("../../attestation/src/snp/milan.vcek")) - .unwrap(), - report: include_bytes!("../../attestation/src/snp/milan.rprt"), - } - .to_vec() - .unwrap(); - - let ext = Extension { - extn_id: Snp::OID, - critical: false, - extn_value: &evidence, - }; - - let request = Request::builder() - .method("POST") - .uri("/") - .header(CONTENT_TYPE, header) - .body(Body::from(cr(SECP_384_R_1, vec![ext], multi))) - .unwrap(); - - let response = app(certificates_state()).oneshot(request).await.unwrap(); - assert_eq!(response.status(), StatusCode::OK); - attest_response(certificates_state(), response, multi).await; - } - - #[rstest] - #[case(PKCS10, false)] - #[case(BUNDLE, true)] - #[tokio::test] - async fn snp_hostname(#[case] header: &str, #[case] multi: bool) { - TRACING.call_once(init_tracing); - let evidence = Evidence { - vcek: Certificate::from_der(include_bytes!("../../attestation/src/snp/milan.vcek")) - .unwrap(), - report: include_bytes!("../../attestation/src/snp/milan.rprt"), - } - .to_vec() - .unwrap(); - - let ext = Extension { - extn_id: Snp::OID, - critical: false, - extn_value: &evidence, - }; - - let request = Request::builder() - .method("POST") - .uri("/") - .header(CONTENT_TYPE, header) - .body(Body::from(cr(SECP_384_R_1, vec![ext], multi))) - .unwrap(); - - let state = hostname_state(); - let response = app(state.clone()).oneshot(request).await.unwrap(); - assert_eq!(response.status(), StatusCode::OK); - attest_response(state, response, multi).await; - } - #[rstest] #[case(PKCS10, false)] #[case(BUNDLE, true)] #[tokio::test] async fn err_no_attestation_certs(#[case] header: &str, #[case] multi: bool) { + TRACING.call_once(init_tracing); let request = Request::builder() .method("POST") .uri("/") @@ -776,6 +654,7 @@ mod tests { #[tokio::test] async fn err_no_attestation_hostname() { + TRACING.call_once(init_tracing); let request = Request::builder() .method("POST") .uri("/") @@ -792,6 +671,7 @@ mod tests { #[case(true)] #[tokio::test] async fn err_no_content_type(#[case] multi: bool) { + TRACING.call_once(init_tracing); let request = Request::builder() .method("POST") .uri("/") @@ -804,6 +684,7 @@ mod tests { #[tokio::test] async fn err_empty_body() { + TRACING.call_once(init_tracing); let request = Request::builder() .method("POST") .uri("/") @@ -816,6 +697,7 @@ mod tests { #[tokio::test] async fn err_bad_body() { + TRACING.call_once(init_tracing); let request = Request::builder() .method("POST") .uri("/") @@ -828,6 +710,7 @@ mod tests { #[tokio::test] async fn err_bad_csr_sig() { + TRACING.call_once(init_tracing); let mut cr = cr(SECP_256_R_1, vec![], true); let last = cr.last_mut().unwrap(); *last = last.wrapping_add(1); // Modify the signature... @@ -862,9 +745,9 @@ mod tests { const DEFAULT_CONFIG: &str = include_str!("../../../testdata/steward.toml"); const ICELAKE_CSR: &[u8] = - include_bytes!("../../../crates/attestation/src/sgx/icelake.signed.csr"); + include_bytes!("../../../crates/attestation/src/sgx/icelake.signed.crl.csr"); const MILAN_CSR: &[u8] = - include_bytes!("../../../crates/attestation/src/snp/milan.signed.csr"); + include_bytes!("../../../crates/attestation/src/snp/milan.signed.crl.csr"); fn assert_sgx_config( csr: &CertReq<'_>, @@ -885,7 +768,7 @@ mod tests { .collect::, _>>()?; // Validate the report. - let pck = sgx.trusted(&chain)?; + let pck = sgx.trusted(&chain, "e.crls)?; let report = quote.verify(pck)?; sgx.verify(&csr.info, &ext, Some(conf), false)?; } diff --git a/testdata/steward.toml b/testdata/steward.toml index aaeb661f..8af7d143 100644 --- a/testdata/steward.toml +++ b/testdata/steward.toml @@ -1,14 +1,14 @@ [sgx] -signer = ["c8dc9fe36caaeef871e6512c481092754c57c2ea999f128282ccb563d1602774"] -hash = ["e106565074be5ef3897711472617a0a000bae5c577f69a42202e3f76a07980f3"] +signer = ["c88de47bcb4c199a599c5ea0ab43bf4f4292071a16ea96c840409d95c4f98480"] +hash = ["c2d4e5ac5ccfeeec41f44431c1af4f6878388d86300896125fc60143d30e67bd"] features = ["Debug", "ProvisioningKey", "EInitKey", "KSS"] enclave_security_version = 0 enclave_product_id = 0 [snp] -signer = ["5b2181f5e2294fa0709d22b3f85d9d88b287b897c6b7289004802b53bbf09bc50f5469f98a6d6718d5f9c918d3d3c16f"] -id_key_digest = ["966a25a22ee44283aa51bfb3682c990fd9e0a7457c5f60f4ac4eb5c41715478c4b206b0e01dc11aae8628f5aa29e0560"] -hash = ["6ff9ac4c61adc4cd2d86264230afc386358a5b41221dd236de92a3b45cb8a590bf719388994711ab9fe2b192bebc18a2"] +signer = ["7dc22240a8344fce6ba5f22ffbedabc52d4123ae0ba1c59796e521b953916b503f223b15c4429e7d8c5489ad71f1e193"] +id_key_digest = ["d71a4d1da440d515cd69fbb1314acf4221726e82768a8bf6e4a4063ed542ac78349c8145b4666a4242a91a374387b473"] +hash = ["ff717ae719840c93c1fca3b7db96488454c3c21b43531488eecff51cfed3febcd91da8be87a4cbcbc52a3bae770987c3"] abi = ">=1.51" policy_flags = ["SMT"] platform_info_flags = "SME"