/* Provenance: openssl/openssl DH_check (fixed). * repo: openssl/openssl * commit: 9002fd07327a91f35ba6c1307e71fa6fd4409b7f * parent: e648db50d9a63f71cab5cb78424c2932d019a744 * commit_url: https://github.com/openssl/openssl/commit/9002fd07327a91f35ba6c1307e71fa6fd4409b7f * cve: CVE-2023-3817 * license: Apache-2.0 * function: DH_check * relpath: crypto/dh/dh_check.c */ int DH_check(const DH *dh, int *ret) { #ifdef FIPS_MODULE return DH_check_params(dh, ret); #else int ok = 0, r, q_good = 0; BN_CTX *ctx = NULL; BIGNUM *t1 = NULL, *t2 = NULL; int nid = DH_get_nid((DH *)dh); *ret = 0; if (nid != NID_undef) return 1; /* Don't do any checks at all with an excessively large modulus */ if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) { ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); *ret = DH_MODULUS_TOO_LARGE | DH_CHECK_P_NOT_PRIME; return 0; } if (!DH_check_params(dh, ret)) return 0; ctx = BN_CTX_new_ex(dh->libctx); if (ctx == NULL) goto err; BN_CTX_start(ctx); t1 = BN_CTX_get(ctx); t2 = BN_CTX_get(ctx); if (t2 == NULL) goto err; if (dh->params.q != NULL) { if (BN_ucmp(dh->params.p, dh->params.q) > 0) q_good = 1; else *ret |= DH_CHECK_INVALID_Q_VALUE; } if (q_good) { if (BN_cmp(dh->params.g, BN_value_one()) <= 0) *ret |= DH_NOT_SUITABLE_GENERATOR; else if (BN_cmp(dh->params.g, dh->params.p) >= 0) *ret |= DH_NOT_SUITABLE_GENERATOR; else { /* Check g^q == 1 mod p */ if (!BN_mod_exp(t1, dh->params.g, dh->params.q, dh->params.p, ctx)) goto err; if (!BN_is_one(t1)) *ret |= DH_NOT_SUITABLE_GENERATOR; } r = BN_check_prime(dh->params.q, ctx, NULL); if (r < 0) goto err; if (!r) *ret |= DH_CHECK_Q_NOT_PRIME; /* Check p == 1 mod q i.e. q divides p - 1 */ if (!BN_div(t1, t2, dh->params.p, dh->params.q, ctx)) goto err; if (!BN_is_one(t2)) *ret |= DH_CHECK_INVALID_Q_VALUE; if (dh->params.j != NULL && BN_cmp(dh->params.j, t1)) *ret |= DH_CHECK_INVALID_J_VALUE; } r = BN_check_prime(dh->params.p, ctx, NULL); if (r < 0) goto err; if (!r) *ret |= DH_CHECK_P_NOT_PRIME; else if (dh->params.q == NULL) { if (!BN_rshift1(t1, dh->params.p)) goto err; r = BN_check_prime(t1, ctx, NULL); if (r < 0) goto err; if (!r) *ret |= DH_CHECK_P_NOT_SAFE_PRIME; } ok = 1; err: BN_CTX_end(ctx); BN_CTX_free(ctx); return ok; #endif /* FIPS_MODULE */ }