Can revoke issued certificates

This commit is contained in:
2024-07-17 18:31:57 +02:00
parent 751e33cb72
commit 717ad5b5e0
3 changed files with 87 additions and 11 deletions

View File

@ -13,10 +13,11 @@ use openssl::pkey::{PKey, Private};
use openssl::x509::extension::{
BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName, SubjectKeyIdentifier,
};
use openssl::x509::{X509Crl, X509Name, X509NameBuilder, X509Req, X509};
use openssl::x509::{CrlStatus, X509Crl, X509Name, X509NameBuilder, X509Req, X509};
use openssl_sys::{
X509_CRL_add0_revoked, X509_CRL_set1_lastUpdate, X509_CRL_set1_nextUpdate,
X509_CRL_add0_revoked, X509_CRL_new, X509_CRL_set1_lastUpdate, X509_CRL_set1_nextUpdate,
X509_CRL_set_issuer_name, X509_CRL_set_version, X509_CRL_sign, X509_REVOKED_dup,
X509_REVOKED_new, X509_REVOKED_set_revocationDate, X509_REVOKED_set_serialNumber,
};
use crate::app_config::AppConfig;
@ -365,7 +366,7 @@ pub fn initialize_server_ca() -> anyhow::Result<()> {
}
/// Initialize or refresh a CRL
fn refresh_crl(d: &CertData) -> anyhow::Result<()> {
fn refresh_crl(d: &CertData, new_cert: Option<&X509>) -> anyhow::Result<()> {
let crl_path = d.crl.as_ref().ok_or(PKIError::MissingCRL)?;
let old_crl = if crl_path.exists() {
@ -373,7 +374,9 @@ fn refresh_crl(d: &CertData) -> anyhow::Result<()> {
// 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 {
if next_update.compare(Asn1Time::days_from_now(0)?.as_ref())? == Ordering::Greater
&& new_cert.is_none()
{
return Ok(());
}
@ -386,7 +389,7 @@ fn refresh_crl(d: &CertData) -> anyhow::Result<()> {
// based on https://github.com/openssl/openssl/blob/master/crypto/x509/x509_vfy.c
unsafe {
let crl = openssl_sys::X509_CRL_new();
let crl = X509_CRL_new();
if crl.is_null() {
return Err(PKIError::GenCRLError("Could not construct CRL!").into());
}
@ -420,6 +423,31 @@ fn refresh_crl(d: &CertData) -> anyhow::Result<()> {
}
}
// If requested, add new entry
if let Some(new_cert) = new_cert {
let entry = X509_REVOKED_new();
if entry.is_null() {
return Err(PKIError::GenCRLError("X509_CRL_new for new entry").into());
}
if X509_REVOKED_set_serialNumber(entry, new_cert.serial_number().as_ptr()) == 0 {
return Err(
PKIError::GenCRLError("X509_REVOKED_set_serialNumber for new entry").into(),
);
}
let revocation_date = Asn1Time::days_from_now(0)?;
if X509_REVOKED_set_revocationDate(entry, revocation_date.as_ptr()) == 0 {
return Err(
PKIError::GenCRLError("X509_REVOKED_set_revocationDate for new entry").into(),
);
}
if X509_CRL_add0_revoked(crl, X509_REVOKED_dup(entry)) == 0 {
return Err(PKIError::GenCRLError("X509_CRL_add0_revoked for new entry").into());
}
}
let md = MessageDigest::sha256();
if X509_CRL_sign(crl, d.key.as_ptr(), md.as_ptr()) == 0 {
return Err(PKIError::GenCRLError("X509_CRL_sign").into());
@ -434,9 +462,9 @@ fn refresh_crl(d: &CertData) -> anyhow::Result<()> {
/// Refresh revocation lists
pub fn refresh_crls() -> anyhow::Result<()> {
refresh_crl(&CertData::load_root_ca()?)?;
refresh_crl(&CertData::load_web_ca()?)?;
refresh_crl(&CertData::load_devices_ca()?)?;
refresh_crl(&CertData::load_root_ca()?, None)?;
refresh_crl(&CertData::load_web_ca()?, None)?;
refresh_crl(&CertData::load_devices_ca()?, None)?;
Ok(())
}
@ -451,3 +479,31 @@ pub fn gen_certificate_for_device(csr: &X509Req) -> anyhow::Result<String> {
Ok(String::from_utf8(cert)?)
}
/// Check if a certificate is revoked
fn is_revoked(cert: &X509, ca: &CertData) -> anyhow::Result<bool> {
let crl = X509Crl::from_pem(&std::fs::read(
ca.crl.as_ref().ok_or(PKIError::MissingCRL)?,
)?)?;
let res = crl.get_by_cert(cert);
Ok(matches!(res, CrlStatus::Revoked(_)))
}
/// Revoke a certificate
pub fn revoke(cert: &X509, ca: &CertData) -> anyhow::Result<()> {
// Check if certificate is already revoked
if is_revoked(cert, ca)? {
// No op
return Ok(());
}
refresh_crl(ca, Some(cert))?;
Ok(())
}
/// Revoke a device certificate
pub fn revoke_device_cert(cert: &X509) -> anyhow::Result<()> {
revoke(cert, &CertData::load_devices_ca()?)
}