Update
This commit is contained in:
parent
8bac181552
commit
32d5707055
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!");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user