cert signing tests

This commit is contained in:
c0repwn3r 2023-02-27 10:55:53 -05:00
parent 020abccf79
commit 33ba674073
Signed by: core
GPG Key ID: FDBF740DADDCEECF
5 changed files with 75 additions and 14 deletions

3
Cargo.lock generated
View File

@ -555,6 +555,7 @@ checksum = "7bd577ba9d4bcab443cac60003d8fd32c638e7024a3ec92c200d7af5d2c397ed"
dependencies = [ dependencies = [
"curve25519-dalek 4.0.0-rc.1", "curve25519-dalek 4.0.0-rc.1",
"ed25519", "ed25519",
"rand_core 0.6.4",
"serde", "serde",
"sha2", "sha2",
"zeroize", "zeroize",
@ -2425,6 +2426,8 @@ dependencies = [
"ipnet", "ipnet",
"pem", "pem",
"quick-protobuf", "quick-protobuf",
"rand",
"rand_core 0.6.4",
"sha2", "sha2",
"x25519-dalek", "x25519-dalek",
] ]

View File

@ -9,8 +9,10 @@ description = "A rust implementation of the Nebula PKI system"
[dependencies] [dependencies]
pem = "1.1.1" pem = "1.1.1"
x25519-dalek = "2.0.0-pre.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" ipnet = "2.7.1"
quick-protobuf = "0.8.1" quick-protobuf = "0.8.1"
hex = "0.4.3" hex = "0.4.3"
sha2 = "0.10.6" sha2 = "0.10.6"
rand_core = "0.6.4"
rand = "0.8.5"

View File

@ -3,6 +3,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error; use std::error::Error;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::time::SystemTime;
use ed25519_dalek::VerifyingKey; use ed25519_dalek::VerifyingKey;
use crate::cert::{deserialize_nebula_certificate_from_pem, NebulaCertificate}; 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)?)? { 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 /// Checks if the given certificate is blocklisted
@ -77,6 +93,11 @@ impl NebulaCAPool {
Ok(self.cas.get(&cert.details.issuer)) 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)] #[derive(Debug)]

View File

@ -7,7 +7,6 @@ use std::net::Ipv4Addr;
use std::ops::Add; use std::ops::Add;
use std::time::{Duration, SystemTime, UNIX_EPOCH}; use std::time::{Duration, SystemTime, UNIX_EPOCH};
use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey}; use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
use ed25519_dalek::ed25519::pkcs8::spki::der::Encode;
use ipnet::{Ipv4Net}; use ipnet::{Ipv4Net};
use pem::Pem; use pem::Pem;
use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer}; use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer};
@ -294,14 +293,9 @@ impl NebulaCertificate {
pub fn sign(&mut self, key: &SigningKey) -> Result<(), Box<dyn Error>> { pub fn sign(&mut self, key: &SigningKey) -> Result<(), Box<dyn Error>> {
let mut out = Vec::new(); let mut out = Vec::new();
let mut writer = Writer::new(&mut out); 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 = key.sign(&out).to_vec();
self.signature = match sig.to_vec() {
Ok(v) => v,
Err(_) => return Err("signature error".into())
};
Ok(()) Ok(())
} }
@ -311,9 +305,11 @@ impl NebulaCertificate {
pub fn check_signature(&self, key: &VerifyingKey) -> Result<bool, Box<dyn Error>> { pub fn check_signature(&self, key: &VerifyingKey) -> Result<bool, Box<dyn Error>> {
let mut out = Vec::new(); let mut out = Vec::new();
let mut writer = Writer::new(&mut out); 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 /// Returns true if the signature is too young or too old compared to the provided time

View File

@ -8,6 +8,8 @@ use std::time::{Duration, SystemTime, SystemTimeError, UNIX_EPOCH};
use ipnet::Ipv4Net; use ipnet::Ipv4Net;
use crate::cert::{deserialize_nebula_certificate, NebulaCertificate, NebulaCertificateDetails}; use crate::cert::{deserialize_nebula_certificate, NebulaCertificate, NebulaCertificateDetails};
use std::str::FromStr; 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. /// 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-----"; 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_export]
macro_rules! netmask { macro_rules! netmask {
($ip:expr,$mask:expr) => { ($ip:expr,$mask:expr) => {