From 5df8022a5d328da732204181a23eb9554ac94f85 Mon Sep 17 00:00:00 2001 From: Emma Stensland Date: Wed, 12 Aug 2026 10:28:33 -0600 Subject: [PATCH 1/6] F-7427: Remove WOLFSSL_MP_INVMOD_CONSTANT_TIME macro --- wolfcrypt/src/dsa.c | 72 +++++---------------------------------------- wolfcrypt/src/rsa.c | 9 ++---- 2 files changed, 9 insertions(+), 72 deletions(-) diff --git a/wolfcrypt/src/dsa.c b/wolfcrypt/src/dsa.c index c9caf213064..3f4681d6d23 100644 --- a/wolfcrypt/src/dsa.c +++ b/wolfcrypt/src/dsa.c @@ -775,15 +775,11 @@ int wc_DsaSign_ex(const byte* digest, word32 digestSz, byte* out, DsaKey* key, mp_int *r = NULL; mp_int *s = NULL; mp_int *H = NULL; -#ifndef WOLFSSL_MP_INVMOD_CONSTANT_TIME mp_int *b = NULL; -#endif byte *buffer = NULL; #else mp_int k[1], kInv[1], r[1], s[1], H[1]; -#ifndef WOLFSSL_MP_INVMOD_CONSTANT_TIME mp_int b[1]; -#endif byte buffer[DSA_MAX_HALF_SIZE]; #endif mp_int* qMinus1; @@ -807,9 +803,7 @@ int wc_DsaSign_ex(const byte* digest, word32 digestSz, byte* out, DsaKey* key, r = (mp_int *)XMALLOC(sizeof *r, key->heap, DYNAMIC_TYPE_TMP_BUFFER); s = (mp_int *)XMALLOC(sizeof *s, key->heap, DYNAMIC_TYPE_TMP_BUFFER); H = (mp_int *)XMALLOC(sizeof *H, key->heap, DYNAMIC_TYPE_TMP_BUFFER); -#ifndef WOLFSSL_MP_INVMOD_CONSTANT_TIME b = (mp_int *)XMALLOC(sizeof *b, key->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif buffer = (byte *)XMALLOC(DSA_MAX_HALF_SIZE, key->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -817,25 +811,18 @@ int wc_DsaSign_ex(const byte* digest, word32 digestSz, byte* out, DsaKey* key, (kInv == NULL) || (r == NULL) || (s == NULL) || - (H == NULL) -#ifndef WOLFSSL_MP_INVMOD_CONSTANT_TIME - || (b == NULL) -#endif - || (buffer == NULL)) { + (H == NULL) || + (b == NULL) || + (buffer == NULL)) { ret = MEMORY_E; break; } #endif -#ifdef WOLFSSL_MP_INVMOD_CONSTANT_TIME - if (mp_init_multi(k, kInv, r, s, H, 0) != MP_OKAY) -#else - if (mp_init_multi(k, kInv, r, s, H, b) != MP_OKAY) -#endif - { - ret = MP_INIT_E; - break; - } + if (mp_init_multi(k, kInv, r, s, H, b) != MP_OKAY) { + ret = MP_INIT_E; + break; + } halfSz = min(DSA_MAX_HALF_SIZE, (word32)mp_unsigned_bin_size(&key->q)); /* NIST FIPS 186-4: Sections 4.1 @@ -896,46 +883,6 @@ int wc_DsaSign_ex(const byte* digest, word32 digestSz, byte* out, DsaKey* key, break; } -#ifdef WOLFSSL_MP_INVMOD_CONSTANT_TIME - /* inverse k mod q */ - if (mp_invmod(k, &key->q, kInv) != MP_OKAY) { - ret = MP_INVMOD_E; - break; - } - - /* generate r, r = (g exp k mod p) mod q */ - if (mp_exptmod_ex(&key->g, k, key->q.used, &key->p, r) != MP_OKAY) { - ret = MP_EXPTMOD_E; - break; - } - - if (mp_mod(r, &key->q, r) != MP_OKAY) { - ret = MP_MOD_E; - break; - } - - /* generate H from sha digest */ - if (mp_read_unsigned_bin(H, digest, digestSz) != MP_OKAY) { - ret = MP_READ_E; - break; - } - - /* generate s, s = (kInv * (H + x*r)) % q */ - if (mp_mul(&key->x, r, s) != MP_OKAY) { - ret = MP_MUL_E; - break; - } - - if (mp_add(s, H, s) != MP_OKAY) { - ret = MP_ADD_E; - break; - } - - if (mp_mulmod(s, kInv, &key->q, s) != MP_OKAY) { - ret = MP_MULMOD_E; - break; - } -#else /* Blinding value * Generate b in range [1, q-1]. */ @@ -1024,7 +971,6 @@ int wc_DsaSign_ex(const byte* digest, word32 digestSz, byte* out, DsaKey* key, ret = MP_MOD_E; break; } -#endif /* detect zero r or s */ if ((mp_iszero(r) == MP_YES) || (mp_iszero(s) == MP_YES)) { @@ -1074,14 +1020,12 @@ int wc_DsaSign_ex(const byte* digest, word32 digestSz, byte* out, DsaKey* key, mp_clear(H); XFREE(H, key->heap, DYNAMIC_TYPE_TMP_BUFFER); } -#ifndef WOLFSSL_MP_INVMOD_CONSTANT_TIME if (b) { if ((ret != WC_NO_ERR_TRACE(MP_INIT_E)) && (ret != WC_NO_ERR_TRACE(MEMORY_E))) mp_forcezero(b); XFREE(b, key->heap, DYNAMIC_TYPE_TMP_BUFFER); } -#endif if (buffer) { ForceZero(buffer, halfSz); XFREE(buffer, key->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -1091,9 +1035,7 @@ int wc_DsaSign_ex(const byte* digest, word32 digestSz, byte* out, DsaKey* key, ForceZero(buffer, halfSz); mp_forcezero(kInv); mp_forcezero(k); -#ifndef WOLFSSL_MP_INVMOD_CONSTANT_TIME mp_forcezero(b); -#endif mp_clear(H); mp_clear(s); mp_clear(r); diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 096c0e50e21..a1a6abd142b 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -94,7 +94,6 @@ RSA keys can be used to encrypt, decrypt, sign and verify data. * RSA_LOW_MEM: Non-CRT private ops, less memory default: off * WC_RSA_NONBLOCK: Non-blocking RSA operations default: off * WC_RSA_NONBLOCK_TIME: Time-based non-blocking RSA default: off - * WOLFSSL_MP_INVMOD_CONSTANT_TIME: Constant-time modular inverse default: off * WC_RSA_NO_FERMAT_CHECK: Skip Fermat factorization check on default: off * key generation (p and q closeness) * @@ -5732,15 +5731,11 @@ int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng) err = mp_mod(&key->d, tmp1, &key->dP); if (err == MP_OKAY) /* key->dQ = d mod(q-1) */ err = mp_mod(&key->d, tmp2, &key->dQ); -#ifdef WOLFSSL_MP_INVMOD_CONSTANT_TIME - if (err == MP_OKAY) /* key->u = 1/q mod p */ - err = mp_invmod(q, p, &key->u); -#else + /* key->u = 1/q mod p = q^(p-2) mod p */ if (err == MP_OKAY) err = mp_sub_d(p, 2, tmp3); - if (err == MP_OKAY) /* key->u = 1/q mod p = q^p-2 mod p */ + if (err == MP_OKAY) err = mp_exptmod(q, tmp3, p, &key->u); -#endif if (err == MP_OKAY) err = mp_copy(p, &key->p); if (err == MP_OKAY) From 0d9994d7463ea896d770b95ff8b5753f87100272 Mon Sep 17 00:00:00 2001 From: Emma Stensland Date: Wed, 12 Aug 2026 10:28:33 -0600 Subject: [PATCH 2/6] F-7097: Route secret ECC scalars around the fixed-point cache --- wolfcrypt/src/ecc.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 54206d2fb4a..5d8a6bad54b 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -13780,7 +13780,9 @@ static int build_lut(int idx, mp_int* a, mp_int* modulus, mp_digit mp, return err; } -/* perform a fixed point ECC mulmod */ +#ifndef ECC_TIMING_RESISTANT +/* perform a fixed point ECC mulmod. Not constant-time; do not use with + * secret scalars. */ static int accel_fp_mul(int idx, const mp_int* k, ecc_point *R, mp_int* a, mp_int* modulus, mp_digit mp, int map) { @@ -13960,6 +13962,7 @@ static int accel_fp_mul(int idx, const mp_int* k, ecc_point *R, mp_int* a, return err; } +#endif /* !ECC_TIMING_RESISTANT */ #endif #ifdef ECC_SHAMIR @@ -14456,6 +14459,7 @@ int wc_ecc_mulmod_ex(const mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, } +#ifndef ECC_TIMING_RESISTANT if (err == MP_OKAY) { /* if it's 2 build the LUT, if it's higher just use the LUT */ if (idx >= 0 && fp_cache[idx].lru_count >= 2 && !fp_cache[idx].LUT_set) { @@ -14486,6 +14490,15 @@ int wc_ecc_mulmod_ex(const mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, err = normal_ecc_mulmod(k, G, R, a, modulus, NULL, map, heap); } } +#else + /* No RNG here, so FP-cache LUT can't be blinded; skip building/using + * it and always take the constant-time ladder. */ + if (err == MP_OKAY) { + err = normal_ecc_mulmod(k, G, R, a, modulus, NULL, map, heap); + } +#endif + (void)mp; + (void)mpSetup; out: @@ -14615,6 +14628,12 @@ int wc_ecc_mulmod_ex2(const mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, } +#if !defined(ECC_TIMING_RESISTANT) || defined(ECC_SHAMIR) + /* Build/refresh the FP-cache LUT for this point. Needed directly by + * accel_fp_mul below when not timing-resistant, and also pre-warms + * the cache for accel_fp_mul2add's Shamir-trick path (public-scalar + * only, safe without RNG blinding), which may hit this same point + * later even when the ladder is used here. */ if (err == MP_OKAY) { /* if it's 2 build the LUT, if it's higher just use the LUT */ if (idx >= 0 && fp_cache[idx].lru_count >= 2 && !fp_cache[idx].LUT_set) { @@ -14632,7 +14651,16 @@ int wc_ecc_mulmod_ex2(const mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, err = build_lut(idx, a, modulus, mp, mu); } } +#endif +#ifdef ECC_TIMING_RESISTANT + if (err == MP_OKAY) { + /* accel_fp_mul is not safe for secret scalars. Fall back to ladder. */ + (void)mpSetup; + (void)mp; + err = normal_ecc_mulmod(k, G, R, a, modulus, rng, map, heap); + } +#else if (err == MP_OKAY) { if (idx >= 0 && fp_cache[idx].LUT_set) { if (mpSetup == 0) { @@ -14645,6 +14673,7 @@ int wc_ecc_mulmod_ex2(const mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, err = normal_ecc_mulmod(k, G, R, a, modulus, rng, map, heap); } } +#endif out: From 0fa0b1de0e2079b1dab27c061fd12cfc767f32ac Mon Sep 17 00:00:00 2001 From: Emma Stensland Date: Wed, 12 Aug 2026 10:28:33 -0600 Subject: [PATCH 3/6] F-7098: Use Fermat exponentiation instead of mp_invmod for ECCSI signing --- wolfcrypt/src/eccsi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/eccsi.c b/wolfcrypt/src/eccsi.c index d0417ec879a..36453708b9d 100644 --- a/wolfcrypt/src/eccsi.c +++ b/wolfcrypt/src/eccsi.c @@ -1995,9 +1995,13 @@ int wc_SignEccsiHash(EccsiKey* key, WC_RNG* rng, enum wc_HashType hashType, err = eccsi_gen_sig(key, rng, hashType, msg, msgSz, r, s); } - /* Step 5: s' = ( (( HE + r * SSK )^-1) * j ) modulo q, erase j */ + /* Step 5: s' = ( (( HE + r * SSK )^-1) * j ) modulo q, erase j + * Invert via Fermat's little theorem (s^(order-2) mod order) */ if (err == 0) { - err = mp_invmod(s, &key->params.order, s); + err = mp_sub_d(&key->params.order, 2, &key->tmp); + if (err == MP_OKAY) { + err = mp_exptmod(s, &key->tmp, &key->params.order, s); + } } if (err == 0) { j = wc_ecc_key_get_priv(&key->pubkey); From 024fcd1bfc6f198d106ebb292ba1ab66babed67f Mon Sep 17 00:00:00 2001 From: Emma Stensland Date: Wed, 12 Aug 2026 10:28:33 -0600 Subject: [PATCH 4/6] F-7099: Use Fermat exponentiation instead of mp_invmod for SAKKE RSK derivation --- wolfcrypt/src/sakke.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/sakke.c b/wolfcrypt/src/sakke.c index a7b64e32a76..b69fd2a3186 100644 --- a/wolfcrypt/src/sakke.c +++ b/wolfcrypt/src/sakke.c @@ -993,9 +993,19 @@ int wc_MakeSakkeRsk(SakkeKey* key, const byte* id, word16 idSz, ecc_point* rsk) if (err == 0) { err = mp_addmod(a, wc_ecc_key_get_priv(&key->ecc), &key->params.q, a); } - /* (a + z_T) ^ 1 modulo q */ + /* mp_exptmod silently yields 0 for a zero base; check invertibility. */ + if ((err == 0) && mp_iszero(a)) { + err = MP_VAL; + } + /* (a + z_T)^-1 mod q via Fermat's Little Theorem (a^(q-2) mod q). + * Fenrir finding: avoids EGCD invmod timing leaks that would expose + * the fixed KMS secret z_T. */ if (err == 0) { - err = mp_invmod(a, &key->params.q, a); + mp_int* tmp = &key->tmp.m2; + err = mp_sub_d(&key->params.q, 2, tmp); + if (err == 0) { + err = mp_exptmod(a, tmp, &key->params.q, a); + } } /* [ (a + z_T) ^ 1 modulo q ]P */ From c87338e66c6ea305cb946da07890e285a6deadec Mon Sep 17 00:00:00 2001 From: Emma Stensland Date: Wed, 12 Aug 2026 10:28:33 -0600 Subject: [PATCH 5/6] F-7426: Implement heap-math CT primitives using branchless masks --- wolfcrypt/src/integer.c | 151 +++++++++++++++++++++++++++++++++------- 1 file changed, 124 insertions(+), 27 deletions(-) diff --git a/wolfcrypt/src/integer.c b/wolfcrypt/src/integer.c index bcd050c117f..66006d26932 100644 --- a/wolfcrypt/src/integer.c +++ b/wolfcrypt/src/integer.c @@ -1698,19 +1698,43 @@ int mp_div_2(mp_int * a, mp_int * b) /* c = a / 2 (mod b) - constant time (a < b and positive) */ int mp_div_2_mod_ct(mp_int *a, mp_int *b, mp_int *c) { - int res; + int res, i; + mp_digit mask, u; - if (mp_isodd(a)) { - res = mp_add(a, b, c); - if (res == MP_OKAY) { - res = mp_div_2(c, c); - } + if (a->used > b->used) { + return MP_VAL; + } + + if ((res = mp_grow(c, b->used + 1)) != MP_OKAY) { + return res; } - else { - res = mp_div_2(a, c); + + mask = (mp_digit)0 - (a->used > 0 ? (a->dp[0] & 1) : 0); + u = 0; + for (i = 0; i < b->used; i++) { + mp_digit a_val = (i < a->used) ? a->dp[i] : 0; + c->dp[i] = a_val + (b->dp[i] & mask) + u; + u = c->dp[i] >> DIGIT_BIT; + c->dp[i] &= MP_MASK; } + c->dp[b->used] = u; - return res; + for (i = 0; i < b->used; i++) { + c->dp[i] = (c->dp[i] >> 1) | ((c->dp[i+1] & 1) << (DIGIT_BIT - 1)); + } + + { + int old_used = c->used; + c->used = b->used; + for (i = b->used; i < old_used; i++) { + c->dp[i] = 0; + } + c->dp[b->used] = 0; + } + c->sign = MP_ZPOS; + mp_clamp(c); + + return MP_OKAY; } @@ -3115,29 +3139,59 @@ int mp_submod_ct(mp_int* a, mp_int* b, mp_int* c, mp_int* d) int res; mp_int t; mp_int* r = d; + mp_digit u, mask; + int i; + + if (a->used > c->used || b->used > c->used) { + return MP_VAL; + } if (c == d) { r = &t; - if ((res = mp_init (r)) != MP_OKAY) { return res; } } - res = mp_sub (a, b, r); - if (res == MP_OKAY) { - if (mp_isneg (r)) { - res = mp_add (r, c, d); - } else if (c == d) { - res = mp_copy (r, d); + if ((res = mp_grow(r, c->used)) != MP_OKAY) { + if (c == d) { mp_clear(r); } + return res; + } + + u = 0; + for (i = 0; i < c->used; i++) { + mp_digit a_val = (i < a->used) ? a->dp[i] : 0; + mp_digit b_val = (i < b->used) ? b->dp[i] : 0; + mp_digit val = a_val - b_val - u; + r->dp[i] = val & MP_MASK; + u = val >> (CHAR_BIT * sizeof(mp_digit) - 1); + } + + mask = (mp_digit)0 - u; + u = 0; + for (i = 0; i < c->used; i++) { + r->dp[i] += (c->dp[i] & mask) + u; + u = r->dp[i] >> DIGIT_BIT; + r->dp[i] &= MP_MASK; + } + + { + int old_used = r->used; + r->used = c->used; + for (i = c->used; i < old_used; i++) { + r->dp[i] = 0; } } + r->sign = MP_ZPOS; + mp_clamp(r); if (c == d) { - mp_clear (r); + res = mp_copy(r, d); + mp_clear(r); + return res; } - return res; + return MP_OKAY; } /* d = a + b (mod c) - a < c and b < c and positive */ @@ -3146,29 +3200,72 @@ int mp_addmod_ct(mp_int* a, mp_int* b, mp_int* c, mp_int* d) int res; mp_int t; mp_int* r = d; + mp_digit u, borrow, mask; + int i; + + if (a->used > c->used || b->used > c->used) { + return MP_VAL; + } if (c == d) { r = &t; - if ((res = mp_init (r)) != MP_OKAY) { return res; } } - res = mp_add (a, b, r); - if (res == MP_OKAY) { - if (mp_cmp (r, c) != MP_LT) { - res = mp_sub (r, c, d); - } else if (c == d) { - res = mp_copy (r, d); + if ((res = mp_grow(r, c->used + 1)) != MP_OKAY) { + if (c == d) { mp_clear(r); } + return res; + } + + u = 0; + for (i = 0; i < c->used; i++) { + mp_digit a_val = (i < a->used) ? a->dp[i] : 0; + mp_digit b_val = (i < b->used) ? b->dp[i] : 0; + r->dp[i] = a_val + b_val + u; + u = r->dp[i] >> DIGIT_BIT; + r->dp[i] &= MP_MASK; + } + r->dp[c->used] = u; + + borrow = 0; + for (i = 0; i < c->used; i++) { + mp_digit val = r->dp[i] - c->dp[i] - borrow; + borrow = val >> (CHAR_BIT * sizeof(mp_digit) - 1); + } + { + mp_digit val = r->dp[c->used] - borrow; + borrow = val >> (CHAR_BIT * sizeof(mp_digit) - 1); + } + + mask = (mp_digit)0 - (1 - borrow); + + borrow = 0; + for (i = 0; i < c->used; i++) { + mp_digit val = r->dp[i] - (c->dp[i] & mask) - borrow; + r->dp[i] = val & MP_MASK; + borrow = val >> (CHAR_BIT * sizeof(mp_digit) - 1); + } + + { + int old_used = r->used; + r->used = c->used; + for (i = c->used; i < old_used; i++) { + r->dp[i] = 0; } + r->dp[c->used] = 0; } + r->sign = MP_ZPOS; + mp_clamp(r); if (c == d) { - mp_clear (r); + res = mp_copy(r, d); + mp_clear(r); + return res; } - return res; + return MP_OKAY; } /* computes b = a*a */ From 23cc479387ac7fb412d9edc31704f88d4e334f88 Mon Sep 17 00:00:00 2001 From: Emma Stensland Date: Wed, 12 Aug 2026 14:18:49 -0600 Subject: [PATCH 6/6] Refactor to enforce ConstantCompare across codebase and optimize with volatile pointers --- src/internal.c | 15 ++++++++------- wolfcrypt/src/asn.c | 4 ++-- wolfcrypt/src/misc.c | 4 +++- wolfcrypt/src/port/atmel/atmel.c | 2 +- wolfcrypt/src/rsa.c | 2 +- wolfcrypt/src/wc_lms_impl.c | 2 +- wolfcrypt/src/wc_mldsa.c | 6 ++++-- wolfcrypt/src/wc_slhdsa.c | 2 +- wolfcrypt/src/wc_xmss_impl.c | 2 +- wolfssl/wolfcrypt/settings.h | 13 ++++++++++++- 10 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/internal.c b/src/internal.c index 9101a464583..ca1a84b474b 100644 --- a/src/internal.c +++ b/src/internal.c @@ -35104,8 +35104,8 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, ssl->buffers.digest.length, TypeHash(ssl->options.peerHashAlgo)); if (encSigSz != args->sigSz || !args->output || - XMEMCMP(args->output, encodedSig, - min(encSigSz, + ConstantCompare(args->output, encodedSig, + (int)min(encSigSz, MAX_ENCODED_CLASSIC_SIG_SZ)) != 0) { ret = VERIFY_SIGN_ERROR; @@ -35118,7 +35118,7 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, } else if (args->sigSz != FINISHED_SZ || !args->output || - XMEMCMP(args->output, + ConstantCompare(args->output, ssl->buffers.digest.buffer, FINISHED_SZ) != 0) { ERROR_OUT(VERIFY_SIGN_ERROR, exit_dske); @@ -40863,8 +40863,8 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) TypeHash(ssl->options.peerHashAlgo)); if (args->sendSz != args->sigSz || !args->output || - XMEMCMP(args->output, encodedSig, - min(args->sigSz, MAX_ENCODED_CLASSIC_SIG_SZ)) != 0) { + ConstantCompare(args->output, encodedSig, + (int)min(args->sigSz, MAX_ENCODED_CLASSIC_SIG_SZ)) != 0) { ret = VERIFY_CERT_ERROR; } @@ -40874,8 +40874,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) } else { if (args->sendSz != FINISHED_SZ || !args->output || - XMEMCMP(args->output, - &ssl->hsHashes->certHashes, FINISHED_SZ) != 0) { + ConstantCompare(args->output, + (const byte*)&ssl->hsHashes->certHashes, + FINISHED_SZ) != 0) { ret = VERIFY_CERT_ERROR; } } diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 1995f8207af..8b6b5618c75 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -18325,8 +18325,8 @@ int ConfirmSignature(SignatureCtx* sigCtx, sigCtx->digest, (word32)sigCtx->digestSz, sigCtx->typeH); if (encodedSigSz == verifySz && sigCtx->out != NULL && - XMEMCMP(sigCtx->out, encodedSig, - (size_t)encodedSigSz) == 0) { + ConstantCompare(sigCtx->out, encodedSig, + encodedSigSz) == 0) { ret = 0; } else { diff --git a/wolfcrypt/src/misc.c b/wolfcrypt/src/misc.c index 1642f9b1caf..05db57293bd 100644 --- a/wolfcrypt/src/misc.c +++ b/wolfcrypt/src/misc.c @@ -731,9 +731,11 @@ WC_MISC_STATIC WC_INLINE int ConstantCompare(const byte* a, const byte* b, { int i; int compareSum = 0; + const volatile byte* va = (const volatile byte*)a; + const volatile byte* vb = (const volatile byte*)b; for (i = 0; i < length; i++) { - compareSum |= a[i] ^ b[i]; + compareSum |= va[i] ^ vb[i]; } return compareSum; diff --git a/wolfcrypt/src/port/atmel/atmel.c b/wolfcrypt/src/port/atmel/atmel.c index e9156ee13de..cd812e66900 100644 --- a/wolfcrypt/src/port/atmel/atmel.c +++ b/wolfcrypt/src/port/atmel/atmel.c @@ -2034,7 +2034,7 @@ static int wc_Microchip_AesGcmCommon(Aes* aes, byte* out, const byte* in, in, sz, out, tag_buf); if (status == ATCA_SUCCESS) { copy_sz = authTagSz; - if (XMEMCMP(tag_buf, authTag, copy_sz) != 0) { + if (ConstantCompare(tag_buf, authTag, (int)copy_sz) != 0) { return AES_GCM_AUTH_E; } } diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index a1a6abd142b..b301b2eaa38 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -4597,7 +4597,7 @@ int wc_RsaPSS_CheckPadding_ex2(const byte* in, word32 inSz, const byte* sig, sigCheck, inSz); } if (ret == 0) { - if (XMEMCMP(sigCheck, sig + saltLen, inSz) != 0) { + if (ConstantCompare(sigCheck, sig + saltLen, (int)inSz) != 0) { WOLFSSL_MSG("RsaPSS_CheckPadding: Padding Error"); ret = BAD_PADDING_E; } diff --git a/wolfcrypt/src/wc_lms_impl.c b/wolfcrypt/src/wc_lms_impl.c index e88c032d87e..4661a18d41e 100644 --- a/wolfcrypt/src/wc_lms_impl.c +++ b/wolfcrypt/src/wc_lms_impl.c @@ -2872,7 +2872,7 @@ static int wc_lms_verify(LmsState* state, const byte* pub, const byte* msg, ret = wc_lms_compute_root(state, q, kc, sig_path, tc); } /* Algorithm 6. Step 4. */ - if ((ret == 0) && (XMEMCMP(pub_k, tc, params->hash_len) != 0)) { + if ((ret == 0) && (ConstantCompare(pub_k, tc, (int)params->hash_len) != 0)) { ret = SIG_VERIFY_E; } diff --git a/wolfcrypt/src/wc_mldsa.c b/wolfcrypt/src/wc_mldsa.c index 73edac5d1f4..ab4b73f9a53 100644 --- a/wolfcrypt/src/wc_mldsa.c +++ b/wolfcrypt/src/wc_mldsa.c @@ -9768,7 +9768,8 @@ static int mldsa_verify_with_mu(wc_MlDsaKey* key, const byte* mu, } if ((ret == 0) && valid) { /* Step 13: Compare commit. */ - valid = (XMEMCMP(commit, commit_calc, params->lambda / 4) == 0); + valid = (ConstantCompare(commit, commit_calc, + (int)(params->lambda / 4)) == 0); } *res = valid; @@ -10023,7 +10024,8 @@ static int mldsa_verify_with_mu(wc_MlDsaKey* key, const byte* mu, } if ((ret == 0) && valid) { /* Step 13: Compare commit. */ - valid = (XMEMCMP(commit, commit_calc, params->lambda / 4) == 0); + valid = (ConstantCompare(commit, commit_calc, + (int)(params->lambda / 4)) == 0); } *res = valid; diff --git a/wolfcrypt/src/wc_slhdsa.c b/wolfcrypt/src/wc_slhdsa.c index c70310ff229..8d74219bfd8 100644 --- a/wolfcrypt/src/wc_slhdsa.c +++ b/wolfcrypt/src/wc_slhdsa.c @@ -5018,7 +5018,7 @@ static int slhdsakey_ht_verify(SlhDsaKey* key, const byte* m, } } /* Step 13: Compare computed node with public key root. */ - if ((ret == 0) && (XMEMCMP(node, pk_root, n) != 0)) { + if ((ret == 0) && (ConstantCompare(node, pk_root, (int)n) != 0)) { /* Step 16: Return signature verification failed. */ ret = SIG_VERIFY_E; } diff --git a/wolfcrypt/src/wc_xmss_impl.c b/wolfcrypt/src/wc_xmss_impl.c index 369f0740803..957db889d9f 100644 --- a/wolfcrypt/src/wc_xmss_impl.c +++ b/wolfcrypt/src/wc_xmss_impl.c @@ -4383,7 +4383,7 @@ int wc_xmssmt_verify(XmssState* state, const unsigned char* m, word32 mlen, ret = state->ret; } /* Compare calculated node with public key root. */ - if ((ret == 0) && (XMEMCMP(node, pub_root, n) != 0)) { + if ((ret == 0) && (ConstantCompare(node, pub_root, (int)n) != 0)) { ret = SIG_VERIFY_E; } diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 696ece03230..dd9566dc30d 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -5012,8 +5012,19 @@ blinding by defining WC_BLINDING_NO_RNG_ACKNOWLEDGE_WEAKNESS." #define WOLFSSL_NO_CT_OPS #endif +/* Only auto-disable ConstantCompare() when no feature below still calls it. + * Manually defining WOLFSSL_NO_CONST_CMP still requires supplying your own + * ConstantCompare() (see wolfssl/wolfcrypt/misc.h). */ #if defined(WOLFCRYPT_ONLY) && defined(NO_AES) && !defined(HAVE_CURVE25519) && \ - !defined(HAVE_CURVE448) && defined(WC_NO_RNG) && defined(WC_NO_RSA_OAEP) + !defined(HAVE_CURVE448) && defined(WC_NO_RNG) && \ + defined(WC_NO_RSA_OAEP) && defined(NO_RSA) && !defined(HAVE_ECC) && \ + !defined(HAVE_ASCON) && \ + !(defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) && \ + !defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_HAVE_XMSS) && \ + !defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_HAVE_SLHDSA) && \ + !defined(HAVE_ED25519) && !defined(HAVE_ED448) && \ + !defined(WOLFSSL_CMAC) && !defined(WOLFCRYPT_HAVE_SRP) && \ + !defined(HAVE_PKCS12) #undef WOLFSSL_NO_CONST_CMP #define WOLFSSL_NO_CONST_CMP #endif