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 3D1621FF13F for ; Thu, 26 Feb 2026 12:11:55 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 287DD1D266; Thu, 26 Feb 2026 12:12:50 +0100 (CET) From: Nicolas Frey To: pve-devel@lists.proxmox.com Subject: [PATCH proxmox-offline-mirror 3/3] verifier: remove module Date: Thu, 26 Feb 2026 12:12:39 +0100 Message-ID: <20260226111239.80602-4-n.frey@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260226111239.80602-1-n.frey@proxmox.com> References: <20260226111239.80602-1-n.frey@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.113 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 KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods RDNS_NONE 0.793 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record Message-ID-Hash: 6J4GQQBIXSYOQ74QCLQLMCUNLPDZ6WDQ X-Message-ID-Hash: 6J4GQQBIXSYOQ74QCLQLMCUNLPDZ6WDQ X-MailFrom: nfrey@miso.proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Signed-off-by: Nicolas Frey --- src/helpers/mod.rs | 3 - src/helpers/verifier.rs | 163 ---------------------------------------- 2 files changed, 166 deletions(-) delete mode 100644 src/helpers/verifier.rs diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index fb084a0..906a087 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -1,6 +1,3 @@ pub mod http; pub mod tty; - -mod verifier; -pub(crate) use verifier::verify_signature; diff --git a/src/helpers/verifier.rs b/src/helpers/verifier.rs deleted file mode 100644 index e1a663e..0000000 --- a/src/helpers/verifier.rs +++ /dev/null @@ -1,163 +0,0 @@ -use std::io; - -use anyhow::{Error, bail, format_err}; -use sequoia_openpgp::cert::CertParser; -use sequoia_openpgp::parse::stream::{ - DetachedVerifierBuilder, MessageLayer, MessageStructure, VerificationError, VerificationHelper, - VerifierBuilder, -}; -use sequoia_openpgp::parse::{PacketParser, PacketParserResult, Parse}; -use sequoia_openpgp::policy::StandardPolicy; -use sequoia_openpgp::types::HashAlgorithm; -use sequoia_openpgp::{Cert, KeyHandle}; - -use crate::config::WeakCryptoConfig; - -struct Helper<'a> { - cert: &'a Cert, -} - -impl VerificationHelper for Helper<'_> { - fn get_certs(&mut self, _ids: &[KeyHandle]) -> sequoia_openpgp::Result> { - // Return public keys for signature verification here. - Ok(vec![self.cert.clone()]) - } - - fn check(&mut self, structure: MessageStructure) -> sequoia_openpgp::Result<()> { - // In this function, we implement our signature verification policy. - - let mut good = false; - - // we don't want compression and/or encryption - let layers: Vec<_> = structure.iter().collect(); - if layers.len() > 1 || layers.is_empty() { - bail!( - "unexpected GPG message structure - expected plain signed data, got {} layers!", - layers.len() - ); - } - let layer = &layers[0]; - let mut errors = Vec::new(); - match layer { - MessageLayer::SignatureGroup { results } => { - // We possibly have multiple signatures, but not all keys, so `or` all the individual results. - for result in results { - match result { - Ok(_) => good = true, - Err(e) => errors.push(e), - } - } - } - _ => return Err(anyhow::anyhow!("Unexpected message structure")), - } - - if good { - Ok(()) // Good signature. - } else { - if errors.len() > 1 { - eprintln!("\nEncountered {} errors:", errors.len()); - } - - for (n, err) in errors.iter().enumerate() { - if errors.len() > 1 { - eprintln!("\nSignature #{n}: {err}"); - } else { - eprintln!("\n{err}"); - } - match err { - VerificationError::MalformedSignature { error, .. } - | VerificationError::UnboundKey { error, .. } - | VerificationError::BadKey { error, .. } - | VerificationError::BadSignature { error, .. } => { - let mut cause = error.chain(); - if cause.len() > 1 { - cause.next(); // already included in `err` above - eprintln!("Caused by:"); - for (n, e) in cause.enumerate() { - eprintln!("\t{n}: {e}"); - } - } - } - VerificationError::MissingKey { .. } - | VerificationError::UnknownSignature { .. } => {} // doesn't contain a cause - _ => {} // we already print the error above in full - }; - } - eprintln!(); - Err(anyhow::anyhow!("No valid signature found.")) - } - } -} - -/// Verifies GPG-signed `msg` was signed by `key`, returning the verified data without signature. -pub(crate) fn verify_signature( - msg: &[u8], - key: &[u8], - detached_sig: Option<&[u8]>, - weak_crypto: &WeakCryptoConfig, -) -> Result, Error> { - let mut policy = StandardPolicy::new(); - if weak_crypto.allow_sha1 { - policy.accept_hash(HashAlgorithm::SHA1); - } - if let Some(min_dsa) = weak_crypto.min_dsa_key_size { - if min_dsa <= 1024 { - policy.accept_asymmetric_algo(sequoia_openpgp::policy::AsymmetricAlgorithm::DSA1024); - } - } - if let Some(min_rsa) = weak_crypto.min_rsa_key_size { - if min_rsa <= 1024 { - policy.accept_asymmetric_algo(sequoia_openpgp::policy::AsymmetricAlgorithm::RSA1024); - } - } - - let verifier = |cert| { - let helper = Helper { cert: &cert }; - - if let Some(sig) = detached_sig { - let mut verifier = - DetachedVerifierBuilder::from_bytes(sig)?.with_policy(&policy, None, helper)?; - verifier.verify_bytes(msg)?; - Ok(msg.to_vec()) - } else { - let mut verified = Vec::new(); - let mut verifier = - VerifierBuilder::from_bytes(msg)?.with_policy(&policy, None, helper)?; - let bytes = io::copy(&mut verifier, &mut verified)?; - println!("{bytes} bytes verified"); - if !verifier.message_processed() { - bail!("Failed to verify message!"); - } - Ok(verified) - } - }; - - let mut packed_parser = PacketParser::from_bytes(key)?; - - // parse all packets to see whether this is a simple certificate or a keyring - while let PacketParserResult::Some(pp) = packed_parser { - packed_parser = pp.recurse()?.1; - } - - if let PacketParserResult::EOF(eof) = packed_parser { - // verify against a single certificate - if eof.is_cert().is_ok() { - let cert = Cert::from_bytes(key)?; - return verifier(cert); - // verify against a keyring - } else if eof.is_keyring().is_ok() { - let packed_parser = PacketParser::from_bytes(key)?; - - return CertParser::from(packed_parser) - // flatten here as we ignore packets that aren't a certificate - .flatten() - // keep trying to verify the message until the first certificate that succeeds - .find_map(|c| verifier(c).ok()) - // if no certificate verified the message, abort - .ok_or_else(|| format_err!("No key in keyring could verify the message!")); - } - } - - // neither a keyring nor a certificate was detect, so we abort here - bail!("'key-path' contains neither a keyring nor a certificate, aborting!"); -} -- 2.47.3