Skip to content

Commit

Permalink
signature: add hazmat-preview feature (#1099)
Browse files Browse the repository at this point in the history
Adds a `hazmat` module gated under a newly added `hazmat-preview`
feature which calls out the relevant functionality as subject to change
with minor versions.

It adds the following traits:

- `PrehashSigner`
- `PrehashVerifier`

These APIs accept the digest to be signed/verified as a raw byte slice.
This comes with potential misuses like failing to use a
cryptographically secure hash function as the `prehash`, which could
enable existential forgeries of signatures, hence gating it under a
`hazmat-preview` feature and placing it in a `hazmat` module.

Note that we previously explored APIs like this for `DigestSigner`. They
were removed in RustCrypto/signatures#17 due to the afforementioned
misuse potential.

However, these APIs are occasionally needed for implementing protocols
that use special rules for computing hashes (e.g. EIP-712 structured
hashes), or for implementing things like network signing services which
want to accept a prehash of a message to be signed rather than the full
message (to cut down on network bandwidth).

The traits accept a byte slice `prehash`, which permits multiple lengths
and allows the implementation to decide which lengths are valid. This
makes it possible for e.g. ECDSA implementations to automatically
truncate message prehashes which are larger than the field size.
  • Loading branch information
tarcieri committed Sep 9, 2022
1 parent 726e5cd commit db853f1
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 7 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/signature.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ jobs:
target: ${{ matrix.target }}
override: true
profile: minimal
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
- run: cargo build --target ${{ matrix.target }} --release --no-default-features
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features derive-preview
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features digest-preview
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features hazmat-preview
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features rand-preview

minimal-versions:
uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master
Expand Down
1 change: 1 addition & 0 deletions signature/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ std = []
# See https://docs.rs/signature/latest/signature/#unstable-features for more information.
derive-preview = ["digest-preview", "signature_derive"]
digest-preview = ["digest"]
hazmat-preview = []
rand-preview = ["rand_core"]

[package.metadata.docs.rs]
Expand Down
49 changes: 49 additions & 0 deletions signature/src/hazmat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//! Hazardous Materials: low-level APIs which can be insecure if misused.
//!
//! The traits in this module are not generally recommended, and should only be
//! used in special cases where they are specifically needed.
//!
//! Using them incorrectly can introduce security vulnerabilities. Please
//! carefully read the documentation before attempting to use them.
//!
//! To use them, enable the `hazmat-preview` crate feature. Note that this
//! feature is semi-unstable and not subject to regular 1.x SemVer guarantees.
//! However, any breaking changes will be accompanied with a minor version bump.

use crate::{Error, Signature};

/// Sign the provided message prehash, returning a digital signature.
pub trait PrehashSigner<S: Signature> {
/// Attempt to sign the given message digest, returning a digital signature
/// on success, or an error if something went wrong.
///
/// The `prehash` parameter should be the output of a secure cryptographic
/// hash function.
///
/// This API takes a `prehash` byte slice as there can potentially be many
/// compatible lengths for the message digest for a given concrete signature
/// algorithm.
///
/// Allowed lengths are algorithm-dependent and up to a particular
/// implementation to decide.
fn try_sign_prehash(&self, prehash: &[u8]) -> Result<S, Error>;
}

/// Verify the provided message prehash using `Self` (e.g. a public key)
pub trait PrehashVerifier<S: Signature> {
/// Use `Self` to verify that the provided signature for a given message
/// `prehash` is authentic.
///
/// The `prehash` parameter should be the output of a secure cryptographic
/// hash function.
///
/// Returns `Error` if it is inauthentic or some other error occurred, or
/// otherwise returns `Ok(())`.
///
/// # ⚠️ Security Warning
///
/// If `prehash` is something other than the output of a cryptographically
/// secure hash function, an attacker can potentially forge signatures by
/// solving a system of linear equations.
fn verify_prehash(&self, prehash: &[u8], signature: &S) -> Result<(), Error>;
}
16 changes: 10 additions & 6 deletions signature/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,16 @@ compile_error!(
Use the `rand-preview` feature instead."
);

#[cfg(feature = "hazmat-preview")]
#[cfg_attr(docsrs, doc(cfg(feature = "hazmat-preview")))]
pub mod hazmat;

mod error;
mod keypair;
mod signature;
mod signer;
mod verifier;

#[cfg(feature = "derive-preview")]
#[cfg_attr(docsrs, doc(cfg(feature = "derive-preview")))]
pub use signature_derive::{Signer, Verifier};
Expand All @@ -175,10 +185,4 @@ pub use digest;
#[cfg_attr(docsrs, doc(cfg(feature = "rand-preview")))]
pub use rand_core;

mod error;
mod keypair;
mod signature;
mod signer;
mod verifier;

pub use crate::{error::*, keypair::*, signature::*, signer::*, verifier::*};

0 comments on commit db853f1

Please sign in to comment.