pgp/
errors.rs

1use std::num::TryFromIntError;
2
3use ed25519_dalek::SignatureError;
4use snafu::{Backtrace, Snafu};
5
6pub type Result<T, E = Error> = ::std::result::Result<T, E>;
7
8// custom nom error types
9pub const MPI_TOO_LONG: u32 = 1000;
10
11pub use crate::parsing::{Error as ParsingError, RemainingError};
12
13/// Error types
14#[derive(Debug, Snafu)]
15#[snafu(visibility(pub(crate)))]
16#[non_exhaustive]
17pub enum Error {
18    #[snafu(display("invalid input"))]
19    InvalidInput { backtrace: Option<Backtrace> },
20    #[snafu(display("invalid armor wrappers"))]
21    InvalidArmorWrappers,
22    #[snafu(display("invalid crc24 checksum"))]
23    InvalidChecksum,
24    #[snafu(transparent)]
25    Base64Decode {
26        source: base64::DecodeError,
27        backtrace: Option<Backtrace>,
28    },
29    #[snafu(display("requested data size is larger than the packet body"))]
30    RequestedSizeTooLarge,
31    #[snafu(display("no matching packet found"))]
32    NoMatchingPacket { backtrace: Option<Backtrace> },
33    #[snafu(display("more than one matching packet was found"))]
34    TooManyPackets,
35    #[snafu(display("packet contained more data than was parsable (trailing bytes {size})"))]
36    PacketTooLarge { size: u64 },
37    #[snafu(transparent)]
38    RSAError {
39        #[snafu(source(from(rsa::errors::Error, Box::new)))]
40        source: Box<rsa::errors::Error>,
41        backtrace: Option<Backtrace>,
42    },
43    #[snafu(transparent)]
44    EllipticCurve {
45        source: elliptic_curve::Error,
46        backtrace: Option<Backtrace>,
47    },
48    #[snafu(display("IO error: {}", source), context(false))]
49    IO {
50        source: std::io::Error,
51        backtrace: Option<Backtrace>,
52    },
53    #[snafu(display("invalid key length"))]
54    InvalidKeyLength,
55    #[snafu(display("block mode error"))]
56    BlockMode,
57    #[snafu(display("missing key"))]
58    MissingKey,
59    #[snafu(display("cfb: invalid key iv length"))]
60    CfbInvalidKeyIvLength,
61    #[snafu(display("Not yet implemented: {message}"))]
62    Unimplemented {
63        message: String,
64        backtrace: Option<Backtrace>,
65    },
66    /// Signals packet versions and parameters we don't support, but can safely ignore
67    #[snafu(display("Unsupported: {message}"))]
68    Unsupported {
69        message: String,
70        backtrace: Option<Backtrace>,
71    },
72    #[snafu(display("{message}"))]
73    Message {
74        message: String,
75        backtrace: Option<Backtrace>,
76    },
77    #[snafu(display("Invalid Packet {kind:?}"))]
78    PacketError { kind: nom::error::ErrorKind },
79    #[snafu(display("Unpadding failed"))]
80    UnpadError,
81    #[snafu(display("Padding failed"))]
82    PadError,
83    #[snafu(transparent)]
84    Utf8Error {
85        source: std::str::Utf8Error,
86        backtrace: Option<Backtrace>,
87    },
88    #[snafu(transparent)]
89    ParseIntError {
90        source: std::num::ParseIntError,
91        backtrace: Option<Backtrace>,
92    },
93    #[snafu(display("Invalid Packet Content {source:?}"))]
94    InvalidPacketContent { source: Box<Error> },
95    #[snafu(transparent)]
96    SignatureError { source: SignatureError },
97    #[snafu(display("Modification Detection Code error"))]
98    MdcError,
99    #[snafu(transparent)]
100    TryFromInt {
101        source: TryFromIntError,
102        backtrace: Option<Backtrace>,
103    },
104    #[snafu(display("AEAD {:?}", source), context(false))]
105    Aead { source: crate::crypto::aead::Error },
106    #[snafu(display("AES key wrap {:?}", source), context(false))]
107    AesKw {
108        source: crate::crypto::aes_kw::Error,
109    },
110    #[snafu(transparent)]
111    ChecksumMissmatch {
112        source: crate::crypto::checksum::ChecksumMismatch,
113    },
114    #[snafu(transparent)]
115    Sha1HashCollision {
116        source: crate::crypto::checksum::Sha1HashCollision,
117    },
118    #[snafu(transparent)]
119    AesKek { source: aes_kw::Error },
120    #[snafu(transparent)]
121    PacketParsing {
122        #[snafu(backtrace, source(from(ParsingError, Box::new)))]
123        source: Box<ParsingError>,
124    },
125    #[snafu(display("packet is incomplete"))]
126    PacketIncomplete {
127        #[snafu(backtrace)]
128        source: Box<ParsingError>,
129    },
130    #[snafu(transparent)]
131    Argon2 {
132        source: argon2::Error,
133        backtrace: Option<Backtrace>,
134    },
135    #[snafu(transparent)]
136    SigningError { source: cx448::SigningError },
137}
138
139impl From<crate::crypto::hash::Error> for Error {
140    fn from(err: crate::crypto::hash::Error) -> Self {
141        match err {
142            crate::crypto::hash::Error::Unsupported { alg } => UnsupportedSnafu {
143                message: format!("hash algorithm: {:?}", alg),
144            }
145            .build(),
146            crate::crypto::hash::Error::Sha1HashCollision { source } => source.into(),
147        }
148    }
149}
150
151impl<T> From<nom::error::Error<T>> for Error {
152    fn from(err: nom::error::Error<T>) -> Self {
153        Self::PacketError { kind: err.code }
154    }
155}
156
157impl From<cipher::InvalidLength> for Error {
158    fn from(_: cipher::InvalidLength) -> Error {
159        Error::CfbInvalidKeyIvLength
160    }
161}
162
163impl From<block_padding::UnpadError> for Error {
164    fn from(_: block_padding::UnpadError) -> Error {
165        Error::UnpadError
166    }
167}
168
169impl From<String> for Error {
170    fn from(err: String) -> Error {
171        Error::Message {
172            message: err,
173            backtrace: Some(snafu::GenerateImplicitData::generate()),
174        }
175    }
176}
177
178impl From<derive_builder::UninitializedFieldError> for Error {
179    fn from(err: derive_builder::UninitializedFieldError) -> Error {
180        Error::Message {
181            message: err.to_string(),
182            backtrace: Some(snafu::GenerateImplicitData::generate()),
183        }
184    }
185}
186
187macro_rules! unimplemented_err {
188    ($e:expr) => {
189        return Err($crate::errors::UnimplementedSnafu { message: $e.to_string() }.build())
190    };
191    ($fmt:expr, $($arg:tt)+) => {
192        return Err($crate::errors::UnimplementedSnafu { message: format!($fmt, $($arg)+)}.build())
193    };
194}
195
196macro_rules! unsupported_err {
197    ($e:expr) => {
198        return Err($crate::errors::UnsupportedSnafu {
199            message: $e.to_string(),
200        }.build())
201    };
202    ($fmt:expr, $($arg:tt)+) => {
203        return Err($crate::errors::UnsupportedSnafu {
204            message: format!($fmt, $($arg)+),
205        }.build())
206    };
207}
208
209macro_rules! bail {
210    ($e:expr) => {
211        return Err($crate::errors::Error::Message {
212            message: $e.to_string(),
213            backtrace: ::snafu::GenerateImplicitData::generate(),
214        })
215    };
216    ($fmt:expr, $($arg:tt)+) => {
217        return Err($crate::errors::Error::Message {
218            message: format!($fmt, $($arg)+),
219            backtrace: ::snafu::GenerateImplicitData::generate(),
220        })
221    };
222}
223
224macro_rules! format_err {
225    ($e:expr) => {
226        $crate::errors::Error::Message {
227            message: $e.to_string(),
228            backtrace: ::snafu::GenerateImplicitData::generate(),
229        }
230    };
231    ($fmt:expr, $($arg:tt)+) => {
232        $crate::errors::Error::Message {
233            message: format!($fmt, $($arg)+),
234            backtrace: ::snafu::GenerateImplicitData::generate(),
235        }
236    };
237}
238
239macro_rules! ensure {
240    ($cond:expr, $e:expr) => {
241        if !($cond) {
242            $crate::errors::bail!($e);
243        }
244    };
245    ($cond:expr, $fmt:expr, $($arg:tt)+) => {
246        if !($cond) {
247            $crate::errors::bail!($fmt, $($arg)+);
248        }
249    };
250}
251
252macro_rules! ensure_eq {
253    ($left:expr, $right:expr) => ({
254        match (&$left, &$right) {
255            (left_val, right_val) => {
256                if !(*left_val == *right_val) {
257                    $crate::errors::bail!(r#"assertion failed: `(left == right)`
258  left: `{:?}`,
259 right: `{:?}`"#, left_val, right_val)
260                }
261            }
262        }
263    });
264    ($left:expr, $right:expr,) => ({
265        $crate::errors::ensure_eq!($left, $right)
266    });
267    ($left:expr, $right:expr, $($arg:tt)+) => ({
268        match (&($left), &($right)) {
269            (left_val, right_val) => {
270                if !(*left_val == *right_val) {
271                    $crate::errors::bail!(r#"assertion failed: `(left == right)`
272  left: `{:?}`,
273 right: `{:?}`: {}"#, left_val, right_val,
274                           format_args!($($arg)+))
275                }
276            }
277        }
278    });
279}
280
281macro_rules! err_opt {
282    ($e:expr) => {
283        match $e {
284            Ok(v) => v,
285            Err(err) => return Some(Err(err)),
286        }
287    };
288}
289
290pub(crate) use bail;
291pub(crate) use ensure;
292pub(crate) use ensure_eq;
293pub(crate) use err_opt;
294pub(crate) use format_err;
295pub(crate) use unimplemented_err;
296pub(crate) use unsupported_err;
297
298#[cfg(test)]
299mod tests {
300    /// Check the size of the error enum
301    ///
302    /// Because clippy will start throwing warning if an enum gets above 128, we'd like to keep the
303    /// size of the `Error` enum lower than that limit with some headroom to be wrapped by a
304    /// downstream crate.
305    ///
306    /// If this test triggers, you should consider Box'ing the offending member.
307    ///
308    /// See: <https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err>
309    #[cfg(target_pointer_width = "64")]
310    #[test]
311    fn size_of_error() {
312        assert_eq!(core::mem::size_of::<super::Error>(), 80);
313    }
314}