]> git.proxmox.com Git - proxmox-offline-mirror.git/blame - src/helpers/verifier.rs
verifier: elide explicit lifetime
[proxmox-offline-mirror.git] / src / helpers / verifier.rs
CommitLineData
f4f8dff0
FG
1use anyhow::{bail, Error};
2
3use sequoia_openpgp::{
4 parse::{
5 stream::{
c71d4349
FG
6 DetachedVerifierBuilder, MessageLayer, MessageStructure, VerificationError,
7 VerificationHelper, VerifierBuilder,
f4f8dff0
FG
8 },
9 Parse,
10 },
11 policy::StandardPolicy,
fa95f21a 12 types::HashAlgorithm,
f4f8dff0
FG
13 Cert, KeyHandle,
14};
15use std::io;
16
fa95f21a
FG
17use crate::config::WeakCryptoConfig;
18
f4f8dff0
FG
19struct Helper<'a> {
20 cert: &'a Cert,
21}
22
23impl<'a> VerificationHelper for Helper<'a> {
24 fn get_certs(&mut self, _ids: &[KeyHandle]) -> sequoia_openpgp::Result<Vec<Cert>> {
25 // Return public keys for signature verification here.
26 Ok(vec![self.cert.clone()])
27 }
28
29 fn check(&mut self, structure: MessageStructure) -> sequoia_openpgp::Result<()> {
30 // In this function, we implement our signature verification policy.
31
32 let mut good = false;
33
34 // we don't want compression and/or encryption
35 if structure.len() > 1 || structure.is_empty() {
36 bail!(
37 "unexpected GPG message structure - expected plain signed data, got {} layers!",
38 structure.len()
39 );
40 }
41 let layer = &structure[0];
42 let mut errors = Vec::new();
43 match layer {
44 MessageLayer::SignatureGroup { results } => {
45 // We possibly have multiple signatures, but not all keys, so `or` all the individual results.
46 for result in results {
47 match result {
48 Ok(_) => good = true,
49 Err(e) => errors.push(e),
50 }
51 }
52 }
53 _ => return Err(anyhow::anyhow!("Unexpected message structure")),
54 }
55
56 if good {
57 Ok(()) // Good signature.
f4f8dff0 58 } else {
c71d4349
FG
59 if errors.len() > 1 {
60 eprintln!("\nEncountered {} errors:", errors.len());
9ecde319 61 }
c71d4349
FG
62
63 for (n, err) in errors.iter().enumerate() {
64 if errors.len() > 1 {
65 eprintln!("\nSignature #{n}: {err}");
66 } else {
67 eprintln!("\n{err}");
68 }
69 match err {
70 VerificationError::MalformedSignature { error, .. }
71 | VerificationError::UnboundKey { error, .. }
72 | VerificationError::BadKey { error, .. }
73 | VerificationError::BadSignature { error, .. } => {
74 let mut cause = error.chain();
75 if cause.len() > 1 {
76 cause.next(); // already included in `err` above
77 eprintln!("Caused by:");
78 for (n, e) in cause.enumerate() {
79 eprintln!("\t{n}: {e}");
80 }
81 }
82 }
83 VerificationError::MissingKey { .. } => {} // doesn't contain a cause
84 };
85 }
86 eprintln!();
87 Err(anyhow::anyhow!("No valid signature found."))
f4f8dff0
FG
88 }
89 }
90}
2d13dcfc
FG
91
92/// Verifies GPG-signed `msg` was signed by `key`, returning the verified data without signature.
373a3ed3
MS
93pub(crate) fn verify_signature(
94 msg: &[u8],
f4f8dff0
FG
95 key: &[u8],
96 detached_sig: Option<&[u8]>,
fa95f21a 97 weak_crypto: &WeakCryptoConfig,
f4f8dff0
FG
98) -> Result<Vec<u8>, Error> {
99 let cert = Cert::from_bytes(key)?;
100
fa95f21a
FG
101 let mut policy = StandardPolicy::new();
102 if weak_crypto.allow_sha1 {
103 policy.accept_hash(HashAlgorithm::SHA1);
104 }
105 if let Some(min_dsa) = weak_crypto.min_dsa_key_size {
106 if min_dsa <= 1024 {
107 policy.accept_asymmetric_algo(sequoia_openpgp::policy::AsymmetricAlgorithm::DSA1024);
108 }
109 }
4f923066 110 if let Some(min_rsa) = weak_crypto.min_rsa_key_size {
fa95f21a
FG
111 if min_rsa <= 1024 {
112 policy.accept_asymmetric_algo(sequoia_openpgp::policy::AsymmetricAlgorithm::RSA1024);
113 }
114 }
115
f4f8dff0
FG
116 let helper = Helper { cert: &cert };
117
118 let verified = if let Some(sig) = detached_sig {
119 let mut verifier =
120 DetachedVerifierBuilder::from_bytes(sig)?.with_policy(&policy, None, helper)?;
121 verifier.verify_bytes(msg)?;
122 msg.to_vec()
123 } else {
124 let mut verified = Vec::new();
9ecde319 125 let mut verifier = VerifierBuilder::from_bytes(msg)?.with_policy(&policy, None, helper)?;
f4f8dff0
FG
126 let bytes = io::copy(&mut verifier, &mut verified)?;
127 println!("{bytes} bytes verified");
128 if !verifier.message_processed() {
129 bail!("Failed to verify message!");
130 }
131 verified
132 };
133
134 Ok(verified)
135}