pub use core::str::Utf8Error;
use crate::{Length, Tag};
use core::{convert::Infallible, fmt};
#[cfg(feature = "oid")]
use crate::ObjectIdentifier;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Error {
kind: ErrorKind,
position: Option<Length>,
}
impl Error {
pub fn new(kind: ErrorKind, position: Length) -> Error {
Error {
kind,
position: Some(position),
}
}
pub fn kind(self) -> ErrorKind {
self.kind
}
pub fn position(self) -> Option<Length> {
self.position
}
pub fn nested(self, nested_position: Length) -> Self {
let position = (nested_position + self.position.unwrap_or_default()).ok();
Self {
kind: self.kind,
position,
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.kind)?;
if let Some(pos) = self.position {
write!(f, " at DER byte {}", pos)?;
}
Ok(())
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Error {
Error {
kind,
position: None,
}
}
}
impl From<Infallible> for Error {
fn from(_: Infallible) -> Error {
unreachable!()
}
}
impl From<Utf8Error> for Error {
fn from(err: Utf8Error) -> Error {
Error {
kind: ErrorKind::Utf8(err),
position: None,
}
}
}
#[cfg(feature = "oid")]
impl From<const_oid::Error> for Error {
fn from(_: const_oid::Error) -> Error {
ErrorKind::Oid.into()
}
}
#[cfg(feature = "std")]
impl std::error::Error for ErrorKind {}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum ErrorKind {
Failed,
Length {
tag: Tag,
},
Noncanonical,
Oid,
Overflow,
Overlength,
TrailingData {
decoded: Length,
remaining: Length,
},
Truncated,
Underlength {
expected: Length,
actual: Length,
},
UnexpectedTag {
expected: Option<Tag>,
actual: Tag,
},
#[cfg(feature = "oid")]
#[cfg_attr(docsrs, doc(cfg(feature = "oid")))]
UnknownOid {
oid: ObjectIdentifier,
},
UnknownTag {
byte: u8,
},
Utf8(Utf8Error),
Value {
tag: Tag,
},
}
impl ErrorKind {
pub fn at(self, position: Length) -> Error {
Error::new(self, position)
}
}
impl fmt::Display for ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ErrorKind::Failed => write!(f, "operation failed"),
ErrorKind::Length { tag } => write!(f, "incorrect length for {}", tag),
ErrorKind::Noncanonical => write!(f, "DER is not canonically encoded"),
ErrorKind::Oid => write!(f, "malformed OID"),
ErrorKind::Overflow => write!(f, "integer overflow"),
ErrorKind::Overlength => write!(f, "DER message is too long"),
ErrorKind::TrailingData { decoded, remaining } => {
write!(
f,
"trailing data at end of DER message: decoded {} bytes, {} bytes remaining",
decoded, remaining
)
}
ErrorKind::Truncated => write!(f, "DER message is truncated"),
ErrorKind::Underlength { expected, actual } => write!(
f,
"DER message too short: expected {}, got {}",
expected, actual
),
ErrorKind::UnexpectedTag { expected, actual } => {
write!(f, "unexpected ASN.1 DER tag: ")?;
if let Some(tag) = expected {
write!(f, "expected {}, ", tag)?;
}
write!(f, "got {}", actual)
}
#[cfg(feature = "oid")]
ErrorKind::UnknownOid { oid } => {
write!(f, "unknown/unsupported OID: {}", oid)
}
ErrorKind::UnknownTag { byte } => {
write!(f, "unknown/unsupported ASN.1 DER tag: 0x{:02x}", byte)
}
ErrorKind::Utf8(e) => write!(f, "{}", e),
ErrorKind::Value { tag } => write!(f, "malformed ASN.1 DER value for {}", tag),
}
}
}