summaryrefslogtreecommitdiffstats
path: root/openpgp/src
diff options
context:
space:
mode:
Diffstat (limited to 'openpgp/src')
-rw-r--r--openpgp/src/parse.rs6
-rw-r--r--openpgp/src/parse/stream.rs96
2 files changed, 95 insertions, 7 deletions
diff --git a/openpgp/src/parse.rs b/openpgp/src/parse.rs
index 3e5eead6..eaa10d29 100644
--- a/openpgp/src/parse.rs
+++ b/openpgp/src/parse.rs
@@ -4922,6 +4922,12 @@ impl <'a> PacketParser<'a> {
pub fn take_map(&mut self) -> Option<map::Map> {
self.map.take()
}
+
+ /// Checks if we are processing a signed message using the
+ /// Cleartext Signature Framework.
+ pub(crate) fn processing_csf_message(&self) -> bool {
+ Cookie::processing_csf_message(&self.reader)
+ }
}
/// This interface allows a caller to read the content of a
diff --git a/openpgp/src/parse/stream.rs b/openpgp/src/parse/stream.rs
index bd0a07ce..992b6f3c 100644
--- a/openpgp/src/parse/stream.rs
+++ b/openpgp/src/parse/stream.rs
@@ -647,14 +647,23 @@ impl IMessageStructure {
}
}
- fn push_signature(&mut self, sig: Signature) {
+ fn push_signature(&mut self, sig: Signature, csf_message: bool) {
for layer in self.layers.iter_mut().rev() {
match layer {
IMessageLayer::SignatureGroup {
ref mut sigs, ref mut count,
} if *count > 0 => {
sigs.push(sig);
- *count -= 1;
+ if csf_message {
+ // The CSF transformation does not know how
+ // many signatures will follow, so we may end
+ // up with too few synthesized OPS packets.
+ // But, we only have one layer anyway, and no
+ // notarizations, so we don't need to concern
+ // ourself with the counter.
+ } else {
+ *count -= 1;
+ }
return;
},
_ => (),
@@ -1719,6 +1728,11 @@ pub struct Decryptor<'a, H: VerificationHelper + DecryptionHelper> {
/// The mode of operation.
mode: Mode,
+ /// Whether we are actually processing a cleartext signature
+ /// framework message. If so, we need to tweak our behavior a
+ /// bit.
+ processing_csf_message: Option<bool>,
+
/// Signature verification relative to this time.
///
/// This is needed for checking the signature's liveness.
@@ -2309,12 +2323,19 @@ impl<'a, H: VerificationHelper + DecryptionHelper> Decryptor<'a, H> {
time,
clock_skew_tolerance: tolerance,
policy,
+ processing_csf_message: None, // We don't know yet.
};
let mut pkesks: Vec<packet::PKESK> = Vec::new();
let mut skesks: Vec<packet::SKESK> = Vec::new();
while let PacketParserResult::Some(mut pp) = ppr {
+ // Check whether we are actually processing a cleartext
+ // signature framework message.
+ if v.processing_csf_message.is_none() {
+ v.processing_csf_message = Some(pp.processing_csf_message());
+ }
+
v.policy.packet(&pp.packet)?;
v.helper.inspect(&pp)?;
@@ -2330,8 +2351,19 @@ impl<'a, H: VerificationHelper + DecryptionHelper> Decryptor<'a, H> {
.into());
}
} else if let Err(err) = pp.possible_message() {
- t!("Malformed message: {}", err);
- return Err(err.context("Malformed OpenPGP message"));
+ if v.processing_csf_message.expect("set by now") {
+ // Our CSF transformation yields just one OPS
+ // packet per encountered 'Hash' algorithm header,
+ // and it cannot know how many signatures are in
+ // fact following. Therefore, the message will
+ // not be well-formed according to the grammar.
+ // But, since we created the message structure
+ // during the transformation, we know it is good,
+ // even if it is a little out of spec.
+ } else {
+ t!("Malformed message: {}", err);
+ return Err(err.context("Malformed OpenPGP message"));
+ }
}
let sym_algo_hint = if let Packet::AED(ref aed) = pp.packet {
@@ -2488,7 +2520,8 @@ impl<'a, H: VerificationHelper + DecryptionHelper> Decryptor<'a, H> {
match p {
Packet::Signature(sig) => {
sig.get_issuers().into_iter().for_each(|i| self.push_issuer(i));
- self.structure.push_signature(sig);
+ self.structure.push_signature(
+ sig, self.processing_csf_message.expect("set by now"));
},
_ => (),
}
@@ -2603,8 +2636,14 @@ impl<'a, H: VerificationHelper + DecryptionHelper> Decryptor<'a, H> {
}
if let Err(err) = possible_message {
- return Err(err.context(
- "Malformed OpenPGP message"));
+ if self.processing_csf_message.expect("set by now") {
+ // CSF transformation creates slightly out
+ // of spec message structure. See above
+ // for longer explanation.
+ } else {
+ return Err(err.context(
+ "Malformed OpenPGP message"));
+ }
}
self.push_sig(p)?;
@@ -3694,4 +3733,47 @@ EK8=
Ok(())
}
+
+ /// Tests whether messages using the cleartext signature framework
+ /// with multiple signatures and signers are correctly handled.
+ #[test]
+ fn csf_multiple_signers() -> Result<()> {
+ struct H(bool);
+ impl VerificationHelper for H {
+ fn get_certs(&mut self, _ids: &[crate::KeyHandle])
+ -> Result<Vec<Cert>> {
+ crate::cert::CertParser::from_bytes(
+ crate::tests::key("InRelease.signers.pgp"))?
+ .collect()
+ }
+
+ fn check(&mut self, m: MessageStructure)
+ -> Result<()> {
+ for (i, layer) in m.into_iter().enumerate() {
+ assert_eq!(i, 0);
+ if let MessageLayer::SignatureGroup { results } = layer {
+ assert_eq!(results.len(), 3);
+ for result in results {
+ assert!(result.is_ok());
+ }
+ self.0 = true;
+ } else {
+ panic!();
+ }
+ }
+
+ Ok(())
+ }
+ }
+
+ let p = &P::new();
+ let mut verifier = VerifierBuilder::from_bytes(
+ crate::tests::message("InRelease"))?
+ .with_policy(p, None, H(false))?;
+ let mut b = Vec::new();
+ verifier.read_to_end(&mut b)?;
+ let h = verifier.into_helper();
+ assert!(h.0);
+ Ok(())
+ }
}