flexiber/
error.rs

1//! Error types.
2
3// pub use core::str::Utf8Error;
4
5use crate::{Length, Tag};
6use core::{convert::Infallible, fmt};
7
8/// Result type.
9pub type Result<T> = core::result::Result<T, Error>;
10
11/// Error type.
12#[derive(Copy, Clone, Debug, Eq, PartialEq)]
13pub struct Error {
14    /// Kind of error
15    kind: ErrorKind,
16
17    /// Position inside of message where error occurred
18    position: Option<Length>,
19}
20
21impl Error {
22    /// Create a new [`Error`]
23    pub fn new(kind: ErrorKind, position: Length) -> Error {
24        Error {
25            kind,
26            position: Some(position),
27        }
28    }
29
30    /// Get the [`ErrorKind`] which occurred.
31    pub fn kind(self) -> ErrorKind {
32        self.kind
33    }
34
35    /// Get the position inside of the message where the error occurred.
36    pub fn position(self) -> Option<Length> {
37        self.position
38    }
39
40    /// For errors occurring inside of a nested message, extend the position
41    /// count by the location where the nested message occurs.
42    pub fn nested(self, nested_position: Length) -> Self {
43        // TODO(tarcieri): better handle length overflows occurring in this calculation?
44        let position = (nested_position + self.position.unwrap_or_default()).ok();
45
46        Self {
47            kind: self.kind,
48            position,
49        }
50    }
51}
52
53impl fmt::Display for Error {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        write!(f, "{}", self.kind)?;
56
57        if let Some(pos) = self.position {
58            write!(f, " at BER-TLV byte {}", pos)?;
59        }
60
61        Ok(())
62    }
63}
64
65#[cfg(feature = "std")]
66impl std::error::Error for Error {}
67
68impl From<ErrorKind> for Error {
69    fn from(kind: ErrorKind) -> Error {
70        Error {
71            kind,
72            position: None,
73        }
74    }
75}
76
77impl From<core::convert::Infallible> for Error {
78    fn from(_: Infallible) -> Error {
79        unreachable!()
80    }
81}
82
83// impl From<Utf8Error> for Error {
84//     fn from(err: Utf8Error) -> Error {
85//         Error {
86//             kind: ErrorKind::Utf8(err),
87//             position: None,
88//         }
89//     }
90// }
91
92// #[cfg(feature = "oid")]
93// impl From<const_oid::Error> for Error {
94//     fn from(_: const_oid::Error) -> Error {
95//         ErrorKind::Oid.into()
96//     }
97// }
98
99#[cfg(feature = "std")]
100impl std::error::Error for ErrorKind {}
101
102/// Error type.
103#[derive(Copy, Clone, Debug, Eq, PartialEq)]
104#[non_exhaustive]
105pub enum ErrorKind {
106    /// Operation failed due to previous error
107    Failed,
108
109    /// Class has more than 2 bytes
110    InvalidClass { value: u8 },
111
112    /// Invalid tag
113    InvalidTag {
114        /// Raw byte value of the tag
115        byte: u8,
116    },
117
118    /// Length greater than u16::MAX
119    InvalidLength,
120
121    /// Incorrect length for a given field
122    Length {
123        /// Tag type of the value being decoded
124        tag: Tag,
125    },
126
127    // /// Message is not canonically encoded
128    // Noncanonical,
129
130    // /// Malformed OID
131    // Oid,
132    /// Integer overflow occurred (library bug!)
133    Overflow,
134
135    /// Message is longer than BER-TLV's limits support
136    Overlength,
137
138    /// Undecoded trailing data at end of message
139    TrailingData {
140        /// Length of the decoded data
141        decoded: Length,
142
143        /// Total length of the remaining data left in the buffer
144        remaining: Length,
145    },
146
147    /// Unexpected end-of-message/nested field when decoding
148    Truncated,
149
150    /// Encoded message is shorter than the expected length
151    /// (i.e. an `Encodable` impl on a particular type has a buggy `encoded_length`)
152    Underlength {
153        /// Expected length
154        expected: Length,
155
156        /// Actual length
157        actual: Length,
158    },
159
160    /// Unexpected tag
161    UnexpectedTag {
162        /// Tag the decoder was expecting (if there is a single such tag).
163        ///
164        /// `None` if multiple tags are expected/allowed, but the `actual` tag
165        /// does not match any of them.
166        expected: Option<Tag>,
167
168        /// Actual tag encountered in the message
169        actual: Tag,
170    },
171
172    // /// Unknown/unsupported tag
173    // UnknownTag {
174    //     /// Raw byte value of the tag
175    //     byte: u8,
176    // },
177
178    // /// UTF-8 errors
179    // Utf8(Utf8Error),
180
181    // /// Unexpected value
182    // Value {
183    //     /// Tag of the unexpected value
184    //     tag: Tag,
185    // },
186    /// Tag does not fit in 3 bytes
187    UnsupportedTagSize,
188}
189
190impl ErrorKind {
191    /// Annotate an [`ErrorKind`] with context about where it occurred,
192    /// returning an error.
193    pub fn at(self, position: Length) -> Error {
194        Error::new(self, position)
195    }
196}
197
198impl fmt::Display for ErrorKind {
199    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200        match self {
201            ErrorKind::Failed => write!(f, "operation failed"),
202            ErrorKind::InvalidClass { value } => write!(f, "invalid class {}", value),
203            ErrorKind::InvalidLength => write!(f, "length greater than protocol maximum"),
204            ErrorKind::InvalidTag { byte } => {
205                write!(f, "invalid BER-TLV tag: 0x{:02x}", byte)
206            }
207            ErrorKind::Length { tag } => write!(f, "incorrect length for {}", tag),
208            // ErrorKind::Noncanonical => write!(f, "DER is not canonically encoded"),
209            // ErrorKind::Oid => write!(f, "malformed OID"),
210            ErrorKind::Overflow => write!(f, "integer overflow"),
211            ErrorKind::Overlength => write!(f, "BER-TLV message is too long"),
212            ErrorKind::TrailingData { decoded, remaining } => {
213                write!(
214                    f,
215                    "trailing data at end of BER-TLV message: decoded {} bytes, {} bytes remaining",
216                    decoded, remaining
217                )
218            }
219            ErrorKind::Truncated => write!(f, "BER-TLV message is truncated"),
220            ErrorKind::Underlength { expected, actual } => write!(
221                f,
222                "BER-TLV message too short: expected {}, got {}",
223                expected, actual
224            ),
225            ErrorKind::UnexpectedTag { expected, actual } => {
226                write!(f, "unexpected BER-TLV tag: ")?;
227
228                if let Some(tag) = expected {
229                    write!(f, "expected {}, ", tag)?;
230                }
231
232                write!(f, "got {}", actual)
233            }
234            // ErrorKind::UnknownTag { byte } => {
235            //     write!(f, "unknown/unsupported ASN.1 DER tag: 0x{:02x}", byte)
236            // }
237            // ErrorKind::Utf8(e) => write!(f, "{}", e),
238            // ErrorKind::Value { tag } => write!(f, "malformed ASN.1 DER value for {}", tag),
239            ErrorKind::UnsupportedTagSize => {
240                write!(f, "tags occupying more than 3 octets not supported")
241            }
242        }
243    }
244}