diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2020-03-31 17:16:54 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2020-04-01 16:15:00 +0200 |
commit | 9af04b06c72571867ce8c21fd571d3693397df12 (patch) | |
tree | 217802d8c2340d7b6e3d824509c4d38b11184a43 | |
parent | 6fc293ea80f7331c7262174f93dc44d3be1302ba (diff) |
openpgp: Implement Arbitrary for Signature.
-rw-r--r-- | openpgp/src/packet/mod.rs | 21 | ||||
-rw-r--r-- | openpgp/src/packet/signature/mod.rs | 90 | ||||
-rw-r--r-- | openpgp/src/packet/signature/subpacket.rs | 103 | ||||
-rw-r--r-- | openpgp/src/types/mod.rs | 18 |
4 files changed, 221 insertions, 11 deletions
diff --git a/openpgp/src/packet/mod.rs b/openpgp/src/packet/mod.rs index 8e2c029e..f4713ec3 100644 --- a/openpgp/src/packet/mod.rs +++ b/openpgp/src/packet/mod.rs @@ -234,16 +234,17 @@ impl<'a> DerefMut for Packet { impl Arbitrary for Packet { fn arbitrary<G: Gen>(g: &mut G) -> Self { use rand::Rng; - match g.gen_range(0, 9) { - 0 => OnePassSig::arbitrary(g).into(), - 1 => Marker::arbitrary(g).into(), - 2 => Trust::arbitrary(g).into(), - 3 => UserID::arbitrary(g).into(), - 4 => UserAttribute::arbitrary(g).into(), - 5 => Literal::arbitrary(g).into(), - 6 => CompressedData::arbitrary(g).into(), - 7 => PKESK::arbitrary(g).into(), - 8 => SKESK::arbitrary(g).into(), + match g.gen_range(0, 10) { + 0 => Signature::arbitrary(g).into(), + 1 => OnePassSig::arbitrary(g).into(), + 2 => Marker::arbitrary(g).into(), + 3 => Trust::arbitrary(g).into(), + 4 => UserID::arbitrary(g).into(), + 5 => UserAttribute::arbitrary(g).into(), + 6 => Literal::arbitrary(g).into(), + 7 => CompressedData::arbitrary(g).into(), + 8 => PKESK::arbitrary(g).into(), + 9 => SKESK::arbitrary(g).into(), _ => unreachable!(), } } diff --git a/openpgp/src/packet/signature/mod.rs b/openpgp/src/packet/signature/mod.rs index 6800050b..754e3b6b 100644 --- a/openpgp/src/packet/signature/mod.rs +++ b/openpgp/src/packet/signature/mod.rs @@ -2,6 +2,7 @@ use std::fmt; use std::ops::{Deref, DerefMut}; +use quickcheck::{Arbitrary, Gen}; use crate::Error; use crate::Result; @@ -27,6 +28,28 @@ use crate::packet::signature::subpacket::{ SubpacketAreas, }; +/// Like quickcheck::Arbitrary, but bounded. +trait ArbitraryBounded { + /// Generates an arbitrary value, but only recurses if `depth > + /// 0`. + fn arbitrary_bounded<G: Gen>(g: &mut G, depth: usize) -> Self; +} + +/// Default depth when implementing Arbitrary using ArbitraryBounded. +const DEFAULT_ARBITRARY_DEPTH: usize = 2; + +macro_rules! impl_arbitrary_with_bound { + ($typ:path) => { + impl Arbitrary for $typ { + fn arbitrary<G: Gen>(g: &mut G) -> Self { + Self::arbitrary_bounded( + g, + crate::packet::signature::DEFAULT_ARBITRARY_DEPTH) + } + } + } +} + pub mod subpacket; /// Builds a signature packet. @@ -78,6 +101,22 @@ pub struct Builder { subpackets: SubpacketAreas, } +impl ArbitraryBounded for Builder { + fn arbitrary_bounded<G: Gen>(g: &mut G, depth: usize) -> Self { + Builder { + // XXX: Make this more interesting once we dig other + // versions. + version: 4, + typ: Arbitrary::arbitrary(g), + pk_algo: PublicKeyAlgorithm::arbitrary_for_signing(g), + hash_algo: Arbitrary::arbitrary(g), + subpackets: ArbitraryBounded::arbitrary_bounded(g, depth), + } + } +} + +impl_arbitrary_with_bound!(Builder); + impl Deref for Builder { type Target = SubpacketAreas; @@ -1173,6 +1212,57 @@ impl From<Signature4> for super::Signature { } } +impl ArbitraryBounded for super::Signature { + fn arbitrary_bounded<G: Gen>(g: &mut G, depth: usize) -> Self { + Signature4::arbitrary_bounded(g, depth).into() + } +} + +impl_arbitrary_with_bound!(super::Signature); + +impl ArbitraryBounded for Signature4 { + fn arbitrary_bounded<G: Gen>(g: &mut G, depth: usize) -> Self { + use mpis::MPI; + use PublicKeyAlgorithm::*; + + let fields = Builder::arbitrary_bounded(g, depth); + #[allow(deprecated)] + let mpis = match fields.pk_algo() { + RSAEncryptSign | RSASign => mpis::Signature::RSA { + s: MPI::arbitrary(g), + }, + + DSA => mpis::Signature::DSA { + r: MPI::arbitrary(g), + s: MPI::arbitrary(g), + }, + + EdDSA => mpis::Signature::EdDSA { + r: MPI::arbitrary(g), + s: MPI::arbitrary(g), + }, + + ECDSA => mpis::Signature::ECDSA { + r: MPI::arbitrary(g), + s: MPI::arbitrary(g), + }, + + _ => unreachable!(), + }; + + Signature4 { + common: Arbitrary::arbitrary(g), + fields, + digest_prefix: [Arbitrary::arbitrary(g), + Arbitrary::arbitrary(g)], + mpis, + computed_digest: None, + level: 0, + } + } +} + +impl_arbitrary_with_bound!(Signature4); #[cfg(test)] mod test { diff --git a/openpgp/src/packet/signature/subpacket.rs b/openpgp/src/packet/signature/subpacket.rs index 83fcebc9..ec5badcc 100644 --- a/openpgp/src/packet/signature/subpacket.rs +++ b/openpgp/src/packet/signature/subpacket.rs @@ -71,7 +71,7 @@ use crate::{ Error, Result, packet::Signature, - packet::signature::{self, Signature4}, + packet::signature::{self, Signature4, ArbitraryBounded}, packet::key, packet::Key, Fingerprint, @@ -340,6 +340,21 @@ pub struct SubpacketArea { parsed: Mutex<RefCell<Option<HashMap<SubpacketTag, usize>>>>, } +impl ArbitraryBounded for SubpacketArea { + fn arbitrary_bounded<G: Gen>(g: &mut G, depth: usize) -> Self { + use rand::Rng; + + let mut a = Self::default(); + for _ in 0..g.gen_range(0, 32) { + let _ = a.add(ArbitraryBounded::arbitrary_bounded(g, depth)); + } + + a + } +} + +impl_arbitrary_with_bound!(SubpacketArea); + impl Default for SubpacketArea { fn default() -> Self { Self::new(Default::default()) @@ -516,6 +531,16 @@ pub struct NotationData { value: Vec<u8>, } +impl Arbitrary for NotationData { + fn arbitrary<G: Gen>(g: &mut G) -> Self { + NotationData { + flags: Arbitrary::arbitrary(g), + name: Arbitrary::arbitrary(g), + value: Arbitrary::arbitrary(g), + } + } +} + impl NotationData { /// Creates a new Notation Data subpacket payload. pub fn new<N, V, F>(name: N, value: V, flags: F) -> Self @@ -562,6 +587,12 @@ impl From<u32> for NotationDataFlags { } } +impl Arbitrary for NotationDataFlags { + fn arbitrary<G: Gen>(g: &mut G) -> Self { + u32::arbitrary(g).into() + } +} + impl fmt::Debug for NotationDataFlags { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut d = f.debug_struct("NotationDataFlags"); @@ -716,6 +747,58 @@ pub enum SubpacketValue { #[doc(hidden)] __Nonexhaustive, } +impl ArbitraryBounded for SubpacketValue { + fn arbitrary_bounded<G: Gen>(g: &mut G, depth: usize) -> Self { + use rand::Rng; + use self::SubpacketValue::*; + loop { + break match g.gen_range(0, 26) { + 0 => SignatureCreationTime(Arbitrary::arbitrary(g)), + 1 => SignatureExpirationTime(Arbitrary::arbitrary(g)), + 2 => ExportableCertification(Arbitrary::arbitrary(g)), + 3 => TrustSignature { + level: Arbitrary::arbitrary(g), + trust: Arbitrary::arbitrary(g), + }, + 4 => RegularExpression(Arbitrary::arbitrary(g)), + 5 => Revocable(Arbitrary::arbitrary(g)), + 6 => KeyExpirationTime(Arbitrary::arbitrary(g)), + 7 => PreferredSymmetricAlgorithms(Arbitrary::arbitrary(g)), + 8 => RevocationKey(Arbitrary::arbitrary(g)), + 9 => Issuer(Arbitrary::arbitrary(g)), + 10 => NotationData(Arbitrary::arbitrary(g)), + 11 => PreferredHashAlgorithms(Arbitrary::arbitrary(g)), + 12 => PreferredCompressionAlgorithms(Arbitrary::arbitrary(g)), + 13 => KeyServerPreferences(Arbitrary::arbitrary(g)), + 14 => PreferredKeyServer(Arbitrary::arbitrary(g)), + 15 => PrimaryUserID(Arbitrary::arbitrary(g)), + 16 => PolicyURI(Arbitrary::arbitrary(g)), + 17 => KeyFlags(Arbitrary::arbitrary(g)), + 18 => SignersUserID(Arbitrary::arbitrary(g)), + 19 => ReasonForRevocation { + code: Arbitrary::arbitrary(g), + reason: Arbitrary::arbitrary(g), + }, + 20 => Features(Arbitrary::arbitrary(g)), + 21 => SignatureTarget { + pk_algo: Arbitrary::arbitrary(g), + hash_algo: Arbitrary::arbitrary(g), + digest: Arbitrary::arbitrary(g), + }, + 22 if depth == 0 => continue, // Don't recurse, try again. + 22 => EmbeddedSignature( + ArbitraryBounded::arbitrary_bounded(g, depth - 1)), + 23 => IssuerFingerprint(Arbitrary::arbitrary(g)), + 24 => PreferredAEADAlgorithms(Arbitrary::arbitrary(g)), + 25 => IntendedRecipient(Arbitrary::arbitrary(g)), + _ => unreachable!(), + } + } + } +} + +impl_arbitrary_with_bound!(SubpacketValue); + impl SubpacketValue { /// Returns the subpacket tag for this value. pub fn tag(&self) -> SubpacketTag { @@ -778,6 +861,15 @@ pub struct Subpacket { value: SubpacketValue, } +impl ArbitraryBounded for Subpacket { + fn arbitrary_bounded<G: Gen>(g: &mut G, depth: usize) -> Self { + Subpacket::new(ArbitraryBounded::arbitrary_bounded(g, depth), + Arbitrary::arbitrary(g)).unwrap() + } +} + +impl_arbitrary_with_bound!(Subpacket); + impl fmt::Debug for Subpacket { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut s = f.debug_struct("Subpacket"); @@ -1553,6 +1645,15 @@ pub struct SubpacketAreas { unhashed_area: SubpacketArea, } +impl ArbitraryBounded for SubpacketAreas { + fn arbitrary_bounded<G: Gen>(g: &mut G, depth: usize) -> Self { + SubpacketAreas::new(ArbitraryBounded::arbitrary_bounded(g, depth), + ArbitraryBounded::arbitrary_bounded(g, depth)) + } +} + +impl_arbitrary_with_bound!(SubpacketAreas); + impl Deref for SubpacketAreas { type Target = SubpacketArea; diff --git a/openpgp/src/types/mod.rs b/openpgp/src/types/mod.rs index 93516f16..0e7dff89 100644 --- a/openpgp/src/types/mod.rs +++ b/openpgp/src/types/mod.rs @@ -187,6 +187,24 @@ impl Arbitrary for PublicKeyAlgorithm { } } +impl PublicKeyAlgorithm { + pub(crate) fn arbitrary_for_signing<G: Gen>(g: &mut G) -> Self { + use rand::Rng; + use self::PublicKeyAlgorithm::*; + #[allow(deprecated)] + let a = match g.gen_range(0, 5) { + 0 => RSAEncryptSign, + 1 => RSASign, + 2 => DSA, + 3 => ECDSA, + 4 => EdDSA, + _ => unreachable!(), + }; + assert!(a.for_signing()); + a + } +} + /// Elliptic curves used in OpenPGP. /// /// `PublicKeyAlgorithm` does not differentiate between elliptic |