From 2f367a44752241dacd01814632d6fbc8ba9e9710 Mon Sep 17 00:00:00 2001 From: Zhangfei Gao Date: Mon, 23 Oct 2023 03:08:53 +0000 Subject: [PATCH 51/63] uadk: add uadk_prov_dh Two funcs are supported key generation, ie. keymgmt key exchange, ie. keyexch Test: openssl dhparam -out dhparam.pem 2048 openssl genpkey -paramfile dhparam.pem -out privatekey1.pem \ -provider uadk_provider openssl genpkey -paramfile dhparam.pem -out privatekey2.pem \ -provider uadk_provider openssl pkey -in privatekey1.pem -pubout -out publickey1.pem \ -provider uadk_provider openssl pkey -in privatekey2.pem -pubout -out publickey2.pem \ -provider uadk_provider openssl pkeyutl -derive -inkey privatekey1.pem -peerkey publickey2.pem \ -out secret1.bin -provider uadk_provider openssl pkeyutl -derive -inkey privatekey2.pem -peerkey publickey1.pem \ -out secret2.bin -provider uadk_provider cmp secret1.bin secret2.bin Signed-off-by: Zhangfei Gao --- src/Makefile.am | 2 +- src/uadk_prov.h | 4 + src/uadk_prov_dh.c | 1863 ++++++++++++++++++++++++++++++++++++++++++ src/uadk_prov_init.c | 21 +- 4 files changed, 1883 insertions(+), 7 deletions(-) create mode 100644 src/uadk_prov_dh.c diff --git a/src/Makefile.am b/src/Makefile.am index 9d5102a..668ba13 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -52,7 +52,7 @@ endif #WD_KAE uadk_provider_la_SOURCES=uadk_prov_init.c uadk_async.c uadk_utils.c \ uadk_prov_digest.c uadk_prov_cipher.c \ - uadk_prov_rsa.c + uadk_prov_rsa.c uadk_prov_dh.c uadk_provider_la_LDFLAGS=-module -version-number $(VERSION) uadk_provider_la_LIBADD=$(WD_LIBS) -lpthread diff --git a/src/uadk_prov.h b/src/uadk_prov.h index 01e799e..718e78c 100644 --- a/src/uadk_prov.h +++ b/src/uadk_prov.h @@ -117,7 +117,11 @@ extern const OSSL_DISPATCH uadk_rsa_signature_functions[]; extern const OSSL_DISPATCH uadk_rsa_keymgmt_functions[]; extern const OSSL_DISPATCH uadk_rsa_asym_cipher_functions[]; +extern const OSSL_DISPATCH uadk_dh_keymgmt_functions[]; +extern const OSSL_DISPATCH uadk_dh_keyexch_functions[]; + void uadk_prov_destroy_digest(void); void uadk_prov_destroy_cipher(void); void uadk_prov_destroy_rsa(void); +void uadk_prov_destroy_dh(void); #endif diff --git a/src/uadk_prov_dh.c b/src/uadk_prov_dh.c new file mode 100644 index 0000000..cf84cb9 --- /dev/null +++ b/src/uadk_prov_dh.c @@ -0,0 +1,1863 @@ +/* + * Copyright 2023-2024 Huawei Technologies Co.,Ltd. All rights reserved. + * Copyright 2023-2024 Linaro ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include +#include +#include +#include +#include +#include "uadk.h" +#include "uadk_async.h" +#include "uadk_prov.h" + +#define DH768BITS 768 +#define DH1024BITS 1024 +#define DH1536BITS 1536 +#define DH2048BITS 2048 +#define DH3072BITS 3072 +#define DH4096BITS 4096 +#define UADK_DH_MAX_MODULE_BIT 4096 +#define DH_GENERATOR_2 2 +#define DH_GENERATOR_5 5 +#define CHAR_BIT_SIZE 3 +#define DH_PARAMS_CNT 3 +#define CTX_MODE_NUM 2 +#define UN_SET 0 +#define IS_SET 1 +#define CTX_ASYNC 1 +#define CTX_SYNC 0 +#define CTX_NUM 2 +#define UADK_DO_SOFT (-0xE0) +#define UADK_E_SUCCESS 1 +#define UADK_E_FAIL 0 +#define UADK_E_POLL_SUCCESS 0 +#define UADK_E_POLL_FAIL (-1) +#define UADK_E_INIT_SUCCESS 0 +#define ENV_ENABLED 1 +#define KEY_GEN_BY_ENGINE 1 + +struct evp_keyexch_st { + int name_id; + char *type_name; + const char *description; + OSSL_PROVIDER *prov; + CRYPTO_REF_COUNT refcnt; + + OSSL_FUNC_keyexch_newctx_fn *newctx; + OSSL_FUNC_keyexch_init_fn *init; + OSSL_FUNC_keyexch_set_peer_fn *set_peer; + OSSL_FUNC_keyexch_derive_fn *derive; + OSSL_FUNC_keyexch_freectx_fn *freectx; + OSSL_FUNC_keyexch_dupctx_fn *dupctx; + OSSL_FUNC_keyexch_set_ctx_params_fn *set_ctx_params; + OSSL_FUNC_keyexch_settable_ctx_params_fn *settable_ctx_params; + OSSL_FUNC_keyexch_get_ctx_params_fn *get_ctx_params; + OSSL_FUNC_keyexch_gettable_ctx_params_fn *gettable_ctx_params; +} /* EVP_KEYEXCH */; + +typedef struct ffc_params_st { + /* Primes */ + BIGNUM *p; + BIGNUM *q; + /* Generator */ + BIGNUM *g; + /* DH X9.42 Optional Subgroup factor j >= 2 where p = j * q + 1 */ + BIGNUM *j; + + /* Required for FIPS186_4 validation of p, q and optionally canonical g */ + unsigned char *seed; + /* If this value is zero the hash size is used as the seed length */ + size_t seedlen; + /* Required for FIPS186_4 validation of p and q */ + int pcounter; + int nid; /* The identity of a named group */ + + /* + * Required for FIPS186_4 generation & validation of canonical g. + * It uses unverifiable g if this value is -1. + */ + int gindex; + int h; /* loop counter for unverifiable g */ + + unsigned int flags; + /* + * The digest to use for generation or validation. If this value is NULL, + * then the digest is chosen using the value of N. + */ + const char *mdname; + const char *mdprops; +#if OPENSSL_VERSION_NUMBER >= 0x30000060 + /* Default key length for known named groups according to RFC7919 */ + int keylength; +#endif +} FFC_PARAMS; + +struct dh_st { + /* + * This first argument is used to pick up errors when a DH is passed + * instead of a EVP_PKEY + */ + int pad; + int version; + FFC_PARAMS params; + /* max generated private key length (can be less than len(q)) */ + int32_t length; + BIGNUM *pub_key; /* g^x % p */ + BIGNUM *priv_key; /* x */ + int flags; + BN_MONT_CTX *method_mont_p; + CRYPTO_REF_COUNT references; +#ifndef FIPS_MODULE + CRYPTO_EX_DATA ex_data; + ENGINE *engine; +#endif + OSSL_LIB_CTX * libctx; + const DH_METHOD *meth; + CRYPTO_RWLOCK *lock; + + /* Provider data */ + size_t dirty_cnt; /* If any key material changes, increment this */ +}; /* DH */ + +struct dh_method { + char *name; + /* Methods here */ + int (*generate_key)(DH *dh); + int (*compute_key)(unsigned char *key, const BIGNUM *pub_key, DH *dh); + + /* Can be null */ + int (*bn_mod_exp)(const DH *dh, BIGNUM *r, const BIGNUM *a, + const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx); + int (*init)(DH *dh); + int (*finish)(DH *dh); + int flags; + char *app_data; + /* If this is non-NULL, it will be used to generate parameters */ + int (*generate_params)(DH *dh, int prime_len, int generator, + BN_GENCB *cb); +}; + +#define FFC_UNVERIFIABLE_GINDEX -1 +#define FFC_PARAM_FLAG_VALIDATE_PQ 0x01 +#define FFC_PARAM_FLAG_VALIDATE_G 0x02 +#define FFC_PARAM_FLAG_VALIDATE_PQG \ + (FFC_PARAM_FLAG_VALIDATE_PQ | FFC_PARAM_FLAG_VALIDATE_G) + +struct uadk_dh_sess { + handle_t sess; + struct wd_dh_sess_setup setup; + struct wd_dh_req req; + DH *alg; + __u16 key_size; + /* key_flag: 0 - key is defined by user, 1 - key is generated by engine */ + int key_flag; +}; + +struct dh_res { + int pid; +} g_dh_res; + +static pthread_mutex_t dh_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* + * This type is only really used to handle some legacy related functionality. + * If you need to use other KDF's (such as SSKDF) just use PROV_DH_KDF_NONE + * here and then create and run a KDF after the key is derived. + * Note that X942 has 2 variants of key derivation: + * (1) DH_KDF_X9_42_ASN1 - which contains an ANS1 encoded object that has + * the counter embedded in it. + * (2) DH_KDF_X941_CONCAT - which is the same as ECDH_X963_KDF (which can be + * done by creating a "X963KDF". + */ +enum kdf_type { + PROV_DH_KDF_NONE = 0, + PROV_DH_KDF_X9_42_ASN1 +}; + +/* + * What's passed as an actual key is defined by the KEYMGMT interface. + * We happen to know that our KEYMGMT simply passes DH structures, so + * we use that here too. + */ + +typedef struct { + OSSL_LIB_CTX *libctx; + DH *dh; + DH *dhpeer; + unsigned int pad : 1; + + /* DH KDF */ + /* KDF (if any) to use for DH */ + enum kdf_type kdf_type; + /* Message digest to use for key derivation */ + EVP_MD *kdf_md; + /* User key material */ + unsigned char *kdf_ukm; + size_t kdf_ukmlen; + /* KDF output length */ + size_t kdf_outlen; + char *kdf_cekalg; +} UADK_PROV_DH_CTX; + +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; +}; + +typedef struct { + int id; /* libcrypto internal */ + int name_id; + char *type_name; + const char *description; + OSSL_PROVIDER *prov; + + int refcnt; + void *lock; + + /* Constructor(s), destructor, information */ + OSSL_FUNC_keymgmt_new_fn *new; + OSSL_FUNC_keymgmt_free_fn *free; + OSSL_FUNC_keymgmt_get_params_fn *get_params; + OSSL_FUNC_keymgmt_gettable_params_fn *gettable_params; + OSSL_FUNC_keymgmt_set_params_fn *set_params; + OSSL_FUNC_keymgmt_settable_params_fn *settable_params; + + /* Generation, a complex constructor */ + OSSL_FUNC_keymgmt_gen_init_fn *gen_init; + OSSL_FUNC_keymgmt_gen_set_template_fn *gen_set_template; + OSSL_FUNC_keymgmt_gen_set_params_fn *gen_set_params; + OSSL_FUNC_keymgmt_gen_settable_params_fn *gen_settable_params; + OSSL_FUNC_keymgmt_gen_fn *gen; + OSSL_FUNC_keymgmt_gen_cleanup_fn *gen_cleanup; + OSSL_FUNC_keymgmt_load_fn *load; + + /* Key object checking */ + OSSL_FUNC_keymgmt_query_operation_name_fn *query_operation_name; + OSSL_FUNC_keymgmt_has_fn *has; + OSSL_FUNC_keymgmt_validate_fn *validate; + OSSL_FUNC_keymgmt_match_fn *match; + + /* Import and export routines */ + OSSL_FUNC_keymgmt_import_fn *import; + OSSL_FUNC_keymgmt_import_types_fn *import_types; + OSSL_FUNC_keymgmt_export_fn *export; + OSSL_FUNC_keymgmt_export_types_fn *export_types; + OSSL_FUNC_keymgmt_dup_fn *dup; + +} UADK_DH_KEYMGMT; + +static inline int CRYPTO_UP_REF(int *val, int *ret, ossl_unused void *lock) +{ + *ret = __atomic_fetch_add(val, 1, __ATOMIC_RELAXED) + 1; + return 1; +} + +static inline int CRYPTO_DOWN_REF(int *val, int *ret, + ossl_unused void *lock) +{ + *ret = __atomic_fetch_sub(val, 1, __ATOMIC_RELAXED) - 1; + if (*ret == 0) + __atomic_thread_fence(__ATOMIC_ACQUIRE); + return 1; +} + +static FFC_PARAMS *uadk_dh_get0_params(DH *dh) +{ + return &dh->params; +} + +static int uadk_DH_size(const DH *dh) +{ + if (dh->params.p != NULL) + return BN_num_bytes(dh->params.p); + return -1; +} + +static void uadk_DH_get0_key(const DH *dh, const BIGNUM **pub_key, + const BIGNUM **priv_key) +{ + if (pub_key != NULL) + *pub_key = dh->pub_key; + if (priv_key != NULL) + *priv_key = dh->priv_key; +} + +static int uadk_DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) +{ + if (pub_key != NULL) { + BN_clear_free(dh->pub_key); + dh->pub_key = pub_key; + } + + if (priv_key != NULL) { + BN_clear_free(dh->priv_key); + dh->priv_key = priv_key; + } + + dh->dirty_cnt++; + return 1; +} + +static FFC_PARAMS *uadk_ossl_dh_get0_params(DH *dh) +{ + return &dh->params; +} + +static const BIGNUM *uadk_DH_get0_p(const DH *dh) +{ + return dh->params.p; +} + +static int ossl_ffc_params_set_seed(FFC_PARAMS *params, + const unsigned char *seed, size_t seedlen) +{ + if (params == NULL) + return 0; + + if (params->seed != NULL) { + if (params->seed == seed) + return 1; + OPENSSL_free(params->seed); + } + + if (seed != NULL && seedlen > 0) { + params->seed = OPENSSL_memdup(seed, seedlen); + if (params->seed == NULL) + return 0; + params->seedlen = seedlen; + } else { + params->seed = NULL; + params->seedlen = 0; + } + return 1; +} + +static int ffc_bn_cpy(BIGNUM **dst, const BIGNUM *src) +{ + BIGNUM *a; + + /* + * If source is read only just copy the pointer, so + * we don't have to reallocate it. + */ + if (src == NULL) + a = NULL; + else if (BN_get_flags(src, BN_FLG_STATIC_DATA) + && !BN_get_flags(src, BN_FLG_MALLOCED)) + a = (BIGNUM *)src; + else { + a = BN_dup(src); + if (a == NULL) + return 0; + } + + BN_clear_free(*dst); + *dst = a; + return 1; +} + +static int ossl_ffc_params_copy(FFC_PARAMS *dst, const FFC_PARAMS *src) +{ + if (!ffc_bn_cpy(&dst->p, src->p) + || !ffc_bn_cpy(&dst->g, src->g) + || !ffc_bn_cpy(&dst->q, src->q) + || !ffc_bn_cpy(&dst->j, src->j)) + return 0; + + OPENSSL_free(dst->seed); + dst->seedlen = src->seedlen; + if (src->seed != NULL) { + dst->seed = OPENSSL_memdup(src->seed, src->seedlen); + if (dst->seed == NULL) + return 0; + } else { + dst->seed = NULL; + } + dst->nid = src->nid; + dst->pcounter = src->pcounter; + dst->h = src->h; + dst->gindex = src->gindex; + dst->flags = src->flags; + return 1; +} + +static const BIGNUM *uadk_DH_get0_q(const DH *dh) +{ + return dh->params.q; +} + +static long uadk_DH_get_length(const DH *dh) +{ + return dh->length; +} + +static void ossl_ffc_params_get0_pqg(const FFC_PARAMS *d, const BIGNUM **p, + const BIGNUM **q, const BIGNUM **g) +{ + if (p != NULL) + *p = d->p; + if (q != NULL) + *q = d->q; + if (g != NULL) + *g = d->g; +} + +static void uadk_DH_get0_pqg(const DH *dh, const BIGNUM **p, + const BIGNUM **q, const BIGNUM **g) +{ + ossl_ffc_params_get0_pqg(&dh->params, p, q, g); +} + +static const BIGNUM *uadk_DH_get0_priv_key(const DH *dh) +{ + return dh->priv_key; +} + +static const BIGNUM *uadk_DH_get0_pub_key(const DH *dh) +{ + return dh->pub_key; +} + +static int uadk_DH_bits(const DH *dh) +{ + if (dh->params.p != NULL) + return BN_num_bits(dh->params.p); + return -1; +} + +static void uadk_DH_clear_flags(DH *dh, int flags) +{ + dh->flags &= ~flags; +} + +static void uadk_DH_set_flags(DH *dh, int flags) +{ + dh->flags |= flags; +} + +static int uadk_ffc_params_cmp(const FFC_PARAMS *a, const FFC_PARAMS *b, int ignore_q) +{ + return BN_cmp(a->p, b->p) == 0 && BN_cmp(a->g, b->g) == 0 && + (ignore_q || BN_cmp(a->q, b->q) == 0); /* Note: q may be NULL */ +} + +static int uadk_DH_up_ref(DH *r) +{ + int i; + + if (CRYPTO_UP_REF(&r->references, &i, r->lock) <= 0) + return 0; + + if (i < 2) { + fprintf(stderr, "refcount error.\n"); + return 0; + } + return ((i > 1) ? 1 : 0); +} + +static EVP_KEYEXCH get_default_keyexch(void) +{ + static EVP_KEYEXCH s_keyexch; + static int initilazed; + + if (!initilazed) { + EVP_KEYEXCH *keyexch = + (EVP_KEYEXCH *)EVP_KEYEXCH_fetch(NULL, "DH", "provider=default"); + if (keyexch) { + s_keyexch = *keyexch; + EVP_KEYEXCH_free((EVP_KEYEXCH *)keyexch); + initilazed = 1; + } else { + fprintf(stderr, "EVP_KEYEXCH_fetch from default provider failed"); + } + } + return s_keyexch; +} + +static int dh_generate_new_priv_key(const DH *dh, BIGNUM *new_priv_key) +{ + const BIGNUM *q = uadk_DH_get0_q(dh); + int bits; + + if (q) { + do { + if (!BN_priv_rand_range(new_priv_key, q)) + return UADK_E_FAIL; + } while (BN_is_zero(new_priv_key) || BN_is_one(new_priv_key)); + } else { + bits = uadk_DH_get_length(dh) ? + uadk_DH_get_length(dh) : BN_num_bits(uadk_DH_get0_p(dh)) - 1; + if (!BN_priv_rand(new_priv_key, bits, BN_RAND_TOP_ONE, + BN_RAND_BOTTOM_ANY)) + return UADK_E_FAIL; + } + + return UADK_E_SUCCESS; +} + +static int dh_try_get_priv_key(struct uadk_dh_sess *dh_sess, const DH *dh, BIGNUM **priv_key) +{ + *priv_key = (BIGNUM *)uadk_DH_get0_priv_key(dh); + if (!(*priv_key)) { + *priv_key = BN_secure_new(); + if (!(*priv_key)) + return UADK_E_FAIL; + + if (!dh_generate_new_priv_key(dh, *priv_key)) + goto err; + + dh_sess->key_flag = KEY_GEN_BY_ENGINE; + } + + return UADK_E_SUCCESS; + +err: + BN_free(*priv_key); + return UADK_E_FAIL; +} + +static void uadk_prov_dh_cb(void *req_t) +{ + struct wd_dh_req *req_new = (struct wd_dh_req *)req_t; + struct uadk_e_cb_info *cb_param; + struct wd_dh_req *req_origin; + struct async_op *op; + + if (!req_new) + return; + + cb_param = req_new->cb_param; + if (!cb_param) + return; + + req_origin = cb_param->priv; + if (!req_origin) + return; + + req_origin->status = req_new->status; + if (!req_origin->status) + req_origin->pri_bytes = req_new->pri_bytes; + + op = cb_param->op; + if (op && op->job && !op->done) { + op->done = 1; + async_free_poll_task(op->idx, 1); + async_wake_job(op->job); + } +} + +static int uadk_dh_env_poll(void *ctx) +{ + __u64 rx_cnt = 0; + __u32 recv = 0; + /* Poll one packet currently */ + int expt = 1; + int ret; + + do { + ret = wd_dh_poll(expt, &recv); + if (ret < 0 || recv == expt) + return ret; + rx_cnt++; + } while (rx_cnt < ENGINE_RECV_MAX_CNT); + + fprintf(stderr, "failed to poll msg: timeout!\n"); + + return -ETIMEDOUT; +} + +static int uadk_prov_dh_init(void) +{ + int ret; + + pthread_mutex_lock(&dh_mutex); + if (g_dh_res.pid != getpid()) { + ret = wd_dh_init2("dh", 0, 0); + if (unlikely(ret)) + return ret; + g_dh_res.pid = getpid(); + async_register_poll_fn(ASYNC_TASK_DH, uadk_dh_env_poll); + } + pthread_mutex_unlock(&dh_mutex); + + return UADK_E_INIT_SUCCESS; +} + +static struct uadk_dh_sess *dh_new_eng_session(DH *dh_alg) +{ + struct uadk_dh_sess *dh_sess; + + dh_sess = OPENSSL_malloc(sizeof(struct uadk_dh_sess)); + if (!dh_sess) + return NULL; + + memset(dh_sess, 0, sizeof(struct uadk_dh_sess)); + + dh_sess->alg = dh_alg; + + return dh_sess; +} + +static int dh_init_eng_session(struct uadk_dh_sess *dh_sess, + __u16 bits, bool is_g2) +{ + __u16 key_size = bits >> CHAR_BIT_SIZE; + struct sched_params params = {0}; + + if (dh_sess->sess && dh_sess->req.x_p) { + memset(dh_sess->req.x_p, 0, dh_sess->req.pbytes + + dh_sess->req.xbytes); + return UADK_E_SUCCESS; + } + + if (!dh_sess->sess) { + dh_sess->key_size = key_size; + dh_sess->setup.key_bits = bits; + dh_sess->setup.is_g2 = is_g2; + /* Use the default numa parameters */ + params.numa_id = -1; + dh_sess->setup.sched_param = ¶ms; + dh_sess->sess = wd_dh_alloc_sess(&dh_sess->setup); + if (!dh_sess->sess) + return UADK_E_FAIL; + } + + return UADK_E_SUCCESS; +} + +static void dh_free_eng_session(struct uadk_dh_sess *dh_sess) +{ + if (!dh_sess) + return; + + if (dh_sess->sess) + wd_dh_free_sess(dh_sess->sess); + + if (dh_sess->req.x_p) + OPENSSL_free(dh_sess->req.x_p); + + if (dh_sess->req.pv) + OPENSSL_free(dh_sess->req.pv); + + OPENSSL_free(dh_sess); +} + +static struct uadk_dh_sess *dh_get_eng_session(DH *dh, __u16 bits, + bool is_g2) +{ + struct uadk_dh_sess *dh_sess = dh_new_eng_session(dh); + int ret; + + if (!dh_sess) + return NULL; + + ret = dh_init_eng_session(dh_sess, bits, is_g2); + if (!ret) { + dh_free_eng_session(dh_sess); + return NULL; + } + + return dh_sess; +} + +static int check_dh_bit_useful(const __u16 bits) +{ + /* + * Check whether bits exceeds the limit. + * The max module bits of openssl soft alg is + * OPENSSL_DH_MAX_MODULUS_BITS, 10000 bits. + * OpenSSL speed tool supports 2048/3072/4096/6144/8192 bits. + * UADK supports 768/1024/1536/2048/3072/4096 bits. + * UADK-engine will be consistent with UADK. + */ + switch (bits) { + case DH768BITS: + case DH1024BITS: + case DH1536BITS: + case DH2048BITS: + case DH3072BITS: + case DH4096BITS: + return UADK_E_SUCCESS; + default: + break; + } + + return UADK_E_FAIL; +} + +static int dh_prepare_data(const BIGNUM *g, DH *dh, + struct uadk_dh_sess **dh_sess, + BIGNUM **priv_key) +{ + bool is_g2 = BN_is_word(g, DH_GENERATOR_2); + __u16 bits; + int ret; + + /* + * The max module bits of DH is + * OPENSSL_DH_MAX_MODULUS_BITS, 10000 bits. + */ + bits = (__u16)uadk_DH_bits(dh); + ret = check_dh_bit_useful(bits); + if (!ret) { + fprintf(stderr, "op size is not supported by uadk engine\n"); + return UADK_E_FAIL; + } + + *dh_sess = dh_get_eng_session(dh, bits, is_g2); + if (!(*dh_sess)) { + fprintf(stderr, "failed to get eng ctx\n"); + return UADK_E_FAIL; + } + + ret = dh_try_get_priv_key(*dh_sess, dh, priv_key); + if (!ret) { + dh_free_eng_session(*dh_sess); + return UADK_E_FAIL; + } + + return ret; +} + +static int dh_set_g(const BIGNUM *g, const __u16 key_size, + unsigned char *ag_bin, struct uadk_dh_sess *dh_sess) +{ + struct wd_dtb g_dtb; + __u32 gbytes; + int ret; + + gbytes = BN_bn2bin(g, ag_bin); + g_dtb.data = (char *)ag_bin; + g_dtb.bsize = key_size; + g_dtb.dsize = gbytes; + + ret = wd_dh_set_g(dh_sess->sess, &g_dtb); + if (ret) { + fprintf(stderr, "failed to set dh g\n"); + return UADK_E_FAIL; + } + + return UADK_E_SUCCESS; +} + +static int dh_get_pubkey(struct uadk_dh_sess *dh_sess, BIGNUM **pubkey) +{ + const unsigned char *pubkey_str; + + pubkey_str = (const unsigned char *)dh_sess->req.pri; + if (!pubkey_str) + return UADK_E_FAIL; + + *pubkey = BN_bin2bn(pubkey_str, dh_sess->req.pri_bytes, *pubkey); + if (!(*pubkey)) + return UADK_E_FAIL; + + return UADK_E_SUCCESS; +} + +static int dh_fill_genkey_req(const BIGNUM *g, const BIGNUM *p, + const BIGNUM *priv_key, + struct uadk_dh_sess *dh_sess) +{ + __u16 key_size = dh_sess->key_size; + unsigned char *apriv_key_bin; + unsigned char *ag_bin; + unsigned char *ap_bin; + unsigned char *out_pri; + int ret; + + ag_bin = OPENSSL_malloc(key_size); + if (!ag_bin) + return UADK_E_FAIL; + + /* Malloc a contiguous chunk of memory */ + apriv_key_bin = OPENSSL_malloc(key_size * DH_PARAMS_CNT); + if (!apriv_key_bin) + goto free_ag; + + ap_bin = apriv_key_bin + key_size; + out_pri = ap_bin + key_size; + memset(ag_bin, 0, key_size); + memset(apriv_key_bin, 0, key_size); + memset(ap_bin, 0, key_size); + memset(out_pri, 0, key_size); + + /* Construct data block of g */ + ret = dh_set_g(g, key_size, ag_bin, dh_sess); + if (!ret) + goto free_apriv; + + dh_sess->req.xbytes = BN_bn2bin(priv_key, apriv_key_bin); + dh_sess->req.pbytes = BN_bn2bin(p, ap_bin); + dh_sess->req.x_p = (void *)apriv_key_bin; + dh_sess->req.pri = out_pri; + dh_sess->req.pri_bytes = key_size; + dh_sess->req.op_type = WD_DH_PHASE1; + + OPENSSL_free(ag_bin); + + return ret; + +free_apriv: + OPENSSL_free(apriv_key_bin); +free_ag: + OPENSSL_free(ag_bin); + return UADK_E_FAIL; +} + +static int dh_fill_compkey_req(const BIGNUM *g, const BIGNUM *p, + const BIGNUM *priv_key, const BIGNUM *pub_key, + struct uadk_dh_sess *dh_sess) +{ + __u16 key_size = dh_sess->key_size; + unsigned char *apriv_key_bin; + unsigned char *ap_bin; + unsigned char *ag_bin; + unsigned char *out_pri; + int ret; + + ag_bin = OPENSSL_malloc(key_size); + if (!ag_bin) + return UADK_E_FAIL; + + apriv_key_bin = OPENSSL_malloc(key_size * DH_PARAMS_CNT); + if (!apriv_key_bin) + goto free_ag; + + ap_bin = apriv_key_bin + key_size; + out_pri = ap_bin + key_size; + memset(ag_bin, 0, key_size); + memset(apriv_key_bin, 0, key_size); + memset(ap_bin, 0, key_size); + memset(out_pri, 0, key_size); + + ret = dh_set_g(g, key_size, ag_bin, dh_sess); + if (!ret) + goto free_apriv; + + dh_sess->req.x_p = apriv_key_bin; + dh_sess->req.xbytes = BN_bn2bin(priv_key, apriv_key_bin); + dh_sess->req.pbytes = BN_bn2bin(p, ap_bin); + + dh_sess->req.pv = ag_bin; + dh_sess->req.pvbytes = BN_bn2bin(pub_key, ag_bin); + dh_sess->req.pri = out_pri; + dh_sess->req.pri_bytes = key_size; + dh_sess->req.op_type = WD_DH_PHASE2; + + return ret; + +free_apriv: + OPENSSL_free(apriv_key_bin); +free_ag: + OPENSSL_free(ag_bin); + return UADK_E_FAIL; +} + +static int dh_do_crypto(struct uadk_dh_sess *dh_sess) +{ + struct uadk_e_cb_info cb_param; + struct async_op op; + int idx, ret; + + ret = async_setup_async_event_notification(&op); + if (!ret) { + printf("failed to setup async event notification.\n"); + return UADK_E_FAIL; + } + + if (!op.job) { + ret = wd_do_dh_sync(dh_sess->sess, &dh_sess->req); + if (ret) + return UADK_E_FAIL; + } else { + cb_param.op = &op; + cb_param.priv = &dh_sess->req; + dh_sess->req.cb = uadk_prov_dh_cb; + dh_sess->req.cb_param = &cb_param; + dh_sess->req.status = -1; + ret = async_get_free_task(&idx); + if (!ret) + goto err; + + op.idx = idx; + + do { + ret = wd_do_dh_async(dh_sess->sess, &dh_sess->req); + if (ret < 0 && ret != -EBUSY) { + async_free_poll_task(idx, 0); + goto err; + } + } while (ret == -EBUSY); + + ret = async_pause_job(dh_sess, &op, ASYNC_TASK_DH, idx); + if (!ret) + goto err; + + ret = dh_sess->req.status; + if (ret) + goto err; + } + + return UADK_E_SUCCESS; + +err: + (void)async_clear_async_event_notification(); + return UADK_E_FAIL; +} + +static int dh_soft_set_pkey(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) +{ + const BIGNUM *old_pub = uadk_DH_get0_pub_key(dh); + const BIGNUM *old_priv = uadk_DH_get0_priv_key(dh); + + if (old_pub != pub_key && old_priv != priv_key) + uadk_DH_set0_key(dh, pub_key, priv_key); + else if (old_pub != pub_key) + uadk_DH_set0_key(dh, pub_key, NULL); + else if (old_priv != priv_key) + uadk_DH_set0_key(dh, NULL, priv_key); + + return UADK_E_SUCCESS; +} + +static int uadk_dh_generate_key(DH *dh) +{ + struct uadk_dh_sess *dh_sess = NULL; + BIGNUM *priv_key = NULL; + BIGNUM *pub_key = NULL; + const BIGNUM *p = NULL; + const BIGNUM *g = NULL; + const BIGNUM *q = NULL; + int ret; + + if (!dh) + goto exe_soft; + + ret = uadk_prov_dh_init(); + if (ret) + goto exe_soft; + + uadk_DH_get0_pqg(dh, &p, &q, &g); + if (!p || !g || q) + goto exe_soft; + + /* Get session and prepare private key */ + ret = dh_prepare_data(g, dh, &dh_sess, &priv_key); + if (!ret) { + fprintf(stderr, "prepare dh data failed\n"); + goto exe_soft; + } + + ret = dh_fill_genkey_req(g, p, priv_key, dh_sess); + if (!ret) { + fprintf(stderr, "failed to fill req\n"); + goto free_data; + } + + ret = dh_do_crypto(dh_sess); + if (!ret) { + fprintf(stderr, "failed to generate DH key\n"); + goto free_data; + } + + ret = dh_get_pubkey(dh_sess, &pub_key); + if (!ret) { + fprintf(stderr, "failed to get public key\n"); + goto free_data; + } + + ret = dh_soft_set_pkey(dh, pub_key, priv_key); + dh_free_eng_session(dh_sess); + + return ret; + +free_data: + if (dh_sess->key_flag == KEY_GEN_BY_ENGINE) + BN_free(priv_key); + dh_free_eng_session(dh_sess); +exe_soft: + fprintf(stderr, "switch to execute openssl software calculation.\n"); + return UADK_DO_SOFT; +} + +static int uadk_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, + DH *dh) +{ + struct uadk_dh_sess *dh_sess = NULL; + BIGNUM *priv_key = NULL; + const BIGNUM *p = NULL; + const BIGNUM *g = NULL; + const BIGNUM *q = NULL; + int ret; + + if (!dh || !key || !pub_key || !uadk_DH_get0_priv_key(dh)) + goto exe_soft; + + ret = uadk_prov_dh_init(); + if (ret) + goto exe_soft; + + uadk_DH_get0_pqg(dh, &p, &q, &g); + if (!p || !g) + goto exe_soft; + + ret = dh_prepare_data(g, dh, &dh_sess, &priv_key); + if (!ret) { + fprintf(stderr, "failed to prepare dh data\n"); + goto exe_soft; + } + + ret = dh_fill_compkey_req(g, p, priv_key, pub_key, dh_sess); + if (!ret) { + fprintf(stderr, "failed to fill req\n"); + goto free_data; + } + + ret = dh_do_crypto(dh_sess); + if (!ret) { + fprintf(stderr, "failed to generate DH shared key\n"); + goto free_data; + } + + memcpy(key, dh_sess->req.pri, dh_sess->req.pri_bytes); + ret = dh_sess->req.pri_bytes; + dh_free_eng_session(dh_sess); + + return ret; + +free_data: + if (dh_sess->key_flag == KEY_GEN_BY_ENGINE) + BN_free(priv_key); + dh_free_eng_session(dh_sess); +exe_soft: + fprintf(stderr, "switch to execute openssl software calculation.\n"); + return UADK_DO_SOFT; +} + +static void uadk_ffc_params_init(FFC_PARAMS *params) +{ + memset(params, 0, sizeof(*params)); + params->pcounter = -1; + params->gindex = FFC_UNVERIFIABLE_GINDEX; + params->flags = FFC_PARAM_FLAG_VALIDATE_PQG; +} + +static void uadk_ffc_params_cleanup(FFC_PARAMS *params) +{ + BN_free(params->p); + BN_free(params->q); + BN_free(params->g); + BN_free(params->j); + OPENSSL_free(params->seed); + uadk_ffc_params_init(params); +} + +static void uadk_DH_free(DH *r) +{ + int i; + + if (r == NULL) + return; + + CRYPTO_DOWN_REF(&r->references, &i, r->lock); + if (i > 0) + return; + + if (i < 0) + fprintf(stderr, "WARN: refcount error.\n"); + + if (r->meth != NULL && r->meth->finish != NULL) + r->meth->finish(r); + + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DH, r, &r->ex_data); + + CRYPTO_THREAD_lock_free(r->lock); + + uadk_ffc_params_cleanup(&r->params); + BN_clear_free(r->pub_key); + BN_clear_free(r->priv_key); + OPENSSL_free(r); +} + +static void *uadk_dh_keyexch_newctx(void *provctx) +{ + UADK_PROV_DH_CTX *pdhctx; + + pdhctx = OPENSSL_zalloc(sizeof(UADK_PROV_DH_CTX)); + if (pdhctx == NULL) + return NULL; + pdhctx->libctx = prov_libctx_of(provctx); + pdhctx->kdf_type = PROV_DH_KDF_NONE; + return pdhctx; +} + +/* The 2 parties must share the same domain parameters */ +static int uadk_dh_keyexch_match_params(DH *priv, DH *peer) +{ + int ret; + FFC_PARAMS *dhparams_priv = uadk_dh_get0_params(priv); + FFC_PARAMS *dhparams_peer = uadk_dh_get0_params(peer); + + ret = dhparams_priv != NULL && dhparams_peer != NULL && + uadk_ffc_params_cmp(dhparams_priv, dhparams_peer, 1); + if (!ret) + ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS); + return ret; +} + +static int uadk_dh_keyexch_set_peer(void *vpdhctx, void *vdh) +{ + UADK_PROV_DH_CTX *pdhctx = (UADK_PROV_DH_CTX *)vpdhctx; + + if (pdhctx == NULL || vdh == NULL || + !uadk_dh_keyexch_match_params(vdh, pdhctx->dh) || + !uadk_DH_up_ref(vdh)) + return 0; + uadk_DH_free(pdhctx->dhpeer); + pdhctx->dhpeer = vdh; + return 1; +} + +static int uadk_dh_plain_derive(void *vpdhctx, unsigned char *secret, + size_t *secretlen, size_t outlen) +{ + UADK_PROV_DH_CTX *pdhctx = (UADK_PROV_DH_CTX *)vpdhctx; + const BIGNUM *pub_key = NULL; + size_t dhsize; + int ret; + + if (pdhctx->dh == NULL || pdhctx->dhpeer == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); + return 0; + } + + dhsize = (size_t)uadk_DH_size(pdhctx->dh); + if (secret == NULL) { + *secretlen = dhsize; + return 1; + } + + if (outlen < dhsize) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + uadk_DH_get0_key(pdhctx->dhpeer, &pub_key, NULL); + + ret = uadk_dh_compute_key(secret, pub_key, pdhctx->dh); + if (ret <= 0) + return ret; + + *secretlen = ret; + return 1; +} +static int uadk_dh_keyexch_derive(void *vpdhctx, unsigned char *secret, + size_t *psecretlen, size_t outlen) +{ + typedef int (*fun_ptr)(void *vpdhctx, unsigned char *secret, + size_t *secretlen, size_t outlen); + UADK_PROV_DH_CTX *pdhctx = (UADK_PROV_DH_CTX *)vpdhctx; + int ret = 0; + + switch (pdhctx->kdf_type) { + case PROV_DH_KDF_NONE: + ret = uadk_dh_plain_derive(pdhctx, secret, psecretlen, outlen); + if (ret == UADK_DO_SOFT) + goto exec_soft; + default: + break; + } + return ret; + +exec_soft: + fprintf(stderr, "switch to execute openssl software calculation.\n"); + fun_ptr fun = get_default_keyexch().derive; + + if (!fun) + return 0; + + return fun(vpdhctx, secret, psecretlen, outlen); +} + +static void uadk_dh_keyexch_freectx(void *vpdhctx) +{ + UADK_PROV_DH_CTX *pdhctx = (UADK_PROV_DH_CTX *)vpdhctx; + + OPENSSL_free(pdhctx->kdf_cekalg); + uadk_DH_free(pdhctx->dh); + uadk_DH_free(pdhctx->dhpeer); + EVP_MD_free(pdhctx->kdf_md); + OPENSSL_clear_free(pdhctx->kdf_ukm, pdhctx->kdf_ukmlen); + OPENSSL_free(pdhctx); +} + +static void *uadk_dh_keyexch_dupctx(void *vpdhctx) +{ + UADK_PROV_DH_CTX *srcctx = (UADK_PROV_DH_CTX *)vpdhctx; + UADK_PROV_DH_CTX *dstctx; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) + return NULL; + + *dstctx = *srcctx; + dstctx->dh = NULL; + dstctx->dhpeer = NULL; + dstctx->kdf_md = NULL; + dstctx->kdf_ukm = NULL; + dstctx->kdf_cekalg = NULL; + + if (srcctx->dh != NULL && !uadk_DH_up_ref(srcctx->dh)) + goto err; + else + dstctx->dh = srcctx->dh; + + if (srcctx->dhpeer != NULL && !uadk_DH_up_ref(srcctx->dhpeer)) + goto err; + else + dstctx->dhpeer = srcctx->dhpeer; + + if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md)) + goto err; + else + dstctx->kdf_md = srcctx->kdf_md; + + /* Duplicate UKM data if present */ + if (srcctx->kdf_ukm != NULL && srcctx->kdf_ukmlen > 0) { + dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm, + srcctx->kdf_ukmlen); + if (dstctx->kdf_ukm == NULL) + goto err; + } + + if (srcctx->kdf_cekalg != NULL) { + dstctx->kdf_cekalg = OPENSSL_strdup(srcctx->kdf_cekalg); + if (dstctx->kdf_cekalg == NULL) + goto err; + } + + return dstctx; +err: + uadk_dh_keyexch_freectx(dstctx); + return NULL; +} + +static int uadk_dh_keyexch_set_ctx_params(void *vpdhctx, + const OSSL_PARAM params[]) +{ + UADK_PROV_DH_CTX *pdhctx = (UADK_PROV_DH_CTX *)vpdhctx; + const OSSL_PARAM *p; + unsigned int pad; + char name[80] = {'\0'}; /* should be big enough */ + char *str = NULL; + + if (pdhctx == NULL) + return 0; + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); + if (p != NULL) { + str = name; + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) + return 0; + + if (name[0] == '\0') + pdhctx->kdf_type = PROV_DH_KDF_NONE; + else if (strcmp(name, OSSL_KDF_NAME_X942KDF_ASN1) == 0) + pdhctx->kdf_type = PROV_DH_KDF_X9_42_ASN1; + else + return 0; + } + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); + if (p != NULL) { + char mdprops[80] = {'\0'}; /* should be big enough */ + + str = name; + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) + return 0; + + str = mdprops; + p = OSSL_PARAM_locate_const(params, + OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS); + + if (p != NULL) + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops))) + return 0; + + EVP_MD_free(pdhctx->kdf_md); + pdhctx->kdf_md = EVP_MD_fetch(pdhctx->libctx, name, mdprops); + + if (pdhctx->kdf_md == NULL) + return 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); + if (p != NULL) { + size_t outlen; + + if (!OSSL_PARAM_get_size_t(p, &outlen)) + return 0; + pdhctx->kdf_outlen = outlen; + } + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM); + if (p != NULL) { + void *tmp_ukm = NULL; + size_t tmp_ukmlen; + + OPENSSL_free(pdhctx->kdf_ukm); + pdhctx->kdf_ukm = NULL; + pdhctx->kdf_ukmlen = 0; + /* ukm is an optional field so it can be NULL */ + if (p->data != NULL && p->data_size != 0) { + if (!OSSL_PARAM_get_octet_string(p, &tmp_ukm, 0, &tmp_ukmlen)) + return 0; + pdhctx->kdf_ukm = tmp_ukm; + pdhctx->kdf_ukmlen = tmp_ukmlen; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_PAD); + if (p != NULL) { + if (!OSSL_PARAM_get_uint(p, &pad)) + return 0; + pdhctx->pad = pad ? 1 : 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_CEK_ALG); + if (p != NULL) { + str = name; + + OPENSSL_free(pdhctx->kdf_cekalg); + pdhctx->kdf_cekalg = NULL; + if (p->data != NULL && p->data_size != 0) { + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) + return 0; + pdhctx->kdf_cekalg = OPENSSL_strdup(name); + if (pdhctx->kdf_cekalg == NULL) + return 0; + } + } + return 1; +} + +static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_PAD, NULL), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0), + OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), + OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0), + OSSL_PARAM_END +}; + +static const +OSSL_PARAM *uadk_dh_keyexch_settable_ctx_params(ossl_unused void *vpdhctx, + ossl_unused void *provctx) +{ + return known_settable_ctx_params; +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), + OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), + OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR, + NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0), + OSSL_PARAM_END +}; + +static const +OSSL_PARAM *uadk_dh_keyexch_gettable_ctx_params(ossl_unused void *vpdhctx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +static int uadk_dh_keyexch_get_ctx_params(void *vpdhctx, OSSL_PARAM params[]) +{ + UADK_PROV_DH_CTX *pdhctx = (UADK_PROV_DH_CTX *)vpdhctx; + OSSL_PARAM *p; + + if (pdhctx == NULL) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); + if (p != NULL) { + const char *kdf_type = NULL; + + switch (pdhctx->kdf_type) { + case PROV_DH_KDF_NONE: + kdf_type = ""; + break; + case PROV_DH_KDF_X9_42_ASN1: + kdf_type = OSSL_KDF_NAME_X942KDF_ASN1; + break; + default: + return 0; + } + + if (!OSSL_PARAM_set_utf8_string(p, kdf_type)) + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_md == NULL + ? "" + : EVP_MD_get0_name(pdhctx->kdf_md))) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, pdhctx->kdf_outlen)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM); + if (p != NULL && !OSSL_PARAM_set_octet_ptr(p, pdhctx->kdf_ukm, pdhctx->kdf_ukmlen)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_CEK_ALG); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_cekalg == NULL + ? "" + : pdhctx->kdf_cekalg)) + return 0; + + return 1; +} + +static int uadk_dh_keyexch_init(void *vpdhctx, void *vdh, const OSSL_PARAM params[]) +{ + UADK_PROV_DH_CTX *pdhctx = (UADK_PROV_DH_CTX *)vpdhctx; + + if (pdhctx == NULL || vdh == NULL || !uadk_DH_up_ref(vdh)) + return 0; + uadk_DH_free(pdhctx->dh); + pdhctx->dh = vdh; + pdhctx->kdf_type = PROV_DH_KDF_NONE; + return uadk_dh_keyexch_set_ctx_params(pdhctx, params); +} + +static UADK_DH_KEYMGMT get_default_keymgmt(void) +{ + static UADK_DH_KEYMGMT s_keymgmt; + static int initilazed; + + if (!initilazed) { + UADK_DH_KEYMGMT *keymgmt = + (UADK_DH_KEYMGMT *)EVP_KEYMGMT_fetch(NULL, "DH", "provider=default"); + + if (keymgmt) { + s_keymgmt = *keymgmt; + EVP_KEYMGMT_free((EVP_KEYMGMT *)keymgmt); + initilazed = 1; + } else { + fprintf(stderr, "WARN: EVP_KEYMGMT_fetch from default provider failed"); + } + } + return s_keymgmt; +} + +static void *uadk_dh_keymgmt_newdata(void *provctx) +{ + typedef void *(*fun_ptr)(void *); + fun_ptr fun = get_default_keymgmt().new; + + if (!fun) + return NULL; + return fun(provctx); +} + +static void uadk_dh_keymgmt_freedata(void *keydata) +{ + typedef void (*fun_ptr)(void *); + fun_ptr fun = get_default_keymgmt().free; + + if (!fun) + return; + fun(keydata); +} + +static int uadk_dh_keymgmt_has(const void *keydata, int selection) +{ + typedef int (*fun_ptr)(const void *, int); + fun_ptr fun = get_default_keymgmt().has; + + if (!fun) + return 0; + return fun(keydata, selection); +} + +static int uadk_dh_keymgmt_match(const void *keydata1, const void *keydata2, int selection) +{ + typedef int (*fun_ptr)(const void *, const void *, int); + fun_ptr fun = get_default_keymgmt().match; + + if (!fun) + return 0; + return fun(keydata1, keydata2, selection); +} + +static int uadk_dh_keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + typedef int (*fun_ptr)(void *, int, const OSSL_PARAM *); + fun_ptr fun = get_default_keymgmt().import; + + if (!fun) + return 0; + return fun(keydata, selection, params); +} + +static int uadk_dh_keymgmt_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, + void *cbarg) +{ + typedef int (*fun_ptr)(void *, int, OSSL_CALLBACK *, void *); + fun_ptr fun = get_default_keymgmt().export; + + if (!fun) + return 0; + return fun(keydata, selection, param_cb, cbarg); +} + +static const OSSL_PARAM *uadk_dh_keymgmt_import_types(int selection) +{ + typedef const OSSL_PARAM *(*fun_ptr)(int); + fun_ptr fun = get_default_keymgmt().import_types; + + if (!fun) + return NULL; + return fun(selection); +} + +static const OSSL_PARAM *uadk_dh_keymgmt_export_types(int selection) +{ + typedef const OSSL_PARAM *(*fun_ptr)(int); + fun_ptr fun = get_default_keymgmt().export_types; + + if (!fun) + return NULL; + return fun(selection); +} + +static ossl_inline int uadk_dh_keymgmt_get_params(void *key, OSSL_PARAM params[]) +{ + typedef int (*fun_ptr)(void *, OSSL_PARAM *); + fun_ptr fun = get_default_keymgmt().get_params; + + if (!fun) + return 0; + return fun(key, params); +} + +static const OSSL_PARAM *uadk_dh_keymgmt_gettable_params(void *provctx) +{ + typedef const OSSL_PARAM *(*fun_ptr)(void *); + fun_ptr fun = get_default_keymgmt().gettable_params; + + if (!fun) + return NULL; + return fun(provctx); +} + +static const OSSL_PARAM *uadk_dh_keymgmt_settable_params(void *provctx) +{ + typedef const OSSL_PARAM *(*fun_ptr)(void *); + fun_ptr fun = get_default_keymgmt().settable_params; + + if (!fun) + return NULL; + return fun(provctx); +} + +static int uadk_dh_keymgmt_set_params(void *key, const OSSL_PARAM params[]) +{ + typedef int (*fun_ptr)(void *, const OSSL_PARAM *); + fun_ptr fun = get_default_keymgmt().set_params; + + if (!fun) + return 0; + return fun(key, params); +} + +static int uadk_dh_keymgmt_validate(const void *keydata, int selection, int checktype) +{ + typedef int (*fun_ptr)(const void *, int, int); + fun_ptr fun = get_default_keymgmt().validate; + + if (!fun) + return 0; + return fun(keydata, selection, checktype); +} + +static void *uadk_dh_keymgmt_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + typedef void *(*fun_ptr)(void *, int, const OSSL_PARAM *); + fun_ptr fun = get_default_keymgmt().gen_init; + + if (!fun) + return NULL; + return fun(provctx, selection, params); +} + +static int uadk_dh_keymgmt_gen_set_template(void *genctx, void *templ) +{ + typedef int (*fun_ptr)(void *, void *); + fun_ptr fun = get_default_keymgmt().gen_set_template; + + if (!fun) + return 0; + return fun(genctx, templ); +} + +static const +OSSL_PARAM *uadk_dh_keymgmt_gen_settable_params(ossl_unused void *genctx, + ossl_unused void *provctx) +{ + typedef const OSSL_PARAM *(*fun_ptr)(void *, void *); + fun_ptr fun = get_default_keymgmt().gen_settable_params; + + if (!fun) + return NULL; + return fun(genctx, provctx); +} + +static int uadk_dh_keymgmt_gen_set_params(void *genctx, + const OSSL_PARAM params[]) +{ + typedef int (*fun_ptr)(void *, const OSSL_PARAM *); + fun_ptr fun = get_default_keymgmt().gen_set_params; + + if (!fun) + return 0; + return fun(genctx, params); +} + +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 DH *ossl_dh_new_ex(OSSL_LIB_CTX *libctx) +{ + DH *ret = OPENSSL_zalloc(sizeof(*ret)); + + if (ret == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE); + return NULL; + } + + ret->references = 1; + ret->lock = CRYPTO_THREAD_lock_new(); + if (ret->lock == NULL) { + ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); + OPENSSL_free(ret); + return NULL; + } + + ret->libctx = libctx; + + return ret; +} + +static void *uadk_dh_keymgmt_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) +{ + typedef void* (*fun_ptr)(void *, OSSL_CALLBACK *, void *); + struct dh_gen_ctx *gctx = genctx; + DH *dh = NULL; + BN_GENCB *gencb = NULL; + FFC_PARAMS *ffc; + fun_ptr fun; + int ret; + + if (gctx == NULL) + return NULL; + + dh = ossl_dh_new_ex(gctx->libctx); + if (dh == NULL) + return NULL; + ffc = uadk_ossl_dh_get0_params(dh); + if (gctx->ffc_params != NULL + && !ossl_ffc_params_copy(ffc, gctx->ffc_params)) + goto exec_soft; + if (!ossl_ffc_params_set_seed(ffc, gctx->seed, gctx->seedlen)) + goto exec_soft; + gctx->cb = osslcb; + gctx->cbarg = cbarg; + gencb = BN_GENCB_new(); + if (gencb != NULL) + BN_GENCB_set(gencb, dh_gencb, genctx); + + + ret = uadk_dh_generate_key(dh); + if (ret == UADK_DO_SOFT) + goto exec_soft; + uadk_DH_clear_flags(dh, DH_FLAG_TYPE_MASK); + uadk_DH_set_flags(dh, gctx->dh_type); + BN_GENCB_free(gencb); + return dh; + +exec_soft: + if (dh) + uadk_dh_keymgmt_freedata(dh); + if (gencb) + BN_GENCB_free(gencb); + fun = get_default_keymgmt().gen; + if (!fun) + return NULL; + return fun(genctx, osslcb, cbarg); +} + +static void uadk_dh_keymgmt_gen_cleanup(void *genctx) +{ + typedef void (*fun_ptr)(void *); + fun_ptr fun = get_default_keymgmt().gen_cleanup; + + if (!fun) + return; + fun(genctx); +} + +static void *uadk_dh_keymgmt_load(const void *reference, size_t reference_sz) +{ + typedef void *(*fun_ptr)(const void *, size_t); + fun_ptr fun = get_default_keymgmt().load; + + if (!fun) + return NULL; + return fun(reference, reference_sz); +} + +static void *uadk_dh_keymgmt_dup(const void *keydata_from, int selection) +{ + typedef void *(*fun_ptr)(const void *, int); + fun_ptr fun = get_default_keymgmt().dup; + + if (!fun) + return NULL; + return fun(keydata_from, selection); +} + +const OSSL_DISPATCH uadk_dh_keyexch_functions[] = { + {OSSL_FUNC_KEYEXCH_NEWCTX, + (void (*)(void))uadk_dh_keyexch_newctx}, + {OSSL_FUNC_KEYEXCH_INIT, + (void (*)(void))uadk_dh_keyexch_init}, + {OSSL_FUNC_KEYEXCH_DERIVE, + (void (*)(void))uadk_dh_keyexch_derive}, + {OSSL_FUNC_KEYEXCH_SET_PEER, + (void (*)(void))uadk_dh_keyexch_set_peer}, + {OSSL_FUNC_KEYEXCH_FREECTX, + (void (*)(void))uadk_dh_keyexch_freectx}, + {OSSL_FUNC_KEYEXCH_DUPCTX, + (void (*)(void))uadk_dh_keyexch_dupctx}, + {OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, + (void (*)(void))uadk_dh_keyexch_set_ctx_params}, + {OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS, + (void (*)(void))uadk_dh_keyexch_settable_ctx_params}, + {OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, + (void (*)(void))uadk_dh_keyexch_get_ctx_params}, + {OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS, + (void (*)(void))uadk_dh_keyexch_gettable_ctx_params}, + {0, NULL} +}; + +const OSSL_DISPATCH uadk_dh_keymgmt_functions[] = { + {OSSL_FUNC_KEYMGMT_NEW, + (void (*)(void))uadk_dh_keymgmt_newdata}, + {OSSL_FUNC_KEYMGMT_GEN_INIT, + (void (*)(void))uadk_dh_keymgmt_gen_init}, + {OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE, + (void (*)(void))uadk_dh_keymgmt_gen_set_template}, + {OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, + (void (*)(void))uadk_dh_keymgmt_gen_set_params}, + {OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, + (void (*)(void))uadk_dh_keymgmt_gen_settable_params}, + {OSSL_FUNC_KEYMGMT_GEN, + (void (*)(void))uadk_dh_keymgmt_gen}, + {OSSL_FUNC_KEYMGMT_GEN_CLEANUP, + (void (*)(void))uadk_dh_keymgmt_gen_cleanup}, + {OSSL_FUNC_KEYMGMT_LOAD, + (void (*)(void))uadk_dh_keymgmt_load}, + {OSSL_FUNC_KEYMGMT_FREE, + (void (*)(void))uadk_dh_keymgmt_freedata}, + {OSSL_FUNC_KEYMGMT_GET_PARAMS, + (void (*)(void))uadk_dh_keymgmt_get_params}, + {OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, + (void (*)(void))uadk_dh_keymgmt_gettable_params}, + {OSSL_FUNC_KEYMGMT_SET_PARAMS, + (void (*)(void))uadk_dh_keymgmt_set_params}, + {OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, + (void (*)(void))uadk_dh_keymgmt_settable_params}, + {OSSL_FUNC_KEYMGMT_HAS, + (void (*)(void))uadk_dh_keymgmt_has}, + {OSSL_FUNC_KEYMGMT_MATCH, + (void (*)(void))uadk_dh_keymgmt_match}, + {OSSL_FUNC_KEYMGMT_VALIDATE, + (void (*)(void))uadk_dh_keymgmt_validate}, + {OSSL_FUNC_KEYMGMT_IMPORT, + (void (*)(void))uadk_dh_keymgmt_import}, + {OSSL_FUNC_KEYMGMT_IMPORT_TYPES, + (void (*)(void))uadk_dh_keymgmt_import_types}, + {OSSL_FUNC_KEYMGMT_EXPORT, + (void (*)(void))uadk_dh_keymgmt_export}, + {OSSL_FUNC_KEYMGMT_EXPORT_TYPES, + (void (*)(void))uadk_dh_keymgmt_export_types}, + {OSSL_FUNC_KEYMGMT_DUP, + (void (*)(void))uadk_dh_keymgmt_dup}, + {0, NULL} +}; + +void uadk_prov_destroy_dh(void) +{ + pthread_mutex_lock(&dh_mutex); + if (g_dh_res.pid == getpid()) { + wd_dh_uninit2(); + g_dh_res.pid = 0; + } + pthread_mutex_lock(&dh_mutex); +} diff --git a/src/uadk_prov_init.c b/src/uadk_prov_init.c index fc09b64..c3d4a63 100644 --- a/src/uadk_prov_init.c +++ b/src/uadk_prov_init.c @@ -78,15 +78,16 @@ const OSSL_ALGORITHM uadk_prov_ciphers[] = { }; static const OSSL_ALGORITHM uadk_prov_signature[] = { - {"RSA", UADK_DEFAULT_PROPERTIES, - uadk_rsa_signature_functions, "uadk_provider rsa_signature" }, - {NULL, NULL, NULL} + { "RSA", UADK_DEFAULT_PROPERTIES, + uadk_rsa_signature_functions, "uadk_provider rsa_signature" }, + { NULL, NULL, NULL } }; static const OSSL_ALGORITHM uadk_prov_keymgmt[] = { - {"RSA", UADK_DEFAULT_PROPERTIES, - uadk_rsa_keymgmt_functions, "uadk RSA Keymgmt implementation."}, - {NULL, NULL, NULL} + { "RSA", UADK_DEFAULT_PROPERTIES, + uadk_rsa_keymgmt_functions, "uadk RSA Keymgmt implementation." }, + { "DH", UADK_DEFAULT_PROPERTIES, uadk_dh_keymgmt_functions }, + { NULL, NULL, NULL } }; static const OSSL_ALGORITHM uadk_prov_asym_cipher[] = { @@ -94,6 +95,12 @@ static const OSSL_ALGORITHM uadk_prov_asym_cipher[] = { { NULL, NULL, NULL } }; +static const OSSL_ALGORITHM uadk_prov_keyexch[] = { + { "DH", UADK_DEFAULT_PROPERTIES, + uadk_dh_keyexch_functions, "UADK DH keyexch implementation"}, + { NULL, NULL, NULL } +}; + static const OSSL_ALGORITHM *uadk_query(void *provctx, int operation_id, int *no_cache) { @@ -120,6 +127,8 @@ static const OSSL_ALGORITHM *uadk_query(void *provctx, int operation_id, return uadk_prov_keymgmt; case OSSL_OP_ASYM_CIPHER: return uadk_prov_asym_cipher; + case OSSL_OP_KEYEXCH: + return uadk_prov_keyexch; case OSSL_OP_STORE: return prov->query_operation(provctx, operation_id, no_cache); } -- 2.25.1