Verified Commit 9d8ff452 authored by Justus Winter's avatar Justus Winter
Browse files

Split the digest prefix test into two, one of which is sign-only.

parent 6ad027da
Loading
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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(())
}
+91 −46
Original line number Diff line number Diff line
@@ -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()
@@ -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()
@@ -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()),
@@ -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>)>>
    {
@@ -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),
@@ -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()
@@ -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(())
@@ -202,3 +246,4 @@ impl ConsumptionTest<(Data, Variant), (Data, Vec<Verification>)> for DigestPrefi
        }
    }
}