signatures icon indicating copy to clipboard operation
signatures copied to clipboard

DSA: `Verifier` trait not implemented

Open Geobert opened this issue 3 years ago • 6 comments

Hi,

I'm in a case where I need to verify a signature done on a whole &[u8] rather than a digest and I see that the relevant method is in the Verifier trait but it is not implemented anywhere in the dsa crate.

Is that an oversight or it is something just waiting for a contribution? Or am I missing something?

Regards,

Geobert avatar Sep 05 '22 14:09 Geobert

If you have a while message aggregated inside a byte slice and you want to verify it, you can do the following (replace Sha1 with whatever hashing algorithm you use):

let is_valid = verifying_key.verify_digest(Sha1::new_with_prefix(data)).is_ok();

This could maybe be added as to the documentation as reference.

An implementation of the Verifier trait would do roughly the same thing but default to the preferred hashing algorithm for the signature scheme. DigestVerifier is more flexible and lets you choose the hashing algorithm you want to use.

aumetra avatar Sep 05 '22 14:09 aumetra

Fair enough, I have to add dsa support after I've done ed25519 and the latter had verify so that confused me.

Thanks a lot for your answer!

Geobert avatar Sep 05 '22 14:09 Geobert

Both sets of traits can be implemented. We should do both unless there’s a complication I’m not thinking of.

tarcieri avatar Sep 05 '22 15:09 tarcieri

There shouldn't be any complications. The preferred hashing algorithm for DSA is SHA-1, if I'm not mistaken?

aumetra avatar Sep 05 '22 15:09 aumetra

Ugh, well at the very least that should be feature-gated due to the insecurity of SHA-1.

Looking for relevant RFCs, I see a lot of Internet-Drafts to update the default hash algorithm for DSA, but none of them actually accepted as standards-track RFCs, e.g. draft-rsa-dsa-sha2-256 which became draft-ietf-curdle-rsa-sha2(RSA-only) and eventually RFC8332.

tarcieri avatar Sep 06 '22 14:09 tarcieri

RFC 5754 defines DSA with SHA-224 and SHA256.

lumag avatar Sep 12 '22 15:09 lumag

I had a quick look at this one. It seems RFC 5754 assumes an identifier is included to indicate what hash algorithm was used. So for a plain signature as used for Signer and Verifier this would be an issue. If DSA is used with SHA-1 by default, but then this is disallowed, considered unsafe for many cases. So any choice for the implementation of Signer and Verifier is rather arbitrary IIUC. (And, if the default changes at some later point, implementations that upgrade will suddenly find themselves operating with different parameters, which may be a source of problems in itself, especially with interop.) update So, I guess the question is, is such an implementation desirable? update I am rereading, because I feel like I am missing something. Is the idea to have the generic type as part of the Signature-type, such that Signer and Verifier can derive the hashing algorithm automatically?

cobratbq avatar Oct 23 '22 15:10 cobratbq

I'd follow what was done for the RSA crate: turn the Digest into the generic type argument for the Signer and Verifier implementations:

pub struct Signature {...}
impl signature::Signature for Signature {....}
pub struct SigningKey<D> where D: Digest {...}
impl<D> RandomizedSigner<Signature> for SigningKey<D> where D: Digest {....}
impl<D> RandomizedDigestSigner<Signature> for SigningKey<D> where D: Digest {....}
#[cfg(feature = "hazmat")]
impl<D> RandomizedPrehashSigner<Signature> for SigningKey<D> where D: Digest {....}

lumag avatar Oct 23 '22 17:10 lumag

In other words: let the caller code determine used digest algo and pass it as a generic argument.

lumag avatar Oct 23 '22 17:10 lumag

@lumag yeah exactly, if I'm reading RFC 5754 correctly it uses a similar OID-based approach to RSA, so we can do the exact same thing and query the OID via AssociatedOid.

I would recommend SHA-256 as the default, as SHA-1 is insecure.

tarcieri avatar Oct 23 '22 18:10 tarcieri

'd follow what was done for the RSA crate: turn the Digest into the generic type argument for the Signer and Verifier implementations: [..]

This does mean that, within the same application, a produced Signature can be handled incorrectly by lack of type-safety. ~~Acknowledged~~ Granted, this is not the most common use-case, still.

cobratbq avatar Oct 25 '22 13:10 cobratbq

@cobratbq I don't follow your complaint. You're arguing that using a generic parameter somehow reduces type safety? Safety around what, and compared to what alternative?

tarcieri avatar Oct 25 '22 13:10 tarcieri

@tarcieri If I use some Signer -- based on SHA-1 -- to produce a Signature, then use another Verifier -- based on SHA-256 -- to verify the signature, it will only fail at run-time for not being able to verify the signature. It could have failed syntax checking (type consistency) if a generic parameter would be included. (My reasoning is based on the code sample above, if it is missing some detail, then I am making wrong assumptions.) NOTE: I am not arguing for or against either solution, just want to make sure this consideration is taken into account.

cobratbq avatar Oct 25 '22 13:10 cobratbq

It could have failed syntax checking (type consistency) if a generic parameter would be included. (My reasoning is based on the code sample above, if it is missing some detail, then I am making wrong assumptions.)

But that example is using a generic parameter? I still don't follow.

One complication in generic code is there are potentially multiple implementations of the same digest which should be treated the same even if they aren't the same type, such as wrappers for cryptographic accelerators.

But the AssociatedOid trait would still let you bound on a particular OID constant at the type level, e.g.

where D: AssociatedOid<OID = sha2::Sha256::OID>

tarcieri avatar Oct 25 '22 14:10 tarcieri

@tarcieri hmmm, I think it does. I get it now.

cobratbq avatar Oct 25 '22 14:10 cobratbq

PR #559 is a minimal implementation of Signer and Verifier. The changes to the types discussed above are still possible, but not covered. The PR shows the implementation needed to make it work within the current code-base. I have no urgent need for this contribution myself, but it is a logical next incremental addition. If you consider the type-system changes deal-breaking, let me know and I'll close the request.

cobratbq avatar Oct 27 '22 14:10 cobratbq

I think this could be closed, as further changes depend on https://github.com/RustCrypto/traits/pull/1141.

cobratbq avatar Nov 01 '22 16:11 cobratbq