diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2022-03-02 14:44:21 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2024-07-01 12:46:47 +0200 |
commit | db5366db17d6127f5e18a2d26f7be708661c16af (patch) | |
tree | 192ba12ba66b3cf976a3bdf380cec4ed5be797ac | |
parent | 83068f6c6f17d91730feb39b9eea0fa03a8bcf2e (diff) |
openpgp: Implement support for the padding packet.
- The packet is correctly recognized and ignored, but not yet
emitted. It would be cool if the streaming padder would detect
which encryption container is used and use the correct padding
method.
-rw-r--r-- | openpgp/src/cert/parser/mod.rs | 18 | ||||
-rw-r--r-- | openpgp/src/message/mod.rs | 5 | ||||
-rw-r--r-- | openpgp/src/packet/any.rs | 2 | ||||
-rw-r--r-- | openpgp/src/packet/header/mod.rs | 1 | ||||
-rw-r--r-- | openpgp/src/packet/mod.rs | 15 | ||||
-rw-r--r-- | openpgp/src/packet/padding.rs | 92 | ||||
-rw-r--r-- | openpgp/src/packet/prelude.rs | 1 | ||||
-rw-r--r-- | openpgp/src/packet/tag.rs | 9 | ||||
-rw-r--r-- | openpgp/src/packet/unknown.rs | 1 | ||||
-rw-r--r-- | openpgp/src/parse.rs | 27 | ||||
-rw-r--r-- | openpgp/src/serialize.rs | 27 |
11 files changed, 189 insertions, 9 deletions
diff --git a/openpgp/src/cert/parser/mod.rs b/openpgp/src/cert/parser/mod.rs index 2b04922a..70ce11bf 100644 --- a/openpgp/src/cert/parser/mod.rs +++ b/openpgp/src/cert/parser/mod.rs @@ -767,11 +767,19 @@ impl<'a> CertParser<'a> { // returns None. fn parse(&mut self, p: Packet) -> Result<Option<Cert>> { 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 d6da5a8f..2d2d6884 100644 --- a/openpgp/src/message/mod.rs +++ b/openpgp/src/message/mod.rs @@ -216,6 +216,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 5b9f59ae..6ecac159 100644 --- a/openpgp/src/packet/any.rs +++ b/openpgp/src/packet/any.rs @@ -18,6 +18,7 @@ use crate::packet::{ SEIP, MDC, AED, + Padding, }; /// Convenient downcasting from Packets to Packet Bodies. @@ -137,6 +138,7 @@ impl_downcasts!( SEIP, MDC, AED, + Padding, ); // We ow selectively implement downcasts for the key types that alias diff --git a/openpgp/src/packet/header/mod.rs b/openpgp/src/packet/header/mod.rs index 61eab916..df4b9785 100644 --- a/openpgp/src/packet/header/mod.rs +++ b/openpgp/src/packet/header/mod.rs @@ -207,6 +207,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 5bdc6389..4452e8b3 100644 --- a/openpgp/src/packet/mod.rs +++ b/openpgp/src/packet/mod.rs @@ -217,6 +217,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. /// @@ -286,6 +288,8 @@ pub enum Packet { MDC(MDC), /// AEAD Encrypted Data Packet. AED(AED), + /// Padding packet. + Padding(Padding), } assert_send_and_sync!(Packet); @@ -362,6 +366,7 @@ impl Packet { #[allow(deprecated)] Packet::MDC(_) => Tag::MDC, Packet::AED(_) => Tag::AED, + Packet::Padding(_) => Tag::Padding, } } @@ -405,6 +410,7 @@ impl Packet { #[allow(deprecated)] Packet::MDC(_) => None, Packet::AED(p) => Some(p.version()), + Packet::Padding(_) => None, } } @@ -447,6 +453,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), } } } @@ -478,6 +485,7 @@ impl Deref for Packet { #[allow(deprecated)] Packet::MDC(ref packet) => &packet.common, Packet::AED(ref packet) => &packet.common, + Packet::Padding(packet) => &packet.common, } } } @@ -506,6 +514,7 @@ impl DerefMut for Packet { #[allow(deprecated)] Packet::MDC(ref mut packet) => &mut packet.common, Packet::AED(ref mut packet) => &mut packet.common, + Packet::Padding(packet) => &mut packet.common, } } } @@ -534,6 +543,7 @@ impl fmt::Debug for Packet { #[allow(deprecated)] MDC(v) => write!(f, "MDC({:?})", v), AED(v) => write!(f, "AED({:?})", v), + Padding(v) => write!(f, "Padding({:?})", v), } } @@ -560,7 +570,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::<key::PublicParts, key::UnspecifiedRole>::arbitrary(g) @@ -579,7 +589,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<u8>, +} + +assert_send_and_sync!(Padding); + +impl From<Vec<u8>> for Padding { + fn from(u: Vec<u8>) -> 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<Padding> for Packet { + fn from(s: Padding) -> Self { + Packet::Padding(s) + } +} + +#[cfg(test)] +impl Arbitrary for Padding { + fn arbitrary(g: &mut Gen) -> Self { + Vec::<u8>::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 c433dda9..1e41b16a 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<u8> 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 7216bf19..e2591e91 100644 --- a/openpgp/src/packet/unknown.rs +++ b/openpgp/src/packet/unknown.rs @@ -256,6 +256,7 @@ impl std::convert::TryFrom<Packet> for Unknown { Packet::SKESK(v) => convert(tag, common, v), #[allow(deprecated)] 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 5b536288..65789d84 100644 --- a/openpgp/src/parse.rs +++ b/openpgp/src/parse.rs @@ -3592,6 +3592,19 @@ impl AED1 { } } +impl Padding { + /// Parses the body of a padding packet. + fn parse(mut php: PacketHeaderParser) -> Result<PacketParser> { + tracer!(TRACE, "Padding::parse", php.recursion_depth()); + make_php_try!(php); + // XXX: I don't think we should capture the body. + let value = php_try!(php.parse_bytes_eof("value")); + php.ok(Packet::Padding(Padding::from(value))) + } +} + +impl_parse_with_buffered_reader!(Padding); + impl MPI { /// Parses an OpenPGP MPI. /// @@ -4938,6 +4951,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), @@ -5198,6 +5221,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()), }?; @@ -5483,7 +5507,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 74064760..81a6b017 100644 --- a/openpgp/src/serialize.rs +++ b/openpgp/src/serialize.rs @@ -3078,6 +3078,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<usize> { + generic_serialize_into(self, MarshalInto::serialized_len(self), buf) + } +} impl Serialize for Packet {} impl seal::Sealed for Packet {} @@ -3121,6 +3145,7 @@ impl Marshal for Packet { #[allow(deprecated)] Packet::MDC(ref p) => p.serialize(o), Packet::AED(ref p) => p.serialize(o), + Packet::Padding(p) => p.serialize(o), } } @@ -3163,6 +3188,7 @@ impl Marshal for Packet { #[allow(deprecated)] Packet::MDC(ref p) => p.export(o), Packet::AED(ref p) => p.export(o), + Packet::Padding(p) => p.export(o), } } } @@ -3189,6 +3215,7 @@ impl NetLength for Packet { #[allow(deprecated)] Packet::MDC(ref p) => p.net_len(), Packet::AED(ref p) => p.net_len(), + Packet::Padding(p) => p.net_len(), } } } |