Add cert generation.
This commit is contained in:
parent
76d606a58f
commit
ef8690bcd9
|
|
@ -7,5 +7,5 @@ edition = "2024"
|
|||
anyhow = "1.0.100"
|
||||
clap = { version = "4.5.53", features = ["derive"] }
|
||||
pem = "3.0.6"
|
||||
rcgen = { version = "0.14.6", features = ["fips"] }
|
||||
rcgen = { version = "0.14.6", features = ["fips", "x509-parser"] }
|
||||
time = "0.3.44"
|
||||
|
|
|
|||
|
|
@ -61,6 +61,10 @@ fn main() -> Result<()> {
|
|||
format!("{}/key.pem", &args.output),
|
||||
key_pair.serialize_pem().as_bytes(),
|
||||
)?;
|
||||
fs::write(
|
||||
format!("{}/public.pem", &args.output),
|
||||
key_pair.public_key_pem().as_bytes(),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
#![feature(duration_constructors)]
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use rcgen::{
|
||||
CertificateParams, DistinguishedName, DnType, ExtendedKeyUsagePurpose,
|
||||
Issuer, KeyPair, KeyUsagePurpose, SanType,
|
||||
};
|
||||
use rcgen::string::Ia5String;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use time::{Duration, OffsetDateTime};
|
||||
|
||||
/// Generate a Certificate Authority with some opinionated
|
||||
/// options selected.
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Args {
|
||||
/// Common name for this cert.
|
||||
#[arg(long)]
|
||||
common_name: String,
|
||||
|
||||
/// Email address to assign to cert.
|
||||
#[arg(long)]
|
||||
email_address: Option<String>,
|
||||
|
||||
/// Domain address to assign to cert.
|
||||
#[arg(long)]
|
||||
domain_name: Option<String>,
|
||||
|
||||
/// Set to make this cert valid for client authentication.
|
||||
#[arg(long)]
|
||||
client_auth: bool,
|
||||
|
||||
/// Set to make this cert valid for server authentication.
|
||||
#[arg(long)]
|
||||
server_auth: bool,
|
||||
|
||||
/// Days for CA to valid for.
|
||||
#[arg(long, default_value = "365")]
|
||||
valid_length: i64,
|
||||
|
||||
/// Path to CA folder.
|
||||
#[arg(long)]
|
||||
ca_path: String,
|
||||
|
||||
/// Output directory for artifacts.
|
||||
#[arg(long, short)]
|
||||
output: String,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args = Args::parse();
|
||||
|
||||
if (args.client_auth && args.server_auth) || (!args.client_auth && !args.server_auth) {
|
||||
return Err(anyhow::Error::msg(
|
||||
"Must set one and only one of client or server auth.",
|
||||
));
|
||||
}
|
||||
|
||||
// Set up our identity.
|
||||
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::CommonName, args.common_name);
|
||||
if args.email_address.is_some() {
|
||||
let email_address = Ia5String::try_from(args.email_address.unwrap())?;
|
||||
params
|
||||
.subject_alt_names
|
||||
.push(SanType::Rfc822Name(email_address));
|
||||
}
|
||||
if args.domain_name.is_some() {
|
||||
let domain_name = Ia5String::try_from(args.domain_name.unwrap())?;
|
||||
params
|
||||
.subject_alt_names
|
||||
.push(SanType::DnsName(domain_name));
|
||||
}
|
||||
|
||||
// Set up our purposes.
|
||||
params.key_usages.push(KeyUsagePurpose::DigitalSignature);
|
||||
if args.client_auth {
|
||||
params
|
||||
.extended_key_usages
|
||||
.push(ExtendedKeyUsagePurpose::ClientAuth);
|
||||
}
|
||||
if args.server_auth {
|
||||
params
|
||||
.extended_key_usages
|
||||
.push(ExtendedKeyUsagePurpose::ServerAuth);
|
||||
}
|
||||
|
||||
// Get the ca key pair and cert.
|
||||
let ca_keys_file = PathBuf::from(format!("{}/key.pem", &args.ca_path));
|
||||
let ca_cert_file = PathBuf::from(format!("{}/cert.pem", &args.ca_path));
|
||||
|
||||
let ca_keys_pem = fs::read_to_string(&ca_keys_file)?;
|
||||
let ca_cert_pem = fs::read_to_string(&ca_cert_file)?;
|
||||
|
||||
let ca_key_pair = KeyPair::from_pem(&ca_keys_pem)?;
|
||||
let signer = Issuer::from_ca_cert_pem(&ca_cert_pem, ca_key_pair)?;
|
||||
|
||||
let key_pair = KeyPair::generate()?;
|
||||
let cert = params.signed_by(&key_pair, &signer)?;
|
||||
|
||||
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(())
|
||||
}
|
||||
Loading…
Reference in New Issue