summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2022-05-12 15:42:51 +0200
committerJustus Winter <justus@sequoia-pgp.org>2022-06-08 10:54:52 +0200
commit0bc5fa77df3c9dc325afd824b413841b51a4e7ec (patch)
tree3890cc985bd58bf81e18ce71d909e7e9202968f3
parente049498509107f93849e86fc902d0dff49ae0a93 (diff)
openpgp: Implement TryFrom<Packet> for Unknown.
-rw-r--r--openpgp/NEWS3
-rw-r--r--openpgp/src/packet/unknown.rs110
2 files changed, 113 insertions, 0 deletions
diff --git a/openpgp/NEWS b/openpgp/NEWS
index 967ee426..a69105d7 100644
--- a/openpgp/NEWS
+++ b/openpgp/NEWS
@@ -2,6 +2,9 @@
#+TITLE: sequoia-openpgp NEWS – history of user-visible changes
#+STARTUP: content hidestars
+* Changes in 1.10.0
+** New functionality
+ - TryFrom<Packet> for Unknown
* Changes in 1.9.0
** New functionality
- AEADAlgorithm::nonce_size replaces AEADAlgorithm::iv_size
diff --git a/openpgp/src/packet/unknown.rs b/openpgp/src/packet/unknown.rs
index 50000a61..1302f407 100644
--- a/openpgp/src/packet/unknown.rs
+++ b/openpgp/src/packet/unknown.rs
@@ -146,3 +146,113 @@ impl From<Unknown> for Packet {
Packet::Unknown(s)
}
}
+
+impl std::convert::TryFrom<Packet> for Unknown {
+ type Error = crate::Error;
+
+ /// Tries to convert a packet to an `Unknown`. Returns an error
+ /// if the given packet is a container packet (i.e. a compressed
+ /// data packet or an encrypted data packet of any kind).
+ fn try_from(p: Packet) -> std::result::Result<Self, Self::Error> {
+ use std::ops::Deref;
+ use packet::{Any, Body, Common, Container};
+ use crate::serialize::MarshalInto;
+
+ let tag = p.tag();
+
+ // First, short-circuit happy and unhappy paths so that we
+ // avoid copying the potentially large packet parser maps in
+ // common.
+ match &p {
+ // Happy path.
+ Packet::Unknown(_) =>
+ return Ok(p.downcast().expect("is an unknown")),
+
+ // The container packets we flat-out refuse to convert.
+ // The Unknown packet has an unprocessed body, and we
+ // cannot recreate that from processed or structured
+ // bodies.
+ Packet::CompressedData(_)
+ | Packet::SEIP(_)
+ | Packet::AED(_) =>
+ return Err(Self::Error::InvalidOperation(
+ format!("Cannot convert {} to unknown packets", tag))),
+
+ _ => (),
+ }
+
+ // Now we copy the common bits that we'll need.
+ let common = p.deref().clone();
+
+ fn convert<V>(tag: Tag, common: Common, body: V)
+ -> Result<Unknown, crate::Error>
+ where
+ V: MarshalInto,
+ {
+ let container = {
+ let mut c = Container::default_unprocessed();
+ c.set_body(Body::Unprocessed(
+ body.to_vec().expect("infallible serialization")));
+ c
+ };
+
+ Ok(Unknown {
+ container,
+ common,
+ tag,
+ error: crate::Error::MalformedPacket(
+ format!("Implicit conversion from {} to unknown packet",
+ tag)).into(),
+ })
+ }
+
+ match p {
+ // Happy path.
+ Packet::Unknown(_) => unreachable!("handled above"),
+
+ // These packets convert infallibly.
+ Packet::Signature(v) => convert(tag, common, v),
+ Packet::OnePassSig(v) => convert(tag, common, v),
+ Packet::PublicKey(v) => convert(tag, common, v),
+ Packet::PublicSubkey(v) => convert(tag, common, v),
+ Packet::SecretKey(v) => convert(tag, common, v),
+ Packet::SecretSubkey(v) => convert(tag, common, v),
+ Packet::Marker(v) => convert(tag, common, v),
+ Packet::Trust(v) => convert(tag, common, v),
+ Packet::UserID(v) => convert(tag, common, v),
+ Packet::UserAttribute(v) => convert(tag, common, v),
+ Packet::PKESK(v) => convert(tag, common, v),
+ Packet::SKESK(v) => convert(tag, common, v),
+ Packet::MDC(v) => convert(tag, common, v),
+
+ // Here we can avoid copying the body.
+ Packet::Literal(mut v) => {
+ let container = {
+ let mut c = Container::default_unprocessed();
+ // Get v's body out without copying.
+ c.set_body(Body::Unprocessed(v.set_body(
+ Vec::with_capacity(0))));
+ c
+ };
+ let common = v.common.clone(); // XXX why can't I decompose `p`?
+
+ Ok(Unknown {
+ container,
+ common,
+ tag,
+ error: crate::Error::MalformedPacket(
+ format!("Implicit conversion from {} to unknown packet",
+ tag)).into(),
+ })
+ },
+
+ // The container packets we flat-out refuse to convert.
+ // The Unknown packet has an unprocessed body, and we
+ // cannot recreate that from processed or structured
+ // bodies.
+ Packet::CompressedData(_)
+ | Packet::SEIP(_)
+ | Packet::AED(_) => unreachable!("handled above"),
+ }
+ }
+}