Refactor Certificate management

This commit is contained in:
2024-03-18 13:40:34 +01:00
parent 177d472d59
commit a1b4865b3f
15 changed files with 659 additions and 108 deletions

View File

@@ -25,7 +25,13 @@ rmp-serde = "1.1.2"
rcgen = { version = "0.12.1", features = ["x509-parser"] }
rand = "0.8.5"
uuid = { version = "1.7.0", features = ["v4", "serde"] }
rustls-pemfile = "2.0.0"
x509-parser = "0.16.0"
[[bin]]
name = "init_certs"
path = "src/bin/init_certs.rs"
[[bin]]
name = "init_certs_2"
path = "src/bin/init_certs_2.rs"

View File

@@ -0,0 +1,201 @@
use std::fs::File;
use std::io::Write;
use rcgen::{self, BasicConstraints, Certificate, CertificateParams, DnType};
fn server_root_cert() -> Certificate {
let subject_alt_names = vec!["hello.world.example".into()];
let mut certparams = CertificateParams::new(subject_alt_names);
certparams.is_ca = rcgen::IsCa::Ca(BasicConstraints::Unconstrained);
let mut distname = rcgen::DistinguishedName::new();
distname.push(DnType::OrganizationName, "Eister Corporation");
distname.push(DnType::CommonName, "Bonknet Server Root Cert CA");
certparams.distinguished_name = distname;
Certificate::from_params(certparams).unwrap()
}
fn server_cert() -> Certificate {
let mut params = CertificateParams::new(vec!["entity.other.host".into(), "bonk.server.1".into()]);
params.distinguished_name.push(DnType::CommonName, "Server 1");
params.use_authority_key_identifier_extension = true;
params.key_usages.push(rcgen::KeyUsagePurpose::DigitalSignature);
params
.extended_key_usages
.push(rcgen::ExtendedKeyUsagePurpose::ClientAuth);
Certificate::from_params(params).unwrap()
}
fn guestserver_root_cert() -> Certificate {
let subject_alt_names = vec!["hello.world.example".into()];
let mut certparams = CertificateParams::new(subject_alt_names);
certparams.is_ca = rcgen::IsCa::Ca(BasicConstraints::Unconstrained);
let mut distname = rcgen::DistinguishedName::new();
distname.push(DnType::OrganizationName, "Eister Corporation");
distname.push(DnType::CommonName, "Bonknet Guest Server Root Cert CA");
certparams.distinguished_name = distname;
Certificate::from_params(certparams).unwrap()
}
fn guestserver_cert() -> Certificate {
let mut params = CertificateParams::new(vec!["entity.other.host".into(), "bonk.guestserver.1".into()]);
params.distinguished_name.push(DnType::CommonName, "Guest Server 1");
params.use_authority_key_identifier_extension = true;
params.key_usages.push(rcgen::KeyUsagePurpose::DigitalSignature);
params
.extended_key_usages
.push(rcgen::ExtendedKeyUsagePurpose::ClientAuth);
Certificate::from_params(params).unwrap()
}
fn client_root_cert() -> Certificate {
let subject_alt_names = vec!["hello.world.example".into()];
let mut certparams = CertificateParams::new(subject_alt_names);
certparams.is_ca = rcgen::IsCa::Ca(BasicConstraints::Unconstrained);
let mut distname = rcgen::DistinguishedName::new();
distname.push(DnType::OrganizationName, "Eister Corporation");
distname.push(DnType::CommonName, "Bonknet Client Root Cert CA");
certparams.distinguished_name = distname;
Certificate::from_params(certparams).unwrap()
}
fn client_cert() -> Certificate {
let mut params = CertificateParams::new(vec!["entity.other.host".into(), "bonk.client.1".into()]);
params.distinguished_name.push(DnType::CommonName, "Client 1");
params.use_authority_key_identifier_extension = true;
params.key_usages.push(rcgen::KeyUsagePurpose::DigitalSignature);
params
.extended_key_usages
.push(rcgen::ExtendedKeyUsagePurpose::ClientAuth);
Certificate::from_params(params).unwrap()
}
fn broker_root_cert() -> Certificate {
let subject_alt_names = vec!["hello.world.example".into()];
let mut certparams = CertificateParams::new(subject_alt_names);
certparams.is_ca = rcgen::IsCa::Ca(BasicConstraints::Unconstrained);
let mut distname = rcgen::DistinguishedName::new();
distname.push(DnType::OrganizationName, "Eister Corporation");
distname.push(DnType::CommonName, "Bonknet Broker Root Cert CA");
certparams.distinguished_name = distname;
Certificate::from_params(certparams).unwrap()
}
fn broker_cert() -> Certificate {
let mut params = CertificateParams::new(vec!["entity.other.host".into(), "localhost".into()]);
params.distinguished_name.push(DnType::CommonName, "localhost");
params.use_authority_key_identifier_extension = true;
params.key_usages.push(rcgen::KeyUsagePurpose::DigitalSignature);
params
.extended_key_usages
.push(rcgen::ExtendedKeyUsagePurpose::ServerAuth);
Certificate::from_params(params).unwrap()
}
fn main() -> std::io::Result<()> {
// Generate Root CA Certificates
let server_root_cert = server_root_cert();
let guestserver_root_cert = guestserver_root_cert();
let client_root_cert = client_root_cert();
let broker_root_cert = broker_root_cert();
// Generate Leafs
let server_leaf_cert = server_cert();
let guestserver_leaf_cert = guestserver_cert();
let client_leaf_cert = client_cert();
let broker_leaf_cert = broker_cert();
// Generate PEMs
// every time you generate one, a new random number is taken, so different cert hashes!
// and we need this PEMs to appear in multiple files
// We don't need this for the pvkey because we generate them only one time for each cert
// IF YOU NEED TO WRITE PVKEY IN MULTIPLE FILES, PLEASE DO IT LIKE THESE LINES FOR THE x509!!!
let server_root_cert_pem = server_root_cert.serialize_pem().unwrap();
let guestserver_root_cert_pem = guestserver_root_cert.serialize_pem().unwrap();
let client_root_cert_pem = client_root_cert.serialize_pem().unwrap();
let broker_root_cert_pem = broker_root_cert.serialize_pem().unwrap();
let server_leaf_cert_pem = server_leaf_cert.serialize_pem_with_signer(&server_root_cert).unwrap();
let guestserver_leaf_cert_pem = guestserver_leaf_cert.serialize_pem_with_signer(&guestserver_root_cert).unwrap();
let client_leaf_cert_pem = client_leaf_cert.serialize_pem_with_signer(&client_root_cert).unwrap();
let broker_leaf_cert_pem = broker_leaf_cert.serialize_pem_with_signer(&broker_root_cert).unwrap();
// Root CA PEMs
/*
1 - CA Cert
2 - CA Prkey
*/
// Generate Server Root CA PEM
{
let mut pemfile = File::create("certs_pem/server_root_ca.pem")?;
pemfile.write_all(server_root_cert_pem.as_bytes())?;
pemfile.write_all(server_root_cert.serialize_private_key_pem().as_bytes())?;
}
// Generate GuestServer Root CA PEM
{
let mut pemfile = File::create("certs_pem/guestserver_root_ca.pem")?;
pemfile.write_all(guestserver_root_cert_pem.as_bytes())?;
pemfile.write_all(guestserver_root_cert.serialize_private_key_pem().as_bytes())?;
}
// Generate Client Root CA PEM
{
let mut pemfile = File::create("certs_pem/client_root_ca.pem")?;
pemfile.write_all(client_root_cert_pem.as_bytes())?;
pemfile.write_all(client_root_cert.serialize_private_key_pem().as_bytes())?;
}
// Generate Broker Root CA PEM
{
let mut pemfile = File::create("certs_pem/broker_root_ca.pem")?;
pemfile.write_all(broker_root_cert_pem.as_bytes())?;
pemfile.write_all(broker_root_cert.serialize_private_key_pem().as_bytes())?;
}
// Generate Broker CA Cert PEM for Server Authentication
{
let mut pemfile = File::create("certs_pem/broker_root_ca_cert.pem")?;
pemfile.write_all(broker_root_cert_pem.as_bytes())?;
}
// Generate Server Leaf PEM
/*
1 - Server Leaf Cert
2 - Server CA Cert chain
3 - Server Leaf Prkey
*/
{
let mut pemfile = File::create("certs_pem/server.pem")?;
pemfile.write_all(server_leaf_cert_pem.as_bytes())?;
pemfile.write_all(server_root_cert_pem.as_bytes())?;
pemfile.write_all(server_leaf_cert.serialize_private_key_pem().as_bytes())?;
}
// Generate GuestServer Leaf PEM
/*
1 - GuestServer Leaf Cert
2 - GuestServer CA Cert chain
3 - GuestServer Leaf Prkey
*/
{
let mut pemfile = File::create("certs_pem/guestserver.pem")?;
pemfile.write_all(guestserver_leaf_cert_pem.as_bytes())?;
pemfile.write_all(guestserver_root_cert_pem.as_bytes())?;
pemfile.write_all(guestserver_leaf_cert.serialize_private_key_pem().as_bytes())?;
}
// Generate Client Leaf PEM
/*
1 - Client Leaf Cert
2 - Client CA Cert chain
3 - Client Leaf Prkey
*/
{
let mut pemfile = File::create("certs_pem/client.pem")?;
pemfile.write_all(client_leaf_cert_pem.as_bytes())?;
pemfile.write_all(client_root_cert_pem.as_bytes())?;
pemfile.write_all(client_leaf_cert.serialize_private_key_pem().as_bytes())?;
}
// Generate Broker Leaf PEM
/*
1 - Broker Leaf Cert
2 - Broker CA Cert
3 - Broker Leaf Prkey
*/
{
let mut pemfile = File::create("certs_pem/broker.pem")?;
pemfile.write_all(broker_leaf_cert_pem.as_bytes())?;
pemfile.write_all(broker_root_cert_pem.as_bytes())?;
pemfile.write_all(broker_leaf_cert.serialize_private_key_pem().as_bytes())?;
}
println!("Certificates created");
Ok(())
}

View File

@@ -1,20 +0,0 @@
use rcgen::{Certificate, CertificateParams, DnType};
pub struct ServerCert {
pub cert: Vec<u8>,
pub prkey: Vec<u8>,
}
pub fn generate_server_cert(root_cert: &Certificate, name: &str) -> ServerCert {
let mut params = CertificateParams::new(vec!["entity.other.host".into(), format!("bonk.server.{name}")]);
params.distinguished_name.push(DnType::CommonName, name);
params.use_authority_key_identifier_extension = true;
params.key_usages.push(rcgen::KeyUsagePurpose::DigitalSignature);
params
.extended_key_usages
.push(rcgen::ExtendedKeyUsagePurpose::ClientAuth);
let certificate = Certificate::from_params(params).unwrap();
let cert = certificate.serialize_der_with_signer(root_cert).unwrap();
let prkey = certificate.serialize_private_key_der();
ServerCert { cert, prkey }
}

View File

@@ -3,7 +3,6 @@ mod pendingdataconndb;
mod servermanager;
mod dataconnmanager;
mod streamutils;
mod certutils;
use servercertdb::*;
use pendingdataconndb::*;
@@ -12,9 +11,9 @@ use dataconnmanager::*;
use streamutils::*;
use actix::prelude::*;
use std::sync::Arc;
use libbonknet::*;
use libbonknet::servermsg::*;
use libbonknet::clientmsg::*;
use libbonknet::cert::*;
use rustls::{RootCertStore, ServerConfig};
use rustls::server::WebPkiClientVerifier;
use actix_tls::accept::rustls_0_22::{Acceptor as RustlsAcceptor, TlsStream};
@@ -24,15 +23,13 @@ use actix_service::ServiceFactoryExt as _;
use futures::{SinkExt, StreamExt};
use tokio_util::codec::{Framed, LengthDelimitedCodec};
use tracing::{error, info, warn};
use rcgen::{Certificate, CertificateParams, KeyPair};
use rustls::pki_types::CertificateDer;
#[derive(Clone)]
struct BrokerContext {
server_root_cert_der: CertificateDer<'static>,
client_root_cert_der: CertificateDer<'static>,
guestserver_root_cert_der: CertificateDer<'static>,
broker_leaf: LeafCertPair<'static>,
client_ca: CACertPair<'static>,
server_ca: CACertPair<'static>,
guestserver_ca: CACertPair<'static>,
scdb_addr: Addr<ServerCertDB>,
pdcm_addr: Addr<PendingDataConnManager>,
sm_addr: Addr<ServerManager>,
@@ -44,66 +41,58 @@ async fn main() {
// Tracing Subscriber
let subscriber = tracing_subscriber::FmtSubscriber::new();
tracing::subscriber::set_global_default(subscriber).unwrap();
// BROKER CERTS
let broker_root_cert_der = load_cert("certs/broker_root_cert.pem").unwrap();
let broker_cert_der = load_cert("certs/broker_cert.pem").unwrap();
let broker_prkey_der = load_prkey("certs/broker_key.pem").unwrap();
// SERVER ROOT
let server_root_cert_der = load_cert("certs/server_root_cert.pem").unwrap();
let server_root_prkey_der = load_prkey("certs/server_root_key.pem").unwrap();
// GUESTSERVER ROOT
let guestserver_root_cert_der = load_cert("certs/guestserver_root_cert.pem").unwrap();
// CLIENT ROOT
let client_root_cert_der = load_cert("certs/client_root_cert.pem").unwrap();
// Client Verifier
let mut broker_root_store = RootCertStore::empty();
broker_root_store.add(server_root_cert_der.clone()).unwrap();
broker_root_store.add(client_root_cert_der.clone()).unwrap();
broker_root_store.add(guestserver_root_cert_der.clone()).unwrap();
let server_verifier = WebPkiClientVerifier::builder(Arc::new(broker_root_store)).build().unwrap();
// Configure TLS
let server_tlsconfig = ServerConfig::builder()
.with_client_cert_verifier(server_verifier)
.with_single_cert(vec![broker_cert_der.clone(), broker_root_cert_der.clone()], broker_prkey_der.into())
.unwrap();
let server_acceptor = RustlsAcceptor::new(server_tlsconfig);
// Load Identity
let broker_leaf = LeafCertPair::load_from_file("certs_pem/broker.pem").unwrap();
let client_ca = CACertPair::load_from_file("certs_pem/client_root_ca.pem").unwrap();
let server_ca = CACertPair::load_from_file("certs_pem/server_root_ca.pem").unwrap();
let guestserver_ca = CACertPair::load_from_file("certs_pem/guestserver_root_ca.pem").unwrap();
// Load Actors
let scdb_addr = ServerCertDB::new().start();
let dcm_addr = DataConnManager::new().start();
let pdcm_addr = PendingDataConnManager::new(dcm_addr).start();
let sm_addr = ServerManager::new(pdcm_addr.clone()).start();
let server_root_prkey = KeyPair::from_der(server_root_prkey_der.secret_pkcs8_der()).unwrap();
let server_root_cert = Arc::new(Certificate::from_params(CertificateParams::from_ca_cert_der(
&server_root_cert_der,
server_root_prkey
).unwrap()).unwrap());
// Create Context
let ctx = Arc::new(BrokerContext {
server_root_cert_der,
client_root_cert_der,
guestserver_root_cert_der,
broker_leaf,
client_ca,
server_ca,
guestserver_ca,
scdb_addr,
pdcm_addr,
sm_addr,
});
// Pki Client Verifier
let mut broker_root_store = RootCertStore::empty();
broker_root_store.add(ctx.server_ca.cert().clone()).unwrap();
broker_root_store.add(ctx.client_ca.cert().clone()).unwrap();
broker_root_store.add(ctx.guestserver_ca.cert().clone()).unwrap();
let server_verifier = WebPkiClientVerifier::builder(Arc::new(broker_root_store)).build().unwrap();
// Configure TLS
let server_tlsconfig = ServerConfig::builder()
.with_client_cert_verifier(server_verifier)
.with_single_cert(ctx.broker_leaf.fullchain(), ctx.broker_leaf.clone_key().into())
.unwrap();
let server_acceptor = RustlsAcceptor::new(server_tlsconfig);
Server::build()
.bind("server-command", ("localhost", 2541), move || {
let ctx = Arc::clone(&ctx);
let server_root_cert = Arc::clone(&server_root_cert);
// Set up TLS service factory
server_acceptor
.clone()
.map_err(|err| println!("Rustls error: {:?}", err))
.and_then(move |stream: TlsStream<TcpStream>| {
let ctx = Arc::clone(&ctx);
let server_root_cert = Arc::clone(&server_root_cert);
async move {
let peer_certs = stream.get_ref().1.peer_certificates().unwrap();
let peer_cert_bytes = peer_certs.first().unwrap().to_vec();
let peer_root_cert_der = peer_certs.last().unwrap().clone();
if peer_root_cert_der == ctx.server_root_cert_der {
info!("{:?}", &peer_root_cert_der);
info!("{:?}", ctx.server_ca.cert());
info!("{:?}", ctx.guestserver_ca.cert());
info!("{:?}", ctx.client_ca.cert());
if &peer_root_cert_der == ctx.server_ca.cert() {
info!("Server connection");
let mut transport = Framed::new(stream, LengthDelimitedCodec::new());
match transport.next().await {
@@ -150,12 +139,12 @@ async fn main() {
}
}
info!("Server Task terminated!");
} else if peer_root_cert_der == ctx.guestserver_root_cert_der {
} else if &peer_root_cert_der == ctx.guestserver_ca.cert() {
info!("GuestServer connection");
let codec = LengthDelimitedCodec::new();
let transport = Framed::new(stream, codec);
guestserver_handler(&ctx, transport, &server_root_cert).await;
} else if peer_root_cert_der == ctx.client_root_cert_der {
guestserver_handler(&ctx, transport).await;
} else if &peer_root_cert_der == ctx.client_ca.cert() {
info!("Client connection");
let codec = LengthDelimitedCodec::new();
let transport = Framed::new(stream, codec);
@@ -244,7 +233,7 @@ async fn server_command_handler(ctx: &BrokerContext, mut transport: TransportStr
}
}
async fn guestserver_handler(ctx: &BrokerContext, mut transport: TransportStream, server_root_cert: &Certificate) {
async fn guestserver_handler(ctx: &BrokerContext, mut transport: TransportStream) {
loop {
match transport.next().await {
None => {
@@ -266,15 +255,12 @@ async fn guestserver_handler(ctx: &BrokerContext, mut transport: TransportStream
transport.send(rmp_serde::to_vec(&reply).unwrap().into()).await.unwrap();
break; // Stop reading
} else {
let cert = certutils::generate_server_cert(server_root_cert, name.as_str());
let cert = ctx.server_ca.sign_new_cert(server_leaf_certparams(name.as_str()));
ctx.scdb_addr.send(RegisterServer {
cert: cert.cert.clone(),
cert: cert.cert().to_vec(),
name,
}).await.unwrap().unwrap();
let reply = ToGuestServerMessage::OkAnnounce {
server_cert: cert.cert,
server_prkey: cert.prkey
};
let reply = ToGuestServerMessage::make_okannounce(&cert);
transport.send(rmp_serde::to_vec(&reply).unwrap().into()).await.unwrap();
}
}