-
Notifications
You must be signed in to change notification settings - Fork 50
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
Optionally pad OpenPGP EdDSA signature parameters #340
Conversation
Add special crafted test signature, using GnuPG/MacGPG2 v2.2.24, where the DATA and TIMESTAMP to be hashed and signed are chosen such that the S value of the resulting signature starts with a 0-byte and is thus omitted as per the RFC 4880 MPI encoding, making the overall signature one byte shorter than required as per RFC 8032. Kudos to @jku for providing the following reproducer: ``` DATA="hello" TIMESTAMP=1613479847 HOMEDIR="tests/gpg_keyrings/eddsa/" echo -n $DATA | gpg --faked-system-time $TIMESTAMP \ --homedir $HOMEDIR \ --digest-algo SHA256 \ --local-user 4E630F84838BF6F7447B830B22692F5FEA9E2DD2 \ --detach-sign > short.sig gpg --list-packets --verbose short.sig echo -n $DATA | gpg --homedir $HOMEDIR --verify short.sig - ```
EdDSA signatures must be 64 bytes long as per RFC 8032 5.1.6. (6). This commit adds a constant for this length which may be used to to pad shorter signatures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
securesystemslib/gpg/eddsa.py
Outdated
r = r.rjust(int(ED25519_SIG_LENGTH / 2), b"\x00") | ||
s = s.rjust(int(ED25519_SIG_LENGTH / 2), b"\x00") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not a big deal but I think this should work in all pythons:
r = r.rjust(int(ED25519_SIG_LENGTH / 2), b"\x00") | |
s = s.rjust(int(ED25519_SIG_LENGTH / 2), b"\x00") | |
r = r.rjust(ED25519_SIG_LENGTH // 2, b"\x00") | |
s = s.rjust(ED25519_SIG_LENGTH // 2, b"\x00") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice use of the floor division operator. Will update.
|
||
# Check that the signature is padded upon parsing | ||
signature = parse_signature_packet(signature_data) | ||
self.assertTrue(len(signature["signature"]) == (ED25519_SIG_LENGTH * 2)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is double length here because signature is already a hex string at this point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly. I'll add a comment.
Left-zero-pad 'r' and 's' values that are shorter than required by RFC 8032 (5.1.6.), to make up for omitted leading zeros in RFC 4880 (3.2.) MPIs. This is especially important for 's', which is little-endian. Note that GnuPG seems to correctly parse EdDSA signatures with MPIs that omit leading zeros prior to validation. But in order to validate these signatures outside the context of RFC 4880, e.g. with pyca/cryptography's OpenSSL backend, we need to guarantee the correct length of the parsed signatures ourselves.
Test correct padding of OpenPGP EdDSA signature upon parsing, using a special-crafted short signature pre-generated with GnuPG.
3f83988
to
b55fa42
Compare
Addressed your comments and force-pushed. Thanks for the review, @jku! |
Fixes: #334
Description of the changes being introduced by the pull request:
Left-zero-pad 'r' and 's' values that are shorter than required by RFC 8032 (5.1.6.), to make up for omitted leading zeros in RFC 4880 (3.2.) MPIs. This is especially important for 's', which is little-endian.
Note that GnuPG seems to correctly parse EdDSA signatures with MPIs that omit leading zeros prior to validation. But in order to validate these signatures outside the context of RFC 4880, e.g. with pyca/cryptography's OpenSSL backend, we need to guarantee the correct length of the parsed signatures ourselves.
This PR also adds a test using a special-crafted short signature.
See commit messages and #334 for more details.
Kudos to @jku and @SantiagoTorres for helping to troubleshoot.
Please verify and check that the pull request fulfils the following requirements: