From df5854986c9ffc532e31159a10d57379dd64b1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= Date: Tue, 26 Mar 2024 09:15:03 +0100 Subject: [PATCH] fix #5248: client: allow self-signed/untrusted certificate chains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit instead of rejecting any non-leaf certificate not pre-validated by OpenSSL, treat them as valid but keep track of the fact that the pre-validation result is no logner trustable. certificate chains completely trusted by openssl are still accepted like before, and leaf certificates without a chain are also handled the same (since the verify callback is only ever called with depth == 0 in that case). Signed-off-by: Fabian Grünbichler --- pbs-client/src/http_client.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/pbs-client/src/http_client.rs b/pbs-client/src/http_client.rs index ab67bba2..27e6ab5d 100644 --- a/pbs-client/src/http_client.rs +++ b/pbs-client/src/http_client.rs @@ -332,6 +332,7 @@ impl HttpClient { let interactive = options.interactive; let fingerprint_cache = options.fingerprint_cache; let prefix = options.prefix.clone(); + let trust_openssl_valid = Arc::new(Mutex::new(true)); ssl_connector_builder.set_verify_callback( openssl::ssl::SslVerifyMode::PEER, move |valid, ctx| match Self::verify_callback( @@ -339,6 +340,7 @@ impl HttpClient { ctx, expected_fingerprint.as_ref(), interactive, + Arc::clone(&trust_openssl_valid), ) { Ok(None) => true, Ok(Some(fingerprint)) => { @@ -561,8 +563,12 @@ impl HttpClient { ctx: &mut X509StoreContextRef, expected_fingerprint: Option<&String>, interactive: bool, + trust_openssl: Arc>, ) -> Result, Error> { - if openssl_valid { + let mut trust_openssl_valid = trust_openssl.lock().unwrap(); + + // we can only rely on openssl's prevalidation if we haven't forced it earlier + if openssl_valid && *trust_openssl_valid { return Ok(None); } @@ -571,11 +577,13 @@ impl HttpClient { None => bail!("context lacks current certificate."), }; - let depth = ctx.error_depth(); - if depth != 0 { - bail!("context depth != 0") + // force trust in case of a chain, but set flag to no longer trust prevalidation by openssl + if ctx.error_depth() > 0 { + *trust_openssl_valid = false; + return Ok(None); } + // leaf certificate - if we end up here, we have to verify the fingerprint! let fp = match cert.digest(openssl::hash::MessageDigest::sha256()) { Ok(fp) => fp, Err(err) => bail!("failed to calculate certificate FP - {}", err), // should not happen