feat: actual cert verification ignoring UnknownIssuer

This commit is contained in:
DarkCat09 2024-08-28 19:03:13 +04:00
parent 0e8d023880
commit 8e8fa85206
Signed by: DarkCat09
GPG key ID: BD3CE9B65916CD82
3 changed files with 62 additions and 9 deletions

7
Cargo.lock generated
View file

@ -702,7 +702,7 @@ dependencies = [
"once_cell",
"ring 0.17.8",
"rustls-pki-types",
"rustls-webpki 0.102.6",
"rustls-webpki 0.102.7",
"subtle",
"zeroize",
]
@ -734,9 +734,9 @@ dependencies = [
[[package]]
name = "rustls-webpki"
version = "0.102.6"
version = "0.102.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e"
checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56"
dependencies = [
"ring 0.17.8",
"rustls-pki-types",
@ -887,6 +887,7 @@ dependencies = [
"hickory-client",
"mime",
"num_enum",
"rustls-webpki 0.102.7",
"sha2",
"tokio",
"tokio-rustls 0.26.0",

View file

@ -25,6 +25,7 @@ tokio-rustls = { version = "0.26.0", default-features = false, features = ["ring
dashmap = { version = "6.0.1", optional = true }
hickory-client = { version = "0.24.1", optional = true }
async-trait = "0.1.81"
rustls-webpki = "0.102.7"
[dev-dependencies]
tokio = { version = "1.39.2", features = ["macros", "rt-multi-thread"] }

View file

@ -1,5 +1,6 @@
//! Custom verifier for Rustls accepting any TLS cert
//! (usually called "insecure mode")
//! Custom verifier for Rustls allowing self-signed certs
//! but performing other required checks;
//! mostly for internal use
use std::sync::Arc;
@ -9,6 +10,8 @@ use tokio_rustls::rustls::{
crypto::CryptoProvider,
};
use webpki::EndEntityCert;
/// Custom verifier for Rustls accepting any TLS certificate
#[derive(Debug)]
pub struct InternalCertVerifier(Arc<CryptoProvider>);
@ -39,15 +42,42 @@ impl From<Arc<CryptoProvider>> for InternalCertVerifier {
}
impl ServerCertVerifier for InternalCertVerifier {
#[inline]
fn verify_server_cert(
&self,
_end_entity: &rustls::pki_types::CertificateDer<'_>,
end_entity: &rustls::pki_types::CertificateDer<'_>,
_intermediates: &[rustls::pki_types::CertificateDer<'_>],
_server_name: &rustls::pki_types::ServerName<'_>,
server_name: &rustls::pki_types::ServerName<'_>,
_ocsp_response: &[u8],
_now: rustls::pki_types::UnixTime,
now: rustls::pki_types::UnixTime,
) -> Result<ServerCertVerified, rustls::Error> {
let cert = EndEntityCert::try_from(end_entity).map_err(pki_error)?;
match cert.verify_for_usage(
self.0.signature_verification_algorithms.all,
&[], // no trusted anchors (i.e. CAs)
&[], // i think there's no point in passing intermediates without CAs
now, // `now` as the time for expiration check
webpki::KeyUsage::server_auth(),
None, // no CRLs
None, // no verify_path callback
) {
Ok(_) => Ok(()), // unreachable
Err(webpki::Error::UnknownIssuer) => {
// trust anchors verification is done after
// any other issuer-independent checks (including expiration),
// so this error can be safely ignored as
// we are working with self-signed certificates.
// for reference -- fn webpki::verify_cert::build_chain_inner
// (NOTE: should be re-checked on every rustls update)
Ok(())
}
Err(e) => Err(e),
}
.map_err(pki_error)?;
cert.verify_is_valid_for_subject_name(server_name)
.map_err(pki_error)?;
Ok(ServerCertVerified::assertion())
}
@ -86,3 +116,24 @@ impl ServerCertVerifier for InternalCertVerifier {
self.0.signature_verification_algorithms.supported_schemes()
}
}
pub fn pki_error(e: webpki::Error) -> rustls::CertificateError {
// partially copied from private fn rustls::webpki::pki_error(e)
use rustls::{CertificateError, OtherError};
use webpki::Error::*;
match e {
BadDer | BadDerTime | TrailingData(_) => CertificateError::BadEncoding,
CertNotValidYet => CertificateError::NotValidYet,
CertExpired | InvalidCertValidity => CertificateError::Expired,
UnknownIssuer => CertificateError::UnknownIssuer,
CertNotValidForName => CertificateError::NotValidForName,
CertRevoked => CertificateError::Revoked,
UnknownRevocationStatus => CertificateError::UnknownRevocationStatus,
InvalidSignatureForPublicKey
| UnsupportedSignatureAlgorithm
| UnsupportedSignatureAlgorithmForPublicKey => CertificateError::BadSignature,
_ => CertificateError::Other(OtherError(Arc::new(e))),
}
}