summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGalen Guyer <galen@galenguyer.com>2022-03-28 21:59:22 -0400
committerGalen Guyer <galen@galenguyer.com>2022-03-28 21:59:22 -0400
commit777b2e22cf25586908467f87501c55ef833e5ac2 (patch)
tree36254193a9dea0b3ef0cb6d4811347775ba32f13
parent0a6292937e57dcf42c10c28aa52fb1a6efa79324 (diff)
support subject alternative names
-rw-r--r--src/cert.rs9
-rw-r--r--src/cli.rs4
-rw-r--r--src/main.rs28
-rw-r--r--src/req.rs25
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(),
diff --git a/src/cli.rs b/src/cli.rs
index 573b2f5..69a39b8 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -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);
diff --git a/src/req.rs b/src/req.rs
index d903b37..2b5974f 100644
--- a/src/req.rs
+++ b/src/req.rs
@@ -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(),