From 8e5176c21b8cb7535cce6cea637c9bfa9a61fbdb Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Wed, 2 Mar 2022 14:44:21 +0100 Subject: wip: very rough padding packet support --- openpgp/src/cert/parser/mod.rs | 18 +++++--- openpgp/src/message/mod.rs | 5 +++ openpgp/src/packet/any.rs | 2 + openpgp/src/packet/header/mod.rs | 1 + openpgp/src/packet/mod.rs | 15 ++++++- openpgp/src/packet/padding.rs | 92 ++++++++++++++++++++++++++++++++++++++++ openpgp/src/packet/prelude.rs | 1 + openpgp/src/packet/tag.rs | 9 +++- openpgp/src/packet/unknown.rs | 1 + openpgp/src/parse.rs | 27 +++++++++++- openpgp/src/serialize.rs | 27 ++++++++++++ sq/src/commands/dump.rs | 6 +++ 12 files changed, 195 insertions(+), 9 deletions(-) create mode 100644 openpgp/src/packet/padding.rs diff --git a/openpgp/src/cert/parser/mod.rs b/openpgp/src/cert/parser/mod.rs index d376c0c1..aea9c101 100644 --- a/openpgp/src/cert/parser/mod.rs +++ b/openpgp/src/cert/parser/mod.rs @@ -757,11 +757,19 @@ impl<'a> CertParser<'a> { // returns None. fn parse(&mut self, p: Packet) -> Result> { tracer!(TRACE, "CertParser::parse", 0); - if let Packet::Marker(_) = p { - // Ignore Marker Packet. RFC4880, section 5.8: - // - // Such a packet MUST be ignored when received. - return Ok(None); + match p { + Packet::Marker(_) => { + // Ignore Marker Packet. RFC4880, section 5.8: + // + // Such a packet MUST be ignored when received. + return Ok(None); + }, + Packet::Padding(_) => { + // "[Padding packets] MUST be ignored when received.", + // section 5.15 of RFC XXXX. + return Ok(None); + }, + _ => {}, } if !self.packets.is_empty() { diff --git a/openpgp/src/message/mod.rs b/openpgp/src/message/mod.rs index ec715380..441fc334 100644 --- a/openpgp/src/message/mod.rs +++ b/openpgp/src/message/mod.rs @@ -214,6 +214,11 @@ impl MessageValidator { // section 5.8 of RFC4880. return; }, + Tag::Padding => { + // "[Padding packets] MUST be ignored when received.", + // section 5.15 of RFC XXXX. + return; + }, _ => { // Unknown token. self.error = Some(MessageParserError::OpenPGP( diff --git a/openpgp/src/packet/any.rs b/openpgp/src/packet/any.rs index 8af73eaf..3238bf86 100644 --- a/openpgp/src/packet/any.rs +++ b/openpgp/src/packet/any.rs @@ -22,6 +22,7 @@ use crate::packet::{ SEIP, MDC, AED, + Padding, }; /// Convenient downcasting from Packets to Packet Bodies. @@ -136,6 +137,7 @@ impl_downcasts!( SEIP, MDC, AED, + Padding, ); diff --git a/openpgp/src/packet/header/mod.rs b/openpgp/src/packet/header/mod.rs index 0040d501..40bf2943 100644 --- a/openpgp/src/packet/header/mod.rs +++ b/openpgp/src/packet/header/mod.rs @@ -205,6 +205,7 @@ impl Header { Tag::Marker => l == 3, Tag::Reserved => true, + Tag::Padding => true, }; if ! valid { diff --git a/openpgp/src/packet/mod.rs b/openpgp/src/packet/mod.rs index 1a3da9ab..3c132486 100644 --- a/openpgp/src/packet/mod.rs +++ b/openpgp/src/packet/mod.rs @@ -208,6 +208,8 @@ pub mod pkesk; mod mdc; pub use self::mdc::MDC; pub mod aed; +mod padding; +pub use self::padding::Padding; /// Enumeration of packet types. /// @@ -276,6 +278,8 @@ pub enum Packet { MDC(MDC), /// AEAD Encrypted Data Packet. AED(AED), + /// Padding packet. + Padding(Padding), } assert_send_and_sync!(Packet); @@ -351,6 +355,7 @@ impl Packet { Packet::SEIP(_) => Tag::SEIP, Packet::MDC(_) => Tag::MDC, Packet::AED(_) => Tag::AED, + Packet::Padding(_) => Tag::Padding, } } @@ -393,6 +398,7 @@ impl Packet { Packet::SEIP(p) => Some(p.version()), Packet::MDC(_) => None, Packet::AED(p) => Some(p.version()), + Packet::Padding(_) => None, } } @@ -434,6 +440,7 @@ impl Packet { Packet::MDC(x) => Hash::hash(&x, state), Packet::AED(x) => Hash::hash(&x, state), Packet::Unknown(x) => Hash::hash(&x, state), + Packet::Padding(x) => Padding::hash(&x, state), } } } @@ -463,6 +470,7 @@ impl Deref for Packet { Packet::SEIP(ref packet) => &packet.common, Packet::MDC(ref packet) => &packet.common, Packet::AED(ref packet) => &packet.common, + Packet::Padding(packet) => &packet.common, } } } @@ -489,6 +497,7 @@ impl DerefMut for Packet { Packet::SEIP(ref mut packet) => &mut packet.common, Packet::MDC(ref mut packet) => &mut packet.common, Packet::AED(ref mut packet) => &mut packet.common, + Packet::Padding(packet) => &mut packet.common, } } } @@ -516,6 +525,7 @@ impl fmt::Debug for Packet { SEIP(v) => write!(f, "SEIP({:?})", v), MDC(v) => write!(f, "MDC({:?})", v), AED(v) => write!(f, "AED({:?})", v), + Padding(v) => write!(f, "Padding({:?})", v), } } @@ -542,7 +552,7 @@ impl Arbitrary for Packet { fn arbitrary(g: &mut Gen) -> Self { use crate::arbitrary_helper::gen_arbitrary_from_range; - match gen_arbitrary_from_range(0..15, g) { + match gen_arbitrary_from_range(0..16, g) { 0 => Signature::arbitrary(g).into(), 1 => OnePassSig::arbitrary(g).into(), 2 => Key::::arbitrary(g) @@ -561,7 +571,8 @@ impl Arbitrary for Packet { 11 => CompressedData::arbitrary(g).into(), 12 => PKESK::arbitrary(g).into(), 13 => SKESK::arbitrary(g).into(), - 14 => loop { + 14 => Padding::arbitrary(g).into(), + 15 => loop { let mut u = Unknown::new( Tag::arbitrary(g), anyhow::anyhow!("Arbitrary::arbitrary")); u.set_body(Arbitrary::arbitrary(g)); diff --git a/openpgp/src/packet/padding.rs b/openpgp/src/packet/padding.rs new file mode 100644 index 00000000..6b7fab5f --- /dev/null +++ b/openpgp/src/packet/padding.rs @@ -0,0 +1,92 @@ +use std::fmt; + +#[cfg(test)] +use quickcheck::{Arbitrary, Gen}; + +use crate::packet; +use crate::Packet; + +/// Holds a Padding packet. +/// +/// Padding packets are used to obscure the size of cryptographic +/// artifacts. +/// +/// See [Section 5.15 of RFC XXX] for details. +/// +/// [Section 5.15 of RFC XXX]: https://openpgp-wg.gitlab.io/rfc4880bis/#name-padding-packet-tag-21 +// 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 Padding { + pub(crate) common: packet::Common, + value: Vec, +} + +assert_send_and_sync!(Padding); + +impl From> for Padding { + fn from(u: Vec) -> Self { + Padding { + common: Default::default(), + value: u, + } + } +} + +impl fmt::Display for Padding { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let padding = String::from_utf8_lossy(&self.value[..]); + write!(f, "{}", padding) + } +} + +impl fmt::Debug for Padding { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Padding {{ {} bytes }}", self.value.len()) + } +} + +impl Padding { + /// Creates a new Padding packet of the given size. + /// + /// Note that this is the net size, packet framing (CTB and packet + /// length) will come on top. + pub fn new(size: usize) -> Padding { + let mut v = vec![0; size]; + crate::crypto::random(&mut v); + v.into() + } + + /// Gets the padding packet's value. + pub(crate) fn value(&self) -> &[u8] { + self.value.as_slice() + } +} + +impl From for Packet { + fn from(s: Padding) -> Self { + Packet::Padding(s) + } +} + +#[cfg(test)] +impl Arbitrary for Padding { + fn arbitrary(g: &mut Gen) -> Self { + Vec::::arbitrary(g).into() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::parse::Parse; + use crate::serialize::MarshalInto; + + quickcheck! { + fn roundtrip(p: Padding) -> bool { + let q = Padding::from_bytes(&p.to_vec().unwrap()).unwrap(); + assert_eq!(p, q); + true + } + } +} diff --git a/openpgp/src/packet/prelude.rs b/openpgp/src/packet/prelude.rs index 3a1e6d88..7e00367f 100644 --- a/openpgp/src/packet/prelude.rs +++ b/openpgp/src/packet/prelude.rs @@ -34,6 +34,7 @@ pub use crate::packet::{ OnePassSig, PKESK, Packet, + Padding, SEIP, SKESK, Signature, diff --git a/openpgp/src/packet/tag.rs b/openpgp/src/packet/tag.rs index a95ddae2..26a93c74 100644 --- a/openpgp/src/packet/tag.rs +++ b/openpgp/src/packet/tag.rs @@ -54,6 +54,8 @@ pub enum Tag { /// /// This feature is [experimental](crate#experimental-features). AED, + /// Padding packet. + Padding, /// Unassigned packets (as of RFC4880). Unknown(u8), /// Experimental packets. @@ -116,6 +118,7 @@ impl From for Tag { 18 => SEIP, 19 => MDC, 20 => AED, + 21 => Padding, 60..=63 => Private(u), _ => Unknown(u), } @@ -150,6 +153,7 @@ impl From<&Tag> for u8 { Tag::SEIP => 18, Tag::MDC => 19, Tag::AED => 20, + Tag::Padding => 21, Tag::Private(x) => *x, Tag::Unknown(x) => *x, } @@ -209,6 +213,8 @@ impl fmt::Display for Tag { f.write_str("Modification Detection Code Packet"), Tag::AED => f.write_str("AEAD Encrypted Data Packet"), + Tag::Padding => + f.write_str("Padding Packet"), Tag::Private(u) => f.write_fmt(format_args!("Private/Experimental Packet {}", u)), Tag::Unknown(u) => @@ -217,7 +223,7 @@ impl fmt::Display for Tag { } } -const PACKET_TAG_VARIANTS: [Tag; 18] = [ +const PACKET_TAG_VARIANTS: [Tag; 19] = [ Tag::PKESK, Tag::Signature, Tag::SKESK, @@ -236,6 +242,7 @@ const PACKET_TAG_VARIANTS: [Tag; 18] = [ Tag::SEIP, Tag::MDC, Tag::AED, + Tag::Padding, ]; #[cfg(test)] diff --git a/openpgp/src/packet/unknown.rs b/openpgp/src/packet/unknown.rs index 1302f407..b32c6fe8 100644 --- a/openpgp/src/packet/unknown.rs +++ b/openpgp/src/packet/unknown.rs @@ -224,6 +224,7 @@ impl std::convert::TryFrom for Unknown { Packet::PKESK(v) => convert(tag, common, v), Packet::SKESK(v) => convert(tag, common, v), Packet::MDC(v) => convert(tag, common, v), + Packet::Padding(v) => convert(tag, common, v), // XXX: can we do better like for the Literal? // Here we can avoid copying the body. Packet::Literal(mut v) => { diff --git a/openpgp/src/parse.rs b/openpgp/src/parse.rs index 17d9fe11..bd33bc8c 100644 --- a/openpgp/src/parse.rs +++ b/openpgp/src/parse.rs @@ -2911,6 +2911,19 @@ impl AED1 { } } +impl Padding { + /// Parses the body of a padding packet. + fn parse<'a, T: 'a + BufferedReader>(mut php: PacketHeaderParser) + -> Result> + { + make_php_try!(php); + let value = php_try!(php.parse_bytes_eof("value")); + php.ok(Packet::Padding(Padding::from(value))) + } +} + +impl_parse_generic_packet!(Padding); + impl MPI { /// Parses an OpenPGP MPI. /// @@ -4189,6 +4202,16 @@ impl <'a> PacketParser<'a> { Err(Error::MalformedPacket("Looks like garbage".into()).into()), Tag::Marker => Marker::plausible(bio, header), + Tag::Padding => { + // Even though a padding packet may occur here, it has + // so little structure, that we're likely better off + // trying to find the next packet. + // + // XXX: We could optimize that though, by using the + // potential padding packet's length to see if the + // next packet is plausible. + bad + }, Tag::Signature => Signature::plausible(bio, header), Tag::SecretKey => Key::plausible(bio, header), @@ -4448,6 +4471,7 @@ impl <'a> PacketParser<'a> { Tag::MDC => MDC::parse(parser), Tag::PKESK => PKESK::parse(parser), Tag::AED => AED::parse(parser), + Tag::Padding => Padding::parse(parser), _ => Unknown::parse(parser, Error::UnsupportedPacketType(tag).into()), }?; @@ -4732,7 +4756,8 @@ impl <'a> PacketParser<'a> { | Packet::UserID(_) | Packet::UserAttribute(_) | Packet::Literal(_) | Packet::PKESK(_) | Packet::SKESK(_) | Packet::SEIP(_) | Packet::MDC(_) | Packet::AED(_) - | Packet::CompressedData(_) => { + | Packet::CompressedData(_) + | Packet::Padding(_) => { // Drop through. t!("A {:?} packet is not a container, not recursing.", self.packet.tag()); diff --git a/openpgp/src/serialize.rs b/openpgp/src/serialize.rs index 531b3d35..3d3bc0dd 100644 --- a/openpgp/src/serialize.rs +++ b/openpgp/src/serialize.rs @@ -2698,6 +2698,30 @@ impl MarshalInto for AED1 { generic_serialize_into(self, MarshalInto::serialized_len(self), buf) } } + +impl seal::Sealed for Padding {} +impl Marshal for Padding { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + o.write_all(self.value())?; + Ok(()) + } +} + +impl NetLength for Padding { + fn net_len(&self) -> usize { + self.value().len() + } +} + +impl MarshalInto for Padding { + fn serialized_len(&self) -> usize { + self.net_len() + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, MarshalInto::serialized_len(self), buf) + } +} impl Serialize for Packet {} impl seal::Sealed for Packet {} @@ -2740,6 +2764,7 @@ impl Marshal for Packet { Packet::SEIP(ref p) => p.serialize(o), Packet::MDC(ref p) => p.serialize(o), Packet::AED(ref p) => p.serialize(o), + Packet::Padding(p) => p.serialize(o), } } @@ -2781,6 +2806,7 @@ impl Marshal for Packet { Packet::SEIP(ref p) => p.export(o), Packet::MDC(ref p) => p.export(o), Packet::AED(ref p) => p.export(o), + Packet::Padding(p) => p.export(o), } } } @@ -2806,6 +2832,7 @@ impl NetLength for Packet { Packet::SEIP(ref p) => p.net_len(), Packet::MDC(ref p) => p.net_len(), Packet::AED(ref p) => p.net_len(), + Packet::Padding(p) => p.net_len(), } } } diff --git a/sq/src/commands/dump.rs b/sq/src/commands/dump.rs index 0b3d4157..7a76b6d1 100644 --- a/sq/src/commands/dump.rs +++ b/sq/src/commands/dump.rs @@ -719,6 +719,12 @@ impl PacketDumper { writeln!(output, "{} IV: {}", i, hex::encode(a.iv()))?; }, + Padding(p) => { + use openpgp::serialize::MarshalInto; + writeln!(output, "{} Net amount: {} bytes", i, + p.serialized_len())?; + }, + // openpgp::Packet is non-exhaustive. u => writeln!(output, "{} Unknown variant: {:?}", i, u)?, } -- cgit v1.2.3