Update
This commit is contained in:
		
							
								
								
									
										3
									
								
								central_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3
									
								
								central_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -106,9 +106,12 @@ dependencies = [ | ||||
|  "asn1", | ||||
|  "clap", | ||||
|  "env_logger", | ||||
|  "foreign-types-shared", | ||||
|  "lazy_static", | ||||
|  "libc", | ||||
|  "log", | ||||
|  "openssl", | ||||
|  "openssl-sys", | ||||
|  "thiserror", | ||||
| ] | ||||
|  | ||||
|   | ||||
| @@ -11,4 +11,7 @@ clap = { version = "4.5.7", features = ["derive", "env"] } | ||||
| anyhow = "1.0.86" | ||||
| thiserror = "1.0.61" | ||||
| openssl = { version = "0.10.64" } | ||||
| openssl-sys = "0.9.102" | ||||
| libc = "0.2.155" | ||||
| foreign-types-shared = "0.1.1" | ||||
| asn1 = "0.16" | ||||
| @@ -1,2 +1,3 @@ | ||||
| pub mod crl_extension; | ||||
| pub mod openssl_utils; | ||||
| pub mod pki; | ||||
|   | ||||
							
								
								
									
										24
									
								
								central_backend/src/crypto/openssl_utils.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								central_backend/src/crypto/openssl_utils.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| use openssl::asn1::{Asn1Time, Asn1TimeRef}; | ||||
|  | ||||
| /// Clone Asn1 time | ||||
| pub fn clone_asn1_time(time: &Asn1TimeRef) -> anyhow::Result<Asn1Time> { | ||||
|     let diff = time.diff(Asn1Time::from_unix(0)?.as_ref())?; | ||||
|     let days = diff.days.abs(); | ||||
|     let secs = diff.secs.abs(); | ||||
|  | ||||
|     Ok(Asn1Time::from_unix((days * 3600 * 24 + secs) as i64)?) | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod test { | ||||
|     use crate::crypto::openssl_utils::clone_asn1_time; | ||||
|     use openssl::asn1::Asn1Time; | ||||
|     use std::cmp::Ordering; | ||||
|  | ||||
|     #[test] | ||||
|     fn test_clone_asn1_time() { | ||||
|         let a = Asn1Time::from_unix(10).unwrap(); | ||||
|         let b = clone_asn1_time(a.as_ref()).unwrap(); | ||||
|         assert_eq!(a.compare(&b).unwrap(), Ordering::Equal); | ||||
|     } | ||||
| } | ||||
| @@ -1,5 +1,9 @@ | ||||
| use crate::app_config::AppConfig; | ||||
| use crate::crypto::crl_extension::CRLDistributionPointExt; | ||||
| use std::cmp::Ordering; | ||||
| use std::path::{Path, PathBuf}; | ||||
|  | ||||
| use foreign_types_shared::ForeignType; | ||||
| use foreign_types_shared::ForeignTypeRef; | ||||
| use libc::c_long; | ||||
| use openssl::asn1::Asn1Time; | ||||
| use openssl::bn::{BigNum, MsbOption}; | ||||
| use openssl::ec::EcGroup; | ||||
| @@ -7,8 +11,22 @@ use openssl::hash::MessageDigest; | ||||
| use openssl::nid::Nid; | ||||
| use openssl::pkey::{PKey, Private}; | ||||
| use openssl::x509::extension::{BasicConstraints, KeyUsage, SubjectKeyIdentifier}; | ||||
| use openssl::x509::{X509NameBuilder, X509}; | ||||
| use std::path::{Path, PathBuf}; | ||||
| use openssl::x509::{ReasonCode, X509Crl, X509NameBuilder, X509}; | ||||
| use openssl_sys::{X509_CRL_free, X509_CRL_set1_lastUpdate, X509_CRL_set1_nextUpdate, X509_CRL_set_issuer_name, X509_CRL_set_version}; | ||||
|  | ||||
| use crate::app_config::AppConfig; | ||||
| use crate::crypto::crl_extension::CRLDistributionPointExt; | ||||
| use crate::crypto::openssl_utils::clone_asn1_time; | ||||
|  | ||||
| #[derive(thiserror::Error, Debug)] | ||||
| pub enum PKIError { | ||||
|     #[error("Certification Authority does not have a CRL")] | ||||
|     MissingCRL, | ||||
|     #[error("Certification Authority does not have a CRL next update time")] | ||||
|     MissingCRLNextUpdate, | ||||
|     #[error("Failed to initialize CRL! {0}")] | ||||
|     GenCRLError(&'static str), | ||||
| } | ||||
|  | ||||
| /// Certificate and private key | ||||
| struct CertData { | ||||
| @@ -48,6 +66,11 @@ fn load_certificate_from_file<P: AsRef<Path>>(path: P) -> anyhow::Result<X509> { | ||||
|     Ok(X509::from_pem(&std::fs::read(path)?)?) | ||||
| } | ||||
|  | ||||
| /// Load CRL from PEM file | ||||
| fn load_crl_from_file<P: AsRef<Path>>(path: P) -> anyhow::Result<X509Crl> { | ||||
|     Ok(X509Crl::from_pem(&std::fs::read(path)?)?) | ||||
| } | ||||
|  | ||||
| #[derive(Default)] | ||||
| struct GenCertificateReq<'a> { | ||||
|     cn: &'a str, | ||||
| @@ -202,3 +225,72 @@ pub fn initialize_devices_ca() -> anyhow::Result<()> { | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| /// Intialize or refresh a CRL | ||||
| fn refresh_crl(d: &CertData) -> anyhow::Result<()> { | ||||
|     let crl_path = d.crl.as_ref().ok_or(PKIError::MissingCRL)?; | ||||
|  | ||||
|     let old_list = if crl_path.exists() { | ||||
|         let crl = load_crl_from_file(crl_path)?; | ||||
|  | ||||
|         // Check if revocation is un-needed | ||||
|         let next_update = crl.next_update().ok_or(PKIError::MissingCRLNextUpdate)?; | ||||
|         if next_update.compare(Asn1Time::days_from_now(0)?.as_ref())? < Ordering::Greater { | ||||
|             return Ok(()); | ||||
|         } | ||||
|  | ||||
|         match crl.get_revoked() { | ||||
|             Some(l) => Some( | ||||
|                 l.iter() | ||||
|                     .map(|r| { | ||||
|                         Ok(( | ||||
|                             r.serial_number().to_owned()?, | ||||
|                             clone_asn1_time(r.revocation_date())?, | ||||
|                             r.extension::<ReasonCode>()?, | ||||
|                         )) | ||||
|                     }) | ||||
|                     .collect::<anyhow::Result<Vec<_>>>()?, | ||||
|             ), | ||||
|             None => None, | ||||
|         } | ||||
|     } else { | ||||
|         None | ||||
|     }; | ||||
|  | ||||
|     log::info!("Generating a new CRL..."); | ||||
|  | ||||
|     // based on https://github.com/openssl/openssl/blob/master/crypto/x509/x509_vfy.c | ||||
|     unsafe { | ||||
|         let crl = openssl_sys::X509_CRL_new(); | ||||
|         if crl.is_null() { | ||||
|             return Err(PKIError::GenCRLError("Could not construct CRL!").into()); | ||||
|         } | ||||
|  | ||||
|         const X509_CRL_VERSION_2: c_long = 1; | ||||
|         if X509_CRL_set_version(crl, X509_CRL_VERSION_2) == 0 { | ||||
|             return Err(PKIError::GenCRLError("X509_CRL_set_version").into()); | ||||
|         } | ||||
|         if X509_CRL_set_issuer_name(crl, d.cert.issuer_name().as_ptr()) == 0 { | ||||
|             return Err(PKIError::GenCRLError("X509_CRL_set_issuer_name").into()); | ||||
|         } | ||||
|  | ||||
|         let last_update = Asn1Time::days_from_now(0)?; | ||||
|         if X509_CRL_set1_lastUpdate(crl, last_update.as_ptr()) == 0 { | ||||
|             return Err(PKIError::GenCRLError("X509_CRL_set1_lastUpdate").into()); | ||||
|         } | ||||
|  | ||||
|         let next_update = Asn1Time::days_from_now(10)?; | ||||
|         if X509_CRL_set1_nextUpdate(crl, next_update.as_ptr()) == 0 { | ||||
|             return Err(PKIError::GenCRLError("X509_CRL_set1_nextUpdate").into()); | ||||
|         } | ||||
|  | ||||
|         X509_CRL_free(crl); | ||||
|     } | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| /// Initialize or refresh Root CA CRL, if needed | ||||
| pub fn initialize_root_ca_crl() -> anyhow::Result<()> { | ||||
|     refresh_crl(&CertData::load_root_ca()?) | ||||
| } | ||||
|   | ||||
| @@ -3,6 +3,9 @@ use central_backend::crypto::pki; | ||||
| use central_backend::utils::files_utils::create_directory_if_missing; | ||||
|  | ||||
| fn main() { | ||||
|     // Initialize OpenSSL | ||||
|     openssl_sys::init(); | ||||
|  | ||||
|     env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); | ||||
|  | ||||
|     // Initialize storage | ||||
| @@ -12,4 +15,6 @@ fn main() { | ||||
|     pki::initialize_root_ca().expect("Failed to initialize Root CA!"); | ||||
|     pki::initialize_web_ca().expect("Failed to initialize web CA!"); | ||||
|     pki::initialize_devices_ca().expect("Failed to initialize devices CA!"); | ||||
|  | ||||
|     pki::initialize_root_ca_crl().expect("Failed to initialize Root CA!"); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user