Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

signature: add hazmat-preview feature #1099

Merged
merged 1 commit into from
Sep 9, 2022

Conversation

tarcieri
Copy link
Member

@tarcieri tarcieri commented Sep 9, 2022

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.

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.
@tarcieri tarcieri force-pushed the signature/hazmat-preview-feature branch from a74710b to 75426c9 Compare September 9, 2022 00:15
///
/// Allowed lengths are algorithm-dependent and up to a particular
/// implementation to decide.
fn try_sign_prehash(&self, prehash: &[u8]) -> Result<S, Error>;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about a few different alternatives to prehash: &[u8] (i.e. a byte slice), including:

  • Adding a const generic parameter to the trait, which would permit overlapping impls for different sizes
  • Using generic-array

While both of those are worth considering, algorithms like DSA and RSASSA-PKCS#1v15/PSS both currently use num-bigint-dig with heap-allocated bignums that don't know their own size at a type level.

So I think a slice really is the only option that's general enough.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could introduce two separate methods: array and slice based. The latter would have a default impl in terms of the former. The mentioned algorithm implementations would overwrite the slice-based method and implement the array-based one using slice-based.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only algorithm that would benefit for now is ECDSA, and that would need generic-array so the implementation in the ecdsa crate can be generic around field sizes.

However, using the slice-based API means we can implement hash truncation / zero padding in one place, which would make it easier to support some exotic combinations of curve and hash functions, such as ECDSA/P-256 with SHA384, or ECDSA/P-384 with SHA-256.

@tarcieri
Copy link
Member Author

tarcieri commented Sep 9, 2022

It would probably be nice to add custom derive support for DigestSigner/DigestVerifier to add boilerplate impls which thunk to PrehashSigner/PrehashVerifier.

@tarcieri
Copy link
Member Author

tarcieri commented Sep 9, 2022

@lumag FYI, if we merge these, you may want to impl them for the RSA signature keys

@tarcieri tarcieri merged commit db853f1 into master Sep 9, 2022
@tarcieri tarcieri deleted the signature/hazmat-preview-feature branch September 9, 2022 14:07
@lumag
Copy link
Contributor

lumag commented Sep 10, 2022

@tarcieri I think I should abstain from implementing it for now. Let's not complicate unreleased dependencies anymore. Not to mention that it adds no direct benefit, as one can use old API to operate on raw (prehashed) data.

@tarcieri
Copy link
Member Author

@lumag sure, it'd be great if we could wrap up the rsa work and get another release out soon.

Note that the intended use case of these traits is abstracting across signing implementations where the rsa crate's software implementation is just one, however I think we can hold off on such support until we start getting requests for it and it's available in other hardware signer crates (e.g. yubikey and yubihsm)

@lumag
Copy link
Contributor

lumag commented Sep 12, 2022

agree

@tarcieri tarcieri mentioned this pull request Sep 12, 2022
tarcieri added a commit to RustCrypto/signatures that referenced this pull request Sep 12, 2022
Adds "hazmat" trait impls to `SigningKey` and `VerifyingKey`
respectively which allow computing signatures over raw message digests.
See RustCrypto/traits#1099.

The implementation allows digests which are shorter or longer than the
field size of the curve, using zero-padding if the digest is too short,
and truncating if it's too long. The minimum digest size is set to half
of the curve's field size.
tarcieri added a commit to RustCrypto/signatures that referenced this pull request Sep 12, 2022
Adds "hazmat" trait impls to `SigningKey` and `VerifyingKey`
respectively which allow computing signatures over raw message digests.
See RustCrypto/traits#1099.

The implementation allows digests which are shorter or longer than the
field size of the curve, using zero-padding if the digest is too short,
and truncating if it's too long. The minimum digest size is set to half
of the curve's field size.
tarcieri added a commit to RustCrypto/signatures that referenced this pull request Sep 12, 2022
Adds "hazmat" trait impls to `SigningKey` and `VerifyingKey`
respectively which allow computing signatures over raw message digests.
See RustCrypto/traits#1099.

The implementation allows digests which are shorter or longer than the
field size of the curve, using zero-padding if the digest is too short,
and truncating if it's too long. The minimum digest size is set to half
of the curve's field size.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants