Skip to main content

pgp/
errors.rs

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