diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2022-02-22 12:56:42 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2022-02-22 12:56:42 +0100 |
commit | 676ccb079d0e9af6e81e77d9dc0b0f912ada5b3c (patch) | |
tree | 0988a4f20cdc7baaef58a61af0d689a245b9d01f /openpgp/src/serialize/stream.rs | |
parent | 623821a3b582b563029395dd051285caab3402db (diff) |
openpgp: Fix emitting multiple signatures.
- Previously, stream::Signer did not properly bracket OPS/Sig
packets when using more than one signer, i.e. OPS_a OPS_b Literal
Sig_a Sig_b instead of OPS_a OPS_b Literal Sig_b Sig_a.
- This is a regression introduced in
5bef3bde45f71126cdca3e8ad30b1047287c843a.
- Fixes #816.
Diffstat (limited to 'openpgp/src/serialize/stream.rs')
-rw-r--r-- | openpgp/src/serialize/stream.rs | 65 |
1 files changed, 64 insertions, 1 deletions
diff --git a/openpgp/src/serialize/stream.rs b/openpgp/src/serialize/stream.rs index 61fe94e3..2ea700a9 100644 --- a/openpgp/src/serialize/stream.rs +++ b/openpgp/src/serialize/stream.rs @@ -1334,7 +1334,7 @@ impl<'a> Signer<'a> { // Emit the signatures in reverse, so that the // one-pass-signature and signature packets "bracket" the // message. - for signer in self.signers.iter_mut() { + for signer in self.signers.iter_mut().rev() { // Part of the signature packet is hashed in, // therefore we need to clone the hash. let hash = self.hash.clone(); @@ -3781,4 +3781,67 @@ mod test { unreachable!(); }; } + + /// Tests that multiple signatures are in the correct order. + #[test] + fn issue_816() -> Result<()> { + use crate::{ + packet::key::{Key4, PrimaryRole}, + types::Curve, + KeyHandle, + }; + + let signer_a = + Key4::<_, PrimaryRole>::generate_ecc(true, Curve::Ed25519)? + .into_keypair()?; + + let signer_b = + Key4::<_, PrimaryRole>::generate_ecc(true, Curve::Ed25519)? + .into_keypair()?; + + let mut sink = Vec::new(); + let message = Message::new(&mut sink); + let message = Signer::new(message, signer_a) + .add_signer(signer_b) + .build()?; + let mut message = LiteralWriter::new(message).build()?; + message.write_all(b"Make it so, number one!")?; + message.finalize()?; + + let pp = crate::PacketPile::from_bytes(&sink)?; + assert_eq!(pp.children().count(), 5); + + let first_signer: KeyHandle = + if let Packet::OnePassSig(ops) = pp.path_ref(&[0]).unwrap() { + ops.issuer().into() + } else { + panic!("expected ops packet") + }; + + let second_signer: KeyHandle = + if let Packet::OnePassSig(ops) = pp.path_ref(&[1]).unwrap() { + ops.issuer().into() + } else { + panic!("expected ops packet") + }; + + assert!(matches!(pp.path_ref(&[2]).unwrap(), Packet::Literal(_))); + + // OPS and Signature packets "bracket" the literal, i.e. the + // last occurring ops packet is met by the first occurring + // signature packet. + if let Packet::Signature(sig) = pp.path_ref(&[3]).unwrap() { + assert!(sig.get_issuers()[0].aliases(&second_signer)); + } else { + panic!("expected sig packet") + } + + if let Packet::Signature(sig) = pp.path_ref(&[4]).unwrap() { + assert!(sig.get_issuers()[0].aliases(&first_signer)); + } else { + panic!("expected sig packet") + } + + Ok(()) + } } |