## Ticket: CVE-2026-5466 — wolfSSL ECCSI universal signature forgery

**CVE**: CVE-2026-5466 | **CWE-347** (Improper Verification of Cryptographic Signature) | **CVSS 3.1**: 8.1 (High) | **CVSS 4.0**: 7.6 (High)
**Vendor / Product**: wolfSSL — `wolfcrypt` ECCSI verifier
**Repository**: https://github.com/wolfSSL/wolfssl
**Affected**: `< 5.9.1` | **Fixed**: `5.9.1`
**Upstream PR**: https://github.com/wolfSSL/wolfssl/pull/10102
**NVD**: https://nvd.nist.gov/vuln/detail/CVE-2026-5466
**Cited on**: https://red.anthropic.com/2026/cvd/

### Impact (this is bad)

wolfSSL's ECCSI (RFC 6507 — Elliptic Curve-based Certificateless Signatures for Identity-based Encryption) verifier `wc_VerifyEccsiHash` decodes the scalar components `r` and `s` from the signature blob using `mp_read_unsigned_bin` **without first asserting that `1 <= r < q` and `1 <= s < q`** (where `q` is the curve order). The subsequent verification arithmetic — at the points where `0` or `q` appear — collapses to identities that the verifier mistakes for a valid result.

The consequence is a **universal signature forgery**: an attacker who knows only the victim's public key material (no private key, no chosen-message oracle, no preimage) can submit a signature consisting of literally trivial constants (`r = 0`, `s = 0` is one such tuple; `r = q, s = q` is another) and the verifier accepts it as a valid signature for **any** message under **any** signer identity. ECCSI is used as the identity-binding primitive in MIKEY-SAKKE, 3GPP MCData/MCVideo, and other private-protocol identity-based PKI deployments — a universal forgery effectively turns the signature into a no-op.

### Affected / Fixed

| | Version |
|--|--|
| **Vulnerable** | wolfSSL `< 5.9.1` (last vulnerable tag: `v5.9.0-stable`) |
| **Fixed** | `5.9.1` (PR https://github.com/wolfSSL/wolfssl/pull/10102) |

### Where the patch lives

```
git clone https://github.com/wolfSSL/wolfssl external/wolfssl
cd external/wolfssl
git log --oneline v5.9.0-stable..v5.9.1-stable -- wolfcrypt/src/eccsi.c wolfcrypt/src/ecc.c
```

The fix adds explicit range checks immediately after the `mp_read_unsigned_bin` calls for `r` and `s` — rejecting any signature where either scalar is outside `[1, q-1]`.

### Reproduction plan (end-to-end forgery is REQUIRED)

This is a crypto-protocol bug. The validation bar is **demonstrate an actual forgery**, not "ASAN says something". The repro must show:

1. Build vulnerable wolfSSL (`v5.9.0-stable`) with ECCSI enabled into `/tmp/wolfssl-vuln`:
   ```
   git clone https://github.com/wolfSSL/wolfssl external/wolfssl-vuln && cd external/wolfssl-vuln
   git checkout v5.9.0-stable
   ./autogen.sh
   ./configure --enable-eccsi --enable-ecc --enable-sha256 \
       --disable-shared --enable-static --enable-debug \
       --prefix=/tmp/wolfssl-vuln
   make -j && make install
   ```
   Repeat at `v5.9.1-stable` into `/tmp/wolfssl-fixed`.

2. Write a small C program `repro/eccsi_forge.c` that:
   1. Loads (or generates) a valid ECCSI key/identity pair (KMS PVT, SSK, PVT — see RFC 6507).
   2. Picks an attacker-chosen message `M = "FORGED: any text the attacker wants the victim to authenticate"`.
   3. Constructs a forged signature blob by setting the scalar bytes of `r` and `s` to one of:
      - all-zero (`r = 0, s = 0`)
      - the curve order `q` (`r = q, s = q`)
      - `r = q, s = 0`
      - `r = q, s = 1`
      - a multiple of `q` (`r = 2*q, s = 2*q`)
   4. Calls `wc_VerifyEccsiHash(public_key, identity, M, /*M_len*/, forged_sig)`.
   5. Prints the exact return value and the scalar tuple used.

3. Compile + run against both libs:
   ```
   gcc repro/eccsi_forge.c -I/tmp/wolfssl-vuln/include -L/tmp/wolfssl-vuln/lib -lwolfssl -o /tmp/forge-vuln
   gcc repro/eccsi_forge.c -I/tmp/wolfssl-fixed/include -L/tmp/wolfssl-fixed/lib -lwolfssl -o /tmp/forge-fixed
   LD_LIBRARY_PATH=/tmp/wolfssl-vuln/lib  /tmp/forge-vuln
   LD_LIBRARY_PATH=/tmp/wolfssl-fixed/lib /tmp/forge-fixed
   ```
   - **Vulnerable build**: `wc_VerifyEccsiHash` returns 0 (success) on at least one forged-scalar choice → the forger has authenticated an arbitrary message under an arbitrary identity using no private key. Print the M, identity, and (r, s) values.
   - **Fixed build**: `wc_VerifyEccsiHash` returns a non-zero error code (likely `MP_ZERO_E`, `MP_VAL`, or `BAD_FUNC_ARG`) for ALL of the tried scalar choices.

4. The reproduction script must walk through several distinct scalar choices and report which one(s) produced the forgery. If NONE of them produce a forgery on vulnerable, the verdict is `not_confirmed` — do not file an ASAN-only proof. The bug is a forgery, the evidence has to be a forgery.

### Expected reproduction artifacts

- `repro/reproduction_steps.sh` — builds vuln + fixed wolfSSL, compiles the forgery harness, runs against both, captures stdout from both.
- `repro/eccsi_forge.c` — the forgery program (writes M, identity, forged (r,s), and verifier return code).
- `repro/validation_verdict.json` — `confirmed` only if (a) the vulnerable verifier returns success for at least one forged-scalar choice over an attacker-supplied message, AND (b) the fixed verifier rejects all of them.
- `logs/vulnerable_forge.txt` — vulnerable run output (must include the line proving forgery acceptance + the (r, s) tuple that worked).
- `logs/fixed_forge.txt` — fixed run output (must show the verifier rejecting each tried scalar with its error code).
- `repro/rca_report.md` — RCA explaining the missing scalar range check in `wc_VerifyEccsiHash` and why each "trivial" scalar collapses the verifier's arithmetic to a passing identity.
