Skip to content

Commit 3747ded

Browse files
yosuke-wolfsslpadelsbach
authored andcommitted
Enforce DH minimum prime size on the parameters-only generation path
1 parent e24bd6c commit 3747ded

5 files changed

Lines changed: 130 additions & 19 deletions

File tree

include/wolfprovider/internal.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@
6565
/** Maximum supported digest name size. */
6666
#define WP_MAX_PROPS_SIZE 80
6767

68+
/** Minimum accepted DH prime size in bits for parameter/key generation. */
69+
#ifdef HAVE_FIPS
70+
#define WP_DH_MIN_BITS 2048
71+
#else
72+
#define WP_DH_MIN_BITS 1024
73+
#endif
74+
6875
/* DER key encoding/decoding formats. */
6976
/** SubjectPublicKeyInfo encoding format. */
7077
#define WP_ENC_FORMAT_SPKI 1

src/wp_dh_kmgmt.c

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,6 @@ static const int wp_dh_decode_nids[] = {
5151
/** Maximum size of the group name string. */
5252
#define WP_MAX_DH_GROUP_NAME_SZ 10
5353

54-
/* Min accepted bitlen for keygen */
55-
#ifdef HAVE_FIPS
56-
#define WP_DH_MIN_BITS 2048
57-
#else
58-
#define WP_DH_MIN_BITS 1024
59-
#endif
60-
6154
/**
6255
* DH key.
6356
*/
@@ -1574,18 +1567,19 @@ static wp_DhGenCtx* wp_dh_gen_init(WOLFPROV_CTX* provCtx,
15741567
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_InitRng", rc);
15751568
ok = 0;
15761569
}
1577-
if (ok) {
1578-
if (!wp_dh_gen_set_params(ctx, params)) {
1579-
wc_FreeRng(&ctx->rng);
1580-
ok = 0;
1581-
}
1582-
}
1570+
/* Defaults first so init-time parameters override them. */
15831571
if (ok) {
15841572
ctx->provCtx = provCtx;
15851573
ctx->selection = selection;
15861574
ctx->bits = 2048;
15871575
ctx->generator = 2;
15881576
}
1577+
if (ok) {
1578+
if (!wp_dh_gen_set_params(ctx, params)) {
1579+
wc_FreeRng(&ctx->rng);
1580+
ok = 0;
1581+
}
1582+
}
15891583

15901584
if (!ok) {
15911585
/* Rng freed when parameters fail to set. */
@@ -1644,13 +1638,25 @@ static int wp_dh_gen_set_template(wp_DhGenCtx* ctx, const wp_Dh* dh)
16441638
static int wp_dh_gen_set_params(wp_DhGenCtx* ctx, const OSSL_PARAM params[])
16451639
{
16461640
int ok = 1;
1641+
int bits;
16471642
const OSSL_PARAM* p;
16481643

16491644
WOLFPROV_ENTER(WP_LOG_COMP_DH, "wp_dh_gen_set_params");
16501645

16511646
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_PBITS);
1652-
if ((p != NULL) && (!OSSL_PARAM_get_int(p, &ctx->bits))) {
1653-
ok = 0;
1647+
if (p != NULL) {
1648+
if (!OSSL_PARAM_get_int(p, &bits)) {
1649+
ok = 0;
1650+
}
1651+
/* Reject a prime size below the provider minimum. */
1652+
if (ok && (bits < WP_DH_MIN_BITS)) {
1653+
ERR_raise(ERR_LIB_PROV, PROV_R_KEY_SIZE_TOO_SMALL);
1654+
ok = 0;
1655+
}
1656+
/* Only store the value once it has passed the size check. */
1657+
if (ok) {
1658+
ctx->bits = bits;
1659+
}
16541660
}
16551661
if (ok) {
16561662
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_PRIV_LEN);
@@ -1928,12 +1934,13 @@ static wp_Dh* wp_dh_gen(wp_DhGenCtx *ctx, OSSL_CALLBACK *cb, void *cbArg)
19281934
else if (!wp_dh_gen_copy_parameters(ctx, dh)) {
19291935
ok = 0;
19301936
}
1937+
/* Validate parameters meet minimum requirements in every path. */
1938+
if (ok && (!wp_dh_params_validate(dh))) {
1939+
ok = 0;
1940+
}
19311941
/* Generate key pair if requested. */
19321942
if (ok && ((ctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)) {
1933-
if (!wp_dh_params_validate(dh)) {
1934-
ok = 0;
1935-
}
1936-
if (ok && (!wp_dh_gen_keypair(ctx, dh))) {
1943+
if (!wp_dh_gen_keypair(ctx, dh)) {
19371944
ok = 0;
19381945
}
19391946
}

test/test_dh.c

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "unit.h"
2222
#include <openssl/core_names.h>
2323
#include <openssl/decoder.h>
24+
#include <wolfprovider/internal.h>
2425

2526
#ifdef WP_HAVE_DH
2627

@@ -1546,4 +1547,98 @@ int test_dh_import_group_no_nul(void *data)
15461547
return err;
15471548
}
15481549

1550+
/* Enforce the minimum prime size: a below-minimum request must not produce
1551+
* parameters, while a request at the minimum must still succeed. Sizes come
1552+
* from the provider's own WP_DH_MIN_BITS so the two cannot diverge. */
1553+
#define TEST_DH_MIN_BITS WP_DH_MIN_BITS
1554+
#define TEST_DH_WEAK_BITS (WP_DH_MIN_BITS / 2)
1555+
int test_dh_pgen_min_bits(void *data)
1556+
{
1557+
int err = 0;
1558+
int rc;
1559+
EVP_PKEY_CTX *ctx = NULL;
1560+
EVP_PKEY *keyParams = NULL;
1561+
EVP_PKEY *weakParams = NULL;
1562+
BIGNUM *prime = NULL;
1563+
1564+
(void)data;
1565+
1566+
PRINT_MSG("Testing DH parameter generation minimum prime size enforcement");
1567+
1568+
/* Below-minimum size must be rejected at set-params time. */
1569+
ctx = EVP_PKEY_CTX_new_from_name(wpLibCtx, "DH", NULL);
1570+
if (ctx == NULL) {
1571+
err = 1;
1572+
}
1573+
if (err == 0) {
1574+
err = EVP_PKEY_paramgen_init(ctx) != 1;
1575+
}
1576+
if (err == 0) {
1577+
rc = EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, TEST_DH_WEAK_BITS);
1578+
if (rc == 1) {
1579+
PRINT_MSG("set_dh_paramgen_prime_len accepted a below-minimum size");
1580+
err = 1;
1581+
}
1582+
}
1583+
EVP_PKEY_CTX_free(ctx);
1584+
ctx = NULL;
1585+
1586+
/* A caller that ignores the set-params failure must never end up with
1587+
* below-minimum parameters: generation either fails, or the prime it
1588+
* produced is at least the minimum size. */
1589+
if (err == 0) {
1590+
ctx = EVP_PKEY_CTX_new_from_name(wpLibCtx, "DH", NULL);
1591+
err = ctx == NULL;
1592+
}
1593+
if (err == 0) {
1594+
err = EVP_PKEY_paramgen_init(ctx) != 1;
1595+
}
1596+
if (err == 0) {
1597+
(void)EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, TEST_DH_WEAK_BITS);
1598+
if (EVP_PKEY_paramgen(ctx, &weakParams) == 1) {
1599+
err = EVP_PKEY_get_bn_param(weakParams, OSSL_PKEY_PARAM_FFC_P,
1600+
&prime) != 1;
1601+
if ((err == 0) && (BN_num_bits(prime) < TEST_DH_MIN_BITS)) {
1602+
PRINT_MSG("paramgen produced a prime below the minimum size");
1603+
err = 1;
1604+
}
1605+
}
1606+
}
1607+
EVP_PKEY_CTX_free(ctx);
1608+
ctx = NULL;
1609+
1610+
/* Size at the minimum must still succeed. */
1611+
if (err == 0) {
1612+
ctx = EVP_PKEY_CTX_new_from_name(wpLibCtx, "DH", NULL);
1613+
err = ctx == NULL;
1614+
}
1615+
if (err == 0) {
1616+
err = EVP_PKEY_paramgen_init(ctx) != 1;
1617+
}
1618+
if (err == 0) {
1619+
err = EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, TEST_DH_MIN_BITS)
1620+
!= 1;
1621+
}
1622+
if (err == 0) {
1623+
err = EVP_PKEY_paramgen(ctx, &keyParams) != 1;
1624+
if (err != 0) {
1625+
PRINT_MSG("DH paramgen failed at the minimum prime size");
1626+
}
1627+
}
1628+
if (err == 0) {
1629+
err = EVP_PKEY_get_bn_param(keyParams, OSSL_PKEY_PARAM_FFC_P,
1630+
&prime) != 1;
1631+
if ((err == 0) && (BN_num_bits(prime) < TEST_DH_MIN_BITS)) {
1632+
PRINT_MSG("paramgen produced a prime below the minimum size");
1633+
err = 1;
1634+
}
1635+
}
1636+
1637+
BN_free(prime);
1638+
EVP_PKEY_free(weakParams);
1639+
EVP_PKEY_free(keyParams);
1640+
EVP_PKEY_CTX_free(ctx);
1641+
return err;
1642+
}
1643+
15491644
#endif /* WP_HAVE_DH */

test/unit.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ TEST_CASE test_case[] = {
338338
TEST_DECL(test_dh_fromdata_oversize, NULL),
339339
TEST_DECL(test_dh_param_check_explicit, NULL),
340340
TEST_DECL(test_dh_import_group_no_nul, NULL),
341+
TEST_DECL(test_dh_pgen_min_bits, NULL),
341342
#ifndef WOLFPROV_QUICKTEST
342343
TEST_DECL(test_dh_get_params, NULL),
343344
#endif

test/unit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ int test_dh_x963_kdf(void *data);
361361
int test_dh_fromdata_oversize(void *data);
362362
int test_dh_param_check_explicit(void *data);
363363
int test_dh_import_group_no_nul(void *data);
364+
int test_dh_pgen_min_bits(void *data);
364365
#endif /* WP_HAVE_DH */
365366

366367
#ifdef WP_HAVE_ECC

0 commit comments

Comments
 (0)