summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-03-31 17:16:54 +0200
committerJustus Winter <justus@sequoia-pgp.org>2020-04-01 16:15:00 +0200
commit9af04b06c72571867ce8c21fd571d3693397df12 (patch)
tree217802d8c2340d7b6e3d824509c4d38b11184a43
parent6fc293ea80f7331c7262174f93dc44d3be1302ba (diff)
openpgp: Implement Arbitrary for Signature.
-rw-r--r--openpgp/src/packet/mod.rs21
-rw-r--r--openpgp/src/packet/signature/mod.rs90
-rw-r--r--openpgp/src/packet/signature/subpacket.rs103
-rw-r--r--openpgp/src/types/mod.rs18
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