Add support for CRL on server side
This commit is contained in:
@ -16,4 +16,6 @@ serde = { version = "1.0.144", features = ["derive"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
futures = "0.3.24"
|
||||
rustls = "0.20.6"
|
||||
webpki = "0.22.0"
|
||||
webpki = "0.22.0"
|
||||
x509-parser = "0.14.0"
|
||||
pem = "1.1.0"
|
@ -48,6 +48,10 @@ pub struct ServerConfig {
|
||||
/// This option automatically enable TLS client authentication
|
||||
#[clap(long)]
|
||||
pub tls_client_auth_root_cert: Option<String>,
|
||||
|
||||
/// TLS client authentication revocation list (CRL file)
|
||||
#[clap(long)]
|
||||
pub tls_revocation_list: Option<String>,
|
||||
}
|
||||
|
||||
impl ServerConfig {
|
||||
|
@ -1,8 +1,10 @@
|
||||
use std::sync::Arc;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use rustls::internal::msgs::enums::AlertDescription;
|
||||
use rustls::server::{AllowAnyAuthenticatedClient, ClientCertVerified, ClientCertVerifier};
|
||||
use rustls::{Certificate, DistinguishedNames, Error, RootCertStore};
|
||||
use x509_parser::prelude::{CertificateRevocationList, FromDer, X509Certificate};
|
||||
|
||||
use base::cert_utils::parse_pem_certificates;
|
||||
|
||||
@ -10,10 +12,12 @@ use crate::server_config::ServerConfig;
|
||||
|
||||
pub struct CustomCertClientVerifier {
|
||||
upstream_cert_verifier: Box<Arc<dyn ClientCertVerifier>>,
|
||||
crl: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl CustomCertClientVerifier {
|
||||
pub fn new(conf: Arc<ServerConfig>) -> Self {
|
||||
// Build root certifications list
|
||||
let cert_path = conf
|
||||
.tls_client_auth_root_cert
|
||||
.as_deref()
|
||||
@ -36,8 +40,20 @@ impl CustomCertClientVerifier {
|
||||
.expect("Failed to add certificate to root store");
|
||||
}
|
||||
|
||||
// Parse CRL file (if any)
|
||||
let crl = if let Some(crl_file) = &conf.tls_revocation_list {
|
||||
let crl_file = std::fs::read(crl_file).expect("Failed to open / read CRL file!");
|
||||
|
||||
let parsed_crl = pem::parse(crl_file).expect("Failed to decode CRL file!");
|
||||
|
||||
Some(parsed_crl.contents)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Self {
|
||||
upstream_cert_verifier: Box::new(AllowAnyAuthenticatedClient::new(store)),
|
||||
crl,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -61,6 +77,26 @@ impl ClientCertVerifier for CustomCertClientVerifier {
|
||||
intermediates: &[Certificate],
|
||||
now: SystemTime,
|
||||
) -> Result<ClientCertVerified, Error> {
|
||||
// Check the certificates sent by the client has been revoked
|
||||
if let Some(crl) = &self.crl {
|
||||
let (_rem, crl) =
|
||||
CertificateRevocationList::from_der(crl).expect("Failed to read CRL!");
|
||||
|
||||
let (_rem, cert) =
|
||||
X509Certificate::from_der(&end_entity.0).expect("Failed to read certificate!");
|
||||
|
||||
for revoked in crl.iter_revoked_certificates() {
|
||||
if revoked.user_certificate == cert.serial {
|
||||
log::error!(
|
||||
"Client attempted to use a revoked certificate! Serial={:?} Subject={}",
|
||||
cert.serial,
|
||||
cert.subject
|
||||
);
|
||||
return Err(Error::AlertReceived(AlertDescription::CertificateRevoked));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.upstream_cert_verifier
|
||||
.verify_client_cert(end_entity, intermediates, now)
|
||||
}
|
||||
|
Reference in New Issue
Block a user