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

Optionally pad OpenPGP EdDSA signature parameters #340

Merged
merged 4 commits into from
Feb 25, 2021

Conversation

lukpueh
Copy link
Member

@lukpueh lukpueh commented Feb 24, 2021

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:

  • The code follows the Code Style Guidelines
  • Tests have been added for the bug fix or new feature
  • Docs have been added for the bug fix or new feature

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.
@lukpueh lukpueh requested a review from jku February 24, 2021 15:12
@lukpueh lukpueh mentioned this pull request Feb 24, 2021
Copy link
Collaborator

@jku jku left a comment

Choose a reason for hiding this comment

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

LGTM

Comment on lines 148 to 149
r = r.rjust(int(ED25519_SIG_LENGTH / 2), b"\x00")
s = s.rjust(int(ED25519_SIG_LENGTH / 2), b"\x00")
Copy link
Collaborator

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:

Suggested change
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")

Copy link
Member Author

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))
Copy link
Collaborator

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?

Copy link
Member Author

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.
@lukpueh
Copy link
Member Author

lukpueh commented Feb 25, 2021

Addressed your comments and force-pushed. Thanks for the review, @jku!

@lukpueh lukpueh merged commit 6895306 into secure-systems-lab:master Feb 25, 2021
@lukpueh lukpueh mentioned this pull request Feb 26, 2021
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.

Flaky GPG EdDSA tests
2 participants