From 89337646884b59c894329432eea960be4b3e335e Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Thu, 26 Mar 2020 17:21:32 +0100 Subject: openpgp: Change packet bodies to be tristate. - Packet bodies can now be either unprocessed (e.g. compressed, encrypted), processed (e.g. uncompressed, decrypted), or structured (e.g. parsed into packets). - Make the container types deref to Container, and container deref to packet bodies. - This cleanly avoids the confusion when serializing containers: We can serialize compressed data packets with either body, but we can only serialize encryption containers with unprocessed bodies. - Fixes #187. --- openpgp/src/serialize/mod.rs | 139 +++++++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 57 deletions(-) (limited to 'openpgp/src/serialize') diff --git a/openpgp/src/serialize/mod.rs b/openpgp/src/serialize/mod.rs index e8d9b38b..0fc09f8a 100644 --- a/openpgp/src/serialize/mod.rs +++ b/openpgp/src/serialize/mod.rs @@ -1919,42 +1919,69 @@ impl Marshal for CompressedData { /// This function works recursively: if the `CompressedData` packet /// contains any packets, they are also serialized. fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { - if TRACE { - eprintln!("CompressedData::serialize(\ - algo: {}, {:?} children, {:?} bytes)", - self.algo(), - self.children().count(), - self.body().len()); - } + match self.body() { + Body::Unprocessed(bytes) => { + if TRACE { + eprintln!("CompressedData::serialize(\ + algo: {}, {} bytes of unprocessed body)", + self.algo(), bytes.len()); + } - let o = stream::Message::new(o); - let mut o = stream::Compressor::new_naked( - o, self.algo(), Default::default(), 0)?; + o.write_all(&[self.algo().into()])?; + o.write_all(bytes)?; + }, - // Serialize the packets. - for p in self.children() { - (p as &dyn Marshal).serialize(&mut o)?; - } + Body::Processed(bytes) => { + if TRACE { + eprintln!("CompressedData::serialize(\ + algo: {}, {} bytes of processed body)", + self.algo(), bytes.len()); + } - // Append the data. - o.write_all(self.body())?; - o.finalize() + let o = stream::Message::new(o); + let mut o = stream::Compressor::new_naked( + o, self.algo(), Default::default(), 0)?; + o.write_all(bytes)?; + o.finalize()?; + }, + + Body::Structured(children) => { + if TRACE { + eprintln!("CompressedData::serialize(\ + algo: {}, {:?} children)", + self.algo(), children.len()); + } + + let o = stream::Message::new(o); + let mut o = stream::Compressor::new_naked( + o, self.algo(), Default::default(), 0)?; + + // Serialize the packets. + for p in children { + (p as &dyn Marshal).serialize(&mut o)?; + } + + o.finalize()?; + }, + } + Ok(()) } } impl NetLength for CompressedData { fn net_len(&self) -> usize { - let inner_length = - self.children().map(|p| { - (p as &dyn MarshalInto).serialized_len() - }).sum::() - + self.body().len(); - // Worst case, the data gets larger. Account for that. - let inner_length = inner_length + cmp::max(inner_length / 2, 128); + let compressed = |l| l + cmp::max(l / 2, 128); - 1 // Algorithm. - + inner_length // Compressed data. + match self.body() { + Body::Unprocessed(bytes) => 1 /* Algo */ + bytes.len(), + Body::Processed(bytes) => 1 /* Algo */ + compressed(bytes.len()), + Body::Structured(packets) => + 1 // Algo + + compressed(packets.iter().map(|p| { + (p as &dyn MarshalInto).serialized_len() + }).sum::()), + } } } @@ -2153,33 +2180,31 @@ impl Marshal for SEIP { /// To construct an encrypted message, use /// `serialize::stream::Encryptor`. fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { - if self.children().next().is_some() { - return Err(Error::InvalidOperation( + match self.body() { + Body::Unprocessed(bytes) => { + o.write_all(&[self.version()])?; + o.write_all(bytes)?; + Ok(()) + }, + _ => Err(Error::InvalidOperation( "Cannot encrypt, use serialize::stream::Encryptor".into()) - .into()); - } else { - o.write_all(&[self.version()])?; - o.write_all(self.body())?; + .into()), } - - Ok(()) } } impl NetLength for SEIP { fn net_len(&self) -> usize { - 1 // Version. - + self.body().len() + match self.body() { + Body::Unprocessed(bytes) => 1 /* Version */ + bytes.len(), + _ => 0, + } } } impl MarshalInto for SEIP { fn serialized_len(&self) -> usize { - if self.children().next().is_some() { - 0 // XXX - } else { - self.gross_len() - } + self.gross_len() } fn serialize_into(&self, buf: &mut [u8]) -> Result { @@ -2257,34 +2282,34 @@ impl Marshal for AED1 { /// To construct an encrypted message, use /// `serialize::stream::Encryptor`. fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { - if self.children().next().is_some() { - return Err(Error::InvalidOperation( + match self.body() { + Body::Unprocessed(bytes) => { + self.serialize_headers(o)?; + o.write_all(bytes)?; + Ok(()) + }, + _ => Err(Error::InvalidOperation( "Cannot encrypt, use serialize::stream::Encryptor".into()) - .into()); - } else { - self.serialize_headers(o)?; - o.write_all(self.body())?; + .into()), } - - Ok(()) } } impl NetLength for AED1 { fn net_len(&self) -> usize { - if self.children().next().is_some() { - 0 - } else { - 4 // Headers. + match self.body() { + Body::Unprocessed(bytes) => + 4 // Headers. + self.iv().len() - + self.body().len() + + bytes.len(), + _ => 0, } } } impl MarshalInto for AED1 { fn serialized_len(&self) -> usize { - self.net_len() + self.gross_len() } fn serialize_into(&self, buf: &mut [u8]) -> Result { @@ -2936,14 +2961,14 @@ mod test { eprintln!("Orig:"); let p = pile.children().next().unwrap(); eprintln!("{:?}", p); - let body = p.body().unwrap(); + let body = p.processed_body().unwrap(); eprintln!("Body: {}", body.len()); eprintln!("{}", binary_pp(body)); eprintln!("Reparsed:"); let p = pile2.children().next().unwrap(); eprintln!("{:?}", p); - let body = p.body().unwrap(); + let body = p.processed_body().unwrap(); eprintln!("Body: {}", body.len()); eprintln!("{}", binary_pp(body)); -- cgit v1.2.3