From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id E201E1FF170 for ; Thu, 21 Aug 2025 10:43:17 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 4B5E019E76; Thu, 21 Aug 2025 10:43:10 +0200 (CEST) From: Dominik Csapak To: pdm-devel@lists.proxmox.com Date: Thu, 21 Aug 2025 10:39:24 +0200 Message-ID: <20250821084229.1523597-4-d.csapak@proxmox.com> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250821084229.1523597-1-d.csapak@proxmox.com> References: <20250821084229.1523597-1-d.csapak@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.022 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pdm-devel] [PATCH datacenter-manager v3 03/23] server: connection: add probe_tls_connection helper X-BeenThere: pdm-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Datacenter Manager development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Datacenter Manager development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pdm-devel-bounces@lists.proxmox.com Sender: "pdm-devel" this is intended to help us probe a remote/host before using it to check whether the tls connection is working fine, or it returns the certificate information so we can show it to the user. Signed-off-by: Dominik Csapak --- lib/pdm-api-types/Cargo.toml | 1 + lib/pdm-api-types/src/remotes.rs | 10 ++++ server/src/connection.rs | 83 +++++++++++++++++++++++++++++++- 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/lib/pdm-api-types/Cargo.toml b/lib/pdm-api-types/Cargo.toml index 7e72a19..26f7227 100644 --- a/lib/pdm-api-types/Cargo.toml +++ b/lib/pdm-api-types/Cargo.toml @@ -13,6 +13,7 @@ regex.workspace = true serde.workspace = true serde_plain.workspace = true +proxmox-acme-api.workspace = true proxmox-auth-api = { workspace = true, features = ["api-types"] } proxmox-lang.workspace = true proxmox-config-digest.workspace = true diff --git a/lib/pdm-api-types/src/remotes.rs b/lib/pdm-api-types/src/remotes.rs index dca2fa0..7e67eec 100644 --- a/lib/pdm-api-types/src/remotes.rs +++ b/lib/pdm-api-types/src/remotes.rs @@ -179,3 +179,13 @@ mod serde_option_uri { } } } + +#[allow(clippy::large_enum_variant)] +#[derive(Clone, PartialEq, Deserialize, Serialize)] +/// Represents the outcome of TLS probing. +pub enum TlsProbeOutcome { + /// The certificate is trusted with the given hostname/fingerprint + TrustedCertificate, + /// The certificate is untrusted with the given hostname/fingerprint + UntrustedCertificate(proxmox_acme_api::CertificateInfo), +} diff --git a/server/src/connection.rs b/server/src/connection.rs index 7d5027f..6e54e86 100644 --- a/server/src/connection.rs +++ b/server/src/connection.rs @@ -15,11 +15,13 @@ use std::time::{Duration, SystemTime}; use anyhow::{bail, format_err, Error}; use http::uri::Authority; use http::Method; +use openssl::x509::X509StoreContextRef; use serde::Serialize; +use proxmox_acme_api::CertificateInfo; use proxmox_client::{Client, HttpApiClient, HttpApiResponse, HttpApiResponseStream, TlsOptions}; -use pdm_api_types::remotes::{NodeUrl, Remote, RemoteType}; +use pdm_api_types::remotes::{NodeUrl, Remote, RemoteType, TlsProbeOutcome}; use pve_api_types::client::PveClientImpl; use crate::pbs_client::PbsClient; @@ -799,3 +801,82 @@ impl HttpApiClient for MultiClient { try_request! { self, method, path_and_query, params, streaming_request } } } + +/// Checks TLS connection to the given remote +/// +/// Returns `Ok(None)` if connecting with the given parameters works +/// Returns `Ok(Some(cert))` if no fingerprint was given and some certificate could not be validated +/// Returns `Err(err)` if some other error occurred +/// +/// # Example +/// +/// ``` +/// use server::connection::probe_tls_connection; +/// use pdm_api_types::remotes::RemoteType; +/// +/// # async fn function() { +/// let result = probe_tls_connection(RemoteType::Pve, "192.168.2.100".to_string(), None).await; +/// match result { +/// Ok(None) => { /* everything ok */ }, +/// Ok(Some(cert)) => { /* do something with cert */ }, +/// Err(err) => { /* do something with error */ }, +/// } +/// # } +/// ``` +pub async fn probe_tls_connection( + remote_type: RemoteType, + hostname: String, + fingerprint: Option, +) -> Result { + let host_port: Authority = hostname.parse()?; + + let uri: http::uri::Uri = format!( + "https://{}:{}", + host_port.host(), + host_port.port_u16().unwrap_or(remote_type.default_port()) + ) + .parse()?; + + // to save the invalid cert we find + let invalid_cert = Arc::new(StdMutex::new(None)); + + let options = if let Some(fp) = &fingerprint { + TlsOptions::parse_fingerprint(fp)? + } else { + TlsOptions::Callback(Box::new({ + let invalid_cert = invalid_cert.clone(); + move |valid: bool, chain: &mut X509StoreContextRef| { + if let Some(cert) = chain.current_cert() { + if !valid { + let cert = cert + .to_pem() + .map_err(Error::from) + .and_then(|pem| CertificateInfo::from_pem("", &pem)); + *invalid_cert.lock().unwrap() = Some(cert); + } + } + true + } + })) + }; + let client = proxmox_client::Client::with_options(uri, options, Default::default())?; + + // set fake auth info. we don't need any, but the proxmox client will return unauthenticated if + // none is set. + client.set_authentication(proxmox_client::Token { + userid: "".to_string(), + value: "".to_string(), + prefix: "".to_string(), + perl_compat: false, + }); + + client.request(Method::GET, "/", None::<()>).await?; + + let cert = invalid_cert.lock().unwrap().take(); + let outcome = if let Some(cert) = cert { + TlsProbeOutcome::UntrustedCertificate(cert?) + } else { + TlsProbeOutcome::TrustedCertificate + }; + Ok(outcome) +} -- 2.47.2 _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel