# Variant Root Cause Analysis: CVE-2026-5466 — wolfSSL ECCSI Signature Verification

## Summary

The original CVE-2026-5466 vulnerability is a universal signature forgery in wolfSSL’s ECCSI (`wc_VerifyEccsiHash`) verifier caused by missing scalar range checks on the decoded signature components `r` and `s`. The upstream fix (commit `13a016367ff4b4d3cc4c9bc2bfdfe692a512dd81`, released in v5.9.1) adds three defenses: (1) a `[1, q-1]` range check on `r` immediately after decoding in `wc_VerifyEccsiHash`; (2) a matching range check on `s` in `eccsi_calc_j` after `eccsi_decode_sig_s`; and (3) a defense-in-depth point-at-infinity guard on `j` before the final comparison.

This variant analysis systematically tested **ten distinct bypass and alternate-trigger scenarios** against both the vulnerable (`v5.9.0-stable`, commit `922d04b3568c6428a9fb905ddee3ef5a68db3108`) and fixed (`v5.9.1-stable`, commit `1d363f3adceba9d1478230ede476a37b0dcdef24`) versions. **No bypass was found.** The fix correctly rejects all tested scalar boundary conditions, malformed encodings, and parser-robustness attempts.

## Fix Coverage / Assumptions

The fix assumes that the only code path capable of verifying an ECCSI signature is `wc_VerifyEccsiHash` (client-side), which internally calls the static helper `eccsi_calc_j`. The fix enforces the following invariants:

- **Invariant 1**: After `eccsi_decode_sig_r_pvt` decodes `r` from the signature buffer, `r` must satisfy `1 <= r < q` (where `q` is the curve order). This is checked with `mp_iszero(r)` and `mp_cmp(r, &params->order) != MP_LT`.
- **Invariant 2**: After `eccsi_decode_sig_s` decodes `s`, `s` must satisfy `1 <= s < q`. This is checked with `mp_iszero(s)` and `mp_cmp(s, &key->params.order) != MP_LT`.
- **Invariant 3 (defense-in-depth)**: The intermediate point `j` must not be the point at infinity before the final `mp_cmp(jx, r)` comparison.

The fix explicitly covers:
- `wc_VerifyEccsiHash` in `wolfcrypt/src/eccsi.c`
- `eccsi_calc_j` in `wolfcrypt/src/eccsi.c`

It does **not** modify the signing path (`wc_SignEccsiHash` / `eccsi_gen_sig`), because the signing loop already re-rolls when `s == 0` or `s == HE`. It also does not modify `wc_ValidateEccsiPair` or `wc_ValidateEccsiPvt`, which are key-pair validation routines that do not process attacker-supplied signature buffers.

## Variant / Alternate Trigger

Ten distinct variant attempts were executed and logged. None succeeded on the fixed version.

| # | Variant Description | Vulnerable Result | Fixed Result |
|---|---------------------|-----------------|--------------|
| 1 | `r = 0, s = 0` (original exploit) | **ACCEPTED** | Rejected (`MP_ZERO_E`, -121) |
| 2 | `r = q, s = q` (exact order) | Rejected | Rejected (`ECC_OUT_OF_RANGE_E`, -217) |
| 3 | `r = q+1, s = q+1` (above order) | Rejected | Rejected (`ECC_OUT_OF_RANGE_E`, -217) |
| 4 | `r = 2q, s = 2q` (double order) | Rejected | Rejected (verified=0) |
| 5 | `r = 0, s = q-1` (zero-r, valid-s) | Rejected | Rejected (`MP_ZERO_E`, -121) |
| 6 | `r = 1, s = 0` (valid-r, zero-s) | Rejected | Rejected (`MP_ZERO_E`, -121) |
| 7 | `r = q-1, s = q-1` (valid boundary) | Rejected | Rejected (verified=0) |
| 8 | Wrong `sigSz` (`SIG_SIZE - 1`) | Rejected (`BAD_FUNC_ARG`, -173) | Rejected (`BAD_FUNC_ARG`, -173) |
| 9 | `r = 0, s = 0` with PVT encoded as infinity | Rejected (`ECC_INF_E`, -140) | Rejected (`ECC_INF_E`, -140) |
| 10 | `r = 0, s = 0` with a different message | **ACCEPTED** | Rejected (`MP_ZERO_E`, -121) |

**Entry point for all attempts**: `wc_VerifyEccsiHash` in `wolfcrypt/src/eccsi.c` (lines 2204–2333 in v5.9.0-stable, lines 2204–2348 in v5.9.1-stable).

**Key finding**: `wc_VerifyEccsiHash` is the sole ECCSI verification API exposed by wolfSSL. `eccsi_calc_j`, `eccsi_decode_sig_r_pvt`, and `eccsi_decode_sig_s` are all `static` functions with exactly one caller each inside `eccsi.c`. Therefore there are no alternate entry points that reach the same verification arithmetic without passing through the new checks.

## Impact

- **Package/Component**: wolfSSL `wolfcrypt/src/eccsi.c`, `wc_VerifyEccsiHash`
- **Affected Versions**: `< 5.9.1` (tested `v5.9.0-stable`)
- **Fixed Version**: `5.9.1-stable` (commit `1d363f3adceba9d1478230ede476a37b0dcdef24`)
- **Risk Level**: High for unpatched versions; the patched version is **not vulnerable** to the tested variants.

## Root Cause

The same underlying root cause (missing scalar range validation after `mp_read_unsigned_bin`) is fully mitigated by the upstream fix. No code path in the fixed version reaches the `eccsi_calc_j` scalar multiplication or the final `mp_cmp(jx, r)` comparison without first satisfying:

1. `r != 0` and `r < q` (checked in `wc_VerifyEccsiHash`)
2. `s != 0` and `s < q` (checked in `eccsi_calc_j`)
3. `j` is not the point at infinity (checked before the final comparison)

## Reproduction Steps

1. Run `bash vuln_variant/reproduction_steps.sh`.
2. The script:
   - Builds wolfSSL `v5.9.0-stable` (vulnerable) and `v5.9.1-stable` (fixed) with `--enable-eccsi --enable-ecc --enable-sha256`.
   - Compiles `vuln_variant/eccsi_variant.c` against each build.
   - Executes the harness against both libraries, capturing output to `logs/variant_vulnerable.txt` and `logs/variant_fixed.txt`.
3. **Expected outcome**: The vulnerable library accepts `r=0, s=0` for any message (universal forgery). The fixed library rejects all ten variant attempts with non-zero error codes (`MP_ZERO_E`, `ECC_OUT_OF_RANGE_E`, `BAD_FUNC_ARG`, or `ECC_INF_E`).

## Evidence

- **Vulnerable run log**: `logs/variant_vulnerable.txt`
  - Shows `*** FORGERY ACCEPTED ***` for Tests 1 and 10 (`r=0, s=0`).
- **Fixed run log**: `logs/variant_fixed.txt`
  - Shows all ten tests rejected; no `FORGERY ACCEPTED` lines.
- **Script output**: Confirms `NO BYPASS: fixed version correctly rejects all variant attempts`.

## Recommendations / Next Steps

1. **No additional fix is required** for the ECCSI verification path tested here. The upstream patch is complete for `wc_VerifyEccsiHash`.
2. **Future hardening**: Consider centralizing scalar validation for all ECC-based signature schemes (ECCSI, ECDSA, SM2 if applicable) through the existing `wc_ecc_check_r_s_range` helper rather than inlining checks. This reduces the risk of the same class of bug re-appearing in new schemes.
3. **Regression test**: Add a unit test in `wolfcrypt/test/test.c` that explicitly feeds `r=0, s=0`, `r=q, s=q`, and `r=q+1, s=q+1` into `wc_VerifyEccsiHash` and asserts rejection, to prevent regression.
4. **Documentation**: Update the ECCSI header doxygen comments to state that `r` and `s` must be in `[1, q-1]`, matching RFC 6507 Section 5.2.2 requirements.

## Additional Notes

- **Idempotency**: `vuln_variant/reproduction_steps.sh` was executed twice consecutively; both runs produced identical results and exited cleanly with code 1 (no bypass).
- **Trust boundary**: All tests exercise the attacker-controlled signature buffer path (untrusted input delivered to `wc_VerifyEccsiHash`). This is the same trust boundary as the original CVE.
- **Security policy**: wolfSSL’s `.github/SECURITY.md` does not exclude cryptographic signature verification failures from scope; the fix is in-scope.
