Loading src/tests/detached_signatures.rs +2 −1 Original line number Diff line number Diff line Loading @@ -1090,6 +1090,7 @@ pub fn schedule(plan: &mut TestPlan) -> Result<()> { plan.add(Box::new(LineBreakNormalizationTest::new()?)); plan.add(Box::new(unknown_packets::UnknownPackets::new()?)); plan.add(Box::new(short_rsa_sigs::ShortRSASigs::new()?)); plan.add(Box::new(digest_prefix::DigestPrefix::new()?)); plan.add(Box::new(digest_prefix::Production::new()?)); plan.add(Box::new(digest_prefix::Consumption::new()?)); Ok(()) } src/tests/detached_signatures/digest_prefix.rs +91 −46 Original line number Diff line number Diff line Loading @@ -41,15 +41,90 @@ fn corrupt_hash_digest(p: Packet) -> Result<Packet> { } } /// Explores whether implementations set the digest prefix correctly, /// and whether they consider signatures with invalid digest prefixes /// invalid. pub struct DigestPrefix { /// Explores whether implementations set the digest prefix correctly. pub struct Production { } impl Production { pub fn new() -> Result<Production> { Ok(Production {}) } } impl crate::plan::Runnable<TestMatrix> for Production { fn title(&self) -> String { "Signature digest prefix, production".into() } fn description(&self) -> String { "<p>Explores whether implementations set the digest prefix correctly. \ To that end, we ask implementations to make a detached signature \ and check whether the digest prefix is correct.</p>" .into() } fn artifacts(&self) -> Vec<(String, Data)> { vec![ ("Bob's key".into(), data::certificate("bob-secret.pgp").into()), ] } fn run(&self, implementations: &[crate::Sop]) -> Result<TestMatrix> { ConsumptionTest::run(self, implementations) } } impl ConsumptionTest<Data, Data> for Production { fn produce(&self) -> Result<Vec<(String, Data, Option<Expectation>)>> { Ok(vec![ ("Checking produced prefix".into(), data::certificate("bob-secret.pgp").into(), Some(Ok("Digest prefix MUST be set correctly".into()))), ]) } fn consume(&self, pgp: &Sop, artifact: &Data) -> Result<Data> { pgp.sop() .sign() .key(artifact) .data(crate::tests::MESSAGE) } fn check_consumer(&self, _: &Data, result: &Data, _: &Option<Expectation>) -> Result<()> { let p = Packet::from_bytes(result)?; let s: Signature = p.downcast() .map_err(|p| anyhow::anyhow!("Expected a signature packet, \ got {:?}", p))?; let mut h = s.hash_algo().context()?; h.update(crate::tests::MESSAGE); s.hash(&mut h); let d = h.into_digest()?; ensure!(s.digest_prefix() == &d[..2], CheckError::HardFailure(format!( "Digest prefix mismatch. Got: {:?}, want: {:?}.", s.digest_prefix(), &d[..2]))); Ok(()) } } /// Explores whether implementations consider signatures with invalid /// digest prefixes invalid. pub struct Consumption { bob_corrupted: Data, } impl DigestPrefix { pub fn new() -> Result<DigestPrefix> { impl Consumption { pub fn new() -> Result<Consumption> { let bob_corrupted = PacketPile::from_bytes(data::certificate("bob.pgp"))? .into_children() Loading @@ -57,25 +132,22 @@ impl DigestPrefix { .collect::<PacketPile>() .to_vec()? .into(); Ok(DigestPrefix { Ok(Consumption { bob_corrupted, }) } } impl crate::plan::Runnable<TestMatrix> for DigestPrefix { impl crate::plan::Runnable<TestMatrix> for Consumption { fn title(&self) -> String { "Signature digest prefix".into() "Signature digest prefix, consumption".into() } fn description(&self) -> String { "<p>Explores whether implementations set the digest prefix correctly, \ and whether they consider signatures with invalid digest prefixes \ invalid. There are three checks:</p>\ <ol><li>We ask implementations to make a detached signature and check \ whether the digest prefix is correct.</li>\ <li>We make a detached signature, corrupt the digest prefix, and ask \ implementations to verify it.</li>\ "<p>Explores whether implementations consider signatures with \ invalid digest prefixes invalid. There are two checks:</p>\ <ol><li>We make a detached signature, corrupt the digest prefix, \ and ask implementations to verify it.</li>\ <li>We ask implementations to verify a signature using a cert where \ we corrupted all digest prefixes in the binding signatures.</li></ol>" .into() Loading @@ -83,7 +155,6 @@ impl crate::plan::Runnable<TestMatrix> for DigestPrefix { fn artifacts(&self) -> Vec<(String, Data)> { vec![ ("Bob's key".into(), data::certificate("bob-secret.pgp").into()), ("Bob's cert".into(), data::certificate("bob.pgp").into()), ("Bob's cert with corrupted digest prefixes".into(), self.bob_corrupted.clone()), Loading @@ -101,13 +172,12 @@ impl crate::plan::Runnable<TestMatrix> for DigestPrefix { } enum Variant { CheckSigning, CheckCorruptedSig, CheckCorruptedCert, } use Variant::*; impl ConsumptionTest<(Data, Variant), (Data, Vec<Verification>)> for DigestPrefix { impl ConsumptionTest<(Data, Variant), (Data, Vec<Verification>)> for Consumption { fn produce(&self) -> Result<Vec<(String, (Data, Variant), Option<Expectation>)>> { Loading @@ -127,9 +197,6 @@ impl ConsumptionTest<(Data, Variant), (Data, Vec<Verification>)> for DigestPrefi let sig = Packet::from_bytes(&sig)?; Ok(vec![ ("Checking produced prefix".into(), (data::certificate("bob-secret.pgp").into(), CheckSigning), Some(Ok("Digest prefix MUST be set correctly".into()))), ("Sig w/corrupted prefix".into(), (corrupt_hash_digest(sig.clone())?.to_vec()?.into(), CheckCorruptedSig), None), Loading @@ -143,13 +210,6 @@ impl ConsumptionTest<(Data, Variant), (Data, Vec<Verification>)> for DigestPrefi -> Result<(Data, Vec<Verification>)> { match variant { CheckSigning => { Ok((pgp.sop() .sign() .key(artifact) .data(crate::tests::MESSAGE)?, vec![])) }, CheckCorruptedSig => { Ok((Default::default(), pgp.sop() Loading @@ -171,26 +231,10 @@ impl ConsumptionTest<(Data, Variant), (Data, Vec<Verification>)> for DigestPrefi fn check_consumer(&self, (_, variant): &(Data, Variant), (result, verifications): &(Data, Vec<Verification>), (_, verifications): &(Data, Vec<Verification>), _: &Option<Expectation>) -> Result<()> { match variant { CheckSigning => { let p = Packet::from_bytes(result)?; let s: Signature = p.downcast() .map_err(|p| anyhow::anyhow!("Expected a signature packet, \ got {:?}", p))?; let mut h = s.hash_algo().context()?; h.update(crate::tests::MESSAGE); s.hash(&mut h); let d = h.into_digest()?; ensure!(s.digest_prefix() == &d[..2], CheckError::HardFailure(format!( "Digest prefix mismatch. Got: {:?}, want: {:?}.", s.digest_prefix(), &d[..2]))); Ok(()) }, CheckCorruptedSig => { let _ = verifications; // XXX Ok(()) Loading @@ -202,3 +246,4 @@ impl ConsumptionTest<(Data, Variant), (Data, Vec<Verification>)> for DigestPrefi } } } Loading
src/tests/detached_signatures.rs +2 −1 Original line number Diff line number Diff line Loading @@ -1090,6 +1090,7 @@ pub fn schedule(plan: &mut TestPlan) -> Result<()> { plan.add(Box::new(LineBreakNormalizationTest::new()?)); plan.add(Box::new(unknown_packets::UnknownPackets::new()?)); plan.add(Box::new(short_rsa_sigs::ShortRSASigs::new()?)); plan.add(Box::new(digest_prefix::DigestPrefix::new()?)); plan.add(Box::new(digest_prefix::Production::new()?)); plan.add(Box::new(digest_prefix::Consumption::new()?)); Ok(()) }
src/tests/detached_signatures/digest_prefix.rs +91 −46 Original line number Diff line number Diff line Loading @@ -41,15 +41,90 @@ fn corrupt_hash_digest(p: Packet) -> Result<Packet> { } } /// Explores whether implementations set the digest prefix correctly, /// and whether they consider signatures with invalid digest prefixes /// invalid. pub struct DigestPrefix { /// Explores whether implementations set the digest prefix correctly. pub struct Production { } impl Production { pub fn new() -> Result<Production> { Ok(Production {}) } } impl crate::plan::Runnable<TestMatrix> for Production { fn title(&self) -> String { "Signature digest prefix, production".into() } fn description(&self) -> String { "<p>Explores whether implementations set the digest prefix correctly. \ To that end, we ask implementations to make a detached signature \ and check whether the digest prefix is correct.</p>" .into() } fn artifacts(&self) -> Vec<(String, Data)> { vec![ ("Bob's key".into(), data::certificate("bob-secret.pgp").into()), ] } fn run(&self, implementations: &[crate::Sop]) -> Result<TestMatrix> { ConsumptionTest::run(self, implementations) } } impl ConsumptionTest<Data, Data> for Production { fn produce(&self) -> Result<Vec<(String, Data, Option<Expectation>)>> { Ok(vec![ ("Checking produced prefix".into(), data::certificate("bob-secret.pgp").into(), Some(Ok("Digest prefix MUST be set correctly".into()))), ]) } fn consume(&self, pgp: &Sop, artifact: &Data) -> Result<Data> { pgp.sop() .sign() .key(artifact) .data(crate::tests::MESSAGE) } fn check_consumer(&self, _: &Data, result: &Data, _: &Option<Expectation>) -> Result<()> { let p = Packet::from_bytes(result)?; let s: Signature = p.downcast() .map_err(|p| anyhow::anyhow!("Expected a signature packet, \ got {:?}", p))?; let mut h = s.hash_algo().context()?; h.update(crate::tests::MESSAGE); s.hash(&mut h); let d = h.into_digest()?; ensure!(s.digest_prefix() == &d[..2], CheckError::HardFailure(format!( "Digest prefix mismatch. Got: {:?}, want: {:?}.", s.digest_prefix(), &d[..2]))); Ok(()) } } /// Explores whether implementations consider signatures with invalid /// digest prefixes invalid. pub struct Consumption { bob_corrupted: Data, } impl DigestPrefix { pub fn new() -> Result<DigestPrefix> { impl Consumption { pub fn new() -> Result<Consumption> { let bob_corrupted = PacketPile::from_bytes(data::certificate("bob.pgp"))? .into_children() Loading @@ -57,25 +132,22 @@ impl DigestPrefix { .collect::<PacketPile>() .to_vec()? .into(); Ok(DigestPrefix { Ok(Consumption { bob_corrupted, }) } } impl crate::plan::Runnable<TestMatrix> for DigestPrefix { impl crate::plan::Runnable<TestMatrix> for Consumption { fn title(&self) -> String { "Signature digest prefix".into() "Signature digest prefix, consumption".into() } fn description(&self) -> String { "<p>Explores whether implementations set the digest prefix correctly, \ and whether they consider signatures with invalid digest prefixes \ invalid. There are three checks:</p>\ <ol><li>We ask implementations to make a detached signature and check \ whether the digest prefix is correct.</li>\ <li>We make a detached signature, corrupt the digest prefix, and ask \ implementations to verify it.</li>\ "<p>Explores whether implementations consider signatures with \ invalid digest prefixes invalid. There are two checks:</p>\ <ol><li>We make a detached signature, corrupt the digest prefix, \ and ask implementations to verify it.</li>\ <li>We ask implementations to verify a signature using a cert where \ we corrupted all digest prefixes in the binding signatures.</li></ol>" .into() Loading @@ -83,7 +155,6 @@ impl crate::plan::Runnable<TestMatrix> for DigestPrefix { fn artifacts(&self) -> Vec<(String, Data)> { vec![ ("Bob's key".into(), data::certificate("bob-secret.pgp").into()), ("Bob's cert".into(), data::certificate("bob.pgp").into()), ("Bob's cert with corrupted digest prefixes".into(), self.bob_corrupted.clone()), Loading @@ -101,13 +172,12 @@ impl crate::plan::Runnable<TestMatrix> for DigestPrefix { } enum Variant { CheckSigning, CheckCorruptedSig, CheckCorruptedCert, } use Variant::*; impl ConsumptionTest<(Data, Variant), (Data, Vec<Verification>)> for DigestPrefix { impl ConsumptionTest<(Data, Variant), (Data, Vec<Verification>)> for Consumption { fn produce(&self) -> Result<Vec<(String, (Data, Variant), Option<Expectation>)>> { Loading @@ -127,9 +197,6 @@ impl ConsumptionTest<(Data, Variant), (Data, Vec<Verification>)> for DigestPrefi let sig = Packet::from_bytes(&sig)?; Ok(vec![ ("Checking produced prefix".into(), (data::certificate("bob-secret.pgp").into(), CheckSigning), Some(Ok("Digest prefix MUST be set correctly".into()))), ("Sig w/corrupted prefix".into(), (corrupt_hash_digest(sig.clone())?.to_vec()?.into(), CheckCorruptedSig), None), Loading @@ -143,13 +210,6 @@ impl ConsumptionTest<(Data, Variant), (Data, Vec<Verification>)> for DigestPrefi -> Result<(Data, Vec<Verification>)> { match variant { CheckSigning => { Ok((pgp.sop() .sign() .key(artifact) .data(crate::tests::MESSAGE)?, vec![])) }, CheckCorruptedSig => { Ok((Default::default(), pgp.sop() Loading @@ -171,26 +231,10 @@ impl ConsumptionTest<(Data, Variant), (Data, Vec<Verification>)> for DigestPrefi fn check_consumer(&self, (_, variant): &(Data, Variant), (result, verifications): &(Data, Vec<Verification>), (_, verifications): &(Data, Vec<Verification>), _: &Option<Expectation>) -> Result<()> { match variant { CheckSigning => { let p = Packet::from_bytes(result)?; let s: Signature = p.downcast() .map_err(|p| anyhow::anyhow!("Expected a signature packet, \ got {:?}", p))?; let mut h = s.hash_algo().context()?; h.update(crate::tests::MESSAGE); s.hash(&mut h); let d = h.into_digest()?; ensure!(s.digest_prefix() == &d[..2], CheckError::HardFailure(format!( "Digest prefix mismatch. Got: {:?}, want: {:?}.", s.digest_prefix(), &d[..2]))); Ok(()) }, CheckCorruptedSig => { let _ = verifications; // XXX Ok(()) Loading @@ -202,3 +246,4 @@ impl ConsumptionTest<(Data, Variant), (Data, Vec<Verification>)> for DigestPrefi } } }