Skip to content

Commit 7b1deda

Browse files
authored
Merge pull request #12023 from dgarske/ecc_ct_inverse
Keep secret values out of the variable-time inversion in ECC, ECCSI, SAKKE and BN
2 parents 626840e + 692a832 commit 7b1deda

37 files changed

Lines changed: 1754 additions & 332 deletions

‎.github/configs/os-check-linux.json‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,5 +621,12 @@
621621
"configure": ["--enable-leanpsk", "--enable-weak-entropy"],
622622
"extra_cflags": "-Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -Werror=implicit-function-declaration -Wno-error=cpp",
623623
"check": false,
624-
"run": [["./wolfcrypt/test/testwolfcrypt"]]}
624+
"run": [["./wolfcrypt/test/testwolfcrypt"]]},
625+
{"name": "fpecc-no-shamir",
626+
"comment": "FP_ECC with ECC_TIMING_RESISTANT but no ECC_SHAMIR: only the constant-time comb consumes the fixed-point cache.",
627+
"configure": ["--enable-fpecc", "--disable-eccshamir"]},
628+
{"name": "sp-math-sakke",
629+
"comment": "SAKKE on WOLFSSL_SP_MATH without RSA, DH, or ECCSI: its blinded RSK inverse needs sp_mulmod, which nothing else builds in this shape.",
630+
"configure": ["--enable-cryptonly", "--enable-sp-math", "--enable-sp",
631+
"--disable-rsa", "--disable-dh", "--enable-sakke"]}
625632
]

‎.wolfssl_known_macro_extras‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1068,7 +1068,6 @@ WOLFSSL_MLKEM_NO_MALLOC
10681068
WOLFSSL_MLKEM_NTT_UNROLL
10691069
WOLFSSL_MONT_RED_CT
10701070
WOLFSSL_MP_COND_COPY
1071-
WOLFSSL_MP_INVMOD_CONSTANT_TIME
10721071
WOLFSSL_MULTICIRCULATE_ALTNAMELIST
10731072
WOLFSSL_MX2_CONF_INCLUDE
10741073
WOLFSSL_NETX_DUO
@@ -1082,6 +1081,7 @@ WOLFSSL_NO_CHACHA20_POLY1305_FUSED_IFMA
10821081
WOLFSSL_NO_CHACHA20_POLY1305_SHORT
10831082
WOLFSSL_NO_CHACHA20_POLY1305_SMALL_ASM
10841083
WOLFSSL_NO_CLIENT_CERT_ERROR
1084+
WOLFSSL_NO_CONST_CMP
10851085
WOLFSSL_NO_COPY_KEY
10861086
WOLFSSL_NO_CRL_DATE_CHECK
10871087
WOLFSSL_NO_CRL_NEXT_DATE

‎CMakeLists.txt‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2040,6 +2040,9 @@ if(WOLFSSL_SAKKE)
20402040
if (NOT WOLFSSL_ECC)
20412041
message(FATAL_ERROR "cannot enable SAKKE without enabling ECC.")
20422042
endif()
2043+
if (NOT WOLFSSL_RNG)
2044+
message(FATAL_ERROR "cannot enable SAKKE without enabling RNG.")
2045+
endif()
20432046

20442047
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFCRYPT_HAVE_SAKKE")
20452048
endif()

‎configure.ac‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1962,7 +1962,8 @@ then
19621962
test "$enable_aessiv" = "" && enable_aessiv=yes
19631963
# AFALG lacks AES-EAX
19641964
test "$enable_aeseax" = "" && test "$enable_afalg" != "yes" && enable_aeseax=yes
1965-
test "$enable_sakke" = "" && test "$enable_ecc" != "no" && enable_sakke=yes
1965+
test "$enable_sakke" = "" && test "$enable_ecc" != "no" && \
1966+
test "$enable_rng" != "no" && enable_sakke=yes
19661967
test "$enable_atomicuser" = "" && enable_atomicuser=yes
19671968
test "$enable_cryptocb" = "" && enable_cryptocb=yes
19681969
test "$enable_pkcallbacks" = "" && enable_pkcallbacks=yes
@@ -6754,6 +6755,11 @@ then
67546755
AC_MSG_ERROR([SAKKE requires ECC.])
67556756
fi
67566757

6758+
if test "$ENABLED_SAKKE" != "no" && test "$ENABLED_RNG" = "no"
6759+
then
6760+
AC_MSG_ERROR([--enable-sakke requires --enable-rng])
6761+
fi
6762+
67576763
if test "x$ENABLED_SAKKE" = "xsmall"
67586764
then
67596765
ENABLED_SAKKE="yes"

‎doc/dox_comments/header_files-ja/doxygen_groups.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@
170170
-# wc_MakeSakkeKey(), wc_ExportSakkeKey(), wc_ExportSakkePublicKey() または
171171
-# wc_ImportSakkeKey()
172172
-# リクエストを待機:
173-
-# クライアントのIDに基づいてRSKを作成: wc_MakeSakkeRsk()
173+
-# クライアントのIDに基づいてRSKを作成: wc_MakeSakkeRsk_ex()
174174
-# クライアントへの転送のためにRSKをエンコード: wc_EncodeSakkeRsk()
175175
-# SAKKE鍵の解放: wc_FreeSakkeKey()
176176
@@ -231,7 +231,7 @@
231231
これらの操作は、受信者秘密鍵(RSK)を作成、検証、エンコード、デコードします。
232232
233233
RSKは、SSVを導出するために必要です(wc_DeriveSakkeSSV()を参照)。\n
234-
KMSで、クライアントのIDからRSKを作成(wc_MakeSakkeRsk())。\n
234+
KMSで、クライアントのIDからRSKを作成(wc_MakeSakkeRsk_ex())。\n
235235
クライアントで、IDでRSKを検証(wc_ValidateSakkeRsk())。\n
236236
クライアントへの転送またはストレージのためにRSKをエンコード(wc_EncodeSakkeRsk())。\n
237237
必要に応じてクライアントでRSKをデコード(wc_DecodeSakkeRsk())。\n

‎doc/dox_comments/header_files-ja/sakke.h‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ int wc_MakeSakkeRsk(SakkeKey* key, const byte* id, word16 idSz,
3030
/*!
3131
\ingroup SAKKE_RSK
3232
*/
33+
int wc_MakeSakkeRsk_ex(SakkeKey* key, const byte* id, word16 idSz,
34+
ecc_point* rsk, WC_RNG* rng);
35+
/*!
36+
\ingroup SAKKE_RSK
37+
*/
3338
int wc_ValidateSakkeRsk(SakkeKey* key, const byte* id, word16 idSz,
3439
ecc_point* rsk, int* valid);
3540
/*!

‎doc/dox_comments/header_files/doxygen_groups.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@
211211
-# wc_MakeSakkeKey(), wc_ExportSakkeKey(), wc_ExportSakkePublicKey() or
212212
-# wc_ImportSakkeKey()
213213
-# Wait for request:
214-
-# Make an RSK base on ID for the client: wc_MakeSakkeRsk()
214+
-# Make an RSK base on ID for the client: wc_MakeSakkeRsk_ex()
215215
-# Encode RSK for transfer to client: wc_EncodeSakkeRsk()
216216
-# Free SAKKE Key: wc_FreeSakkeKey()
217217
@@ -272,7 +272,7 @@
272272
These operations make, validate, encode and decode a Receiver Secret Key (RSK).
273273
274274
An RSK is required to derive an SSV (see wc_DeriveSakkeSSV()).\n
275-
On the KMS, make an RSK (wc_MakeSakkeRsk()) from the client's ID.\n
275+
On the KMS, make an RSK (wc_MakeSakkeRsk_ex()) from the client's ID.\n
276276
On the client, validate the RSK (wc_ValidateSakkeRsk()) with the ID.\n
277277
Encode the RSK (wc_EncodeSakkeRsk()) to pass to client or for storage.\n
278278
Decode the RSK (wc_DecodeSakkeRsk()) on the client when needed.\n

‎doc/dox_comments/header_files/sakke.h‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ int wc_MakeSakkeRsk(SakkeKey* key, const byte* id, word16 idSz,
3030
/*!
3131
\ingroup SAKKE_RSK
3232
*/
33+
int wc_MakeSakkeRsk_ex(SakkeKey* key, const byte* id, word16 idSz,
34+
ecc_point* rsk, WC_RNG* rng);
35+
/*!
36+
\ingroup SAKKE_RSK
37+
*/
3338
int wc_ValidateSakkeRsk(SakkeKey* key, const byte* id, word16 idSz,
3439
ecc_point* rsk, int* valid);
3540
/*!

‎src/pk_ec.c‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2365,6 +2365,9 @@ static int ec_mul2add(ecc_point* r, ecc_point* b, mp_int* n, ecc_point* q,
23652365
*
23662366
* r = base point * n + q * m
23672367
*
2368+
* With both n and q/m given the sum uses Shamir's trick, which is variable
2369+
* time: do not pass secret scalars that way.
2370+
*
23682371
* @param [in] curveIdx Index of curve in ecc_set.
23692372
* @param [out] r EC point that is result of operation.
23702373
* @param [in] n Scalar to multiply by base point. May be NULL.

‎src/ssl_bn.c‎

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1969,10 +1969,102 @@ int wolfSSL_BN_mod_exp(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a,
19691969
return ret;
19701970
}
19711971

1972+
/* Number of random blinding factors to try. A modulus with many small factors
1973+
* rejects most of them. */
1974+
#define BN_INVMOD_BLIND_TRIES 128
1975+
1976+
/* Compute r = a^-1 mod m with a blinded by a random factor.
1977+
*
1978+
* When a*b has no inverse, the factor b is tested by itself: if it has one then
1979+
* a has none, otherwise another factor is tried.
1980+
* Invert directly when there is no random number generator or no factor found:
1981+
* this API has no way to ask for blinding, so it must not start failing for
1982+
* lack of it. r may alias a or m.
1983+
*
1984+
* @param [in] a MP integer to invert.
1985+
* @param [in] m Big number that is the modulus.
1986+
* @param [out] r MP integer to hold the result.
1987+
* @return MP_OKAY on success.
1988+
* @return Other value on error, including when there is no inverse.
1989+
*/
1990+
static int wolfssl_bn_invmod_blind(mp_int* a, const WOLFSSL_BIGNUM* m,
1991+
mp_int* r)
1992+
{
1993+
mp_int* mod = (mp_int*)m->internal;
1994+
int err = MP_OKAY;
1995+
int found = 0;
1996+
WOLFSSL_BIGNUM* t = wolfSSL_BN_new();
1997+
#ifndef WC_NO_RNG
1998+
int i;
1999+
WOLFSSL_BIGNUM* b = wolfSSL_BN_new();
2000+
WOLFSSL_BIGNUM* ar = wolfSSL_BN_new();
2001+
2002+
if ((t == NULL) || (b == NULL) || (ar == NULL)) {
2003+
err = MEMORY_E;
2004+
}
2005+
if ((err == MP_OKAY) && (mp_cmp_d(mod, 2) == MP_GT)) {
2006+
/* Reduce a once, as mp_invmod() would: a*b may not fit when a is much
2007+
* wider than m. */
2008+
err = mp_mod(a, mod, (mp_int*)ar->internal);
2009+
for (i = 0; (err == MP_OKAY) && (!found) &&
2010+
(i < BN_INVMOD_BLIND_TRIES) &&
2011+
(wolfSSL_BN_rand_range(b, m) == 1); i++) {
2012+
if (mp_iszero((mp_int*)b->internal)) {
2013+
continue;
2014+
}
2015+
err = mp_mulmod((mp_int*)ar->internal, (mp_int*)b->internal, mod,
2016+
(mp_int*)t->internal);
2017+
if (err == MP_OKAY) {
2018+
err = mp_invmod((mp_int*)t->internal, mod,
2019+
(mp_int*)t->internal);
2020+
if (err == MP_OKAY) {
2021+
err = mp_mulmod((mp_int*)t->internal, (mp_int*)b->internal,
2022+
mod, (mp_int*)t->internal);
2023+
found = (err == MP_OKAY);
2024+
}
2025+
else if (err == WC_NO_ERR_TRACE(MP_VAL)) {
2026+
/* b has an inverse, so a has none: fail. Otherwise b
2027+
* shares a factor with m: try another. */
2028+
err = mp_invmod((mp_int*)b->internal, mod,
2029+
(mp_int*)t->internal);
2030+
if (err == MP_OKAY) {
2031+
err = MP_VAL;
2032+
}
2033+
else if (err == WC_NO_ERR_TRACE(MP_VAL)) {
2034+
err = MP_OKAY;
2035+
}
2036+
}
2037+
}
2038+
}
2039+
}
2040+
#else
2041+
if (t == NULL) {
2042+
err = MEMORY_E;
2043+
}
2044+
#endif
2045+
if ((err == MP_OKAY) && (!found)) {
2046+
err = mp_invmod(a, mod, (mp_int*)t->internal);
2047+
}
2048+
if (err == MP_OKAY) {
2049+
err = mp_copy((mp_int*)t->internal, r);
2050+
}
2051+
2052+
#ifndef WC_NO_RNG
2053+
wolfSSL_BN_clear_free(ar);
2054+
wolfSSL_BN_clear_free(b);
2055+
#endif
2056+
wolfSSL_BN_clear_free(t);
2057+
2058+
return err;
2059+
}
2060+
19722061
/* Calculate the modular inverse of a mod m into r. r = a^-1 mod m
19732062
*
19742063
* A new big number is allocated when r is NULL.
19752064
*
2065+
* The operand is blinded when a random blinding factor can be generated, and
2066+
* inverted unblinded otherwise. BN_FLG_CONSTTIME is not checked.
2067+
*
19762068
* @param [in, out] r Big number to hold result. May be NULL.
19772069
* @param [in] a Big number to invert.
19782070
* @param [in] m Big number that is the modulus.
@@ -2009,8 +2101,8 @@ WOLFSSL_BIGNUM *wolfSSL_BN_mod_inverse(WOLFSSL_BIGNUM *r, WOLFSSL_BIGNUM *a,
20092101
}
20102102

20112103
/* Compute inverse of a modulo n and return in r */
2012-
if ((!err) && (mp_invmod((mp_int *)a->internal, (mp_int *)m->internal,
2013-
(mp_int*)r->internal) != MP_OKAY)) {
2104+
if ((!err) && (wolfssl_bn_invmod_blind((mp_int *)a->internal,
2105+
(const WOLFSSL_BIGNUM*)m, (mp_int*)r->internal) != MP_OKAY)) {
20142106
WOLFSSL_MSG("mp_invmod() error");
20152107
err = 1;
20162108
}
@@ -2153,6 +2245,9 @@ int wolfSSL_BN_rand(WOLFSSL_BIGNUM* bn, int bits, int top, int bottom)
21532245
ret = 0;
21542246
}
21552247
/* Dispose of buffer - no longer needed. */
2248+
if (buff != NULL) {
2249+
ForceZero(buff, len);
2250+
}
21562251
XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER);
21572252

21582253
/* Truncate to requested bit length when not a whole number of bytes. */

0 commit comments

Comments
 (0)