Update
This commit is contained in:
		
							
								
								
									
										3
									
								
								central_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3
									
								
								central_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -106,9 +106,12 @@ dependencies = [
 | 
				
			|||||||
 "asn1",
 | 
					 "asn1",
 | 
				
			||||||
 "clap",
 | 
					 "clap",
 | 
				
			||||||
 "env_logger",
 | 
					 "env_logger",
 | 
				
			||||||
 | 
					 "foreign-types-shared",
 | 
				
			||||||
 "lazy_static",
 | 
					 "lazy_static",
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 "log",
 | 
					 "log",
 | 
				
			||||||
 "openssl",
 | 
					 "openssl",
 | 
				
			||||||
 | 
					 "openssl-sys",
 | 
				
			||||||
 "thiserror",
 | 
					 "thiserror",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,4 +11,7 @@ clap = { version = "4.5.7", features = ["derive", "env"] }
 | 
				
			|||||||
anyhow = "1.0.86"
 | 
					anyhow = "1.0.86"
 | 
				
			||||||
thiserror = "1.0.61"
 | 
					thiserror = "1.0.61"
 | 
				
			||||||
openssl = { version = "0.10.64" }
 | 
					openssl = { version = "0.10.64" }
 | 
				
			||||||
 | 
					openssl-sys = "0.9.102"
 | 
				
			||||||
 | 
					libc = "0.2.155"
 | 
				
			||||||
 | 
					foreign-types-shared = "0.1.1"
 | 
				
			||||||
asn1 = "0.16"
 | 
					asn1 = "0.16"
 | 
				
			||||||
@@ -1,2 +1,3 @@
 | 
				
			|||||||
pub mod crl_extension;
 | 
					pub mod crl_extension;
 | 
				
			||||||
 | 
					pub mod openssl_utils;
 | 
				
			||||||
pub mod pki;
 | 
					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 std::cmp::Ordering;
 | 
				
			||||||
use crate::crypto::crl_extension::CRLDistributionPointExt;
 | 
					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::asn1::Asn1Time;
 | 
				
			||||||
use openssl::bn::{BigNum, MsbOption};
 | 
					use openssl::bn::{BigNum, MsbOption};
 | 
				
			||||||
use openssl::ec::EcGroup;
 | 
					use openssl::ec::EcGroup;
 | 
				
			||||||
@@ -7,8 +11,22 @@ use openssl::hash::MessageDigest;
 | 
				
			|||||||
use openssl::nid::Nid;
 | 
					use openssl::nid::Nid;
 | 
				
			||||||
use openssl::pkey::{PKey, Private};
 | 
					use openssl::pkey::{PKey, Private};
 | 
				
			||||||
use openssl::x509::extension::{BasicConstraints, KeyUsage, SubjectKeyIdentifier};
 | 
					use openssl::x509::extension::{BasicConstraints, KeyUsage, SubjectKeyIdentifier};
 | 
				
			||||||
use openssl::x509::{X509NameBuilder, X509};
 | 
					use openssl::x509::{ReasonCode, X509Crl, X509NameBuilder, X509};
 | 
				
			||||||
use std::path::{Path, PathBuf};
 | 
					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
 | 
					/// Certificate and private key
 | 
				
			||||||
struct CertData {
 | 
					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)?)?)
 | 
					    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)]
 | 
					#[derive(Default)]
 | 
				
			||||||
struct GenCertificateReq<'a> {
 | 
					struct GenCertificateReq<'a> {
 | 
				
			||||||
    cn: &'a str,
 | 
					    cn: &'a str,
 | 
				
			||||||
@@ -202,3 +225,72 @@ pub fn initialize_devices_ca() -> anyhow::Result<()> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    Ok(())
 | 
					    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;
 | 
					use central_backend::utils::files_utils::create_directory_if_missing;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() {
 | 
					fn main() {
 | 
				
			||||||
 | 
					    // Initialize OpenSSL
 | 
				
			||||||
 | 
					    openssl_sys::init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
 | 
					    env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Initialize storage
 | 
					    // Initialize storage
 | 
				
			||||||
@@ -12,4 +15,6 @@ fn main() {
 | 
				
			|||||||
    pki::initialize_root_ca().expect("Failed to initialize Root CA!");
 | 
					    pki::initialize_root_ca().expect("Failed to initialize Root CA!");
 | 
				
			||||||
    pki::initialize_web_ca().expect("Failed to initialize web CA!");
 | 
					    pki::initialize_web_ca().expect("Failed to initialize web CA!");
 | 
				
			||||||
    pki::initialize_devices_ca().expect("Failed to initialize devices 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