From 33ba67407377e7077b17a556c2642a5ca5f47161 Mon Sep 17 00:00:00 2001 From: c0repwn3r Date: Mon, 27 Feb 2023 10:55:53 -0500 Subject: [PATCH] cert signing tests --- Cargo.lock | 3 +++ trifid-pki/Cargo.toml | 6 ++++-- trifid-pki/src/ca.rs | 25 +++++++++++++++++++++++-- trifid-pki/src/cert.rs | 16 ++++++---------- trifid-pki/src/test.rs | 39 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 75 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d95187..4723dc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -555,6 +555,7 @@ checksum = "7bd577ba9d4bcab443cac60003d8fd32c638e7024a3ec92c200d7af5d2c397ed" dependencies = [ "curve25519-dalek 4.0.0-rc.1", "ed25519", + "rand_core 0.6.4", "serde", "sha2", "zeroize", @@ -2425,6 +2426,8 @@ dependencies = [ "ipnet", "pem", "quick-protobuf", + "rand", + "rand_core 0.6.4", "sha2", "x25519-dalek", ] diff --git a/trifid-pki/Cargo.toml b/trifid-pki/Cargo.toml index ed990d7..2976001 100644 --- a/trifid-pki/Cargo.toml +++ b/trifid-pki/Cargo.toml @@ -9,8 +9,10 @@ description = "A rust implementation of the Nebula PKI system" [dependencies] pem = "1.1.1" x25519-dalek = "2.0.0-pre.1" -ed25519-dalek = "2.0.0-pre.0" +ed25519-dalek = { version = "2.0.0-pre.0", features = ["rand_core", "alloc"] } ipnet = "2.7.1" quick-protobuf = "0.8.1" hex = "0.4.3" -sha2 = "0.10.6" \ No newline at end of file +sha2 = "0.10.6" +rand_core = "0.6.4" +rand = "0.8.5" \ No newline at end of file diff --git a/trifid-pki/src/ca.rs b/trifid-pki/src/ca.rs index a977c34..236a237 100644 --- a/trifid-pki/src/ca.rs +++ b/trifid-pki/src/ca.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use std::error::Error; use std::fmt::{Display, Formatter}; +use std::time::SystemTime; use ed25519_dalek::VerifyingKey; use crate::cert::{deserialize_nebula_certificate_from_pem, NebulaCertificate}; @@ -55,10 +56,25 @@ impl NebulaCAPool { } if !cert.check_signature(&VerifyingKey::from_bytes(&cert.details.public_key)?)? { - + return Err(CaPoolError::NotSelfSigned.into()) } - Ok(false) + let fingerprint = cert.sha256sum()?; + let expired = cert.expired(SystemTime::now()); + + self.cas.insert(fingerprint, cert); + + Ok(expired) + } + + /// Blocklist the given certificate in the CA pool + pub fn blocklist_fingerprint(&mut self, fingerprint: &str) { + self.cert_blocklist.push(fingerprint.to_string()); + } + + /// Clears the list of blocklisted fingerprints + pub fn reset_blocklist(&mut self) { + self.cert_blocklist = vec![]; } /// Checks if the given certificate is blocklisted @@ -77,6 +93,11 @@ impl NebulaCAPool { Ok(self.cas.get(&cert.details.issuer)) } + + /// Get a list of trusted CA fingerprints + pub fn get_fingerprints(&self) -> Vec<&String> { + self.cas.keys().collect() + } } #[derive(Debug)] diff --git a/trifid-pki/src/cert.rs b/trifid-pki/src/cert.rs index 4be50b8..6c7dbd8 100644 --- a/trifid-pki/src/cert.rs +++ b/trifid-pki/src/cert.rs @@ -7,7 +7,6 @@ use std::net::Ipv4Addr; use std::ops::Add; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey}; -use ed25519_dalek::ed25519::pkcs8::spki::der::Encode; use ipnet::{Ipv4Net}; use pem::Pem; use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer}; @@ -294,14 +293,9 @@ impl NebulaCertificate { pub fn sign(&mut self, key: &SigningKey) -> Result<(), Box> { let mut out = Vec::new(); let mut writer = Writer::new(&mut out); - writer.write_message(&self.get_raw_details())?; + self.get_raw_details().write_message(&mut writer)?; - let sig = key.sign(&out).to_bytes(); - - self.signature = match sig.to_vec() { - Ok(v) => v, - Err(_) => return Err("signature error".into()) - }; + self.signature = key.sign(&out).to_vec(); Ok(()) } @@ -311,9 +305,11 @@ impl NebulaCertificate { pub fn check_signature(&self, key: &VerifyingKey) -> Result> { let mut out = Vec::new(); let mut writer = Writer::new(&mut out); - writer.write_message(&self.get_raw_details())?; + self.get_raw_details().write_message(&mut writer)?; - Ok(key.verify(&out, &Signature::try_from(&*self.signature)?).is_ok()) + let sig = Signature::from_slice(&self.signature)?; + + Ok(key.verify(&out, &sig).is_ok()) } /// Returns true if the signature is too young or too old compared to the provided time diff --git a/trifid-pki/src/test.rs b/trifid-pki/src/test.rs index 35b662e..17b1283 100644 --- a/trifid-pki/src/test.rs +++ b/trifid-pki/src/test.rs @@ -8,6 +8,8 @@ use std::time::{Duration, SystemTime, SystemTimeError, UNIX_EPOCH}; use ipnet::Ipv4Net; use crate::cert::{deserialize_nebula_certificate, NebulaCertificate, NebulaCertificateDetails}; use std::str::FromStr; +use ed25519_dalek::{SigningKey}; +use rand::rngs::OsRng; /// This is a cert that we (e3team) actually use in production, and it's a known-good certificate. pub const KNOWN_GOOD_CERT: &[u8; 258] = b"-----BEGIN NEBULA CERTIFICATE-----\nCkkKF2UzdGVhbSBJbnRlcm5hbCBOZXR3b3JrKJWev5wGMJWFxKsGOiCvpwoHyKY5\n8Q5+2XxDjtoCf/zlNY/EUdB8bwXQSwEo50ABEkB0Dx76lkMqc3IyH5+ml2dKjTyv\nB4Jiw6x3abf5YZcf8rDuVEgQpvFdJmo3xJyIb3C9vKZ6kXsUxjw6s1JdWgkA\n-----END NEBULA CERTIFICATE-----"; @@ -68,6 +70,43 @@ fn certificate_serialization() { } } +#[test] +fn cert_signing() { + let before = round_systime_to_secs(SystemTime::now() - Duration::from_secs(60)).unwrap(); + let after = round_systime_to_secs(SystemTime::now() + Duration::from_secs(60)).unwrap(); + let pub_key = b"1234567890abcedfghij1234567890ab"; + + let mut cert = NebulaCertificate { + details: NebulaCertificateDetails { + name: "testing".to_string(), + ips: vec![ + netmask!("10.1.1.1", "255.255.255.0"), + netmask!("10.1.1.2", "255.255.0.0"), + netmask!("10.1.1.3", "255.0.0.0") + ], + subnets: vec![ + netmask!("9.1.1.1", "255.255.255.128"), + netmask!("9.1.1.2", "255.255.255.0"), + netmask!("9.1.1.3", "255.255.0.0") + ], + groups: vec!["test-group1".to_string(), "test-group2".to_string(), "test-group3".to_string()], + not_before: before, + not_after: after, + public_key: *pub_key, + is_ca: false, + issuer: "1234567890abcedfabcd1234567890ab".to_string(), + }, + signature: b"1234567890abcedfghij1234567890ab".to_vec(), + }; + + let mut csprng = OsRng; + let key = SigningKey::generate(&mut csprng); + + assert!(cert.check_signature(&key.verifying_key()).is_err()); + cert.sign(&key).unwrap(); + assert!(cert.check_signature(&key.verifying_key()).unwrap()); +} + #[macro_export] macro_rules! netmask { ($ip:expr,$mask:expr) => {