#![feature(duration_constructors)] use anyhow::Result; use clap::Parser; use rcgen::{ BasicConstraints, CertificateParams, DistinguishedName, DnType, IsCa, KeyPair, KeyUsagePurpose, }; use std::fs; use time::{Duration, OffsetDateTime}; /// Generate a Certificate Authority with some opinionated /// options selected. #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Args { /// Name of the organization for the CA. #[arg(long)] org_name: String, /// Days for CA to valid for. #[arg(long, default_value = "3650")] valid_length: i64, /// Output directory for artifacts. #[arg(long, short)] output: String, } fn main() -> Result<()> { let args = Args::parse(); let mut params: CertificateParams = Default::default(); let earliest_date = OffsetDateTime::now_utc(); let latest_date = OffsetDateTime::now_utc() .checked_add(Duration::days(args.valid_length)) .ok_or(anyhow::Error::msg("Could not get date."))?; params.not_before = earliest_date; params.not_after = latest_date; params.distinguished_name = DistinguishedName::new(); params .distinguished_name .push(DnType::OrganizationName, args.org_name); params.distinguished_name.push(DnType::CommonName, "CA"); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); params.key_usages.push(KeyUsagePurpose::DigitalSignature); params.key_usages.push(KeyUsagePurpose::KeyCertSign); params.key_usages.push(KeyUsagePurpose::CrlSign); let key_pair = KeyPair::generate()?; let cert = params.self_signed(&key_pair)?; let pem_serialized = cert.pem(); println!("Saving artifacts."); fs::create_dir_all(&args.output)?; fs::write( format!("{}/cert.pem", &args.output), pem_serialized.as_bytes(), )?; fs::write( format!("{}/key.pem", &args.output), key_pair.serialize_pem().as_bytes(), )?; Ok(()) }