Generate Root CA

This commit is contained in:
2024-06-27 18:55:09 +02:00
commit e0801661eb
9 changed files with 620 additions and 0 deletions

View File

@ -0,0 +1,60 @@
use std::path::{Path, PathBuf};
use clap::Parser;
/// Solar system central backend
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
pub struct AppConfig {
/// The port the server will listen to (using HTTPS)
#[arg(short, long, env, default_value = "0.0.0.0:8443")]
listen_address: String,
/// Server storage path
#[arg(short, long, env, default_value = "storage")]
storage: String,
}
lazy_static::lazy_static! {
static ref ARGS: AppConfig = {
AppConfig::parse()
};
}
impl AppConfig {
/// Get parsed command line arguments
pub fn get() -> &'static AppConfig {
&ARGS
}
/// Get storage path
pub fn storage_path(&self) -> PathBuf {
Path::new(&self.storage).to_path_buf()
}
/// Get PKI storage path
pub fn pki_path(&self) -> PathBuf {
self.storage_path().join("pki")
}
/// Get PKI root CA cert path
pub fn root_ca_cert_path(&self) -> PathBuf {
self.pki_path().join("root_ca.pem")
}
/// Get PKI root CA private key path
pub fn root_ca_priv_key_path(&self) -> PathBuf {
self.pki_path().join("root_ca.key")
}
}
#[cfg(test)]
mod test {
use crate::app_config::AppConfig;
#[test]
fn verify_cli() {
use clap::CommandFactory;
AppConfig::command().debug_assert()
}
}

View File

@ -0,0 +1,3 @@
pub mod app_config;
pub mod pki;
pub mod utils;

View File

@ -0,0 +1,13 @@
use central_backend::app_config::AppConfig;
use central_backend::pki;
use central_backend::utils::files_utils::create_directory_if_missing;
fn main() {
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
// Initialize storage
create_directory_if_missing(&AppConfig::get().pki_path()).unwrap();
// Initialize PKI
pki::initialize_root_ca().expect("Failed to initialize Root CA!");
}

View File

@ -0,0 +1,68 @@
use openssl::asn1::Asn1Time;
use openssl::bn::{BigNum, MsbOption};
use openssl::ec::EcGroup;
use openssl::hash::MessageDigest;
use openssl::nid::Nid;
use openssl::pkey::PKey;
use openssl::x509::extension::{BasicConstraints, KeyUsage, SubjectKeyIdentifier};
use openssl::x509::{X509, X509NameBuilder};
use crate::app_config::AppConfig;
/// Initialize Root CA, if required
pub fn initialize_root_ca() -> anyhow::Result<()> {
if AppConfig::get().root_ca_cert_path().exists()
&& AppConfig::get().root_ca_priv_key_path().exists() {
return Ok(());
}
log::info!("Generating root ca...");
// Generate root private key
let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve
let group = EcGroup::from_curve_name(nid)?;
let key = openssl::ec::EcKey::generate(&group)?;
let key_pair = PKey::from_ec_key(key.clone())?;
let mut x509_name = X509NameBuilder::new()?;
x509_name.append_entry_by_text("C", "FR")?;
x509_name.append_entry_by_text("CN", "SolarEnergy Root CA")?;
let x509_name = x509_name.build();
let mut cert_builder = X509::builder()?;
cert_builder.set_version(2)?;
let serial_number = {
let mut serial = BigNum::new()?;
serial.rand(159, MsbOption::MAYBE_ZERO, false)?;
serial.to_asn1_integer()?
};
cert_builder.set_serial_number(&serial_number)?;
cert_builder.set_subject_name(&x509_name)?;
cert_builder.set_issuer_name(&x509_name)?;
cert_builder.set_pubkey(&key_pair)?;
let not_before = Asn1Time::days_from_now(0)?;
cert_builder.set_not_before(&not_before)?;
let not_after = Asn1Time::days_from_now(365 * 30)?;
cert_builder.set_not_after(&not_after)?;
cert_builder.append_extension(BasicConstraints::new().critical().ca().build()?)?;
cert_builder.append_extension(
KeyUsage::new()
.critical()
.key_cert_sign()
.crl_sign()
.build()?,
)?;
let subject_key_identifier =
SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?;
cert_builder.append_extension(subject_key_identifier)?;
cert_builder.sign(&key_pair, MessageDigest::sha256())?;
let cert = cert_builder.build();
// Serialize generated root CA
std::fs::write(AppConfig::get().root_ca_priv_key_path(), key.private_key_to_pem()?)?;
std::fs::write(AppConfig::get().root_ca_cert_path(), cert.to_pem()?)?;
Ok(())
}

View File

@ -0,0 +1,10 @@
use std::path::Path;
/// Create directory if missing
pub fn create_directory_if_missing<P: AsRef<Path>>(path: P) -> anyhow::Result<()> {
let path = path.as_ref();
if !path.exists() {
std::fs::create_dir_all(path)?;
}
Ok(())
}

View File

@ -0,0 +1 @@
pub mod files_utils;