Add support for CRL on server side

This commit is contained in:
Pierre HUBERT 2022-08-31 15:37:51 +02:00
parent c063cdcef6
commit 1ce19ff56a
4 changed files with 224 additions and 1 deletions

181
Cargo.lock generated
View File

@ -294,6 +294,45 @@ dependencies = [
"alloc-no-stdlib", "alloc-no-stdlib",
] ]
[[package]]
name = "asn1-rs"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf6690c370453db30743b373a60ba498fc0d6d83b11f4abfd87a84a075db5dd4"
dependencies = [
"asn1-rs-derive",
"asn1-rs-impl",
"displaydoc",
"nom",
"num-traits",
"rusticata-macros",
"thiserror",
"time",
]
[[package]]
name = "asn1-rs-derive"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "asn1-rs-impl"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@ -524,6 +563,26 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "data-encoding"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
[[package]]
name = "der-parser"
version = "8.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42d4bc9b0db0a0df9ae64634ac5bdefb7afcb534e182275ca0beadbe486701c1"
dependencies = [
"asn1-rs",
"displaydoc",
"nom",
"num-bigint",
"num-traits",
"rusticata-macros",
]
[[package]] [[package]]
name = "derive_more" name = "derive_more"
version = "0.99.17" version = "0.99.17"
@ -547,6 +606,17 @@ dependencies = [
"crypto-common", "crypto-common",
] ]
[[package]]
name = "displaydoc"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.31" version = "0.8.31"
@ -1000,6 +1070,12 @@ version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.5.3" version = "0.5.3"
@ -1039,6 +1115,46 @@ dependencies = [
"tempfile", "tempfile",
] ]
[[package]]
name = "nom"
version = "7.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "num-bigint"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.13.1" version = "1.13.1"
@ -1058,6 +1174,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "oid-registry"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d4bda43fd1b844cbc6e6e54b5444e2b1bc7838bce59ad205902cccbb26d6761"
dependencies = [
"asn1-rs",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.13.1" version = "1.13.1"
@ -1144,6 +1269,15 @@ version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22" checksum = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22"
[[package]]
name = "pem"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03c64931a1a212348ec4f3b4362585eca7159d0d09cbdf4a7f74f02173596fd4"
dependencies = [
"base64",
]
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.1.0" version = "2.1.0"
@ -1347,6 +1481,15 @@ dependencies = [
"semver", "semver",
] ]
[[package]]
name = "rusticata-macros"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
dependencies = [
"nom",
]
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.20.6" version = "0.20.6"
@ -1563,6 +1706,18 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "synstructure"
version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
dependencies = [
"proc-macro2",
"quote",
"syn",
"unicode-xid",
]
[[package]] [[package]]
name = "tcp_relay_client" name = "tcp_relay_client"
version = "0.1.0" version = "0.1.0"
@ -1594,10 +1749,12 @@ dependencies = [
"env_logger", "env_logger",
"futures", "futures",
"log", "log",
"pem",
"rustls", "rustls",
"serde", "serde",
"tokio", "tokio",
"webpki", "webpki",
"x509-parser",
] ]
[[package]] [[package]]
@ -1846,6 +2003,12 @@ dependencies = [
"tinyvec", "tinyvec",
] ]
[[package]]
name = "unicode-xid"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
[[package]] [[package]]
name = "untrusted" name = "untrusted"
version = "0.7.1" version = "0.7.1"
@ -2082,6 +2245,24 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "x509-parser"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8"
dependencies = [
"asn1-rs",
"base64",
"data-encoding",
"der-parser",
"lazy_static",
"nom",
"oid-registry",
"rusticata-macros",
"thiserror",
"time",
]
[[package]] [[package]]
name = "zstd" name = "zstd"
version = "0.11.2+zstd.1.5.2" version = "0.11.2+zstd.1.5.2"

View File

@ -16,4 +16,6 @@ serde = { version = "1.0.144", features = ["derive"] }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
futures = "0.3.24" futures = "0.3.24"
rustls = "0.20.6" rustls = "0.20.6"
webpki = "0.22.0" webpki = "0.22.0"
x509-parser = "0.14.0"
pem = "1.1.0"

View File

@ -48,6 +48,10 @@ pub struct ServerConfig {
/// This option automatically enable TLS client authentication /// This option automatically enable TLS client authentication
#[clap(long)] #[clap(long)]
pub tls_client_auth_root_cert: Option<String>, 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 { impl ServerConfig {

View File

@ -1,8 +1,10 @@
use std::sync::Arc; use std::sync::Arc;
use std::time::SystemTime; use std::time::SystemTime;
use rustls::internal::msgs::enums::AlertDescription;
use rustls::server::{AllowAnyAuthenticatedClient, ClientCertVerified, ClientCertVerifier}; use rustls::server::{AllowAnyAuthenticatedClient, ClientCertVerified, ClientCertVerifier};
use rustls::{Certificate, DistinguishedNames, Error, RootCertStore}; use rustls::{Certificate, DistinguishedNames, Error, RootCertStore};
use x509_parser::prelude::{CertificateRevocationList, FromDer, X509Certificate};
use base::cert_utils::parse_pem_certificates; use base::cert_utils::parse_pem_certificates;
@ -10,10 +12,12 @@ use crate::server_config::ServerConfig;
pub struct CustomCertClientVerifier { pub struct CustomCertClientVerifier {
upstream_cert_verifier: Box<Arc<dyn ClientCertVerifier>>, upstream_cert_verifier: Box<Arc<dyn ClientCertVerifier>>,
crl: Option<Vec<u8>>,
} }
impl CustomCertClientVerifier { impl CustomCertClientVerifier {
pub fn new(conf: Arc<ServerConfig>) -> Self { pub fn new(conf: Arc<ServerConfig>) -> Self {
// Build root certifications list
let cert_path = conf let cert_path = conf
.tls_client_auth_root_cert .tls_client_auth_root_cert
.as_deref() .as_deref()
@ -36,8 +40,20 @@ impl CustomCertClientVerifier {
.expect("Failed to add certificate to root store"); .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 { Self {
upstream_cert_verifier: Box::new(AllowAnyAuthenticatedClient::new(store)), upstream_cert_verifier: Box::new(AllowAnyAuthenticatedClient::new(store)),
crl,
} }
} }
} }
@ -61,6 +77,26 @@ impl ClientCertVerifier for CustomCertClientVerifier {
intermediates: &[Certificate], intermediates: &[Certificate],
now: SystemTime, now: SystemTime,
) -> Result<ClientCertVerified, Error> { ) -> 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 self.upstream_cert_verifier
.verify_client_cert(end_entity, intermediates, now) .verify_client_cert(end_entity, intermediates, now)
} }