Skip to content

Domain separation between pre-hashed & pure version (forge signature for hash) #104

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

Closed
stevenwdv opened this issue Oct 8, 2021 · 2 comments

Comments

@stevenwdv
Copy link

stevenwdv commented Oct 8, 2021

You probably know this, but I thought I'd mention it anyway as I haven't found something documenting this:
I noticed that with the pre-hashed (ED) version, a Blake2b hash is directly signed with the regular Ed25519 scheme, without any domain separation, as the scheme used (Ed/ED) is never signed. This means that in case of a pre-hashed signature it is trivial to forge one specific signature: given a pre-hashed signature for file.txt, change the algorithm to Ed, and it will work as a signature for a file containing the Blake2b hash of file.txt. (The other way around is technically also possible, but only if what is signed is already a file containing a (non-encoded) Blake2b hash for which the pre-image is known.)

Example attack

For an attacker, this would probably mostly be useful as a way to disrupt services. For example, say I have a service running that regularly downloads a pre-hashed signed JSON config file, verifies the signature, replaces the previous config file, parses the file, and applies the configuration. Now an attacker might replace the file with its hash, update the algorithm in the signature, and give it to the service. The service will then happily verify the signature, replace the previous config file, and crash while parsing the config because the hash is not valid JSON. Compare this with a more general DoS attack where an attacker just blocks the download: at least there the server can later retry and it does not need to be manually restarted with a valid config file again.

In some (hopefully) niche cases where the original file was a binary file which was basically a struct serialization, the hash may actually be interpreted as valid data, but likely with very extreme values.

Mitigations / solutions

I'm not sure if all this was deliberate to keep the design of the tool simple, but it seems undesirable to me that an attacker would be able to forge any signature.

A mitigation would be to not use the pre-hashed variant, or always check that the variant used is the one you were expecting (ED and not Ed), if that is known beforehand.
As a solution, the latter could be integrated per key, such that a key may only be used to verify one variant, but then it will be hard to switch to another variant if that is desired. Alternatively, the variant could be signed, e.g. in the trusted comment signature, but this will be harder to accomplish keeping backwards compatibility in mind.

Underlying cause

For some context, I would say that the underlying problem is that Minisign does not use the Ed25519ph scheme from RFC 8032, which would set the pre-hash flag to 1 and thus provide separation between the two cases. However, Ed25519ph uses SHA-512 instead of Blake2b. (Of course this is not the only way to accomplish separation, e.g. Ed25519ctx or just signing the variant in Ed25519 would work as well.)

@jedisct1
Copy link
Owner

jedisct1 commented Oct 8, 2021

A format identifier should have been part of the input being signed.

Minisign predates the EdDSA RFC; Ed25519ph didn't exist back then.

A signature can essentially only verify two different representations of the same message. But indeed, parsers can get content they didn't expect.

The best thing to do is probably to always prehash and gradually deprecate non-prehashed files. Minizign has a -H option that will only verify prehashed inputs; this is something that can be easily added to other implementations.

@jedisct1
Copy link
Owner

jedisct1 commented Oct 8, 2021

Done in 1e050e7

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

No branches or pull requests

2 participants