diff --git a/core/src/commands/generate.rs b/core/src/commands/generate.rs index 54fbdc1..4ace90f 100644 --- a/core/src/commands/generate.rs +++ b/core/src/commands/generate.rs @@ -1,3 +1,14 @@ +use std::{ + fs, + path::{Path, PathBuf}, +}; + +use crate::x509::{ + ca_cert::CACert, ca_req::CAReq, distinguished_name::DistinguishedName, leaf_cert::LeafCert, + Certificate, +}; +use openssl::x509::{X509Req, X509}; + pub fn generate( domains: Vec, noca: bool, @@ -11,22 +22,89 @@ pub fn generate( state: Option, output: Option, request: bool, -) { +) -> Result<(), Box> { if request { // ONLY CSR (CA Not Required) - for domain in &domains {} + for domain in &domains { + let distinguished_name: DistinguishedName = DistinguishedName { + common_name: commonname.clone(), + organization: organization.clone(), + country: country.clone(), + state: state.clone(), + }; + let ca_req_certificate: X509Req = + CAReq::new(distinguished_name)?.generate_certificate()?; + if let Some(output) = &output { + let output_path: &Path = Path::new(output); + if !output_path.exists() { + fs::create_dir_all(output_path)?; + } + let output_path: PathBuf = if output_path.is_absolute() { + output_path.to_path_buf() + } else { + std::env::current_dir()?.join(output_path) + }; + let file_name: PathBuf = output_path.join(format!("{}.pem", domain)); + let file_name_str: Option<&str> = file_name.to_str(); + if let Some(file_name_str) = file_name_str { + CAReq::save_certificate_to_file(&ca_req_certificate, file_name_str)?; + } else { + eprintln!("Error: Error creating file for domain : {}", domain); + } + } else { + let output_path: PathBuf = std::env::current_dir()?; + let file_name: PathBuf = output_path.join(format!("{}.pem", domain)); + let file_name_str: Option<&str> = file_name.to_str(); + if let Some(file_name_str) = file_name_str { + CAReq::save_certificate_to_file(&ca_req_certificate, file_name_str)?; + } else { + eprintln!("Error: Error creating file for domain : {}", domain); + } + } + } + return Ok(()); } - if certfile.is_some() { - // check file data - // Correct - if csr.is_some() { - // Generate for this CSR + if let Some(certfile) = certfile { + if let Some(keyfile) = keyfile { + // No need to check for files as load_ca_cert handles and throws X509 Error + let (cert, pkey) = CACert::load_ca_cert(&certfile, &keyfile)?; + if let Some(csr) = &csr { + let distinguished_name: DistinguishedName = DistinguishedName { + common_name: commonname.clone(), + organization: organization.clone(), + country: country.clone(), + state: state.clone(), + }; + let csr_object: X509Req = CAReq::read_csr_from_file(csr)?; + let leaf_cert_object: LeafCert = LeafCert::new(distinguished_name)?; + let leaf_certificate: X509 = LeafCert::generate_certificate( + leaf_cert_object, + &cert, + &pkey, + Some(&csr_object), + )?; + // Save File + } else { + for domain in &domains { + let distinguished_name: DistinguishedName = DistinguishedName { + // replace to domain_name + common_name: commonname.clone(), + organization: organization.clone(), + country: country.clone(), + state: state.clone(), + }; + let leaf_cert_object: LeafCert = LeafCert::new(distinguished_name)?; + let leaf_certificate: X509 = + LeafCert::generate_certificate(leaf_cert_object, &cert, &pkey, None)?; + // Save file + } + } + return Ok(()); + } else { + eprintln!("Corresponding KeyFile Not Found"); + std::process::exit(1); } - for domain in &domains {} - - // NOT Correct - // Error - Files not correct } // Check for CA files in default path @@ -46,4 +124,6 @@ pub fn generate( // Use Found CA and CSR to Generate } for domain in domains {} + + Ok(()) } diff --git a/core/src/main.rs b/core/src/main.rs index b6724ae..aa38025 100644 --- a/core/src/main.rs +++ b/core/src/main.rs @@ -99,8 +99,8 @@ fn main() { ); std::process::exit(1); } - - generate( + + let _ = generate( domains, noca, debug, @@ -113,7 +113,7 @@ fn main() { state, output, request, - ) + ); } } } diff --git a/core/src/utils.rs b/core/src/utils.rs index 9ab6531..8dde2b3 100644 --- a/core/src/utils.rs +++ b/core/src/utils.rs @@ -1,11 +1,18 @@ -use crate::errors::{CertKeyPairError, CertKeyResult, SerialNumberError, SerialNumberResult}; +use crate::{ + errors::{CertKeyPairError, CertKeyResult, SerialNumberError, SerialNumberResult}, + x509::{self, ca_cert::CACert}, +}; use openssl::{ asn1::Asn1Integer, bn::BigNum, error::ErrorStack, pkey::{PKey, Private}, rsa::Rsa, + x509::X509, }; +use std::error::Error; +use std::fs; +use std::path::PathBuf; pub fn generate_cert_key_pair() -> CertKeyResult<(Rsa, PKey)> { let rsa: Rsa = @@ -16,12 +23,33 @@ pub fn generate_cert_key_pair() -> CertKeyResult<(Rsa, PKey)> } pub fn generate_certificate_serial_number() -> SerialNumberResult { - let mut serial_number: BigNum = - BigNum::new().map_err(|err: ErrorStack| SerialNumberError::BigNumberInitializationError(err))?; + let mut serial_number: BigNum = BigNum::new() + .map_err(|err: ErrorStack| SerialNumberError::BigNumberInitializationError(err))?; serial_number .rand(128, openssl::bn::MsbOption::MAYBE_ZERO, false) .map_err(|err: ErrorStack| SerialNumberError::RandomBigNumberGenerationError(err))?; Ok(serial_number .to_asn1_integer() .map_err(|err: ErrorStack| SerialNumberError::ConvertBigNumberToASN1Error(err))?) -} \ No newline at end of file +} + +pub fn get_certificates_from_data_dir() -> Result<(X509, PKey), Box> { + if let Some(ref data_dir) = *x509::DATA_DIR { + if !data_dir.exists() { + fs::create_dir_all(data_dir)?; + } + let ca_certfile: PathBuf = data_dir.join("ca_cert.pem"); + let ca_keyfile: PathBuf = data_dir.join("ca_key.pem"); + let ca_cert_file_str: &str = ca_certfile + .to_str() + .ok_or("Failed to convert ca_certfile path to string")?; + let ca_key_file_str: &str = ca_keyfile + .to_str() + .ok_or("Failed to convert ca_keyfile path to string")?; + let (cert, pkey) = CACert::load_ca_cert(ca_cert_file_str, ca_key_file_str)?; + Ok((cert, pkey)) + } else { + eprintln!("Unable to get Data Directory"); + std::process::exit(1); + } +} diff --git a/core/src/x509/distinguished_name.rs b/core/src/x509/distinguished_name.rs index ee5a3ef..6e7aba1 100644 --- a/core/src/x509/distinguished_name.rs +++ b/core/src/x509/distinguished_name.rs @@ -6,11 +6,10 @@ use openssl::{ #[derive(Debug)] pub struct DistinguishedName { - common_name: Option, - organization: Option, - country: Option, - state: Option, - city: Option, + pub common_name: Option, + pub organization: Option, + pub country: Option, + pub state: Option, } impl DistinguishedName { @@ -45,13 +44,6 @@ impl DistinguishedName { X509Error::X509NameBuilderEntryError(err, "ST".to_string(), state) })?; } - if let Some(city) = self.city { - x509_name - .append_entry_by_text("L", &city) - .map_err(|err: ErrorStack| { - X509Error::X509NameBuilderEntryError(err, "L".to_string(), city) - })?; - } let x509_name: X509Name = x509_name.build(); Ok(x509_name) } diff --git a/core/src/x509/leaf_cert.rs b/core/src/x509/leaf_cert.rs index 65e0059..6f968f5 100644 --- a/core/src/x509/leaf_cert.rs +++ b/core/src/x509/leaf_cert.rs @@ -51,7 +51,7 @@ impl LeafCert { } } - fn generate_certificate( + pub fn generate_certificate( self, cert_file: &X509, key_file: &PKey, diff --git a/core/src/x509/mod.rs b/core/src/x509/mod.rs index f4a7a55..90f9829 100644 --- a/core/src/x509/mod.rs +++ b/core/src/x509/mod.rs @@ -4,12 +4,12 @@ use lazy_static::lazy_static; use std::path::PathBuf; pub mod ca_cert; pub mod ca_req; -mod distinguished_name; +pub mod distinguished_name; mod errors; pub mod leaf_cert; lazy_static! { - static ref DATA_DIR: Option = dirs::data_dir().map(|path| path.join("vanish")); + pub static ref DATA_DIR: Option = dirs::data_dir().map(|path| path.join("vanish")); } #[derive(Debug)]