From acd6dfcd2c971bae87fd934aa117eb0f47d9a52b Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Thu, 2 Apr 2020 13:23:12 +0200 Subject: openpgp: Rename. --- openpgp/src/serialize.rs | 3293 ++++++++++++++++++++++++++++++++++++++++++ openpgp/src/serialize/mod.rs | 3293 ------------------------------------------ 2 files changed, 3293 insertions(+), 3293 deletions(-) create mode 100644 openpgp/src/serialize.rs delete mode 100644 openpgp/src/serialize/mod.rs (limited to 'openpgp') diff --git a/openpgp/src/serialize.rs b/openpgp/src/serialize.rs new file mode 100644 index 00000000..7049f421 --- /dev/null +++ b/openpgp/src/serialize.rs @@ -0,0 +1,3293 @@ +//! Packet serialization infrastructure. +//! +//! There are two interfaces to serialize OpenPGP data. Which one is +//! applicable depends on whether or not the packet structure is +//! already assembled in memory, with all information already in place +//! (e.g. because it was parsed). +//! +//! If it is, you can use the [`Serialize`] or [`SerializeInto`] +//! trait. Otherwise, please use our [streaming serialization +//! interface]. +//! +//! [`Serialize`]: trait.Serialize.html +//! [`SerializeInto`]: trait.SerializeInto.html +//! [streaming serialization interface]: stream/index.html + +use std::io::{self, Write}; +use std::cmp; +use std::convert::TryFrom; + +use super::*; + +mod partial_body; +mod sexp; +mod cert; +pub use self::cert::TSK; +mod cert_armored; +use self::partial_body::PartialBodyFilter; +pub mod writer; +pub mod stream; +#[cfg(feature = "compression-deflate")] +pub mod padding; +use crate::crypto::S2K; +use crate::packet::header::{ + BodyLength, + CTB, + CTBNew, + CTBOld, +}; +use crate::packet::signature::subpacket::{ + SubpacketArea, Subpacket, SubpacketValue, +}; +use crate::packet::prelude::*; +use crate::types::{ + RevocationKey, + Timestamp, +}; + +// Whether to trace the modules execution (on stderr). +const TRACE : bool = false; + +/// Serializes OpenPGP data structures. +/// +/// This trait provides the same interface as the `Marshal` trait (in +/// fact, it is just a wrapper around that trait), but only data +/// structures that it makes sense to export implement it. +/// +/// Having a separate trait for data structures that it makes sense to +/// export avoids an easy-to-make and hard-to-debug bug: inadvertently +/// exporting an OpenPGP data structure without any framing +/// information. +/// +/// This bug is easy to make, because Rust infers types, which means +/// that it is often not clear from the immediate context exactly what +/// is being serialized. This bug is hard to debug, because errors +/// parsing data that has been incorrectly exported, are removed from +/// the serialization code. +/// +/// The following example shows how to correctly export a revocation +/// certificate. It should make clear how easy it is to forget to +/// convert a bare signature into an OpenPGP packet before serializing +/// it: +/// +/// ``` +/// # extern crate sequoia_openpgp as openpgp; +/// # use openpgp::Result; +/// use openpgp::cert::prelude::*; +/// use openpgp::Packet; +/// use openpgp::serialize::Serialize; +/// +/// # fn main() { f().unwrap(); } +/// # fn f() -> Result<()> { +/// let (_cert, rev) = +/// CertBuilder::general_purpose(None, Some("alice@example.org")) +/// .generate()?; +/// let rev : Packet = rev.into(); +/// # let output = &mut Vec::new(); +/// rev.serialize(output)?; +/// # Ok(()) +/// # } +/// ``` +/// +/// Note: if you `use` both `Serialize` and `Marshal`, then, because +/// they both have the same methods, and all data structures that +/// implement `Serialize` also implement `Marshal`, you will have to +/// use the Universal Function Call Syntax (UFCS) to call the methods +/// on those objects, for example: +/// +/// ``` +/// # extern crate sequoia_openpgp as openpgp; +/// # use openpgp::Result; +/// # use openpgp::cert::prelude::*; +/// # use openpgp::Packet; +/// # use openpgp::serialize::Serialize; +/// # +/// # fn main() { f().unwrap(); } +/// # fn f() -> Result<()> { +/// # let (_cert, rev) = +/// # CertBuilder::general_purpose(None, Some("alice@example.org")) +/// # .generate()?; +/// # let rev : Packet = rev.into(); +/// # let output = &mut Vec::new(); +/// Serialize::serialize(&rev, output)?; +/// # Ok(()) +/// # } +/// ``` +/// +/// If you really needed `Marshal`, we strongly recommend importing it +/// in as small a scope as possible to avoid this, and to avoid +/// accidentally exporting data without the required framing. +pub trait Serialize : Marshal { + /// Writes a serialized version of the object to `o`. + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + Marshal::serialize(self, o) + } + + /// Exports a serialized version of the object to `o`. + /// + /// This is similar to [`serialize(..)`], with these exceptions: + /// + /// - It is an error to export a [`Signature`] if it is marked + /// as non-exportable. + /// - When exporting a [`Cert`], non-exportable signatures are + /// not exported, and any component bound merely by + /// non-exportable signatures is not exported. + /// + /// [`serialize(..)`]: #tymethod.serialize + /// [`Signature`]: ../packet/enum.Signature.html + /// [`Cert`]: ../struct.Cert.html + fn export(&self, o: &mut dyn std::io::Write) -> Result<()> { + Marshal::export(self, o) + } +} + +/// Serializes OpenPGP data structures. +/// +/// This trait provides the same interface as `Serialize`, but is +/// implemented for all data structures that can be serialized. +/// +/// In general, you should prefer the `Serialize` trait, as it is only +/// implemented for data structures that are normally exported. See +/// the documentation for `Serialize` for more details. +pub trait Marshal { + /// Writes a serialized version of the object to `o`. + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()>; + + /// Exports a serialized version of the object to `o`. + /// + /// This is similar to [`serialize(..)`], with these exceptions: + /// + /// - It is an error to export a [`Signature`] if it is marked + /// as non-exportable. + /// - When exporting a [`Cert`], non-exportable signatures are + /// not exported, and any component bound merely by + /// non-exportable signatures is not exported. + /// + /// [`serialize(..)`]: #tymethod.serialize + /// [`Signature`]: ../packet/enum.Signature.html + /// [`Cert`]: ../struct.Cert.html + fn export(&self, o: &mut dyn std::io::Write) -> Result<()> { + self.serialize(o) + } +} + +/// Serializes OpenPGP data structures into pre-allocated buffers. +/// +/// This trait provides the same interface as `MarshalInto`, but is +/// only implemented for data structures that can be serialized. +/// +/// In general, you should prefer this trait to `MarshalInto`, as it +/// is only implemented for data structures that are normally +/// exported. See the documentation for `Serialize` for more details. +pub trait SerializeInto : MarshalInto { + /// Computes the maximal length of the serialized representation. + /// + /// # Errors + /// + /// If serialization would fail, this function underestimates the + /// length. + fn serialized_len(&self) -> usize { + MarshalInto::serialized_len(self) + } + + /// Serializes into the given buffer. + /// + /// Returns the length of the serialized representation. + /// + /// # Errors + /// + /// If the length of the given slice is smaller than the maximal + /// length computed by `serialized_len()`, this function returns + /// `Error::InvalidArgument`. + fn serialize_into(&self, buf: &mut [u8]) -> Result { + MarshalInto::serialize_into(self, buf) + } + + /// Serializes the packet to a vector. + fn to_vec(&self) -> Result> { + MarshalInto::to_vec(self) + } + + /// Exports into the given buffer. + /// + /// This is similar to [`serialize_into(..)`], with these + /// exceptions: + /// + /// - It is an error to export a [`Signature`] if it is marked + /// as non-exportable. + /// - When exporting a [`Cert`], non-exportable signatures are + /// not exported, and any component bound merely by + /// non-exportable signatures is not exported. + /// + /// [`serialize_into(..)`]: #tymethod.serialize_into + /// [`Signature`]: ../packet/enum.Signature.html + /// [`Cert`]: ../struct.Cert.html + /// + /// Returns the length of the serialized representation. + /// + /// # Errors + /// + /// If the length of the given slice is smaller than the maximal + /// length computed by `serialized_len()`, this function returns + /// `Error::InvalidArgument`. + fn export_into(&self, buf: &mut [u8]) -> Result { + MarshalInto::export_into(self, buf) + } + + /// Exports to a vector. + /// + /// This is similar to [`to_vec()`], with these exceptions: + /// + /// - It is an error to export a [`Signature`] if it is marked + /// as non-exportable. + /// - When exporting a [`Cert`], non-exportable signatures are + /// not exported, and any component bound merely by + /// non-exportable signatures is not exported. + /// + /// [`to_vec()`]: #method.to_vec + /// [`Signature`]: ../packet/enum.Signature.html + /// [`Cert`]: ../struct.Cert.html + fn export_to_vec(&self) -> Result> { + MarshalInto::export_to_vec(self) + } +} + +/// Serializes OpenPGP data structures into pre-allocated buffers. +/// +/// This trait provides the same interface as `SerializeInto`, but is +/// implemented for all data structures that can be serialized. +/// +/// In general, you should prefer the `SerializeInto` trait, as it is +/// only implemented for data structures that are normally exported. +/// See the documentation for `Serialize` for more details. +pub trait MarshalInto { + /// Computes the maximal length of the serialized representation. + /// + /// # Errors + /// + /// If serialization would fail, this function underestimates the + /// length. + fn serialized_len(&self) -> usize; + + /// Serializes into the given buffer. + /// + /// Returns the length of the serialized representation. + /// + /// # Errors + /// + /// If the length of the given slice is smaller than the maximal + /// length computed by `serialized_len()`, this function returns + /// `Error::InvalidArgument`. + fn serialize_into(&self, buf: &mut [u8]) -> Result; + + /// Serializes the packet to a vector. + fn to_vec(&self) -> Result> { + let mut o = vec![0; self.serialized_len()]; + let len = self.serialize_into(&mut o[..])?; + vec_truncate(&mut o, len); + o.shrink_to_fit(); + Ok(o) + } + + /// Exports into the given buffer. + /// + /// This is similar to [`serialize_into(..)`], with these + /// exceptions: + /// + /// - It is an error to export a [`Signature`] if it is marked + /// as non-exportable. + /// - When exporting a [`Cert`], non-exportable signatures are + /// not exported, and any component bound merely by + /// non-exportable signatures is not exported. + /// + /// [`serialize_into(..)`]: #tymethod.serialize_into + /// [`Signature`]: ../packet/enum.Signature.html + /// [`Cert`]: ../struct.Cert.html + /// + /// Returns the length of the serialized representation. + /// + /// # Errors + /// + /// If the length of the given slice is smaller than the maximal + /// length computed by `serialized_len()`, this function returns + /// `Error::InvalidArgument`. + fn export_into(&self, buf: &mut [u8]) -> Result { + self.serialize_into(buf) + } + + /// Exports to a vector. + /// + /// This is similar to [`to_vec()`], with these exceptions: + /// + /// - It is an error to export a [`Signature`] if it is marked + /// as non-exportable. + /// - When exporting a [`Cert`], non-exportable signatures are + /// not exported, and any component bound merely by + /// non-exportable signatures is not exported. + /// + /// [`to_vec()`]: #method.to_vec + /// [`Signature`]: ../packet/enum.Signature.html + /// [`Cert`]: ../struct.Cert.html + fn export_to_vec(&self) -> Result> { + let mut o = vec![0; self.serialized_len()]; + let len = self.export_into(&mut o[..])?; + vec_truncate(&mut o, len); + o.shrink_to_fit(); + Ok(o) + } +} + +trait NetLength { + /// Computes the maximal length of the serialized representation + /// without framing. + /// + /// # Errors + /// + /// If serialization would fail, this function underestimates the + /// length. + fn net_len(&self) -> usize; + + /// Computes the maximal length of the serialized representation + /// with framing. + /// + /// # Errors + /// + /// If serialization would fail, this function underestimates the + /// length. + fn gross_len(&self) -> usize { + let net = self.net_len(); + + 1 // CTB + + BodyLength::Full(net as u32).serialized_len() + + net + } +} + +/// Provides a generic implementation for SerializeInto::serialize_into. +/// +/// For now, we express SerializeInto using Serialize. In the future, +/// we may provide implementations not relying on Serialize for a +/// no_std configuration of this crate. +fn generic_serialize_into(o: &T, buf: &mut [u8]) + -> Result { + let buf_len = buf.len(); + let mut cursor = ::std::io::Cursor::new(buf); + match o.serialize(&mut cursor) { + Ok(_) => (), + Err(e) => { + let short_write = + if let Some(ioe) = e.downcast_ref::() { + ioe.kind() == io::ErrorKind::WriteZero + } else { + false + }; + return if short_write { + assert!(buf_len < o.serialized_len(), + "o.serialized_len() underestimated the required space"); + Err(Error::InvalidArgument( + format!("Invalid buffer size, expected {}, got {}", + o.serialized_len(), buf_len)).into()) + } else { + Err(e) + } + } + }; + Ok(cursor.position() as usize) +} + +/// Provides a generic implementation for SerializeInto::export_into. +/// +/// For now, we express SerializeInto using Serialize. In the future, +/// we may provide implementations not relying on Serialize for a +/// no_std configuration of this crate. +fn generic_export_into(o: &T, buf: &mut [u8]) + -> Result { + let buf_len = buf.len(); + let mut cursor = ::std::io::Cursor::new(buf); + match o.export(&mut cursor) { + Ok(_) => (), + Err(e) => { + let short_write = + if let Some(ioe) = e.downcast_ref::() { + ioe.kind() == io::ErrorKind::WriteZero + } else { + false + }; + return if short_write { + assert!(buf_len < o.serialized_len(), + "o.serialized_len() underestimated the required space"); + Err(Error::InvalidArgument( + format!("Invalid buffer size, expected {}, got {}", + o.serialized_len(), buf_len)).into()) + } else { + Err(e) + } + } + }; + Ok(cursor.position() as usize) +} + +#[test] +fn test_generic_serialize_into() { + let u = UserID::from("Mr. Pink"); + let mut b = vec![0; u.serialized_len()]; + u.serialize_into(&mut b[..]).unwrap(); + + // Short buffer. + let mut b = vec![0; u.serialized_len() - 1]; + let e = u.serialize_into(&mut b[..]).unwrap_err(); + assert_match!(Some(Error::InvalidArgument(_)) = e.downcast_ref()); +} + +#[test] +fn test_generic_export_into() { + let u = UserID::from("Mr. Pink"); + let mut b = vec![0; u.serialized_len()]; + u.export_into(&mut b[..]).unwrap(); + + // Short buffer. + let mut b = vec![0; u.serialized_len() - 1]; + let e = u.export_into(&mut b[..]).unwrap_err(); + assert_match!(Some(Error::InvalidArgument(_)) = e.downcast_ref()); +} + +fn write_byte(o: &mut dyn std::io::Write, b: u8) -> io::Result<()> { + let b : [u8; 1] = [b; 1]; + o.write_all(&b[..]) +} + +fn write_be_u16(o: &mut dyn std::io::Write, n: u16) -> io::Result<()> { + let b : [u8; 2] = [ ((n >> 8) & 0xFF) as u8, (n & 0xFF) as u8 ]; + o.write_all(&b[..]) +} + +fn write_be_u32(o: &mut dyn std::io::Write, n: u32) -> io::Result<()> { + let b : [u8; 4] = [ (n >> 24) as u8, ((n >> 16) & 0xFF) as u8, + ((n >> 8) & 0xFF) as u8, (n & 0xFF) as u8 ]; + o.write_all(&b[..]) +} + +// Compute the log2 of an integer. (This is simply the most +// significant bit.) Note: log2(0) = -Inf, but this function returns +// log2(0) as 0 (which is the closest number that we can represent). +fn log2(x: u32) -> usize { + if x == 0 { + 0 + } else { + 31 - x.leading_zeros() as usize + } +} + +#[test] +fn log2_test() { + for i in 0..32 { + // eprintln!("log2(1 << {} = {}) = {}", i, 1u32 << i, log2(1u32 << i)); + assert_eq!(log2(1u32 << i), i); + if i > 0 { + assert_eq!(log2((1u32 << i) - 1), i - 1); + assert_eq!(log2((1u32 << i) + 1), i); + } + } +} + +impl Marshal for BodyLength { + /// Emits the length encoded for use with new-style CTBs. + /// + /// Note: the CTB itself is not emitted. + /// + /// # Errors + /// + /// Returns [`Error::InvalidArgument`] if invoked on + /// [`BodyLength::Indeterminate`]. If you want to serialize an + /// old-style length, use [`serialize_old(..)`]. + /// + /// [`Error::InvalidArgument`]: ../../enum.Error.html#variant.InvalidArgument + /// [`BodyLength::Indeterminate`]: #variant.Indeterminate + /// [`serialize_old(..)`]: #method.serialize_old + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + match self { + &BodyLength::Full(l) => { + if l <= 191 { + write_byte(o, l as u8)?; + } else if l <= 8383 { + let v = l - 192; + let v = v + (192 << 8); + write_be_u16(o, v as u16)?; + } else { + write_byte(o, 0xff)?; + write_be_u32(o, l)?; + } + }, + &BodyLength::Partial(l) => { + if l > 1 << 30 { + return Err(Error::InvalidArgument( + format!("Partial length too large: {}", l)).into()); + } + + let chunk_size_log2 = log2(l); + let chunk_size = 1 << chunk_size_log2; + + if l != chunk_size { + return Err(Error::InvalidArgument( + format!("Not a power of two: {}", l)).into()); + } + + let size_byte = 224 + chunk_size_log2; + assert!(size_byte < 255); + write_byte(o, size_byte as u8)?; + }, + &BodyLength::Indeterminate => + return Err(Error::InvalidArgument( + "Indeterminate lengths are not support for new format packets". + into()).into()), + } + + Ok(()) + } +} + +impl MarshalInto for BodyLength { + fn serialized_len(&self) -> usize { + match self { + &BodyLength::Full(l) => { + if l <= 191 { + 1 + } else if l <= 8383 { + 2 + } else { + 5 + } + }, + &BodyLength::Partial(_) => 1, + &BodyLength::Indeterminate => 0, + } + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl BodyLength { + /// Emits the length encoded for use with old-style CTBs. + /// + /// Note: the CTB itself is not emitted. + /// + /// # Errors + /// + /// Returns [`Error::InvalidArgument`] if invoked on + /// [`BodyLength::Partial`]. If you want to serialize a + /// new-style length, use [`serialize(..)`]. + /// + /// [`Error::InvalidArgument`]: ../../enum.Error.html#variant.InvalidArgument + /// [`BodyLength::Partial`]: #variant.Partial + /// [`serialize(..)`]: #impl-Serialize + pub fn serialize_old(&self, o: &mut W) -> Result<()> { + // Assume an optimal encoding is desired. + let mut buffer = Vec::with_capacity(4); + match self { + &BodyLength::Full(l) => { + match l { + // One octet length. + // write_byte can't fail for a Vec. + 0 ..= 0xFF => + write_byte(&mut buffer, l as u8).unwrap(), + // Two octet length. + 0x1_00 ..= 0xFF_FF => + write_be_u16(&mut buffer, l as u16).unwrap(), + // Four octet length, + _ => + write_be_u32(&mut buffer, l as u32).unwrap(), + } + }, + &BodyLength::Indeterminate => {}, + &BodyLength::Partial(_) => + return Err(Error::InvalidArgument( + "Partial body lengths are not support for old format packets". + into()).into()), + } + + o.write_all(&buffer)?; + Ok(()) + } +} + +impl Marshal for CTBNew { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + let tag: u8 = self.tag().into(); + o.write_all(&[0b1100_0000u8 | tag])?; + Ok(()) + } +} + +impl MarshalInto for CTBNew { + fn serialized_len(&self) -> usize { 1 } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for CTBOld { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + let tag: u8 = self.tag().into(); + let length_type: u8 = self.length_type.into(); + o.write_all(&[0b1000_0000u8 | (tag << 2) | length_type])?; + Ok(()) + } +} + +impl MarshalInto for CTBOld { + fn serialized_len(&self) -> usize { 1 } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for CTB { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + match self { + &CTB::New(ref c) => c.serialize(o), + &CTB::Old(ref c) => c.serialize(o), + }?; + Ok(()) + } +} + +impl MarshalInto for CTB { + fn serialized_len(&self) -> usize { 1 } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for Header { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + self.ctb().serialize(o)?; + self.length().serialize(o)?; + Ok(()) + } +} + +impl Serialize for KeyID {} +impl Marshal for KeyID { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + let raw = match self { + &KeyID::V4(ref fp) => &fp[..], + &KeyID::Invalid(ref fp) => &fp[..], + }; + o.write_all(raw)?; + Ok(()) + } +} + +impl SerializeInto for KeyID {} +impl MarshalInto for KeyID { + fn serialized_len(&self) -> usize { + match self { + &KeyID::V4(_) => 8, + &KeyID::Invalid(ref fp) => fp.len(), + } + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Serialize for Fingerprint {} +impl Marshal for Fingerprint { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + o.write_all(self.as_slice())?; + Ok(()) + } +} + +impl SerializeInto for Fingerprint {} +impl MarshalInto for Fingerprint { + fn serialized_len(&self) -> usize { + match self { + Fingerprint::V4(_) => 20, + Fingerprint::Invalid(ref fp) => fp.len(), + } + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for crypto::mpis::MPI { + fn serialize(&self, w: &mut dyn std::io::Write) -> Result<()> { + write_be_u16(w, self.bits() as u16)?; + w.write_all(self.value())?; + Ok(()) + } +} + +impl MarshalInto for crypto::mpis::MPI { + fn serialized_len(&self) -> usize { + 2 + self.value().len() + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for crypto::mpis::ProtectedMPI { + fn serialize(&self, w: &mut dyn std::io::Write) -> Result<()> { + write_be_u16(w, self.bits() as u16)?; + w.write_all(self.value())?; + Ok(()) + } +} + +impl MarshalInto for crypto::mpis::ProtectedMPI { + fn serialized_len(&self) -> usize { + 2 + self.value().len() + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for crypto::mpis::PublicKey { + fn serialize(&self, w: &mut dyn std::io::Write) -> Result<()> { + use crate::crypto::mpis::PublicKey::*; + + match self { + &RSA { ref e, ref n } => { + n.serialize(w)?; + e.serialize(w)?; + } + + &DSA { ref p, ref q, ref g, ref y } => { + p.serialize(w)?; + q.serialize(w)?; + g.serialize(w)?; + y.serialize(w)?; + } + + &ElGamal { ref p, ref g, ref y } => { + p.serialize(w)?; + g.serialize(w)?; + y.serialize(w)?; + } + + &EdDSA { ref curve, ref q } => { + w.write_all(&[curve.oid().len() as u8])?; + w.write_all(curve.oid())?; + q.serialize(w)?; + } + + &ECDSA { ref curve, ref q } => { + w.write_all(&[curve.oid().len() as u8])?; + w.write_all(curve.oid())?; + q.serialize(w)?; + } + + &ECDH { ref curve, ref q, hash, sym } => { + w.write_all(&[curve.oid().len() as u8])?; + w.write_all(curve.oid())?; + q.serialize(w)?; + w.write_all(&[3u8, 1u8, u8::from(hash), u8::from(sym)])?; + } + + &Unknown { ref mpis, ref rest } => { + for mpi in mpis.iter() { + mpi.serialize(w)?; + } + w.write_all(rest)?; + } + + __Nonexhaustive => unreachable!(), + } + + Ok(()) + } +} + +impl MarshalInto for crypto::mpis::PublicKey { + fn serialized_len(&self) -> usize { + use crate::crypto::mpis::PublicKey::*; + match self { + &RSA { ref e, ref n } => { + n.serialized_len() + e.serialized_len() + } + + &DSA { ref p, ref q, ref g, ref y } => { + p.serialized_len() + q.serialized_len() + g.serialized_len() + + y.serialized_len() + } + + &ElGamal { ref p, ref g, ref y } => { + p.serialized_len() + g.serialized_len() + y.serialized_len() + } + + &EdDSA { ref curve, ref q } => { + 1 + curve.oid().len() + q.serialized_len() + } + + &ECDSA { ref curve, ref q } => { + 1 + curve.oid().len() + q.serialized_len() + } + + &ECDH { ref curve, ref q, hash: _, sym: _ } => { + 1 + curve.oid().len() + q.serialized_len() + 4 + } + + &Unknown { ref mpis, ref rest } => { + mpis.iter().map(|mpi| mpi.serialized_len()).sum::() + + rest.len() + } + + __Nonexhaustive => unreachable!(), + } + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for crypto::mpis::SecretKeyMaterial { + fn serialize(&self, w: &mut dyn std::io::Write) -> Result<()> { + use crate::crypto::mpis::SecretKeyMaterial::*; + + match self { + &RSA{ ref d, ref p, ref q, ref u } => { + d.serialize(w)?; + p.serialize(w)?; + q.serialize(w)?; + u.serialize(w)?; + } + + &DSA{ ref x } => { + x.serialize(w)?; + } + + &ElGamal{ ref x } => { + x.serialize(w)?; + } + + &EdDSA{ ref scalar } => { + scalar.serialize(w)?; + } + + &ECDSA{ ref scalar } => { + scalar.serialize(w)?; + } + + &ECDH{ ref scalar } => { + scalar.serialize(w)?; + } + + &Unknown { ref mpis, ref rest } => { + for mpi in mpis.iter() { + mpi.serialize(w)?; + } + w.write_all(rest)?; + } + + __Nonexhaustive => unreachable!(), + } + + Ok(()) + } +} + +impl MarshalInto for crypto::mpis::SecretKeyMaterial { + fn serialized_len(&self) -> usize { + use crate::crypto::mpis::SecretKeyMaterial::*; + match self { + &RSA{ ref d, ref p, ref q, ref u } => { + d.serialized_len() + p.serialized_len() + q.serialized_len() + + u.serialized_len() + } + + &DSA{ ref x } => { + x.serialized_len() + } + + &ElGamal{ ref x } => { + x.serialized_len() + } + + &EdDSA{ ref scalar } => { + scalar.serialized_len() + } + + &ECDSA{ ref scalar } => { + scalar.serialized_len() + } + + &ECDH{ ref scalar } => { + scalar.serialized_len() + } + + &Unknown { ref mpis, ref rest } => { + mpis.iter().map(|mpi| mpi.serialized_len()).sum::() + + rest.len() + } + + __Nonexhaustive => unreachable!(), + } + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl crypto::mpis::SecretKeyMaterial { + /// Writes this secret key with a checksum to `w`. + pub fn serialize_chksumd(&self, w: &mut W) -> Result<()> { + // First, the MPIs. + self.serialize(w)?; + + // The checksum is SHA1 over the serialized MPIs. + let mut hash = HashAlgorithm::SHA1.context().unwrap(); + self.serialize(&mut hash)?; + let mut digest = [0u8; 20]; + hash.digest(&mut digest); + w.write_all(&digest)?; + + Ok(()) + } +} + +impl Marshal for crypto::mpis::Ciphertext { + fn serialize(&self, w: &mut dyn std::io::Write) -> Result<()> { + use crate::crypto::mpis::Ciphertext::*; + + match self { + &RSA{ ref c } => { + c.serialize(w)?; + } + + &ElGamal{ ref e, ref c } => { + e.serialize(w)?; + c.serialize(w)?; + } + + &ECDH{ ref e, ref key } => { + e.serialize(w)?; + + w.write_all(&[key.len() as u8])?; + w.write_all(&key)?; + } + + &Unknown { ref mpis, ref rest } => { + for mpi in mpis.iter() { + mpi.serialize(w)?; + } + w.write_all(rest)?; + } + + __Nonexhaustive => unreachable!(), + } + + Ok(()) + } +} + +impl MarshalInto for crypto::mpis::Ciphertext { + fn serialized_len(&self) -> usize { + use crate::crypto::mpis::Ciphertext::*; + match self { + &RSA{ ref c } => { + c.serialized_len() + } + + &ElGamal{ ref e, ref c } => { + e.serialized_len() + c.serialized_len() + } + + &ECDH{ ref e, ref key } => { + e.serialized_len() + 1 + key.len() + } + + &Unknown { ref mpis, ref rest } => { + mpis.iter().map(|mpi| mpi.serialized_len()).sum::() + + rest.len() + } + + __Nonexhaustive => unreachable!(), + } + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for crypto::mpis::Signature { + fn serialize(&self, w: &mut dyn std::io::Write) -> Result<()> { + use crate::crypto::mpis::Signature::*; + + match self { + &RSA { ref s } => { + s.serialize(w)?; + } + &DSA { ref r, ref s } => { + r.serialize(w)?; + s.serialize(w)?; + } + &ElGamal { ref r, ref s } => { + r.serialize(w)?; + s.serialize(w)?; + } + &EdDSA { ref r, ref s } => { + r.serialize(w)?; + s.serialize(w)?; + } + &ECDSA { ref r, ref s } => { + r.serialize(w)?; + s.serialize(w)?; + } + + &Unknown { ref mpis, ref rest } => { + for mpi in mpis.iter() { + mpi.serialize(w)?; + } + w.write_all(rest)?; + } + + __Nonexhaustive => unreachable!(), + } + + Ok(()) + } +} + +impl MarshalInto for crypto::mpis::Signature { + fn serialized_len(&self) -> usize { + use crate::crypto::mpis::Signature::*; + match self { + &RSA { ref s } => { + s.serialized_len() + } + &DSA { ref r, ref s } => { + r.serialized_len() + s.serialized_len() + } + &ElGamal { ref r, ref s } => { + r.serialized_len() + s.serialized_len() + } + &EdDSA { ref r, ref s } => { + r.serialized_len() + s.serialized_len() + } + &ECDSA { ref r, ref s } => { + r.serialized_len() + s.serialized_len() + } + + &Unknown { ref mpis, ref rest } => { + mpis.iter().map(|mpi| mpi.serialized_len()).sum::() + + rest.len() + } + + __Nonexhaustive => unreachable!(), + } + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for S2K { + fn serialize(&self, w: &mut dyn std::io::Write) -> Result<()> { + match self { + &S2K::Simple{ hash } => { + w.write_all(&[0, hash.into()])?; + } + &S2K::Salted{ hash, salt } => { + w.write_all(&[1, hash.into()])?; + w.write_all(&salt[..])?; + } + &S2K::Iterated{ hash, salt, hash_bytes } => { + w.write_all(&[3, hash.into()])?; + w.write_all(&salt[..])?; + w.write_all(&[S2K::encode_count(hash_bytes)?])?; + } + &S2K::Private(s2k) | &S2K::Unknown(s2k) => { + w.write_all(&[s2k])?; + } + } + + Ok(()) + } +} + +impl MarshalInto for S2K { + fn serialized_len(&self) -> usize { + match self { + &S2K::Simple{ .. } => 2, + &S2K::Salted{ .. } => 2 + 8, + &S2K::Iterated{ .. } => 2 + 8 + 1, + &S2K::Private(_) | &S2K::Unknown(_) => 1, + } + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for Unknown { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + o.write_all(self.body())?; + Ok(()) + } +} + +impl NetLength for Unknown { + fn net_len(&self) -> usize { + self.body().len() + } +} + +impl MarshalInto for Unknown { + fn serialized_len(&self) -> usize { + self.net_len() + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for SubpacketArea { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + for sb in self.iter() { + sb.serialize(o)?; + } + Ok(()) + } +} + +impl MarshalInto for SubpacketArea { + fn serialized_len(&self) -> usize { + self.iter().map(|sb| sb.serialized_len()).sum() + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + let mut written = 0; + for sb in self.iter() { + let n = sb.serialize_into(&mut buf[written..])?; + written += cmp::min(buf.len() - written, n); + } + Ok(written) + } +} + +impl Marshal for Subpacket { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + let tag = u8::from(self.tag()) + | if self.critical() { 1 << 7 } else { 0 }; + + self.length.serialize(o)?; + o.write_all(&[tag])?; + self.value().serialize(o) + } +} + +impl MarshalInto for Subpacket { + fn serialized_len(&self) -> usize { + self.length.serialized_len() + 1 + self.value().serialized_len() + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for SubpacketValue { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + use self::SubpacketValue::*; + match self { + SignatureCreationTime(t) => + write_be_u32(o, t.clone().into())?, + SignatureExpirationTime(t) => + write_be_u32(o, t.clone().into())?, + ExportableCertification(e) => + o.write_all(&[if *e { 1 } else { 0 }])?, + TrustSignature { ref level, ref trust } => + o.write_all(&[*level, *trust])?, + RegularExpression(ref re) => { + o.write_all(re)?; + o.write_all(&[0])?; + }, + Revocable(r) => + o.write_all(&[if *r { 1 } else { 0 }])?, + KeyExpirationTime(t) => + write_be_u32(o, t.clone().into())?, + PreferredSymmetricAlgorithms(ref p) => + for a in p { + o.write_all(&[(*a).into()])?; + }, + RevocationKey(rk) => rk.serialize(o)?, + Issuer(ref id) => + o.write_all(id.as_slice())?, + NotationData(nd) => { + write_be_u32(o, nd.flags().raw())?; + write_be_u16(o, nd.name().len() as u16)?; + write_be_u16(o, nd.value().len() as u16)?; + o.write_all(nd.name().as_bytes())?; + o.write_all(nd.value())?; + }, + PreferredHashAlgorithms(ref p) => + for a in p { + o.write_all(&[(*a).into()])?; + }, + PreferredCompressionAlgorithms(ref p) => + for a in p { + o.write_all(&[(*a).into()])?; + }, + KeyServerPreferences(ref p) => + o.write_all(&p.to_vec())?, + PreferredKeyServer(ref p) => + o.write_all(p)?, + PrimaryUserID(p) => + o.write_all(&[if *p { 1 } else { 0 }])?, + PolicyURI(ref p) => + o.write_all(p)?, + KeyFlags(ref f) => + o.write_all(&f.to_vec())?, + SignersUserID(ref uid) => + o.write_all(uid)?, + ReasonForRevocation { ref code, ref reason } => { + o.write_all(&[(*code).into()])?; + o.write_all(reason)?; + }, + Features(ref f) => + o.write_all(&f.to_vec())?, + SignatureTarget { pk_algo, hash_algo, ref digest } => { + o.write_all(&[(*pk_algo).into(), (*hash_algo).into()])?; + o.write_all(digest)?; + }, + EmbeddedSignature(sig) => sig.serialize(o)?, + IssuerFingerprint(ref fp) => match fp { + Fingerprint::V4(_) => { + o.write_all(&[4])?; + o.write_all(fp.as_slice())?; + }, + _ => return Err(Error::InvalidArgument( + "Unknown kind of fingerprint".into()).into()), + } + PreferredAEADAlgorithms(ref p) => + for a in p { + o.write_all(&[(*a).into()])?; + }, + IntendedRecipient(ref fp) => match fp { + Fingerprint::V4(_) => { + o.write_all(&[4])?; + o.write_all(fp.as_slice())?; + }, + _ => return Err(Error::InvalidArgument( + "Unknown kind of fingerprint".into()).into()), + } + Unknown { body, .. } => + o.write_all(body)?, + __Nonexhaustive => unreachable!(), + } + Ok(()) + } +} + +impl MarshalInto for SubpacketValue { + fn serialized_len(&self) -> usize { + use self::SubpacketValue::*; + match self { + SignatureCreationTime(_) => 4, + SignatureExpirationTime(_) => 4, + ExportableCertification(_) => 1, + TrustSignature { .. } => 2, + RegularExpression(ref re) => re.len() + 1, + Revocable(_) => 1, + KeyExpirationTime(_) => 4, + PreferredSymmetricAlgorithms(ref p) => p.len(), + RevocationKey(rk) => rk.serialized_len(), + Issuer(ref id) => (id as &dyn MarshalInto).serialized_len(), + NotationData(nd) => 4 + 2 + 2 + nd.name().len() + nd.value().len(), + PreferredHashAlgorithms(ref p) => p.len(), + PreferredCompressionAlgorithms(ref p) => p.len(), + KeyServerPreferences(ref p) => p.to_vec().len(), + PreferredKeyServer(ref p) => p.len(), + PrimaryUserID(_) => 1, + PolicyURI(ref p) => p.len(), + KeyFlags(ref f) => f.to_vec().len(), + SignersUserID(ref uid) => uid.len(), + ReasonForRevocation { ref reason, .. } => 1 + reason.len(), + Features(ref f) => f.to_vec().len(), + SignatureTarget { ref digest, .. } => 2 + digest.len(), + EmbeddedSignature(sig) => sig.serialized_len(), + IssuerFingerprint(ref fp) => match fp { + Fingerprint::V4(_) => + 1 + (fp as &dyn MarshalInto).serialized_len(), + // Educated guess for unknown versions. + Fingerprint::Invalid(_) => 1 + fp.as_slice().len(), + }, + PreferredAEADAlgorithms(ref p) => p.len(), + IntendedRecipient(ref fp) => match fp { + Fingerprint::V4(_) => + 1 + (fp as &dyn MarshalInto).serialized_len(), + // Educated guess for unknown versions. + Fingerprint::Invalid(_) => 1 + fp.as_slice().len(), + }, + Unknown { body, .. } => body.len(), + __Nonexhaustive => unreachable!(), + } + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for RevocationKey { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + let (pk_algo, fp) = self.revoker(); + o.write_all(&[self.class(), (pk_algo).into()])?; + o.write_all(fp.as_slice())?; + Ok(()) + } +} + +impl MarshalInto for RevocationKey { + fn serialized_len(&self) -> usize { + 1 + 1 + self.revoker().1.as_slice().len() + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for Signature { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + match self { + &Signature::V4(ref s) => s.serialize(o), + Signature::__Nonexhaustive => unreachable!(), + } + } + + fn export(&self, o: &mut dyn std::io::Write) -> Result<()> { + match self { + &Signature::V4(ref s) => s.export(o), + Signature::__Nonexhaustive => unreachable!(), + } + } +} + +impl MarshalInto for Signature { + fn serialized_len(&self) -> usize { + match self { + &Signature::V4(ref s) => s.serialized_len(), + Signature::__Nonexhaustive => unreachable!(), + } + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + match self { + &Signature::V4(ref s) => s.serialize_into(buf), + Signature::__Nonexhaustive => unreachable!(), + } + } + + fn export_into(&self, buf: &mut [u8]) -> Result { + match self { + &Signature::V4(ref s) => s.export_into(buf), + Signature::__Nonexhaustive => unreachable!(), + } + } + + fn export_to_vec(&self) -> Result> { + match self { + &Signature::V4(ref s) => s.export_to_vec(), + Signature::__Nonexhaustive => unreachable!(), + } + } +} + +impl Marshal for Signature4 { + /// Writes a serialized version of the specified `Signature` + /// packet to `o`. + /// + /// # Errors + /// + /// Returns [`Error::InvalidArgument`] if either the hashed-area + /// or the unhashed-area exceeds the size limit of 2^16. + /// + /// [`Error::InvalidArgument`]: ../../enum.Error.html#variant.InvalidArgument + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + assert_eq!(self.version(), 4); + write_byte(o, self.version())?; + write_byte(o, self.typ().into())?; + write_byte(o, self.pk_algo().into())?; + write_byte(o, self.hash_algo().into())?; + + let l = self.hashed_area().serialized_len(); + if l > std::u16::MAX as usize { + return Err(Error::InvalidArgument( + "Hashed area too large".into()).into()); + } + write_be_u16(o, l as u16)?; + self.hashed_area().serialize(o)?; + + let l = self.unhashed_area().serialized_len(); + if l > std::u16::MAX as usize { + return Err(Error::InvalidArgument( + "Unhashed area too large".into()).into()); + } + write_be_u16(o, l as u16)?; + self.unhashed_area().serialize(o)?; + + write_byte(o, self.digest_prefix()[0])?; + write_byte(o, self.digest_prefix()[1])?; + + self.mpis().serialize(o)?; + + Ok(()) + } + + fn export(&self, o: &mut dyn std::io::Write) -> Result<()> { + self.exportable()?; + self.serialize(o) + } +} + +impl NetLength for Signature4 { + fn net_len(&self) -> usize { + 1 // Version. + + 1 // Signature type. + + 1 // PK algorithm. + + 1 // Hash algorithm. + + 2 // Hashed area size. + + self.hashed_area().serialized_len() + + 2 // Unhashed area size. + + self.unhashed_area().serialized_len() + + 2 // Hash prefix. + + self.mpis().serialized_len() + } +} + +impl MarshalInto for Signature4 { + fn serialized_len(&self) -> usize { + self.net_len() + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } + + fn export_into(&self, buf: &mut [u8]) -> Result { + if ! self.exportable_certification().unwrap_or(true) { + return Err(Error::InvalidOperation( + "Cannot export non-exportable certification".into()).into()); + } + + self.serialize_into(buf) + } + + fn export_to_vec(&self) -> Result> { + if ! self.exportable_certification().unwrap_or(true) { + return Err(Error::InvalidOperation( + "Cannot export non-exportable certification".into()).into()); + } + + self.to_vec() + } +} + +impl Marshal for OnePassSig { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + match self { + &OnePassSig::V3(ref s) => s.serialize(o), + OnePassSig::__Nonexhaustive => unreachable!(), + } + } +} + +impl MarshalInto for OnePassSig { + fn serialized_len(&self) -> usize { + match self { + &OnePassSig::V3(ref s) => s.serialized_len(), + OnePassSig::__Nonexhaustive => unreachable!(), + } + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + match self { + &OnePassSig::V3(ref s) => s.serialize_into(buf), + OnePassSig::__Nonexhaustive => unreachable!(), + } + } +} + +impl Marshal for OnePassSig3 { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + write_byte(o, 3)?; // Version. + write_byte(o, self.typ().into())?; + write_byte(o, self.hash_algo().into())?; + write_byte(o, self.pk_algo().into())?; + o.write_all(self.issuer().as_slice())?; + write_byte(o, self.last_raw())?; + + Ok(()) + } +} + +impl NetLength for OnePassSig3 { + fn net_len(&self) -> usize { + 1 // Version. + + 1 // Signature type. + + 1 // Hash algorithm + + 1 // PK algorithm. + + 8 // Issuer. + + 1 // Last. + } +} + +impl MarshalInto for OnePassSig3 { + fn serialized_len(&self) -> usize { + self.net_len() + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for Key { + fn serialize(&self, o: &mut dyn io::Write) -> Result<()> { + match self { + &Key::V4(ref p) => p.serialize(o), + Key::__Nonexhaustive => unreachable!(), + } + } +} + +impl Key { + fn net_len_key(&self, serialize_secrets: bool) -> usize { + match self { + &Key::V4(ref p) => p.net_len_key(serialize_secrets), + Key::__Nonexhaustive => unreachable!(), + } + } +} + +impl MarshalInto for Key { + fn serialized_len(&self) -> usize { + match self { + &Key::V4(ref p) => p.serialized_len(), + Key::__Nonexhaustive => unreachable!(), + } + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + match self { + &Key::V4(ref p) => p.serialize_into(buf), + Key::__Nonexhaustive => unreachable!(), + } + } +} + +impl Marshal for Key4 + where P: key::KeyParts, + R: key::KeyRole, +{ + fn serialize(&self, o: &mut dyn io::Write) -> Result<()> { + self.serialize_key(o, true) + } +} + +impl Key4 + where P: key::KeyParts, + R: key::KeyRole, +{ + pub(crate) // For tests in key. + fn serialize_key(&self, o: &mut dyn io::Write, serialize_secrets: bool) + -> Result<()> { + let have_secret_key = self.has_secret() && serialize_secrets; + + write_byte(o, 4)?; // Version. + write_be_u32(o, Timestamp::try_from(self.creation_time())?.into())?; + write_byte(o, self.pk_algo().into())?; + self.mpis().serialize(o)?; + + if have_secret_key { + match self.optional_secret().unwrap() { + SecretKeyMaterial::Unencrypted(ref u) => u.map(|mpis| -> Result<()> { + // S2K usage. + write_byte(o, 0)?; + + // To compute the checksum, serialize to a buffer first. + let mut buf = Vec::new(); + mpis.serialize(&mut buf)?; + let buf: crate::crypto::mem::Protected = buf.into(); + let checksum: usize = buf.iter().map(|x| *x as usize) + .sum(); + + // Then, just write out the buffer. + o.write_all(&buf)?; + write_be_u16(o, checksum as u16)?; + Ok(()) + })?, + SecretKeyMaterial::Encrypted(ref e) => { + // S2K usage. + write_byte(o, 254)?; + write_byte(o, e.algo().into())?; + e.s2k().serialize(o)?; + o.write_all(e.ciphertext())?; + }, + } + } + + Ok(()) + } + + fn net_len_key(&self, serialize_secrets: bool) -> usize { + let have_secret_key = self.has_secret() && serialize_secrets; + + 1 // Version. + + 4 // Creation time. + + 1 // PK algo. + + self.mpis().serialized_len() + + if have_secret_key { + 1 + match self.optional_secret().unwrap() { + SecretKeyMaterial::Unencrypted(ref u) => + u.map(|mpis| mpis.serialized_len()) + + 2, // Two octet checksum. + SecretKeyMaterial::Encrypted(ref e) => + 1 + e.s2k().serialized_len() + e.ciphertext().len(), + } + } else { + 0 + } + } +} + +impl MarshalInto for Key4 + where P: key::KeyParts, + R: key::KeyRole, +{ + fn serialized_len(&self) -> usize { + self.net_len_key(true) + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for Marker { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + o.write_all(Marker::BODY)?; + Ok(()) + } +} + +impl NetLength for Marker { + fn net_len(&self) -> usize { + Marker::BODY.len() + } +} + +impl MarshalInto for Marker { + fn serialized_len(&self) -> usize { + self.net_len() + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for Trust { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + o.write_all(self.value())?; + Ok(()) + } +} + +impl NetLength for Trust { + fn net_len(&self) -> usize { + self.value().len() + } +} + +impl MarshalInto for Trust { + fn serialized_len(&self) -> usize { + self.net_len() + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for UserID { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + o.write_all(self.value())?; + Ok(()) + } +} + +impl NetLength for UserID { + fn net_len(&self) -> usize { + self.value().len() + } +} + +impl MarshalInto for UserID { + fn serialized_len(&self) -> usize { + self.net_len() + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for UserAttribute { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + o.write_all(self.value())?; + Ok(()) + } +} + +impl NetLength for UserAttribute { + fn net_len(&self) -> usize { + self.value().len() + } +} + +impl MarshalInto for UserAttribute { + fn serialized_len(&self) -> usize { + self.net_len() + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for user_attribute::Subpacket { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + match self { + user_attribute::Subpacket::Image(image) => + image.serialize(o)?, + user_attribute::Subpacket::Unknown(tag, data) => { + BodyLength::Full(1 + data.len() as u32) + .serialize(o)?; + write_byte(o, *tag)?; + o.write_all(&data[..])?; + } + } + + Ok(()) + } +} + +impl MarshalInto for user_attribute::Subpacket { + fn serialized_len(&self) -> usize { + match self { + user_attribute::Subpacket::Image(image) => + image.serialized_len(), + user_attribute::Subpacket::Unknown(_tag, data) => { + let header_len = BodyLength::Full(1 + data.len() as u32) + .serialized_len(); + header_len + 1 + data.len() + } + } + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for user_attribute::Image { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + match self { + user_attribute::Image::JPEG(data) => { + let header = BodyLength::Full(1 + data.len() as u32); + header.serialize(o)?; + write_byte(o, 0)?; + o.write_all(&data[..])?; + } + user_attribute::Image::Unknown(tag, data) + | user_attribute::Image::Private(tag, data) => { + let header = BodyLength::Full(1 + data.len() as u32); + header.serialize(o)?; + write_byte(o, *tag)?; + o.write_all(&data[..])?; + } + } + + Ok(()) + } +} + +impl MarshalInto for user_attribute::Image { + fn serialized_len(&self) -> usize { + match self { + user_attribute::Image::JPEG(data) + | user_attribute::Image::Unknown(_, data) + | user_attribute::Image::Private(_, data) => + 1 + BodyLength::Full(1 + data.len() as u32).serialized_len() + + data.len(), + } + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Literal { + /// Writes the headers of the `Literal` data packet to `o`. + pub(crate) fn serialize_headers(&self, o: &mut dyn std::io::Write, + write_tag: bool) -> Result<()> + { + let filename = if let Some(ref filename) = self.filename() { + let len = cmp::min(filename.len(), 255) as u8; + &filename[..len as usize] + } else { + &b""[..] + }; + + let date = if let Some(d) = self.date() { + Timestamp::try_from(d)?.into() + } else { + 0 + }; + + if write_tag { + let len = 1 + (1 + filename.len()) + 4 + + self.body().len(); + CTB::new(Tag::Literal).serialize(o)?; + BodyLength::Full(len as u32).serialize(o)?; + } + write_byte(o, self.format().into())?; + write_byte(o, filename.len() as u8)?; + o.write_all(filename)?; + write_be_u32(o, date)?; + Ok(()) + } +} + +impl Marshal for Literal { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + let body = self.body(); + if TRACE { + let prefix = &body[..cmp::min(body.len(), 20)]; + eprintln!("Literal::serialize({}{}, {} bytes)", + String::from_utf8_lossy(prefix), + if body.len() > 20 { "..." } else { "" }, + body.len()); + } + + self.serialize_headers(o, false)?; + o.write_all(body)?; + + Ok(()) + } +} + +impl NetLength for Literal { + fn net_len(&self) -> usize { + 1 + (1 + self.filename().map(|f| f.len()).unwrap_or(0)) + 4 + + self.body().len() + } +} + +impl MarshalInto for Literal { + fn serialized_len(&self) -> usize { + self.net_len() + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for CompressedData { + /// Writes a serialized version of the specified `CompressedData` + /// packet to `o`. + /// + /// 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<()> { + match self.body() { + Body::Unprocessed(bytes) => { + if TRACE { + eprintln!("CompressedData::serialize(\ + algo: {}, {} bytes of unprocessed body)", + self.algo(), bytes.len()); + } + + o.write_all(&[self.algo().into()])?; + o.write_all(bytes)?; + }, + + Body::Processed(bytes) => { + if TRACE { + eprintln!("CompressedData::serialize(\ + algo: {}, {} bytes of processed 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(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 { + // Worst case, the data gets larger. Account for that. + // Experiments suggest that the overhead of compressing random + // data is worse for BZIP2, but it converges to 20% starting + // at ~2k of random data. + let compressed = |l| l + cmp::max(l / 5, 4096); + + 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::()), + } + } +} + +impl MarshalInto for CompressedData { + /// Computes the maximal length of the serialized representation. + /// + /// The size of the serialized compressed data packet is tricky to + /// predict. First, it depends on the data being compressed. + /// Second, we emit partial body encoded data. + /// + /// This function tries overestimates the length. However, it may + /// happen that `serialize_into()` fails. + /// + /// # Errors + /// + /// If serialization would fail, this function returns 0. + fn serialized_len(&self) -> usize { + self.net_len() + } + + fn serialize_into(&self, buf: &mut [u8]) -> Result { + generic_serialize_into(self, buf) + } +} + +impl Marshal for PKESK { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + match self { + &PKESK::V3(ref p) => p.serialize(o), + PKESK::__Nonexhaustive => unreachable!(), + } + } +} + +impl MarshalInto for PKESK { + fn serialized_len(&self