Skip to content

Commit ee291fa

Browse files
committed
Reject even moduli in sp_exptmod_nct when the generic path is not built
1 parent ab4a0a6 commit ee291fa

3 files changed

Lines changed: 31 additions & 141 deletions

File tree

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,9 +543,13 @@
543543
"configure": ["--enable-cryptonly", "--enable-rsavfy",
544544
"--enable-ecccustcurves=all", "--disable-examples"]},
545545
{"name": "cryptonly-rsapub-no-dh-public-mp", "minutes": 1.0,
546-
"comment": "RSA public only with DH off, so sp_exptmod_ex hands every modulus to sp_exptmod_nct and the constant-time generic exponentiation is not compiled. WOLFSSL_PUBLIC_MP lets wolfcrypt test run mp_test, whose even modulus checks cover the non-Montgomery path of sp_exptmod_nct in this shape.",
546+
"comment": "RSA public only with DH off, so sp_exptmod_ex hands every modulus to sp_exptmod_nct and the constant-time generic exponentiation is not compiled. WOLFSSL_PUBLIC_MP lets wolfcrypt test run mp_test, whose even modulus checks confirm sp_exptmod_nct returns MP_VAL in this shape instead of a wrong Montgomery result.",
547547
"configure": ["--enable-cryptonly", "--enable-rsapub", "--disable-dh",
548548
"--disable-examples", "CPPFLAGS=-DWOLFSSL_PUBLIC_MP"]},
549+
{"name": "cryptonly-rsapub-public-mp", "minutes": 1.0,
550+
"comment": "RSA public only with DH at its default (on), so the generic exponentiation is compiled and sp_exptmod_nct must use it for an even modulus rather than Montgomery. WOLFSSL_PUBLIC_MP lets wolfcrypt test run mp_test's even modulus checks in this shape.",
551+
"configure": ["--enable-cryptonly", "--enable-rsapub",
552+
"--disable-examples", "CPPFLAGS=-DWOLFSSL_PUBLIC_MP"]},
549553
{"name": "pkcs12-pbkdf-mp-api", "minutes": 1.0,
550554
"comment": "WC_PKCS12_PBKDF_USING_MP_API selects a second wc_PKCS12_PBKDF_ex implementation that no configure option reaches.",
551555
"configure": ["--enable-pkcs12", "--enable-des3", "--enable-opensslextra",

‎wolfcrypt/src/sp_int.c‎

Lines changed: 10 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -14199,7 +14199,8 @@ static int _sp_exptmod_base_2(const sp_int* e, int digits, const sp_int* m,
1419914199
*
1420014200
* @return MP_OKAY on success.
1420114201
* @return MP_VAL when b, e, m or r is NULL, digits is negative, or m <= 0 or
14202-
* e is negative.
14202+
* e is negative; or m is even in an RSA verify/public only build
14203+
* without DH.
1420314204
* @return MP_MEM when dynamic memory allocation fails.
1420414205
*/
1420514206
int sp_exptmod_ex(const sp_int* b, const sp_int* e, int digits, const sp_int* m,
@@ -14830,62 +14831,6 @@ static int _sp_exptmod_nct(const sp_int* b, const sp_int* e, const sp_int* m,
1483014831
}
1483114832
#endif /* WOLFSSL_SP_FAST_NCT_EXPTMOD || !WOLFSSL_SP_SMALL */
1483214833

14833-
#if defined(WOLFSSL_RSA_VERIFY_ONLY) || defined(WOLFSSL_RSA_PUBLIC_ONLY)
14834-
/* Internal. Exponentiates b to the power of e modulo m into r: r = b ^ e mod m
14835-
* Left-to-right binary square-and-multiply, reducing by m at each step.
14836-
* Works for any modulus including even moduli, which Montgomery form does not
14837-
* support. Is NOT constant time.
14838-
*
14839-
* Assumes e is greater than zero.
14840-
*
14841-
* @param [in] b SP integer that is the base.
14842-
* @param [in] e SP integer that is the exponent.
14843-
* @param [in] m SP integer that is the modulus.
14844-
* @param [out] r SP integer to hold result.
14845-
*
14846-
* @return MP_OKAY on success.
14847-
* @return MP_MEM when dynamic memory allocation fails.
14848-
*/
14849-
static int _sp_exptmod_nct_generic(const sp_int* b, const sp_int* e,
14850-
const sp_int* m, sp_int* r)
14851-
{
14852-
int i;
14853-
int err = MP_OKAY;
14854-
int bits = sp_count_bits(e);
14855-
DECL_SP_INT_ARRAY(t, m->used * 2 + 1, 2);
14856-
14857-
/* Allocate memory for:
14858-
* - base reduced modulo m
14859-
* - temporary result (in case r is same var as another parameter). */
14860-
ALLOC_SP_INT_ARRAY(t, m->used * 2 + 1, 2, err, NULL);
14861-
if (err == MP_OKAY) {
14862-
_sp_init_size(t[0], m->used * 2 + 1);
14863-
_sp_init_size(t[1], m->used * 2 + 1);
14864-
/* t[1] = b mod m */
14865-
err = sp_mod(b, m, t[1]);
14866-
}
14867-
if (err == MP_OKAY) {
14868-
/* Result starts as base as top bit of exponent is set. */
14869-
_sp_copy(t[1], t[0]);
14870-
}
14871-
/* For each bit in exponent starting at second highest. */
14872-
for (i = bits - 2; (err == MP_OKAY) && (i >= 0); i--) {
14873-
err = sp_sqrmod(t[0], m, t[0]);
14874-
if ((err == MP_OKAY) &&
14875-
(((e->dp[i >> SP_WORD_SHIFT] >> (i & SP_WORD_MASK)) & 1) !=
14876-
0)) {
14877-
err = sp_mulmod(t[0], t[1], m, t[0]);
14878-
}
14879-
}
14880-
if (err == MP_OKAY) {
14881-
_sp_copy(t[0], r);
14882-
}
14883-
14884-
FREE_SP_INT_ARRAY(t, NULL);
14885-
return err;
14886-
}
14887-
#endif /* WOLFSSL_RSA_VERIFY_ONLY || WOLFSSL_RSA_PUBLIC_ONLY */
14888-
1488914834
/* Exponentiates b to the power of e modulo m into r: r = b ^ e mod m
1489014835
* Non-constant time implementation.
1489114836
*
@@ -14895,7 +14840,8 @@ static int _sp_exptmod_nct_generic(const sp_int* b, const sp_int* e,
1489514840
* @param [out] r SP integer to hold result.
1489614841
*
1489714842
* @return MP_OKAY on success.
14898-
* @return MP_VAL when b, e, m or r is NULL; or m <= 0 or e is negative.
14843+
* @return MP_VAL when b, e, m or r is NULL; or m <= 0 or e is negative; or
14844+
* m is even in an RSA verify/public only build without DH.
1489914845
* @return MP_MEM when dynamic memory allocation fails.
1490014846
*/
1490114847
int sp_exptmod_nct(const sp_int* b, const sp_int* e, const sp_int* m, sp_int* r)
@@ -14942,14 +14888,17 @@ int sp_exptmod_nct(const sp_int* b, const sp_int* e, const sp_int* m, sp_int* r)
1494214888
else if (m->used * 2 >= r->size) {
1494314889
err = MP_VAL;
1494414890
}
14945-
#if !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_PUBLIC_ONLY)
14891+
#if (defined(WOLFSSL_SP_MATH_ALL) && !defined(WOLFSSL_RSA_VERIFY_ONLY) && \
14892+
!defined(WOLFSSL_RSA_PUBLIC_ONLY)) || !defined(NO_DH) || \
14893+
defined(OPENSSL_ALL)
1494614894
else if (mp_iseven(m)) {
1494714895
err = _sp_exptmod_ex(b, e, (int)(e->used * SP_WORD_SIZE), m, r);
1494814896
}
1494914897
#else
14950-
/* Montgomery form requires an odd modulus. */
14898+
/* Montgomery form requires an odd modulus and the generic implementation
14899+
* is not compiled in (RSA verify/public only without DH). */
1495114900
else if (mp_iseven(m)) {
14952-
err = _sp_exptmod_nct_generic(b, e, m, r);
14901+
err = MP_VAL;
1495314902
}
1495414903
#endif
1495514904
else {

‎wolfcrypt/test/test.c‎

Lines changed: 16 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -95254,7 +95254,10 @@ static wc_test_ret_t mp_test_exptmod(mp_int* b, mp_int* e, mp_int* m, mp_int* r,
9525495254

9525595255
/* Even, multi-word modulus uses the generic exponentiation path for
9525695256
* both mp_exptmod_ex and mp_exptmod_nct. Verify b^6 mod m against
95257-
* repeated modular multiplication. */
95257+
* repeated modular multiplication. RSA public only builds without DH
95258+
* do not compile the generic path, and mp_exptmod_ex hands every modulus
95259+
* to mp_exptmod_nct, so both must reject the even modulus instead of
95260+
* returning a wrong Montgomery result. */
9525895261
if ((ret = mp_set(m, 1)) != MP_OKAY ||
9525995262
(ret = mp_mul_2d(m, 521, m)) != MP_OKAY || /* m = 2^521 (even) */
9526095263
(ret = mp_set(b, 7)) != MP_OKAY ||
@@ -95267,6 +95270,17 @@ static wc_test_ret_t mp_test_exptmod(mp_int* b, mp_int* e, mp_int* m, mp_int* r,
9526795270
return WC_TEST_RET_ENC_EC(ret);
9526895271
}
9526995272
}
95273+
#if defined(WOLFSSL_RSA_PUBLIC_ONLY) && defined(NO_DH) && \
95274+
!defined(OPENSSL_ALL)
95275+
ret = mp_exptmod_ex(b, e, (int)e->used, m, r);
95276+
if (ret != WC_NO_ERR_TRACE(MP_VAL)) {
95277+
return WC_TEST_RET_ENC_EC(ret);
95278+
}
95279+
ret = mp_exptmod_nct(b, e, m, r);
95280+
if (ret != WC_NO_ERR_TRACE(MP_VAL)) {
95281+
return WC_TEST_RET_ENC_EC(ret);
95282+
}
95283+
#else
9527095284
if ((ret = mp_exptmod_ex(b, e, (int)e->used, m, r)) != MP_OKAY) {
9527195285
return WC_TEST_RET_ENC_EC(ret);
9527295286
}
@@ -95279,84 +95293,7 @@ static wc_test_ret_t mp_test_exptmod(mp_int* b, mp_int* e, mp_int* m, mp_int* r,
9527995293
if (mp_cmp(r, t) != MP_EQ) {
9528095294
return WC_TEST_RET_ENC_NC;
9528195295
}
95282-
95283-
/* Even modulus, more varied inputs:
95284-
* k == 0: base >= m (m + 7) must give the same result as base 7.
95285-
* k == 1: exponent 2^130 + 1 spans several words for any word size.
95286-
* Reference: square the base 130 times, then multiply by it.
95287-
* k == 2: single word even modulus 10 with base 17 >= m, exponent 6. */
95288-
for (k = 0; k < 3; k++) {
95289-
int i;
95290-
int sqrs = 0;
95291-
95292-
if ((ret = mp_set(m, 1)) != MP_OKAY) {
95293-
return WC_TEST_RET_ENC_EC(ret);
95294-
}
95295-
if (k == 2) {
95296-
ret = mp_set(m, 10);
95297-
}
95298-
else {
95299-
ret = mp_mul_2d(m, 521, m); /* m = 2^521 */
95300-
}
95301-
if (ret == MP_OKAY) {
95302-
ret = mp_set(b, 7);
95303-
}
95304-
if (ret == MP_OKAY) {
95305-
ret = mp_set(t, 1);
95306-
}
95307-
if (ret != MP_OKAY) {
95308-
return WC_TEST_RET_ENC_EC(ret);
95309-
}
95310-
95311-
if (k == 1) {
95312-
/* t = b^(2^130 + 1) mod m */
95313-
sqrs = 130;
95314-
if ((ret = mp_copy(b, t)) != MP_OKAY) {
95315-
return WC_TEST_RET_ENC_EC(ret);
95316-
}
95317-
for (i = 0; i < sqrs; i++) {
95318-
if ((ret = mp_sqrmod(t, m, t)) != MP_OKAY) {
95319-
return WC_TEST_RET_ENC_EC(ret);
95320-
}
95321-
}
95322-
if ((ret = mp_mulmod(t, b, m, t)) != MP_OKAY) {
95323-
return WC_TEST_RET_ENC_EC(ret);
95324-
}
95325-
if ((ret = mp_set(e, 1)) != MP_OKAY ||
95326-
(ret = mp_mul_2d(e, sqrs, e)) != MP_OKAY ||
95327-
(ret = mp_add_d(e, 1, e)) != MP_OKAY) {
95328-
return WC_TEST_RET_ENC_EC(ret);
95329-
}
95330-
}
95331-
else {
95332-
/* t = b^6 mod m, with the reduced base. */
95333-
if ((ret = mp_set(e, 6)) != MP_OKAY) {
95334-
return WC_TEST_RET_ENC_EC(ret);
95335-
}
95336-
for (i = 0; i < 6; i++) {
95337-
if ((ret = mp_mulmod(t, b, m, t)) != MP_OKAY) {
95338-
return WC_TEST_RET_ENC_EC(ret);
95339-
}
95340-
}
95341-
/* Bring the base to m + b so it needs reducing. */
95342-
if ((ret = mp_add(b, m, b)) != MP_OKAY) {
95343-
return WC_TEST_RET_ENC_EC(ret);
95344-
}
95345-
}
95346-
95347-
if ((ret = mp_exptmod_ex(b, e, (int)e->used, m, r)) != MP_OKAY) {
95348-
return WC_TEST_RET_ENC_EC(ret);
95349-
}
95350-
if (mp_cmp(r, t) != MP_EQ) {
95351-
return WC_TEST_RET_ENC_NC;
95352-
}
95353-
if ((ret = mp_exptmod_nct(b, e, m, r)) != MP_OKAY) {
95354-
return WC_TEST_RET_ENC_EC(ret);
95355-
}
95356-
if (mp_cmp(r, t) != MP_EQ) {
95357-
return WC_TEST_RET_ENC_NC;
95358-
}
95359-
}
95296+
#endif
9536095297

9536195298
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
9536295299

0 commit comments

Comments
 (0)