summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGalen Guyer <galen@galenguyer.com>2022-06-20 21:25:07 -0400
committerGalen Guyer <galen@galenguyer.com>2022-06-20 21:25:07 -0400
commit5df81c937fbf71d7d81aa19a0c3820aa3d2f436e (patch)
treeedcf692d599d67ccc235ba4934dd2aefecad0a05
parent83924a3d3699186169c8c67b9f7ac5cc53978de9 (diff)
reorganize project file structure
-rw-r--r--Cargo.toml8
-rw-r--r--src/cli.rs116
-rw-r--r--src/lib/cert.rs (renamed from src/cert.rs)0
-rw-r--r--src/lib/mod.rs (renamed from src/lib.rs)1
-rw-r--r--src/lib/ops.rs209
-rw-r--r--src/lib/path.rs (renamed from src/path.rs)6
-rw-r--r--src/lib/pkey.rs (renamed from src/pkey.rs)0
-rw-r--r--src/lib/req.rs (renamed from src/req.rs)0
-rw-r--r--src/lib/root.rs (renamed from src/root.rs)0
-rw-r--r--src/main.rs109
10 files changed, 230 insertions, 219 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 03da59b..ff041c4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,6 +3,14 @@ name = "hancock"
version = "1.0.0"
edition = "2021"
+
+[lib]
+path = "src/lib/mod.rs"
+
+[[bin]]
+name = "hancock"
+path = "src/cli.rs"
+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
diff --git a/src/cli.rs b/src/cli.rs
index 69a39b8..0e4e064 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -1,4 +1,6 @@
-use clap::{Args, Parser, Subcommand};
+use clap::{Parser, Subcommand};
+
+use hancock::ops::*;
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
@@ -14,113 +16,11 @@ pub enum Commands {
Issue(Issue),
}
-#[derive(Args, Debug)]
-#[clap(about = "Generate a new root certificate")]
-pub struct Init {
- /// Base directory to store certificates
- #[clap(long, default_value = "~/.hancock", env = "CA_BASE_DIR")]
- pub base_dir: String,
-
- /// Algorithm to generate private keys ('RSA' or 'ECDSA')
- #[clap(long, short = 't', default_value = "RSA", validator = validate_key_type)]
- pub key_type: String,
-
- /// Length to use when generating an RSA key. Ignored for ECDSA
- #[clap(long, short = 'b', default_value_t = 4096)]
- pub key_length: u32,
-
- /// Lifetime in days of the generated certificate
- #[clap(long, short = 'd', default_value_t = 365 * 10)]
- pub lifetime: u32,
-
- /// Certificate CommonName
- #[clap(long, short = 'n')]
- pub common_name: Option<String>,
-
- /// Certificate Country
- #[clap(long, short = 'c')]
- pub country: Option<String>,
-
- /// Certificate State or Province
- #[clap(long, short = 's')]
- pub state: Option<String>,
-
- /// Certificate Locality
- #[clap(long, short = 'l')]
- pub locality: Option<String>,
-
- /// Certificate Organization
- #[clap(long, short = 'o')]
- pub organization: Option<String>,
-
- /// Certificate Organizational Unit
- #[clap(long, short = 'u')]
- pub organizational_unit: Option<String>,
-
- /// Password for private key
- #[clap(long, short = 'p', env = "CA_PASSWORD")]
- pub password: Option<String>,
-}
-#[derive(Args, Debug)]
-#[clap(about = "Issue a new certificate")]
-pub struct Issue {
- /// Base directory to store certificates
- #[clap(long, default_value = "~/.hancock", env = "CA_BASE_DIR")]
- pub base_dir: String,
-
- /// Algorithm to generate private keys ('RSA' or 'ECDSA')
- #[clap(long, short = 't', default_value = "RSA", validator = validate_key_type)]
- pub key_type: String,
-
- /// Length to use when generating an RSA key. Ignored for ECDSA
- #[clap(long, short = 'b', default_value_t = 2048)]
- pub key_length: u32,
-
- /// Lifetime in days of the generated certificate
- #[clap(long, short = 'd', default_value_t = 90)]
- pub lifetime: u32,
-
- /// Certificate CommonName
- #[clap(long, short = 'n')]
- pub common_name: String,
-
- /// Certificate Country
- #[clap(long, short = 'c')]
- pub country: Option<String>,
-
- /// Certificate State or Province
- #[clap(long, short = 's')]
- pub state: Option<String>,
-
- /// Certificate Locality
- #[clap(long, short = 'l')]
- pub locality: Option<String>,
-
- /// Certificate Organization
- #[clap(long, short = 'o')]
- pub organization: Option<String>,
-
- /// Certificate Organizational Unit
- #[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>,
-}
+fn main() {
+ let cli = dbg!(Cli::parse());
-fn validate_key_type(input: &str) -> Result<(), String> {
- let input = input.to_string().to_uppercase();
- if input == "RSA" || input == "ECDSA" {
- Ok(())
- } else {
- Err(format!(
- "{} is not a valid key type ['rsa', 'ecdsa']",
- input
- ))
+ match cli.command {
+ Commands::Init(args) => init(args),
+ Commands::Issue(args) => issue(args),
}
}
diff --git a/src/cert.rs b/src/lib/cert.rs
index 14ac9fd..14ac9fd 100644
--- a/src/cert.rs
+++ b/src/lib/cert.rs
diff --git a/src/lib.rs b/src/lib/mod.rs
index 745c200..654585a 100644
--- a/src/lib.rs
+++ b/src/lib/mod.rs
@@ -3,6 +3,7 @@ pub mod path;
pub mod pkey;
pub mod req;
pub mod root;
+pub mod ops;
#[derive(Clone, Copy)]
pub enum KeyType {
diff --git a/src/lib/ops.rs b/src/lib/ops.rs
new file mode 100644
index 0000000..8abe832
--- /dev/null
+++ b/src/lib/ops.rs
@@ -0,0 +1,209 @@
+use clap::Args;
+use std::path::Path;
+
+use crate::KeyType;
+use crate::*;
+
+#[derive(Args, Debug)]
+#[clap(about = "Generate a new root certificate")]
+pub struct Init {
+ /// Base directory to store certificates
+ #[clap(long, default_value = "~/.hancock", env = "CA_BASE_DIR")]
+ pub base_dir: String,
+
+ /// Algorithm to generate private keys ('RSA' or 'ECDSA')
+ #[clap(long, short = 't', default_value = "RSA", validator = validate_key_type)]
+ pub key_type: String,
+
+ /// Length to use when generating an RSA key. Ignored for ECDSA
+ #[clap(long, short = 'b', default_value_t = 4096)]
+ pub key_length: u32,
+
+ /// Lifetime in days of the generated certificate
+ #[clap(long, short = 'd', default_value_t = 365 * 10)]
+ pub lifetime: u32,
+
+ /// Certificate CommonName
+ #[clap(long, short = 'n')]
+ pub common_name: Option<String>,
+
+ /// Certificate Country
+ #[clap(long, short = 'c')]
+ pub country: Option<String>,
+
+ /// Certificate State or Province
+ #[clap(long, short = 's')]
+ pub state: Option<String>,
+
+ /// Certificate Locality
+ #[clap(long, short = 'l')]
+ pub locality: Option<String>,
+
+ /// Certificate Organization
+ #[clap(long, short = 'o')]
+ pub organization: Option<String>,
+
+ /// Certificate Organizational Unit
+ #[clap(long, short = 'u')]
+ pub organizational_unit: Option<String>,
+
+ /// Password for private key
+ #[clap(long, short = 'p', env = "CA_PASSWORD")]
+ pub password: Option<String>,
+}
+
+#[derive(Args, Debug)]
+#[clap(about = "Issue a new certificate")]
+pub struct Issue {
+ /// Base directory to store certificates
+ #[clap(long, default_value = "~/.hancock", env = "CA_BASE_DIR")]
+ pub base_dir: String,
+
+ /// Algorithm to generate private keys ('RSA' or 'ECDSA')
+ #[clap(long, short = 't', default_value = "RSA", validator = validate_key_type)]
+ pub key_type: String,
+
+ /// Length to use when generating an RSA key. Ignored for ECDSA
+ #[clap(long, short = 'b', default_value_t = 2048)]
+ pub key_length: u32,
+
+ /// Lifetime in days of the generated certificate
+ #[clap(long, short = 'd', default_value_t = 90)]
+ pub lifetime: u32,
+
+ /// Certificate CommonName
+ #[clap(long, short = 'n')]
+ pub common_name: String,
+
+ /// Certificate Country
+ #[clap(long, short = 'c')]
+ pub country: Option<String>,
+
+ /// Certificate State or Province
+ #[clap(long, short = 's')]
+ pub state: Option<String>,
+
+ /// Certificate Locality
+ #[clap(long, short = 'l')]
+ pub locality: Option<String>,
+
+ /// Certificate Organization
+ #[clap(long, short = 'o')]
+ pub organization: Option<String>,
+
+ /// Certificate Organizational Unit
+ #[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>,
+}
+
+pub fn init(args: Init) {
+ let base_dir = path::base_dir(&args.base_dir);
+
+ let key_type = match args.key_type.to_uppercase().as_str() {
+ "RSA" => KeyType::Rsa(args.key_length),
+ "ECDSA" => KeyType::Ecdsa,
+ _ => panic!("key_type not ECDSA or RSA after validation. This should never happen"),
+ };
+
+ let pkey_path = path::ca_pkey(&base_dir, key_type);
+
+ let pkey = match Path::new(&pkey_path).exists() {
+ true => pkey::read_pkey(&pkey_path, args.password),
+ false => {
+ let pkey = pkey::generate_pkey(key_type);
+ pkey::save_pkey(&pkey_path, &pkey, args.password);
+ pkey
+ }
+ };
+
+ let cert_path = path::ca_crt(&base_dir, key_type);
+ if !Path::new(&cert_path).exists() {
+ let cert = root::generate_root_cert(
+ args.lifetime,
+ &args.common_name,
+ &args.country,
+ &args.state,
+ &args.locality,
+ &args.organization,
+ &args.organizational_unit,
+ &pkey,
+ );
+ cert::save_cert(&cert_path, &cert);
+ }
+}
+
+pub fn issue(args: Issue) {
+ let base_dir = path::base_dir(&args.base_dir);
+
+ let key_type = match args.key_type.to_uppercase().as_str() {
+ "RSA" => KeyType::Rsa(args.key_length),
+ "ECDSA" => KeyType::Ecdsa,
+ _ => panic!("key_type not ECDSA or RSA after validation. This should never happen"),
+ };
+
+ let ca_pkey_path = path::ca_pkey(&base_dir, key_type);
+
+ let ca_pkey = match Path::new(&ca_pkey_path).exists() {
+ true => pkey::read_pkey(&ca_pkey_path, args.password),
+ false => {
+ let pkey = pkey::generate_pkey(key_type);
+ pkey::save_pkey(&ca_pkey_path, &pkey, args.password);
+ pkey
+ }
+ };
+
+ let ca_cert_path = path::ca_crt(&base_dir, key_type);
+ let ca_cert = cert::read_cert(&ca_cert_path);
+
+ let pkey_path = path::cert_pkey(&base_dir, &args.common_name, key_type);
+ let pkey = match Path::new(&pkey_path).exists() {
+ true => pkey::read_pkey(&pkey_path, None),
+ false => {
+ let pkey = pkey::generate_pkey(key_type);
+ pkey::save_pkey(&pkey_path, &pkey, None);
+ pkey
+ }
+ };
+
+ let x509_req_path = path::cert_csr(&base_dir, &args.common_name, key_type);
+ 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);
+ cert::save_cert(
+ &path::cert_crt(&base_dir, &args.common_name, key_type),
+ &cert,
+ );
+}
+
+fn validate_key_type(input: &str) -> Result<(), String> {
+ let input = input.to_string().to_uppercase();
+ if input == "RSA" || input == "ECDSA" {
+ Ok(())
+ } else {
+ Err(format!(
+ "{} is not a valid key type ['rsa', 'ecdsa']",
+ input
+ ))
+ }
+}
diff --git a/src/path.rs b/src/lib/path.rs
index a65a8ad..d77fd59 100644
--- a/src/path.rs
+++ b/src/lib/path.rs
@@ -41,7 +41,8 @@ pub fn cert_csr(base_dir: &str, name: &str, key_type: KeyType) -> String {
_ => {
format!("{base_dir}/{name}/{name}.{}.csr", key_type.to_string())
}
- }}
+ }
+}
pub fn cert_crt(base_dir: &str, name: &str, key_type: KeyType) -> String {
match key_type {
KeyType::Rsa(_) => {
@@ -50,7 +51,8 @@ pub fn cert_crt(base_dir: &str, name: &str, key_type: KeyType) -> String {
_ => {
format!("{base_dir}/{name}/{name}.{}.crt", key_type.to_string())
}
- }}
+ }
+}
pub fn base_dir(raw_base: &str) -> String {
Path::new(&shellexpand::tilde(&raw_base).to_string())
diff --git a/src/pkey.rs b/src/lib/pkey.rs
index 41bb3e9..41bb3e9 100644
--- a/src/pkey.rs
+++ b/src/lib/pkey.rs
diff --git a/src/req.rs b/src/lib/req.rs
index 2b5974f..2b5974f 100644
--- a/src/req.rs
+++ b/src/lib/req.rs
diff --git a/src/root.rs b/src/lib/root.rs
index 9b8393c..9b8393c 100644
--- a/src/root.rs
+++ b/src/lib/root.rs
diff --git a/src/main.rs b/src/main.rs
deleted file mode 100644
index 4f63a00..0000000
--- a/src/main.rs
+++ /dev/null
@@ -1,109 +0,0 @@
-use clap::Parser;
-
-use hancock::*;
-
-use std::path::Path;
-
-mod cli;
-use crate::cli::*;
-
-fn main() {
- let cli = dbg!(Cli::parse());
-
- match cli.command {
- Commands::Init(args) => init(args),
- Commands::Issue(args) => issue(args),
- }
-}
-
-fn init(args: Init) {
- let base_dir = path::base_dir(&args.base_dir);
-
- let key_type = match args.key_type.to_uppercase().as_str() {
- "RSA" => KeyType::Rsa(args.key_length),
- "ECDSA" => KeyType::Ecdsa,
- _ => panic!("key_type not ECDSA or RSA after validation. This should never happen"),
- };
-
- let pkey_path = path::ca_pkey(&base_dir, key_type);
-
- let pkey = match Path::new(&pkey_path).exists() {
- true => pkey::read_pkey(&pkey_path, args.password),
- false => {
- let pkey = pkey::generate_pkey(key_type);
- pkey::save_pkey(&pkey_path, &pkey, args.password);
- pkey
- }
- };
-
- let cert_path = path::ca_crt(&base_dir, key_type);
- if !Path::new(&cert_path).exists() {
- let cert = root::generate_root_cert(
- args.lifetime,
- &args.common_name,
- &args.country,
- &args.state,
- &args.locality,
- &args.organization,
- &args.organizational_unit,
- &pkey,
- );
- cert::save_cert(&cert_path, &cert);
- }
-}
-
-fn issue(args: Issue) {
- let base_dir = path::base_dir(&args.base_dir);
-
- let key_type = match args.key_type.to_uppercase().as_str() {
- "RSA" => KeyType::Rsa(args.key_length),
- "ECDSA" => KeyType::Ecdsa,
- _ => panic!("key_type not ECDSA or RSA after validation. This should never happen"),
- };
-
- let ca_pkey_path = path::ca_pkey(&base_dir, key_type);
-
- let ca_pkey = match Path::new(&ca_pkey_path).exists() {
- true => pkey::read_pkey(&ca_pkey_path, args.password),
- false => {
- let pkey = pkey::generate_pkey(key_type);
- pkey::save_pkey(&ca_pkey_path, &pkey, args.password);
- pkey
- }
- };
-
- let ca_cert_path = path::ca_crt(&base_dir, key_type);
- let ca_cert = cert::read_cert(&ca_cert_path);
-
- let pkey_path = path::cert_pkey(&base_dir, &args.common_name, key_type);
- let pkey = match Path::new(&pkey_path).exists() {
- true => pkey::read_pkey(&pkey_path, None),
- false => {
- let pkey = pkey::generate_pkey(key_type);
- pkey::save_pkey(&pkey_path, &pkey, None);
- pkey
- }
- };
-
- let x509_req_path = path::cert_csr(&base_dir, &args.common_name, key_type);
- 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);
- cert::save_cert(
- &path::cert_crt(&base_dir, &args.common_name, key_type),
- &cert,
- );
-}