Skip to content

Commit

Permalink
der: add Error::(set_)source; remove Clone + Copy (#1328)
Browse files Browse the repository at this point in the history
When the `std` feature is enabled, adds support for propagating an
arbitrary error source which can be set using `Error::set_source`.

The main use case is passing back an arbitrary error value in the
`ErrorKind::Value` use case, to handle passing back what specifically
was wrong with a given value in a DER-encoded document.

This entails removing the `Clone` + `Copy` bounds since the error is
stored in a `Box`, which can't be `Copy` and can't reflect a `Clone`
bound. Fortunately, nothing in this repo ever seems to clone an `Error`
so it's not really an issue.

Also adds `Error::source` impls to the downstream error types in
`pkcs1`, `pkcs5`, `pkcs8`, `sec1`, and `spki`.
  • Loading branch information
tarcieri authored Mar 2, 2024
1 parent c501837 commit 7784f2d
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 16 deletions.
56 changes: 49 additions & 7 deletions der/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,24 @@ use crate::asn1::ObjectIdentifier;
#[cfg(feature = "pem")]
use crate::pem;

#[cfg(feature = "std")]
use alloc::boxed::Box;

/// Result type.
pub type Result<T> = core::result::Result<T, Error>;

/// Error type.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Debug)]
pub struct Error {
/// Kind of error.
kind: ErrorKind,

/// Position inside of message where error occurred.
position: Option<Length>,

/// Source of the error.
#[cfg(feature = "std")]
source: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
}

impl Error {
Expand All @@ -30,6 +37,8 @@ impl Error {
Error {
kind,
position: Some(position),
#[cfg(feature = "std")]
source: None,
}
}

Expand All @@ -48,15 +57,27 @@ impl Error {
}

/// Get the [`ErrorKind`] which occurred.
pub fn kind(self) -> ErrorKind {
pub fn kind(&self) -> ErrorKind {
self.kind
}

/// Get the position inside of the message where the error occurred.
pub fn position(self) -> Option<Length> {
pub fn position(&self) -> Option<Length> {
self.position
}

/// Set the source of this error. Useful for e.g. propagating an additional error with
/// [`ErrorKind::Value`].
///
/// Overwrites any previously set source.
#[cfg(feature = "std")]
pub fn set_source<E>(&mut self, source: E)
where
E: std::error::Error + Send + Sync + 'static,
{
self.source = Some(Box::new(source));
}

/// For errors occurring inside of a nested message, extend the position
/// count by the location where the nested message occurs.
pub(crate) fn nested(self, nested_position: Length) -> Self {
Expand All @@ -66,13 +87,12 @@ impl Error {
Self {
kind: self.kind,
position,
#[cfg(feature = "std")]
source: self.source,
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for Error {}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.kind)?;
Expand All @@ -85,11 +105,20 @@ impl fmt::Display for Error {
}
}

impl Eq for Error {}
impl PartialEq for Error {
fn eq(&self, other: &Self) -> bool {
self.kind == other.kind && self.position == other.position
}
}

impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Error {
Error {
kind,
position: None,
#[cfg(feature = "std")]
source: None,
}
}
}
Expand All @@ -101,10 +130,12 @@ impl From<Infallible> for Error {
}

impl From<TryFromIntError> for Error {
fn from(_: TryFromIntError) -> Error {
fn from(_err: TryFromIntError) -> Error {
Error {
kind: ErrorKind::Overflow,
position: None,
#[cfg(feature = "std")]
source: Some(Box::new(_err)),
}
}
}
Expand All @@ -114,6 +145,8 @@ impl From<Utf8Error> for Error {
Error {
kind: ErrorKind::Utf8(err),
position: None,
#[cfg(feature = "std")]
source: Some(Box::new(err)),
}
}
}
Expand Down Expand Up @@ -158,6 +191,15 @@ impl From<time::error::ComponentRange> for Error {
}
}

#[cfg(feature = "std")]
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source
.as_ref()
.map(|source| source.as_ref() as &(dyn std::error::Error + 'static))
}
}

/// Error type.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
Expand Down
13 changes: 11 additions & 2 deletions pkcs1/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use der::pem;
pub type Result<T> = core::result::Result<T, Error>;

/// Error type
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Error {
/// ASN.1 DER-related errors.
Expand Down Expand Up @@ -92,4 +92,13 @@ impl From<pkcs8::spki::Error> for Error {
}

#[cfg(feature = "std")]
impl std::error::Error for Error {}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Asn1(err) => Some(err),
#[cfg(feature = "pkcs8")]
Error::Pkcs8(err) => Some(err),
_ => None,
}
}
}
2 changes: 2 additions & 0 deletions pkcs5/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ hex-literal = "0.4"

[features]
alloc = []
std = ["alloc"]

3des = ["dep:des", "pbes2"]
des-insecure = ["dep:des", "pbes2"]
getrandom = ["rand_core/getrandom"]
Expand Down
3 changes: 3 additions & 0 deletions pkcs5/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,6 @@ impl fmt::Display for Error {
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for Error {}
3 changes: 3 additions & 0 deletions pkcs5/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
#[cfg(all(feature = "alloc", feature = "pbes2"))]
extern crate alloc;

#[cfg(feature = "std")]
extern crate std;

mod error;

pub mod pbes1;
Expand Down
2 changes: 1 addition & 1 deletion pkcs8/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ tempfile = "3"

[features]
alloc = ["der/alloc", "der/zeroize", "spki/alloc"]
std = ["alloc", "der/std", "spki/std"]
std = ["alloc", "der/std", "pkcs5?/std", "spki/std"]

3des = ["encryption", "pkcs5/3des"]
des-insecure = ["encryption", "pkcs5/des-insecure"]
Expand Down
14 changes: 12 additions & 2 deletions pkcs8/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use der::pem;
pub type Result<T> = core::result::Result<T, Error>;

/// Error type
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Error {
/// ASN.1 DER-related errors.
Expand Down Expand Up @@ -48,7 +48,17 @@ impl fmt::Display for Error {
}

#[cfg(feature = "std")]
impl std::error::Error for Error {}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Asn1(err) => Some(err),
#[cfg(feature = "pkcs5")]
Error::EncryptedPrivateKey(err) => Some(err),
Error::PublicKey(err) => Some(err),
_ => None,
}
}
}

impl From<der::Error> for Error {
fn from(err: der::Error) -> Error {
Expand Down
5 changes: 4 additions & 1 deletion pkcs8/tests/encrypted_private_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
#![cfg(feature = "pkcs5")]

use hex_literal::hex;
use pkcs8::{pkcs5::pbes2, EncryptedPrivateKeyInfo, PrivateKeyInfo};
use pkcs8::{pkcs5::pbes2, EncryptedPrivateKeyInfo};

#[cfg(feature = "alloc")]
use der::Encode;

#[cfg(feature = "encryption")]
use pkcs8::PrivateKeyInfo;

#[cfg(feature = "pem")]
use der::EncodePem;

Expand Down
2 changes: 1 addition & 1 deletion sec1/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use der::pem;
pub type Result<T> = core::result::Result<T, Error>;

/// Error type
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Error {
/// ASN.1 DER-related errors.
Expand Down
11 changes: 9 additions & 2 deletions spki/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub type Result<T> = core::result::Result<T, Error>;
use der::pem;

/// Error type
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Error {
/// Algorithm parameters are missing.
Expand Down Expand Up @@ -65,4 +65,11 @@ impl From<pem::Error> for Error {
}

#[cfg(feature = "std")]
impl std::error::Error for Error {}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Asn1(err) => Some(err),
_ => None,
}
}
}

0 comments on commit 7784f2d

Please sign in to comment.