der/
error.rs

1//! Error types.
2
3pub use core::str::Utf8Error;
4
5use crate::{Length, Tag};
6use core::{convert::Infallible, fmt, num::TryFromIntError};
7
8#[cfg(feature = "oid")]
9use crate::asn1::ObjectIdentifier;
10
11#[cfg(feature = "pem")]
12use crate::pem;
13
14/// Result type.
15pub type Result<T> = core::result::Result<T, Error>;
16
17/// Error type.
18#[derive(Copy, Clone, Debug, Eq, PartialEq)]
19pub struct Error {
20    /// Kind of error.
21    kind: ErrorKind,
22
23    /// Position inside of message where error occurred.
24    position: Option<Length>,
25}
26
27impl Error {
28    /// Create a new [`Error`].
29    pub fn new(kind: ErrorKind, position: Length) -> Error {
30        Error {
31            kind,
32            position: Some(position),
33        }
34    }
35
36    /// Create a new [`ErrorKind::Incomplete`] for the given length.
37    ///
38    /// Computes the expected len as being one greater than `actual_len`.
39    pub fn incomplete(actual_len: Length) -> Self {
40        match actual_len + Length::ONE {
41            Ok(expected_len) => ErrorKind::Incomplete {
42                expected_len,
43                actual_len,
44            }
45            .at(actual_len),
46            Err(err) => err.kind().at(actual_len),
47        }
48    }
49
50    /// Get the [`ErrorKind`] which occurred.
51    pub fn kind(self) -> ErrorKind {
52        self.kind
53    }
54
55    /// Get the position inside of the message where the error occurred.
56    pub fn position(self) -> Option<Length> {
57        self.position
58    }
59
60    /// For errors occurring inside of a nested message, extend the position
61    /// count by the location where the nested message occurs.
62    pub(crate) fn nested(self, nested_position: Length) -> Self {
63        // TODO(tarcieri): better handle length overflows occurring in this calculation?
64        let position = (nested_position + self.position.unwrap_or_default()).ok();
65
66        Self {
67            kind: self.kind,
68            position,
69        }
70    }
71}
72
73#[cfg(feature = "std")]
74impl std::error::Error for Error {}
75
76impl fmt::Display for Error {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        write!(f, "{}", self.kind)?;
79
80        if let Some(pos) = self.position {
81            write!(f, " at DER byte {}", pos)?;
82        }
83
84        Ok(())
85    }
86}
87
88impl From<ErrorKind> for Error {
89    fn from(kind: ErrorKind) -> Error {
90        Error {
91            kind,
92            position: None,
93        }
94    }
95}
96
97impl From<Infallible> for Error {
98    fn from(_: Infallible) -> Error {
99        unreachable!()
100    }
101}
102
103impl From<TryFromIntError> for Error {
104    fn from(_: TryFromIntError) -> Error {
105        Error {
106            kind: ErrorKind::Overflow,
107            position: None,
108        }
109    }
110}
111
112impl From<Utf8Error> for Error {
113    fn from(err: Utf8Error) -> Error {
114        Error {
115            kind: ErrorKind::Utf8(err),
116            position: None,
117        }
118    }
119}
120
121#[cfg(feature = "alloc")]
122impl From<alloc::string::FromUtf8Error> for Error {
123    fn from(err: alloc::string::FromUtf8Error) -> Error {
124        ErrorKind::Utf8(err.utf8_error()).into()
125    }
126}
127
128#[cfg(feature = "oid")]
129impl From<const_oid::Error> for Error {
130    fn from(_: const_oid::Error) -> Error {
131        ErrorKind::OidMalformed.into()
132    }
133}
134
135#[cfg(feature = "pem")]
136impl From<pem::Error> for Error {
137    fn from(err: pem::Error) -> Error {
138        ErrorKind::Pem(err).into()
139    }
140}
141
142#[cfg(feature = "std")]
143impl From<std::io::Error> for Error {
144    fn from(err: std::io::Error) -> Error {
145        match err.kind() {
146            std::io::ErrorKind::NotFound => ErrorKind::FileNotFound,
147            std::io::ErrorKind::PermissionDenied => ErrorKind::PermissionDenied,
148            other => ErrorKind::Io(other),
149        }
150        .into()
151    }
152}
153
154#[cfg(feature = "time")]
155impl From<time::error::ComponentRange> for Error {
156    fn from(_: time::error::ComponentRange) -> Error {
157        ErrorKind::DateTime.into()
158    }
159}
160
161/// Error type.
162#[derive(Copy, Clone, Debug, Eq, PartialEq)]
163#[non_exhaustive]
164pub enum ErrorKind {
165    /// Date-and-time related errors.
166    DateTime,
167
168    /// This error indicates a previous DER parsing operation resulted in
169    /// an error and tainted the state of a `Decoder` or `Encoder`.
170    ///
171    /// Once this occurs, the overall operation has failed and cannot be
172    /// subsequently resumed.
173    Failed,
174
175    /// File not found error.
176    #[cfg(feature = "std")]
177    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
178    FileNotFound,
179
180    /// Message is incomplete and does not contain all of the expected data.
181    Incomplete {
182        /// Expected message length.
183        ///
184        /// Note that this length represents a *minimum* lower bound on how
185        /// much additional data is needed to continue parsing the message.
186        ///
187        /// It's possible upon subsequent message parsing that the parser will
188        /// discover even more data is needed.
189        expected_len: Length,
190
191        /// Actual length of the message buffer currently being processed.
192        actual_len: Length,
193    },
194
195    /// I/O errors.
196    #[cfg(feature = "std")]
197    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
198    Io(std::io::ErrorKind),
199
200    /// Incorrect length for a given field.
201    Length {
202        /// Tag of the value being decoded.
203        tag: Tag,
204    },
205
206    /// Message is not canonically encoded.
207    Noncanonical {
208        /// Tag of the value which is not canonically encoded.
209        tag: Tag,
210    },
211
212    /// OID is improperly encoded.
213    OidMalformed,
214
215    /// Unknown OID.
216    ///
217    /// This error is intended to be used by libraries which parse DER-based
218    /// formats which encounter unknown or unsupported OID libraries.
219    ///
220    /// It enables passing back the OID value to the caller, which allows them
221    /// to determine which OID(s) are causing the error (and then potentially
222    /// contribute upstream support for algorithms they care about).
223    #[cfg(feature = "oid")]
224    #[cfg_attr(docsrs, doc(cfg(feature = "oid")))]
225    OidUnknown {
226        /// OID value that was unrecognized by a parser for a DER-based format.
227        oid: ObjectIdentifier,
228    },
229
230    /// `SET` ordering error: items not in canonical order.
231    SetOrdering,
232
233    /// Integer overflow occurred (library bug!).
234    Overflow,
235
236    /// Message is longer than this library's internal limits support.
237    Overlength,
238
239    /// PEM encoding errors.
240    #[cfg(feature = "pem")]
241    #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
242    Pem(pem::Error),
243
244    /// Permission denied reading file.
245    #[cfg(feature = "std")]
246    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
247    PermissionDenied,
248
249    /// Reader does not support the requested operation.
250    Reader,
251
252    /// Unknown tag mode.
253    TagModeUnknown,
254
255    /// Invalid tag number.
256    ///
257    /// The "tag number" is the lower 5-bits of a tag's octet.
258    /// This error occurs in the case that all 5-bits are set to `1`,
259    /// which indicates a multi-byte tag which is unsupported by this library.
260    TagNumberInvalid,
261
262    /// Unexpected tag.
263    TagUnexpected {
264        /// Tag the decoder was expecting (if there is a single such tag).
265        ///
266        /// `None` if multiple tags are expected/allowed, but the `actual` tag
267        /// does not match any of them.
268        expected: Option<Tag>,
269
270        /// Actual tag encountered in the message.
271        actual: Tag,
272    },
273
274    /// Unknown/unsupported tag.
275    TagUnknown {
276        /// Raw byte value of the tag.
277        byte: u8,
278    },
279
280    /// Undecoded trailing data at end of message.
281    TrailingData {
282        /// Length of the decoded data.
283        decoded: Length,
284
285        /// Total length of the remaining data left in the buffer.
286        remaining: Length,
287    },
288
289    /// UTF-8 errors.
290    Utf8(Utf8Error),
291
292    /// Unexpected value.
293    Value {
294        /// Tag of the unexpected value.
295        tag: Tag,
296    },
297}
298
299impl ErrorKind {
300    /// Annotate an [`ErrorKind`] with context about where it occurred,
301    /// returning an error.
302    pub fn at(self, position: Length) -> Error {
303        Error::new(self, position)
304    }
305}
306
307impl fmt::Display for ErrorKind {
308    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
309        match self {
310            ErrorKind::DateTime => write!(f, "date/time error"),
311            ErrorKind::Failed => write!(f, "operation failed"),
312            #[cfg(feature = "std")]
313            ErrorKind::FileNotFound => write!(f, "file not found"),
314            ErrorKind::Incomplete {
315                expected_len,
316                actual_len,
317            } => write!(
318                f,
319                "ASN.1 DER message is incomplete: expected {}, actual {}",
320                expected_len, actual_len
321            ),
322            #[cfg(feature = "std")]
323            ErrorKind::Io(err) => write!(f, "I/O error: {:?}", err),
324            ErrorKind::Length { tag } => write!(f, "incorrect length for {}", tag),
325            ErrorKind::Noncanonical { tag } => {
326                write!(f, "ASN.1 {} not canonically encoded as DER", tag)
327            }
328            ErrorKind::OidMalformed => write!(f, "malformed OID"),
329            #[cfg(feature = "oid")]
330            ErrorKind::OidUnknown { oid } => {
331                write!(f, "unknown/unsupported OID: {}", oid)
332            }
333            ErrorKind::SetOrdering => write!(f, "SET OF ordering error"),
334            ErrorKind::Overflow => write!(f, "integer overflow"),
335            ErrorKind::Overlength => write!(f, "ASN.1 DER message is too long"),
336            #[cfg(feature = "pem")]
337            ErrorKind::Pem(e) => write!(f, "PEM error: {}", e),
338            #[cfg(feature = "std")]
339            ErrorKind::PermissionDenied => write!(f, "permission denied"),
340            ErrorKind::Reader => write!(f, "reader does not support the requested operation"),
341            ErrorKind::TagModeUnknown => write!(f, "unknown tag mode"),
342            ErrorKind::TagNumberInvalid => write!(f, "invalid tag number"),
343            ErrorKind::TagUnexpected { expected, actual } => {
344                write!(f, "unexpected ASN.1 DER tag: ")?;
345
346                if let Some(tag) = expected {
347                    write!(f, "expected {}, ", tag)?;
348                }
349
350                write!(f, "got {}", actual)
351            }
352            ErrorKind::TagUnknown { byte } => {
353                write!(f, "unknown/unsupported ASN.1 DER tag: 0x{:02x}", byte)
354            }
355            ErrorKind::TrailingData { decoded, remaining } => {
356                write!(
357                    f,
358                    "trailing data at end of DER message: decoded {} bytes, {} bytes remaining",
359                    decoded, remaining
360                )
361            }
362            ErrorKind::Utf8(e) => write!(f, "{}", e),
363            ErrorKind::Value { tag } => write!(f, "malformed ASN.1 DER value for {}", tag),
364        }
365    }
366}