Skip to content

fix: bound ECDSA r/s before copy in PSoC6 verify (stack overflow)#10921

Open
MarkAtwood wants to merge 1 commit into
wolfSSL:masterfrom
MarkAtwood:fix/psoc6-ecdsa-rs-bounds
Open

fix: bound ECDSA r/s before copy in PSoC6 verify (stack overflow)#10921
MarkAtwood wants to merge 1 commit into
wolfSSL:masterfrom
MarkAtwood:fix/psoc6-ecdsa-rs-bounds

Conversation

@MarkAtwood

Copy link
Copy Markdown
Contributor

psoc6_ecc_verify_hash_ex() copies the signature's r and s components into a fixed 132-byte stack buffer sized for the largest supported curve:

uint8_t signature_buf[MAX_ECC_KEYSIZE * 2] = { 0 };   /* 66 * 2 */
...
rSz = mp_unsigned_bin_size(r);   /* from the untrusted signature */
sSz = mp_unsigned_bin_size(s);
...
mp_to_unsigned_bin(r, signature_buf);          /* writes rSz bytes at [0]   */
mp_to_unsigned_bin(s, signature_buf + keySz);  /* writes sSz bytes at [keySz] */

keySz is bounded (keySz > MAX_ECC_KEYSIZE is rejected), but rSz/sSz are not. In a verify operation r and s come straight from the attacker-supplied signature, so an oversized r or s overflows signature_buf on the stack.

The generic path guards this with wc_ecc_check_r_s_range() (rejects r,s outside [1, order-1]), but that function is #if !defined(WOLFSSL_PSOC6_CRYPTO) — compiled out for this port — and wc_ecc_verify_hash_ex() returns early into psoc6_ecc_verify_hash_ex() before the check would run.

Fix: reject rSz > keySz || sSz > keySz before the copies, mirroring the adjacent keySz guard. A valid ECDSA r,s is in [1, order-1] and always fits in keySz bytes, so this rejects nothing legitimate.

Verification. The PSoC6 port needs Cypress PDL headers/hardware and can't be built or run here, so this is a code-read fix. I modeled the exact buffer arithmetic in a standalone harness under AddressSanitizer: pre-fix, an oversized r (200 bytes, secp256r1 keySz=32) triggers stack-buffer-overflow in the r/s copy; post-fix it's rejected and a valid signature (rSz/sSz ≤ keySz) still passes. Runtime confirmation on real PSoC6 hardware would be welcome.

Scope note. The STM32 PKA path (WOLFSSL_STM32_PKA) has the same early-return-before-check structure; I left it untouched since I only verified the PSoC6 buffer arithmetic. Worth a look by someone with that hardware.

Found by Fenrir (finding 6778).


Update after Skoll self-review: also corrected three inverted error returns in this function (return -BAD_FUNC_ARG returned +173, since BAD_FUNC_ARG is already -173 — two predate this change), and added a path-agnostic negative test (oversized r/s of keySz+1 bytes) to test_wc_EccDecisionCoverage2 that exercises wc_ecc_check_r_s_range() on software builds and the new guard on-device. Verified: the test passes on a software build and fails under a negative control (asserting the oversized signature must not verify).

psoc6_ecc_verify_hash_ex copied mp_unsigned_bin_size(r/s) bytes of
attacker-controlled signature into the fixed signature_buf keyed only
on keySz, with no upper bound on r/s. The generic path guards this via
wc_ecc_check_r_s_range(), which is compiled out for WOLFSSL_PSOC6_CRYPTO
and skipped by the early return in wc_ecc_verify_hash_ex. Reject
rSz/sSz > keySz before the copies, preventing a stack buffer overflow.

Also correct three inverted error returns in the same function:
'return -BAD_FUNC_ARG' returned +173 (BAD_FUNC_ARG is already -173),
violating the negative-error contract; two predate this change.

Add a path-agnostic negative test (oversized r/s of keySz+1 bytes) to
test_wc_EccDecisionCoverage2: exercises wc_ecc_check_r_s_range on
software builds and the new guard under WOLFSSL_PSOC6_CRYPTO on-device.

Found by Fenrir (finding 6778).
Copilot AI review requested due to automatic review settings July 15, 2026 21:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the PSoC6 hardware ECDSA verify path against stack buffer overflow by bounding attacker-controlled ECDSA signature component sizes before copying into a fixed-size stack buffer, and adds a regression test to ensure oversized r/s values are rejected.

Changes:

  • Fix inverted error returns in psoc6_ecc_verify_hash_ex() (returning BAD_FUNC_ARG instead of -BAD_FUNC_ARG).
  • Reject signatures where rSz or sSz exceed the curve byte size (keySz) before copying into signature_buf.
  • Add a negative test case that constructs r/s with keySz + 1 bytes and asserts verification fails.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
wolfcrypt/src/port/cypress/psoc6_crypto.c Add rSz/sSz > keySz guard and correct BAD_FUNC_ARG returns to prevent stack overflow in PSoC6 ECDSA verify.
tests/api/test_ecc.c Add a path-agnostic negative test for oversized r/s inputs in wc_ecc_verify_hash_ex().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 2095 to +2096
if (!key || !verif_res || !r || !s || !hash)
return -BAD_FUNC_ARG;
return BAD_FUNC_ARG;
@Frauschi

Copy link
Copy Markdown
Contributor

jenkins retest this please

@Frauschi Frauschi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

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.

3 participants