ecc: reject compressed EC points with incorrect length#9985
Closed
MarkAtwood wants to merge 1 commit intowolfSSL:masterfrom
Closed
ecc: reject compressed EC points with incorrect length#9985MarkAtwood wants to merge 1 commit intowolfSSL:masterfrom
MarkAtwood wants to merge 1 commit intowolfSSL:masterfrom
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds stricter validation when importing compressed EC points so truncated inputs (e.g., a single 0x02/0x03 byte) are rejected instead of being decompressed as a valid point.
Changes:
- Add a length check for compressed point encodings in
wc_ecc_import_point_der_ex. - Return
ECC_BAD_ARG_Ewhen the compressed point length doesn’t match the curve’s field element size.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
wolfcrypt/src/ecc.c
Outdated
Comment on lines
+9476
to
+9477
| int numlen = ecc_sets[curve_idx].size; | ||
| if ((int)(inLen - 1) != numlen) { |
wolfcrypt/src/ecc.c
Outdated
Comment on lines
+9472
to
+9480
| compressed = 1; | ||
| /* Compressed point must be exactly 1 + field_element_size bytes. | ||
| * Reject truncated inputs (e.g. a bare 0x02/0x03 byte). */ | ||
| { | ||
| int numlen = ecc_sets[curve_idx].size; | ||
| if ((int)(inLen - 1) != numlen) { | ||
| err = ECC_BAD_ARG_E; | ||
| } | ||
| } |
wc_ecc_import_point_der_ex accepts a single byte 0x02 or 0x03 as a valid compressed EC point. It treats the missing X coordinate as zero, decompresses it (producing a valid on-curve point), and wc_ecc_check_key passes. This allows ECDH key agreement with a crafted 1-byte peer public key. Add length validation for compressed points: after identifying 0x02/0x03 format byte, verify that inLen == ecc_sets[curve_idx].size + 1 using unsigned comparison to avoid underflow. Only set compressed = 1 after the length check passes, keeping state consistent on the error path. Reproducer: call EC_POINT_oct2point with a 1-byte buffer containing 0x02 for any NIST curve. Before this fix it succeeds; after, it returns ECC_BAD_ARG_E. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
f525e68 to
dc9c45e
Compare
Contributor
|
Added a check on the key size found and a regression test case here #9989 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
wc_ecc_import_point_der_exaccepts a single byte0x02or0x03as a valid compressed EC point for all NIST curves (P-256, P-384, P-521). It treats the missing X coordinate bytes as zeros, successfully decompresses the point (which lands on the curve), andwc_ecc_check_keypasses the result. This allows ECDH key agreement with a crafted 1-byte peer public key.Root Cause
The function validates the format byte (
0x02/0x03/0x04) but does not validate that the input length matches the expected size for the curve. A compressed point should be exactly1 + field_element_sizebytes (33 for P-256, 49 for P-384, 67 for P-521). The existinginLen & 1 == 0check (must be odd) passes for a single byte.Reproducer
Also reproducible via the OpenSSL compat layer:
Security Impact
An attacker can supply a 1-byte "public key" (
0x02or0x03) to an ECDH key agreement. wolfSSL will decompress this to the curve point with X=0, compute a shared secret, and return it to the caller. This is a peer public key validation bypass. In protocols that rely on the crypto library to reject malformed keys (e.g., TLS), this could lead to key compromise via a small number of crafted handshakes.Fix
Added a length check in
wc_ecc_import_point_der_eximmediately after identifying a compressed point type. Verifies thatinLen - 1 == ecc_sets[curve_idx].size. ReturnsECC_BAD_ARG_Eif the length doesn't match.The non-
_exwrapperwc_ecc_import_point_derdelegates to_ex, so it's automatically fixed.Test Plan
0x02/0x03is rejected for all curves🤖 Generated with Claude Code