diff --git a/wolfcrypt/src/port/maxim/max3266x.c b/wolfcrypt/src/port/maxim/max3266x.c index d48e1efe9ad..7d0dcaca845 100644 --- a/wolfcrypt/src/port/maxim/max3266x.c +++ b/wolfcrypt/src/port/maxim/max3266x.c @@ -2495,6 +2495,10 @@ int hw_mulmod(mp_int* multiplier, mp_int* multiplicand, mp_int* mod, return MP_VAL; } if ((multiplier->used == 0) || (multiplicand->used == 0)) { + /* A zero modulus is invalid whatever the operands are. */ + if (mod->used == 0) { + return MP_VAL; + } mp_zero(result); return 0; } @@ -2591,6 +2595,10 @@ int hw_sqrmod(mp_int* base, mp_int* mod, mp_int* result) return MP_VAL; } if (base->used == 0) { + /* A zero modulus is invalid whatever the base is. */ + if (mod->used == 0) { + return MP_VAL; + } mp_zero(result); return 0; } diff --git a/wolfcrypt/src/sp_int.c b/wolfcrypt/src/sp_int.c index 83017ae29f5..3340d0bc672 100644 --- a/wolfcrypt/src/sp_int.c +++ b/wolfcrypt/src/sp_int.c @@ -12292,6 +12292,7 @@ int sp_mul(const sp_int* a, const sp_int* b, sp_int* r) * @param [out] r SP integer result. * * @return MP_OKAY on success. + * @return MP_VAL when m is 0. * @return MP_MEM when dynamic memory allocation fails. */ static int _sp_mulmod_tmp(const sp_int* a, const sp_int* b, const sp_int* m, @@ -12300,7 +12301,15 @@ static int _sp_mulmod_tmp(const sp_int* a, const sp_int* b, const sp_int* m, int err = MP_OKAY; if (sp_iszero(a) || sp_iszero(b)) { - _sp_zero(r); + /* Only reached from sp_mulmod() when the result aliases the modulus. + * The zero-operand short-circuit would otherwise bypass the sp_mod() + * validation that the non-zero operand path relies on. */ + if (sp_iszero(m)) { + err = MP_VAL; + } + else { + _sp_zero(r); + } } else { /* Create temporary for multiplication result. */ @@ -12334,6 +12343,7 @@ static int _sp_mulmod_tmp(const sp_int* a, const sp_int* b, const sp_int* m, * @param [out] r SP integer result. * * @return MP_OKAY on success. + * @return MP_VAL when m is 0. * @return MP_MEM when dynamic memory allocation fails. */ static int _sp_mulmod(const sp_int* a, const sp_int* b, const sp_int* m, @@ -17501,6 +17511,7 @@ int sp_sqr(const sp_int* a, sp_int* r) * @param [out] r SP integer result. * * @return MP_OKAY on success. + * @return MP_VAL when m is 0. * @return MP_MEM when dynamic memory allocation fails. */ static int _sp_sqrmod(const sp_int* a, const sp_int* m, sp_int* r) @@ -17508,7 +17519,15 @@ static int _sp_sqrmod(const sp_int* a, const sp_int* m, sp_int* r) int err = MP_OKAY; if (sp_iszero(a)) { - _sp_zero(r); + /* Only reached from sp_sqrmod() when the result aliases the modulus. + * The zero-operand short-circuit would otherwise bypass the sp_mod() + * validation that the non-zero operand path relies on. */ + if (sp_iszero(m)) { + err = MP_VAL; + } + else { + _sp_zero(r); + } } else { /* Create temporary for multiplication result. */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 2953550ae90..5dcda911aa8 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -75903,6 +75903,39 @@ static wc_test_ret_t mp_test_mulmod_sqrmod(mp_int* a, mp_int* b, mp_int* m, if (!mp_iszero(m)) return WC_TEST_RET_ENC_NC; + /* A zero modulus is invalid whether or not the result aliases it. The + * zero-operand short-circuits must not hide it. */ + ret = mp_set(a, 0); + if (ret == MP_OKAY) + ret = mp_set(b, 0x5); + if (ret == MP_OKAY) + ret = mp_set(m, 0); + if (ret != MP_OKAY) + return WC_TEST_RET_ENC_EC(ret); + if (mp_sqrmod(a, m, r) != WC_NO_ERR_TRACE(MP_VAL)) + return WC_TEST_RET_ENC_NC; + if (mp_sqrmod(a, m, m) != WC_NO_ERR_TRACE(MP_VAL)) + return WC_TEST_RET_ENC_NC; + ret = mp_set(m, 0); + if (ret != MP_OKAY) + return WC_TEST_RET_ENC_EC(ret); + if (mp_mulmod(a, b, m, r) != WC_NO_ERR_TRACE(MP_VAL)) + return WC_TEST_RET_ENC_NC; + if (mp_mulmod(a, b, m, m) != WC_NO_ERR_TRACE(MP_VAL)) + return WC_TEST_RET_ENC_NC; + /* Cover the other half of the zero-operand test in _sp_mulmod_tmp. */ + ret = mp_set(a, 0x5); + if (ret == MP_OKAY) + ret = mp_set(b, 0); + if (ret == MP_OKAY) + ret = mp_set(m, 0); + if (ret != MP_OKAY) + return WC_TEST_RET_ENC_EC(ret); + if (mp_mulmod(a, b, m, r) != WC_NO_ERR_TRACE(MP_VAL)) + return WC_TEST_RET_ENC_NC; + if (mp_mulmod(a, b, m, m) != WC_NO_ERR_TRACE(MP_VAL)) + return WC_TEST_RET_ENC_NC; + return 0; }