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",
|
"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!");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user