openssl/providers/implementations/keymgmt/dh_kmgmt.c
Matt Caswell 46c1c2d7fa Fix the export routines to not return success if param alloc failed
We fix the dsa, dh, ec and rsa export routines so that they are
consistent with each other and do not report success if the allocation
of parameters failed.

This is essentially the same fix as applied in #18483 but applied to all
relevant key types.

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18507)
2022-06-15 11:47:46 +01:00

882 lines
29 KiB
C

/*
* Copyright 2019-2022 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
*/
/*
* DH low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <string.h> /* strcmp */
#include <openssl/core_dispatch.h>
#include <openssl/core_names.h>
#include <openssl/bn.h>
#include <openssl/err.h>
#include "prov/implementations.h"
#include "prov/providercommon.h"
#include "prov/provider_ctx.h"
#include "crypto/dh.h"
#include "internal/sizes.h"
static OSSL_FUNC_keymgmt_new_fn dh_newdata;
static OSSL_FUNC_keymgmt_free_fn dh_freedata;
static OSSL_FUNC_keymgmt_gen_init_fn dh_gen_init;
static OSSL_FUNC_keymgmt_gen_init_fn dhx_gen_init;
static OSSL_FUNC_keymgmt_gen_set_template_fn dh_gen_set_template;
static OSSL_FUNC_keymgmt_gen_set_params_fn dh_gen_set_params;
static OSSL_FUNC_keymgmt_gen_settable_params_fn dh_gen_settable_params;
static OSSL_FUNC_keymgmt_gen_fn dh_gen;
static OSSL_FUNC_keymgmt_gen_cleanup_fn dh_gen_cleanup;
static OSSL_FUNC_keymgmt_load_fn dh_load;
static OSSL_FUNC_keymgmt_get_params_fn dh_get_params;
static OSSL_FUNC_keymgmt_gettable_params_fn dh_gettable_params;
static OSSL_FUNC_keymgmt_set_params_fn dh_set_params;
static OSSL_FUNC_keymgmt_settable_params_fn dh_settable_params;
static OSSL_FUNC_keymgmt_has_fn dh_has;
static OSSL_FUNC_keymgmt_match_fn dh_match;
static OSSL_FUNC_keymgmt_validate_fn dh_validate;
static OSSL_FUNC_keymgmt_import_fn dh_import;
static OSSL_FUNC_keymgmt_import_types_fn dh_import_types;
static OSSL_FUNC_keymgmt_export_fn dh_export;
static OSSL_FUNC_keymgmt_export_types_fn dh_export_types;
static OSSL_FUNC_keymgmt_dup_fn dh_dup;
#define DH_POSSIBLE_SELECTIONS \
(OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)
struct dh_gen_ctx {
OSSL_LIB_CTX *libctx;
FFC_PARAMS *ffc_params;
int selection;
/* All these parameters are used for parameter generation only */
/* If there is a group name then the remaining parameters are not needed */
int group_nid;
size_t pbits;
size_t qbits;
unsigned char *seed; /* optional FIPS186-4 param for testing */
size_t seedlen;
int gindex; /* optional FIPS186-4 generator index (ignored if -1) */
int gen_type; /* see dhtype2id */
int generator; /* Used by DH_PARAMGEN_TYPE_GENERATOR in non fips mode only */
int pcounter;
int hindex;
int priv_len;
char *mdname;
char *mdprops;
OSSL_CALLBACK *cb;
void *cbarg;
int dh_type;
};
static int dh_gen_type_name2id_w_default(const char *name, int type)
{
if (strcmp(name, "default") == 0) {
#ifdef FIPS_MODULE
if (type == DH_FLAG_TYPE_DHX)
return DH_PARAMGEN_TYPE_FIPS_186_4;
return DH_PARAMGEN_TYPE_GROUP;
#else
if (type == DH_FLAG_TYPE_DHX)
return DH_PARAMGEN_TYPE_FIPS_186_2;
return DH_PARAMGEN_TYPE_GENERATOR;
#endif
}
return ossl_dh_gen_type_name2id(name, type);
}
static void *dh_newdata(void *provctx)
{
DH *dh = NULL;
if (ossl_prov_is_running()) {
dh = ossl_dh_new_ex(PROV_LIBCTX_OF(provctx));
if (dh != NULL) {
DH_clear_flags(dh, DH_FLAG_TYPE_MASK);
DH_set_flags(dh, DH_FLAG_TYPE_DH);
}
}
return dh;
}
static void *dhx_newdata(void *provctx)
{
DH *dh = NULL;
dh = ossl_dh_new_ex(PROV_LIBCTX_OF(provctx));
if (dh != NULL) {
DH_clear_flags(dh, DH_FLAG_TYPE_MASK);
DH_set_flags(dh, DH_FLAG_TYPE_DHX);
}
return dh;
}
static void dh_freedata(void *keydata)
{
DH_free(keydata);
}
static int dh_has(const void *keydata, int selection)
{
const DH *dh = keydata;
int ok = 1;
if (!ossl_prov_is_running() || dh == NULL)
return 0;
if ((selection & DH_POSSIBLE_SELECTIONS) == 0)
return 1; /* the selection is not missing */
if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
ok = ok && (DH_get0_pub_key(dh) != NULL);
if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
ok = ok && (DH_get0_priv_key(dh) != NULL);
if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
ok = ok && (DH_get0_p(dh) != NULL && DH_get0_g(dh) != NULL);
return ok;
}
static int dh_match(const void *keydata1, const void *keydata2, int selection)
{
const DH *dh1 = keydata1;
const DH *dh2 = keydata2;
int ok = 1;
if (!ossl_prov_is_running())
return 0;
if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
int key_checked = 0;
if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
const BIGNUM *pa = DH_get0_pub_key(dh1);
const BIGNUM *pb = DH_get0_pub_key(dh2);
if (pa != NULL && pb != NULL) {
ok = ok && BN_cmp(pa, pb) == 0;
key_checked = 1;
}
}
if (!key_checked
&& (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
const BIGNUM *pa = DH_get0_priv_key(dh1);
const BIGNUM *pb = DH_get0_priv_key(dh2);
if (pa != NULL && pb != NULL) {
ok = ok && BN_cmp(pa, pb) == 0;
key_checked = 1;
}
}
ok = ok && key_checked;
}
if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) {
FFC_PARAMS *dhparams1 = ossl_dh_get0_params((DH *)dh1);
FFC_PARAMS *dhparams2 = ossl_dh_get0_params((DH *)dh2);
ok = ok && ossl_ffc_params_cmp(dhparams1, dhparams2, 1);
}
return ok;
}
static int dh_import(void *keydata, int selection, const OSSL_PARAM params[])
{
DH *dh = keydata;
int ok = 1;
if (!ossl_prov_is_running() || dh == NULL)
return 0;
if ((selection & DH_POSSIBLE_SELECTIONS) == 0)
return 0;
if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0)
ok = ok && ossl_dh_params_fromdata(dh, params);
if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
int include_private =
selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0;
ok = ok && ossl_dh_key_fromdata(dh, params, include_private);
}
return ok;
}
static int dh_export(void *keydata, int selection, OSSL_CALLBACK *param_cb,
void *cbarg)
{
DH *dh = keydata;
OSSL_PARAM_BLD *tmpl = NULL;
OSSL_PARAM *params = NULL;
int ok = 1;
if (!ossl_prov_is_running() || dh == NULL)
return 0;
tmpl = OSSL_PARAM_BLD_new();
if (tmpl == NULL)
return 0;
if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0)
ok = ok && ossl_dh_params_todata(dh, tmpl, NULL);
if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
int include_private =
selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0;
ok = ok && ossl_dh_key_todata(dh, tmpl, NULL, include_private);
}
if (!ok || (params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL) {
ok = 0;
goto err;
}
ok = param_cb(params, cbarg);
OSSL_PARAM_free(params);
err:
OSSL_PARAM_BLD_free(tmpl);
return ok;
}
/* IMEXPORT = IMPORT + EXPORT */
# define DH_IMEXPORTABLE_PARAMETERS \
OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_P, NULL, 0), \
OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_Q, NULL, 0), \
OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_G, NULL, 0), \
OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_COFACTOR, NULL, 0), \
OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_GINDEX, NULL), \
OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_PCOUNTER, NULL), \
OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_H, NULL), \
OSSL_PARAM_int(OSSL_PKEY_PARAM_DH_PRIV_LEN, NULL), \
OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_FFC_SEED, NULL, 0), \
OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0)
# define DH_IMEXPORTABLE_PUBLIC_KEY \
OSSL_PARAM_BN(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0)
# define DH_IMEXPORTABLE_PRIVATE_KEY \
OSSL_PARAM_BN(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0)
static const OSSL_PARAM dh_all_types[] = {
DH_IMEXPORTABLE_PARAMETERS,
DH_IMEXPORTABLE_PUBLIC_KEY,
DH_IMEXPORTABLE_PRIVATE_KEY,
OSSL_PARAM_END
};
static const OSSL_PARAM dh_parameter_types[] = {
DH_IMEXPORTABLE_PARAMETERS,
OSSL_PARAM_END
};
static const OSSL_PARAM dh_key_types[] = {
DH_IMEXPORTABLE_PUBLIC_KEY,
DH_IMEXPORTABLE_PRIVATE_KEY,
OSSL_PARAM_END
};
static const OSSL_PARAM *dh_types[] = {
NULL, /* Index 0 = none of them */
dh_parameter_types, /* Index 1 = parameter types */
dh_key_types, /* Index 2 = key types */
dh_all_types /* Index 3 = 1 + 2 */
};
static const OSSL_PARAM *dh_imexport_types(int selection)
{
int type_select = 0;
if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0)
type_select += 1;
if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
type_select += 2;
return dh_types[type_select];
}
static const OSSL_PARAM *dh_import_types(int selection)
{
return dh_imexport_types(selection);
}
static const OSSL_PARAM *dh_export_types(int selection)
{
return dh_imexport_types(selection);
}
static ossl_inline int dh_get_params(void *key, OSSL_PARAM params[])
{
DH *dh = key;
OSSL_PARAM *p;
if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL
&& !OSSL_PARAM_set_int(p, DH_bits(dh)))
return 0;
if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS)) != NULL
&& !OSSL_PARAM_set_int(p, DH_security_bits(dh)))
return 0;
if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL
&& !OSSL_PARAM_set_int(p, DH_size(dh)))
return 0;
if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY)) != NULL) {
if (p->data_type != OSSL_PARAM_OCTET_STRING)
return 0;
p->return_size = ossl_dh_key2buf(dh, (unsigned char **)&p->data,
p->data_size, 0);
if (p->return_size == 0)
return 0;
}
return ossl_dh_params_todata(dh, NULL, params)
&& ossl_dh_key_todata(dh, NULL, params, 1);
}
static const OSSL_PARAM dh_params[] = {
OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0),
DH_IMEXPORTABLE_PARAMETERS,
DH_IMEXPORTABLE_PUBLIC_KEY,
DH_IMEXPORTABLE_PRIVATE_KEY,
OSSL_PARAM_END
};
static const OSSL_PARAM *dh_gettable_params(void *provctx)
{
return dh_params;
}
static const OSSL_PARAM dh_known_settable_params[] = {
OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0),
OSSL_PARAM_END
};
static const OSSL_PARAM *dh_settable_params(void *provctx)
{
return dh_known_settable_params;
}
static int dh_set_params(void *key, const OSSL_PARAM params[])
{
DH *dh = key;
const OSSL_PARAM *p;
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY);
if (p != NULL
&& (p->data_type != OSSL_PARAM_OCTET_STRING
|| !ossl_dh_buf2key(dh, p->data, p->data_size)))
return 0;
return 1;
}
static int dh_validate_public(const DH *dh, int checktype)
{
const BIGNUM *pub_key = NULL;
int res = 0;
DH_get0_key(dh, &pub_key, NULL);
if (pub_key == NULL)
return 0;
/* The partial test is only valid for named group's with q = (p - 1) / 2 */
if (checktype == OSSL_KEYMGMT_VALIDATE_QUICK_CHECK
&& ossl_dh_is_named_safe_prime_group(dh))
return ossl_dh_check_pub_key_partial(dh, pub_key, &res);
return DH_check_pub_key(dh, pub_key, &res);
}
static int dh_validate_private(const DH *dh)
{
int status = 0;
const BIGNUM *priv_key = NULL;
DH_get0_key(dh, NULL, &priv_key);
if (priv_key == NULL)
return 0;
return ossl_dh_check_priv_key(dh, priv_key, &status);
}
static int dh_validate(const void *keydata, int selection, int checktype)
{
const DH *dh = keydata;
int ok = 1;
if (!ossl_prov_is_running())
return 0;
if ((selection & DH_POSSIBLE_SELECTIONS) == 0)
return 1; /* nothing to validate */
if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) {
/*
* Both of these functions check parameters. DH_check_params_ex()
* performs a lightweight check (e.g. it does not check that p is a
* safe prime)
*/
if (checktype == OSSL_KEYMGMT_VALIDATE_QUICK_CHECK)
ok = ok && DH_check_params_ex(dh);
else
ok = ok && DH_check_ex(dh);
}
if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
ok = ok && dh_validate_public(dh, checktype);
if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
ok = ok && dh_validate_private(dh);
if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR)
== OSSL_KEYMGMT_SELECT_KEYPAIR)
ok = ok && ossl_dh_check_pairwise(dh);
return ok;
}
static void *dh_gen_init_base(void *provctx, int selection,
const OSSL_PARAM params[], int type)
{
OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx);
struct dh_gen_ctx *gctx = NULL;
if (!ossl_prov_is_running())
return NULL;
if ((selection & (OSSL_KEYMGMT_SELECT_KEYPAIR
| OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)) == 0)
return NULL;
if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) {
gctx->selection = selection;
gctx->libctx = libctx;
gctx->pbits = 2048;
gctx->qbits = 224;
gctx->mdname = NULL;
#ifdef FIPS_MODULE
gctx->gen_type = (type == DH_FLAG_TYPE_DHX)
? DH_PARAMGEN_TYPE_FIPS_186_4
: DH_PARAMGEN_TYPE_GROUP;
#else
gctx->gen_type = (type == DH_FLAG_TYPE_DHX)
? DH_PARAMGEN_TYPE_FIPS_186_2
: DH_PARAMGEN_TYPE_GENERATOR;
#endif
gctx->gindex = -1;
gctx->hindex = 0;
gctx->pcounter = -1;
gctx->generator = DH_GENERATOR_2;
gctx->dh_type = type;
}
if (!dh_gen_set_params(gctx, params)) {
OPENSSL_free(gctx);
gctx = NULL;
}
return gctx;
}
static void *dh_gen_init(void *provctx, int selection,
const OSSL_PARAM params[])
{
return dh_gen_init_base(provctx, selection, params, DH_FLAG_TYPE_DH);
}
static void *dhx_gen_init(void *provctx, int selection,
const OSSL_PARAM params[])
{
return dh_gen_init_base(provctx, selection, params, DH_FLAG_TYPE_DHX);
}
static int dh_gen_set_template(void *genctx, void *templ)
{
struct dh_gen_ctx *gctx = genctx;
DH *dh = templ;
if (!ossl_prov_is_running() || gctx == NULL || dh == NULL)
return 0;
gctx->ffc_params = ossl_dh_get0_params(dh);
return 1;
}
static int dh_set_gen_seed(struct dh_gen_ctx *gctx, unsigned char *seed,
size_t seedlen)
{
OPENSSL_clear_free(gctx->seed, gctx->seedlen);
gctx->seed = NULL;
gctx->seedlen = 0;
if (seed != NULL && seedlen > 0) {
gctx->seed = OPENSSL_memdup(seed, seedlen);
if (gctx->seed == NULL)
return 0;
gctx->seedlen = seedlen;
}
return 1;
}
static int dh_gen_common_set_params(void *genctx, const OSSL_PARAM params[])
{
struct dh_gen_ctx *gctx = genctx;
const OSSL_PARAM *p;
if (gctx == NULL)
return 0;
if (params == NULL)
return 1;
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_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
|| p->data == NULL
|| (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;
}
}
if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_PBITS)) != NULL
&& !OSSL_PARAM_get_size_t(p, &gctx->pbits))
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_PRIV_LEN);
if (p != NULL && !OSSL_PARAM_get_int(p, &gctx->priv_len))
return 0;
return 1;
}
static const OSSL_PARAM *dh_gen_settable_params(ossl_unused void *genctx,
ossl_unused void *provctx)
{
static const OSSL_PARAM dh_gen_settable[] = {
OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_TYPE, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0),
OSSL_PARAM_int(OSSL_PKEY_PARAM_DH_PRIV_LEN, NULL),
OSSL_PARAM_size_t(OSSL_PKEY_PARAM_FFC_PBITS, NULL),
OSSL_PARAM_int(OSSL_PKEY_PARAM_DH_GENERATOR, NULL),
OSSL_PARAM_END
};
return dh_gen_settable;
}
static const OSSL_PARAM *dhx_gen_settable_params(ossl_unused void *genctx,
ossl_unused void *provctx)
{
static const OSSL_PARAM dhx_gen_settable[] = {
OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_TYPE, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0),
OSSL_PARAM_int(OSSL_PKEY_PARAM_DH_PRIV_LEN, NULL),
OSSL_PARAM_size_t(OSSL_PKEY_PARAM_FFC_PBITS, NULL),
OSSL_PARAM_size_t(OSSL_PKEY_PARAM_FFC_QBITS, NULL),
OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_DIGEST, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_DIGEST_PROPS, NULL, 0),
OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_GINDEX, NULL),
OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_FFC_SEED, NULL, 0),
OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_PCOUNTER, NULL),
OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_H, NULL),
OSSL_PARAM_END
};
return dhx_gen_settable;
}
static int dhx_gen_set_params(void *genctx, const OSSL_PARAM params[])
{
struct dh_gen_ctx *gctx = genctx;
const OSSL_PARAM *p;
if (!dh_gen_common_set_params(genctx, params))
return 0;
/* Parameters related to fips186-4 and fips186-2 */
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_GINDEX);
if (p != NULL && !OSSL_PARAM_get_int(p, &gctx->gindex))
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_PCOUNTER);
if (p != NULL && !OSSL_PARAM_get_int(p, &gctx->pcounter))
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_H);
if (p != NULL && !OSSL_PARAM_get_int(p, &gctx->hindex))
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_SEED);
if (p != NULL
&& (p->data_type != OSSL_PARAM_OCTET_STRING
|| !dh_set_gen_seed(gctx, p->data, p->data_size)))
return 0;
if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_QBITS)) != NULL
&& !OSSL_PARAM_get_size_t(p, &gctx->qbits))
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_DIGEST);
if (p != NULL) {
if (p->data_type != OSSL_PARAM_UTF8_STRING)
return 0;
OPENSSL_free(gctx->mdname);
gctx->mdname = OPENSSL_strdup(p->data);
if (gctx->mdname == NULL)
return 0;
}
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_DIGEST_PROPS);
if (p != NULL) {
if (p->data_type != OSSL_PARAM_UTF8_STRING)
return 0;
OPENSSL_free(gctx->mdprops);
gctx->mdprops = OPENSSL_strdup(p->data);
if (gctx->mdprops == NULL)
return 0;
}
/* Parameters that are not allowed for DHX */
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_GENERATOR);
if (p != NULL) {
ERR_raise(ERR_LIB_PROV, ERR_R_UNSUPPORTED);
return 0;
}
return 1;
}
static int dh_gen_set_params(void *genctx, const OSSL_PARAM params[])
{
struct dh_gen_ctx *gctx = genctx;
const OSSL_PARAM *p;
if (!dh_gen_common_set_params(genctx, params))
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_GENERATOR);
if (p != NULL && !OSSL_PARAM_get_int(p, &gctx->generator))
return 0;
/* Parameters that are not allowed for DH */
if (OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_GINDEX) != NULL
|| OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_PCOUNTER) != NULL
|| OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_H) != NULL
|| OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_SEED) != NULL
|| OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_QBITS) != NULL
|| OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_DIGEST) != NULL
|| OSSL_PARAM_locate_const(params,
OSSL_PKEY_PARAM_FFC_DIGEST_PROPS) != NULL) {
ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
return 1;
}
static int dh_gencb(int p, int n, BN_GENCB *cb)
{
struct dh_gen_ctx *gctx = BN_GENCB_get_arg(cb);
OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END };
params[0] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_POTENTIAL, &p);
params[1] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_ITERATION, &n);
return gctx->cb(params, gctx->cbarg);
}
static void *dh_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
{
int ret = 0;
struct dh_gen_ctx *gctx = genctx;
DH *dh = NULL;
BN_GENCB *gencb = NULL;
FFC_PARAMS *ffc;
if (!ossl_prov_is_running() || gctx == NULL)
return NULL;
/*
* If a group name is selected then the type is group regardless of what the
* the user selected. This overrides rather than errors for backwards
* compatibility.
*/
if (gctx->group_nid != NID_undef)
gctx->gen_type = DH_PARAMGEN_TYPE_GROUP;
/* For parameter generation - If there is a group name just create it */
if (gctx->gen_type == DH_PARAMGEN_TYPE_GROUP
&& gctx->ffc_params == NULL) {
/* Select a named group if there is not one already */
if (gctx->group_nid == NID_undef)
gctx->group_nid = ossl_dh_get_named_group_uid_from_size(gctx->pbits);
if (gctx->group_nid == NID_undef)
return NULL;
dh = ossl_dh_new_by_nid_ex(gctx->libctx, gctx->group_nid);
if (dh == NULL)
return NULL;
ffc = ossl_dh_get0_params(dh);
} else {
dh = ossl_dh_new_ex(gctx->libctx);
if (dh == NULL)
return NULL;
ffc = ossl_dh_get0_params(dh);
/* Copy the template value if one was passed */
if (gctx->ffc_params != NULL
&& !ossl_ffc_params_copy(ffc, gctx->ffc_params))
goto end;
if (!ossl_ffc_params_set_seed(ffc, gctx->seed, gctx->seedlen))
goto end;
if (gctx->gindex != -1) {
ossl_ffc_params_set_gindex(ffc, gctx->gindex);
if (gctx->pcounter != -1)
ossl_ffc_params_set_pcounter(ffc, gctx->pcounter);
} else if (gctx->hindex != 0) {
ossl_ffc_params_set_h(ffc, gctx->hindex);
}
if (gctx->mdname != NULL) {
if (!ossl_ffc_set_digest(ffc, gctx->mdname, gctx->mdprops))
goto end;
}
gctx->cb = osslcb;
gctx->cbarg = cbarg;
gencb = BN_GENCB_new();
if (gencb != NULL)
BN_GENCB_set(gencb, dh_gencb, genctx);
if ((gctx->selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) {
/*
* NOTE: The old safe prime generator code is not used in fips mode,
* (i.e internally it ignores the generator and chooses a named
* group based on pbits.
*/
if (gctx->gen_type == DH_PARAMGEN_TYPE_GENERATOR)
ret = DH_generate_parameters_ex(dh, gctx->pbits,
gctx->generator, gencb);
else
ret = ossl_dh_generate_ffc_parameters(dh, gctx->gen_type,
gctx->pbits, gctx->qbits,
gencb);
if (ret <= 0)
goto end;
}
}
if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
if (ffc->p == NULL || ffc->g == NULL)
goto end;
if (gctx->priv_len > 0)
DH_set_length(dh, (long)gctx->priv_len);
ossl_ffc_params_enable_flags(ffc, FFC_PARAM_FLAG_VALIDATE_LEGACY,
gctx->gen_type == DH_PARAMGEN_TYPE_FIPS_186_2);
if (DH_generate_key(dh) <= 0)
goto end;
}
DH_clear_flags(dh, DH_FLAG_TYPE_MASK);
DH_set_flags(dh, gctx->dh_type);
ret = 1;
end:
if (ret <= 0) {
DH_free(dh);
dh = NULL;
}
BN_GENCB_free(gencb);
return dh;
}
static void dh_gen_cleanup(void *genctx)
{
struct dh_gen_ctx *gctx = genctx;
if (gctx == NULL)
return;
OPENSSL_free(gctx->mdname);
OPENSSL_free(gctx->mdprops);
OPENSSL_clear_free(gctx->seed, gctx->seedlen);
OPENSSL_free(gctx);
}
static void *dh_load(const void *reference, size_t reference_sz)
{
DH *dh = NULL;
if (ossl_prov_is_running() && reference_sz == sizeof(dh)) {
/* The contents of the reference is the address to our object */
dh = *(DH **)reference;
/* We grabbed, so we detach it */
*(DH **)reference = NULL;
return dh;
}
return NULL;
}
static void *dh_dup(const void *keydata_from, int selection)
{
if (ossl_prov_is_running())
return ossl_dh_dup(keydata_from, selection);
return NULL;
}
const OSSL_DISPATCH ossl_dh_keymgmt_functions[] = {
{ OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))dh_newdata },
{ OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))dh_gen_init },
{ OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE, (void (*)(void))dh_gen_set_template },
{ OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))dh_gen_set_params },
{ OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS,
(void (*)(void))dh_gen_settable_params },
{ OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))dh_gen },
{ OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))dh_gen_cleanup },
{ OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))dh_load },
{ OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))dh_freedata },
{ OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dh_get_params },
{ OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dh_gettable_params },
{ OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))dh_set_params },
{ OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))dh_settable_params },
{ OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))dh_has },
{ OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))dh_match },
{ OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))dh_validate },
{ OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))dh_import },
{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))dh_import_types },
{ OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))dh_export },
{ OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))dh_export_types },
{ OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))dh_dup },
{ 0, NULL }
};
/* For any DH key, we use the "DH" algorithms regardless of sub-type. */
static const char *dhx_query_operation_name(int operation_id)
{
return "DH";
}
const OSSL_DISPATCH ossl_dhx_keymgmt_functions[] = {
{ OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))dhx_newdata },
{ OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))dhx_gen_init },
{ OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE, (void (*)(void))dh_gen_set_template },
{ OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))dhx_gen_set_params },
{ OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS,
(void (*)(void))dhx_gen_settable_params },
{ OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))dh_gen },
{ OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))dh_gen_cleanup },
{ OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))dh_load },
{ OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))dh_freedata },
{ OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dh_get_params },
{ OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dh_gettable_params },
{ OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))dh_set_params },
{ OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))dh_settable_params },
{ OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))dh_has },
{ OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))dh_match },
{ OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))dh_validate },
{ OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))dh_import },
{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))dh_import_types },
{ OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))dh_export },
{ OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))dh_export_types },
{ OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME,
(void (*)(void))dhx_query_operation_name },
{ OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))dh_dup },
{ 0, NULL }
};