diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2018-09-20 15:50:41 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2018-09-21 10:09:55 +0200 |
commit | e55735fccd7acfead9138f5002e8d01f08fe6759 (patch) | |
tree | 8ddba2737f38273459a96c206c84dcfafa93d967 | |
parent | 8f08555f0a28597470cdac36a6536e0773c14a3b (diff) |
openpgp: Improve the streaming verifier.
- Remove result, and call check once with all the verification
results in such a way that it indicates the signature level.
-rw-r--r-- | openpgp/src/parse/stream.rs | 96 | ||||
-rw-r--r-- | tool/src/commands.rs | 62 |
2 files changed, 95 insertions, 63 deletions
diff --git a/openpgp/src/parse/stream.rs b/openpgp/src/parse/stream.rs index d9aae1f5..dc7ea6dc 100644 --- a/openpgp/src/parse/stream.rs +++ b/openpgp/src/parse/stream.rs @@ -58,15 +58,7 @@ const BUFFER_SIZE: usize = 25 * 1024 * 1024; /// fn get_public_keys(&mut self, _ids: &[KeyID]) -> Result<Vec<TPK>> { /// Ok(Vec::new()) // Feed the TPKs to the verifier here... /// } -/// fn result(&mut self, result: VerificationResult) -> Result<()> { -/// if let VerificationResult::Unknown(_) = result { -/// // We didn't supply the key, hence unknown. -/// } else { -/// panic!("unexpected result: {:?}", result); -/// } -/// Ok(()) -/// } -/// fn check(&mut self) -> Result<()> { +/// fn check(&mut self, sigs: Vec<Vec<VerificationResult>>) -> Result<()> { /// Ok(()) // Implement your verification policy here. /// } /// } @@ -105,6 +97,7 @@ pub struct Verifier<'a, H: VerificationHelper> { buffer: Vec<u8>, seen_eof: bool, oppr: Option<PacketParserResult<'a>>, + sigs: Vec<Vec<VerificationResult>>, } /// Contains the result of a signature verification. @@ -127,6 +120,18 @@ pub enum VerificationResult { Bad(Signature), } +impl VerificationResult { + /// Simple private forwarder. + fn level(&self) -> usize { + use self::VerificationResult::*; + match self { + &Good(ref sig) => sig.level(), + &Unknown(ref sig) => sig.level(), + &Bad(ref sig) => sig.level(), + } + } +} + /// Helper for signature verification. pub trait VerificationHelper { /// Retrieves the TPKs containing the specified keys. @@ -134,25 +139,21 @@ pub trait VerificationHelper { /// Conveys the result of a signature verification. /// - /// This callback is only called before all data is returned. - /// That is, once `io::Read` returns EOF, this callback will not - /// be called again. As such, any error returned by this function - /// will abort reading, and the error will be propagated via the - /// `io::Read` operation. - fn result(&mut self, VerificationResult) -> Result<()>; - - /// Signals that the last signature has been verified. - /// + /// This is called after the last signature has been verified. /// This is the place to implement your verification policy. /// Check that the required number of signatures or notarizations /// were confirmed as valid. /// + /// The argument is a vector, with `sigs[0]` being the vector of + /// signatures over the data, `vec[1]` being notarizations over + /// signatures of level 0, and the data, and so on. + /// /// This callback is only called before all data is returned. /// That is, once `io::Read` returns EOF, this callback will not /// be called again. As such, any error returned by this function /// will abort reading, and the error will be propagated via the /// `io::Read` operation. - fn check(&mut self) -> Result<()>; + fn check(&mut self, sigs: Vec<Vec<VerificationResult>>) -> Result<()>; } impl<'a, H: VerificationHelper> Verifier<'a, H> { @@ -219,6 +220,7 @@ impl<'a, H: VerificationHelper> Verifier<'a, H> { buffer: Vec::new(), seen_eof: false, oppr: None, + sigs: Vec::new(), }; let mut issuers = Vec::new(); @@ -285,7 +287,8 @@ impl<'a, H: VerificationHelper> Verifier<'a, H> { Err(Error::MalformedMessage( "Malformed OpenPGP message".into()).into()) } else { - v.helper.check()?; + v.helper.check(::std::mem::replace(&mut v.sigs, + Vec::new()))?; Ok(v) }, PacketParserResult::Some(pp) => { @@ -316,23 +319,40 @@ impl<'a, H: VerificationHelper> Verifier<'a, H> { fn verify(&mut self, p: Packet) -> Result<()> { match p { Packet::Signature(sig) => { + if self.sigs.is_empty() { + self.sigs.push(Vec::new()); + } + + if let Some(current_level) = self.sigs.iter().last() + .expect("sigs is never empty") + .get(0).map(|r| r.level()) + { + if current_level != sig.level() { + self.sigs.push(Vec::new()); + } + } + if let Some(issuer) = sig.get_issuer() { if let Some((i, j)) = self.keys.get(&issuer) { let (_, key) = self.tpks[*i].keys().nth(*j).unwrap(); if sig.verify(key).unwrap_or(false) { - self.helper.result( - VerificationResult::Good(sig))?; + self.sigs.iter_mut().last() + .expect("sigs is never empty").push( + VerificationResult::Good(sig)); } else { - self.helper.result( - VerificationResult::Bad(sig))?; + self.sigs.iter_mut().last() + .expect("sigs is never empty").push( + VerificationResult::Bad(sig)); } } else { - self.helper.result( - VerificationResult::Unknown(sig))?; + self.sigs.iter_mut().last() + .expect("sigs is never empty").push( + VerificationResult::Unknown(sig)); } } else { - self.helper.result( - VerificationResult::Bad(sig))?; + self.sigs.iter_mut().last() + .expect("sigs is never empty").push( + VerificationResult::Bad(sig)); } }, _ => (), @@ -382,7 +402,8 @@ impl<'a, H: VerificationHelper> Verifier<'a, H> { return Err(Error::MalformedMessage( "Malformed OpenPGP message".into()).into()); } else { - self.helper.check()?; + self.helper.check(::std::mem::replace( + &mut self.sigs, Vec::new()))?; }, PacketParserResult::Some(pp) => { self.oppr = Some(PacketParserResult::Some(pp)); @@ -467,17 +488,18 @@ mod test { Ok(self.keys.clone()) } - fn result(&mut self, result: VerificationResult) -> Result<()> { + fn check(&mut self, sigs: Vec<Vec<VerificationResult>>) -> Result<()> { use self::VerificationResult::*; - match result { - Good(_) => self.good += 1, - Unknown(_) => self.unknown += 1, - Bad(_) => self.bad += 1, + for level in sigs { + for result in level { + match result { + Good(_) => self.good += 1, + Unknown(_) => self.unknown += 1, + Bad(_) => self.bad += 1, + } + } } - Ok(()) - } - fn check(&mut self) -> Result<()> { if self.good > 0 && self.bad == 0 { Ok(()) } else { diff --git a/tool/src/commands.rs b/tool/src/commands.rs index 76c62e5c..8f400404 100644 --- a/tool/src/commands.rs +++ b/tool/src/commands.rs @@ -457,36 +457,46 @@ impl<'a> VerificationHelper for VHelper<'a> { Ok(tpks) } - fn result(&mut self, result: VerificationResult) -> Result<()> { + fn check(&mut self, sigs: Vec<Vec<VerificationResult>>) -> Result<()> { use self::VerificationResult::*; - match result { - Good(sig) => { - let issuer = sig.get_issuer().unwrap(); - let issuer_str = format!("{}", issuer); - eprintln!("Good signature from {}", - self.labels.get(&issuer).unwrap_or(&issuer_str)); - self.good += 1; - }, - Unknown(sig) => { - eprintln!("No key to check signature from {}", - sig.get_issuer().unwrap()); - self.unknown += 1; - }, - Bad(sig) => { - if let Some(issuer) = sig.get_issuer() { - let issuer_str = format!("{}", issuer); - eprintln!("Bad signature from {}", - self.labels.get(&issuer).unwrap_or(&issuer_str)); - } else { - eprintln!("Bad signature without issuer information"); + for (i, results) in sigs.into_iter().enumerate() { + let what = if i == 0 { + "signature".into() + } else { + format!("level {} notarization", i) + }; + + for result in results { + match result { + Good(sig) => { + let issuer = sig.get_issuer().unwrap(); + let issuer_str = format!("{}", issuer); + eprintln!("Good {} from {}", what, + self.labels.get(&issuer).unwrap_or( + &issuer_str)); + self.good += 1; + }, + Unknown(sig) => { + eprintln!("No key to check {} from {}", what, + sig.get_issuer().unwrap()); + self.unknown += 1; + }, + Bad(sig) => { + if let Some(issuer) = sig.get_issuer() { + let issuer_str = format!("{}", issuer); + eprintln!("Bad {} from {}", what, + self.labels.get(&issuer).unwrap_or( + &issuer_str)); + } else { + eprintln!("Bad {} without issuer information", + what); + } + self.bad += 1; + }, } - self.bad += 1; - }, + } } - Ok(()) - } - fn check(&mut self) -> Result<()> { if self.good > 0 && self.bad == 0 { Ok(()) } else { |