sequoia_openpgp/packet/
unknown.rs

1use std::hash::{Hash, Hasher};
2use std::cmp::Ordering;
3
4use crate::packet::Tag;
5use crate::packet;
6use crate::Packet;
7use crate::policy::HashAlgoSecurity;
8
9/// Holds an unknown packet.
10///
11/// This is used by the parser to hold packets that it doesn't know
12/// how to process rather than abort.
13///
14/// This packet effectively holds a binary blob.
15///
16/// # A note on equality
17///
18/// Two `Unknown` packets are considered equal if their tags and their
19/// bodies are equal.
20#[derive(Debug)]
21pub struct Unknown {
22    /// CTB packet header fields.
23    pub(crate) common: packet::Common,
24    /// Packet tag.
25    tag: Tag,
26    /// Error that caused parsing or processing to abort.
27    error: anyhow::Error,
28    /// The unknown data packet is a container packet, but cannot
29    /// store packets.
30    ///
31    /// This is written when serialized, and set by the packet parser
32    /// if `buffer_unread_content` is used.
33    container: packet::Container,
34}
35
36assert_send_and_sync!(Unknown);
37
38impl PartialEq for Unknown {
39    fn eq(&self, other: &Unknown) -> bool {
40        self.tag == other.tag
41            && self.container == other.container
42    }
43}
44
45impl Eq for Unknown { }
46
47impl Hash for Unknown {
48    fn hash<H: Hasher>(&self, state: &mut H) {
49        self.tag.hash(state);
50        self.container.hash(state);
51    }
52}
53
54impl Clone for Unknown {
55    fn clone(&self) -> Self {
56        Unknown {
57            common: self.common.clone(),
58            tag: self.tag,
59            error: {
60                // anyhow::Error isn't Clone, so we cannot, in
61                // general, duplicate the error without losing
62                // information.  We can try to downcast to the most
63                // likely errors, and clone them, but this can never
64                // cover all possibilities.
65                use std::io;
66
67                if let Some(e) = self.error.downcast_ref::<crate::Error>() {
68                    e.clone().into()
69                } else if let Some(e) = self.error.downcast_ref::<io::Error>() {
70                    if let Some(wrapped) = e.get_ref() {
71                        // The wrapped error isn't clone, so this
72                        // loses information here.  This will always
73                        // be lossy, even once we changed this crate
74                        // to return concrete errors.
75                        io::Error::new(e.kind(), wrapped.to_string()).into()
76                    } else {
77                        io::Error::from(e.kind()).into()
78                    }
79                } else {
80                    // Here, we lose information, but the conversion
81                    // was lossy before.
82                    crate::Error::InvalidOperation(self.error.to_string())
83                        .into()
84                }
85            },
86            container: self.container.clone(),
87        }
88    }
89}
90
91
92impl Unknown {
93    /// Returns a new `Unknown` packet.
94    pub fn new(tag: Tag, error: anyhow::Error) -> Self {
95        Unknown {
96            common: Default::default(),
97            tag,
98            error,
99            container: packet::Container::default_unprocessed(),
100        }
101    }
102
103    /// The security requirements of the hash algorithm for
104    /// self-signatures.
105    ///
106    /// A cryptographic hash algorithm usually has [three security
107    /// properties]: pre-image resistance, second pre-image
108    /// resistance, and collision resistance.  If an attacker can
109    /// influence the signed data, then the hash algorithm needs to
110    /// have both second pre-image resistance, and collision
111    /// resistance.  If not, second pre-image resistance is
112    /// sufficient.
113    ///
114    ///   [three security properties]: https://en.wikipedia.org/wiki/Cryptographic_hash_function#Properties
115    ///
116    /// In general, an attacker may be able to influence third-party
117    /// signatures.  But direct key signatures, and binding signatures
118    /// are only over data fully determined by signer.  And, an
119    /// attacker's control over self signatures over User IDs is
120    /// limited due to their structure.
121    ///
122    /// These observations can be used to extend the life of a hash
123    /// algorithm after its collision resistance has been partially
124    /// compromised, but not completely broken.  For more details,
125    /// please refer to the documentation for [HashAlgoSecurity].
126    ///
127    ///   [HashAlgoSecurity]: crate::policy::HashAlgoSecurity
128    pub fn hash_algo_security(&self) -> HashAlgoSecurity {
129        HashAlgoSecurity::CollisionResistance
130    }
131
132    /// Gets the unknown packet's tag.
133    pub fn tag(&self) -> Tag {
134        self.tag
135    }
136
137    /// Sets the unknown packet's tag.
138    pub fn set_tag(&mut self, tag: Tag) -> Tag {
139        ::std::mem::replace(&mut self.tag, tag)
140    }
141
142    /// Gets the unknown packet's error.
143    ///
144    /// This is the error that caused parsing or processing to abort.
145    pub fn error(&self) -> &anyhow::Error {
146        &self.error
147    }
148
149    /// Sets the unknown packet's error.
150    ///
151    /// This is the error that caused parsing or processing to abort.
152    pub fn set_error(&mut self, error: anyhow::Error) -> anyhow::Error {
153        ::std::mem::replace(&mut self.error, error)
154    }
155
156    /// Returns the error.
157    pub fn into_error(self) -> anyhow::Error {
158        self.error
159    }
160
161    /// Best effort Ord implementation.
162    ///
163    /// The Cert canonicalization needs to order Unknown packets.
164    /// However, due to potential streaming, Unknown cannot implement
165    /// Eq.  This is cheating a little, we simply ignore the streaming
166    /// case.
167    pub(crate) // For cert/mod.rs
168    fn best_effort_cmp(&self, other: &Unknown) -> Ordering {
169        self.tag.cmp(&other.tag).then_with(|| self.body().cmp(other.body()))
170    }
171}
172
173impl_unprocessed_body_forwards!(Unknown);
174
175impl From<Unknown> for Packet {
176    fn from(s: Unknown) -> Self {
177        Packet::Unknown(s)
178    }
179}
180
181impl std::convert::TryFrom<Packet> for Unknown {
182    type Error = crate::Error;
183
184    /// Tries to convert a packet to an `Unknown`.  Returns an error
185    /// if the given packet is a container packet (i.e. a compressed
186    /// data packet or an encrypted data packet of any kind).
187    fn try_from(p: Packet) -> std::result::Result<Self, Self::Error> {
188        use packet::{Any, Body, Common, Container};
189        use crate::serialize::MarshalInto;
190
191        let tag = p.tag();
192
193        // First, short-circuit happy and unhappy paths so that we
194        // avoid copying the potentially large packet parser maps in
195        // common.
196        match &p {
197            // Happy path.
198            Packet::Unknown(_) =>
199                return Ok(p.downcast().expect("is an unknown")),
200
201            // The container packets we flat-out refuse to convert.
202            // The Unknown packet has an unprocessed body, and we
203            // cannot recreate that from processed or structured
204            // bodies.
205            Packet::CompressedData(_)
206                | Packet::SEIP(_) =>
207                return Err(Self::Error::InvalidOperation(
208                    format!("Cannot convert {} to unknown packets", tag))),
209
210            _ => (),
211        }
212
213        // Now we copy the common bits that we'll need.
214        let common = p.common().clone();
215
216        fn convert<V>(tag: Tag, common: Common, body: V)
217                      -> Result<Unknown, crate::Error>
218        where
219            V: MarshalInto,
220        {
221            let container = {
222                let mut c = Container::default_unprocessed();
223                c.set_body(Body::Unprocessed(
224                    body.to_vec().expect("infallible serialization")));
225                c
226            };
227
228            Ok(Unknown {
229                container,
230                common,
231                tag,
232                error: crate::Error::MalformedPacket(
233                    format!("Implicit conversion from {} to unknown packet",
234                            tag)).into(),
235            })
236        }
237
238        match p {
239            // Happy path.
240            Packet::Unknown(_) => unreachable!("handled above"),
241
242            // These packets convert infallibly.
243            Packet::Signature(v) => convert(tag, common, v),
244            Packet::OnePassSig(v) => convert(tag, common, v),
245            Packet::PublicKey(v) => convert(tag, common, v),
246            Packet::PublicSubkey(v) => convert(tag, common, v),
247            Packet::SecretKey(v) => convert(tag, common, v),
248            Packet::SecretSubkey(v) => convert(tag, common, v),
249            Packet::Marker(v) => convert(tag, common, v),
250            Packet::Trust(v) => convert(tag, common, v),
251            Packet::UserID(v) => convert(tag, common, v),
252            Packet::UserAttribute(v) => convert(tag, common, v),
253            Packet::PKESK(v) => convert(tag, common, v),
254            Packet::SKESK(v) => convert(tag, common, v),
255            #[allow(deprecated)]
256            Packet::MDC(v) => convert(tag, common, v),
257            Packet::Padding(v) => convert(tag, common, v), // XXX: can we do better like for the Literal?
258
259            // Here we can avoid copying the body.
260            Packet::Literal(mut v) => {
261                let container = {
262                    let mut c = Container::default_unprocessed();
263                    // Get v's body out without copying.
264                    c.set_body(Body::Unprocessed(v.set_body(
265                        Vec::with_capacity(0))));
266                    c
267                };
268                let common = v.common.clone(); // XXX why can't I decompose `p`?
269
270                Ok(Unknown {
271                    container,
272                    common,
273                    tag,
274                    error: crate::Error::MalformedPacket(
275                        format!("Implicit conversion from {} to unknown packet",
276                                tag)).into(),
277                })
278            },
279
280            // The container packets we flat-out refuse to convert.
281            // The Unknown packet has an unprocessed body, and we
282            // cannot recreate that from processed or structured
283            // bodies.
284            Packet::CompressedData(_)
285                | Packet::SEIP(_) => unreachable!("handled above"),
286        }
287    }
288}