MORE TESTS! 95% pki coverage
This commit is contained in:
parent
7d5234b003
commit
b0872780dd
|
@ -2419,7 +2419,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "trifid-pki"
|
||||
version = "0.1.0"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"ed25519-dalek",
|
||||
"hex",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "trifid-pki"
|
||||
version = "0.1.0"
|
||||
version = "0.1.2"
|
||||
edition = "2021"
|
||||
description = "A rust implementation of the Nebula PKI system"
|
||||
license = "GPL-3.0-or-later"
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
# trifid-pki
|
||||
trifid-pki is a crate for interacting with the Nebula PKI system. It was created to prevent the need to make constant CLI calls for signing operations in Nebula. Is is designed to be interoperable with the original Go implementation and as such has some oddities with key management to ensure compatability.
|
||||
|
||||
This crate has not received any formal security audits, however the underlying crates used for actual cryptographic operations (ed25519-dalek and curve25519-dalek) have been audited, finding no major issues.
|
||||
|
||||
# Examples
|
||||
|
||||
See [the documentation](https://docs.rs/trifid-pki) for examples.
|
|
@ -113,6 +113,7 @@ pub enum CaPoolError {
|
|||
NoIssuer
|
||||
}
|
||||
impl Error for CaPoolError {}
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
impl Display for CaPoolError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
|
|
|
@ -83,6 +83,7 @@ pub enum CertificateError {
|
|||
/// The public key does not match the expected value
|
||||
KeyMismatch
|
||||
}
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
impl Display for CertificateError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
|
@ -108,6 +109,7 @@ fn map_cidr_pairs(pairs: &[u32]) -> Result<Vec<Ipv4Net>, Box<dyn Error>> {
|
|||
Ok(res_vec)
|
||||
}
|
||||
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
impl Display for NebulaCertificate {
|
||||
#[allow(clippy::unwrap_used)]
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
|
@ -186,12 +188,19 @@ pub fn deserialize_nebula_certificate(bytes: &[u8]) -> Result<NebulaCertificate,
|
|||
#[derive(Debug)]
|
||||
pub enum KeyError {
|
||||
/// Keys should have their associated PEM tags but this had the wrong one
|
||||
WrongPemTag
|
||||
WrongPemTag,
|
||||
/// Ed25519 private keys are 64 bytes
|
||||
Not64Bytes,
|
||||
/// X25519 private keys are 32 bytes
|
||||
Not32Bytes
|
||||
}
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
impl Display for KeyError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::WrongPemTag => write!(f, "Keys should have their associated PEM tags but this had the wrong one")
|
||||
Self::WrongPemTag => write!(f, "Keys should have their associated PEM tags but this had the wrong one"),
|
||||
Self::Not64Bytes => write!(f, "Ed25519 private keys are 64 bytes"),
|
||||
Self::Not32Bytes => write!(f, "X25519 private keys are 32 bytes")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -233,6 +242,9 @@ pub fn deserialize_x25519_private(bytes: &[u8]) -> Result<Vec<u8>, Box<dyn Error
|
|||
if pem.tag != X25519_PRIVATE_KEY_BANNER {
|
||||
return Err(KeyError::WrongPemTag.into())
|
||||
}
|
||||
if pem.contents.len() != 32 {
|
||||
return Err(KeyError::Not32Bytes.into())
|
||||
}
|
||||
Ok(pem.contents)
|
||||
}
|
||||
|
||||
|
@ -244,6 +256,9 @@ pub fn deserialize_x25519_public(bytes: &[u8]) -> Result<Vec<u8>, Box<dyn Error>
|
|||
if pem.tag != X25519_PUBLIC_KEY_BANNER {
|
||||
return Err(KeyError::WrongPemTag.into())
|
||||
}
|
||||
if pem.contents.len() != 32 {
|
||||
return Err(KeyError::Not32Bytes.into())
|
||||
}
|
||||
Ok(pem.contents)
|
||||
}
|
||||
|
||||
|
@ -271,6 +286,9 @@ pub fn deserialize_ed25519_private(bytes: &[u8]) -> Result<Vec<u8>, Box<dyn Erro
|
|||
if pem.tag != ED25519_PRIVATE_KEY_BANNER {
|
||||
return Err(KeyError::WrongPemTag.into())
|
||||
}
|
||||
if pem.contents.len() != 64 {
|
||||
return Err(KeyError::Not64Bytes.into())
|
||||
}
|
||||
Ok(pem.contents)
|
||||
}
|
||||
|
||||
|
@ -282,6 +300,9 @@ pub fn deserialize_ed25519_public(bytes: &[u8]) -> Result<Vec<u8>, Box<dyn Error
|
|||
if pem.tag != ED25519_PUBLIC_KEY_BANNER {
|
||||
return Err(KeyError::WrongPemTag.into())
|
||||
}
|
||||
if pem.contents.len() != 64 {
|
||||
return Err(KeyError::Not64Bytes.into())
|
||||
}
|
||||
Ok(pem.contents)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//! trifid-pki is a crate for interacting with the Nebula PKI system. It was created to prevent the need to make constant CLI calls for signing operations in Nebula.
|
||||
//! It is designed to be interoperable with the original Go implementation and as such has some oddities with key management to ensure compatability.
|
||||
//!
|
||||
//! This crate has not received any format security audits, however the underlying crates used for actual cryptographic operations (ed25519-dalek and curve25519-dalek) have been audited with no major issues.
|
||||
//! This crate has not received any formal security audits, however the underlying crates used for actual cryptographic operations (ed25519-dalek and curve25519-dalek) have been audited with no major issues.
|
||||
|
||||
#![warn(clippy::pedantic)]
|
||||
#![warn(clippy::nursery)]
|
||||
|
|
|
@ -295,7 +295,7 @@ fn x25519_serialization() {
|
|||
|
||||
#[test]
|
||||
fn ed25519_serialization() {
|
||||
let bytes = [0u8; 32];
|
||||
let bytes = [0u8; 64];
|
||||
assert_eq!(deserialize_ed25519_private(&serialize_ed25519_private(&bytes)).unwrap(), bytes);
|
||||
assert!(deserialize_ed25519_private(&[0u8; 32]).is_err());
|
||||
assert_eq!(deserialize_ed25519_public(&serialize_ed25519_public(&bytes)).unwrap(), bytes);
|
||||
|
@ -549,7 +549,7 @@ fn test_ca_cert(before: SystemTime, after: SystemTime, ips: Vec<Ipv4Net>, subnet
|
|||
not_after: after,
|
||||
public_key: pub_key.to_bytes(),
|
||||
is_ca: true,
|
||||
issuer: "".to_string(),
|
||||
issuer: String::new(),
|
||||
},
|
||||
signature: vec![],
|
||||
};
|
||||
|
@ -557,6 +557,154 @@ fn test_ca_cert(before: SystemTime, after: SystemTime, ips: Vec<Ipv4Net>, subnet
|
|||
(cert, key, pub_key)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_ed25519_private() {
|
||||
let priv_key = b"-----BEGIN NEBULA ED25519 PRIVATE KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
|
||||
-----END NEBULA ED25519 PRIVATE KEY-----";
|
||||
let short_key = b"-----BEGIN NEBULA ED25519 PRIVATE KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
-----END NEBULA ED25519 PRIVATE KEY-----";
|
||||
let invalid_banner = b"-----BEGIN NOT A NEBULA PRIVATE KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
|
||||
-----END NOT A NEBULA PRIVATE KEY-----";
|
||||
let invalid_pem = b"-BEGIN NEBULA ED25519 PRIVATE KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
|
||||
-END NEBULA ED25519 PRIVATE KEY-----";
|
||||
|
||||
deserialize_ed25519_private(priv_key).unwrap();
|
||||
|
||||
deserialize_ed25519_private(short_key).unwrap_err();
|
||||
|
||||
deserialize_ed25519_private(invalid_banner).unwrap_err();
|
||||
|
||||
deserialize_ed25519_private(invalid_pem).unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_x25519_private() {
|
||||
let priv_key = b"-----BEGIN NEBULA X25519 PRIVATE KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||
-----END NEBULA X25519 PRIVATE KEY-----";
|
||||
let short_key = b"-----BEGIN NEBULA X25519 PRIVATE KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
|
||||
-----END NEBULA X25519 PRIVATE KEY-----";
|
||||
let invalid_banner = b"-----BEGIN NOT A NEBULA PRIVATE KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||
-----END NOT A NEBULA PRIVATE KEY-----";
|
||||
let invalid_pem = b"-BEGIN NEBULA X25519 PRIVATE KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||
-END NEBULA X25519 PRIVATE KEY-----";
|
||||
|
||||
deserialize_x25519_private(priv_key).unwrap();
|
||||
|
||||
deserialize_x25519_private(short_key).unwrap_err();
|
||||
|
||||
deserialize_x25519_private(invalid_banner).unwrap_err();
|
||||
|
||||
deserialize_x25519_private(invalid_pem).unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pem_deserialization() {
|
||||
let good_cert = b"# A good cert
|
||||
-----BEGIN NEBULA CERTIFICATE-----
|
||||
CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL
|
||||
vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv
|
||||
bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB
|
||||
-----END NEBULA CERTIFICATE-----";
|
||||
let bad_banner = b"-----BEGIN NOT A NEBULA CERTIFICATE-----
|
||||
CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL
|
||||
vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv
|
||||
bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB
|
||||
-----END NOT A NEBULA CERTIFICATE-----";
|
||||
let invalid_pem = b"# Not a valid PEM format
|
||||
-BEGIN NEBULA CERTIFICATE-----
|
||||
CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL
|
||||
vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv
|
||||
bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB
|
||||
-END NEBULA CERTIFICATE----";
|
||||
|
||||
// success
|
||||
deserialize_nebula_certificate_from_pem(good_cert).unwrap();
|
||||
|
||||
// fail because invalid banner
|
||||
deserialize_nebula_certificate_from_pem(bad_banner).unwrap_err();
|
||||
|
||||
// fail because nonsense pem
|
||||
deserialize_nebula_certificate_from_pem(invalid_pem).unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_ed25519_public() {
|
||||
let priv_key = b"-----BEGIN NEBULA ED25519 PUBLIC KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
|
||||
-----END NEBULA ED25519 PUBLIC KEY-----";
|
||||
let short_key = b"-----BEGIN NEBULA ED25519 PUBLIC KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
-----END NEBULA ED25519 PUBLIC KEY-----";
|
||||
let invalid_banner = b"-----BEGIN NOT A NEBULA PUBLIC KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
|
||||
-----END NOT A NEBULA PUBLIC KEY-----";
|
||||
let invalid_pem = b"-BEGIN NEBULA ED25519 PUBLIC KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
|
||||
-END NEBULA ED25519 PUBLIC KEY-----";
|
||||
|
||||
deserialize_ed25519_public(priv_key).unwrap();
|
||||
|
||||
deserialize_ed25519_public(short_key).unwrap_err();
|
||||
|
||||
deserialize_ed25519_public(invalid_banner).unwrap_err();
|
||||
|
||||
deserialize_ed25519_public(invalid_pem).unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Ensure that trifid-pki produces the *exact same* bit-for-bit representation as nebula does
|
||||
// to ensure signature interoperability
|
||||
// We use an e3team production certificate for this as it is a known-good certificate.
|
||||
fn test_serialization_interoperability() {
|
||||
let known_good_cert = hex::decode("0a650a08636f72652d74777212098184c4508080f8ff0f28ae9fbf9c06309485c4ab063a20304e6279d8722f0fd8d966faa70adaeec08c4649d486457bb038be243753a7474a2056860ded3d14b7f3b77ca2a062ee5d683dd06b35f87446d8d6a7e923b6a7783d1240eb5d6b688eda0d36e925219c098ff2799e42207a093f7d9b7d875823ca05b2e0d3a749dd2fc9cec811ed9a2865d71c4d53cfdfd1bf7e6d5058bd9ecd388ddf0d").unwrap();
|
||||
|
||||
let cert = deserialize_nebula_certificate(&known_good_cert).unwrap();
|
||||
let reserialized_cert_pem = cert.serialize().unwrap();
|
||||
assert_eq!(known_good_cert, reserialized_cert_pem);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_x25519_public() {
|
||||
let priv_key = b"-----BEGIN NEBULA X25519 PUBLIC KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||
-----END NEBULA X25519 PUBLIC KEY-----";
|
||||
let short_key = b"-----BEGIN NEBULA X25519 PUBLIC KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
|
||||
-----END NEBULA X25519 PUBLIC KEY-----";
|
||||
let invalid_banner = b"-----BEGIN NOT A NEBULA PUBLIC KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||
-----END NOT A NEBULA PUBLIC KEY-----";
|
||||
let invalid_pem = b"-BEGIN NEBULA X25519 PUBLIC KEY-----
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||
-END NEBULA X25519 PUBLIC KEY-----";
|
||||
|
||||
deserialize_x25519_public(priv_key).unwrap();
|
||||
|
||||
deserialize_x25519_public(short_key).unwrap_err();
|
||||
|
||||
deserialize_x25519_public(invalid_banner).unwrap_err();
|
||||
|
||||
deserialize_x25519_public(invalid_pem).unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ca_pool_add_non_ca() {
|
||||
let mut ca_pool = NebulaCAPool::new();
|
||||
|
||||
let (ca, ca_key, _) = test_ca_cert(SystemTime::now(), SystemTime::now() + Duration::from_secs(3600), vec![], vec![], vec![]);
|
||||
let (cert, _, _) = test_cert(&ca, &ca_key, SystemTime::now(), SystemTime::now(), vec![], vec![], vec![]);
|
||||
|
||||
ca_pool.add_ca_certificate(&cert.serialize_to_pem().unwrap()).unwrap_err();
|
||||
}
|
||||
|
||||
fn test_cert(ca: &NebulaCertificate, key: &SigningKey, before: SystemTime, after: SystemTime, ips: Vec<Ipv4Net>, subnets: Vec<Ipv4Net>, groups: Vec<String>) -> (NebulaCertificate, SigningKey, VerifyingKey) {
|
||||
let issuer = ca.sha256sum().unwrap();
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue