diff --git a/Cargo.lock b/Cargo.lock index 5959a12..a083c55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,16 +23,6 @@ dependencies = [ "mach", ] -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - [[package]] name = "aes" version = "0.8.3" @@ -103,7 +93,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -113,7 +103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -227,7 +217,7 @@ dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", - "windows-targets 0.48.0", + "windows-targets", ] [[package]] @@ -427,24 +417,6 @@ dependencies = [ "syn 1.0.107", ] -[[package]] -name = "dice-cert-check" -version = "0.1.0" -dependencies = [ - "anyhow", - "clap", - "const-oid", - "env_logger", - "hex", - "log", - "p384", - "pem-rfc7468", - "ring-compat", - "sha2", - "thiserror", - "x509-cert", -] - [[package]] name = "dice-cert-tmpl" version = "0.1.0" @@ -570,11 +542,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" dependencies = [ - "humantime", - "is-terminal", "log", - "regex", - "termcolor", ] [[package]] @@ -585,7 +553,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -719,12 +687,6 @@ dependencies = [ "syn 1.0.107", ] -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "iana-time-zone" version = "0.1.57" @@ -775,19 +737,7 @@ checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "is-terminal" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" -dependencies = [ - "hermit-abi", - "io-lifetimes", - "rustix 0.36.17", - "windows-sys 0.45.0", + "windows-sys", ] [[package]] @@ -852,12 +802,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "linux-raw-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" - [[package]] name = "linux-raw-sys" version = "0.3.8" @@ -1091,39 +1035,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ring" -version = "0.17.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" -dependencies = [ - "cc", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys 0.48.0", -] - -[[package]] -name = "ring-compat" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccce7bae150b815f0811db41b8312fcb74bffa4cab9cee5429ee00f356dd5bd4" -dependencies = [ - "aead", - "digest", - "ecdsa", - "ed25519", - "generic-array", - "p256", - "p384", - "pkcs8", - "rand_core", - "ring", - "signature", -] - [[package]] name = "ron" version = "0.8.0" @@ -1143,7 +1054,7 @@ checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" dependencies = [ "libc", "rtoolbox", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1175,20 +1086,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustix" -version = "0.36.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.1.4", - "windows-sys 0.45.0", -] - [[package]] name = "rustix" version = "0.37.23" @@ -1199,8 +1096,8 @@ dependencies = [ "errno", "io-lifetimes", "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", + "linux-raw-sys", + "windows-sys", ] [[package]] @@ -1338,12 +1235,6 @@ dependencies = [ "syn 2.0.27", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - [[package]] name = "spki" version = "0.7.2" @@ -1404,17 +1295,8 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall", - "rustix 0.37.23", - "windows-sys 0.48.0", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", + "rustix", + "windows-sys", ] [[package]] @@ -1475,12 +1357,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - [[package]] name = "utf8parse" version = "0.2.1" @@ -1601,15 +1477,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -1622,16 +1489,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.1", + "windows-targets", ] [[package]] @@ -1640,22 +1498,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.1", - "windows_aarch64_msvc 0.42.1", - "windows_i686_gnu 0.42.1", - "windows_i686_msvc 0.42.1", - "windows_x86_64_gnu 0.42.1", - "windows_x86_64_gnullvm 0.42.1", - "windows_x86_64_msvc 0.42.1", + "windows-targets", ] [[package]] @@ -1664,93 +1507,51 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" - [[package]] name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" -[[package]] -name = "windows_i686_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" - [[package]] name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" -[[package]] -name = "windows_i686_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" - [[package]] name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" - [[package]] name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" - [[package]] name = "windows_x86_64_msvc" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 26c0c83..465629d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,6 @@ [workspace] members = [ - "dice-cert-check", "dice-cert-tmpl", "dice-mfg", "dice-mfg-msgs", @@ -26,7 +25,6 @@ log = { version = "0.4", features = ["std"] } p384 = { version = "0.13", default-features = false } pem = { version = "3", default-features = false } pem-rfc7468 = { version = "0.7.0", default-features = false } -ring-compat = { version = "0.8", default-features = false } ron = "0.8" rpassword = "7.3.1" salty = { version = "0.3", default-features = false } diff --git a/dice-cert-check/Cargo.toml b/dice-cert-check/Cargo.toml deleted file mode 100644 index 83c4936..0000000 --- a/dice-cert-check/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "dice-cert-check" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow = { workspace = true, features = ["std"] } -clap.workspace = true -const-oid = { version = "0.9.5", features = ["db"] } -env_logger = { workspace = true, default-features = true } -hex = { workspace = true, default-features = true } -log = { workspace = true, default-features = true, features = ["std"] } -p384 = { workspace = true, default-features = true } -pem-rfc7468 = { workspace = true, default-features = true } -ring-compat = { workspace = true, default-features = true, features = ["std"] } -sha2 = { workspace = true, default-features = true } -thiserror = { workspace = true, default-features = true } -x509-cert = { workspace = true, default-features = true, features = ["pem"] } diff --git a/dice-cert-check/README.md b/dice-cert-check/README.md deleted file mode 100644 index b76d964..0000000 --- a/dice-cert-check/README.md +++ /dev/null @@ -1,7 +0,0 @@ -This is a crate hosting a prototype validation mechanism for the certificate -hierarchies created by Hubris on boot for DICE keys. We're doing this -validation manually / with new code instead of an existing implementation -like webpki because DICE certs contain at least one component (policy OID or v3 -extension) that, if marked as 'critical', cause webpki to balk as it should. -Similarly webpki requires fields like 'subjectAltName' that we don't need -(yet?) and havne't included for size reasons. diff --git a/dice-cert-check/src/lib.rs b/dice-cert-check/src/lib.rs deleted file mode 100644 index e81ad46..0000000 --- a/dice-cert-check/src/lib.rs +++ /dev/null @@ -1,356 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -use const_oid::{ - db::rfc5912::{ECDSA_WITH_SHA_384, ID_EC_PUBLIC_KEY, SECP_384_R_1}, - ObjectIdentifier, -}; -use hex::ToHex; -use log::{error, warn}; -use sha2::Digest; -use std::fmt; -use std::result; -use x509_cert::{ - der::{ - self, - asn1::{Any, BitString}, - Tag, Tagged, - }, - spki::{AlgorithmIdentifierOwned, SubjectPublicKeyInfoOwned}, -}; - -const ID_ED_25519: crate::ObjectIdentifier = - crate::ObjectIdentifier::new_unwrap("1.3.101.112"); - -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error("Signature is not octet aligned")] - BadSignature, - #[error("SPKI has parameters incompatible with Verifier.")] - IncompatibleParams, - #[error("Verifier is not compatible with provided signature")] - IncompatibleSignature, - #[error("Required parameters missing from SPKI.")] - MissingParams, - #[error("Failed to verify signature.")] - P384VerificationFail { - #[from] - source: p384::ecdsa::Error, - }, - #[error("Public key is not octet aligned")] - UnalignedPublicKey, - #[error("SPKI algorithm has parameters where none were expected")] - UnexpectedParams, - #[error("Algorithm not supported")] - UnsupportedAlgorithm, - #[error("Parameter not supported")] - UnsupportedParameter, - #[error("Signature not supported")] - UnsupportedSignature, - #[error("Parameters has unspported tag.")] - UnsupportedTag, - #[error("Unsupported OID in algorith parameter.")] - UnsupportedOid { - #[from] - source: der::Error, - }, - #[error("Wrong key type for verifier")] - WrongAlgorithm, -} - -type Result = result::Result; - -#[derive(Debug, Eq, PartialEq)] -pub enum AlgorithmType { - EcPublicKey, - Ed25519, -} - -impl TryFrom<&ObjectIdentifier> for AlgorithmType { - type Error = Error; - - fn try_from(oid: &ObjectIdentifier) -> result::Result { - match *oid { - ID_EC_PUBLIC_KEY => Ok(AlgorithmType::EcPublicKey), - ID_ED_25519 => Ok(AlgorithmType::Ed25519), - _ => Err(Error::UnsupportedAlgorithm), - } - } -} - -#[derive(Debug, Eq, PartialEq)] -pub enum ParameterType { - P384, -} - -impl TryFrom<&Any> for ParameterType { - type Error = Error; - - fn try_from(param: &Any) -> result::Result { - match param.tag() { - Tag::ObjectIdentifier => { - let oid = param.decode_as()?; - match oid { - SECP_384_R_1 => Ok(ParameterType::P384), - _ => Err(Error::UnsupportedParameter), - } - } - _ => Err(Error::UnsupportedTag), - } - } -} - -#[derive(Debug, Eq, PartialEq)] -pub enum SignatureType { - EcdsaWithSha384, - Ed25519, -} - -impl TryFrom<&ObjectIdentifier> for SignatureType { - type Error = Error; - - fn try_from(oid: &ObjectIdentifier) -> result::Result { - match *oid { - ECDSA_WITH_SHA_384 => Ok(SignatureType::EcdsaWithSha384), - ID_ED_25519 => Ok(SignatureType::Ed25519), - _ => { - warn!("Unsupported signature w/ oid: {}", oid); - Err(Error::UnsupportedSignature) - } - } - } -} - -pub struct Signature { - pub bytes: Vec, - pub kind: SignatureType, - params: Option, -} - -impl Signature { - pub fn new( - algorithm: &AlgorithmIdentifierOwned, - signature: &BitString, - ) -> Result { - let params = match &algorithm.parameters { - Some(params) => Some(ParameterType::try_from(params)?), - None => None, - }; - - let bytes = match signature.as_bytes() { - // copy DER encoded signature - Some(bytes) => bytes.to_vec(), - // we get None back if the ANS.1 BIT STRING has unused bits - None => Err(Error::BadSignature)?, - }; - - Ok(Self { - bytes, - kind: SignatureType::try_from(&algorithm.oid)?, - params, - }) - } -} - -impl fmt::Display for Signature { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "kind: {:?}, params: {:?}, bytes: {}", - self.kind, - self.params, - self.bytes.encode_hex::(), - ) - } -} - -pub trait Verifier { - fn verify(&self, msg: &[u8], sig: &Signature) -> Result<()>; -} - -pub struct P384Verifier { - verifying_key: p384::ecdsa::VerifyingKey, -} - -impl TryFrom<&SubjectPublicKeyInfoOwned> for P384Verifier { - type Error = Error; - - fn try_from( - spki: &SubjectPublicKeyInfoOwned, - ) -> result::Result { - let params = match &spki.algorithm.parameters { - Some(params) => ParameterType::try_from(params)?, - None => return Err(Error::MissingParams), - }; - - if params != ParameterType::P384 { - warn!("P384Verifier: incompatible algorithm parameters"); - return Err(Error::IncompatibleParams); - } - - use p384::ecdsa::VerifyingKey; - use x509_cert::der::referenced::OwnedToRef; - - // do better error handling - let verifying_key = VerifyingKey::try_from(spki.owned_to_ref()) - .expect("p384 VerifyingKey"); - Ok(Self { verifying_key }) - } -} - -impl Verifier for P384Verifier { - fn verify(&self, msg: &[u8], sig: &Signature) -> Result<()> { - if sig.kind != SignatureType::EcdsaWithSha384 { - warn!( - "P384Verifier: incompatible signature algorithm: {:?}", - sig.kind - ); - return Err(Error::IncompatibleSignature); - } - - let digest = sha2::Sha384::digest(msg); - - use p384::ecdsa::{self, signature::hazmat::PrehashVerifier}; - - let signature = ecdsa::Signature::from_der(&sig.bytes)?; - - Ok(self.verifying_key.verify_prehash(&digest, &signature)?) - } -} - -pub struct Ed25519Verifier { - verifying_key: ring_compat::signature::ed25519::VerifyingKey, -} - -impl TryFrom<&SubjectPublicKeyInfoOwned> for Ed25519Verifier { - type Error = Error; - - fn try_from(spki: &SubjectPublicKeyInfoOwned) -> Result { - let algorithm = AlgorithmType::try_from(&spki.algorithm.oid)?; - if algorithm != AlgorithmType::Ed25519 { - return Err(Error::WrongAlgorithm); - } - - if spki.algorithm.parameters.is_some() { - return Err(Error::UnexpectedParams); - } - - use ring_compat::signature::ed25519::VerifyingKey; - - // The ring type behind the VerifyingKey expects the public key - // as the raw bits, not the DER encoded SPKI like the rust crypto - // ecc VerifyingKey. This requires dealing with the ASN.1 BIT - // STRING type and the fact that it may not be byte aligned. - let key_bytes = match spki.subject_public_key.as_bytes() { - Some(b) => b, - None => return Err(Error::UnalignedPublicKey), - }; - - let verifying_key = VerifyingKey::from_slice(key_bytes)?; - Ok(Self { verifying_key }) - } -} - -impl Verifier for Ed25519Verifier { - fn verify(&self, msg: &[u8], sig: &Signature) -> Result<()> { - if sig.kind != SignatureType::Ed25519 { - warn!("Ed25519Verifier: incompatible signature"); - return Err(Error::IncompatibleSignature); - } - - use ring_compat::signature::ed25519::Signature; - use ring_compat::signature::Verifier; - - let signature = Signature::from_slice(&sig.bytes)?; - - match self.verifying_key.verify(msg, &signature) { - Ok(_) => Ok(()), - Err(e) => { - // not sure failed signature checks are worth - // spamming the logs - warn!("Signature verification failed: {}", e); - Err(e.into()) - } - } - } -} - -pub struct VerifierFactory; - -impl VerifierFactory { - pub fn get_verifier( - spki: &SubjectPublicKeyInfoOwned, - ) -> Result> { - match AlgorithmType::try_from(&spki.algorithm.oid)? { - AlgorithmType::EcPublicKey => match &spki.algorithm.parameters { - Some(params) => match ParameterType::try_from(params)? { - ParameterType::P384 => { - Ok(Box::new(P384Verifier::try_from(spki)?)) - } - }, - None => Err(Error::MissingParams), - }, - AlgorithmType::Ed25519 => { - Ok(Box::new(Ed25519Verifier::try_from(spki)?)) - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use x509_cert::der::asn1::Any; - - #[test] - fn test_alg_type_ecpublickey() -> Result<()> { - let alg_oid = ID_EC_PUBLIC_KEY; - - let alg = AlgorithmType::try_from(&alg_oid)?; - assert_eq!(alg, AlgorithmType::EcPublicKey); - - Ok(()) - } - - #[test] - fn test_alg_type_ed25519() -> Result<()> { - let alg_oid = ID_ED_25519; - - let alg = AlgorithmType::try_from(&alg_oid)?; - assert_eq!(alg, AlgorithmType::Ed25519); - - Ok(()) - } - - #[test] - fn test_param_type() -> Result<()> { - let param_oid = SECP_384_R_1; - let param = Any::from(¶m_oid); - - let param = ParameterType::try_from(¶m)?; - assert_eq!(param, ParameterType::P384); - - Ok(()) - } - - #[test] - fn test_sig_type_ecdsa384() -> Result<()> { - let sig_oid = ECDSA_WITH_SHA_384; - let sig = SignatureType::try_from(&sig_oid)?; - - assert_eq!(sig, SignatureType::EcdsaWithSha384); - - Ok(()) - } - - #[test] - fn test_sig_type_ed25519() -> Result<()> { - let sig_oid = ID_ED_25519; - let sig = SignatureType::try_from(&sig_oid)?; - - assert_eq!(sig, SignatureType::Ed25519); - - Ok(()) - } -} diff --git a/dice-cert-check/src/main.rs b/dice-cert-check/src/main.rs deleted file mode 100644 index 5ad7a75..0000000 --- a/dice-cert-check/src/main.rs +++ /dev/null @@ -1,216 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -use anyhow::Result; -use clap::{Parser, ValueEnum}; -use env_logger::Builder; -use hex::ToHex; -use log::{debug, error, info, LevelFilter}; -use pem_rfc7468::{LineEnding, PemLabel}; -use std::{fs, path::PathBuf, process}; -use x509_cert::{ - der::{Decode, DecodePem, Encode, EncodePem}, - Certificate, -}; - -use dice_cert_check::{Signature, VerifierFactory}; - -/// Transform an x509 cert between DER and PEM encoding. -#[derive(Parser, Debug)] -#[clap(author, version, about, long_about = None)] -struct Args { - /// Noisy output. - #[clap(long)] - verbose: bool, - - #[clap(subcommand)] - command: Command, -} - -#[derive(Debug, Parser)] -#[clap(name = "command")] -enum Command { - /// Convert the provided cert to the requested format. - Convert { - /// Input file holding certificate. - #[clap(long = "in")] - infile: PathBuf, - - /// Output file for certificate. - #[clap(long = "out")] - outfile: PathBuf, - - /// Write certificate out in this format. - #[clap(long)] - encoding: Encoding, - }, - /// Verify signatures in the provided cert chain back to the provided - /// root CA. - Verify { - /// Input file holding certificate chain. - #[clap(long = "in")] - infile: PathBuf, - - /// Input file holding certificate chain. - #[clap(long = "root")] - cafile: PathBuf, - }, -} - -#[allow(clippy::upper_case_acronyms)] -#[derive(Clone, Debug, ValueEnum)] -enum Encoding { - DER, - PEM, -} - -fn main() -> Result<()> { - let args = Args::parse(); - - let mut builder = Builder::from_default_env(); - - let level = if args.verbose { - LevelFilter::Debug - } else { - LevelFilter::Error - }; - builder.filter(None, level).init(); - - match args.command { - Command::Convert { - infile, - outfile, - encoding, - } => convert(&infile, &outfile, encoding), - Command::Verify { infile, cafile } => { - let mut cert_chain = parse_pem_cert_chain(&infile)?; - let ca_cert = fs::read_to_string(cafile)?; - let ca_cert = Certificate::from_pem(ca_cert)?; - cert_chain.push(ca_cert); - - let code = match verify(&cert_chain) { - Ok(_) => 0, - Err(e) => { - error!("Error: {}", e); - 1 - } - }; - process::exit(code) - } - } -} - -fn convert( - infile: &PathBuf, - outfile: &PathBuf, - encoding: Encoding, -) -> Result<()> { - let cert = fs::read(infile)?; - - let cert = match Certificate::from_pem(&cert) { - Ok(c) => c, - Err(_) => { - info!("failed to parse input as PEM, trying DER ..."); - Certificate::from_der(&cert)? - } - }; - - // this is a bit weird, but there's a reason ... - let cert_vec = match encoding { - Encoding::DER => cert.to_der()?, - // If we get the PEM encoded cert by just calling 'to_vec' it will - // be preceded by 5 bytes of ... something not PEM. We work around - // this by calling 'as_bytes' first. - Encoding::PEM => { - cert.to_pem(LineEnding::default())?.as_bytes().to_vec() - } - }; - - fs::write(outfile, cert_vec)?; - - Ok(()) -} - -// look into rfc 6066 PkiPath encoding? -// This is gross but ... it works -fn parse_pem_cert_chain(infile: &PathBuf) -> Result> { - let mut tmp = String::new(); - let boundary: String = - String::from("-----END ") + Certificate::PEM_LABEL + "-----"; - let mut chain = Vec::::new(); - - for line in fs::read_to_string(infile)?.lines() { - tmp.push_str(line); - tmp.push('\n'); - if line.contains(&boundary) { - // tmp string now holds one PEM encoded Certificate - chain.push(Certificate::from_pem(&tmp)?); - tmp.clear(); - } - } - - Ok(chain) -} - -fn verify(cert_chain: &[Certificate]) -> Result<()> { - // It's possible we may be handed a self signed cert and asked to verify - // it. For now this is an edge case. - if cert_chain.len() < 2 { - todo!("not enough certs"); - } - - let signature = Signature::new( - &cert_chain[0].signature_algorithm, - &cert_chain[0].signature, - )?; - debug!("Initial signature: {}", signature); - - let message = cert_chain[0].tbs_certificate.to_der()?; - debug!("Initial message: {}", message.encode_hex::()); - - _verify(&cert_chain[1..], &message, &signature) -} - -/// This function should only be called from the 'verify' function. Where -/// 'verify' handles the initial condition for recusrion, this function is -/// the primary recursion. -fn _verify( - cert_chain: &[Certificate], - message: &[u8], - signature: &Signature, -) -> Result<()> { - debug!("cert_chain.len(): {}", cert_chain.len()); - if cert_chain.is_empty() { - error!("Cert chain has no certs. This shouldn't happen."); - process::exit(1); - } - - let verifier = VerifierFactory::get_verifier( - &cert_chain[0].tbs_certificate.subject_public_key_info, - )?; - - // verify signature from previous cert with verifier from current cert - verifier.verify(message, signature)?; - - // prepare data to be verified by next recursion or terminal condition - let signature = Signature::new( - &cert_chain[0].signature_algorithm, - &cert_chain[0].signature, - )?; - let message = cert_chain[0].tbs_certificate.to_der()?; - - if cert_chain.len() > 1 { - _verify(&cert_chain[1..], &message, &signature) - } else { - // the terminal condition (no more certs in the chain) requires that - // we verify the signature on the final cert with the private key from - // the same cert. We've already prepared the signature & message from - // this cert in preparation for the next recursion. Instead of calling - // ourselves again however we do the verification and return. - info!("terminal condition"); - - // verify signature from previous cert with verifier from current cert - Ok(verifier.verify(&message, &signature)?) - } -}