simple_tlv/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 SIMPLE-TLV byte {}", pos)?;
59 }
60
61 Ok(())
62 }
63}
64
65impl From<ErrorKind> for Error {
66 fn from(kind: ErrorKind) -> Error {
67 Error {
68 kind,
69 position: None,
70 }
71 }
72}
73
74impl From<core::convert::Infallible> for Error {
75 fn from(_: Infallible) -> Error {
76 unreachable!()
77 }
78}
79
80// impl From<Utf8Error> for Error {
81// fn from(err: Utf8Error) -> Error {
82// Error {
83// kind: ErrorKind::Utf8(err),
84// position: None,
85// }
86// }
87// }
88
89// #[cfg(feature = "oid")]
90// impl From<const_oid::Error> for Error {
91// fn from(_: const_oid::Error) -> Error {
92// ErrorKind::Oid.into()
93// }
94// }
95
96#[cfg(feature = "std")]
97impl std::error::Error for ErrorKind {}
98
99/// Error type.
100#[derive(Copy, Clone, Debug, Eq, PartialEq)]
101#[non_exhaustive]
102pub enum ErrorKind {
103 /// Operation failed due to previous error
104 Failed,
105
106 /// Invalid tag
107 InvalidTag {
108 /// Raw byte value of the tag
109 byte: u8,
110 },
111
112 /// Length greater than u16::MAX
113 InvalidLength,
114
115 /// Incorrect length for a given field
116 Length {
117 /// Tag type of the value being decoded
118 tag: Tag,
119 },
120
121 // /// Message is not canonically encoded
122 // Noncanonical,
123
124 // /// Malformed OID
125 // Oid,
126
127 /// Integer overflow occurred (library bug!)
128 Overflow,
129
130 /// Message is longer than SIMPLE-TLV's limits support
131 Overlength,
132
133 /// Undecoded trailing data at end of message
134 TrailingData {
135 /// Length of the decoded data
136 decoded: Length,
137
138 /// Total length of the remaining data left in the buffer
139 remaining: Length,
140 },
141
142 /// Unexpected end-of-message/nested field when decoding
143 Truncated,
144
145 /// Encoded message is shorter than the expected length
146 /// (i.e. an `Encodable` impl on a particular type has a buggy `encoded_length`)
147 Underlength {
148 /// Expected length
149 expected: Length,
150
151 /// Actual length
152 actual: Length,
153 },
154
155 /// Unexpected tag
156 UnexpectedTag {
157 /// Tag the decoder was expecting (if there is a single such tag).
158 ///
159 /// `None` if multiple tags are expected/allowed, but the `actual` tag
160 /// does not match any of them.
161 expected: Option<Tag>,
162
163 /// Actual tag encountered in the message
164 actual: Tag,
165 },
166
167 // /// Unknown/unsupported tag
168 // UnknownTag {
169 // /// Raw byte value of the tag
170 // byte: u8,
171 // },
172
173 // /// UTF-8 errors
174 // Utf8(Utf8Error),
175
176 // /// Unexpected value
177 // Value {
178 // /// Tag of the unexpected value
179 // tag: Tag,
180 // },
181}
182
183impl ErrorKind {
184 /// Annotate an [`ErrorKind`] with context about where it occurred,
185 /// returning an error.
186 pub fn at(self, position: Length) -> Error {
187 Error::new(self, position)
188 }
189}
190
191impl fmt::Display for ErrorKind {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 match self {
194 ErrorKind::Failed => write!(f, "operation failed"),
195 ErrorKind::InvalidLength => write!(f, "length greater than protocol maximum"),
196 ErrorKind::Length { tag } => write!(f, "incorrect length for {}", tag),
197 // ErrorKind::Noncanonical => write!(f, "DER is not canonically encoded"),
198 // ErrorKind::Oid => write!(f, "malformed OID"),
199 ErrorKind::Overflow => write!(f, "integer overflow"),
200 ErrorKind::Overlength => write!(f, "SIMPLE-TLV message is too long"),
201 ErrorKind::TrailingData { decoded, remaining } => {
202 write!(
203 f,
204 "trailing data at end of SIMPLE-TLV message: decoded {} bytes, {} bytes remaining",
205 decoded, remaining
206 )
207 }
208 ErrorKind::Truncated => write!(f, "SIMPLE-TLV message is truncated"),
209 ErrorKind::Underlength { expected, actual } => write!(
210 f,
211 "SIMPLE-TLV message too short: expected {}, got {}",
212 expected, actual
213 ),
214 ErrorKind::UnexpectedTag { expected, actual } => {
215 write!(f, "unexpected SIMPLE-TLV tag: ")?;
216
217 if let Some(tag) = expected {
218 write!(f, "expected {}, ", tag)?;
219 }
220
221 write!(f, "got {}", actual)
222 }
223 ErrorKind::InvalidTag { byte } => {
224 write!(f, "invalid SIMPLE-TLV tag: 0x{:02x}", byte)
225 }
226 // ErrorKind::UnknownTag { byte } => {
227 // write!(f, "unknown/unsupported ASN.1 DER tag: 0x{:02x}", byte)
228 // }
229 // ErrorKind::Utf8(e) => write!(f, "{}", e),
230 // ErrorKind::Value { tag } => write!(f, "malformed ASN.1 DER value for {}", tag),
231 }
232 }
233}