der/
error.rs

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