xref: /freebsd/crypto/openssl/providers/implementations/keymgmt/dh_kmgmt.c (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 /*
2  * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 /*
11  * DH low level APIs are deprecated for public use, but still ok for
12  * internal use.
13  */
14 #include "internal/deprecated.h"
15 
16 #include <string.h> /* strcmp */
17 #include <openssl/core_dispatch.h>
18 #include <openssl/core_names.h>
19 #include <openssl/bn.h>
20 #include <openssl/err.h>
21 #include "prov/implementations.h"
22 #include "prov/providercommon.h"
23 #include "prov/provider_ctx.h"
24 #include "crypto/dh.h"
25 #include "internal/sizes.h"
26 
27 static OSSL_FUNC_keymgmt_new_fn dh_newdata;
28 static OSSL_FUNC_keymgmt_free_fn dh_freedata;
29 static OSSL_FUNC_keymgmt_gen_init_fn dh_gen_init;
30 static OSSL_FUNC_keymgmt_gen_init_fn dhx_gen_init;
31 static OSSL_FUNC_keymgmt_gen_set_template_fn dh_gen_set_template;
32 static OSSL_FUNC_keymgmt_gen_set_params_fn dh_gen_set_params;
33 static OSSL_FUNC_keymgmt_gen_settable_params_fn dh_gen_settable_params;
34 static OSSL_FUNC_keymgmt_gen_fn dh_gen;
35 static OSSL_FUNC_keymgmt_gen_cleanup_fn dh_gen_cleanup;
36 static OSSL_FUNC_keymgmt_load_fn dh_load;
37 static OSSL_FUNC_keymgmt_get_params_fn dh_get_params;
38 static OSSL_FUNC_keymgmt_gettable_params_fn dh_gettable_params;
39 static OSSL_FUNC_keymgmt_set_params_fn dh_set_params;
40 static OSSL_FUNC_keymgmt_settable_params_fn dh_settable_params;
41 static OSSL_FUNC_keymgmt_has_fn dh_has;
42 static OSSL_FUNC_keymgmt_match_fn dh_match;
43 static OSSL_FUNC_keymgmt_validate_fn dh_validate;
44 static OSSL_FUNC_keymgmt_import_fn dh_import;
45 static OSSL_FUNC_keymgmt_import_types_fn dh_import_types;
46 static OSSL_FUNC_keymgmt_export_fn dh_export;
47 static OSSL_FUNC_keymgmt_export_types_fn dh_export_types;
48 static OSSL_FUNC_keymgmt_dup_fn dh_dup;
49 
50 #define DH_POSSIBLE_SELECTIONS                                                 \
51     (OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)
52 
53 struct dh_gen_ctx {
54     OSSL_LIB_CTX *libctx;
55 
56     FFC_PARAMS *ffc_params;
57     int selection;
58     /* All these parameters are used for parameter generation only */
59     /* If there is a group name then the remaining parameters are not needed */
60     int group_nid;
61     size_t pbits;
62     size_t qbits;
63     unsigned char *seed; /* optional FIPS186-4 param for testing */
64     size_t seedlen;
65     int gindex; /* optional  FIPS186-4 generator index (ignored if -1) */
66     int gen_type; /* see dhtype2id */
67     int generator; /* Used by DH_PARAMGEN_TYPE_GENERATOR in non fips mode only */
68     int pcounter;
69     int hindex;
70     int priv_len;
71 
72     char *mdname;
73     char *mdprops;
74     OSSL_CALLBACK *cb;
75     void *cbarg;
76     int dh_type;
77 };
78 
79 static int dh_gen_type_name2id_w_default(const char *name, int type)
80 {
81     if (strcmp(name, "default") == 0) {
82 #ifdef FIPS_MODULE
83         if (type == DH_FLAG_TYPE_DHX)
84             return DH_PARAMGEN_TYPE_FIPS_186_4;
85 
86         return DH_PARAMGEN_TYPE_GROUP;
87 #else
88         if (type == DH_FLAG_TYPE_DHX)
89             return DH_PARAMGEN_TYPE_FIPS_186_2;
90 
91         return DH_PARAMGEN_TYPE_GENERATOR;
92 #endif
93     }
94 
95     return ossl_dh_gen_type_name2id(name, type);
96 }
97 
98 static void *dh_newdata(void *provctx)
99 {
100     DH *dh = NULL;
101 
102     if (ossl_prov_is_running()) {
103         dh = ossl_dh_new_ex(PROV_LIBCTX_OF(provctx));
104         if (dh != NULL) {
105             DH_clear_flags(dh, DH_FLAG_TYPE_MASK);
106             DH_set_flags(dh, DH_FLAG_TYPE_DH);
107         }
108     }
109     return dh;
110 }
111 
112 static void *dhx_newdata(void *provctx)
113 {
114     DH *dh = NULL;
115 
116     dh = ossl_dh_new_ex(PROV_LIBCTX_OF(provctx));
117     if (dh != NULL) {
118         DH_clear_flags(dh, DH_FLAG_TYPE_MASK);
119         DH_set_flags(dh, DH_FLAG_TYPE_DHX);
120     }
121     return dh;
122 }
123 
124 static void dh_freedata(void *keydata)
125 {
126     DH_free(keydata);
127 }
128 
129 static int dh_has(const void *keydata, int selection)
130 {
131     const DH *dh = keydata;
132     int ok = 1;
133 
134     if (!ossl_prov_is_running() || dh == NULL)
135         return 0;
136     if ((selection & DH_POSSIBLE_SELECTIONS) == 0)
137         return 1; /* the selection is not missing */
138 
139     if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
140         ok = ok && (DH_get0_pub_key(dh) != NULL);
141     if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
142         ok = ok && (DH_get0_priv_key(dh) != NULL);
143     if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
144         ok = ok && (DH_get0_p(dh) != NULL && DH_get0_g(dh) != NULL);
145     return ok;
146 }
147 
148 static int dh_match(const void *keydata1, const void *keydata2, int selection)
149 {
150     const DH *dh1 = keydata1;
151     const DH *dh2 = keydata2;
152     int ok = 1;
153 
154     if (!ossl_prov_is_running())
155         return 0;
156 
157     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
158         int key_checked = 0;
159 
160         if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
161             const BIGNUM *pa = DH_get0_pub_key(dh1);
162             const BIGNUM *pb = DH_get0_pub_key(dh2);
163 
164             if (pa != NULL && pb != NULL) {
165                 ok = ok && BN_cmp(pa, pb) == 0;
166                 key_checked = 1;
167             }
168         }
169         if (!key_checked
170             && (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
171             const BIGNUM *pa = DH_get0_priv_key(dh1);
172             const BIGNUM *pb = DH_get0_priv_key(dh2);
173 
174             if (pa != NULL && pb != NULL) {
175                 ok = ok && BN_cmp(pa, pb) == 0;
176                 key_checked = 1;
177             }
178         }
179         ok = ok && key_checked;
180     }
181     if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) {
182         FFC_PARAMS *dhparams1 = ossl_dh_get0_params((DH *)dh1);
183         FFC_PARAMS *dhparams2 = ossl_dh_get0_params((DH *)dh2);
184 
185         ok = ok && ossl_ffc_params_cmp(dhparams1, dhparams2, 1);
186     }
187     return ok;
188 }
189 
190 static int dh_import(void *keydata, int selection, const OSSL_PARAM params[])
191 {
192     DH *dh = keydata;
193     int ok = 1;
194 
195     if (!ossl_prov_is_running() || dh == NULL)
196         return 0;
197 
198     if ((selection & DH_POSSIBLE_SELECTIONS) == 0)
199         return 0;
200 
201     /* a key without parameters is meaningless */
202     ok = ok && ossl_dh_params_fromdata(dh, params);
203 
204     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
205         int include_private =
206             selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0;
207 
208         ok = ok && ossl_dh_key_fromdata(dh, params, include_private);
209     }
210 
211     return ok;
212 }
213 
214 static int dh_export(void *keydata, int selection, OSSL_CALLBACK *param_cb,
215                      void *cbarg)
216 {
217     DH *dh = keydata;
218     OSSL_PARAM_BLD *tmpl = NULL;
219     OSSL_PARAM *params = NULL;
220     int ok = 1;
221 
222     if (!ossl_prov_is_running() || dh == NULL)
223         return 0;
224 
225     if ((selection & DH_POSSIBLE_SELECTIONS) == 0)
226         return 0;
227 
228     tmpl = OSSL_PARAM_BLD_new();
229     if (tmpl == NULL)
230         return 0;
231 
232     if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0)
233         ok = ok && ossl_dh_params_todata(dh, tmpl, NULL);
234 
235     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
236         int include_private =
237             selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0;
238 
239         ok = ok && ossl_dh_key_todata(dh, tmpl, NULL, include_private);
240     }
241 
242     if (!ok || (params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL) {
243         ok = 0;
244         goto err;
245     }
246 
247     ok = param_cb(params, cbarg);
248     OSSL_PARAM_free(params);
249 err:
250     OSSL_PARAM_BLD_free(tmpl);
251     return ok;
252 }
253 
254 /* IMEXPORT = IMPORT + EXPORT */
255 
256 # define DH_IMEXPORTABLE_PARAMETERS                                            \
257     OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_P, NULL, 0),                             \
258     OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_Q, NULL, 0),                             \
259     OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_G, NULL, 0),                             \
260     OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_COFACTOR, NULL, 0),                      \
261     OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_GINDEX, NULL),                          \
262     OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_PCOUNTER, NULL),                        \
263     OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_H, NULL),                               \
264     OSSL_PARAM_int(OSSL_PKEY_PARAM_DH_PRIV_LEN, NULL),                         \
265     OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_FFC_SEED, NULL, 0),                \
266     OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0)
267 # define DH_IMEXPORTABLE_PUBLIC_KEY                                            \
268     OSSL_PARAM_BN(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0)
269 # define DH_IMEXPORTABLE_PRIVATE_KEY                                           \
270     OSSL_PARAM_BN(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0)
271 static const OSSL_PARAM dh_all_types[] = {
272     DH_IMEXPORTABLE_PARAMETERS,
273     DH_IMEXPORTABLE_PUBLIC_KEY,
274     DH_IMEXPORTABLE_PRIVATE_KEY,
275     OSSL_PARAM_END
276 };
277 static const OSSL_PARAM dh_parameter_types[] = {
278     DH_IMEXPORTABLE_PARAMETERS,
279     OSSL_PARAM_END
280 };
281 static const OSSL_PARAM dh_key_types[] = {
282     DH_IMEXPORTABLE_PUBLIC_KEY,
283     DH_IMEXPORTABLE_PRIVATE_KEY,
284     OSSL_PARAM_END
285 };
286 static const OSSL_PARAM *dh_types[] = {
287     NULL,                        /* Index 0 = none of them */
288     dh_parameter_types,          /* Index 1 = parameter types */
289     dh_key_types,                /* Index 2 = key types */
290     dh_all_types                 /* Index 3 = 1 + 2 */
291 };
292 
293 static const OSSL_PARAM *dh_imexport_types(int selection)
294 {
295     int type_select = 0;
296 
297     if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0)
298         type_select += 1;
299     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
300         type_select += 2;
301     return dh_types[type_select];
302 }
303 
304 static const OSSL_PARAM *dh_import_types(int selection)
305 {
306     return dh_imexport_types(selection);
307 }
308 
309 static const OSSL_PARAM *dh_export_types(int selection)
310 {
311     return dh_imexport_types(selection);
312 }
313 
314 static ossl_inline int dh_get_params(void *key, OSSL_PARAM params[])
315 {
316     DH *dh = key;
317     OSSL_PARAM *p;
318 
319     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL
320         && !OSSL_PARAM_set_int(p, DH_bits(dh)))
321         return 0;
322     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS)) != NULL
323         && !OSSL_PARAM_set_int(p, DH_security_bits(dh)))
324         return 0;
325     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL
326         && !OSSL_PARAM_set_int(p, DH_size(dh)))
327         return 0;
328     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY)) != NULL) {
329         if (p->data_type != OSSL_PARAM_OCTET_STRING)
330             return 0;
331         p->return_size = ossl_dh_key2buf(dh, (unsigned char **)&p->data,
332                                          p->data_size, 0);
333         if (p->return_size == 0)
334             return 0;
335     }
336 
337     return ossl_dh_params_todata(dh, NULL, params)
338         && ossl_dh_key_todata(dh, NULL, params, 1);
339 }
340 
341 static const OSSL_PARAM dh_params[] = {
342     OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
343     OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
344     OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
345     OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0),
346     DH_IMEXPORTABLE_PARAMETERS,
347     DH_IMEXPORTABLE_PUBLIC_KEY,
348     DH_IMEXPORTABLE_PRIVATE_KEY,
349     OSSL_PARAM_END
350 };
351 
352 static const OSSL_PARAM *dh_gettable_params(void *provctx)
353 {
354     return dh_params;
355 }
356 
357 static const OSSL_PARAM dh_known_settable_params[] = {
358     OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0),
359     OSSL_PARAM_END
360 };
361 
362 static const OSSL_PARAM *dh_settable_params(void *provctx)
363 {
364     return dh_known_settable_params;
365 }
366 
367 static int dh_set_params(void *key, const OSSL_PARAM params[])
368 {
369     DH *dh = key;
370     const OSSL_PARAM *p;
371 
372     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY);
373     if (p != NULL
374             && (p->data_type != OSSL_PARAM_OCTET_STRING
375                 || !ossl_dh_buf2key(dh, p->data, p->data_size)))
376         return 0;
377 
378     return 1;
379 }
380 
381 static int dh_validate_public(const DH *dh, int checktype)
382 {
383     const BIGNUM *pub_key = NULL;
384     int res = 0;
385 
386     DH_get0_key(dh, &pub_key, NULL);
387     if (pub_key == NULL)
388         return 0;
389 
390     /* The partial test is only valid for named group's with q = (p - 1) / 2 */
391     if (checktype == OSSL_KEYMGMT_VALIDATE_QUICK_CHECK
392         && ossl_dh_is_named_safe_prime_group(dh))
393         return ossl_dh_check_pub_key_partial(dh, pub_key, &res);
394 
395     return DH_check_pub_key_ex(dh, pub_key);
396 }
397 
398 static int dh_validate_private(const DH *dh)
399 {
400     int status = 0;
401     const BIGNUM *priv_key = NULL;
402 
403     DH_get0_key(dh, NULL, &priv_key);
404     if (priv_key == NULL)
405         return 0;
406     return ossl_dh_check_priv_key(dh, priv_key, &status);;
407 }
408 
409 static int dh_validate(const void *keydata, int selection, int checktype)
410 {
411     const DH *dh = keydata;
412     int ok = 1;
413 
414     if (!ossl_prov_is_running())
415         return 0;
416 
417     if ((selection & DH_POSSIBLE_SELECTIONS) == 0)
418         return 1; /* nothing to validate */
419 
420     if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) {
421         /*
422          * Both of these functions check parameters. DH_check_params_ex()
423          * performs a lightweight check (e.g. it does not check that p is a
424          * safe prime)
425          */
426         if (checktype == OSSL_KEYMGMT_VALIDATE_QUICK_CHECK)
427             ok = ok && DH_check_params_ex(dh);
428         else
429             ok = ok && DH_check_ex(dh);
430     }
431 
432     if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
433         ok = ok && dh_validate_public(dh, checktype);
434 
435     if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
436         ok = ok && dh_validate_private(dh);
437 
438     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR)
439             == OSSL_KEYMGMT_SELECT_KEYPAIR)
440         ok = ok && ossl_dh_check_pairwise(dh);
441     return ok;
442 }
443 
444 static void *dh_gen_init_base(void *provctx, int selection,
445                               const OSSL_PARAM params[], int type)
446 {
447     OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx);
448     struct dh_gen_ctx *gctx = NULL;
449 
450     if (!ossl_prov_is_running())
451         return NULL;
452 
453     if ((selection & (OSSL_KEYMGMT_SELECT_KEYPAIR
454                       | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)) == 0)
455         return NULL;
456 
457     if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) {
458         gctx->selection = selection;
459         gctx->libctx = libctx;
460         gctx->pbits = 2048;
461         gctx->qbits = 224;
462         gctx->mdname = NULL;
463 #ifdef FIPS_MODULE
464         gctx->gen_type = (type == DH_FLAG_TYPE_DHX)
465                          ? DH_PARAMGEN_TYPE_FIPS_186_4
466                          : DH_PARAMGEN_TYPE_GROUP;
467 #else
468         gctx->gen_type = (type == DH_FLAG_TYPE_DHX)
469                          ? DH_PARAMGEN_TYPE_FIPS_186_2
470                          : DH_PARAMGEN_TYPE_GENERATOR;
471 #endif
472         gctx->gindex = -1;
473         gctx->hindex = 0;
474         gctx->pcounter = -1;
475         gctx->generator = DH_GENERATOR_2;
476         gctx->dh_type = type;
477     }
478     if (!dh_gen_set_params(gctx, params)) {
479         OPENSSL_free(gctx);
480         gctx = NULL;
481     }
482     return gctx;
483 }
484 
485 static void *dh_gen_init(void *provctx, int selection,
486                          const OSSL_PARAM params[])
487 {
488     return dh_gen_init_base(provctx, selection, params, DH_FLAG_TYPE_DH);
489 }
490 
491 static void *dhx_gen_init(void *provctx, int selection,
492                           const OSSL_PARAM params[])
493 {
494    return dh_gen_init_base(provctx, selection, params, DH_FLAG_TYPE_DHX);
495 }
496 
497 static int dh_gen_set_template(void *genctx, void *templ)
498 {
499     struct dh_gen_ctx *gctx = genctx;
500     DH *dh = templ;
501 
502     if (!ossl_prov_is_running() || gctx == NULL || dh == NULL)
503         return 0;
504     gctx->ffc_params = ossl_dh_get0_params(dh);
505     return 1;
506 }
507 
508 static int dh_set_gen_seed(struct dh_gen_ctx *gctx, unsigned char *seed,
509                            size_t seedlen)
510 {
511     OPENSSL_clear_free(gctx->seed, gctx->seedlen);
512     gctx->seed = NULL;
513     gctx->seedlen = 0;
514     if (seed != NULL && seedlen > 0) {
515         gctx->seed = OPENSSL_memdup(seed, seedlen);
516         if (gctx->seed == NULL)
517             return 0;
518         gctx->seedlen = seedlen;
519     }
520     return 1;
521 }
522 
523 static int dh_gen_common_set_params(void *genctx, const OSSL_PARAM params[])
524 {
525     struct dh_gen_ctx *gctx = genctx;
526     const OSSL_PARAM *p;
527 
528     if (gctx == NULL)
529         return 0;
530     if (params == NULL)
531         return 1;
532 
533     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_TYPE);
534     if (p != NULL) {
535         if (p->data_type != OSSL_PARAM_UTF8_STRING
536             || ((gctx->gen_type =
537                  dh_gen_type_name2id_w_default(p->data, gctx->dh_type)) == -1)) {
538             ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);
539             return 0;
540         }
541     }
542     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME);
543     if (p != NULL) {
544         const DH_NAMED_GROUP *group = NULL;
545 
546         if (p->data_type != OSSL_PARAM_UTF8_STRING
547             || p->data == NULL
548             || (group = ossl_ffc_name_to_dh_named_group(p->data)) == NULL
549             || ((gctx->group_nid =
550                  ossl_ffc_named_group_get_uid(group)) == NID_undef)) {
551             ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);
552             return 0;
553         }
554     }
555     if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_PBITS)) != NULL
556         && !OSSL_PARAM_get_size_t(p, &gctx->pbits))
557         return 0;
558     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_PRIV_LEN);
559     if (p != NULL && !OSSL_PARAM_get_int(p, &gctx->priv_len))
560         return 0;
561     return 1;
562 }
563 
564 static const OSSL_PARAM *dh_gen_settable_params(ossl_unused void *genctx,
565                                                 ossl_unused void *provctx)
566 {
567     static const OSSL_PARAM dh_gen_settable[] = {
568         OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_TYPE, NULL, 0),
569         OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0),
570         OSSL_PARAM_int(OSSL_PKEY_PARAM_DH_PRIV_LEN, NULL),
571         OSSL_PARAM_size_t(OSSL_PKEY_PARAM_FFC_PBITS, NULL),
572         OSSL_PARAM_int(OSSL_PKEY_PARAM_DH_GENERATOR, NULL),
573         OSSL_PARAM_END
574     };
575     return dh_gen_settable;
576 }
577 
578 static const OSSL_PARAM *dhx_gen_settable_params(ossl_unused void *genctx,
579                                                  ossl_unused void *provctx)
580 {
581     static const OSSL_PARAM dhx_gen_settable[] = {
582         OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_TYPE, NULL, 0),
583         OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0),
584         OSSL_PARAM_int(OSSL_PKEY_PARAM_DH_PRIV_LEN, NULL),
585         OSSL_PARAM_size_t(OSSL_PKEY_PARAM_FFC_PBITS, NULL),
586         OSSL_PARAM_size_t(OSSL_PKEY_PARAM_FFC_QBITS, NULL),
587         OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_DIGEST, NULL, 0),
588         OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_DIGEST_PROPS, NULL, 0),
589         OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_GINDEX, NULL),
590         OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_FFC_SEED, NULL, 0),
591         OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_PCOUNTER, NULL),
592         OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_H, NULL),
593         OSSL_PARAM_END
594     };
595     return dhx_gen_settable;
596 }
597 
598 static int dhx_gen_set_params(void *genctx, const OSSL_PARAM params[])
599 {
600     struct dh_gen_ctx *gctx = genctx;
601     const OSSL_PARAM *p;
602 
603     if (!dh_gen_common_set_params(genctx, params))
604         return 0;
605 
606     /* Parameters related to fips186-4 and fips186-2 */
607     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_GINDEX);
608     if (p != NULL && !OSSL_PARAM_get_int(p, &gctx->gindex))
609         return 0;
610     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_PCOUNTER);
611     if (p != NULL && !OSSL_PARAM_get_int(p, &gctx->pcounter))
612         return 0;
613     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_H);
614     if (p != NULL && !OSSL_PARAM_get_int(p, &gctx->hindex))
615         return 0;
616     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_SEED);
617     if (p != NULL
618         && (p->data_type != OSSL_PARAM_OCTET_STRING
619             || !dh_set_gen_seed(gctx, p->data, p->data_size)))
620             return 0;
621     if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_QBITS)) != NULL
622         && !OSSL_PARAM_get_size_t(p, &gctx->qbits))
623         return 0;
624     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_DIGEST);
625     if (p != NULL) {
626         if (p->data_type != OSSL_PARAM_UTF8_STRING)
627             return 0;
628         OPENSSL_free(gctx->mdname);
629         gctx->mdname = OPENSSL_strdup(p->data);
630         if (gctx->mdname == NULL)
631             return 0;
632     }
633     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_DIGEST_PROPS);
634     if (p != NULL) {
635         if (p->data_type != OSSL_PARAM_UTF8_STRING)
636             return 0;
637         OPENSSL_free(gctx->mdprops);
638         gctx->mdprops = OPENSSL_strdup(p->data);
639         if (gctx->mdprops == NULL)
640             return 0;
641     }
642 
643     /* Parameters that are not allowed for DHX */
644     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_GENERATOR);
645     if (p != NULL) {
646         ERR_raise(ERR_LIB_PROV, ERR_R_UNSUPPORTED);
647         return 0;
648     }
649     return 1;
650 }
651 
652 static int dh_gen_set_params(void *genctx, const OSSL_PARAM params[])
653 {
654     struct dh_gen_ctx *gctx = genctx;
655     const OSSL_PARAM *p;
656 
657     if (!dh_gen_common_set_params(genctx, params))
658         return 0;
659 
660     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_GENERATOR);
661     if (p != NULL && !OSSL_PARAM_get_int(p, &gctx->generator))
662         return 0;
663 
664     /* Parameters that are not allowed for DH */
665     if (OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_GINDEX) != NULL
666         || OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_PCOUNTER) != NULL
667         || OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_H) != NULL
668         || OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_SEED) != NULL
669         || OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_QBITS) != NULL
670         || OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_DIGEST) != NULL
671         || OSSL_PARAM_locate_const(params,
672                                    OSSL_PKEY_PARAM_FFC_DIGEST_PROPS) != NULL) {
673         ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);
674         return 0;
675     }
676     return 1;
677 }
678 
679 static int dh_gencb(int p, int n, BN_GENCB *cb)
680 {
681     struct dh_gen_ctx *gctx = BN_GENCB_get_arg(cb);
682     OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END };
683 
684     params[0] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_POTENTIAL, &p);
685     params[1] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_ITERATION, &n);
686 
687     return gctx->cb(params, gctx->cbarg);
688 }
689 
690 static void *dh_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
691 {
692     int ret = 0;
693     struct dh_gen_ctx *gctx = genctx;
694     DH *dh = NULL;
695     BN_GENCB *gencb = NULL;
696     FFC_PARAMS *ffc;
697 
698     if (!ossl_prov_is_running() || gctx == NULL)
699         return NULL;
700 
701     /*
702      * If a group name is selected then the type is group regardless of what the
703      * the user selected. This overrides rather than errors for backwards
704      * compatibility.
705      */
706     if (gctx->group_nid != NID_undef)
707         gctx->gen_type = DH_PARAMGEN_TYPE_GROUP;
708 
709     /* For parameter generation - If there is a group name just create it */
710     if (gctx->gen_type == DH_PARAMGEN_TYPE_GROUP
711             && gctx->ffc_params == NULL) {
712         /* Select a named group if there is not one already */
713         if (gctx->group_nid == NID_undef)
714             gctx->group_nid = ossl_dh_get_named_group_uid_from_size(gctx->pbits);
715         if (gctx->group_nid == NID_undef)
716             return NULL;
717         dh = ossl_dh_new_by_nid_ex(gctx->libctx, gctx->group_nid);
718         if (dh == NULL)
719             return NULL;
720         ffc = ossl_dh_get0_params(dh);
721     } else {
722         dh = ossl_dh_new_ex(gctx->libctx);
723         if (dh == NULL)
724             return NULL;
725         ffc = ossl_dh_get0_params(dh);
726 
727         /* Copy the template value if one was passed */
728         if (gctx->ffc_params != NULL
729             && !ossl_ffc_params_copy(ffc, gctx->ffc_params))
730             goto end;
731 
732         if (!ossl_ffc_params_set_seed(ffc, gctx->seed, gctx->seedlen))
733             goto end;
734         if (gctx->gindex != -1) {
735             ossl_ffc_params_set_gindex(ffc, gctx->gindex);
736             if (gctx->pcounter != -1)
737                 ossl_ffc_params_set_pcounter(ffc, gctx->pcounter);
738         } else if (gctx->hindex != 0) {
739             ossl_ffc_params_set_h(ffc, gctx->hindex);
740         }
741         if (gctx->mdname != NULL) {
742             if (!ossl_ffc_set_digest(ffc, gctx->mdname, gctx->mdprops))
743                 goto end;
744         }
745         gctx->cb = osslcb;
746         gctx->cbarg = cbarg;
747         gencb = BN_GENCB_new();
748         if (gencb != NULL)
749             BN_GENCB_set(gencb, dh_gencb, genctx);
750 
751         if ((gctx->selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) {
752             /*
753              * NOTE: The old safe prime generator code is not used in fips mode,
754              * (i.e internally it ignores the generator and chooses a named
755              * group based on pbits.
756              */
757             if (gctx->gen_type == DH_PARAMGEN_TYPE_GENERATOR)
758                 ret = DH_generate_parameters_ex(dh, gctx->pbits,
759                                                 gctx->generator, gencb);
760             else
761                 ret = ossl_dh_generate_ffc_parameters(dh, gctx->gen_type,
762                                                       gctx->pbits, gctx->qbits,
763                                                       gencb);
764             if (ret <= 0)
765                 goto end;
766         }
767     }
768 
769     if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
770         if (ffc->p == NULL || ffc->g == NULL)
771             goto end;
772         if (gctx->priv_len > 0)
773             DH_set_length(dh, (long)gctx->priv_len);
774         ossl_ffc_params_enable_flags(ffc, FFC_PARAM_FLAG_VALIDATE_LEGACY,
775                                      gctx->gen_type == DH_PARAMGEN_TYPE_FIPS_186_2);
776         if (DH_generate_key(dh) <= 0)
777             goto end;
778     }
779     DH_clear_flags(dh, DH_FLAG_TYPE_MASK);
780     DH_set_flags(dh, gctx->dh_type);
781 
782     ret = 1;
783 end:
784     if (ret <= 0) {
785         DH_free(dh);
786         dh = NULL;
787     }
788     BN_GENCB_free(gencb);
789     return dh;
790 }
791 
792 static void dh_gen_cleanup(void *genctx)
793 {
794     struct dh_gen_ctx *gctx = genctx;
795 
796     if (gctx == NULL)
797         return;
798 
799     OPENSSL_free(gctx->mdname);
800     OPENSSL_free(gctx->mdprops);
801     OPENSSL_clear_free(gctx->seed, gctx->seedlen);
802     OPENSSL_free(gctx);
803 }
804 
805 static void *dh_load(const void *reference, size_t reference_sz)
806 {
807     DH *dh = NULL;
808 
809     if (ossl_prov_is_running() && reference_sz == sizeof(dh)) {
810         /* The contents of the reference is the address to our object */
811         dh = *(DH **)reference;
812         /* We grabbed, so we detach it */
813         *(DH **)reference = NULL;
814         return dh;
815     }
816     return NULL;
817 }
818 
819 static void *dh_dup(const void *keydata_from, int selection)
820 {
821     if (ossl_prov_is_running())
822         return ossl_dh_dup(keydata_from, selection);
823     return NULL;
824 }
825 
826 const OSSL_DISPATCH ossl_dh_keymgmt_functions[] = {
827     { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))dh_newdata },
828     { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))dh_gen_init },
829     { OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE, (void (*)(void))dh_gen_set_template },
830     { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))dh_gen_set_params },
831     { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS,
832       (void (*)(void))dh_gen_settable_params },
833     { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))dh_gen },
834     { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))dh_gen_cleanup },
835     { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))dh_load },
836     { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))dh_freedata },
837     { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dh_get_params },
838     { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dh_gettable_params },
839     { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))dh_set_params },
840     { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))dh_settable_params },
841     { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))dh_has },
842     { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))dh_match },
843     { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))dh_validate },
844     { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))dh_import },
845     { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))dh_import_types },
846     { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))dh_export },
847     { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))dh_export_types },
848     { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))dh_dup },
849     { 0, NULL }
850 };
851 
852 /* For any DH key, we use the "DH" algorithms regardless of sub-type. */
853 static const char *dhx_query_operation_name(int operation_id)
854 {
855     return "DH";
856 }
857 
858 const OSSL_DISPATCH ossl_dhx_keymgmt_functions[] = {
859     { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))dhx_newdata },
860     { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))dhx_gen_init },
861     { OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE, (void (*)(void))dh_gen_set_template },
862     { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))dhx_gen_set_params },
863     { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS,
864       (void (*)(void))dhx_gen_settable_params },
865     { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))dh_gen },
866     { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))dh_gen_cleanup },
867     { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))dh_load },
868     { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))dh_freedata },
869     { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dh_get_params },
870     { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dh_gettable_params },
871     { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))dh_set_params },
872     { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))dh_settable_params },
873     { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))dh_has },
874     { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))dh_match },
875     { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))dh_validate },
876     { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))dh_import },
877     { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))dh_import_types },
878     { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))dh_export },
879     { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))dh_export_types },
880     { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME,
881       (void (*)(void))dhx_query_operation_name },
882     { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))dh_dup },
883     { 0, NULL }
884 };
885