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}