certs be good now (maybe)
This commit is contained in:
parent
b8ca91f8e9
commit
cf9efb0ccf
|
@ -172,15 +172,6 @@ version = "1.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.3"
|
||||
|
@ -291,7 +282,7 @@ dependencies = [
|
|||
"hmac",
|
||||
"percent-encoding",
|
||||
"rand",
|
||||
"sha2 0.10.6",
|
||||
"sha2",
|
||||
"subtle",
|
||||
"time 0.3.17",
|
||||
"version_check",
|
||||
|
@ -515,7 +506,7 @@ version = "0.10.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
|
||||
dependencies = [
|
||||
"block-buffer 0.10.3",
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
@ -565,7 +556,7 @@ dependencies = [
|
|||
"curve25519-dalek 4.0.0-rc.1",
|
||||
"ed25519",
|
||||
"serde",
|
||||
"sha2 0.10.6",
|
||||
"sha2",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
|
@ -1862,19 +1853,6 @@ dependencies = [
|
|||
"digest 0.10.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
|
||||
dependencies = [
|
||||
"block-buffer 0.9.0",
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest 0.9.0",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.6"
|
||||
|
@ -1886,16 +1864,6 @@ dependencies = [
|
|||
"digest 0.10.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha256"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "328169f167261957e83d82be47f9e36629e257c62308129033d7f7e7c173d180"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"sha2 0.9.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.4"
|
||||
|
@ -2021,7 +1989,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"sha1",
|
||||
"sha2 0.10.6",
|
||||
"sha2",
|
||||
"smallvec",
|
||||
"sqlformat",
|
||||
"sqlx-rt",
|
||||
|
@ -2044,7 +2012,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"sha2 0.10.6",
|
||||
"sha2",
|
||||
"sqlx-core",
|
||||
"sqlx-rt",
|
||||
"syn",
|
||||
|
@ -2352,7 +2320,7 @@ dependencies = [
|
|||
"qrcodegen",
|
||||
"rand",
|
||||
"sha1",
|
||||
"sha2 0.10.6",
|
||||
"sha2",
|
||||
"url",
|
||||
"urlencoding",
|
||||
]
|
||||
|
@ -2457,7 +2425,7 @@ dependencies = [
|
|||
"ipnet",
|
||||
"pem",
|
||||
"quick-protobuf",
|
||||
"sha256",
|
||||
"sha2",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
|
|
|
@ -13,4 +13,4 @@ ed25519-dalek = "2.0.0-pre.0"
|
|||
ipnet = "2.7.1"
|
||||
quick-protobuf = "0.8.1"
|
||||
hex = "0.4.3"
|
||||
sha256 = "1.1.2"
|
||||
sha2 = "0.10.6"
|
|
@ -0,0 +1 @@
|
|||
0aaa010a0774657374696e67121b8182845080feffff0f828284508080fcff0f83828450808080f80f1a1b8182844880ffffff0f8282844880feffff0f838284488080fcff0f220b746573742d67726f757031220b746573742d67726f757032220b746573742d67726f75703328888cf39f0630808df39f063a20313233343536373839306162636564666768696a3132333435363738393061624a101234567890abcedfabcd1234567890ab1220313233343536373839306162636564666768696a313233343536373839306162
|
|
@ -0,0 +1 @@
|
|||
0a490a1765337465616d20496e7465726e616c204e6574776f726b28959ebf9c06309585c4ab063a20afa70a07c8a639f10e7ed97c438eda027ffce5358fc451d07c6f05d04b0128e740011240740f1efa96432a7372321f9fa697674a8d3caf078262c3ac7769b7f961971ff2b0ee544810a6f15d266a37c49c886f70bdbca67a917b14c63c3ab3525d5a0900
|
|
@ -0,0 +1,5 @@
|
|||
-----BEGIN NEBULA CERTIFICATE-----
|
||||
CkkKF2UzdGVhbSBJbnRlcm5hbCBOZXR3b3JrKJWev5wGMJWFxKsGOiCvpwoHyKY5
|
||||
8Q5+2XxDjtoCf/zlNY/EUdB8bwXQSwEo50ABEkB0Dx76lkMqc3IyH5+ml2dKjTyv
|
||||
B4Jiw6x3abf5YZcf8rDuVEgQpvFdJmo3xJyIb3C9vKZ6kXsUxjw6s1JdWgkA
|
||||
-----END NEBULA CERTIFICATE-----
|
|
@ -10,11 +10,12 @@ 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, Writer};
|
||||
use sha256::digest;
|
||||
use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer};
|
||||
use sha2::Sha256;
|
||||
use x25519_dalek::{PublicKey, StaticSecret};
|
||||
use crate::ca::NebulaCAPool;
|
||||
use crate::cert_codec::{RawNebulaCertificate, RawNebulaCertificateDetails};
|
||||
use sha2::Digest;
|
||||
|
||||
/// The length, in bytes, of public keys
|
||||
pub const PUBLIC_KEY_LENGTH: i32 = 32;
|
||||
|
@ -31,6 +32,7 @@ pub const ED25519_PRIVATE_KEY_BANNER: &str = "NEBULA ED25519 PRIVATE KEY";
|
|||
pub const ED25519_PUBLIC_KEY_BANNER: &str = "NEBULA ED25519 PUBLIC KEY";
|
||||
|
||||
/// A Nebula PKI certificate
|
||||
#[derive(Debug)]
|
||||
pub struct NebulaCertificate {
|
||||
/// The signed data of this certificate
|
||||
pub details: NebulaCertificateDetails,
|
||||
|
@ -39,6 +41,7 @@ pub struct NebulaCertificate {
|
|||
}
|
||||
|
||||
/// The signed details contained in a Nebula PKI certificate
|
||||
#[derive(Debug)]
|
||||
pub struct NebulaCertificateDetails {
|
||||
/// The name of the identity this certificate was issued for
|
||||
pub name: String,
|
||||
|
@ -107,6 +110,26 @@ fn map_cidr_pairs(pairs: &[u32]) -> Result<Vec<Ipv4Net>, Box<dyn Error>> {
|
|||
Ok(res_vec)
|
||||
}
|
||||
|
||||
impl Display for NebulaCertificate {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(f, "NebulaCertificate {{")?;
|
||||
writeln!(f, " Details {{")?;
|
||||
writeln!(f, " Name: {}", self.details.name)?;
|
||||
writeln!(f, " Ips: {:?}", self.details.ips)?;
|
||||
writeln!(f, " Subnets: {:?}", self.details.subnets)?;
|
||||
writeln!(f, " Groups: {:?}", self.details.groups)?;
|
||||
writeln!(f, " Not before: {:?}", self.details.not_before)?;
|
||||
writeln!(f, " Not after: {:?}", self.details.not_after)?;
|
||||
writeln!(f, " Is CA: {}", self.details.is_ca)?;
|
||||
writeln!(f, " Issuer: {}", self.details.issuer)?;
|
||||
writeln!(f, " Public key: {}", hex::encode(self.details.public_key))?;
|
||||
writeln!(f, " }}")?;
|
||||
writeln!(f, " Fingerprint: {}", self.sha256sum().unwrap())?;
|
||||
writeln!(f, " Signature: {}", hex::encode(self.signature.clone()))?;
|
||||
writeln!(f, "}}")
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a protobuf-encoded certificate bytearray, deserialize it into a `NebulaCertificate` object.
|
||||
/// # Errors
|
||||
/// This function will return an error if there is a protobuf parsing error, or if the certificate data is invalid.
|
||||
|
@ -442,7 +465,9 @@ impl NebulaCertificate {
|
|||
|
||||
let mut out = vec![];
|
||||
let mut writer = Writer::new(&mut out);
|
||||
writer.write_message(&raw_cert)?;
|
||||
raw_cert.write_message(&mut writer)?;
|
||||
|
||||
println!("{:?}", hex::encode(out.clone()));
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
|
@ -465,7 +490,10 @@ impl NebulaCertificate {
|
|||
pub fn sha256sum(&self) -> Result<String, Box<dyn Error>> {
|
||||
let pbuf_bytes = self.serialize()?;
|
||||
|
||||
Ok(digest(&pbuf_bytes[..]))
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(pbuf_bytes);
|
||||
|
||||
Ok(hex::encode(hasher.finalize()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#![allow(unknown_lints)]
|
||||
#![allow(clippy::all)]
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(clippy::wildcard_imports)]
|
||||
#![allow(clippy::pedantic)]
|
||||
|
||||
use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result};
|
||||
use quick_protobuf::sizeofs::*;
|
||||
|
@ -36,17 +36,17 @@ impl<'a> MessageRead<'a> for RawNebulaCertificate {
|
|||
}
|
||||
|
||||
impl MessageWrite for RawNebulaCertificate {
|
||||
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
|
||||
if let Some(ref s) = self.Details { w.write_with_tag(10, |w| w.write_message(s))?; }
|
||||
if !self.Signature.is_empty() { w.write_with_tag(18, |w| w.write_bytes(&**&self.Signature))?; }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_size(&self) -> usize {
|
||||
0
|
||||
+ self.Details.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
|
||||
+ if self.Signature.is_empty() { 0 } else { 1 + sizeof_len((&self.Signature).len()) }
|
||||
}
|
||||
|
||||
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
|
||||
if let Some(ref s) = self.Details { w.write_with_tag(10, |w| w.write_message(s))?; }
|
||||
if !self.Signature.is_empty() { w.write_with_tag(18, |w| w.write_bytes(&**&self.Signature))?; }
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
|
@ -85,12 +85,24 @@ impl<'a> MessageRead<'a> for RawNebulaCertificateDetails {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
impl MessageWrite for RawNebulaCertificateDetails {
|
||||
fn get_size(&self) -> usize {
|
||||
0
|
||||
+ if self.Name == String::default() { 0 } else { 1 + sizeof_len((&self.Name).len()) }
|
||||
+ if self.Ips.is_empty() { 0 } else { 1 + sizeof_len(self.Ips.iter().map(|s| sizeof_varint(*(s) as u64)).sum::<usize>()) }
|
||||
+ if self.Subnets.is_empty() { 0 } else { 1 + sizeof_len(self.Subnets.iter().map(|s| sizeof_varint(*(s) as u64)).sum::<usize>()) }
|
||||
+ self.Groups.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
|
||||
+ if self.NotBefore == 0i64 { 0 } else { 1 + sizeof_varint(*(&self.NotBefore) as u64) }
|
||||
+ if self.NotAfter == 0i64 { 0 } else { 1 + sizeof_varint(*(&self.NotAfter) as u64) }
|
||||
+ if self.PublicKey.is_empty() { 0 } else { 1 + sizeof_len((&self.PublicKey).len()) }
|
||||
+ if self.IsCA == false { 0 } else { 1 + sizeof_varint(*(&self.IsCA) as u64) }
|
||||
+ if self.Issuer.is_empty() { 0 } else { 1 + sizeof_len((&self.Issuer).len()) }
|
||||
}
|
||||
|
||||
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
|
||||
if self.Name != String::default() { w.write_with_tag(10, |w| w.write_string(&**&self.Name))?; }
|
||||
w.write_packed_with_tag(18, &self.Ips, |w, m| w.write_uint32(*m), &|m| sizeof_varint(u64::from(*(m))))?;
|
||||
w.write_packed_with_tag(26, &self.Subnets, |w, m| w.write_uint32(*m), &|m| sizeof_varint(u64::from(*(m))))?;
|
||||
w.write_packed_with_tag(18, &self.Ips, |w, m| w.write_uint32(*m), &|m| sizeof_varint(*(m) as u64))?;
|
||||
w.write_packed_with_tag(26, &self.Subnets, |w, m| w.write_uint32(*m), &|m| sizeof_varint(*(m) as u64))?;
|
||||
for s in &self.Groups { w.write_with_tag(34, |w| w.write_string(&**s))?; }
|
||||
if self.NotBefore != 0i64 { w.write_with_tag(40, |w| w.write_int64(*&self.NotBefore))?; }
|
||||
if self.NotAfter != 0i64 { w.write_with_tag(48, |w| w.write_int64(*&self.NotAfter))?; }
|
||||
|
@ -99,18 +111,5 @@ impl MessageWrite for RawNebulaCertificateDetails {
|
|||
if !self.Issuer.is_empty() { w.write_with_tag(74, |w| w.write_bytes(&**&self.Issuer))?; }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_size(&self) -> usize {
|
||||
0
|
||||
+ if self.Name == String::default() { 0 } else { 1 + sizeof_len((&self.Name).len()) }
|
||||
+ if self.Ips.is_empty() { 0 } else { 1 + sizeof_len(self.Ips.iter().map(|s| sizeof_varint(u64::from(*(s)))).sum::<usize>()) }
|
||||
+ if self.Subnets.is_empty() { 0 } else { 1 + sizeof_len(self.Subnets.iter().map(|s| sizeof_varint(u64::from(*(s)))).sum::<usize>()) }
|
||||
+ self.Groups.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
|
||||
+ if self.NotBefore == 0i64 { 0 } else { 1 + sizeof_varint(*(&self.NotBefore) as u64) }
|
||||
+ if self.NotAfter == 0i64 { 0 } else { 1 + sizeof_varint(*(&self.NotAfter) as u64) }
|
||||
+ if self.PublicKey.is_empty() { 0 } else { 1 + sizeof_len((&self.PublicKey).len()) }
|
||||
+ if self.IsCA == false { 0 } else { 1 + sizeof_varint(u64::from(*(&self.IsCA))) }
|
||||
+ if self.Issuer.is_empty() { 0 } else { 1 + sizeof_len((&self.Issuer).len()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#![allow(clippy::module_name_repetitions)]
|
||||
|
||||
|
||||
extern crate core;
|
||||
|
||||
pub mod ca;
|
||||
pub mod cert;
|
||||
pub(crate) mod cert_codec;
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
#![allow(clippy::unwrap_used)]
|
||||
#![allow(clippy::expect_used)]
|
||||
|
||||
use std::fs;
|
||||
use crate::netmask;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use std::ops::Add;
|
||||
use std::time::{Duration, SystemTime, SystemTimeError, UNIX_EPOCH};
|
||||
use ipnet::Ipv4Net;
|
||||
use crate::cert::{deserialize_nebula_certificate, NebulaCertificate, NebulaCertificateDetails};
|
||||
use std::str::FromStr;
|
||||
|
||||
/// 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-----";
|
||||
|
||||
#[test]
|
||||
fn certificate_serialization() {
|
||||
let before = SystemTime::now() - Duration::from_secs(60);
|
||||
let after = SystemTime::now() + Duration::from_secs(60);
|
||||
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 cert = NebulaCertificate {
|
||||
|
@ -20,10 +25,10 @@ fn certificate_serialization() {
|
|||
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.255.0")
|
||||
netmask!("10.1.1.3", "255.0.0.0")
|
||||
],
|
||||
subnets: vec![
|
||||
netmask!("9.1.1.1", "255.0.255.0"),
|
||||
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")
|
||||
],
|
||||
|
@ -32,13 +37,15 @@ fn certificate_serialization() {
|
|||
not_after: after,
|
||||
public_key: *pub_key,
|
||||
is_ca: false,
|
||||
issuer: "1234567890abcedfghij1234567890ab".to_string(),
|
||||
issuer: "1234567890abcedfabcd1234567890ab".to_string(),
|
||||
},
|
||||
signature: b"1234567890abcedfghij1234567890ab".to_vec(),
|
||||
};
|
||||
|
||||
let bytes = cert.serialize().unwrap();
|
||||
|
||||
fs::write("bad.hex.crt", hex::encode(bytes.clone())).unwrap();
|
||||
|
||||
let deserialized = deserialize_nebula_certificate(&bytes).unwrap();
|
||||
/*
|
||||
assert.Equal(t, nc.Details.Name, nc2.Details.Name)
|
||||
|
@ -49,7 +56,9 @@ assert.Equal(t, nc.Details.Name, nc2.Details.Name)
|
|||
*/
|
||||
assert_eq!(cert.signature, deserialized.signature);
|
||||
assert_eq!(cert.details.name, deserialized.details.name);
|
||||
assert_eq!(cert.details.not_before, deserialized.details.not_after);
|
||||
assert_eq!(cert.details.not_before, deserialized.details.not_before);
|
||||
assert_eq!(cert.details.not_after, deserialized.details.not_after);
|
||||
assert_eq!(cert.details.public_key, deserialized.details.public_key);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
@ -58,3 +67,8 @@ macro_rules! netmask {
|
|||
Ipv4Net::with_netmask(Ipv4Addr::from_str($ip).unwrap(), Ipv4Addr::from_str($mask).unwrap()).unwrap()
|
||||
};
|
||||
}
|
||||
|
||||
fn round_systime_to_secs(time: SystemTime) -> Result<SystemTime, SystemTimeError> {
|
||||
let secs = time.duration_since(UNIX_EPOCH)?.as_secs();
|
||||
Ok(SystemTime::UNIX_EPOCH.add(Duration::from_secs(secs)))
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
-----BEGIN NEBULA CERTIFICATE-----
|
||||
zwEKqgEKB3Rlc3RpbmcSG4GChFCA/v//D4KChFCAgPz/D4OChFCAgID4DxobgYKE
|
||||
SID///8PgoKESID+//8Pg4KESICA/P8PIgt0ZXN0LWdyb3VwMSILdGVzdC1ncm91
|
||||
cDIiC3Rlc3QtZ3JvdXAzKLDU8p8GMKjV8p8GOiAxMjM0NTY3ODkwYWJjZWRmZ2hp
|
||||
ajEyMzQ1Njc4OTBhYkoQEjRWeJCrzt+rzRI0VniQqxIgMTIzNDU2Nzg5MGFiY2Vk
|
||||
ZmdoaWoxMjM0NTY3ODkwYWI=
|
||||
-----END NEBULA CERTIFICATE-----
|
Loading…
Reference in New Issue