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>2024-03-13 10:59:50 +0100
commit44c6bb25f967f92b46b03e96efe9050eff1c2743 (patch)
treee961c9d705aeddfe5d8be1fe9ebefdeb8d6a34b8
parent3f76b32c8a161c83f1564cfffdce67b9fec45cd3 (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 eec5a5d0..58378d08 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 21c192f5..af927464 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 48b7da1e..da8dfe7b 100644
--- a/openpgp/src/packet/unknown.rs
+++ b/openpgp/src/packet/unknown.rs
@@ -251,6 +251,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 e7a72920..62f1e225 100644
--- a/openpgp/src/parse.rs
+++ b/openpgp/src/parse.rs
@@ -3567,6 +3567,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.
///
@@ -4911,6 +4923,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),
@@ -5171,6 +5193,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()),
}?;
@@ -5456,7 +5479,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 cead9f46..65bac0fe 100644
--- a/openpgp/src/serialize.rs
+++ b/openpgp/src/serialize.rs
@@ -3066,6 +3066,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 {}
@@ -3109,6 +3133,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),
}
}
@@ -3151,6 +3176,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),
}
}
}
@@ -3177,6 +3203,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(),
}
}
}