summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openpgp/src/lib.rs8
-rw-r--r--openpgp/src/packet/aed.rs26
-rw-r--r--openpgp/src/packet/compressed_data.rs20
-rw-r--r--openpgp/src/packet/key/mod.rs16
-rw-r--r--openpgp/src/packet/literal.rs24
-rw-r--r--openpgp/src/packet/marker.rs17
-rw-r--r--openpgp/src/packet/mdc.rs9
-rw-r--r--openpgp/src/packet/mod.rs78
-rw-r--r--openpgp/src/packet/one_pass_sig.rs27
-rw-r--r--openpgp/src/packet/pkesk.rs22
-rw-r--r--openpgp/src/packet/seip.rs18
-rw-r--r--openpgp/src/packet/signature/mod.rs60
-rw-r--r--openpgp/src/packet/skesk.rs26
-rw-r--r--openpgp/src/packet/trust.rs18
-rw-r--r--openpgp/src/packet/unknown.rs5
-rw-r--r--openpgp/src/packet/user_attribute.rs32
-rw-r--r--openpgp/src/packet/userid/mod.rs13
17 files changed, 193 insertions, 226 deletions
diff --git a/openpgp/src/lib.rs b/openpgp/src/lib.rs
index 5ac45b36..44480a45 100644
--- a/openpgp/src/lib.rs
+++ b/openpgp/src/lib.rs
@@ -332,6 +332,14 @@ pub enum Error {
///
/// Note: This enum cannot be exhaustively matched to allow future
/// extensions.
+///
+/// # A note on equality
+///
+/// We define equality on `Packet` like equality of the serialized
+/// form of the packet bodies defined by RFC4880, i.e. two packets are
+/// considered equal if and only if their serialized form is equal,
+/// modulo the OpenPGP framing (`CTB` and length style, potential
+/// partial body encoding).
#[derive(Debug)]
#[derive(PartialEq, Eq, Hash, Clone)]
pub enum Packet {
diff --git a/openpgp/src/packet/aed.rs b/openpgp/src/packet/aed.rs
index 16a2ee61..a84fcd01 100644
--- a/openpgp/src/packet/aed.rs
+++ b/openpgp/src/packet/aed.rs
@@ -17,7 +17,9 @@ use crate::Result;
/// [Section 5.16 of RFC 4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-05#section-5.16
///
/// This feature is [experimental](../../index.html#experimental-features).
-#[derive(Clone, Debug)]
+// IMPORTANT: If you add fields to this struct, you need to explicitly
+// IMPORTANT: implement PartialEq, Eq, and Hash.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct AED1 {
/// CTB packet header fields.
pub(crate) common: packet::Common,
@@ -47,28 +49,6 @@ impl std::ops::DerefMut for AED1 {
}
}
-impl PartialEq for AED1 {
- fn eq(&self, other: &AED1) -> bool {
- self.sym_algo == other.sym_algo
- && self.aead == other.aead
- && self.chunk_size == other.chunk_size
- && self.iv == other.iv
- && self.container == other.container
- }
-}
-
-impl Eq for AED1 {}
-
-impl std::hash::Hash for AED1 {
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
- std::hash::Hash::hash(&self.sym_algo, state);
- std::hash::Hash::hash(&self.aead, state);
- std::hash::Hash::hash(&self.chunk_size, state);
- std::hash::Hash::hash(&self.iv, state);
- std::hash::Hash::hash(&self.container, state);
- }
-}
-
impl AED1 {
/// Creates a new AED1 object.
pub fn new(sym_algo: SymmetricAlgorithm,
diff --git a/openpgp/src/packet/compressed_data.rs b/openpgp/src/packet/compressed_data.rs
index c9bd74b6..edb858bb 100644
--- a/openpgp/src/packet/compressed_data.rs
+++ b/openpgp/src/packet/compressed_data.rs
@@ -14,7 +14,9 @@ use crate::types::CompressionAlgorithm;
/// of a `CompressedData` packet.
///
/// [Section 5.6 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.6
-#[derive(Clone)]
+// IMPORTANT: If you add fields to this struct, you need to explicitly
+// IMPORTANT: implement PartialEq, Eq, and Hash.
+#[derive(Clone, PartialEq, Eq, Hash)]
pub struct CompressedData {
/// CTB packet header fields.
pub(crate) common: packet::Common,
@@ -38,22 +40,6 @@ impl std::ops::DerefMut for CompressedData {
}
}
-impl PartialEq for CompressedData {
- fn eq(&self, other: &CompressedData) -> bool {
- self.algo == other.algo
- && self.container == other.container
- }
-}
-
-impl Eq for CompressedData {}
-
-impl std::hash::Hash for CompressedData {
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
- std::hash::Hash::hash(&self.algo, state);
- std::hash::Hash::hash(&self.container, state);
- }
-}
-
impl fmt::Debug for CompressedData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("CompressedData")
diff --git a/openpgp/src/packet/key/mod.rs b/openpgp/src/packet/key/mod.rs
index 74ce8445..722bead4 100644
--- a/openpgp/src/packet/key/mod.rs
+++ b/openpgp/src/packet/key/mod.rs
@@ -895,6 +895,20 @@ impl<P, R> Key4<P, R>
self.pk_algo.cmp(&b.pk_algo)
}
+
+ /// This method tests for self and other values to be equal modulo
+ /// the secret bits.
+ ///
+ /// This returns true if the public MPIs, creation time and
+ /// algorithm of the two `Key4`s match. This does not consider
+ /// the packet's encoding, packet's tag or the secret key
+ /// material.
+ pub fn public_eq<PB, RB>(&self, b: &Key4<PB, RB>) -> bool
+ where PB: key::KeyParts,
+ RB: key::KeyRole,
+ {
+ self.public_cmp(b) == Ordering::Equal
+ }
}
impl<R> Key4<key::PublicParts, R>
@@ -1522,6 +1536,8 @@ impl SecretKeyMaterial {
/// demand. See [`crypto::mem::Encrypted`] for details.
///
/// [`crypto::mem::Encrypted`]: ../../crypto/mem/struct.Encrypted.html
+// Note: PartialEq, Eq, and Hash on mem::Encrypted does the right
+// thing.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Unencrypted {
/// MPIs of the secret key.
diff --git a/openpgp/src/packet/literal.rs b/openpgp/src/packet/literal.rs
index 2e66e337..b0c03bb5 100644
--- a/openpgp/src/packet/literal.rs
+++ b/openpgp/src/packet/literal.rs
@@ -21,7 +21,9 @@ use crate::Result;
/// See [Section 5.9 of RFC 4880] for details.
///
/// [Section 5.9 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.9
-#[derive(Clone)]
+// IMPORTANT: If you add fields to this struct, you need to explicitly
+// IMPORTANT: implement PartialEq, Eq, and Hash.
+#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Literal {
/// CTB packet header fields.
pub(crate) common: packet::Common,
@@ -44,26 +46,6 @@ pub struct Literal {
container: packet::Container,
}
-impl PartialEq for Literal {
- fn eq(&self, other: &Literal) -> bool {
- self.format == other.format
- && self.filename == other.filename
- && self.date == other.date
- && self.container == other.container
- }
-}
-
-impl Eq for Literal {}
-
-impl std::hash::Hash for Literal {
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
- std::hash::Hash::hash(&self.format, state);
- std::hash::Hash::hash(&self.filename, state);
- std::hash::Hash::hash(&self.date, state);
- std::hash::Hash::hash(&self.container, state);
- }
-}
-
impl fmt::Debug for Literal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let filename = if let Some(ref filename) = self.filename {
diff --git a/openpgp/src/packet/marker.rs b/openpgp/src/packet/marker.rs
index 9e1e6718..8217901c 100644
--- a/openpgp/src/packet/marker.rs
+++ b/openpgp/src/packet/marker.rs
@@ -8,25 +8,14 @@ use crate::Packet;
/// See [Section 5.8 of RFC 4880] for details.
///
/// [Section 5.8 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.8
-#[derive(Clone, Debug)]
+// IMPORTANT: If you add fields to this struct, you need to explicitly
+// IMPORTANT: implement PartialEq, Eq, and Hash.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Marker {
/// CTB packet header fields.
pub(crate) common: packet::Common,
}
-impl PartialEq for Marker {
- fn eq(&self, _other: &Marker) -> bool {
- true
- }
-}
-
-impl Eq for Marker {}
-
-impl std::hash::Hash for Marker {
- fn hash<H: std::hash::Hasher>(&self, _state: &mut H) {
- }
-}
-
impl Marker {
pub(crate) const BODY: &'static [u8] = &[0x50, 0x47, 0x50];
}
diff --git a/openpgp/src/packet/mdc.rs b/openpgp/src/packet/mdc.rs
index 9ca824a7..704e1c0a 100644
--- a/openpgp/src/packet/mdc.rs
+++ b/openpgp/src/packet/mdc.rs
@@ -8,6 +8,11 @@ use crate::Packet;
/// SEIP packet. See [Section 5.14 of RFC 4880] for details.
///
/// [Section 5.14 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.14
+///
+/// # A note on equality
+///
+/// Two `Signature` packets are considered equal if their serialized
+/// form is equal. This excludes the computed digest.
#[derive(Clone, Debug)]
pub struct MDC {
/// CTB packet header fields.
@@ -20,7 +25,8 @@ pub struct MDC {
impl PartialEq for MDC {
fn eq(&self, other: &MDC) -> bool {
- self.digest == other.digest
+ self.common == other.common
+ && self.digest == other.digest
}
}
@@ -28,6 +34,7 @@ impl Eq for MDC {}
impl std::hash::Hash for MDC {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ std::hash::Hash::hash(&self.common, state);
std::hash::Hash::hash(&self.digest, state);
}
}
diff --git a/openpgp/src/packet/mod.rs b/openpgp/src/packet/mod.rs
index 621a11fb..976d6ecc 100644
--- a/openpgp/src/packet/mod.rs
+++ b/openpgp/src/packet/mod.rs
@@ -112,6 +112,16 @@ impl<'a> DerefMut for Packet {
/// Fields used by multiple packet types.
#[derive(Debug, Clone)]
pub struct Common {
+ // In the future, this structure will hold the parsed CTB, packet
+ // length, and lengths of chunks of partial body encoded packets.
+ // This will allow for bit-perfect roundtripping of parsed
+ // packets. Since we consider Packets to be equal if their
+ // serialized form is equal modulo CTB, packet length encoding,
+ // and chunk lengths, this structure has trivial implementations
+ // for PartialEq, Eq, PartialOrd, Ord, and Hash, so that we can
+ // derive PartialEq, Eq, PartialOrd, Ord, and Hash for most
+ // packets.
+
/// XXX: Prevents trivial matching on this structure. Remove once
/// this structure actually gains some fields.
dummy: std::marker::PhantomData<()>,
@@ -124,6 +134,34 @@ impl Default for Common {
}
}
}
+
+impl PartialEq for Common {
+ fn eq(&self, _: &Common) -> bool {
+ // Don't compare anything.
+ true
+ }
+}
+
+impl Eq for Common {}
+
+impl PartialOrd for Common {
+ fn partial_cmp(&self, _: &Self) -> Option<std::cmp::Ordering> {
+ Some(std::cmp::Ordering::Equal)
+ }
+}
+
+impl Ord for Common {
+ fn cmp(&self, _: &Self) -> std::cmp::Ordering {
+ std::cmp::Ordering::Equal
+ }
+}
+
+impl std::hash::Hash for Common {
+ fn hash<H: std::hash::Hasher>(&self, _: &mut H) {
+ // Don't hash anything.
+ }
+}
+
/// A `Iter` iterates over the *contents* of a packet in
/// depth-first order. It starts by returning the current packet.
@@ -313,6 +351,21 @@ fn packet_path_iter() {
///
/// Note: This enum cannot be exhaustively matched to allow future
/// extensions.
+///
+/// # A note on equality
+///
+/// Two `Signature` packets are considered equal if their serialized
+/// form is equal. Notably this includes the unhashed subpacket area,
+/// but excludes the computed digest and signature level.
+///
+/// A consequence of considering packets in the unhashed subpacket
+/// area is that an adversary can take a valid signature and create
+/// many distinct but valid signatures by changing the unhashed
+/// subpacket area. This has the potential of creating a denial of
+/// service vector. To protect against this, consider using
+/// [`Signature::normalized_eq`].
+///
+/// [`Signature::normalized_eq`]: #method.normalized_eq
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub enum Signature {
/// Signature packet version 4.
@@ -523,6 +576,17 @@ impl From<SKESK> for Packet {
///
/// Note: This enum cannot be exhaustively matched to allow future
/// extensions.
+///
+/// # A note on equality
+///
+/// Two `Key` packets are considered equal if their serialized form is
+/// equal. Notably this includes the secret key material, but
+/// excludes the `KeyParts` and `KeyRole` marker traits.
+///
+/// To compare only the public bits of `Key` packets, use
+/// [`Key::public_eq`].
+///
+/// [`Key::public_eq`]: #method.public_eq
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub enum Key<P: key::KeyParts, R: key::KeyRole> {
/// Key packet version 4.
@@ -567,6 +631,20 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> {
(_, Key::__Nonexhaustive) => unreachable!(),
}
}
+
+ /// This method tests for self and other values to be equal modulo
+ /// the secret bits.
+ ///
+ /// This returns true if the public MPIs, creation time and
+ /// algorithm of the two `Key`s match. This does not consider
+ /// the packet's encoding, packet's tag or the secret key
+ /// material.
+ pub fn public_eq<PB, RB>(&self, b: &Key<PB, RB>) -> bool
+ where PB: key::KeyParts,
+ RB: key::KeyRole,
+ {
+ self.public_cmp(b) == std::cmp::Ordering::Equal
+ }
}
impl From<Key<key::PublicParts, key::PrimaryRole>> for Packet {
diff --git a/openpgp/src/packet/one_pass_sig.rs b/openpgp/src/packet/one_pass_sig.rs
index 62ef88e6..0fdad6e2 100644
--- a/openpgp/src/packet/one_pass_sig.rs
+++ b/openpgp/src/packet/one_pass_sig.rs
@@ -5,7 +5,6 @@
//! [Section 5.4 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.4
use std::fmt;
-use std::hash::{Hash, Hasher};
use quickcheck::{Arbitrary, Gen};
use crate::Error;
@@ -23,7 +22,9 @@ use crate::SignatureType;
/// See [Section 5.4 of RFC 4880] for details.
///
/// [Section 5.4 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.4
-#[derive(Clone)]
+// IMPORTANT: If you add fields to this struct, you need to explicitly
+// IMPORTANT: implement PartialEq, Eq, and Hash.
+#[derive(Clone, PartialEq, Eq, Hash)]
pub struct OnePassSig3 {
/// CTB packet header fields.
pub(crate) common: packet::Common,
@@ -52,28 +53,6 @@ impl fmt::Debug for OnePassSig3 {
}
}
-impl PartialEq for OnePassSig3 {
- fn eq(&self, other: &OnePassSig3) -> bool {
- self.typ == other.typ
- && self.hash_algo == other.hash_algo
- && self.pk_algo == other.pk_algo
- && self.issuer == other.issuer
- && self.last == other.last
- }
-}
-
-impl Eq for OnePassSig3 {}
-
-impl Hash for OnePassSig3 {
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.typ.hash(state);
- self.hash_algo.hash(state);
- self.pk_algo.hash(state);
- self.issuer.hash(state);
- self.last.hash(state);
- }
-}
-
impl OnePassSig3 {
/// Returns a new `Signature` packet.
pub fn new(typ: SignatureType) -> Self {
diff --git a/openpgp/src/packet/pkesk.rs b/openpgp/src/packet/pkesk.rs
index e048cff8..996b5a7a 100644
--- a/openpgp/src/packet/pkesk.rs
+++ b/openpgp/src/packet/pkesk.rs
@@ -26,7 +26,9 @@ use crate::packet;
/// [Section 5.1 of RFC 4880] for details.
///
/// [Section 5.1 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.1
-#[derive(Clone, Debug)]
+// IMPORTANT: If you add fields to this struct, you need to explicitly
+// IMPORTANT: implement PartialEq, Eq, and Hash.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct PKESK3 {
/// CTB header fields.
pub(crate) common: packet::Common,
@@ -38,24 +40,6 @@ pub struct PKESK3 {
esk: Ciphertext,
}
-impl PartialEq for PKESK3 {
- fn eq(&self, other: &PKESK3) -> bool {
- self.recipient == other.recipient
- && self.pk_algo == other.pk_algo
- && self.esk == other.esk
- }
-}
-
-impl Eq for PKESK3 {}
-
-impl std::hash::Hash for PKESK3 {
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
- std::hash::Hash::hash(&self.recipient, state);
- std::hash::Hash::hash(&self.pk_algo, state);
- std::hash::Hash::hash(&self.esk, state);
- }
-}
-
impl PKESK3 {
/// Creates a new PKESK3 packet.
pub fn new(recipient: KeyID, pk_algo: PublicKeyAlgorithm,
diff --git a/openpgp/src/packet/seip.rs b/openpgp/src/packet/seip.rs
index 91785666..76487bef 100644
--- a/openpgp/src/packet/seip.rs
+++ b/openpgp/src/packet/seip.rs
@@ -14,7 +14,9 @@ use crate::Packet;
/// 4880] for details.
///
/// [Section 5.13 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.13
-#[derive(Clone, Debug)]
+// IMPORTANT: If you add fields to this struct, you need to explicitly
+// IMPORTANT: implement PartialEq, Eq, and Hash.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct SEIP1 {
/// CTB packet header fields.
pub(crate) common: packet::Common,
@@ -36,20 +38,6 @@ impl std::ops::DerefMut for SEIP1 {
}
}
-impl PartialEq for SEIP1 {
- fn eq(&self, other: &SEIP1) -> bool {
- self.container == other.container
- }
-}
-
-impl Eq for SEIP1 {}
-
-impl std::hash::Hash for SEIP1 {
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
- std::hash::Hash::hash(&self.container, state);
- }
-}
-
impl SEIP1 {
/// Creates a new SEIP1 packet.
pub fn new() -> Self {
diff --git a/openpgp/src/packet/signature/mod.rs b/openpgp/src/packet/signature/mod.rs
index ad59d927..6800050b 100644
--- a/openpgp/src/packet/signature/mod.rs
+++ b/openpgp/src/packet/signature/mod.rs
@@ -62,6 +62,8 @@ pub mod subpacket;
/// [`set_signature_creation_time`].
///
/// [`set_signature_creation_time`]: #method.set_signature_creation_time
+// IMPORTANT: If you add fields to this struct, you need to explicitly
+// IMPORTANT: implement PartialEq, Eq, and Hash.
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct Builder {
/// Version of the signature packet. Must be 4.
@@ -455,11 +457,8 @@ impl PartialEq for Signature4 {
/// signatures using this predicate.
fn eq(&self, other: &Signature4) -> bool {
self.mpis == other.mpis
- && self.fields.version == other.fields.version
- && self.fields.typ == other.fields.typ
- && self.fields.pk_algo == other.fields.pk_algo
- && self.fields.hash_algo == other.fields.hash_algo
- && self.fields.hashed_area() == other.fields.hashed_area()
+ && self.fields == other.fields
+ && self.digest_prefix == other.digest_prefix
}
}
@@ -468,12 +467,9 @@ impl Eq for Signature4 {}
impl std::hash::Hash for Signature4 {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
use std::hash::Hash as StdHash;
- self.fields.version.hash(state);
- self.fields.typ.hash(state);
- self.fields.pk_algo.hash(state);
- self.fields.hash_algo.hash(state);
- self.fields.hashed_area().hash(state);
StdHash::hash(&self.mpis, state);
+ StdHash::hash(&self.fields, state);
+ self.digest_prefix.hash(state);
}
}
@@ -609,6 +605,26 @@ impl crate::packet::Signature {
issuers
}
+ /// Compares Signatures ignoring the unhashed subpacket area.
+ ///
+ /// We ignore the unhashed subpacket area when comparing
+ /// signatures. This prevents a malicious party to take valid
+ /// signatures, add subpackets to the unhashed area, yielding
+ /// valid but distinct signatures.
+ ///
+ /// The problem we are trying to avoid here is signature spamming.
+ /// Ignoring the unhashed subpackets means that we can deduplicate
+ /// signatures using this predicate.
+ pub fn normalized_eq(&self, other: &Signature) -> bool {
+ self.mpis() == other.mpis()
+ && self.version() == other.version()
+ && self.typ() == other.typ()
+ && self.pk_algo() == other.pk_algo()
+ && self.hash_algo() == other.hash_algo()
+ && self.hashed_area() == other.hashed_area()
+ && self.digest_prefix() == other.digest_prefix()
+ }
+
/// Normalizes the signature.
///
/// This function normalizes the *unhashed* signature subpackets.
@@ -1461,16 +1477,20 @@ mod test {
let keyid = KeyID::from(&fp);
// First, make sure any superfluous subpackets are removed,
- // yet the Issuer and EmbeddedSignature ones are kept.
+ // yet the Issuer, IssuerFingerprint and EmbeddedSignature
+ // ones are kept.
let mut builder = Builder::new(SignatureType::Text);
- // This subpacket does not belong there, and should be
- // removed.
builder.unhashed_area_mut().add(Subpacket::new(
SubpacketValue::IssuerFingerprint(fp.clone()), false).unwrap())
.unwrap();
builder.unhashed_area_mut().add(Subpacket::new(
SubpacketValue::Issuer(keyid.clone()), false).unwrap())
.unwrap();
+ // This subpacket does not belong there, and should be
+ // removed.
+ builder.unhashed_area_mut().add(Subpacket::new(
+ SubpacketValue::PreferredSymmetricAlgorithms(Vec::new()),
+ false).unwrap()).unwrap();
// Build and add an embedded sig.
let embedded_sig = Builder::new(SignatureType::PrimaryKeyBinding)
@@ -1480,22 +1500,14 @@ mod test {
.unwrap()).unwrap();
let sig = builder.sign_hash(&mut pair,
hash.clone()).unwrap().normalize();
- assert_eq!(sig.unhashed_area().iter().count(), 2);
+ assert_eq!(sig.unhashed_area().iter().count(), 3);
assert_eq!(*sig.unhashed_area().iter().nth(0).unwrap(),
Subpacket::new(SubpacketValue::Issuer(keyid.clone()),
false).unwrap());
assert_eq!(sig.unhashed_area().iter().nth(1).unwrap().tag(),
SubpacketTag::EmbeddedSignature);
-
- // Now, make sure that an Issuer subpacket is synthesized from
- // the hashed area for compatibility.
- let sig = Builder::new(SignatureType::Text)
- .set_issuer_fingerprint(fp).unwrap()
- .sign_hash(&mut pair,
- hash.clone()).unwrap().normalize();
- assert_eq!(sig.unhashed_area().iter().count(), 1);
- assert_eq!(*sig.unhashed_area().iter().nth(0).unwrap(),
- Subpacket::new(SubpacketValue::Issuer(keyid.clone()),
+ assert_eq!(*sig.unhashed_area().iter().nth(2).unwrap(),
+ Subpacket::new(SubpacketValue::IssuerFingerprint(fp.clone()),
false).unwrap());
}
diff --git a/openpgp/src/packet/skesk.rs b/openpgp/src/packet/skesk.rs
index c9b032c7..13fc2334 100644
--- a/openpgp/src/packet/skesk.rs
+++ b/openpgp/src/packet/skesk.rs
@@ -54,7 +54,9 @@ impl Arbitrary for SKESK {
/// 4880] for details.
///
/// [Section 5.3 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.3
-#[derive(Clone, Debug)]
+// IMPORTANT: If you add fields to this struct, you need to explicitly
+// IMPORTANT: implement PartialEq, Eq, and Hash.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct SKESK4 {
/// CTB header fields.
pub(crate) common: packet::Common,
@@ -71,26 +73,6 @@ pub struct SKESK4 {
esk: Option<Vec<u8>>,
}
-impl PartialEq for SKESK4 {
- fn eq(&self, other: &SKESK4) -> bool {
- self.version == other.version
- && self.sym_algo == other.sym_algo
- && self.s2k == other.s2k
- && self.esk == other.esk
- }
-}
-
-impl Eq for SKESK4 {}
-
-impl std::hash::Hash for SKESK4 {
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
- std::hash::Hash::hash(&self.version, state);
- std::hash::Hash::hash(&self.sym_algo, state);
- std::hash::Hash::hash(&self.s2k, state);
- std::hash::Hash::hash(&self.esk, state);
- }
-}
-
impl SKESK4 {
/// Creates a new SKESK version 4 packet.
///
@@ -247,6 +229,8 @@ impl Arbitrary for SKESK4 {
/// [Section 5.3 of RFC 4880]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-05#section-5.3
///
/// This feature is [experimental](../../index.html#experimental-features).
+// IMPORTANT: If you add fields to this struct, you need to explicitly
+// IMPORTANT: implement PartialEq, Eq, and Hash.
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub struct SKESK5 {
/// Common fields.
diff --git a/openpgp/src/packet/trust.rs b/openpgp/src/packet/trust.rs
index 35b45597..39499477 100644
---