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-06-26 13:21:33 +0200
commit04e7b2d6c08cb0aeac1ff242fd70c2f9eb0420f1 (patch)
tree2b01f089fb42d6015ba8e7775a87ee1e18611b1d
parent3efd91c7de8a13d6b6ff28c377f8e9c78c15f932 (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 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<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 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 d0df418b..534f8b30 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..a48e99bf 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::<key::PublicParts, key::UnspecifiedRole>::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<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 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<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 1302f407..b32c6fe8 100644
--- a/openpgp/src/packet/unknown.rs
+++ b/openpgp/src/packet/unknown.rs
@@ -224,6 +224,7 @@ impl std::convert::TryFrom<Packet> 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 e3b4f32f..c208435b 100644
--- a/openpgp/src/parse.rs
+++ b/openpgp/src/parse.rs
@@ -2944,6 +2944,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.
///
@@ -4276,6 +4288,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),
@@ -4536,6 +4558,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()),
}?;
@@ -4820,7 +4843,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 ad2cc354..e9e5d240 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<usize> {
+ 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(),
}
}
}