diff options
-rw-r--r-- | openpgp/src/crypto/hash.rs | 12 | ||||
-rw-r--r-- | openpgp/src/packet/key.rs | 14 | ||||
-rw-r--r-- | openpgp/src/packet/mod.rs | 55 | ||||
-rw-r--r-- | openpgp/src/packet/prelude.rs | 1 | ||||
-rw-r--r-- | openpgp/src/packet/signature/mod.rs | 76 | ||||
-rw-r--r-- | openpgp/src/packet/signature/subpacket.rs | 6 | ||||
-rw-r--r-- | openpgp/src/parse/parse.rs | 32 | ||||
-rw-r--r-- | openpgp/src/serialize/mod.rs | 42 | ||||
-rw-r--r-- | openpgp/src/tpk/builder.rs | 5 | ||||
-rw-r--r-- | openpgp/src/tpk/mod.rs | 66 | ||||
-rw-r--r-- | openpgp/src/tsk.rs | 2 | ||||
-rw-r--r-- | tool/src/commands/sign.rs | 2 |
12 files changed, 232 insertions, 81 deletions
diff --git a/openpgp/src/crypto/hash.rs b/openpgp/src/crypto/hash.rs index 1ccdc3e6..f6861957 100644 --- a/openpgp/src/crypto/hash.rs +++ b/openpgp/src/crypto/hash.rs @@ -4,7 +4,8 @@ use HashAlgorithm; use packet::UserID; use packet::UserAttribute; use packet::Key; -use packet::{signature, Signature}; +use packet::Signature; +use packet::signature::{self, Signature4}; use Error; use Result; use conversions::Time; @@ -214,6 +215,15 @@ impl Hash for Key { impl Hash for Signature { /// Adds the `Signature` to the provided hash context. fn hash<H: nettle::Hash + Write>(&self, hash: &mut H) { + match self { + Signature::V4(sig) => sig.hash(hash), + } + } +} + +impl Hash for Signature4 { + /// Adds the `Signature` to the provided hash context. + fn hash<H: nettle::Hash + Write>(&self, hash: &mut H) { self.fields.hash(hash); } } diff --git a/openpgp/src/packet/key.rs b/openpgp/src/packet/key.rs index 71dcf5c3..04329e4f 100644 --- a/openpgp/src/packet/key.rs +++ b/openpgp/src/packet/key.rs @@ -950,7 +950,7 @@ mod tests { use time::{at, Timespec}; use {Fingerprint, KeyID}; use constants::SignatureType; - use packet::signature::Signature; + use packet::signature::Signature4; use packet::signature::subpacket::{ Subpacket, SubpacketValue, SubpacketArea}; @@ -972,12 +972,12 @@ mod tests { unhashed.add(Subpacket::new(SubpacketValue::Issuer(kid), false).unwrap()).unwrap(); eprintln!("fpr: {}",key.fingerprint()); - let sig = Signature::new(SignatureType::Binary, PublicKeyAlgorithm::EdDSA, - HashAlgorithm::SHA256, hashed, unhashed, - [0xa7,0x19], - mpis::Signature::EdDSA{ - r: mpis::MPI::new(r), s: mpis::MPI::new(s) - }); + let sig = Signature4::new(SignatureType::Binary, PublicKeyAlgorithm::EdDSA, + HashAlgorithm::SHA256, hashed, unhashed, + [0xa7,0x19], + mpis::Signature::EdDSA{ + r: mpis::MPI::new(r), s: mpis::MPI::new(s) + }); assert_eq!(sig.verify_message(&key, b"Hello, World\n").ok(), Some(true)); } } diff --git a/openpgp/src/packet/mod.rs b/openpgp/src/packet/mod.rs index 5b32c0a3..233a54dc 100644 --- a/openpgp/src/packet/mod.rs +++ b/openpgp/src/packet/mod.rs @@ -28,7 +28,6 @@ pub use self::header::Header; mod unknown; pub use self::unknown::Unknown; pub mod signature; -pub use self::signature::Signature; mod one_pass_sig; pub use self::one_pass_sig::OnePassSig; pub mod key; @@ -63,7 +62,7 @@ impl<'a> Deref for Packet { fn deref(&self) -> &Self::Target { match self { &Packet::Unknown(ref packet) => &packet.common, - &Packet::Signature(ref packet) => &packet.common, + &Packet::Signature(Signature::V4(ref packet)) => &packet.common, &Packet::OnePassSig(ref packet) => &packet.common, &Packet::PublicKey(ref packet) => &packet.common, &Packet::PublicSubkey(ref packet) => &packet.common, @@ -87,7 +86,8 @@ impl<'a> DerefMut for Packet { fn deref_mut(&mut self) -> &mut Common { match self { &mut Packet::Unknown(ref mut packet) => &mut packet.common, - &mut Packet::Signature(ref mut packet) => &mut packet.common, + &mut Packet::Signature(Signature::V4(ref mut packet)) => + &mut packet.common, &mut Packet::OnePassSig(ref mut packet) => &mut packet.common, &mut Packet::PublicKey(ref mut packet) => &mut packet.common, &mut Packet::PublicSubkey(ref mut packet) => &mut packet.common, @@ -602,6 +602,55 @@ fn packet_path_iter() { } } +/// Holds a signature packet. +/// +/// Signature packets are used both for certification purposes as well +/// as for document signing purposes. +/// +/// See [Section 5.2 of RFC 4880] for details. +/// +/// [Section 5.2 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.2 +#[derive(PartialEq, Eq, Hash, Clone, Debug)] +pub enum Signature { + /// Signature packet version 4. + V4(self::signature::Signature4), +} + +impl Signature { + /// Gets the version. + pub fn version(&self) -> u8 { + match self { + &Signature::V4(_) => 4, + } + } +} + +impl From<Signature> for Packet { + fn from(s: Signature) -> Self { + Packet::Signature(s) + } +} + +// Trivial forwarder for singleton enum. +impl Deref for Signature { + type Target = signature::Signature4; + + fn deref(&self) -> &Self::Target { + match self { + Signature::V4(sig) => sig, + } + } +} + +// Trivial forwarder for singleton enum. +impl DerefMut for Signature { + fn deref_mut(&mut self) -> &mut Self::Target { + match self { + Signature::V4(ref mut sig) => sig, + } + } +} + /// Holds an symmetrically encrypted session key. /// /// Holds an symmetrically encrypted session key. The session key is diff --git a/openpgp/src/packet/prelude.rs b/openpgp/src/packet/prelude.rs index 7d92f175..d5b45e05 100644 --- a/openpgp/src/packet/prelude.rs +++ b/openpgp/src/packet/prelude.rs @@ -4,6 +4,7 @@ pub use super::{ Tag, Unknown, Signature, + signature::Signature4, OnePassSig, Key, key::SecretKey, diff --git a/openpgp/src/packet/signature/mod.rs b/openpgp/src/packet/signature/mod.rs index f207a535..7e906968 100644 --- a/openpgp/src/packet/signature/mod.rs +++ b/openpgp/src/packet/signature/mod.rs @@ -14,6 +14,7 @@ use crypto::{ use HashAlgorithm; use PublicKeyAlgorithm; use SignatureType; +use packet::Signature; use packet::Key; use KeyID; use packet::UserID; @@ -42,7 +43,7 @@ fn path_to(artifact: &str) -> PathBuf { /// Builds a signature packet. /// -/// This is the mutable version of a `Signature` packet. To convert +/// This is the mutable version of a `Signature4` packet. To convert /// it to one, use `sign_hash(..)`. #[derive(Clone, Hash, PartialEq, Eq)] pub struct Builder { @@ -229,25 +230,41 @@ impl Builder { let algo = self.hash_algo; let mpis = signer.sign(algo, &digest)?; - Ok(Signature { + Ok(Signature4 { common: Default::default(), fields: self, hash_prefix: [digest[0], digest[1]], mpis: mpis, computed_hash: Some((algo, digest)), level: 0, - }) + }.into()) } } impl From<Signature> for Builder { fn from(sig: Signature) -> Self { + match sig { + Signature::V4(sig) => sig.into(), + } + } +} + +impl From<Signature4> for Builder { + fn from(sig: Signature4) -> Self { sig.fields } } impl<'a> From<&'a Signature> for &'a Builder { fn from(sig: &'a Signature) -> Self { + match sig { + Signature::V4(ref sig) => sig.into(), + } + } +} + +impl<'a> From<&'a Signature4> for &'a Builder { + fn from(sig: &'a Signature4) -> Self { &sig.fields } } @@ -263,7 +280,7 @@ impl<'a> From<&'a Signature> for &'a Builder { /// [Section 5.2 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.2 // Note: we can't derive PartialEq, because it includes the cached data. #[derive(Eq, Hash, Clone)] -pub struct Signature { +pub struct Signature4 { /// CTB packet header fields. pub(crate) common: packet::Common, @@ -287,7 +304,7 @@ pub struct Signature { level: usize, } -impl Deref for Signature { +impl Deref for Signature4 { type Target = Builder; fn deref(&self) -> &Self::Target { @@ -295,7 +312,7 @@ impl Deref for Signature { } } -impl fmt::Debug for Signature { +impl fmt::Debug for Signature4 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Get the issuer. Prefer the issuer fingerprint to the // issuer keyid, which may be stored in the unhashed area. @@ -307,7 +324,7 @@ impl fmt::Debug for Signature { "Unknown".to_string() }; - f.debug_struct("Signature") + f.debug_struct("Signature4") .field("version", &self.version()) .field("sigtype", &self.sigtype()) .field("issuer", &issuer) @@ -329,12 +346,12 @@ impl fmt::Debug for Signature { } } -impl PartialEq for Signature { - fn eq(&self, other: &Signature) -> bool { +impl PartialEq for Signature4 { + fn eq(&self, other: &Signature4) -> bool { // Comparing the relevant fields is error prone in case we add // a field at some point. Instead, we compare the serialized // versions. As a small optimization, we compare the MPIs. - // Note: two `Signatures` could be different even if they have + // Note: two `Signature4s` could be different even if they have // the same MPI if the MPI was not invalidated when changing a // field. if self.mpis != other.mpis { @@ -350,7 +367,7 @@ impl PartialEq for Signature { } } -impl Signature { +impl Signature4 { /// Creates a new signature packet. /// /// If you want to sign something, consider using the [`Builder`] @@ -362,7 +379,7 @@ impl Signature { unhashed_area: SubpacketArea, hash_prefix: [u8; 2], mpis: mpis::Signature) -> Self { - Signature { + Signature4 { common: Default::default(), fields: Builder { version: 4, @@ -588,7 +605,7 @@ impl Signature { return Err(Error::UnsupportedSignatureType(self.sigtype()).into()); } - let hash = Self::primary_key_binding_hash(self, pk)?; + let hash = Signature::primary_key_binding_hash(self, pk)?; self.verify_hash(signer, self.hash_algo(), &hash[..]) } @@ -606,7 +623,7 @@ impl Signature { return Err(Error::UnsupportedSignatureType(self.sigtype()).into()); } - let hash = Self::primary_key_binding_hash(self, pk)?; + let hash = Signature::primary_key_binding_hash(self, pk)?; self.verify_hash(signer, self.hash_algo(), &hash[..]) } @@ -629,7 +646,7 @@ impl Signature { return Err(Error::UnsupportedSignatureType(self.sigtype()).into()); } - let hash = Self::subkey_binding_hash(self, pk, subkey)?; + let hash = Signature::subkey_binding_hash(self, pk, subkey)?; if self.verify_hash(signer, self.hash_algo(), &hash[..])? { // The signature is good, but we may still need to verify // the back sig. @@ -643,12 +660,14 @@ impl Signature { } let mut backsig_ok = false; - if let Some(Packet::Signature(backsig)) = self.embedded_signature() { + if let Some(Packet::Signature(super::Signature::V4(backsig))) = + self.embedded_signature() + { if backsig.sigtype() != SignatureType::PrimaryKeyBinding { return Err(Error::UnsupportedSignatureType(self.sigtype()).into()); } else { // We can't use backsig.verify_subkey_binding. - let hash = Self::subkey_binding_hash(&backsig, pk, &subkey)?; + let hash = Signature::subkey_binding_hash(&backsig, pk, &subkey)?; match backsig.verify_hash(&subkey, backsig.hash_algo(), &hash[..]) { Ok(true) => { @@ -693,7 +712,7 @@ impl Signature { return Err(Error::UnsupportedSignatureType(self.sigtype()).into()); } - let hash = Self::subkey_binding_hash(self, pk, subkey)?; + let hash = Signature::subkey_binding_hash(self, pk, subkey)?; self.verify_hash(signer, self.hash_algo(), &hash[..]) } @@ -715,7 +734,7 @@ impl Signature { return Err(Error::UnsupportedSignatureType(self.sigtype()).into()); } - let hash = Self::userid_binding_hash(self, pk, userid)?; + let hash = Signature::userid_binding_hash(self, pk, userid)?; self.verify_hash(signer, self.hash_algo(), &hash[..]) } @@ -734,7 +753,7 @@ impl Signature { return Err(Error::UnsupportedSignatureType(self.sigtype()).into()); } - let hash = Self::userid_binding_hash(self, pk, userid)?; + let hash = Signature::userid_binding_hash(self, pk, userid)?; self.verify_hash(signer, self.hash_algo(), &hash[..]) } @@ -756,7 +775,7 @@ impl Signature { return Err(Error::UnsupportedSignatureType(self.sigtype()).into()); } - let hash = Self::user_attribute_binding_hash(self, pk, ua)?; + let hash = Signature::user_attribute_binding_hash(self, pk, ua)?; self.verify_hash(signer, self.hash_algo(), &hash[..]) } @@ -775,7 +794,7 @@ impl Signature { return Err(Error::UnsupportedSignatureType(self.sigtype()).into()); } - let hash = Self::user_attribute_binding_hash(self, pk, ua)?; + let hash = Signature::user_attribute_binding_hash(self, pk, ua)?; self.verify_hash(signer, self.hash_algo(), &hash[..]) } @@ -806,12 +825,19 @@ impl Signature { } } -impl From<Signature> for Packet { - fn from(s: Signature) -> Self { - Packet::Signature(s) +impl From<Signature4> for Packet { + fn from(s: Signature4) -> Self { + Packet::Signature(s.into()) + } +} + +impl From<Signature4> for super::Signature { + fn from(s: Signature4) -> Self { + super::Signature::V4(s) } } + #[cfg(test)] mod test { use nettle::{Random, Yarrow}; diff --git a/openpgp/src/packet/signature/subpacket.rs b/openpgp/src/packet/signature/subpacket.rs index c75f932b..62d9f8b3 100644 --- a/openpgp/src/packet/signature/subpacket.rs +++ b/openpgp/src/packet/signature/subpacket.rs @@ -69,7 +69,7 @@ use { Error, Result, packet::Signature, - packet::signature, + packet::signature::{self, Signature4}, packet::Features, packet::KeyFlags, packet::KeyServerPreferences, @@ -725,7 +725,7 @@ impl<'a> SubpacketValue<'a> { Features(f) => f.as_vec().len(), SignatureTarget { ref digest, .. } => 1 + 1 + digest.len(), EmbeddedSignature(p) => match p { - &Packet::Signature(ref sig) => { + &Packet::Signature(Signature::V4(ref sig)) => { let mut w = Vec::new(); sig.serialize_naked(&mut w).unwrap(); w.len() @@ -1161,7 +1161,7 @@ quickcheck! { } -impl Signature { +impl Signature4 { /// Returns the *last* instance of the specified subpacket. fn subpacket<'a>(&'a self, tag: SubpacketTag) -> Option<Subpacket<'a>> { if let Some(sb) = self.hashed_area().lookup(tag) { diff --git a/openpgp/src/parse/parse.rs b/openpgp/src/parse/parse.rs index 31fa0a79..95080ec7 100644 --- a/openpgp/src/parse/parse.rs +++ b/openpgp/src/parse/parse.rs @@ -22,6 +22,7 @@ use { crypto::s2k::S2K, Error, Header, + packet::signature::Signature4, packet::prelude::*, Packet, KeyID, @@ -859,10 +860,31 @@ impl Signature { let version = php_try!(php.parse_u8("version")); - if version != 4 { - t!("Ignoring version {} packet.", version); - return php.fail("unknown version"); + match version { + 4 => Signature4::parse(php), + _ => { + t!("Ignoring version {} packet.", version); + php.fail("unknown version") + }, } + } + + /// Returns whether the data appears to be a signature (no promises). + fn plausible(bio: &mut buffered_reader::Dup<Cookie>, header: &Header) + -> Result<()> { + Signature4::plausible(bio, header) + } +} + +impl Signature4 { + // Parses a signature packet. + fn parse<'a>(mut php: PacketHeaderParser<'a>) + -> Result<PacketParser<'a>> + { + let indent = php.recursion_depth(); + tracer!(TRACE, "Signature4::parse", indent); + + make_php_try!(php); let sigtype = php_try!(php.parse_u8("sigtype")); let pk_algo: PublicKeyAlgorithm = php_try!(php.parse_u8("pk_algo")).into(); @@ -884,12 +906,12 @@ impl Signature { crypto::mpis::Signature::parse(pk_algo, &mut php)); let hash_algo = hash_algo.into(); - let mut pp = php.ok(Packet::Signature(Signature::new( + let mut pp = php.ok(Packet::Signature(Signature4::new( sigtype.into(), pk_algo.into(), hash_algo, SubpacketArea::new(hashed_area), SubpacketArea::new(unhashed_area), [hash_prefix1, hash_prefix2], - mpis)))?; + mpis).into()))?; // Locate the corresponding HashedReader and extract the // computed hash. diff --git a/openpgp/src/serialize/mod.rs b/openpgp/src/serialize/mod.rs index f314b36d..77998695 100644 --- a/openpgp/src/serialize/mod.rs +++ b/openpgp/src/serialize/mod.rs @@ -1016,6 +1016,42 @@ impl<'a> SerializeInto for SubpacketValue<'a> { impl Serialize for Signature { fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> { + match self { + &Signature::V4(ref s) => s.serialize(o), + } + } +} + +impl SerializeInto for Signature { + fn serialized_len(&self) -> usize { + match self { + &Signature::V4(ref s) => s.serialized_len(), + } + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> { + match self { + &Signature::V4(ref s) => s.serialize_into(buf), + } + } +} + +impl Serialize for Signature4 { + /// Writes a serialized version of the specified `Signature` + /// packet to `o`. + /// + /// Note: this function does not compute the signature (which + /// would require access to the private key); it assumes that + /// sig.mpis is up to date. + /// + /// # Errors + /// + /// Returns [`Error::InvalidArgument`] if invoked on a + /// non-version 4 signature, or if either the hashed-area or the + /// unhashed-area exceeds the size limit of 2^16. + /// + /// [`Error::InvalidArgument`]: ../../enum.Error.html#variant.InvalidArgument + fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> { let len = self.net_len(); CTB::new(Tag::Signature).serialize(o)?; BodyLength::Full(len as u32).serialize(o)?; @@ -1024,7 +1060,7 @@ impl Serialize for Signature { } } -impl NetLength for Signature { +impl NetLength for Signature4 { fn net_len(&self) -> usize { 1 // Version. + 1 // Signature type. @@ -1039,7 +1075,7 @@ impl NetLength for Signature { } } -impl SerializeInto for Signature { +impl SerializeInto for Signature4 { fn serialized_len(&self) -> usize { self.gross_len() } @@ -1049,7 +1085,7 @@ impl SerializeInto for Signature { } } -impl Signature { +impl Signature4 { /// Writes a serialized version of the specified `Signature` /// packet without framing to `o`. /// diff --git a/openpgp/src/tpk/builder.rs b/openpgp/src/tpk/builder.rs index 41e6f29e..5c3ab214 100644 --- a/openpgp/src/tpk/builder.rs +++ b/openpgp/src/tpk/builder.rs @@ -6,7 +6,8 @@ use packet::Key; use Result; use crypto::KeyPair; use HashAlgorithm; -use packet::signature::{self, Signature}; +use packet::Signature; +use packet::signature; use packet::key::SecretKey; use TPK; use Error; @@ -292,7 +293,7 @@ impl TPKBuilder { } }; - Ok((key, sig)) + Ok((key, sig.into())) } } diff --git a/openpgp/src/tpk/mod.rs b/openpgp/src/tpk/mod.rs index 62ed37b4..490efadd 100644 --- a/openpgp/src/tpk/mod.rs +++ b/openpgp/src/tpk/mod.rs @@ -18,7 +18,8 @@ use { SignatureType, HashAlgorithm, packet::Tag, - packet::signature::{self, Signature}, + packet::Signature, + packet::signature, packet::Key, packet::key::SecretKey, packet::UserID, @@ -539,7 +540,7 @@ impl SubkeyBinding { Ok(SubkeyBinding{ subkey: subkey, - selfsigs: vec![sig], + selfsigs: vec![sig.into()], certifications: vec![], self_revocations: vec![], other_revocations: vec![], @@ -658,7 +659,7 @@ impl UserIDBinding { Ok(UserIDBinding{ userid: uid, - selfsigs: vec![sig], + selfsigs: vec![sig.into()], certifications: vec![], self_revocations: vec![], other_revocations: vec![], @@ -1427,31 +1428,36 @@ impl<'a, I: Iterator<Item=Packet>> TPKParser<'a, I> { let primary_keyid = primary.to_keyid(); for sig in sigs.into_iter() { - let sigtype = sig.sigtype(); - - let is_selfsig = - sig.issuer_fingerprint() - .map(|fp| fp == *primary) - .unwrap_or(false) - || sig.issuer() - .map(|keyid| keyid == primary_keyid) - .unwrap_or(false); - - if sigtype == SignatureType::KeyRevocation - || sigtype == SignatureType::SubkeyRevocation - || sigtype == SignatureType::CertificateRevocation - { - if is_selfsig { - self_revs.push(sig); - } else { - other_revs.push(sig); - } - } else { - if is_selfsig { - selfsigs.push(sig); - } else { - certifications.push(sig); - } + match sig { + Signature::V4(sig) => { + let sigtype = sig.sigtype(); + + let is_selfsig = + sig.issuer_fingerprint() + .map(|fp| fp == *primary) + .unwrap_or(false) + || sig.issuer() + .map(|keyid| keyid == primary_keyid) + .unwrap_or(false); + + use self::SignatureType::*; + if sigtype == KeyRevocation + || sigtype == SubkeyRevocation + || sigtype == CertificateRevocation + { + if is_selfsig { + self_revs.push(sig.into()); + } else { + other_revs.push(sig.into()); + } + } else { + if is_selfsig { + selfsigs.push(sig.into()); + } else { + certifications.push(sig.into()); + } + } + }, } } @@ -1881,7 +1887,7 @@ impl TPK { /// Returns whether or not the TPK has expired. pub fn expired(&self) -> bool { - if let Some(sig) = self.primary_key_signature() { + if let Some(Signature::V4(sig)) = self.primary_key_signature() { sig.key_expired(self.primary()) } else { false @@ -1890,7 +1896,7 @@ impl TPK { /// Returns whether or not the key is expired at the given time. pub fn expired_at(&self, tm: time::Tm) -> bool { - if let Some(sig) = self.primary_key_signature() { + if let Some(Signature::V4(sig)) = self.primary_key_signature() { sig.key_expired_at(self.primary(), tm) } else { false diff --git a/openpgp/src/tsk.rs b/openpgp/src/tsk.rs index d8c1cbe3..583234b8 100644 --- a/openpgp/src/tsk.rs +++ b/openpgp/src/tsk.rs @@ -14,7 +14,7 @@ use { use crypto::{KeyPair, Password}; use packet::{ - signature::Signature, + Signature, Tag, UserID, Key, diff --git a/tool/src/commands/sign.rs b/tool/src/commands/sign.rs index b9832035..bcead074 100644 --- a/tool/src/commands/sign.rs +++ b/tool/src/commands/sign.rs @@ -9,7 +9,7 @@ use openpgp::armor; use openpgp::constants::DataFormat; use openpgp::crypto; use openpgp::{Packet, Error, Result}; -use openpgp::packet::signature::Signature; +use openpgp::packet::Signature; use openpgp::parse: |