Skip to content

sakke: keep key state correct across client operations and key changes - #12090

Open
yosuke-wolfssl wants to merge 6 commits into
wolfSSL:masterfrom
yosuke-wolfssl:fix/f-sakke-state
Open

yosuke-wolfssl wants to merge 6 commits into
wolfSSL:masterfrom
yosuke-wolfssl:fix/f-sakke-state

Conversation

@yosuke-wolfssl

Copy link
Copy Markdown
Contributor

Problem

A SakkeKey caches values derived from its keys. Five paths leave that state overwritten or stale when one object changes role or loads a new KMS key.

The API accepts any initialized SakkeKey, and wolfCrypt's own sakke_test loads a new Z into a used object.

Fix (wolfcrypt/src/sakke.c)

  • sakke_compute_point_i() reads the identity into a function-local mp_int.
  • wc_ValidateSakkeRsk() returns BAD_FUNC_ARG for idSz > SAKKE_ID_MAX_SIZE, as wc_SetSakkeIdentity() and wc_MakeSakkePointI() already do. Previously such an identity gave ECC_OUT_OF_RANGE_E or a false valid = 0, and could never be used to derive.
  • wc_ExportSakkeKey() converts Z out of Montgomery form first, as wc_ExportSakkePublicKey() does.
  • A new Z (wc_ImportSakkePublicKey(), wc_ImportSakkeKey(), wc_MakeSakkeKey()) clears zMont and the cached point I.
  • A new point I (wc_MakeSakkePointI(), wc_SetSakkePointI(), wc_ValidateSakkeRsk()) clears the cached identity and table first.

Closes F-16912, F-16913, F-18182, F-18183, F-18184.

Tests

  • test_wc_Sakke_KmsKeyAfterClientOpand test_wc_Sakke_PointICache are added.
  • test_wc_Sakke_DecisionCoverage checks oversized identity.
  • tests/unit-mcdc is updated with the library fixes.

Verification

  • macOS clang: default, --disable-sp, --enable-sp, --enable-sp=small, fastmath, heapmath, smallstack, WOLFSSL_ECC_BLIND_K. The sakke API group (4/4) and testwolfcrypt pass on all; ASan + UBSan clean on three of them.
  • Linux GCC 13, -Werror: default, --enable-sp, fastmath, 0 warnings. ASan + UBSan + LSan clean on heapmath, smallstack and default.
  • whitebox-smoke: both SAKKE white-boxes print done (ok).

@yosuke-wolfssl yosuke-wolfssl self-assigned this Nov 11, 2026
Copilot AI lite review requested due to automatic review settings November 11, 2026 03:14
@yosuke-wolfssl

Copy link
Copy Markdown
Contributor Author

@claude review

@github-actions

github-actions Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

MemBrowse Memory Report · Explore what changed →

zephyr-frdm_rw612

  • FLASH: datas +16 B, log_const_area -8 B, rodata +20 B, text +10,016 B (+3.6%, 292,508 B / 67,108,864 B, total: 0% used)
  • RAM: bss +49 B, datas +16 B (+0.1%, 58,423 B / 983,040 B, total: 6% used)

No memory changes detected for:


Catch memory regressions in CI with MemBrowse. Free for open source.

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.

🟡 Changes recommended

Replacing the key pair leaves stale receiver-side RSK state and metadata active, allowing subsequent derivations to use the old secret with the new public key instead of rejecting the invalid state.

1 open issue
What changed in this PR

This PR hardens SAKKE key-state handling when a SakkeKey is reused across KMS and client operations, keys are replaced, or cached point-I data changes.

Changes:

  • Uses local scalar handling and consistent identity-size validation during point-I and RSK operations.
  • Normalizes exported Montgomery values and invalidates derived cached state when keys or point-I values change.
  • Adds API regression tests and updates MC/DC white-box and fault-injection coverage.
File Description
wolfcrypt/​src/​sakke.c Updates SAKKE point-I computation, identity validation, Montgomery conversion, and key-state cache handling.
tests/​unit-mcdc/​test_sakke_whitebox.c Updates white-box coverage for revised point-I computation and validation behavior.
tests/​unit-mcdc/​test_sakke_fault_whitebox.c Adjusts fault-injection coverage documentation and sweeps for the revised implementation.
tests/​api/​test_sakke.h Declares and registers the new SAKKE regression test groups.
tests/​api/​test_sakke.c Adds coverage for oversized identities, KMS/client key reuse, and point-I cache invalidation.

Review effort: Lite

Comment thread wolfcrypt/src/sakke.c Resolved

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.

Beyond the inline findings, I checked two more things and found no problem. First, the key->i.* reset in wc_ImportSakkePublicKey() has no guard of its own, but it is fine because the function already sits inside the WOLFCRYPT_SAKKE_CLIENT block that starts at sakke.c:1089. Second, setting i.table to NULL in the new reset paths doesn't leak memory, because the table is always a buffer the caller supplies, never one the library allocates.

Extended reasoning...

The change touches SAKKE key-state handling in wolfcrypt/src/sakke.c, which is security-sensitive crypto code. The two extra checks were made by reading where the client-only struct fields are defined in wolfssl/wolfcrypt/sakke.h and every place sakke.c assigns key->i.table.

Additional findings (outside the current diff — GitHub can't attach inline comments there):

  • 🟣 wolfcrypt/src/sakke.c — pre-existing: A sender whose point-I recompute fails can later encapsulate with a corrupted point I for the previously cached identity. sakke_compute_point_r() at sakke.c:6731 recomputes into key->i.i without first clearing key->i.idSz. On error, i.idSz and i.id still name the old identity, so the next call for it is a cache hit on a half-written point. Fix: reset key->i.idSz to 0 before calling sakke_compute_point_i(), matching what this PR now does in wc_MakeSakkePointI(), wc_SetSakkePointI() and wc_ValidateSakkeRsk().

    Why this was flagged

    The key caches point I for identity A (i.idSz/i.id = A). wc_MakeSakkeEncapsulatedSSV() at sakke.c:6848, or the derive path at sakke.c:7045, then runs for identity B, so sakke_compute_point_r() enters the recompute branch at sakke.c:6731-6741. sakke_compute_point_i() then fails after writing part of i. In non-SP builds, sakke_mulmod_base_add() at sakke.c:417-429 writes res via wc_ecc_mulmod() before ecc_projective_add_point()/ecc_map() can return MEMORY_E. Only i.table/i.tableLen are cleared; i.idSz/i.id keep A. A later call for identity A matches the cache check and calls sakke_mulmod_point() on the corrupted point. The result is a wrong R/auth that the receiver cannot derive. The base behaves the same way, so this is pre-existing. The PR fixes this pattern at the three public entry points but leaves this internal recompute site unchanged.

    Verification: pre-existing. sakke_compute_point_r() at wolfcrypt/src/sakke.c:6731-6741 is the same in the base. On failure it clears just key->i.table/key->i.tableLen (6739-6740), so i.idSz/i.id still name identity A. The next call for identity A passes the check at 6731-6732 as a cache hit and runs on the half-written I (6744). That gives a wrong R, with no error reported.

Comment thread wolfcrypt/src/sakke.c Resolved

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #12090

Scan targets checked: wolfcrypt-src, wolfcrypt-bugs, wolfssl-bugs
Not reviewed (no scan target covers them): tests/api/test_sakke.h
Coverage: 4 of 4 in-scope changed file(s) opened by the reviewer

Fenrir result: Approved ✅

No new issues found in the changed files.

Advisory only — this automated result does not count as a GitHub approval.

Review tier: Max

- sakke_compute_point_i() reads the identity into a function-local
  mp_int in place of the key's private scalar.
- wc_ValidateSakkeRsk() returns BAD_FUNC_ARG when idSz is greater
  than SAKKE_ID_MAX_SIZE.
- test: test_wc_Sakke_KmsKeyAfterClientOp is added. test_sakke_whitebox.c
  is updated.

Issue: F-16912
- wc_ExportSakkeKey() converts the public key out of Montgomery form
  with sakke_z_from_mont() before encoding it.
- test: test_wc_Sakke_KmsKeyAfterClientOp is updated.

Issue: F-18182
- wc_MakeSakkeKey() and wc_ImportSakkeKey() clear key->zMont when
  they store the new public key.
- test: test_wc_Sakke_KmsKeyAfterClientOp is updated.

Issue: F-18183
- wc_MakeSakkePointI(), wc_SetSakkePointI() and
  wc_ValidateSakkeRsk() clear the cached identity, point-I table and
  table length before they overwrite point I.
- test: test_wc_Sakke_PointICache.

Issue: F-16913
- wc_ImportSakkePublicKey(), wc_ImportSakkeKey() and
  wc_MakeSakkeKey() clear the cached identity, point-I table and
  table length when they store a new public key.
- test: test_wc_Sakke_PointICache is updated.

Issue: F-18184
- wc_ValidateSakkeRsk() records the cached identity after
  sakke_pairing() succeeds.
- sakke_compute_point_r() clears the cached identity, point-I table
  and table length before it recomputes point I.
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.

4 participants