From b47ca81d2d8f48ba0715a6fb551beacad160e1a3 Mon Sep 17 00:00:00 2001 From: Richard Zak Date: Thu, 20 Oct 2022 12:57:20 -0400 Subject: [PATCH] chore: refactor crypto, attestation into crates Signed-off-by: Richard Zak --- Cargo.lock | 56 ++++++++-- Cargo.toml | 22 ++-- crates/cryptography/Cargo.toml | 22 ++++ .../cryptography/src/ext}/cert.rs | 0 .../cryptography/src/ext}/certreq.rs | 0 .../cryptography/src/ext}/mod.rs | 0 .../cryptography/src/ext}/pki.rs | 0 .../cryptography/src/ext}/spki.rs | 0 crates/cryptography/src/lib.rs | 15 +++ crates/sgx_validation/Cargo.toml | 15 +++ .../sgx_validation/src/lib.rs | 18 ++-- .../sgx_validation/src}/quote.icelake | Bin .../sgx_validation/src}/quote.unknown | Bin .../sgx_validation/src}/quote/body.rs | 0 .../sgx_validation/src}/quote/es256.rs | 4 +- .../sgx_validation/src}/quote/mod.rs | 15 +-- .../sgx_validation/src}/quote/qe/auth.rs | 0 .../sgx_validation/src}/quote/qe/cert.rs | 4 +- .../sgx_validation/src}/quote/qe/mod.rs | 0 .../sgx_validation/src}/quote/traits.rs | 0 .../sgx_validation/src}/root.der | Bin crates/snp_validation/Cargo.toml | 15 +++ .../snp_validation/src}/genoa.pkipath | Bin .../snp_validation/src/lib.rs | 33 +++--- .../snp_validation/src}/milan.pkipath | Bin .../snp_validation/src}/milan.rprt | Bin .../snp_validation/src}/milan.vcek | Bin src/ext/mod.rs | 32 ------ src/{ext => }/kvm.rs | 19 ++-- src/main.rs | 100 ++++++++++-------- 30 files changed, 222 insertions(+), 148 deletions(-) create mode 100644 crates/cryptography/Cargo.toml rename {src/crypto => crates/cryptography/src/ext}/cert.rs (100%) rename {src/crypto => crates/cryptography/src/ext}/certreq.rs (100%) rename {src/crypto => crates/cryptography/src/ext}/mod.rs (100%) rename {src/crypto => crates/cryptography/src/ext}/pki.rs (100%) rename {src/crypto => crates/cryptography/src/ext}/spki.rs (100%) create mode 100644 crates/cryptography/src/lib.rs create mode 100644 crates/sgx_validation/Cargo.toml rename src/ext/sgx/mod.rs => crates/sgx_validation/src/lib.rs (89%) rename {src/ext/sgx => crates/sgx_validation/src}/quote.icelake (100%) rename {src/ext/sgx => crates/sgx_validation/src}/quote.unknown (100%) rename {src/ext/sgx => crates/sgx_validation/src}/quote/body.rs (100%) rename {src/ext/sgx => crates/sgx_validation/src}/quote/es256.rs (99%) rename {src/ext/sgx => crates/sgx_validation/src}/quote/mod.rs (86%) rename {src/ext/sgx => crates/sgx_validation/src}/quote/qe/auth.rs (100%) rename {src/ext/sgx => crates/sgx_validation/src}/quote/qe/cert.rs (90%) rename {src/ext/sgx => crates/sgx_validation/src}/quote/qe/mod.rs (100%) rename {src/ext/sgx => crates/sgx_validation/src}/quote/traits.rs (100%) rename {src/ext/sgx => crates/sgx_validation/src}/root.der (100%) create mode 100644 crates/snp_validation/Cargo.toml rename {src/ext/snp => crates/snp_validation/src}/genoa.pkipath (100%) rename src/ext/snp/mod.rs => crates/snp_validation/src/lib.rs (94%) rename {src/ext/snp => crates/snp_validation/src}/milan.pkipath (100%) rename {src/ext/snp => crates/snp_validation/src}/milan.rprt (100%) rename {src/ext/snp => crates/snp_validation/src}/milan.vcek (100%) delete mode 100644 src/ext/mod.rs rename src/{ext => }/kvm.rs (66%) diff --git a/Cargo.lock b/Cargo.lock index 760d1b0f..b6f9604c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -230,6 +230,26 @@ dependencies = [ "typenum", ] +[[package]] +name = "cryptography" +version = "0.2.0" +dependencies = [ + "anyhow", + "const-oid", + "der", + "p256", + "p384", + "rand", + "rsa", + "rustls-pemfile", + "sec1", + "sha2", + "signature", + "spki", + "x509-cert", + "zeroize", +] + [[package]] name = "der" version = "0.6.0" @@ -989,6 +1009,17 @@ dependencies = [ "xsave", ] +[[package]] +name = "sgx_validation" +version = "0.2.0" +dependencies = [ + "anyhow", + "cryptography", + "der", + "sgx", + "testaso", +] + [[package]] name = "sha1" version = "0.10.5" @@ -1036,6 +1067,17 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +[[package]] +name = "snp_validation" +version = "0.2.0" +dependencies = [ + "anyhow", + "cryptography", + "der", + "flagset", + "testaso", +] + [[package]] name = "socket2" version = "0.4.7" @@ -1071,24 +1113,17 @@ dependencies = [ "base64", "clap", "confargs", - "const-oid", + "cryptography", "der", "flagset", "http", "hyper", "memoffset", "mime", - "p256", - "p384", - "rand", - "rsa", "rstest", - "rustls-pemfile", - "sec1", "sgx", - "sha2", - "signature", - "spki", + "sgx_validation", + "snp_validation", "testaso", "tokio", "tower", @@ -1096,7 +1131,6 @@ dependencies = [ "tracing", "tracing-subscriber", "uuid", - "x509-cert", "zeroize", ] diff --git a/Cargo.toml b/Cargo.toml index 5fbf0027..44dddcd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,21 +10,13 @@ license = "AGPL-3.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -const-oid = { version = "0.9.0", features = ["db"], default-features = false } +sgx_validation = { path = "crates/sgx_validation" } +snp_validation = { path = "crates/snp_validation" } +cryptography = { path = "crates/cryptography" } der = { version = "0.6", features = ["std"], default-features = false } -sec1 = { version = "0.3", features = ["std", "pkcs8"], default-features = false } -spki = { version = "0.6", default-features = false } -x509 = { version = "0.1", features = ["std"], package = "x509-cert", default-features = false } -rustls-pemfile = {version = "1.0.1", default-features = false } -sha2 = { version = "^0.10.2", default-features = false } zeroize = { version = "^1.5.2", features = ["alloc"], default-features = false } flagset = { version = "0.4.3", default-features = false} sgx = { version = "0.5.0", default-features = false } -signature = {version = "1.6", default-features = false } -rsa = {version = "0.7.1", features = ["std"], default-features = false } -p256 = { version = "0.11", features = ["ecdsa", "std", "pem"], default-features = false } -p384 = { version = "0.11", features = ["ecdsa", "std", "pem"], default-features = false } -rand = { version = "0.8", features = ["std"], default-features = false } tracing-subscriber = { version="^0.3.15", features = ["env-filter", "json", "fmt"], default-features = false } tower-http = { version = "^0.3.0", features = ["trace"], default-features = false } @@ -55,3 +47,11 @@ incremental = false codegen-units = 1 lto = true strip = true + +[workspace] +resolver = '2' +members = [ + 'crates/sgx_validation', + 'crates/snp_validation', + 'crates/cryptography', +] diff --git a/crates/cryptography/Cargo.toml b/crates/cryptography/Cargo.toml new file mode 100644 index 00000000..10936e85 --- /dev/null +++ b/crates/cryptography/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "cryptography" +version = "0.2.0" +edition = "2021" +license = "AGPL-3.0" +description = "Cryptography library for Steward" + +[dependencies] +anyhow = { version = "^1.0.55", features = ["std"], default-features = false } +const-oid = { version = "0.9.0", features = ["db"], default-features = false } +der = { version = "0.6", features = ["std"], default-features = false } +rand = { version = "0.8", features = ["std"], default-features = false } +rsa = {version = "0.7.1", features = ["std"], default-features = false } +rustls-pemfile = {version = "1.0.1", default-features = false } +sec1 = { version = "0.3", features = ["std", "pkcs8"], default-features = false } +sha2 = { version = "^0.10.2", default-features = false } +signature = {version = "1.6", default-features = false } +spki = { version = "0.6", default-features = false } +p256 = { version = "0.11", features = ["ecdsa", "std", "pem"], default-features = false } +p384 = { version = "0.11", features = ["ecdsa", "std", "pem"], default-features = false } +x509 = { version = "0.1", features = ["std"], package = "x509-cert", default-features = false } +zeroize = { version = "^1.5.2", features = ["alloc"], default-features = false } diff --git a/src/crypto/cert.rs b/crates/cryptography/src/ext/cert.rs similarity index 100% rename from src/crypto/cert.rs rename to crates/cryptography/src/ext/cert.rs diff --git a/src/crypto/certreq.rs b/crates/cryptography/src/ext/certreq.rs similarity index 100% rename from src/crypto/certreq.rs rename to crates/cryptography/src/ext/certreq.rs diff --git a/src/crypto/mod.rs b/crates/cryptography/src/ext/mod.rs similarity index 100% rename from src/crypto/mod.rs rename to crates/cryptography/src/ext/mod.rs diff --git a/src/crypto/pki.rs b/crates/cryptography/src/ext/pki.rs similarity index 100% rename from src/crypto/pki.rs rename to crates/cryptography/src/ext/pki.rs diff --git a/src/crypto/spki.rs b/crates/cryptography/src/ext/spki.rs similarity index 100% rename from src/crypto/spki.rs rename to crates/cryptography/src/ext/spki.rs diff --git a/crates/cryptography/src/lib.rs b/crates/cryptography/src/lib.rs new file mode 100644 index 00000000..9e8bd054 --- /dev/null +++ b/crates/cryptography/src/lib.rs @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2022 Profian Inc. +// SPDX-License-Identifier: AGPL-3.0-only + +pub mod ext; + +pub use const_oid; +pub use p256; +pub use p384; +pub use rand; +pub use rsa; +pub use rustls_pemfile; +pub use sec1; +pub use sha2; +pub use signature; +pub use x509; diff --git a/crates/sgx_validation/Cargo.toml b/crates/sgx_validation/Cargo.toml new file mode 100644 index 00000000..9291343d --- /dev/null +++ b/crates/sgx_validation/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "sgx_validation" +version = "0.2.0" +edition = "2021" +license = "AGPL-3.0" +description = "Intel SGX Attestation validation library for Steward" + +[dependencies] +cryptography = { path = "../cryptography" } +anyhow = { version = "^1.0.55", default-features = false } +der = { version = "0.6", features = ["std"], default-features = false } +sgx = { version = "0.5.0", default-features = false } + +[dev-dependencies] +testaso = { version = "0.1", default-features = false } diff --git a/src/ext/sgx/mod.rs b/crates/sgx_validation/src/lib.rs similarity index 89% rename from src/ext/sgx/mod.rs rename to crates/sgx_validation/src/lib.rs index d2828dbd..20e5952f 100644 --- a/src/ext/sgx/mod.rs +++ b/crates/sgx_validation/src/lib.rs @@ -3,18 +3,17 @@ mod quote; -use super::ExtVerifier; -use crate::crypto::*; +use cryptography::ext::*; use quote::traits::ParseBytes; use std::fmt::Debug; use anyhow::{anyhow, Result}; -use const_oid::ObjectIdentifier; +use cryptography::const_oid::ObjectIdentifier; +use cryptography::sha2::{Digest, Sha256}; +use cryptography::x509::{ext::Extension, request::CertReqInfo, Certificate, TbsCertificate}; use der::{Decode, Encode}; use sgx::parameters::{Attributes, MiscSelect}; -use sha2::{Digest, Sha256}; -use x509::{ext::Extension, request::CertReqInfo, Certificate, TbsCertificate}; #[derive(Clone, Debug)] pub struct Sgx([Certificate<'static>; 1]); @@ -27,6 +26,8 @@ impl Default for Sgx { impl Sgx { const ROOT: &'static [u8] = include_bytes!("root.der"); + pub const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.4.1.58270.1.2"); + pub const ATT: bool = true; fn trusted<'c>(&'c self, chain: &'c [Certificate<'c>]) -> Result<&'c TbsCertificate<'c>> { let mut signer = &self.0[0].tbs_certificate; @@ -36,13 +37,8 @@ impl Sgx { Ok(signer) } -} - -impl ExtVerifier for Sgx { - const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.4.1.58270.1.2"); - const ATT: bool = true; - fn verify(&self, cri: &CertReqInfo<'_>, ext: &Extension<'_>, dbg: bool) -> Result { + pub fn verify(&self, cri: &CertReqInfo<'_>, ext: &Extension<'_>, dbg: bool) -> Result { if ext.critical { return Err(anyhow!("sgx extension cannot be critical")); } diff --git a/src/ext/sgx/quote.icelake b/crates/sgx_validation/src/quote.icelake similarity index 100% rename from src/ext/sgx/quote.icelake rename to crates/sgx_validation/src/quote.icelake diff --git a/src/ext/sgx/quote.unknown b/crates/sgx_validation/src/quote.unknown similarity index 100% rename from src/ext/sgx/quote.unknown rename to crates/sgx_validation/src/quote.unknown diff --git a/src/ext/sgx/quote/body.rs b/crates/sgx_validation/src/quote/body.rs similarity index 100% rename from src/ext/sgx/quote/body.rs rename to crates/sgx_validation/src/quote/body.rs diff --git a/src/ext/sgx/quote/es256.rs b/crates/sgx_validation/src/quote/es256.rs similarity index 99% rename from src/ext/sgx/quote/es256.rs rename to crates/sgx_validation/src/quote/es256.rs index ffcf3f4b..0427813f 100644 --- a/src/ext/sgx/quote/es256.rs +++ b/crates/sgx_validation/src/quote/es256.rs @@ -3,9 +3,9 @@ use super::{qe::QuotingEnclave, FromBytes, ParseBytes}; -use std::array::TryFromSliceError; - +use anyhow::anyhow; use der::{asn1::UIntRef, Sequence}; +use std::array::TryFromSliceError; #[derive(Clone, Debug)] #[repr(C)] diff --git a/src/ext/sgx/quote/mod.rs b/crates/sgx_validation/src/quote/mod.rs similarity index 86% rename from src/ext/sgx/quote/mod.rs rename to crates/sgx_validation/src/quote/mod.rs index 694a3baa..19368de3 100644 --- a/src/ext/sgx/quote/mod.rs +++ b/crates/sgx_validation/src/quote/mod.rs @@ -15,15 +15,16 @@ pub mod es256; pub mod qe; pub mod traits; -use crate::crypto::TbsCertificateExt; +use anyhow::anyhow; use body::Body; +use cryptography::ext::TbsCertificateExt; use traits::{FromBytes, ParseBytes, Steal}; +use cryptography::p256::ecdsa::signature::Verifier; +use cryptography::sha2::{digest::DynDigest, Sha256}; +use cryptography::x509::TbsCertificate; use der::Encode; -use p256::ecdsa::signature::Verifier; use sgx::ReportBody; -use sha2::{digest::DynDigest, Sha256}; -use x509::TbsCertificate; pub struct Quote<'a> { body: &'a Body, @@ -71,7 +72,7 @@ impl<'a> Quote<'a> { // Validate the Attestation Key. let mut data = [0u8; 64]; - let mut hash = ::new(); + let mut hash = ::new(); hash.update(self.sign.key.as_ref()); hash.update(self.sign.iqe.auth.as_ref()); hash.finalize_into(&mut data[..32])?; @@ -80,8 +81,8 @@ impl<'a> Quote<'a> { } // Verify the signature on the enclave report. - let vkey = p256::ecdsa::VerifyingKey::from_sec1_bytes(self.sign.key.sec1())?; - let sig = p256::ecdsa::Signature::from_der(&self.sign.sig.to_vec()?)?; + let vkey = cryptography::p256::ecdsa::VerifyingKey::from_sec1_bytes(self.sign.key.sec1())?; + let sig = cryptography::p256::ecdsa::Signature::from_der(&self.sign.sig.to_vec()?)?; vkey.verify(self.body.as_ref(), &sig)?; // Verify the PCE security version. diff --git a/src/ext/sgx/quote/qe/auth.rs b/crates/sgx_validation/src/quote/qe/auth.rs similarity index 100% rename from src/ext/sgx/quote/qe/auth.rs rename to crates/sgx_validation/src/quote/qe/auth.rs diff --git a/src/ext/sgx/quote/qe/cert.rs b/crates/sgx_validation/src/quote/qe/cert.rs similarity index 90% rename from src/ext/sgx/quote/qe/cert.rs rename to crates/sgx_validation/src/quote/qe/cert.rs index 6a69a375..898063b7 100644 --- a/src/ext/sgx/quote/qe/cert.rs +++ b/crates/sgx_validation/src/quote/qe/cert.rs @@ -3,6 +3,8 @@ use super::super::{FromBytes, ParseBytes, Steal}; +use anyhow::anyhow; + #[derive(Clone, Debug)] #[non_exhaustive] pub enum Data { @@ -23,7 +25,7 @@ impl<'a> FromBytes<'a> for Data { .map_err(|e| anyhow!("invalid certification data: {}", e))? .replace("-----END CERTIFICATE-----", "-----END CERTIFICATE-----\n"); - let mut certs = rustls_pemfile::certs(&mut chain.as_bytes()) + let mut certs = cryptography::rustls_pemfile::certs(&mut chain.as_bytes()) .map_err(|e| anyhow!("invalid certification data: {}", e))?; certs.reverse(); diff --git a/src/ext/sgx/quote/qe/mod.rs b/crates/sgx_validation/src/quote/qe/mod.rs similarity index 100% rename from src/ext/sgx/quote/qe/mod.rs rename to crates/sgx_validation/src/quote/qe/mod.rs diff --git a/src/ext/sgx/quote/traits.rs b/crates/sgx_validation/src/quote/traits.rs similarity index 100% rename from src/ext/sgx/quote/traits.rs rename to crates/sgx_validation/src/quote/traits.rs diff --git a/src/ext/sgx/root.der b/crates/sgx_validation/src/root.der similarity index 100% rename from src/ext/sgx/root.der rename to crates/sgx_validation/src/root.der diff --git a/crates/snp_validation/Cargo.toml b/crates/snp_validation/Cargo.toml new file mode 100644 index 00000000..a33087b4 --- /dev/null +++ b/crates/snp_validation/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "snp_validation" +version = "0.2.0" +edition = "2021" +license = "AGPL-3.0" +description = "AMD SEV-SNP Attestation validation library for Steward" + +[dependencies] +cryptography = { path = "../cryptography" } +anyhow = { version = "^1.0.55", default-features = false } +der = { version = "0.6", features = ["std"], default-features = false } +flagset = { version = "0.4.3", default-features = false} + +[dev-dependencies] +testaso = { version = "0.1", default-features = false } diff --git a/src/ext/snp/genoa.pkipath b/crates/snp_validation/src/genoa.pkipath similarity index 100% rename from src/ext/snp/genoa.pkipath rename to crates/snp_validation/src/genoa.pkipath diff --git a/src/ext/snp/mod.rs b/crates/snp_validation/src/lib.rs similarity index 94% rename from src/ext/snp/mod.rs rename to crates/snp_validation/src/lib.rs index 92db26c0..e7c046bb 100644 --- a/src/ext/snp/mod.rs +++ b/crates/snp_validation/src/lib.rs @@ -1,24 +1,21 @@ // SPDX-FileCopyrightText: 2022 Profian Inc. // SPDX-License-Identifier: AGPL-3.0-only -use crate::crypto::*; +use cryptography::ext::*; use std::{fmt::Debug, mem::size_of}; use anyhow::{anyhow, Context, Result}; - -use const_oid::db::rfc5912::ECDSA_WITH_SHA_384; -use const_oid::ObjectIdentifier; +use cryptography::const_oid::db::rfc5912::ECDSA_WITH_SHA_384; +use cryptography::const_oid::ObjectIdentifier; +use cryptography::sec1::pkcs8::AlgorithmIdentifier; +use cryptography::sha2::{Digest, Sha384}; +use cryptography::x509::ext::Extension; +use cryptography::x509::{request::CertReqInfo, Certificate}; +use cryptography::x509::{PkiPath, TbsCertificate}; use der::asn1::UIntRef; use der::{Decode, Encode, Sequence}; use flagset::{flags, FlagSet}; -use sec1::pkcs8::AlgorithmIdentifier; -use sha2::Digest; -use x509::ext::Extension; -use x509::{request::CertReqInfo, Certificate}; -use x509::{PkiPath, TbsCertificate}; - -use super::ExtVerifier; #[derive(Clone, Debug, PartialEq, Eq, Sequence)] pub struct Evidence<'a> { @@ -216,6 +213,9 @@ impl Snp { include_bytes!("genoa.pkipath"), ]; + pub const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.4.1.58270.1.3"); + 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>> { for root in Self::ROOTS { @@ -235,13 +235,8 @@ impl Snp { Err(anyhow!("snp vcek is untrusted")) } -} - -impl ExtVerifier for Snp { - const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.4.1.58270.1.3"); - const ATT: bool = true; - fn verify(&self, cri: &CertReqInfo<'_>, ext: &Extension<'_>, dbg: bool) -> Result { + pub fn verify(&self, cri: &CertReqInfo<'_>, ext: &Extension<'_>, dbg: bool) -> Result { if ext.critical { return Err(anyhow!("snp extension cannot be critical")); } @@ -254,7 +249,7 @@ impl ExtVerifier for Snp { // Force certs to have the same key type as the VCEK. // - // A note about this check is in order. We don't want to build crypto + // A note about this check is in order. We don't want to build ext // algorithm negotiation into this protocol. Not only is it complex // but it is also subject to downgrade attacks. For example, if the // weakest link in the certificate chain is a P384 key and the @@ -374,7 +369,7 @@ impl ExtVerifier for Snp { if !dbg { // Validate that the certification request came from an SNP VM. - let hash = sha2::Sha384::digest(&cri.public_key.to_vec()?); + let hash = Sha384::digest(&cri.public_key.to_vec()?); if hash.as_slice() != &report.body.report_data[..hash.as_slice().len()] { return Err(anyhow!("snp report.report_data is invalid")); } diff --git a/src/ext/snp/milan.pkipath b/crates/snp_validation/src/milan.pkipath similarity index 100% rename from src/ext/snp/milan.pkipath rename to crates/snp_validation/src/milan.pkipath diff --git a/src/ext/snp/milan.rprt b/crates/snp_validation/src/milan.rprt similarity index 100% rename from src/ext/snp/milan.rprt rename to crates/snp_validation/src/milan.rprt diff --git a/src/ext/snp/milan.vcek b/crates/snp_validation/src/milan.vcek similarity index 100% rename from src/ext/snp/milan.vcek rename to crates/snp_validation/src/milan.vcek diff --git a/src/ext/mod.rs b/src/ext/mod.rs deleted file mode 100644 index df54f5c9..00000000 --- a/src/ext/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Profian Inc. -// SPDX-License-Identifier: AGPL-3.0-only - -use anyhow::Result; -use const_oid::ObjectIdentifier; -use x509::{ext::Extension, request::CertReqInfo}; - -pub mod kvm; -pub mod sgx; -pub mod snp; - -/// Validates an extension for inclusion in a certificate. -/// -/// The certification request can contain requests to add an extension to a -/// certificate. Instances of this trait can be used to verify these -/// extensions for inclusion. -pub trait ExtVerifier { - /// The OID of the extensions this verifier can verify. - const OID: ObjectIdentifier; - - /// Whether or not this verifier is an attestation. - const ATT: bool = false; - - /// Verifies a certification request extension request. - /// - /// Returning an error will cancel the entire certification request. - /// Returning `Ok(true)` will cause the extension to be included in the - /// certificate. Returning `Ok(false)` will allow the certification request - /// to continue, but this particular extension will not be included - /// in the resulting certificate. - fn verify(&self, cri: &CertReqInfo<'_>, ext: &Extension<'_>, dbg: bool) -> Result; -} diff --git a/src/ext/kvm.rs b/src/kvm.rs similarity index 66% rename from src/ext/kvm.rs rename to src/kvm.rs index fa9a15dd..b06d7abf 100644 --- a/src/ext/kvm.rs +++ b/src/kvm.rs @@ -2,10 +2,8 @@ // SPDX-License-Identifier: AGPL-3.0-only use anyhow::{anyhow, Result}; -use const_oid::ObjectIdentifier; -use x509::{ext::Extension, request::CertReqInfo}; - -use super::ExtVerifier; +use cryptography::const_oid::ObjectIdentifier; +use cryptography::x509::{ext::Extension, request::CertReqInfo}; /// An extension validator for KVM evidence. /// @@ -15,11 +13,16 @@ use super::ExtVerifier; #[derive(Clone, Debug, Default)] pub struct Kvm(()); -impl ExtVerifier for Kvm { - const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.4.1.58270.1.1"); - const ATT: bool = true; +impl Kvm { + pub(crate) const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.4.1.58270.1.1"); + pub(crate) const ATT: bool = true; - fn verify(&self, _cri: &CertReqInfo<'_>, ext: &Extension<'_>, dbg: bool) -> Result { + pub(crate) fn verify( + &self, + _cri: &CertReqInfo<'_>, + ext: &Extension<'_>, + dbg: bool, + ) -> Result { if ext.critical { return Err(anyhow!("kvm extension cannot be critical")); } diff --git a/src/main.rs b/src/main.rs index 63e013b8..f502aa39 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,11 +5,12 @@ #[macro_use] extern crate anyhow; +mod kvm; -mod crypto; -mod ext; - -use crypto::*; +use cryptography::ext::{CertReqExt, PrivateKeyInfoExt, TbsCertificateExt}; +use kvm::Kvm; +use sgx_validation::Sgx; +use snp_validation::Snp; use std::io::BufRead; use std::net::IpAddr; @@ -26,33 +27,31 @@ use axum::routing::{get, post}; use axum::Router; use clap::Parser; use confargs::{prefix_char_filter, Toml}; -use const_oid::db::rfc5280::{ +use cryptography::const_oid::db::rfc5280::{ ID_CE_BASIC_CONSTRAINTS, ID_CE_EXT_KEY_USAGE, ID_CE_KEY_USAGE, ID_CE_SUBJECT_ALT_NAME, ID_KP_CLIENT_AUTH, ID_KP_SERVER_AUTH, }; -use const_oid::db::rfc5912::ID_EXTENSION_REQ; +use cryptography::const_oid::db::rfc5912::ID_EXTENSION_REQ; +use cryptography::rustls_pemfile; +use cryptography::sec1::pkcs8::PrivateKeyInfo; +use cryptography::x509::attr::Attribute; +use cryptography::x509::ext::pkix::name::GeneralName; +use cryptography::x509::ext::pkix::{ + BasicConstraints, ExtendedKeyUsage, KeyUsage, KeyUsages, SubjectAltName, +}; +use cryptography::x509::name::RdnSequence; +use cryptography::x509::request::{CertReq, ExtensionReq}; +use cryptography::x509::time::{Time, Validity}; +use cryptography::x509::{Certificate, TbsCertificate}; use der::asn1::{GeneralizedTime, Ia5StringRef, UIntRef}; use der::{Decode, Encode, Sequence}; -use ext::kvm::Kvm; -use ext::sgx::Sgx; -use ext::snp::Snp; -use ext::ExtVerifier; use hyper::StatusCode; -use rustls_pemfile::Item; -use sec1::pkcs8::PrivateKeyInfo; use tower_http::trace::{ DefaultOnBodyChunk, DefaultOnEos, DefaultOnFailure, DefaultOnRequest, DefaultOnResponse, TraceLayer, }; use tower_http::LatencyUnit; use tracing::{debug, Level}; -use x509::attr::Attribute; -use x509::ext::pkix::name::GeneralName; -use x509::ext::pkix::{BasicConstraints, ExtendedKeyUsage, KeyUsage, KeyUsages, SubjectAltName}; -use x509::name::RdnSequence; -use x509::request::{CertReq, ExtensionReq}; -use x509::time::{Time, Validity}; -use x509::{Certificate, TbsCertificate}; use zeroize::Zeroizing; const PKCS10: &str = "application/pkcs10"; @@ -130,12 +129,12 @@ impl State { mut crt: impl BufRead, ) -> anyhow::Result { let key = match rustls_pemfile::read_one(&mut key)? { - Some(Item::PKCS8Key(buf)) => Zeroizing::new(buf), + Some(rustls_pemfile::Item::PKCS8Key(buf)) => Zeroizing::new(buf), _ => return Err(anyhow!("invalid key file")), }; let crt = match rustls_pemfile::read_one(&mut crt)? { - Some(Item::X509Certificate(buf)) => buf, + Some(rustls_pemfile::Item::X509Certificate(buf)) => buf, _ => return Err(anyhow!("invalid key file")), }; @@ -147,7 +146,7 @@ impl State { } pub fn generate(san: Option, hostname: &str) -> anyhow::Result { - use const_oid::db::rfc5912::SECP_256_R_1 as P256; + use cryptography::const_oid::db::rfc5912::SECP_256_R_1 as P256; // Generate the private key. let key = PrivateKeyInfo::generate(P256)?; @@ -175,7 +174,7 @@ impl State { // Create the certificate body. let tbs = TbsCertificate { - version: x509::Version::V3, + version: cryptography::x509::Version::V3, serial_number: UIntRef::new(&[0u8])?, signature: pki.signs_with()?, issuer: rdns.clone(), @@ -185,12 +184,12 @@ impl State { issuer_unique_id: None, subject_unique_id: None, extensions: Some(vec![ - x509::ext::Extension { + cryptography::x509::ext::Extension { extn_id: ID_CE_KEY_USAGE, critical: true, extn_value: &ku, }, - x509::ext::Extension { + cryptography::x509::ext::Extension { extn_id: ID_CE_BASIC_CONSTRAINTS, critical: true, extn_value: &bc, @@ -364,7 +363,7 @@ fn attest_request( // Add Subject Alternative Name let sans: Vec = sans.to_vec().or(Err(StatusCode::INTERNAL_SERVER_ERROR))?; - extensions.push(x509::ext::Extension { + extensions.push(cryptography::x509::ext::Extension { extn_id: ID_CE_SUBJECT_ALT_NAME, critical: false, extn_value: &sans, @@ -374,7 +373,7 @@ fn attest_request( let eku = ExtendedKeyUsage(vec![ID_KP_SERVER_AUTH, ID_KP_CLIENT_AUTH]) .to_vec() .or(Err(StatusCode::INTERNAL_SERVER_ERROR))?; - extensions.push(x509::ext::Extension { + extensions.push(cryptography::x509::ext::Extension { extn_id: ID_CE_EXT_KEY_USAGE, critical: false, extn_value: &eku, @@ -390,7 +389,7 @@ fn attest_request( // Create and sign the new certificate. TbsCertificate { - version: x509::Version::V3, + version: cryptography::x509::Version::V3, serial_number, signature, issuer: issuer.tbs_certificate.subject.clone(), @@ -471,15 +470,18 @@ async fn attest( #[cfg(test)] mod tests { mod attest { - use crate::ext::{kvm::Kvm, sgx::Sgx, snp::Snp, ExtVerifier}; use crate::*; - use const_oid::db::rfc5912::{ID_EXTENSION_REQ, SECP_256_R_1, SECP_384_R_1}; - use const_oid::ObjectIdentifier; + use cryptography::const_oid::db::rfc5912::{ID_EXTENSION_REQ, SECP_256_R_1, SECP_384_R_1}; + use cryptography::const_oid::ObjectIdentifier; + use cryptography::ext::CertReqInfoExt; + use cryptography::x509::attr::Attribute; + use cryptography::x509::request::{CertReq, CertReqInfo, ExtensionReq}; + use cryptography::x509::PkiPath; + use cryptography::x509::{ext::Extension, name::RdnSequence}; use der::{AnyRef, Encode}; - use x509::attr::Attribute; - use x509::request::{CertReq, CertReqInfo, ExtensionReq}; - use x509::PkiPath; - use x509::{ext::Extension, name::RdnSequence}; + use kvm::Kvm; + use sgx_validation::Sgx; + use snp_validation::{Evidence, Snp}; use axum::response::Response; use http::header::CONTENT_TYPE; @@ -519,7 +521,7 @@ mod tests { // Create a certification request information structure. let cri = CertReqInfo { - version: x509::request::Version::V1, + version: cryptography::x509::request::Version::V1, attributes: vec![att].try_into().unwrap(), subject: RdnSequence::default(), public_key: spki, @@ -664,8 +666,8 @@ mod tests { #[tokio::test] async fn sgx_certs(#[case] header: &str, #[case] multi: bool) { for quote in [ - include_bytes!("ext/sgx/quote.unknown").as_slice(), - include_bytes!("ext/sgx/quote.icelake").as_slice(), + include_bytes!("../crates/sgx_validation/src/quote.unknown").as_slice(), + include_bytes!("../crates/sgx_validation/src/quote.icelake").as_slice(), ] { let ext = Extension { extn_id: Sgx::OID, @@ -692,8 +694,8 @@ mod tests { #[tokio::test] async fn sgx_hostname(#[case] header: &str, #[case] multi: bool) { for quote in [ - include_bytes!("ext/sgx/quote.unknown").as_slice(), - include_bytes!("ext/sgx/quote.icelake").as_slice(), + include_bytes!("../crates/sgx_validation/src/quote.unknown").as_slice(), + include_bytes!("../crates/sgx_validation/src/quote.icelake").as_slice(), ] { let ext = Extension { extn_id: Sgx::OID, @@ -720,9 +722,12 @@ mod tests { #[case(BUNDLE, true)] #[tokio::test] async fn snp_certs(#[case] header: &str, #[case] multi: bool) { - let evidence = ext::snp::Evidence { - vcek: Certificate::from_der(include_bytes!("ext/snp/milan.vcek")).unwrap(), - report: include_bytes!("ext/snp/milan.rprt"), + let evidence = Evidence { + vcek: Certificate::from_der(include_bytes!( + "../crates/snp_validation/src/milan.vcek" + )) + .unwrap(), + report: include_bytes!("../crates/snp_validation/src/milan.rprt"), } .to_vec() .unwrap(); @@ -750,9 +755,12 @@ mod tests { #[case(BUNDLE, true)] #[tokio::test] async fn snp_hostname(#[case] header: &str, #[case] multi: bool) { - let evidence = ext::snp::Evidence { - vcek: Certificate::from_der(include_bytes!("ext/snp/milan.vcek")).unwrap(), - report: include_bytes!("ext/snp/milan.rprt"), + let evidence = Evidence { + vcek: Certificate::from_der(include_bytes!( + "../crates/snp_validation/src/milan.vcek" + )) + .unwrap(), + report: include_bytes!("../crates/snp_validation/src/milan.rprt"), } .to_vec() .unwrap();