]>
Commit | Line | Data |
---|---|---|
f4f8dff0 FG |
1 | use anyhow::{bail, Error}; |
2 | ||
3 | use 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 | }; | |
15 | use std::io; | |
16 | ||
fa95f21a FG |
17 | use crate::config::WeakCryptoConfig; |
18 | ||
f4f8dff0 FG |
19 | struct Helper<'a> { |
20 | cert: &'a Cert, | |
21 | } | |
22 | ||
23 | impl<'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. | |
f4f8dff0 FG |
93 | pub(crate) fn verify_signature<'msg>( |
94 | msg: &'msg [u8], | |
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 | } |