Browse Source

EVP_PKEY & DH: Make DH EVP_PKEY_CTX parameter ctrls / setters more available

EVP_PKEY_CTX_set_dh_ functions were only available when DH was enabled
('no-dsa' not configured).  However, that makes it impossible to use
these functions with an engine or a provider that happens to implement
DH.  This change solves that problem by shuffling these functions to
more appropriate places.

By consequence, there are a number of places where we can remove the
check of OPENSSL_NO_DH.  This requires some re-arrangements of
internal tables to translate between numeric identities and names.

Partially fixes #13550

Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/13589)
Richard Levitte 3 years ago
parent
commit
c829c23b67

+ 1 - 1
crypto/dh/build.info

@@ -5,7 +5,7 @@ $COMMON=dh_lib.c dh_key.c dh_group_params.c dh_check.c dh_backend.c dh_gen.c \
 
 SOURCE[../../libcrypto]=$COMMON\
         dh_asn1.c dh_err.c \
-        dh_ameth.c dh_pmeth.c dh_prn.c dh_rfc5114.c dh_meth.c dh_ctrl.c
+        dh_ameth.c dh_pmeth.c dh_prn.c dh_rfc5114.c dh_meth.c
 IF[{- !$disabled{'deprecated-0.9.8'} -}]
   SOURCE[../../libcrypto]=dh_depr.c
 ENDIF

+ 19 - 143
crypto/dh/dh_group_params.c

@@ -21,160 +21,43 @@
 #include "dh_local.h"
 #include <openssl/bn.h>
 #include <openssl/objects.h>
-#include "crypto/bn_dh.h"
+#include "internal/nelem.h"
 #include "crypto/dh.h"
 #include "e_os.h" /* strcasecmp */
 
-#define FFDHE(sz) {                                                            \
-    SN_ffdhe##sz, NID_ffdhe##sz,                                               \
-    sz,                                                                        \
-    &_bignum_ffdhe##sz##_p, &_bignum_ffdhe##sz##_q, &_bignum_const_2           \
-}
-
-#define MODP(sz)  {                                                            \
-    SN_modp_##sz, NID_modp_##sz,                                               \
-    sz,                                                                        \
-    &_bignum_modp_##sz##_p, &_bignum_modp_##sz##_q,  &_bignum_const_2          \
-}
-
-#define RFC5114(name, uid, sz, tag)  {                                         \
-    name, uid,                                                                 \
-    sz,                                                                        \
-    &_bignum_dh##tag##_p, &_bignum_dh##tag##_q, &_bignum_dh##tag##_g           \
-}
-
-typedef struct dh_named_group_st {
-    const char *name;
-    int uid;
-    int32_t nbits;
-    const BIGNUM *p;
-    const BIGNUM *q;
-    const BIGNUM *g;
-} DH_NAMED_GROUP;
-
-
-static const DH_NAMED_GROUP dh_named_groups[] = {
-    FFDHE(2048),
-    FFDHE(3072),
-    FFDHE(4096),
-    FFDHE(6144),
-    FFDHE(8192),
-#ifndef FIPS_MODULE
-    MODP(1536),
-#endif
-    MODP(2048),
-    MODP(3072),
-    MODP(4096),
-    MODP(6144),
-    MODP(8192),
-    /*
-     * Additional dh named groups from RFC 5114 that have a different g.
-     * The uid can be any unique identifier.
-     */
-#ifndef FIPS_MODULE
-    RFC5114("dh_1024_160", 1, 1024, 1024_160),
-    RFC5114("dh_2048_224", 2, 2048, 2048_224),
-    RFC5114("dh_2048_256", 3, 2048, 2048_256),
-#endif
-};
-
-int ossl_ffc_named_group_to_uid(const char *name)
-{
-    size_t i;
-
-    for (i = 0; i < OSSL_NELEM(dh_named_groups); ++i) {
-        if (strcasecmp(dh_named_groups[i].name, name) == 0)
-            return dh_named_groups[i].uid;
-    }
-    return NID_undef;
-}
-
-const char *ossl_ffc_named_group_from_uid(int uid)
-{
-    size_t i;
-
-    for (i = 0; i < OSSL_NELEM(dh_named_groups); ++i) {
-        if (dh_named_groups[i].uid == uid)
-            return dh_named_groups[i].name;
-    }
-    return NULL;
-}
-
-static DH *dh_param_init(OSSL_LIB_CTX *libctx, int uid, const BIGNUM *p,
-                         const BIGNUM *q, const BIGNUM *g)
+static DH *dh_param_init(OSSL_LIB_CTX *libctx, const DH_NAMED_GROUP *group)
 {
     DH *dh = dh_new_ex(libctx);
 
     if (dh == NULL)
         return NULL;
 
-    dh->params.nid = uid;
-    dh->params.p = (BIGNUM *)p;
-    dh->params.q = (BIGNUM *)q;
-    dh->params.g = (BIGNUM *)g;
-    dh->length = BN_num_bits(q);
+    ossl_ffc_named_group_set_pqg(&dh->params, group);
+    dh->params.nid = ossl_ffc_named_group_get_uid(group);
+    dh->length = BN_num_bits(dh->params.q);
     dh->dirty_cnt++;
     return dh;
 }
 
-static DH *dh_new_by_group_name(OSSL_LIB_CTX *libctx, const char *name)
+DH *dh_new_by_nid_ex(OSSL_LIB_CTX *libctx, int nid)
 {
-    int i;
+    const DH_NAMED_GROUP *group;
 
-    if (name == NULL)
-        return NULL;
+    if ((group = ossl_ffc_uid_to_dh_named_group(nid)) != NULL)
+        return dh_param_init(libctx, group);
 
-    for (i = 0; i < (int)OSSL_NELEM(dh_named_groups); ++i) {
-        if (strcasecmp(dh_named_groups[i].name, name) == 0) {
-            return dh_param_init(libctx, dh_named_groups[i].uid,
-                                 dh_named_groups[i].p,
-                                 dh_named_groups[i].q,
-                                 dh_named_groups[i].g);
-        }
-    }
     ERR_raise(ERR_LIB_DH, DH_R_INVALID_PARAMETER_NID);
     return NULL;
 }
 
-DH *dh_new_by_nid_ex(OSSL_LIB_CTX *libctx, int nid)
-{
-    const char *name = ossl_ffc_named_group_from_uid(nid);
-
-    return dh_new_by_group_name(libctx, name);
-}
-
 DH *DH_new_by_nid(int nid)
 {
     return dh_new_by_nid_ex(NULL, nid);
 }
 
-int ossl_ffc_set_group_pqg(FFC_PARAMS *ffc, const char *group_name)
-{
-    int i;
-    BIGNUM *q = NULL;
-
-    if (ffc == NULL)
-        return 0;
-
-    for (i = 0; i < (int)OSSL_NELEM(dh_named_groups); ++i) {
-        if (strcasecmp(dh_named_groups[i].name, group_name) == 0) {
-            ossl_ffc_params_set0_pqg(ffc,
-                                     (BIGNUM *)dh_named_groups[i].p,
-                                     (BIGNUM *)dh_named_groups[i].q,
-                                     (BIGNUM *)dh_named_groups[i].g);
-            /* flush the cached nid, The DH layer is responsible for caching */
-            ffc->nid = NID_undef;
-            return 1;
-        }
-    }
-    /* gets here on error or if the name was not found */
-    BN_free(q);
-    return 0;
-}
-
 void dh_cache_named_group(DH *dh)
 {
-    int i;
+    const DH_NAMED_GROUP *group;
 
     if (dh == NULL)
         return;
@@ -186,22 +69,15 @@ void dh_cache_named_group(DH *dh)
         || dh->params.g == NULL)
         return;
 
-    for (i = 0; i < (int)OSSL_NELEM(dh_named_groups); ++i) {
-        /* Keep searching until a matching p and g is found */
-        if (BN_cmp(dh->params.p, dh_named_groups[i].p) == 0
-            && BN_cmp(dh->params.g, dh_named_groups[i].g) == 0) {
-                /* Verify q is correct if it exists */
-                if (dh->params.q != NULL) {
-                    if (BN_cmp(dh->params.q, dh_named_groups[i].q) != 0)
-                        continue;  /* ignore if q does not match */
-                } else {
-                    dh->params.q = (BIGNUM *)dh_named_groups[i].q;
-                }
-                dh->params.nid = dh_named_groups[i].uid; /* cache the nid */
-                dh->length = BN_num_bits(dh->params.q);
-                dh->dirty_cnt++;
-                break;
-        }
+    if ((group = ossl_ffc_numbers_to_dh_named_group(dh->params.p,
+                                                    dh->params.q,
+                                                    dh->params.g)) != NULL) {
+        if (dh->params.q == NULL)
+            dh->params.q = (BIGNUM *)ossl_ffc_named_group_get_q(group);
+        /* cache the nid */
+        dh->params.nid = ossl_ffc_named_group_get_uid(group);
+        dh->length = BN_num_bits(dh->params.q);
+        dh->dirty_cnt++;
     }
 }
 

+ 2 - 2
crypto/evp/build.info

@@ -2,7 +2,7 @@ LIBS=../../libcrypto
 $COMMON=digest.c evp_enc.c evp_lib.c evp_fetch.c cmeth_lib.c evp_utils.c \
         mac_lib.c mac_meth.c keymgmt_meth.c keymgmt_lib.c kdf_lib.c kdf_meth.c \
         m_sigver.c pmeth_lib.c signature.c p_lib.c pmeth_gn.c exchange.c \
-        pmeth_check.c evp_rand.c asymcipher.c kem.c
+        pmeth_check.c evp_rand.c asymcipher.c kem.c dh_support.c
 
 SOURCE[../../libcrypto]=$COMMON\
         encode.c evp_key.c evp_cnf.c \
@@ -19,7 +19,7 @@ SOURCE[../../libcrypto]=$COMMON\
 
 # Diverse type specific ctrl functions.  They are kinda sorta legacy, kinda
 # sorta not.
-SOURCE[../../libcrypto]=dsa_ctrl.c
+SOURCE[../../libcrypto]=dh_ctrl.c dsa_ctrl.c
 
 IF[{- !$disabled{'deprecated-3.0'} -}]
   SOURCE[../../libcrypto]=p_enc.c p_dec.c

+ 30 - 16
crypto/dh/dh_ctrl.c → crypto/evp/dh_ctrl.c

@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -7,22 +7,14 @@
  * https://www.openssl.org/source/license.html
  */
 
-/*
- * DH low level APIs are deprecated for public use, but still ok for
- * internal use.
- */
-#include "internal/deprecated.h"
-
 #include <stdio.h>
-#include "crypto/evp.h"
-#include <openssl/bn.h>
-#include <openssl/engine.h>
-#include <openssl/obj_mac.h>
+#include <string.h>
 #include <openssl/core_names.h>
-#include "internal/cryptlib.h"
-#include "internal/refcount.h"
+#include <openssl/params.h>
+#include <openssl/err.h>
+#include <openssl/dh.h>
 #include "crypto/dh.h"
-#include "dh_local.h"
+#include "crypto/evp.h"
 
 static int dh_paramgen_check(EVP_PKEY_CTX *ctx)
 {
@@ -179,7 +171,7 @@ int EVP_PKEY_CTX_set_dh_rfc5114(EVP_PKEY_CTX *ctx, int gen)
     if (ctx->op.keymgmt.genctx == NULL)
         return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_PARAMGEN,
                                  EVP_PKEY_CTRL_DH_RFC5114, gen, NULL);
-    name = ossl_ffc_named_group_from_uid(gen);
+    name = ossl_ffc_named_group_get_name(ossl_ffc_uid_to_dh_named_group(gen));
     if (name == NULL)
         return 0;
 
@@ -208,7 +200,7 @@ int EVP_PKEY_CTX_set_dh_nid(EVP_PKEY_CTX *ctx, int nid)
         return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH,
                                  EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN,
                                  EVP_PKEY_CTRL_DH_NID, nid, NULL);
-    name = ossl_ffc_named_group_from_uid(nid);
+    name = ossl_ffc_named_group_get_name(ossl_ffc_uid_to_dh_named_group(nid));
     if (name == NULL)
         return 0;
 
@@ -218,6 +210,28 @@ int EVP_PKEY_CTX_set_dh_nid(EVP_PKEY_CTX *ctx, int nid)
     return EVP_PKEY_CTX_set_params(ctx, params);
 }
 
+int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad)
+{
+    OSSL_PARAM dh_pad_params[2];
+    unsigned int upad = pad;
+
+    /* We use EVP_PKEY_CTX_ctrl return values */
+    if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        return -2;
+    }
+
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if (ctx->op.kex.exchprovctx == NULL)
+        return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_DERIVE,
+                                 EVP_PKEY_CTRL_DH_PAD, pad, NULL);
+
+    dh_pad_params[0] = OSSL_PARAM_construct_uint(OSSL_EXCHANGE_PARAM_PAD, &upad);
+    dh_pad_params[1] = OSSL_PARAM_construct_end();
+
+    return EVP_PKEY_CTX_set_params(ctx, dh_pad_params);
+}
+
 int EVP_PKEY_CTX_set_dh_kdf_type(EVP_PKEY_CTX *ctx, int kdf)
 {
     int ret;

+ 48 - 0
crypto/evp/dh_support.c

@@ -0,0 +1,48 @@
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h> /* strcmp */
+#include <openssl/dh.h>
+#include "internal/nelem.h"
+#include "crypto/dh.h"
+
+typedef struct dh_name2id_st{
+    const char *name;
+    int id;
+} DH_GENTYPE_NAME2ID;
+
+static const DH_GENTYPE_NAME2ID dhtype2id[]=
+{
+    { "fips186_4", DH_PARAMGEN_TYPE_FIPS_186_4 },
+    { "fips186_2", DH_PARAMGEN_TYPE_FIPS_186_2 },
+    { "group", DH_PARAMGEN_TYPE_GROUP },
+    { "generator", DH_PARAMGEN_TYPE_GENERATOR }
+};
+
+const char *dh_gen_type_id2name(int id)
+{
+    size_t i;
+
+    for (i = 0; i < OSSL_NELEM(dhtype2id); ++i) {
+        if (dhtype2id[i].id == id)
+            return dhtype2id[i].name;
+    }
+    return NULL;
+}
+
+int dh_gen_type_name2id(const char *name)
+{
+    size_t i;
+
+    for (i = 0; i < OSSL_NELEM(dhtype2id); ++i) {
+        if (strcmp(dhtype2id[i].name, name) == 0)
+            return dhtype2id[i].id;
+    }
+    return -1;
+}

+ 6 - 2
crypto/evp/p_lib.c

@@ -1241,8 +1241,12 @@ int EVP_PKEY_get_group_name(const EVP_PKEY *pkey, char *gname, size_t gname_sz,
                 DH *dh = EVP_PKEY_get0_DH(pkey);
                 int uid = DH_get_nid(dh);
 
-                if (uid != NID_undef)
-                    name = ossl_ffc_named_group_from_uid(uid);
+                if (uid != NID_undef) {
+                    const DH_NAMED_GROUP *dh_group =
+                        ossl_ffc_uid_to_dh_named_group(uid);
+
+                    name = ossl_ffc_named_group_get_name(dh_group);
+                }
             }
             break;
 #endif

+ 4 - 29
crypto/evp/pmeth_lib.c

@@ -834,30 +834,6 @@ int evp_pkey_ctx_get_params_strict(EVP_PKEY_CTX *ctx, OSSL_PARAM *params)
     return EVP_PKEY_CTX_get_params(ctx, params);
 }
 
-# ifndef OPENSSL_NO_DH
-int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad)
-{
-    OSSL_PARAM dh_pad_params[2];
-    unsigned int upad = pad;
-
-    /* We use EVP_PKEY_CTX_ctrl return values */
-    if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
-        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
-        return -2;
-    }
-
-    /* TODO(3.0): Remove this eventually when no more legacy */
-    if (ctx->op.kex.exchprovctx == NULL)
-        return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_DERIVE,
-                                 EVP_PKEY_CTRL_DH_PAD, pad, NULL);
-
-    dh_pad_params[0] = OSSL_PARAM_construct_uint(OSSL_EXCHANGE_PARAM_PAD, &upad);
-    dh_pad_params[1] = OSSL_PARAM_construct_end();
-
-    return EVP_PKEY_CTX_set_params(ctx, dh_pad_params);
-}
-# endif
-
 int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **md)
 {
     OSSL_PARAM sig_md_params[2], *p = sig_md_params;
@@ -1252,7 +1228,6 @@ static int legacy_ctrl_to_param(EVP_PKEY_CTX *ctx, int keytype, int optype,
         return evp_pkey_ctx_get1_id_len_prov(ctx, p2);
     }
 
-# ifndef OPENSSL_NO_DH
     if (keytype == EVP_PKEY_DHX) {
         switch (cmd) {
         case EVP_PKEY_CTRL_DH_KDF_TYPE:
@@ -1291,7 +1266,6 @@ static int legacy_ctrl_to_param(EVP_PKEY_CTX *ctx, int keytype, int optype,
                 return EVP_PKEY_CTX_set_dh_rfc5114(ctx, p1);
         }
     }
-# endif
 # ifndef OPENSSL_NO_DSA
     if (keytype == EVP_PKEY_DSA) {
         switch (cmd) {
@@ -1579,7 +1553,6 @@ static int legacy_ctrl_str_to_param(EVP_PKEY_CTX *ctx, const char *name,
     else if (strcmp(name, "dsa_paramgen_md") == 0)
         name = OSSL_PKEY_PARAM_FFC_DIGEST;
 # endif
-# ifndef OPENSSL_NO_DH
     else if (strcmp(name, "dh_paramgen_generator") == 0)
         name = OSSL_PKEY_PARAM_DH_GENERATOR;
     else if (strcmp(name, "dh_paramgen_prime_len") == 0)
@@ -1592,11 +1565,13 @@ static int legacy_ctrl_str_to_param(EVP_PKEY_CTX *ctx, const char *name,
     } else if (strcmp(name, "dh_param") == 0)
         name = OSSL_PKEY_PARAM_GROUP_NAME;
     else if (strcmp(name, "dh_rfc5114") == 0) {
+        int num = atoi(value);
+
         name = OSSL_PKEY_PARAM_GROUP_NAME;
-        value = ossl_ffc_named_group_from_uid(atoi(value));
+        value =
+            ossl_ffc_named_group_get_name(ossl_ffc_uid_to_dh_named_group(num));
     } else if (strcmp(name, "dh_pad") == 0)
         name = OSSL_EXCHANGE_PARAM_PAD;
-# endif
 # ifndef OPENSSL_NO_EC
     else if (strcmp(name, "ec_paramgen_curve") == 0)
         name = OSSL_PKEY_PARAM_GROUP_NAME;

+ 3 - 2
crypto/ffc/build.info

@@ -1,7 +1,8 @@
 LIBS=../../libcrypto
 
-$COMMON=ffc_params.c ffc_params_generate.c ffc_key_generate.c\
-        ffc_params_validate.c ffc_key_validate.c ffc_backend.c
+$COMMON=ffc_params.c ffc_params_generate.c ffc_key_generate.c \
+        ffc_params_validate.c ffc_key_validate.c ffc_backend.c \
+        ffc_dh.c
 
 SOURCE[../../libcrypto]=$COMMON
 SOURCE[../../providers/libfips.a]=$COMMON

+ 6 - 4
crypto/ffc/ffc_backend.c

@@ -29,14 +29,16 @@ int ossl_ffc_params_fromdata(FFC_PARAMS *ffc, const OSSL_PARAM params[])
 
     prm  = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME);
     if (prm != NULL) {
-        if (prm->data_type != OSSL_PARAM_UTF8_STRING)
-            goto err;
-#ifndef OPENSSL_NO_DH
         /*
          * In a no-dh build we just go straight to err because we have no
          * support for this.
          */
-        if (!ossl_ffc_set_group_pqg(ffc, prm->data))
+#ifndef OPENSSL_NO_DH
+        const DH_NAMED_GROUP *group = NULL;
+
+        if (prm->data_type != OSSL_PARAM_UTF8_STRING
+            || (group = ossl_ffc_name_to_dh_named_group(prm->data)) == NULL
+            || !ossl_ffc_named_group_set_pqg(ffc, group))
 #endif
             goto err;
     }

+ 154 - 0
crypto/ffc/ffc_dh.c

@@ -0,0 +1,154 @@
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "internal/ffc.h"
+#include "internal/nelem.h"
+#include "crypto/bn_dh.h"
+#include "e_os.h" /* strcasecmp */
+
+#ifndef OPENSSL_NO_DH
+
+# define FFDHE(sz) {                                                        \
+        SN_ffdhe##sz, NID_ffdhe##sz,                                        \
+        sz,                                                                 \
+        &_bignum_ffdhe##sz##_p, &_bignum_ffdhe##sz##_q, &_bignum_const_2,   \
+    }
+
+# define MODP(sz)  {                                                        \
+        SN_modp_##sz, NID_modp_##sz,                                        \
+        sz,                                                                 \
+        &_bignum_modp_##sz##_p, &_bignum_modp_##sz##_q,  &_bignum_const_2   \
+    }
+
+# define RFC5114(name, uid, sz, tag) {                                      \
+        name, uid,                                                          \
+        sz,                                                                 \
+        &_bignum_dh##tag##_p, &_bignum_dh##tag##_q, &_bignum_dh##tag##_g    \
+    }
+
+#else
+
+# define FFDHE(sz)                      { SN_ffdhe##sz, NID_ffdhe##sz }
+# define MODP(sz)                       { SN_modp_##sz, NID_modp_##sz }
+# define RFC5114(name, uid, sz, tag)    { name, uid }
+
+#endif
+
+struct dh_named_group_st {
+    const char *name;
+    int uid;
+#ifndef OPENSSL_NO_DH
+    int32_t nbits;
+    const BIGNUM *p;
+    const BIGNUM *q;
+    const BIGNUM *g;
+#endif
+};
+
+static const DH_NAMED_GROUP dh_named_groups[] = {
+    FFDHE(2048),
+    FFDHE(3072),
+    FFDHE(4096),
+    FFDHE(6144),
+    FFDHE(8192),
+#ifndef FIPS_MODULE
+    MODP(1536),
+#endif
+    MODP(2048),
+    MODP(3072),
+    MODP(4096),
+    MODP(6144),
+    MODP(8192),
+    /*
+     * Additional dh named groups from RFC 5114 that have a different g.
+     * The uid can be any unique identifier.
+     */
+#ifndef FIPS_MODULE
+    RFC5114("dh_1024_160", 1, 1024, 1024_160),
+    RFC5114("dh_2048_224", 2, 2048, 2048_224),
+    RFC5114("dh_2048_256", 3, 2048, 2048_256),
+#endif
+};
+
+const DH_NAMED_GROUP *ossl_ffc_name_to_dh_named_group(const char *name)
+{
+    size_t i;
+
+    for (i = 0; i < OSSL_NELEM(dh_named_groups); ++i) {
+        if (strcasecmp(dh_named_groups[i].name, name) == 0)
+            return &dh_named_groups[i];
+    }
+    return NULL;
+}
+
+const DH_NAMED_GROUP *ossl_ffc_uid_to_dh_named_group(int uid)
+{
+    size_t i;
+
+    for (i = 0; i < OSSL_NELEM(dh_named_groups); ++i) {
+        if (dh_named_groups[i].uid == uid)
+            return &dh_named_groups[i];
+    }
+    return NULL;
+}
+
+#ifndef OPENSSL_NO_DH
+const DH_NAMED_GROUP *ossl_ffc_numbers_to_dh_named_group(const BIGNUM *p,
+                                                         const BIGNUM *q,
+                                                         const BIGNUM *g)
+{
+    size_t i;
+
+    for (i = 0; i < OSSL_NELEM(dh_named_groups); ++i) {
+        /* Keep searching until a matching p and g is found */
+        if (BN_cmp(p, dh_named_groups[i].p) == 0
+            && BN_cmp(g, dh_named_groups[i].g) == 0
+            /* Verify q is correct if it exists */
+            && (q == NULL || BN_cmp(q, dh_named_groups[i].q) == 0))
+            return &dh_named_groups[i];
+    }
+    return NULL;
+}
+#endif
+
+int ossl_ffc_named_group_get_uid(const DH_NAMED_GROUP *group)
+{
+    if (group == NULL)
+        return NID_undef;
+    return group->uid;
+}
+
+const char *ossl_ffc_named_group_get_name(const DH_NAMED_GROUP *group)
+{
+    if (group == NULL)
+        return NULL;
+    return group->name;
+}
+
+#ifndef OPENSSL_NO_DH
+const BIGNUM *ossl_ffc_named_group_get_q(const DH_NAMED_GROUP *group)
+{
+    if (group == NULL)
+        return NULL;
+    return group->q;
+}
+
+int ossl_ffc_named_group_set_pqg(FFC_PARAMS *ffc, const DH_NAMED_GROUP *group)
+{
+    if (ffc == NULL || group == NULL)
+        return 0;
+
+    ossl_ffc_params_set0_pqg(ffc, (BIGNUM *)group->p, (BIGNUM *)group->q,
+                             (BIGNUM *)group->g);
+
+    /* flush the cached nid, The DH layer is responsible for caching */
+    ffc->nid = NID_undef;
+    return 1;
+}
+#endif

+ 2 - 6
crypto/ffc/ffc_params.c

@@ -269,18 +269,14 @@ int ossl_ffc_params_todata(const FFC_PARAMS *ffc, OSSL_PARAM_BLD *bld,
                                               ffc->seed, ffc->seedlen))
         return 0;
     if (ffc->nid != NID_undef) {
-#ifndef OPENSSL_NO_DH
-        const char *name = ossl_ffc_named_group_from_uid(ffc->nid);
+        const DH_NAMED_GROUP *group = ossl_ffc_uid_to_dh_named_group(ffc->nid);
+        const char *name = ossl_ffc_named_group_get_name(group);
 
         if (name == NULL
             || !ossl_param_build_set_utf8_string(bld, params,
                                                  OSSL_PKEY_PARAM_GROUP_NAME,
                                                  name))
             return 0;
-#else
-        /* How could this be? We should not have a nid in a no-dh build. */
-        return 0;
-#endif
     }
     if (!ossl_param_build_set_utf8_string(bld, params,
                                           OSSL_PKEY_PARAM_FFC_VALIDATE_TYPE,

+ 1 - 0
include/crypto/dh.h

@@ -21,6 +21,7 @@ int dh_generate_public_key(BN_CTX *ctx, const DH *dh, const BIGNUM *priv_key,
                            BIGNUM *pub_key);
 int dh_get_named_group_uid_from_size(int pbits);
 const char *dh_gen_type_id2name(int id);
+int dh_gen_type_name2id(const char *name);
 void dh_cache_named_group(DH *dh);
 
 FFC_PARAMS *dh_get0_params(DH *dh);

+ 16 - 4
include/internal/ffc.h

@@ -188,10 +188,22 @@ int ossl_ffc_validate_private_key(const BIGNUM *upper, const BIGNUM *priv_key,
 int ossl_ffc_params_todata(const FFC_PARAMS *ffc, OSSL_PARAM_BLD *tmpl,
                            OSSL_PARAM params[]);
 int ossl_ffc_params_fromdata(FFC_PARAMS *ffc, const OSSL_PARAM params[]);
-int ossl_ffc_set_group_pqg(FFC_PARAMS *ffc, const char *group_name);
-int ossl_ffc_named_group_to_uid(const char *name);
-const char *ossl_ffc_named_group_from_uid(int nid);
-int ossl_ffc_set_group_pqg(FFC_PARAMS *ffc, const char *group_name);
+
+typedef struct dh_named_group_st DH_NAMED_GROUP;
+const DH_NAMED_GROUP *ossl_ffc_name_to_dh_named_group(const char *name);
+const DH_NAMED_GROUP *ossl_ffc_uid_to_dh_named_group(int uid);
+#ifndef OPENSSL_NO_DH
+const DH_NAMED_GROUP *ossl_ffc_numbers_to_dh_named_group(const BIGNUM *p,
+                                                         const BIGNUM *q,
+                                                         const BIGNUM *g);
+#endif
+int ossl_ffc_named_group_get_uid(const DH_NAMED_GROUP *group);
+const char *ossl_ffc_named_group_get_name(const DH_NAMED_GROUP *);
+#ifndef OPENSSL_NO_DH
+const BIGNUM *ossl_ffc_named_group_get_q(const DH_NAMED_GROUP *group);
+int ossl_ffc_named_group_set_pqg(FFC_PARAMS *ffc, const DH_NAMED_GROUP *group);
+#endif
+
 const char *ossl_ffc_params_flags_to_name(int flags);
 int ossl_ffc_params_flags_from_name(const char *name);
 

+ 60 - 58
include/openssl/dh.h

@@ -17,21 +17,74 @@
 # endif
 
 # include <openssl/opensslconf.h>
+# include <openssl/types.h>
+
+# ifdef  __cplusplus
+extern "C" {
+# endif
+
+#include <stdlib.h>
+
+/* DH parameter generation types used by EVP_PKEY_CTX_set_dh_paramgen_type() */
+# define DH_PARAMGEN_TYPE_GENERATOR     0   /* Use a safe prime generator */
+# define DH_PARAMGEN_TYPE_FIPS_186_2    1   /* Use FIPS186-2 standard */
+# define DH_PARAMGEN_TYPE_FIPS_186_4    2   /* Use FIPS186-4 standard */
+# define DH_PARAMGEN_TYPE_GROUP         3   /* Use a named safe prime group */
+
+int EVP_PKEY_CTX_set_dh_paramgen_type(EVP_PKEY_CTX *ctx, int typ);
+int EVP_PKEY_CTX_set_dh_paramgen_gindex(EVP_PKEY_CTX *ctx, int gindex);
+int EVP_PKEY_CTX_set_dh_paramgen_seed(EVP_PKEY_CTX *ctx,
+                                      const unsigned char *seed,
+                                      size_t seedlen);
+int EVP_PKEY_CTX_set_dh_paramgen_prime_len(EVP_PKEY_CTX *ctx, int pbits);
+int EVP_PKEY_CTX_set_dh_paramgen_subprime_len(EVP_PKEY_CTX *ctx, int qlen);
+int EVP_PKEY_CTX_set_dh_paramgen_generator(EVP_PKEY_CTX *ctx, int gen);
+int EVP_PKEY_CTX_set_dh_nid(EVP_PKEY_CTX *ctx, int nid);
+int EVP_PKEY_CTX_set_dh_rfc5114(EVP_PKEY_CTX *ctx, int gen);
+int EVP_PKEY_CTX_set_dhx_rfc5114(EVP_PKEY_CTX *ctx, int gen);
+int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad);
+
+int EVP_PKEY_CTX_set_dh_kdf_type(EVP_PKEY_CTX *ctx, int kdf);
+int EVP_PKEY_CTX_get_dh_kdf_type(EVP_PKEY_CTX *ctx);
+int EVP_PKEY_CTX_set0_dh_kdf_oid(EVP_PKEY_CTX *ctx, ASN1_OBJECT *oid);
+int EVP_PKEY_CTX_get0_dh_kdf_oid(EVP_PKEY_CTX *ctx, ASN1_OBJECT **oid);
+int EVP_PKEY_CTX_set_dh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
+int EVP_PKEY_CTX_get_dh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD **md);
+int EVP_PKEY_CTX_set_dh_kdf_outlen(EVP_PKEY_CTX *ctx, int len);
+int EVP_PKEY_CTX_get_dh_kdf_outlen(EVP_PKEY_CTX *ctx, int *len);
+int EVP_PKEY_CTX_set0_dh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char *ukm, int len);
+int EVP_PKEY_CTX_get0_dh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char **ukm);
+
+# define EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN     (EVP_PKEY_ALG_CTRL + 1)
+# define EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR     (EVP_PKEY_ALG_CTRL + 2)
+# define EVP_PKEY_CTRL_DH_RFC5114                (EVP_PKEY_ALG_CTRL + 3)
+# define EVP_PKEY_CTRL_DH_PARAMGEN_SUBPRIME_LEN  (EVP_PKEY_ALG_CTRL + 4)
+# define EVP_PKEY_CTRL_DH_PARAMGEN_TYPE          (EVP_PKEY_ALG_CTRL + 5)
+# define EVP_PKEY_CTRL_DH_KDF_TYPE               (EVP_PKEY_ALG_CTRL + 6)
+# define EVP_PKEY_CTRL_DH_KDF_MD                 (EVP_PKEY_ALG_CTRL + 7)
+# define EVP_PKEY_CTRL_GET_DH_KDF_MD             (EVP_PKEY_ALG_CTRL + 8)
+# define EVP_PKEY_CTRL_DH_KDF_OUTLEN             (EVP_PKEY_ALG_CTRL + 9)
+# define EVP_PKEY_CTRL_GET_DH_KDF_OUTLEN         (EVP_PKEY_ALG_CTRL + 10)
+# define EVP_PKEY_CTRL_DH_KDF_UKM                (EVP_PKEY_ALG_CTRL + 11)
+# define EVP_PKEY_CTRL_GET_DH_KDF_UKM            (EVP_PKEY_ALG_CTRL + 12)
+# define EVP_PKEY_CTRL_DH_KDF_OID                (EVP_PKEY_ALG_CTRL + 13)
+# define EVP_PKEY_CTRL_GET_DH_KDF_OID            (EVP_PKEY_ALG_CTRL + 14)
+# define EVP_PKEY_CTRL_DH_NID                    (EVP_PKEY_ALG_CTRL + 15)
+# define EVP_PKEY_CTRL_DH_PAD                    (EVP_PKEY_ALG_CTRL + 16)
+
+/* KDF types */
+# define EVP_PKEY_DH_KDF_NONE                            1
+# define EVP_PKEY_DH_KDF_X9_42                           2
 
 # ifndef OPENSSL_NO_DH
 #  include <openssl/e_os2.h>
 #  include <openssl/bio.h>
 #  include <openssl/asn1.h>
-#  include <openssl/types.h>
 #  ifndef OPENSSL_NO_DEPRECATED_1_1_0
 #   include <openssl/bn.h>
 #  endif
 #  include <openssl/dherr.h>
 
-#  ifdef  __cplusplus
-extern "C" {
-#  endif
-
 #  ifndef OPENSSL_DH_MAX_MODULUS_BITS
 #   define OPENSSL_DH_MAX_MODULUS_BITS    10000
 #  endif
@@ -107,12 +160,6 @@ DECLARE_ASN1_ITEM(DHparams)
  */
 #   define DH_CHECK_P_NOT_STRONG_PRIME     DH_CHECK_P_NOT_SAFE_PRIME
 
-/* DH parameter generation types used by EVP_PKEY_CTX_set_dh_paramgen_type() */
-#   define DH_PARAMGEN_TYPE_GENERATOR    0   /* Use a safe prime generator */
-#   define DH_PARAMGEN_TYPE_FIPS_186_2   1   /* Use FIPS186-2 standard */
-#   define DH_PARAMGEN_TYPE_FIPS_186_4   2   /* Use FIPS186-4 standard */
-#   define DH_PARAMGEN_TYPE_GROUP        3   /* Use a named safe prime group */
-
 #   define d2i_DHparams_fp(fp, x) \
         (DH *)ASN1_d2i_fp((char *(*)())DH_new, \
                           (char *(*)())d2i_DHparams, \
@@ -271,53 +318,8 @@ OSSL_DEPRECATEDIN_0_9_8 DH *DH_generate_parameters(int prime_len, int generator,
                                                    void *cb_arg);
 #  endif
 
-int EVP_PKEY_CTX_set_dh_paramgen_type(EVP_PKEY_CTX *ctx, int typ);
-int EVP_PKEY_CTX_set_dh_paramgen_gindex(EVP_PKEY_CTX *ctx, int gindex);
-int EVP_PKEY_CTX_set_dh_paramgen_seed(EVP_PKEY_CTX *ctx,
-                                      const unsigned char *seed,
-                                      size_t seedlen);
-int EVP_PKEY_CTX_set_dh_paramgen_prime_len(EVP_PKEY_CTX *ctx, int pbits);
-int EVP_PKEY_CTX_set_dh_paramgen_subprime_len(EVP_PKEY_CTX *ctx, int qlen);
-int EVP_PKEY_CTX_set_dh_paramgen_generator(EVP_PKEY_CTX *ctx, int gen);
-int EVP_PKEY_CTX_set_dh_nid(EVP_PKEY_CTX *ctx, int nid);
-int EVP_PKEY_CTX_set_dh_rfc5114(EVP_PKEY_CTX *ctx, int gen);
-int EVP_PKEY_CTX_set_dhx_rfc5114(EVP_PKEY_CTX *ctx, int gen);
-int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad);
-
-int EVP_PKEY_CTX_set_dh_kdf_type(EVP_PKEY_CTX *ctx, int kdf);
-int EVP_PKEY_CTX_get_dh_kdf_type(EVP_PKEY_CTX *ctx);
-int EVP_PKEY_CTX_set0_dh_kdf_oid(EVP_PKEY_CTX *ctx, ASN1_OBJECT *oid);
-int EVP_PKEY_CTX_get0_dh_kdf_oid(EVP_PKEY_CTX *ctx, ASN1_OBJECT **oid);
-int EVP_PKEY_CTX_set_dh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
-int EVP_PKEY_CTX_get_dh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD **md);
-int EVP_PKEY_CTX_set_dh_kdf_outlen(EVP_PKEY_CTX *ctx, int len);
-int EVP_PKEY_CTX_get_dh_kdf_outlen(EVP_PKEY_CTX *ctx, int *len);
-int EVP_PKEY_CTX_set0_dh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char *ukm, int len);
-int EVP_PKEY_CTX_get0_dh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char **ukm);
-
-#  define EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN     (EVP_PKEY_ALG_CTRL + 1)
-#  define EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR     (EVP_PKEY_ALG_CTRL + 2)
-#  define EVP_PKEY_CTRL_DH_RFC5114                (EVP_PKEY_ALG_CTRL + 3)
-#  define EVP_PKEY_CTRL_DH_PARAMGEN_SUBPRIME_LEN  (EVP_PKEY_ALG_CTRL + 4)
-#  define EVP_PKEY_CTRL_DH_PARAMGEN_TYPE          (EVP_PKEY_ALG_CTRL + 5)
-#  define EVP_PKEY_CTRL_DH_KDF_TYPE               (EVP_PKEY_ALG_CTRL + 6)
-#  define EVP_PKEY_CTRL_DH_KDF_MD                 (EVP_PKEY_ALG_CTRL + 7)
-#  define EVP_PKEY_CTRL_GET_DH_KDF_MD             (EVP_PKEY_ALG_CTRL + 8)
-#  define EVP_PKEY_CTRL_DH_KDF_OUTLEN             (EVP_PKEY_ALG_CTRL + 9)
-#  define EVP_PKEY_CTRL_GET_DH_KDF_OUTLEN         (EVP_PKEY_ALG_CTRL + 10)
-#  define EVP_PKEY_CTRL_DH_KDF_UKM                (EVP_PKEY_ALG_CTRL + 11)
-#  define EVP_PKEY_CTRL_GET_DH_KDF_UKM            (EVP_PKEY_ALG_CTRL + 12)
-#  define EVP_PKEY_CTRL_DH_KDF_OID                (EVP_PKEY_ALG_CTRL + 13)
-#  define EVP_PKEY_CTRL_GET_DH_KDF_OID            (EVP_PKEY_ALG_CTRL + 14)
-#  define EVP_PKEY_CTRL_DH_NID                    (EVP_PKEY_ALG_CTRL + 15)
-#  define EVP_PKEY_CTRL_DH_PAD                    (EVP_PKEY_ALG_CTRL + 16)
-
-/* KDF types */
-#  define EVP_PKEY_DH_KDF_NONE                            1
-#  define EVP_PKEY_DH_KDF_X9_42                           2
-
-#  ifdef  __cplusplus
+# endif
+# ifdef  __cplusplus
 }
-#  endif
 # endif
 #endif

+ 2 - 1
providers/implementations/encode_decode/encode_key2text.c

@@ -159,7 +159,8 @@ static int ffc_params_to_text(BIO *out, const FFC_PARAMS *ffc)
 {
     if (ffc->nid != NID_undef) {
 #ifndef OPENSSL_NO_DH
-        const char *name = ossl_ffc_named_group_from_uid(ffc->nid);
+        const DH_NAMED_GROUP *group = ossl_ffc_uid_to_dh_named_group(ffc->nid);
+        const char *name = ossl_ffc_named_group_get_name(group);
 
         if (name == NULL)
             goto err;

+ 10 - 36
providers/implementations/keymgmt/dh_kmgmt.c

@@ -23,7 +23,6 @@
 #include "prov/provider_ctx.h"
 #include "crypto/dh.h"
 #include "internal/sizes.h"
-#include "internal/nelem.h"
 
 static OSSL_FUNC_keymgmt_new_fn dh_newdata;
 static OSSL_FUNC_keymgmt_free_fn dh_freedata;
@@ -76,34 +75,8 @@ struct dh_gen_ctx {
     int dh_type;
 };
 
-typedef struct dh_name2id_st{
-    const char *name;
-    int id;
-} DH_GENTYPE_NAME2ID;
-
-static const DH_GENTYPE_NAME2ID dhtype2id[]=
-{
-    { "fips186_4", DH_PARAMGEN_TYPE_FIPS_186_4 },
-    { "fips186_2", DH_PARAMGEN_TYPE_FIPS_186_2 },
-    { "group", DH_PARAMGEN_TYPE_GROUP },
-    { "generator", DH_PARAMGEN_TYPE_GENERATOR }
-};
-
-const char *dh_gen_type_id2name(int id)
+static int dh_gen_type_name2id_w_default(const char *name, int type)
 {
-    size_t i;
-
-    for (i = 0; i < OSSL_NELEM(dhtype2id); ++i) {
-        if (dhtype2id[i].id == id)
-            return dhtype2id[i].name;
-    }
-    return NULL;
-}
-
-static int dh_gen_type_name2id(const char *name, int type)
-{
-    size_t i;
-
     if (strcmp(name, "default") == 0) {
 #ifdef FIPS_MODULE
         if (type == DH_FLAG_TYPE_DHX)
@@ -118,11 +91,7 @@ static int dh_gen_type_name2id(const char *name, int type)
 #endif
     }
 
-    for (i = 0; i < OSSL_NELEM(dhtype2id); ++i) {
-        if (strcmp(dhtype2id[i].name, name) == 0)
-            return dhtype2id[i].id;
-    }
-    return -1;
+    return dh_gen_type_name2id(name);
 }
 
 static void *dh_newdata(void *provctx)
@@ -506,16 +475,21 @@ static int dh_gen_set_params(void *genctx, const OSSL_PARAM params[])
     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_TYPE);
     if (p != NULL) {
         if (p->data_type != OSSL_PARAM_UTF8_STRING
-            || ((gctx->gen_type = dh_gen_type_name2id(p->data,
-                                                      gctx->dh_type)) == -1)) {
+            || ((gctx->gen_type =
+                 dh_gen_type_name2id_w_default(p->data,
+                                               gctx->dh_type)) == -1)) {
             ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);
             return 0;
         }
     }
     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME);
     if (p != NULL) {
+        const DH_NAMED_GROUP *group = NULL;
+
         if (p->data_type != OSSL_PARAM_UTF8_STRING
-           || ((gctx->group_nid = ossl_ffc_named_group_to_uid(p->data)) == NID_undef)) {
+            || (group = ossl_ffc_name_to_dh_named_group(p->data)) == NULL
+            || ((gctx->group_nid =
+                 ossl_ffc_named_group_get_uid(group)) == NID_undef)) {
             ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);
             return 0;
         }