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 crate::base::cert_utils::parse_pem_certificates; use crate::tcp_relay_server::server_config::ServerConfig; pub struct CustomCertClientVerifier { upstream_cert_verifier: Box>, crl: Option>, } impl CustomCertClientVerifier { pub fn new(conf: Arc) -> Self { // Build root certifications list let cert_path = conf .tls_client_auth_root_cert .as_deref() .expect("No root certificates for client authentication provided!"); let cert_file = std::fs::read(cert_path) .expect("Failed to read root certificates for client authentication!"); let root_certs = parse_pem_certificates(&cert_file) .expect("Failed to read root certificates for server authentication!"); if root_certs.is_empty() { log::error!("No certificates found for client authentication!"); panic!(); } let mut store = RootCertStore::empty(); for cert in root_certs { store .add(&cert) .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, } } } impl ClientCertVerifier for CustomCertClientVerifier { fn offer_client_auth(&self) -> bool { true } fn client_auth_mandatory(&self) -> Option { Some(true) } fn client_auth_root_subjects(&self) -> Option { Some(vec![]) } fn verify_client_cert( &self, end_entity: &Certificate, intermediates: &[Certificate], now: SystemTime, ) -> Result { // 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) } }