Repository navigation
Conversation
|
PR changes generated with: |
|
There was a problem hiding this comment.
🟡 Changes recommended
Critical issues in the newly default path can corrupt digit counts, read uninitialized digits, and suppress multiplication or copy failures.
3 open issues
What changed in this PR
This PR hardens wolfCrypt’s ladder-based cryptographic operations by making copies that access both candidate values the default, reducing secret-dependent cache access.
Changes:
- Updates SP integer math, portable SP C, fastmath, and SAKKE copy selection.
- Adds
WOLFSSL_SP_FAST_MODEXP_COPYas an opt-in, disabled on capability targets. - Documents the security trade-off and adds six CI configurations covering both modes.
| File | Description |
|---|---|
wolfcrypt/src/tfm.c |
Defaults fastmath ladders to conditional copies. |
wolfcrypt/src/sp_int.c |
Defaults SP integer exponentiation to conditional copies. |
wolfcrypt/src/sp_c64.c |
Updates generated 64-bit C exponentiation and ECC copy selection. |
wolfcrypt/src/sp_c32.c |
Updates generated 32-bit C exponentiation and ECC copy selection. |
wolfcrypt/src/sakke.c |
Defaults the SAKKE ladder to conditional copies. |
doc/ASM_AND_MATH_DEFINES.md |
Documents the opt-in and its cache-security implications. |
.github/configs/os-check-linux.json |
Adds default and opt-in coverage across math implementations. |
Review effort: Balanced
ba2fd30 to
ac3c829
Compare
|
PR changes generated with: |
There was a problem hiding this comment.
🔵 Needs a closer look
The side-channel changes span multiple math backends and require cryptographic maintainer review of optimized machine code and cache-access traces, since source inspection and functional CI cannot establish address-oblivious execution.
No open issues 🎉
3 resolved since last review
Review effort: Balanced
ac3c829 to
fb9b79e
Compare
|
Jenkins: retest this please |
bb35c84 to
cc12a71
Compare
The cache-resistant modular exponentiation and ECC/SAKKE scalar-mult ladders
selected the working value from one of two objects (t[0]/t[1], R[0]/R[1],
c[0]/c[1]) on each secret exponent bit with address masking:
_sp_copy((sp_int*)(((size_t)t[0] & sp_off_on_addr[j^1]) +
((size_t)t[1] & sp_off_on_addr[j ])), t[3]);
The mask removes a secret-dependent branch but still resolves to a single
secret-dependent address, so only the selected object is touched. After the
first set exponent bit the selector equals the raw exponent bit, so each copy
discloses it at cache-line granularity, letting a co-resident observer on an
SMT sibling sharing L1D recover RSA CRT exponents dP/dQ (and DH/ECC/SAKKE
secrets) by Prime+Probe.
Make the address-oblivious copy the default for all builds: _sp_cond_copy
(sp_int.c), sp_cond_select/sp_cond_memcpy (generated sp_c64.c/sp_c32.c),
fp_cond_copy (tfm.c) and mp_cond_copy (sakke.c), which touch both candidates
every iteration with a data-dependent mask so the accessed address does not
depend on the secret. This was previously reached only under WC_NO_PTR_INT_CAST.
The faster pointer-masking copy stays available behind the new opt-in
WOLFSSL_SP_FAST_MODEXP_COPY, for deployments where a co-resident cache observer
is outside the threat model. It rebuilds a pointer from integer arithmetic on
two addresses, so it is forced off on capability targets (WC_NO_PTR_INT_CAST),
leaving their behaviour unchanged. Cost of the default is ~2.5-4% on RSA private
operations (less at larger key sizes); the specialised SP ladder cost is within
benchmark noise. The windowed SP assembly back ends are unaffected: they select
from a fully scanned table, not two objects.
sp_c64.c and sp_c32.c are regenerated from the wolfSSL sp scripts. The other SP
targets (sp_arm*, sp_cortexm, sp_riscv64) share the generator and still need
regeneration to pick up the change.
Add os-check CI legs exercising both the oblivious default and the opt-in across
sp_int.c, the generated ladder, fastmath and SAKKE, and document
WOLFSSL_SP_FAST_MODEXP_COPY in doc/ASM_AND_MATH_DEFINES.md.
Harden the promoted oblivious copy helpers, which were previously only built
under WC_NO_PTR_INT_CAST:
- _sp_cond_copy()/fp_cond_copy(): mark WC_MAYBE_UNUSED - the definition guard is
broader than the exptmod ladders that use them (e.g. ECC-with-comp-key or
RSA-verify-only builds define them but compile no private exponentiation),
which tripped -Werror=unused-function (e.g. tinytls13-cert-rsaverify).
- _sp_cond_copy(): derive the 'used'/'sign' masks at their own field width. The
digit-wide mask zero-extended to sp_size_t dropped the high bits of 'used'
when SP_WORD_SIZE==8 and an operand had >=256 digits, copying it as length 0.
- sakke_modexp_loop(): guard each mp_cond_copy() on err so a failure in the
multiply or an earlier copy is preserved instead of overwritten.
Follow-up CI fixes for the now-default oblivious copy:
- Initialise the full digit span of the exptmod ladder temporaries via a new
_sp_init_size_ct() helper. _sp_init_size() only zeroes dp[0], but
_sp_cond_copy() scans a fixed m->used digits, so a working value with fewer
significant digits left indeterminate padding that the copy read - reported
by valgrind (3.22) on the Ada wrapper RSA test. Applied to both
_sp_exptmod_mont_ex variants and both _sp_exptmod_ex variants.
- _sp_cond_copy(): build the 'used' mask with an explicit cast over unsigned
arithmetic so it is -Warith-conversion clean (smallstack-intelasm-precalc).
- sakke.c: declare the local wc_off_on_addr only for the pointer-copy opt-in;
the default oblivious copy does not use it, which was an unused variable under
WC_NO_GLOBAL_OBJECT_POINTERS (linuxkm -Werror).
cc12a71 to
0b54f3a
Compare
|
Jenkins: retest this please |

Description
The cache-resistant modular exponentiation and ECC/SAKKE scalar-mult ladders selected the working value from one of two objects (t[0]/t[1], R[0]/R[1], c[0]/c[1]) on each secret exponent bit with address masking:
The mask removes a secret-dependent branch but still resolves to a single secret-dependent address, so only the selected object is touched. After the first set exponent bit the selector equals the raw exponent bit, so each copy discloses it at cache-line granularity, letting a co-resident observer on an SMT sibling sharing L1D recover RSA CRT exponents dP/dQ (and DH/ECC/SAKKE secrets) by Prime+Probe.
Make the address-oblivious copy the default for all builds: _sp_cond_copy (sp_int.c), sp_cond_select/sp_cond_memcpy (generated sp_c64.c/sp_c32.c), fp_cond_copy (tfm.c) and mp_cond_copy (sakke.c), which touch both candidates every iteration with a data-dependent mask so the accessed address does not depend on the secret. This was previously reached only under WC_NO_PTR_INT_CAST.
The faster pointer-masking copy stays available behind the new opt-in WOLFSSL_SP_FAST_MODEXP_COPY, for deployments where a co-resident cache observer is outside the threat model. It rebuilds a pointer from integer arithmetic on two addresses, so it is forced off on capability targets (WC_NO_PTR_INT_CAST), leaving their behaviour unchanged. Cost of the default is ~2.5-4% on RSA private operations (less at larger key sizes); the specialised SP ladder cost is within benchmark noise. The windowed SP assembly back ends are unaffected: they select from a fully scanned table, not two objects.
sp_c64.c and sp_c32.c are regenerated from the wolfSSL sp scripts. The other SP targets (sp_arm*, sp_cortexm, sp_riscv64) share the generator and still need regeneration to pick up the change.
Add os-check CI legs exercising both the oblivious default and the opt-in across sp_int.c, the generated ladder, fastmath and SAKKE, and document WOLFSSL_SP_FAST_MODEXP_COPY in doc/ASM_AND_MATH_DEFINES.md.
Fixes zd#22721
Testing
./configure --enable-sakke --enable-sp-math-all — sp_int.c + sakke.c, oblivious default
./configure - --enable-sakke --enable-sp-math-all -DWOLFSSL_SP_FAST_MODEXP_COPY — sp_int.c + sakke.c, pointer opt-in
./configure - --enable-sp --disable-sp-asm -DWOLFSSL_SP_LADDER_MODEXP — generated sp_c64.c/sp_c32.c ladder, oblivious default
./configure - --enable-sp --disable-sp-asm -DWOLFSSL_SP_LADDER_MODEXP -DWOLFSSL_SP_FAST_MODEXP_COPY — sp_c64.c/sp_c32.c ladder, pointer opt-in
./configure - --enable-fastmath — tfm.c, oblivious default
./configure - --enable-fastmath -DWOLFSSL_SP_FAST_MODEXP_COPY — tfm.c, pointer opt-in
./configure - --enable-fastmath -DWC_PROTECT_ENCRYPTED_MEM — tfm.c protect-encrypted-mem ladder (validated locally)
./configure - --enable-fastmath -DWC_RSA_NONBLOCK — tfm.c nonblock ladder, both modes (compile-checked locally)