summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2022-03-02 14:44:21 +0100
committerJustus Winter <justus@sequoia-pgp.org>2023-11-07 17:18:57 +0100
commitfbebb87ca69d85ced4885bb9a9f90c1781b44f14 (patch)
treec2eaea07a3a86e483217d9e69c2220e94cd1be39
parent8ea1846baffea8af868ed0a533b61da0edb5331d (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.rs18
-rw-r--r--openpgp/src/message/mod.rs5
-rw-r--r--openpgp/src/packet/any.rs2
-rw-r--r--openpgp/src/packet/header/mod.rs1
-rw-r--r--openpgp/src/packet/mod.rs15
-rw-r--r--openpgp/src/packet/padding.rs92
-rw-r--r--openpgp/src/packet/prelude.rs1
-rw-r--r--openpgp/src/packet/tag.rs9
-rw-r--r--openpgp/src/packet/unknown.rs1
-rw-r--r--openpgp/src/parse.rs26
-rw-r--r--openpgp/src/serialize.rs27
11 files changed, 188 insertions, 9 deletions
diff --git a/openpgp/src/cert/parser/mod.rs b/openpgp/src/cert/parser/mod.rs
index eea20d49..c7ad3ebe 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<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 5a9d3b1f..1fedaa96 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 31994e05..c008e0f4 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.
@@ -137,6 +138,7 @@ impl_downcasts!(
SEIP,
MDC,
AED,
+ Padding,
);
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 dfd3427b..06adebc1 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 e7d82afa..98c2130c 100644
--- a/openpgp/src/packet/unknown.rs
+++ b/openpgp/src/packet/unknown.rs
@@ -225,6 +225,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 f06335d8..34ff7e8e 100644
--- a/openpgp/src/parse.rs
+++ b/openpgp/src/parse.rs
@@ -3476,6 +3476,18 @@ impl AED1 {
}
}
+impl Padding {
+ /// Parses the body of a padding packet.
+ fn parse(mut php: PacketHeaderParser) -> Result<PacketParser> {
+ 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.
///
@@ -4812,6 +4824,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),
@@ -5072,6 +5094,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()),
}?;
@@ -5357,7 +5380,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 e9fc3ca4..6ab52aa9 100644
--- a/openpgp/src/serialize.rs
+++ b/openpgp/src/serialize.rs
@@ -3053,6 +3053,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 {}
@@ -3096,6 +3120,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),
}
}
@@ -3138,6 +3163,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),
}
}
}
@@ -3164,6 +3190,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(),
}
}
}