Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 15 additions & 67 deletions signature/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,73 +1,35 @@
//! Signature error types

use core::convert::Infallible;
use core::fmt::{self, Debug, Display};

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

/// Result type.
///
/// A result with the `signature` crate's [`Error`] type.
pub type Result<T> = core::result::Result<T, Error>;

/// Signature errors.
///
/// This type is deliberately opaque as to avoid sidechannel leakage which
/// could potentially be used recover signing private keys or forge signatures
/// (e.g. [BB'06]).
///
/// When the `alloc` feature is enabled, it supports an optional [`core::error::Error::source`],
/// which can be used by things like remote signers (e.g. HSM, KMS) to report I/O or auth errors.
/// This type is deliberately opaque as to avoid sidechannel leakage which could potentially be used
/// recover signing private keys or forge signatures (e.g. [BB'06]).
///
/// [BB'06]: https://en.wikipedia.org/wiki/Daniel_Bleichenbacher
#[derive(Default)]
#[non_exhaustive]
pub struct Error {
/// Source of the error (if applicable).
#[cfg(feature = "alloc")]
source: Option<Box<dyn core::error::Error + Send + Sync + 'static>>,
}
#[derive(Clone, Copy, Default)]
pub struct Error;

impl Error {
/// Create a new error with no associated source
/// DEPRECATED: create a new error. You can now just use `Error` instead because it's now a unit
/// struct which requires no constructor.
#[deprecated(since = "3.0.0", note = "use `Error` instead (no constructor needed)")]
#[must_use]
pub fn new() -> Self {
Self::default()
}

/// Create a new error with an associated source.
///
/// **NOTE:** The "source" should **NOT** be used to propagate cryptographic
/// errors e.g. signature parsing or verification errors. The intended use
/// cases are for propagating errors related to external signers, e.g.
/// communication/authentication errors with HSMs, KMS, etc.
#[cfg(feature = "alloc")]
pub fn from_source(
source: impl Into<Box<dyn core::error::Error + Send + Sync + 'static>>,
) -> Self {
Self {
source: Some(source.into()),
}
Error
}
}

impl Debug for Error {
#[cfg(not(feature = "alloc"))]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("signature::Error {}")
}

#[cfg(feature = "alloc")]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("signature::Error { source: ")?;

if let Some(source) = &self.source {
write!(f, "Some({source})")?;
} else {
f.write_str("None")?;
}

f.write_str(" }")
f.debug_struct("signature::Error").finish()
}
}

Expand All @@ -77,25 +39,11 @@ impl Display for Error {
}
}

#[cfg(feature = "alloc")]
impl From<Box<dyn core::error::Error + Send + Sync + 'static>> for Error {
fn from(source: Box<dyn core::error::Error + Send + Sync + 'static>) -> Error {
Self::from_source(source)
}
}
impl core::error::Error for Error {}

impl core::error::Error for Error {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
#[cfg(not(feature = "alloc"))]
{
None
}
#[cfg(feature = "alloc")]
#[allow(trivial_casts)]
{
self.source
.as_ref()
.map(|source| source.as_ref() as &(dyn core::error::Error + 'static))
}
// Needed to make error bounds work
impl From<Infallible> for Error {
fn from(_: Infallible) -> Self {
Error
}
}
33 changes: 25 additions & 8 deletions signature/src/hazmat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ use crate::rand_core::TryCryptoRng;

/// Sign the provided message prehash, returning a digital signature.
pub trait PrehashSigner<S> {
/// Error type.
type Error: core::error::Error + Into<Error>;

/// Attempt to sign the given message digest, returning a digital signature on success, or an
/// error if something went wrong.
///
Expand All @@ -28,14 +31,17 @@ pub trait PrehashSigner<S> {
/// Allowed lengths are algorithm-dependent and up to a particular implementation to decide.
///
/// # Errors
/// Returns [`Error`] in the event `prehash` is an invalid length.
fn sign_prehash(&self, prehash: &[u8]) -> Result<S, Error>;
/// Returns `Self::Error` in the event `prehash` is an invalid length.
fn sign_prehash(&self, prehash: &[u8]) -> Result<S, Self::Error>;
}

/// Sign the provided message prehash using the provided external randomness source, returning a
/// digital signature.
#[cfg(feature = "rand_core")]
pub trait RandomizedPrehashSigner<S> {
/// Error type.
type Error: core::error::Error + Into<Error>;

/// Attempt to sign the given message digest, returning a digital signature on success, or an
/// error if something went wrong.
///
Expand All @@ -47,13 +53,13 @@ pub trait RandomizedPrehashSigner<S> {
/// Allowed lengths are algorithm-dependent and up to a particular implementation to decide.
///
/// # Errors
/// Returns [`Error`] in the event `prehash` is an invalid length, or if an internal error
/// Returns `Self::Error` in the event `prehash` is an invalid length, or if an internal error
/// in the provided `rng` occurs.
fn sign_prehash_with_rng<R: TryCryptoRng + ?Sized>(
&self,
rng: &mut R,
prehash: &[u8],
) -> Result<S, Error>;
) -> Result<S, Self::Error>;
}

/// Verify the provided message prehash using `Self` (e.g. a public key)
Expand All @@ -78,8 +84,10 @@ pub trait PrehashVerifier<S> {
}

/// Asynchronously sign the provided message prehash, returning a digital signature.
#[allow(async_fn_in_trait)]
pub trait AsyncPrehashSigner<S> {
/// Error type.
type Error: core::error::Error + Into<Error>;

/// Attempt to sign the given message digest, returning a digital signature on success, or an
/// error if something went wrong.
///
Expand All @@ -89,14 +97,19 @@ pub trait AsyncPrehashSigner<S> {
/// for the message digest for a given concrete signature algorithm.
///
/// Allowed lengths are algorithm-dependent and up to a particular implementation to decide.
async fn sign_prehash_async(&self, prehash: &[u8]) -> Result<S, Error>;
///
/// # Errors
/// Returns `Self::Error` in the event `prehash` is an invalid length.
async fn sign_prehash_async(&self, prehash: &[u8]) -> Result<S, Self::Error>;
}

/// Asynchronously sign the provided message prehash using the provided external randomness source,
/// returning a digital signature.
#[cfg(feature = "rand_core")]
#[allow(async_fn_in_trait)]
pub trait AsyncRandomizedPrehashSigner<S> {
/// Error type.
type Error: core::error::Error + Into<Error>;

/// Attempt to sign the given message digest, returning a digital signature on success, or an
/// error if something went wrong.
///
Expand All @@ -106,9 +119,13 @@ pub trait AsyncRandomizedPrehashSigner<S> {
/// for the message digest for a given concrete signature algorithm.
///
/// Allowed lengths are algorithm-dependent and up to a particular implementation to decide.
///
/// # Errors
/// Returns `Self::Error` in the event `prehash` is an invalid length, or if `rng` experiences
/// an internal failure.
async fn sign_prehash_with_rng_async<R: TryCryptoRng + ?Sized>(
&self,
rng: &mut R,
prehash: &[u8],
) -> Result<S, Error>;
) -> Result<S, Self::Error>;
}
Loading
Loading