1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
#![allow(unknown_lints)]
#![allow(non_local_definitions)] // false positive for displaydoc::Display: https://github.com/yaahc/displaydoc/issues/46
use crate::{Class, Tag};
use alloc::str;
use alloc::string;
#[cfg(not(feature = "std"))]
use alloc::string::String;
use displaydoc::Display;
use nom::error::{ErrorKind, FromExternalError, ParseError};
use nom::IResult;
#[cfg(feature = "std")]
use std::io;
#[cfg(feature = "std")]
use thiserror::Error;
#[cfg(feature = "std")]
impl std::error::Error for DerConstraint {}
#[derive(Clone, Copy, Debug, Display, PartialEq, Eq)]
/// Error types for DER constraints
pub enum DerConstraint {
/// Indefinite length not allowed
IndefiniteLength,
/// Object must not be constructed
Constructed,
/// Object must be constructed
NotConstructed,
/// DateTime object is missing timezone
MissingTimeZone,
/// DateTime object is missing seconds
MissingSeconds,
/// Bitstring unused bits must be set to zero
UnusedBitsNotZero,
/// Boolean value must be 0x00 of 0xff
InvalidBoolean,
/// Integer must not be empty
IntegerEmpty,
/// Leading zeroes in Integer encoding
IntegerLeadingZeroes,
/// Leading 0xff in negative Integer encoding
IntegerLeadingFF,
}
// XXX
// thiserror does not work in no_std
// see https://github.com/dtolnay/thiserror/pull/64
#[cfg(feature = "std")]
impl std::error::Error for Error {}
/// The error type for operations of the [`FromBer`](crate::FromBer),
/// [`FromDer`](crate::FromDer), and associated traits.
#[derive(Clone, Debug, Display, PartialEq, Eq)]
// #[cfg_attr(feature = "std", derive(Error))]
pub enum Error {
/// BER object does not have the expected type
BerTypeError,
/// BER object does not have the expected value
BerValueError,
/// Invalid Length
InvalidLength,
/// Invalid Value when parsing object with tag {tag:?} {msg:}
InvalidValue { tag: Tag, msg: String },
/// Invalid Tag
InvalidTag,
/// Unknown tag: {0:?}
UnknownTag(u32),
/// Unexpected Tag (expected: {expected:?}, actual: {actual:?})
UnexpectedTag { expected: Option<Tag>, actual: Tag },
/// Unexpected Class (expected: {expected:?}, actual: {actual:?})
UnexpectedClass {
expected: Option<Class>,
actual: Class,
},
/// Indefinite length not allowed
IndefiniteLengthUnexpected,
/// DER object was expected to be constructed (and found to be primitive)
ConstructExpected,
/// DER object was expected to be primitive (and found to be constructed)
ConstructUnexpected,
/// Integer too large to fit requested type
IntegerTooLarge,
/// BER integer is negative, while an unsigned integer was requested
IntegerNegative,
/// BER recursive parsing reached maximum depth
BerMaxDepth,
/// Invalid encoding or forbidden characters in string
StringInvalidCharset,
/// Invalid Date or Time
InvalidDateTime,
/// DER Failed constraint: {0:?}
DerConstraintFailed(DerConstraint),
/// Requesting borrowed data from a temporary object
LifetimeError,
/// Feature is not yet implemented
Unsupported,
/// incomplete data, missing: {0:?}
Incomplete(nom::Needed),
/// nom error: {0:?}
NomError(ErrorKind),
}
impl Error {
/// Build an error from the provided invalid value
#[inline]
pub const fn invalid_value(tag: Tag, msg: String) -> Self {
Self::InvalidValue { tag, msg }
}
/// Build an error from the provided unexpected class
#[inline]
pub const fn unexpected_class(expected: Option<Class>, actual: Class) -> Self {
Self::UnexpectedClass { expected, actual }
}
/// Build an error from the provided unexpected tag
#[inline]
pub const fn unexpected_tag(expected: Option<Tag>, actual: Tag) -> Self {
Self::UnexpectedTag { expected, actual }
}
}
impl<'a> ParseError<&'a [u8]> for Error {
fn from_error_kind(_input: &'a [u8], kind: ErrorKind) -> Self {
Error::NomError(kind)
}
fn append(_input: &'a [u8], kind: ErrorKind, _other: Self) -> Self {
Error::NomError(kind)
}
}
impl From<Error> for nom::Err<Error> {
fn from(e: Error) -> Self {
nom::Err::Error(e)
}
}
impl From<str::Utf8Error> for Error {
fn from(_: str::Utf8Error) -> Self {
Error::StringInvalidCharset
}
}
impl From<string::FromUtf8Error> for Error {
fn from(_: string::FromUtf8Error) -> Self {
Error::StringInvalidCharset
}
}
impl From<string::FromUtf16Error> for Error {
fn from(_: string::FromUtf16Error) -> Self {
Error::StringInvalidCharset
}
}
impl From<nom::Err<Error>> for Error {
fn from(e: nom::Err<Error>) -> Self {
match e {
nom::Err::Incomplete(n) => Self::Incomplete(n),
nom::Err::Error(e) | nom::Err::Failure(e) => e,
}
}
}
impl<I, E> FromExternalError<I, E> for Error {
fn from_external_error(_input: I, kind: ErrorKind, _e: E) -> Error {
Error::NomError(kind)
}
}
/// Flatten all `nom::Err` variants error into a single error type
pub fn from_nom_error<E, F>(e: nom::Err<E>) -> F
where
F: From<E> + From<Error>,
{
match e {
nom::Err::Error(e) | nom::Err::Failure(e) => F::from(e),
nom::Err::Incomplete(n) => F::from(Error::Incomplete(n)),
}
}
/// Holds the result of BER/DER serialization functions
pub type ParseResult<'a, T, E = Error> = IResult<&'a [u8], T, E>;
/// A specialized `Result` type for all operations from this crate.
pub type Result<T, E = Error> = core::result::Result<T, E>;
/// The error type for serialization operations of the [`ToDer`](crate::ToDer) trait.
#[cfg(feature = "std")]
#[derive(Debug, Error)]
pub enum SerializeError {
#[error("ASN.1 error: {0:?}")]
ASN1Error(#[from] Error),
#[error("Invalid Class {class:}")]
InvalidClass { class: u8 },
#[error("Invalid Length")]
InvalidLength,
#[error("I/O error: {0:?}")]
IOError(#[from] io::Error),
}
#[cfg(feature = "std")]
/// Holds the result of BER/DER encoding functions
pub type SerializeResult<T> = std::result::Result<T, SerializeError>;