diff --git a/wolfcrypt/src/dh.c b/wolfcrypt/src/dh.c index 3e9abe3d86..4ac4c406e3 100644 --- a/wolfcrypt/src/dh.c +++ b/wolfcrypt/src/dh.c @@ -1808,12 +1808,9 @@ int wc_DhCheckPrivKey_ex(DhKey* key, const byte* priv, word32 privSz, if (ret == 0) { if (mp_iszero(q) == MP_NO) { /* priv (x) shouldn't be greater than q - 1 */ - if (mp_copy(&key->q, q) != MP_OKAY) - ret = MP_INIT_E; - if (ret == 0) { - if (mp_sub_d(q, 1, q) != MP_OKAY) - ret = MP_SUB_E; - } + /* q already holds the supplied prime or key->q; do not clobber it */ + if (mp_sub_d(q, 1, q) != MP_OKAY) + ret = MP_SUB_E; if (ret == 0) { if (mp_cmp(x, q) == MP_GT) ret = DH_CHECK_PRIV_E; diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 49deeaf0ce..35337619d1 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -30504,6 +30504,9 @@ static wc_test_ret_t dh_check_priv_key_test(DhKey* key, const byte* priv, { wc_test_ret_t ret; word32 pSz, qSz, gSz; + byte pBuf[DH_TEST_BUF_SIZE]; + byte qBuf[DH_TEST_BUF_SIZE]; + byte gBuf[DH_TEST_BUF_SIZE]; ret = wc_DhCheckPrivKey(NULL, NULL, 0); if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) @@ -30521,6 +30524,22 @@ static wc_test_ret_t dh_check_priv_key_test(DhKey* key, const byte* priv, if (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_dh_check_priv); + /* Regression: the explicit prime argument to wc_DhCheckPrivKey_ex must be + * honored and not overwritten by key->q. This key is set with p and g + * only, so key->q is empty; supplying the modulus p as a generous bound + * must accept any valid priv (priv < p). The prior defect clobbered the + * loaded bound with the empty key->q and rejected a valid key. */ + if (pSz <= (word32)sizeof(pBuf) && qSz <= (word32)sizeof(qBuf) && + gSz <= (word32)sizeof(gBuf)) { + ret = wc_DhExportParamsRaw(key, pBuf, &pSz, qBuf, &qSz, gBuf, &gSz); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_dh_check_priv); + + ret = wc_DhCheckPrivKey_ex(key, priv, privSz, pBuf, pSz); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_dh_check_priv); + } + ret = 0; exit_dh_check_priv: