Skip to main content

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