2022-08-31 10:24:54 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
use std::time::SystemTime;
|
|
|
|
|
2022-08-31 13:37:51 +00:00
|
|
|
use rustls::internal::msgs::enums::AlertDescription;
|
2022-08-31 10:24:54 +00:00
|
|
|
use rustls::server::{AllowAnyAuthenticatedClient, ClientCertVerified, ClientCertVerifier};
|
2022-09-02 13:58:16 +00:00
|
|
|
use rustls::{Certificate, DistinguishedNames, Error, RootCertStore};
|
2022-08-31 13:37:51 +00:00
|
|
|
use x509_parser::prelude::{CertificateRevocationList, FromDer, X509Certificate};
|
2022-08-31 13:00:41 +00:00
|
|
|
|
2022-09-01 08:11:24 +00:00
|
|
|
use crate::base::cert_utils::parse_pem_certificates;
|
2022-09-02 08:57:53 +00:00
|
|
|
use crate::base::err_utils::{encpasulate_error, new_err};
|
2022-09-01 08:11:24 +00:00
|
|
|
use crate::tcp_relay_server::server_config::ServerConfig;
|
2022-08-31 10:24:54 +00:00
|
|
|
|
|
|
|
pub struct CustomCertClientVerifier {
|
|
|
|
upstream_cert_verifier: Box<Arc<dyn ClientCertVerifier>>,
|
2022-08-31 13:37:51 +00:00
|
|
|
crl: Option<Vec<u8>>,
|
2022-08-31 10:24:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl CustomCertClientVerifier {
|
2022-09-02 08:57:53 +00:00
|
|
|
pub fn new(conf: Arc<ServerConfig>) -> std::io::Result<Self> {
|
2022-08-31 13:37:51 +00:00
|
|
|
// Build root certifications list
|
2022-08-31 12:36:07 +00:00
|
|
|
let cert_path = conf
|
|
|
|
.tls_client_auth_root_cert
|
|
|
|
.as_deref()
|
2022-08-31 10:24:54 +00:00
|
|
|
.expect("No root certificates for client authentication provided!");
|
2022-09-02 08:57:53 +00:00
|
|
|
let cert_file = std::fs::read(cert_path).map_err(|e| {
|
|
|
|
encpasulate_error(
|
|
|
|
e,
|
|
|
|
"Failed to read root certificates for client authentication!",
|
|
|
|
)
|
|
|
|
})?;
|
|
|
|
|
|
|
|
let root_certs = parse_pem_certificates(&cert_file).map_err(|e| {
|
|
|
|
encpasulate_error(
|
|
|
|
e,
|
|
|
|
"Failed to read root certificates for server authentication!",
|
|
|
|
)
|
|
|
|
})?;
|
2022-08-31 10:24:54 +00:00
|
|
|
|
|
|
|
if root_certs.is_empty() {
|
2022-09-02 08:57:53 +00:00
|
|
|
return Err(new_err("No certificates found for client authentication!"));
|
2022-08-31 10:24:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut store = RootCertStore::empty();
|
|
|
|
for cert in root_certs {
|
2022-08-31 12:36:07 +00:00
|
|
|
store
|
|
|
|
.add(&cert)
|
|
|
|
.expect("Failed to add certificate to root store");
|
2022-08-31 10:24:54 +00:00
|
|
|
}
|
|
|
|
|
2022-08-31 13:37:51 +00:00
|
|
|
// Parse CRL file (if any)
|
|
|
|
let crl = if let Some(crl_file) = &conf.tls_revocation_list {
|
2022-09-02 08:57:53 +00:00
|
|
|
let crl_file = std::fs::read(crl_file)
|
|
|
|
.map_err(|e| encpasulate_error(e, "Failed to open / read CRL file!"))?;
|
2022-08-31 13:37:51 +00:00
|
|
|
|
2022-09-02 08:57:53 +00:00
|
|
|
let parsed_crl = pem::parse(crl_file)
|
|
|
|
.map_err(|e| encpasulate_error(e, "Failed to decode CRL file!"))?;
|
2022-08-31 13:37:51 +00:00
|
|
|
|
|
|
|
Some(parsed_crl.contents)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2022-09-02 08:57:53 +00:00
|
|
|
Ok(Self {
|
2022-08-31 10:24:54 +00:00
|
|
|
upstream_cert_verifier: Box::new(AllowAnyAuthenticatedClient::new(store)),
|
2022-08-31 13:37:51 +00:00
|
|
|
crl,
|
2022-09-02 08:57:53 +00:00
|
|
|
})
|
2022-08-31 10:24:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ClientCertVerifier for CustomCertClientVerifier {
|
|
|
|
fn offer_client_auth(&self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
fn client_auth_mandatory(&self) -> Option<bool> {
|
|
|
|
Some(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn client_auth_root_subjects(&self) -> Option<DistinguishedNames> {
|
|
|
|
Some(vec![])
|
|
|
|
}
|
|
|
|
|
2022-08-31 12:36:07 +00:00
|
|
|
fn verify_client_cert(
|
|
|
|
&self,
|
|
|
|
end_entity: &Certificate,
|
|
|
|
intermediates: &[Certificate],
|
|
|
|
now: SystemTime,
|
|
|
|
) -> Result<ClientCertVerified, Error> {
|
2022-09-02 13:40:00 +00:00
|
|
|
let (_rem, cert) =
|
|
|
|
X509Certificate::from_der(&end_entity.0).expect("Failed to read certificate!");
|
|
|
|
|
2022-08-31 13:37:51 +00:00
|
|
|
// 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!");
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-02 13:40:00 +00:00
|
|
|
let result = self
|
|
|
|
.upstream_cert_verifier
|
|
|
|
.verify_client_cert(end_entity, intermediates, now);
|
|
|
|
|
|
|
|
match result.as_ref() {
|
|
|
|
Err(e) => log::error!(
|
|
|
|
"FAILED authentication attempt from Serial={} / Subject={} : {}",
|
|
|
|
cert.serial,
|
|
|
|
cert.subject,
|
|
|
|
e
|
|
|
|
),
|
|
|
|
Ok(_) => log::info!(
|
|
|
|
"SUCCESSFUL authentication attempt from Serial={} / Subject={}",
|
|
|
|
cert.serial,
|
|
|
|
cert.subject
|
|
|
|
),
|
|
|
|
}
|
|
|
|
|
|
|
|
result
|
2022-08-31 10:24:54 +00:00
|
|
|
}
|
|
|
|
}
|