diff options
author | Galen Guyer <galen@galenguyer.com> | 2022-03-28 21:59:22 -0400 |
---|---|---|
committer | Galen Guyer <galen@galenguyer.com> | 2022-03-28 21:59:22 -0400 |
commit | 777b2e22cf25586908467f87501c55ef833e5ac2 (patch) | |
tree | 36254193a9dea0b3ef0cb6d4811347775ba32f13 | |
parent | 0a6292937e57dcf42c10c28aa52fb1a6efa79324 (diff) |
support subject alternative names
-rw-r--r-- | src/cert.rs | 9 | ||||
-rw-r--r-- | src/cli.rs | 4 | ||||
-rw-r--r-- | src/main.rs | 28 | ||||
-rw-r--r-- | src/req.rs | 25 |
4 files changed, 50 insertions, 16 deletions
diff --git a/src/cert.rs b/src/cert.rs index 3492617..14ac9fd 100644 --- a/src/cert.rs +++ b/src/cert.rs @@ -8,7 +8,6 @@ use openssl::x509::*; use crate::path; use std::fs::{read, write}; -#[allow(clippy::too_many_arguments)] pub fn generate_cert( lifetime_days: u32, signing_request: &X509Req, @@ -76,6 +75,14 @@ pub fn generate_cert( .append_extension(authority_key_identifier) .unwrap(); + // TODO: It'd be cool if this ignored anything but SANs + // but I'm not sure if that's possible + if !signing_request.extensions().unwrap().is_empty() { + for extension in signing_request.extensions().unwrap() { + x509_builder.append_extension(extension).unwrap(); + } + } + let digest_algorithm = match signing_request.public_key().unwrap().id() { Id::RSA => MessageDigest::sha256(), Id::EC => MessageDigest::sha384(), @@ -104,6 +104,10 @@ pub struct Issue { #[clap(long, short = 'u')] pub organizational_unit: Option<String>, + /// Subject Alternative Names + #[clap(long)] + pub subject_alt_names: Option<String>, + /// Password for private key #[clap(long, short = 'p', env = "CA_PASSWORD")] pub password: Option<String>, diff --git a/src/main.rs b/src/main.rs index 6b6bd75..4f63a00 100644 --- a/src/main.rs +++ b/src/main.rs @@ -86,21 +86,19 @@ fn issue(args: Issue) { }; let x509_req_path = path::cert_csr(&base_dir, &args.common_name, key_type); - let x509_req = match Path::new(&x509_req_path).exists() { - true => req::read_req(&x509_req_path), - false => { - let req = req::generate_req( - &Some(args.common_name.clone()), - &args.country, - &args.state, - &args.locality, - &args.organization, - &args.organizational_unit, - &pkey, - ); - req::save_req(&x509_req_path, &req); - req - } + let x509_req = { + let req = req::generate_req( + &Some(args.common_name.clone()), + &args.country, + &args.state, + &args.locality, + &args.organization, + &args.organizational_unit, + &args.subject_alt_names, + &pkey, + ); + req::save_req(&x509_req_path, &req); + req }; let cert = cert::generate_cert(args.lifetime, &x509_req, &ca_cert, &ca_pkey); @@ -1,12 +1,17 @@ use openssl::hash::MessageDigest; use openssl::nid::Nid; use openssl::pkey::{Id, PKey, Private}; +use openssl::stack::Stack; +use openssl::x509::extension::SubjectAlternativeName; use openssl::x509::{X509Name, X509Req}; use std::fs::{read, write}; +use std::net::IpAddr; +use std::str::FromStr; use crate::path; +#[allow(clippy::too_many_arguments)] pub fn generate_req( common_name: &Option<String>, country: &Option<String>, @@ -14,6 +19,7 @@ pub fn generate_req( locality: &Option<String>, organization: &Option<String>, organizational_unit: &Option<String>, + subject_alternative_names: &Option<String>, pkey: &PKey<Private>, ) -> X509Req { let mut x509req_builder = X509Req::builder().unwrap(); @@ -55,6 +61,25 @@ pub fn generate_req( let x509_name = x509_name_builder.build(); x509req_builder.set_subject_name(&x509_name).unwrap(); + let mut subject_alt_name = SubjectAlternativeName::new(); + + if let Some(san) = subject_alternative_names { + let alt_names = san.split(','); + for name in alt_names { + if IpAddr::from_str(name).is_ok() { + subject_alt_name.ip(name); + } else { + subject_alt_name.dns(name); + } + } + } + let subject_alt_name = subject_alt_name + .build(&x509req_builder.x509v3_context(None)) + .unwrap(); + let mut stack = Stack::new().unwrap(); + stack.push(subject_alt_name).unwrap(); + x509req_builder.add_extensions(&stack).unwrap(); + let digest_algorithm = match pkey.id() { Id::RSA => MessageDigest::sha256(), Id::EC => MessageDigest::sha384(), |