From: Nicolas Frey <n.frey@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH proxmox v8 2/5] proxmox-pgp: add unit tests for {de, at}tached signatures
Date: Wed, 14 Jan 2026 10:35:59 +0100 [thread overview]
Message-ID: <20260114093602.33057-3-n.frey@proxmox.com> (raw)
In-Reply-To: <20260114093602.33057-1-n.frey@proxmox.com>
test `verify_signature` using `sequoia_openpgp` to create Certs, these cover:
* detached signatures
* attached signatures
* cryptographically weak (SHA1-signed) signatures
Suggested-by: Lukas Wagner <l.wagner@proxmox.com>
Signed-off-by: Nicolas Frey <n.frey@proxmox.com>
---
New in v8
proxmox-pgp/src/verifier.rs | 192 ++++++++++++++++++++++++++++++++++++
1 file changed, 192 insertions(+)
diff --git a/proxmox-pgp/src/verifier.rs b/proxmox-pgp/src/verifier.rs
index c2eadbc5..9beadea0 100644
--- a/proxmox-pgp/src/verifier.rs
+++ b/proxmox-pgp/src/verifier.rs
@@ -192,3 +192,195 @@ pub fn verify_signature(
// neither a keyring nor a certificate was detect, so we abort here
bail!("'key-path' contains neither a keyring nor a certificate, aborting!");
}
+
+#[cfg(test)]
+mod tests {
+ use super::{verify_signature, WeakCryptoConfig};
+ use anyhow::Result;
+ use sequoia_openpgp::packet::prelude::SignatureBuilder;
+ use sequoia_openpgp::packet::signature::subpacket::NotationDataFlags;
+ use sequoia_openpgp::serialize::MarshalInto;
+ use sequoia_openpgp::types::{HashAlgorithm, SignatureType};
+ use sequoia_openpgp::{cert::prelude::*, policy::StandardPolicy, serialize::stream::*};
+ use std::io::Write;
+
+ const MESSAGE: &[u8] = b"Hello, pgp!";
+
+ fn setup(
+ name: &str,
+ mail: &str,
+ hash: Option<HashAlgorithm>,
+ detached: bool,
+ ) -> Result<(Cert, Vec<u8>)> {
+ let mut policy = StandardPolicy::new();
+
+ if let Some(h) = hash {
+ policy.accept_hash(h);
+ }
+
+ let (cert, _sig) =
+ CertBuilder::general_purpose(Some(format!("{name} <{mail}>"))).generate()?;
+
+ let keypair = cert
+ .keys()
+ .secret()
+ .with_policy(&policy, None)
+ .supported()
+ .alive()
+ .revoked(false)
+ .for_signing()
+ .next()
+ .unwrap()
+ .key()
+ .clone()
+ .into_keypair()?;
+
+ let mut sink = Vec::new();
+
+ {
+ let message = Signer::with_template(
+ Message::new(&mut sink),
+ keypair,
+ SignatureBuilder::new(SignatureType::Text)
+ .add_notation(
+ mail,
+ name,
+ NotationDataFlags::empty().set_human_readable(),
+ false,
+ )?
+ .set_hash_algo(hash.unwrap_or(HashAlgorithm::SHA256)),
+ )?
+ .hash_algo(hash.unwrap_or(HashAlgorithm::SHA256))?;
+
+ if detached {
+ let mut message = message.detached().build()?;
+ message.write_all(MESSAGE)?;
+ message.finalize()?;
+ } else {
+ let mut message = LiteralWriter::new(message.build()?).build()?;
+ message.write_all(MESSAGE)?;
+ message.finalize()?;
+ }
+ }
+
+ Ok((cert, sink))
+ }
+
+ fn root_cause_no_valid_sig(err: anyhow::Error) -> bool {
+ err.root_cause()
+ .to_string()
+ .contains("No valid signature found.")
+ }
+
+ #[test]
+ fn verify_attached_signature_success() -> Result<()> {
+ // using same signature will work
+ {
+ let (cert, sink) = setup("Nicolas Frey", "n.frey@proxmox.com", None, false)?;
+ let verified =
+ verify_signature(&sink, &cert.to_vec()?, None, &WeakCryptoConfig::default())?;
+
+ assert_eq!(verified, MESSAGE);
+ }
+
+ Ok(())
+ }
+
+ #[test]
+ fn verify_attached_signature_fail() -> Result<()> {
+ // using different signatures will fail
+ {
+ let (cert1, sink1) = setup("Nicolas Frey", "n.frey@proxmox.com", None, false)?;
+ let (cert2, sink2) = setup("Proxmox Support Team", "support@proxmox.com", None, false)?;
+
+ assert!(
+ verify_signature(&sink1, &cert2.to_vec()?, None, &WeakCryptoConfig::default())
+ .is_err_and(root_cause_no_valid_sig)
+ );
+ assert!(
+ verify_signature(&sink2, &cert1.to_vec()?, None, &WeakCryptoConfig::default())
+ .is_err_and(root_cause_no_valid_sig)
+ );
+ }
+
+ Ok(())
+ }
+
+ #[test]
+ fn verify_detached_signature_success() -> Result<()> {
+ // using same signature will work
+ {
+ let (cert, sink) = setup("Nicolas Frey", "n.frey@proxmox.com", None, true)?;
+ let verified = verify_signature(
+ MESSAGE,
+ &cert.to_vec()?,
+ Some(&sink),
+ &WeakCryptoConfig::default(),
+ )?;
+ assert_eq!(verified, MESSAGE);
+ }
+
+ Ok(())
+ }
+
+ #[test]
+ fn verify_detached_signature_fail() -> Result<()> {
+ // using different signatures will fail
+ {
+ let (cert1, sink1) = setup("Nicolas Frey", "n.frey@proxmox.com", None, true)?;
+ let (cert2, sink2) = setup("Proxmox Support Team", "support@proxmox.com", None, true)?;
+
+ assert!(verify_signature(
+ MESSAGE,
+ &cert2.to_vec()?,
+ Some(&sink1),
+ &WeakCryptoConfig::default()
+ )
+ .is_err_and(root_cause_no_valid_sig));
+
+ assert!(verify_signature(
+ MESSAGE,
+ &cert1.to_vec()?,
+ Some(&sink2),
+ &WeakCryptoConfig::default()
+ )
+ .is_err_and(root_cause_no_valid_sig));
+ }
+
+ Ok(())
+ }
+
+ #[test]
+ fn weak_crypto_config_allow_sha1() -> Result<()> {
+ let (cert, sink) = setup(
+ "Nicolas Frey",
+ "n.frey@proxmox.com",
+ Some(HashAlgorithm::SHA1),
+ false,
+ )?;
+
+ // allowing sha1 will make the policy accept this signature
+ {
+ let verified = verify_signature(
+ &sink,
+ &cert.to_vec()?,
+ None,
+ &WeakCryptoConfig {
+ allow_sha1: true,
+ ..Default::default()
+ },
+ )?;
+ assert_eq!(verified, MESSAGE);
+ }
+
+ // while this will fail
+ {
+ assert!(
+ verify_signature(&sink, &cert.to_vec()?, None, &WeakCryptoConfig::default())
+ .is_err_and(root_cause_no_valid_sig)
+ );
+ }
+
+ Ok(())
+ }
+}
--
2.47.3
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
next prev parent reply other threads:[~2026-01-14 9:36 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-14 9:35 [pve-devel] [PATCH proxmox v8 0/5] fix #5207: apt: check signature of repos with proxmox-pgp Nicolas Frey
2026-01-14 9:35 ` [pve-devel] [PATCH proxmox v8 1/5] add proxmox-pgp subcrate, move POM verifier code to it Nicolas Frey
2026-01-14 9:35 ` Nicolas Frey [this message]
2026-01-14 9:36 ` [pve-devel] [PATCH proxmox v8 3/5] fix #5207: apt: check signature of repos with proxmox-pgp Nicolas Frey
2026-01-14 9:36 ` [pve-devel] [PATCH proxmox v8 4/5] apt: add tests for POM release filenames Nicolas Frey
2026-01-14 9:36 ` [pve-devel] [PATCH proxmox v8 5/5] apt: check for local POM InRelease as fallback Nicolas Frey
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260114093602.33057-3-n.frey@proxmox.com \
--to=n.frey@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox