Merge pull request #10381 from kareem-wolfssl/zd21694

Validate DSA parameters when verifying DSA key.
This commit is contained in:
David Garske
2026-05-12 16:29:29 -07:00
committed by GitHub
6 changed files with 301 additions and 1 deletions
+106
View File
@@ -94,6 +94,104 @@ void wc_FreeDsaKey(DsaKey* key)
}
/* Validate DSA domain parameters and public key.
*
* Performs the following checks (subset of FIPS 186-4 / SP 800-89):
* - p > 1 and q > 1
* - q divides (p - 1) (FIPS 186-4 A.1.1.2)
* - 1 < g < p
* - 1 < y < p
* - g^q mod p == 1 (i.e. ord(g) divides q)
* - y^q mod p == 1 (i.e. ord(y) divides q)
*
* Note: this routine does not run primality tests on p or q. Full FIPS
* 186-4 domain-parameter validation additionally requires that p and q be
* prime; callers that need that level of assurance should use
* wc_DsaImportParamsRawCheck() (which exercises p) and/or run
* mp_prime_is_prime_ex() on q at import time.
*
* key - pointer to DsaKey populated with p, q, g, and y.
* return 0 on success, BAD_FUNC_ARG when the key fails validation, or a
* negative error code on internal failure.
*/
#ifndef NO_DSA_PUBKEY_CHECK
int wc_DsaCheckPubKey(DsaKey* key)
{
int err = MP_OKAY;
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
mp_int* tmp = NULL;
mp_int* tmp2 = NULL;
#else
mp_int tmp[1];
mp_int tmp2[1];
#endif
if (key == NULL)
return BAD_FUNC_ARG;
/* p and q must be at least 2 */
if (mp_cmp_d(&key->p, 1) != MP_GT || mp_cmp_d(&key->q, 1) != MP_GT)
return BAD_FUNC_ARG;
/* 1 < g < p */
if (mp_cmp_d(&key->g, 1) != MP_GT || mp_cmp(&key->g, &key->p) != MP_LT)
return BAD_FUNC_ARG;
/* 1 < y < p */
if (mp_cmp_d(&key->y, 1) != MP_GT || mp_cmp(&key->y, &key->p) != MP_LT)
return BAD_FUNC_ARG;
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
tmp = (mp_int*)XMALLOC(sizeof(*tmp), key->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (tmp == NULL)
return MEMORY_E;
tmp2 = (mp_int*)XMALLOC(sizeof(*tmp2), key->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (tmp2 == NULL) {
XFREE(tmp, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
#endif
err = mp_init_multi(tmp, tmp2, NULL, NULL, NULL, NULL);
if (err != MP_OKAY) {
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(tmp2, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(tmp, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return err;
}
/* q divides (p - 1): tmp2 = (p - 1) mod q, must be 0. */
if (err == MP_OKAY)
err = mp_sub_d(&key->p, 1, tmp);
if (err == MP_OKAY)
err = mp_mod(tmp, &key->q, tmp2);
if (err == MP_OKAY && !mp_iszero(tmp2))
err = BAD_FUNC_ARG;
/* g^q mod p == 1 */
if (err == MP_OKAY)
err = mp_exptmod(&key->g, &key->q, &key->p, tmp);
if (err == MP_OKAY && mp_cmp_d(tmp, 1) != MP_EQ)
err = BAD_FUNC_ARG;
/* y^q mod p == 1 */
if (err == MP_OKAY)
err = mp_exptmod(&key->y, &key->q, &key->p, tmp);
if (err == MP_OKAY && mp_cmp_d(tmp, 1) != MP_EQ)
err = BAD_FUNC_ARG;
mp_clear(tmp);
mp_clear(tmp2);
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(tmp2, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(tmp, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return err;
}
#endif /* !NO_DSA_PUBKEY_CHECK */
/* validate that (L,N) match allowed sizes from FIPS 186-4, Section 4.2.
* modLen - represents L, the size of p (prime modulus) in bits
* divLen - represents N, the size of q (prime divisor) in bits
@@ -1039,6 +1137,14 @@ int wc_DsaVerify_ex(const byte* digest, word32 digestSz, const byte* sig,
return BAD_LENGTH_E;
}
/* Validate domain parameters and public key before doing any
* signature math. */
#ifndef NO_DSA_PUBKEY_CHECK
ret = wc_DsaCheckPubKey(key);
if (ret != 0)
return ret;
#endif
do {
#ifdef WOLFSSL_SMALL_STACK
w = (mp_int *)XMALLOC(sizeof *w, key->heap, DYNAMIC_TYPE_TMP_BUFFER);