This changes the validation logic by always checking the fingerprint of
the leaf certificate, ignoring the openssl verification if a fingerprint
is configured. This now aligns with our perl implementation and the one
for proxmox-websocket-tunnel.

Before, a valid certificate chain would have precedence over an explicit
fingerprint.

Signed-off-by: Dominik Csapak <d.csa...@proxmox.com>
---
 proxmox-client/Cargo.toml    |  2 +-
 proxmox-client/src/client.rs | 48 ++++++------------------------------
 2 files changed, 9 insertions(+), 41 deletions(-)

diff --git a/proxmox-client/Cargo.toml b/proxmox-client/Cargo.toml
index ec4078a9..9831d686 100644
--- a/proxmox-client/Cargo.toml
+++ b/proxmox-client/Cargo.toml
@@ -25,7 +25,7 @@ openssl = { workspace = true, optional = true }
 
 proxmox-login = { workspace = true, features = [ "http" ] }
 
-proxmox-http = { workspace = true, optional = true, features = [ "client" ] }
+proxmox-http = { workspace = true, optional = true, features = [ "client", 
"tls" ] }
 hyper = { workspace = true, optional = true }
 
 proxmox-serde = { workspace = true, features = [ "perl" ] }
diff --git a/proxmox-client/src/client.rs b/proxmox-client/src/client.rs
index da2c5c59..53ebb53b 100644
--- a/proxmox-client/src/client.rs
+++ b/proxmox-client/src/client.rs
@@ -9,9 +9,9 @@ use http::uri::PathAndQuery;
 use http::Method;
 use http::{StatusCode, Uri};
 use http_body_util::BodyExt;
-use openssl::hash::MessageDigest;
 use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
 use openssl::x509::{self, X509};
+use proxmox_http::get_fingerprint_from_u8;
 use proxmox_login::Ticket;
 use serde::Serialize;
 
@@ -110,10 +110,14 @@ impl Client {
             TlsOptions::Insecure => connector.set_verify(SslVerifyMode::NONE),
             TlsOptions::Fingerprint(expected_fingerprint) => {
                 connector.set_verify_callback(SslVerifyMode::PEER, move 
|valid, chain| {
-                    if valid {
-                        return true;
+                    let fp = get_fingerprint_from_u8(&expected_fingerprint);
+                    match proxmox_http::openssl_verify_callback(valid, chain, 
Some(&fp)) {
+                        Ok(()) => true,
+                        Err(err) => {
+                            log::error!("{err}");
+                            false
+                        }
                     }
-                    verify_fingerprint(chain, &expected_fingerprint)
                 });
             }
             TlsOptions::Callback(cb) => {
@@ -545,42 +549,6 @@ impl HttpApiClient for Client {
     }
 }
 
-fn verify_fingerprint(chain: &x509::X509StoreContextRef, expected_fingerprint: 
&[u8]) -> bool {
-    let Some(cert) = chain.current_cert() else {
-        log::error!("no certificate in chain?");
-        return false;
-    };
-
-    let fp = match cert.digest(MessageDigest::sha256()) {
-        Err(err) => {
-            log::error!("error calculating certificate fingerprint: {err}");
-            return false;
-        }
-        Ok(fp) => fp,
-    };
-
-    if expected_fingerprint != fp.as_ref() {
-        log::error!("bad fingerprint: {}", fp_string(&fp));
-        log::error!("expected fingerprint: {}", 
fp_string(expected_fingerprint));
-        return false;
-    }
-
-    true
-}
-
-fn fp_string(fp: &[u8]) -> String {
-    use std::fmt::Write as _;
-
-    let mut out = String::new();
-    for b in fp {
-        if !out.is_empty() {
-            out.push(':');
-        }
-        let _ = write!(out, "{b:02x}");
-    }
-    out
-}
-
 impl Error {
     pub(crate) fn internal<E>(context: &'static str, err: E) -> Self
     where
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to