1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci/*
11e1051a39Sopenharmony_ci * DH low level APIs are deprecated for public use, but still ok for
12e1051a39Sopenharmony_ci * internal use.
13e1051a39Sopenharmony_ci */
14e1051a39Sopenharmony_ci#include "internal/deprecated.h"
15e1051a39Sopenharmony_ci
16e1051a39Sopenharmony_ci#include <string.h>
17e1051a39Sopenharmony_ci#include <openssl/crypto.h>
18e1051a39Sopenharmony_ci#include <openssl/core_dispatch.h>
19e1051a39Sopenharmony_ci#include <openssl/core_names.h>
20e1051a39Sopenharmony_ci#include <openssl/dh.h>
21e1051a39Sopenharmony_ci#include <openssl/err.h>
22e1051a39Sopenharmony_ci#include <openssl/proverr.h>
23e1051a39Sopenharmony_ci#include <openssl/params.h>
24e1051a39Sopenharmony_ci#include "prov/providercommon.h"
25e1051a39Sopenharmony_ci#include "prov/implementations.h"
26e1051a39Sopenharmony_ci#include "prov/provider_ctx.h"
27e1051a39Sopenharmony_ci#include "prov/securitycheck.h"
28e1051a39Sopenharmony_ci#include "crypto/dh.h"
29e1051a39Sopenharmony_ci
30e1051a39Sopenharmony_cistatic OSSL_FUNC_keyexch_newctx_fn dh_newctx;
31e1051a39Sopenharmony_cistatic OSSL_FUNC_keyexch_init_fn dh_init;
32e1051a39Sopenharmony_cistatic OSSL_FUNC_keyexch_set_peer_fn dh_set_peer;
33e1051a39Sopenharmony_cistatic OSSL_FUNC_keyexch_derive_fn dh_derive;
34e1051a39Sopenharmony_cistatic OSSL_FUNC_keyexch_freectx_fn dh_freectx;
35e1051a39Sopenharmony_cistatic OSSL_FUNC_keyexch_dupctx_fn dh_dupctx;
36e1051a39Sopenharmony_cistatic OSSL_FUNC_keyexch_set_ctx_params_fn dh_set_ctx_params;
37e1051a39Sopenharmony_cistatic OSSL_FUNC_keyexch_settable_ctx_params_fn dh_settable_ctx_params;
38e1051a39Sopenharmony_cistatic OSSL_FUNC_keyexch_get_ctx_params_fn dh_get_ctx_params;
39e1051a39Sopenharmony_cistatic OSSL_FUNC_keyexch_gettable_ctx_params_fn dh_gettable_ctx_params;
40e1051a39Sopenharmony_ci
41e1051a39Sopenharmony_ci/*
42e1051a39Sopenharmony_ci * This type is only really used to handle some legacy related functionality.
43e1051a39Sopenharmony_ci * If you need to use other KDF's (such as SSKDF) just use PROV_DH_KDF_NONE
44e1051a39Sopenharmony_ci * here and then create and run a KDF after the key is derived.
45e1051a39Sopenharmony_ci * Note that X942 has 2 variants of key derivation:
46e1051a39Sopenharmony_ci *   (1) DH_KDF_X9_42_ASN1 - which contains an ANS1 encoded object that has
47e1051a39Sopenharmony_ci *   the counter embedded in it.
48e1051a39Sopenharmony_ci *   (2) DH_KDF_X941_CONCAT - which is the same as ECDH_X963_KDF (which can be
49e1051a39Sopenharmony_ci *       done by creating a "X963KDF".
50e1051a39Sopenharmony_ci */
51e1051a39Sopenharmony_cienum kdf_type {
52e1051a39Sopenharmony_ci    PROV_DH_KDF_NONE = 0,
53e1051a39Sopenharmony_ci    PROV_DH_KDF_X9_42_ASN1
54e1051a39Sopenharmony_ci};
55e1051a39Sopenharmony_ci
56e1051a39Sopenharmony_ci/*
57e1051a39Sopenharmony_ci * What's passed as an actual key is defined by the KEYMGMT interface.
58e1051a39Sopenharmony_ci * We happen to know that our KEYMGMT simply passes DH structures, so
59e1051a39Sopenharmony_ci * we use that here too.
60e1051a39Sopenharmony_ci */
61e1051a39Sopenharmony_ci
62e1051a39Sopenharmony_citypedef struct {
63e1051a39Sopenharmony_ci    OSSL_LIB_CTX *libctx;
64e1051a39Sopenharmony_ci    DH *dh;
65e1051a39Sopenharmony_ci    DH *dhpeer;
66e1051a39Sopenharmony_ci    unsigned int pad : 1;
67e1051a39Sopenharmony_ci
68e1051a39Sopenharmony_ci    /* DH KDF */
69e1051a39Sopenharmony_ci    /* KDF (if any) to use for DH */
70e1051a39Sopenharmony_ci    enum kdf_type kdf_type;
71e1051a39Sopenharmony_ci    /* Message digest to use for key derivation */
72e1051a39Sopenharmony_ci    EVP_MD *kdf_md;
73e1051a39Sopenharmony_ci    /* User key material */
74e1051a39Sopenharmony_ci    unsigned char *kdf_ukm;
75e1051a39Sopenharmony_ci    size_t kdf_ukmlen;
76e1051a39Sopenharmony_ci    /* KDF output length */
77e1051a39Sopenharmony_ci    size_t kdf_outlen;
78e1051a39Sopenharmony_ci    char *kdf_cekalg;
79e1051a39Sopenharmony_ci} PROV_DH_CTX;
80e1051a39Sopenharmony_ci
81e1051a39Sopenharmony_cistatic void *dh_newctx(void *provctx)
82e1051a39Sopenharmony_ci{
83e1051a39Sopenharmony_ci    PROV_DH_CTX *pdhctx;
84e1051a39Sopenharmony_ci
85e1051a39Sopenharmony_ci    if (!ossl_prov_is_running())
86e1051a39Sopenharmony_ci        return NULL;
87e1051a39Sopenharmony_ci
88e1051a39Sopenharmony_ci    pdhctx = OPENSSL_zalloc(sizeof(PROV_DH_CTX));
89e1051a39Sopenharmony_ci    if (pdhctx == NULL)
90e1051a39Sopenharmony_ci        return NULL;
91e1051a39Sopenharmony_ci    pdhctx->libctx = PROV_LIBCTX_OF(provctx);
92e1051a39Sopenharmony_ci    pdhctx->kdf_type = PROV_DH_KDF_NONE;
93e1051a39Sopenharmony_ci    return pdhctx;
94e1051a39Sopenharmony_ci}
95e1051a39Sopenharmony_ci
96e1051a39Sopenharmony_cistatic int dh_init(void *vpdhctx, void *vdh, const OSSL_PARAM params[])
97e1051a39Sopenharmony_ci{
98e1051a39Sopenharmony_ci    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
99e1051a39Sopenharmony_ci
100e1051a39Sopenharmony_ci    if (!ossl_prov_is_running()
101e1051a39Sopenharmony_ci            || pdhctx == NULL
102e1051a39Sopenharmony_ci            || vdh == NULL
103e1051a39Sopenharmony_ci            || !DH_up_ref(vdh))
104e1051a39Sopenharmony_ci        return 0;
105e1051a39Sopenharmony_ci    DH_free(pdhctx->dh);
106e1051a39Sopenharmony_ci    pdhctx->dh = vdh;
107e1051a39Sopenharmony_ci    pdhctx->kdf_type = PROV_DH_KDF_NONE;
108e1051a39Sopenharmony_ci    return dh_set_ctx_params(pdhctx, params)
109e1051a39Sopenharmony_ci           && ossl_dh_check_key(pdhctx->libctx, vdh);
110e1051a39Sopenharmony_ci}
111e1051a39Sopenharmony_ci
112e1051a39Sopenharmony_ci/* The 2 parties must share the same domain parameters */
113e1051a39Sopenharmony_cistatic int dh_match_params(DH *priv, DH *peer)
114e1051a39Sopenharmony_ci{
115e1051a39Sopenharmony_ci    int ret;
116e1051a39Sopenharmony_ci    FFC_PARAMS *dhparams_priv = ossl_dh_get0_params(priv);
117e1051a39Sopenharmony_ci    FFC_PARAMS *dhparams_peer = ossl_dh_get0_params(peer);
118e1051a39Sopenharmony_ci
119e1051a39Sopenharmony_ci    ret = dhparams_priv != NULL
120e1051a39Sopenharmony_ci          && dhparams_peer != NULL
121e1051a39Sopenharmony_ci          && ossl_ffc_params_cmp(dhparams_priv, dhparams_peer, 1);
122e1051a39Sopenharmony_ci    if (!ret)
123e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS);
124e1051a39Sopenharmony_ci    return ret;
125e1051a39Sopenharmony_ci}
126e1051a39Sopenharmony_ci
127e1051a39Sopenharmony_cistatic int dh_set_peer(void *vpdhctx, void *vdh)
128e1051a39Sopenharmony_ci{
129e1051a39Sopenharmony_ci    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
130e1051a39Sopenharmony_ci
131e1051a39Sopenharmony_ci    if (!ossl_prov_is_running()
132e1051a39Sopenharmony_ci            || pdhctx == NULL
133e1051a39Sopenharmony_ci            || vdh == NULL
134e1051a39Sopenharmony_ci            || !dh_match_params(vdh, pdhctx->dh)
135e1051a39Sopenharmony_ci            || !DH_up_ref(vdh))
136e1051a39Sopenharmony_ci        return 0;
137e1051a39Sopenharmony_ci    DH_free(pdhctx->dhpeer);
138e1051a39Sopenharmony_ci    pdhctx->dhpeer = vdh;
139e1051a39Sopenharmony_ci    return 1;
140e1051a39Sopenharmony_ci}
141e1051a39Sopenharmony_ci
142e1051a39Sopenharmony_cistatic int dh_plain_derive(void *vpdhctx,
143e1051a39Sopenharmony_ci                           unsigned char *secret, size_t *secretlen,
144e1051a39Sopenharmony_ci                           size_t outlen, unsigned int pad)
145e1051a39Sopenharmony_ci{
146e1051a39Sopenharmony_ci    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
147e1051a39Sopenharmony_ci    int ret;
148e1051a39Sopenharmony_ci    size_t dhsize;
149e1051a39Sopenharmony_ci    const BIGNUM *pub_key = NULL;
150e1051a39Sopenharmony_ci
151e1051a39Sopenharmony_ci    if (pdhctx->dh == NULL || pdhctx->dhpeer == NULL) {
152e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
153e1051a39Sopenharmony_ci        return 0;
154e1051a39Sopenharmony_ci    }
155e1051a39Sopenharmony_ci
156e1051a39Sopenharmony_ci    dhsize = (size_t)DH_size(pdhctx->dh);
157e1051a39Sopenharmony_ci    if (secret == NULL) {
158e1051a39Sopenharmony_ci        *secretlen = dhsize;
159e1051a39Sopenharmony_ci        return 1;
160e1051a39Sopenharmony_ci    }
161e1051a39Sopenharmony_ci    if (outlen < dhsize) {
162e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
163e1051a39Sopenharmony_ci        return 0;
164e1051a39Sopenharmony_ci    }
165e1051a39Sopenharmony_ci
166e1051a39Sopenharmony_ci    DH_get0_key(pdhctx->dhpeer, &pub_key, NULL);
167e1051a39Sopenharmony_ci    if (pad)
168e1051a39Sopenharmony_ci        ret = DH_compute_key_padded(secret, pub_key, pdhctx->dh);
169e1051a39Sopenharmony_ci    else
170e1051a39Sopenharmony_ci        ret = DH_compute_key(secret, pub_key, pdhctx->dh);
171e1051a39Sopenharmony_ci    if (ret <= 0)
172e1051a39Sopenharmony_ci        return 0;
173e1051a39Sopenharmony_ci
174e1051a39Sopenharmony_ci    *secretlen = ret;
175e1051a39Sopenharmony_ci    return 1;
176e1051a39Sopenharmony_ci}
177e1051a39Sopenharmony_ci
178e1051a39Sopenharmony_cistatic int dh_X9_42_kdf_derive(void *vpdhctx, unsigned char *secret,
179e1051a39Sopenharmony_ci                               size_t *secretlen, size_t outlen)
180e1051a39Sopenharmony_ci{
181e1051a39Sopenharmony_ci    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
182e1051a39Sopenharmony_ci    unsigned char *stmp = NULL;
183e1051a39Sopenharmony_ci    size_t stmplen;
184e1051a39Sopenharmony_ci    int ret = 0;
185e1051a39Sopenharmony_ci
186e1051a39Sopenharmony_ci    if (secret == NULL) {
187e1051a39Sopenharmony_ci        *secretlen = pdhctx->kdf_outlen;
188e1051a39Sopenharmony_ci        return 1;
189e1051a39Sopenharmony_ci    }
190e1051a39Sopenharmony_ci
191e1051a39Sopenharmony_ci    if (pdhctx->kdf_outlen > outlen) {
192e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
193e1051a39Sopenharmony_ci        return 0;
194e1051a39Sopenharmony_ci    }
195e1051a39Sopenharmony_ci    if (!dh_plain_derive(pdhctx, NULL, &stmplen, 0, 1))
196e1051a39Sopenharmony_ci        return 0;
197e1051a39Sopenharmony_ci    if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL) {
198e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
199e1051a39Sopenharmony_ci        return 0;
200e1051a39Sopenharmony_ci    }
201e1051a39Sopenharmony_ci    if (!dh_plain_derive(pdhctx, stmp, &stmplen, stmplen, 1))
202e1051a39Sopenharmony_ci        goto err;
203e1051a39Sopenharmony_ci
204e1051a39Sopenharmony_ci    /* Do KDF stuff */
205e1051a39Sopenharmony_ci    if (pdhctx->kdf_type == PROV_DH_KDF_X9_42_ASN1) {
206e1051a39Sopenharmony_ci        if (!ossl_dh_kdf_X9_42_asn1(secret, pdhctx->kdf_outlen,
207e1051a39Sopenharmony_ci                                    stmp, stmplen,
208e1051a39Sopenharmony_ci                                    pdhctx->kdf_cekalg,
209e1051a39Sopenharmony_ci                                    pdhctx->kdf_ukm,
210e1051a39Sopenharmony_ci                                    pdhctx->kdf_ukmlen,
211e1051a39Sopenharmony_ci                                    pdhctx->kdf_md,
212e1051a39Sopenharmony_ci                                    pdhctx->libctx, NULL))
213e1051a39Sopenharmony_ci            goto err;
214e1051a39Sopenharmony_ci    }
215e1051a39Sopenharmony_ci    *secretlen = pdhctx->kdf_outlen;
216e1051a39Sopenharmony_ci    ret = 1;
217e1051a39Sopenharmony_cierr:
218e1051a39Sopenharmony_ci    OPENSSL_secure_clear_free(stmp, stmplen);
219e1051a39Sopenharmony_ci    return ret;
220e1051a39Sopenharmony_ci}
221e1051a39Sopenharmony_ci
222e1051a39Sopenharmony_cistatic int dh_derive(void *vpdhctx, unsigned char *secret,
223e1051a39Sopenharmony_ci                     size_t *psecretlen, size_t outlen)
224e1051a39Sopenharmony_ci{
225e1051a39Sopenharmony_ci    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
226e1051a39Sopenharmony_ci
227e1051a39Sopenharmony_ci    if (!ossl_prov_is_running())
228e1051a39Sopenharmony_ci        return 0;
229e1051a39Sopenharmony_ci
230e1051a39Sopenharmony_ci    switch (pdhctx->kdf_type) {
231e1051a39Sopenharmony_ci        case PROV_DH_KDF_NONE:
232e1051a39Sopenharmony_ci            return dh_plain_derive(pdhctx, secret, psecretlen, outlen,
233e1051a39Sopenharmony_ci                                   pdhctx->pad);
234e1051a39Sopenharmony_ci        case PROV_DH_KDF_X9_42_ASN1:
235e1051a39Sopenharmony_ci            return dh_X9_42_kdf_derive(pdhctx, secret, psecretlen, outlen);
236e1051a39Sopenharmony_ci        default:
237e1051a39Sopenharmony_ci            break;
238e1051a39Sopenharmony_ci    }
239e1051a39Sopenharmony_ci    return 0;
240e1051a39Sopenharmony_ci}
241e1051a39Sopenharmony_ci
242e1051a39Sopenharmony_cistatic void dh_freectx(void *vpdhctx)
243e1051a39Sopenharmony_ci{
244e1051a39Sopenharmony_ci    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
245e1051a39Sopenharmony_ci
246e1051a39Sopenharmony_ci    OPENSSL_free(pdhctx->kdf_cekalg);
247e1051a39Sopenharmony_ci    DH_free(pdhctx->dh);
248e1051a39Sopenharmony_ci    DH_free(pdhctx->dhpeer);
249e1051a39Sopenharmony_ci    EVP_MD_free(pdhctx->kdf_md);
250e1051a39Sopenharmony_ci    OPENSSL_clear_free(pdhctx->kdf_ukm, pdhctx->kdf_ukmlen);
251e1051a39Sopenharmony_ci
252e1051a39Sopenharmony_ci    OPENSSL_free(pdhctx);
253e1051a39Sopenharmony_ci}
254e1051a39Sopenharmony_ci
255e1051a39Sopenharmony_cistatic void *dh_dupctx(void *vpdhctx)
256e1051a39Sopenharmony_ci{
257e1051a39Sopenharmony_ci    PROV_DH_CTX *srcctx = (PROV_DH_CTX *)vpdhctx;
258e1051a39Sopenharmony_ci    PROV_DH_CTX *dstctx;
259e1051a39Sopenharmony_ci
260e1051a39Sopenharmony_ci    if (!ossl_prov_is_running())
261e1051a39Sopenharmony_ci        return NULL;
262e1051a39Sopenharmony_ci
263e1051a39Sopenharmony_ci    dstctx = OPENSSL_zalloc(sizeof(*srcctx));
264e1051a39Sopenharmony_ci    if (dstctx == NULL)
265e1051a39Sopenharmony_ci        return NULL;
266e1051a39Sopenharmony_ci
267e1051a39Sopenharmony_ci    *dstctx = *srcctx;
268e1051a39Sopenharmony_ci    dstctx->dh = NULL;
269e1051a39Sopenharmony_ci    dstctx->dhpeer = NULL;
270e1051a39Sopenharmony_ci    dstctx->kdf_md = NULL;
271e1051a39Sopenharmony_ci    dstctx->kdf_ukm = NULL;
272e1051a39Sopenharmony_ci    dstctx->kdf_cekalg = NULL;
273e1051a39Sopenharmony_ci
274e1051a39Sopenharmony_ci    if (srcctx->dh != NULL && !DH_up_ref(srcctx->dh))
275e1051a39Sopenharmony_ci        goto err;
276e1051a39Sopenharmony_ci    else
277e1051a39Sopenharmony_ci        dstctx->dh = srcctx->dh;
278e1051a39Sopenharmony_ci
279e1051a39Sopenharmony_ci    if (srcctx->dhpeer != NULL && !DH_up_ref(srcctx->dhpeer))
280e1051a39Sopenharmony_ci        goto err;
281e1051a39Sopenharmony_ci    else
282e1051a39Sopenharmony_ci        dstctx->dhpeer = srcctx->dhpeer;
283e1051a39Sopenharmony_ci
284e1051a39Sopenharmony_ci    if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md))
285e1051a39Sopenharmony_ci        goto err;
286e1051a39Sopenharmony_ci    else
287e1051a39Sopenharmony_ci        dstctx->kdf_md = srcctx->kdf_md;
288e1051a39Sopenharmony_ci
289e1051a39Sopenharmony_ci    /* Duplicate UKM data if present */
290e1051a39Sopenharmony_ci    if (srcctx->kdf_ukm != NULL && srcctx->kdf_ukmlen > 0) {
291e1051a39Sopenharmony_ci        dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm,
292e1051a39Sopenharmony_ci                                         srcctx->kdf_ukmlen);
293e1051a39Sopenharmony_ci        if (dstctx->kdf_ukm == NULL)
294e1051a39Sopenharmony_ci            goto err;
295e1051a39Sopenharmony_ci    }
296e1051a39Sopenharmony_ci
297e1051a39Sopenharmony_ci    if (srcctx->kdf_cekalg != NULL) {
298e1051a39Sopenharmony_ci        dstctx->kdf_cekalg = OPENSSL_strdup(srcctx->kdf_cekalg);
299e1051a39Sopenharmony_ci        if (dstctx->kdf_cekalg == NULL)
300e1051a39Sopenharmony_ci            goto err;
301e1051a39Sopenharmony_ci    }
302e1051a39Sopenharmony_ci
303e1051a39Sopenharmony_ci    return dstctx;
304e1051a39Sopenharmony_cierr:
305e1051a39Sopenharmony_ci    dh_freectx(dstctx);
306e1051a39Sopenharmony_ci    return NULL;
307e1051a39Sopenharmony_ci}
308e1051a39Sopenharmony_ci
309e1051a39Sopenharmony_cistatic int dh_set_ctx_params(void *vpdhctx, const OSSL_PARAM params[])
310e1051a39Sopenharmony_ci{
311e1051a39Sopenharmony_ci    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
312e1051a39Sopenharmony_ci    const OSSL_PARAM *p;
313e1051a39Sopenharmony_ci    unsigned int pad;
314e1051a39Sopenharmony_ci    char name[80] = { '\0' }; /* should be big enough */
315e1051a39Sopenharmony_ci    char *str = NULL;
316e1051a39Sopenharmony_ci
317e1051a39Sopenharmony_ci    if (pdhctx == NULL)
318e1051a39Sopenharmony_ci        return 0;
319e1051a39Sopenharmony_ci    if (params == NULL)
320e1051a39Sopenharmony_ci        return 1;
321e1051a39Sopenharmony_ci
322e1051a39Sopenharmony_ci    p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);
323e1051a39Sopenharmony_ci    if (p != NULL) {
324e1051a39Sopenharmony_ci        str = name;
325e1051a39Sopenharmony_ci        if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))
326e1051a39Sopenharmony_ci            return 0;
327e1051a39Sopenharmony_ci
328e1051a39Sopenharmony_ci        if (name[0] == '\0')
329e1051a39Sopenharmony_ci            pdhctx->kdf_type = PROV_DH_KDF_NONE;
330e1051a39Sopenharmony_ci        else if (strcmp(name, OSSL_KDF_NAME_X942KDF_ASN1) == 0)
331e1051a39Sopenharmony_ci            pdhctx->kdf_type = PROV_DH_KDF_X9_42_ASN1;
332e1051a39Sopenharmony_ci        else
333e1051a39Sopenharmony_ci            return 0;
334e1051a39Sopenharmony_ci    }
335e1051a39Sopenharmony_ci    p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);
336e1051a39Sopenharmony_ci    if (p != NULL) {
337e1051a39Sopenharmony_ci        char mdprops[80] = { '\0' }; /* should be big enough */
338e1051a39Sopenharmony_ci
339e1051a39Sopenharmony_ci        str = name;
340e1051a39Sopenharmony_ci        if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))
341e1051a39Sopenharmony_ci            return 0;
342e1051a39Sopenharmony_ci
343e1051a39Sopenharmony_ci        str = mdprops;
344e1051a39Sopenharmony_ci        p = OSSL_PARAM_locate_const(params,
345e1051a39Sopenharmony_ci                                    OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS);
346e1051a39Sopenharmony_ci
347e1051a39Sopenharmony_ci        if (p != NULL) {
348e1051a39Sopenharmony_ci            if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops)))
349e1051a39Sopenharmony_ci                return 0;
350e1051a39Sopenharmony_ci        }
351e1051a39Sopenharmony_ci
352e1051a39Sopenharmony_ci        EVP_MD_free(pdhctx->kdf_md);
353e1051a39Sopenharmony_ci        pdhctx->kdf_md = EVP_MD_fetch(pdhctx->libctx, name, mdprops);
354e1051a39Sopenharmony_ci        if (!ossl_digest_is_allowed(pdhctx->libctx, pdhctx->kdf_md)) {
355e1051a39Sopenharmony_ci            EVP_MD_free(pdhctx->kdf_md);
356e1051a39Sopenharmony_ci            pdhctx->kdf_md = NULL;
357e1051a39Sopenharmony_ci        }
358e1051a39Sopenharmony_ci        if (pdhctx->kdf_md == NULL)
359e1051a39Sopenharmony_ci            return 0;
360e1051a39Sopenharmony_ci    }
361e1051a39Sopenharmony_ci
362e1051a39Sopenharmony_ci    p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);
363e1051a39Sopenharmony_ci    if (p != NULL) {
364e1051a39Sopenharmony_ci        size_t outlen;
365e1051a39Sopenharmony_ci
366e1051a39Sopenharmony_ci        if (!OSSL_PARAM_get_size_t(p, &outlen))
367e1051a39Sopenharmony_ci            return 0;
368e1051a39Sopenharmony_ci        pdhctx->kdf_outlen = outlen;
369e1051a39Sopenharmony_ci    }
370e1051a39Sopenharmony_ci
371e1051a39Sopenharmony_ci    p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM);
372e1051a39Sopenharmony_ci    if (p != NULL) {
373e1051a39Sopenharmony_ci        void *tmp_ukm = NULL;
374e1051a39Sopenharmony_ci        size_t tmp_ukmlen;
375e1051a39Sopenharmony_ci
376e1051a39Sopenharmony_ci        OPENSSL_free(pdhctx->kdf_ukm);
377e1051a39Sopenharmony_ci        pdhctx->kdf_ukm = NULL;
378e1051a39Sopenharmony_ci        pdhctx->kdf_ukmlen = 0;
379e1051a39Sopenharmony_ci        /* ukm is an optional field so it can be NULL */
380e1051a39Sopenharmony_ci        if (p->data != NULL && p->data_size != 0) {
381e1051a39Sopenharmony_ci            if (!OSSL_PARAM_get_octet_string(p, &tmp_ukm, 0, &tmp_ukmlen))
382e1051a39Sopenharmony_ci                return 0;
383e1051a39Sopenharmony_ci            pdhctx->kdf_ukm = tmp_ukm;
384e1051a39Sopenharmony_ci            pdhctx->kdf_ukmlen = tmp_ukmlen;
385e1051a39Sopenharmony_ci        }
386e1051a39Sopenharmony_ci    }
387e1051a39Sopenharmony_ci
388e1051a39Sopenharmony_ci    p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_PAD);
389e1051a39Sopenharmony_ci    if (p != NULL) {
390e1051a39Sopenharmony_ci        if (!OSSL_PARAM_get_uint(p, &pad))
391e1051a39Sopenharmony_ci            return 0;
392e1051a39Sopenharmony_ci        pdhctx->pad = pad ? 1 : 0;
393e1051a39Sopenharmony_ci    }
394e1051a39Sopenharmony_ci
395e1051a39Sopenharmony_ci    p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_CEK_ALG);
396e1051a39Sopenharmony_ci    if (p != NULL) {
397e1051a39Sopenharmony_ci        str = name;
398e1051a39Sopenharmony_ci
399e1051a39Sopenharmony_ci        OPENSSL_free(pdhctx->kdf_cekalg);
400e1051a39Sopenharmony_ci        pdhctx->kdf_cekalg = NULL;
401e1051a39Sopenharmony_ci        if (p->data != NULL && p->data_size != 0) {
402e1051a39Sopenharmony_ci            if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))
403e1051a39Sopenharmony_ci                return 0;
404e1051a39Sopenharmony_ci            pdhctx->kdf_cekalg = OPENSSL_strdup(name);
405e1051a39Sopenharmony_ci            if (pdhctx->kdf_cekalg == NULL)
406e1051a39Sopenharmony_ci                return 0;
407e1051a39Sopenharmony_ci        }
408e1051a39Sopenharmony_ci    }
409e1051a39Sopenharmony_ci    return 1;
410e1051a39Sopenharmony_ci}
411e1051a39Sopenharmony_ci
412e1051a39Sopenharmony_cistatic const OSSL_PARAM known_settable_ctx_params[] = {
413e1051a39Sopenharmony_ci    OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_PAD, NULL),
414e1051a39Sopenharmony_ci    OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),
415e1051a39Sopenharmony_ci    OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),
416e1051a39Sopenharmony_ci    OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0),
417e1051a39Sopenharmony_ci    OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),
418e1051a39Sopenharmony_ci    OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0),
419e1051a39Sopenharmony_ci    OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0),
420e1051a39Sopenharmony_ci    OSSL_PARAM_END
421e1051a39Sopenharmony_ci};
422e1051a39Sopenharmony_ci
423e1051a39Sopenharmony_cistatic const OSSL_PARAM *dh_settable_ctx_params(ossl_unused void *vpdhctx,
424e1051a39Sopenharmony_ci                                                ossl_unused void *provctx)
425e1051a39Sopenharmony_ci{
426e1051a39Sopenharmony_ci    return known_settable_ctx_params;
427e1051a39Sopenharmony_ci}
428e1051a39Sopenharmony_ci
429e1051a39Sopenharmony_cistatic const OSSL_PARAM known_gettable_ctx_params[] = {
430e1051a39Sopenharmony_ci    OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),
431e1051a39Sopenharmony_ci    OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),
432e1051a39Sopenharmony_ci    OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),
433e1051a39Sopenharmony_ci    OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR,
434e1051a39Sopenharmony_ci                    NULL, 0),
435e1051a39Sopenharmony_ci    OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0),
436e1051a39Sopenharmony_ci    OSSL_PARAM_END
437e1051a39Sopenharmony_ci};
438e1051a39Sopenharmony_ci
439e1051a39Sopenharmony_cistatic const OSSL_PARAM *dh_gettable_ctx_params(ossl_unused void *vpdhctx,
440e1051a39Sopenharmony_ci                                                ossl_unused void *provctx)
441e1051a39Sopenharmony_ci{
442e1051a39Sopenharmony_ci    return known_gettable_ctx_params;
443e1051a39Sopenharmony_ci}
444e1051a39Sopenharmony_ci
445e1051a39Sopenharmony_cistatic int dh_get_ctx_params(void *vpdhctx, OSSL_PARAM params[])
446e1051a39Sopenharmony_ci{
447e1051a39Sopenharmony_ci    PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
448e1051a39Sopenharmony_ci    OSSL_PARAM *p;
449e1051a39Sopenharmony_ci
450e1051a39Sopenharmony_ci    if (pdhctx == NULL)
451e1051a39Sopenharmony_ci        return 0;
452e1051a39Sopenharmony_ci
453e1051a39Sopenharmony_ci    p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);
454e1051a39Sopenharmony_ci    if (p != NULL) {
455e1051a39Sopenharmony_ci        const char *kdf_type = NULL;
456e1051a39Sopenharmony_ci
457e1051a39Sopenharmony_ci        switch (pdhctx->kdf_type) {
458e1051a39Sopenharmony_ci            case PROV_DH_KDF_NONE:
459e1051a39Sopenharmony_ci                kdf_type = "";
460e1051a39Sopenharmony_ci                break;
461e1051a39Sopenharmony_ci            case PROV_DH_KDF_X9_42_ASN1:
462e1051a39Sopenharmony_ci                kdf_type = OSSL_KDF_NAME_X942KDF_ASN1;
463e1051a39Sopenharmony_ci                break;
464e1051a39Sopenharmony_ci            default:
465e1051a39Sopenharmony_ci                return 0;
466e1051a39Sopenharmony_ci        }
467e1051a39Sopenharmony_ci
468e1051a39Sopenharmony_ci        if (!OSSL_PARAM_set_utf8_string(p, kdf_type))
469e1051a39Sopenharmony_ci            return 0;
470e1051a39Sopenharmony_ci    }
471e1051a39Sopenharmony_ci
472e1051a39Sopenharmony_ci    p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);
473e1051a39Sopenharmony_ci    if (p != NULL
474e1051a39Sopenharmony_ci            && !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_md == NULL
475e1051a39Sopenharmony_ci                                           ? ""
476e1051a39Sopenharmony_ci                                           : EVP_MD_get0_name(pdhctx->kdf_md))){
477e1051a39Sopenharmony_ci        return 0;
478e1051a39Sopenharmony_ci    }
479e1051a39Sopenharmony_ci
480e1051a39Sopenharmony_ci    p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);
481e1051a39Sopenharmony_ci    if (p != NULL && !OSSL_PARAM_set_size_t(p, pdhctx->kdf_outlen))
482e1051a39Sopenharmony_ci        return 0;
483e1051a39Sopenharmony_ci
484e1051a39Sopenharmony_ci    p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM);
485e1051a39Sopenharmony_ci    if (p != NULL
486e1051a39Sopenharmony_ci        && !OSSL_PARAM_set_octet_ptr(p, pdhctx->kdf_ukm, pdhctx->kdf_ukmlen))
487e1051a39Sopenharmony_ci        return 0;
488e1051a39Sopenharmony_ci
489e1051a39Sopenharmony_ci    p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_CEK_ALG);
490e1051a39Sopenharmony_ci    if (p != NULL
491e1051a39Sopenharmony_ci            && !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_cekalg == NULL
492e1051a39Sopenharmony_ci                                           ? "" :  pdhctx->kdf_cekalg))
493e1051a39Sopenharmony_ci        return 0;
494e1051a39Sopenharmony_ci
495e1051a39Sopenharmony_ci    return 1;
496e1051a39Sopenharmony_ci}
497e1051a39Sopenharmony_ci
498e1051a39Sopenharmony_ciconst OSSL_DISPATCH ossl_dh_keyexch_functions[] = {
499e1051a39Sopenharmony_ci    { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))dh_newctx },
500e1051a39Sopenharmony_ci    { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))dh_init },
501e1051a39Sopenharmony_ci    { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))dh_derive },
502e1051a39Sopenharmony_ci    { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))dh_set_peer },
503e1051a39Sopenharmony_ci    { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))dh_freectx },
504e1051a39Sopenharmony_ci    { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))dh_dupctx },
505e1051a39Sopenharmony_ci    { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))dh_set_ctx_params },
506e1051a39Sopenharmony_ci    { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS,
507e1051a39Sopenharmony_ci      (void (*)(void))dh_settable_ctx_params },
508e1051a39Sopenharmony_ci    { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))dh_get_ctx_params },
509e1051a39Sopenharmony_ci    { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS,
510e1051a39Sopenharmony_ci      (void (*)(void))dh_gettable_ctx_params },
511e1051a39Sopenharmony_ci    { 0, NULL }
512e1051a39Sopenharmony_ci};
513