Coverage Report

Created: 2026-02-22 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/providers/implementations/exchange/ecdh_exch.c
Line
Count
Source
1
/*
2
 * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 */
9
10
/*
11
 * ECDH low level APIs are deprecated for public use, but still ok for
12
 * internal use.
13
 */
14
#include "internal/deprecated.h"
15
16
#include <string.h>
17
#include <openssl/crypto.h>
18
#include <openssl/evp.h>
19
#include <openssl/core_dispatch.h>
20
#include <openssl/core_names.h>
21
#include <openssl/ec.h>
22
#include <openssl/params.h>
23
#include <openssl/err.h>
24
#include <openssl/proverr.h>
25
#include "internal/cryptlib.h"
26
#include "internal/fips.h"
27
#include "prov/provider_ctx.h"
28
#include "prov/providercommon.h"
29
#include "prov/implementations.h"
30
#include "prov/securitycheck.h"
31
#include "crypto/ec.h" /* ossl_ecdh_kdf_X9_63() */
32
#include "providers/implementations/exchange/ecdh_exch.inc"
33
34
static OSSL_FUNC_keyexch_newctx_fn ecdh_newctx;
35
static OSSL_FUNC_keyexch_init_fn ecdh_init;
36
static OSSL_FUNC_keyexch_set_peer_fn ecdh_set_peer;
37
static OSSL_FUNC_keyexch_derive_fn ecdh_derive;
38
static OSSL_FUNC_keyexch_derive_skey_fn ecdh_derive_skey;
39
static OSSL_FUNC_keyexch_freectx_fn ecdh_freectx;
40
static OSSL_FUNC_keyexch_dupctx_fn ecdh_dupctx;
41
static OSSL_FUNC_keyexch_set_ctx_params_fn ecdh_set_ctx_params;
42
static OSSL_FUNC_keyexch_settable_ctx_params_fn ecdh_settable_ctx_params;
43
static OSSL_FUNC_keyexch_get_ctx_params_fn ecdh_get_ctx_params;
44
static OSSL_FUNC_keyexch_gettable_ctx_params_fn ecdh_gettable_ctx_params;
45
46
enum kdf_type {
47
    PROV_ECDH_KDF_NONE = 0,
48
    PROV_ECDH_KDF_X9_63
49
};
50
51
/*
52
 * What's passed as an actual key is defined by the KEYMGMT interface.
53
 * We happen to know that our KEYMGMT simply passes EC_KEY structures, so
54
 * we use that here too.
55
 */
56
57
typedef struct {
58
    OSSL_LIB_CTX *libctx;
59
60
    EC_KEY *k;
61
    EC_KEY *peerk;
62
63
    /*
64
     * ECDH cofactor mode:
65
     *
66
     *  . 0  disabled
67
     *  . 1  enabled
68
     *  . -1 use cofactor mode set for k
69
     */
70
    int cofactor_mode;
71
72
    /************
73
     * ECDH KDF *
74
     ************/
75
    /* KDF (if any) to use for ECDH */
76
    enum kdf_type kdf_type;
77
    /* Message digest to use for key derivation */
78
    EVP_MD *kdf_md;
79
    /* User key material */
80
    unsigned char *kdf_ukm;
81
    size_t kdf_ukmlen;
82
    /* KDF output length */
83
    size_t kdf_outlen;
84
    OSSL_FIPS_IND_DECLARE
85
} PROV_ECDH_CTX;
86
87
static void *ecdh_newctx(void *provctx)
88
0
{
89
0
    PROV_ECDH_CTX *pectx;
90
91
0
    if (!ossl_prov_is_running())
92
0
        return NULL;
93
94
#ifdef FIPS_MODULE
95
    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
96
            ST_ID_KA_ECDH))
97
        return NULL;
98
#endif
99
100
0
    pectx = OPENSSL_zalloc(sizeof(*pectx));
101
0
    if (pectx == NULL)
102
0
        return NULL;
103
104
0
    pectx->libctx = PROV_LIBCTX_OF(provctx);
105
0
    pectx->cofactor_mode = -1;
106
0
    pectx->kdf_type = PROV_ECDH_KDF_NONE;
107
0
    OSSL_FIPS_IND_INIT(pectx)
108
109
0
    return (void *)pectx;
110
0
}
111
112
static int ecdh_init(void *vpecdhctx, void *vecdh, const OSSL_PARAM params[])
113
0
{
114
0
    PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
115
116
0
    if (!ossl_prov_is_running()
117
0
        || pecdhctx == NULL
118
0
        || vecdh == NULL
119
0
        || (EC_KEY_get0_group(vecdh) == NULL)
120
0
        || !EC_KEY_up_ref(vecdh))
121
0
        return 0;
122
0
    EC_KEY_free(pecdhctx->k);
123
0
    pecdhctx->k = vecdh;
124
0
    pecdhctx->cofactor_mode = -1;
125
0
    pecdhctx->kdf_type = PROV_ECDH_KDF_NONE;
126
127
0
    OSSL_FIPS_IND_SET_APPROVED(pecdhctx)
128
0
    if (!ecdh_set_ctx_params(pecdhctx, params))
129
0
        return 0;
130
#ifdef FIPS_MODULE
131
    if (!ossl_fips_ind_ec_key_check(OSSL_FIPS_IND_GET(pecdhctx),
132
            OSSL_FIPS_IND_SETTABLE0, pecdhctx->libctx,
133
            EC_KEY_get0_group(vecdh), "ECDH Init", 1))
134
        return 0;
135
#endif
136
0
    return 1;
137
0
}
138
139
static int ecdh_match_params(const EC_KEY *priv, const EC_KEY *peer)
140
0
{
141
0
    int ret;
142
0
    BN_CTX *ctx = NULL;
143
0
    const EC_GROUP *group_priv = EC_KEY_get0_group(priv);
144
0
    const EC_GROUP *group_peer = EC_KEY_get0_group(peer);
145
146
0
    ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(priv));
147
0
    if (ctx == NULL) {
148
0
        ERR_raise(ERR_LIB_PROV, ERR_R_BN_LIB);
149
0
        return 0;
150
0
    }
151
0
    ret = group_priv != NULL
152
0
        && group_peer != NULL
153
0
        && EC_GROUP_cmp(group_priv, group_peer, ctx) == 0;
154
0
    if (!ret)
155
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS);
156
0
    BN_CTX_free(ctx);
157
0
    return ret;
158
0
}
159
160
static int ecdh_set_peer(void *vpecdhctx, void *vecdh)
161
0
{
162
0
    PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
163
164
0
    if (!ossl_prov_is_running()
165
0
        || pecdhctx == NULL
166
0
        || vecdh == NULL
167
0
        || !ecdh_match_params(pecdhctx->k, vecdh))
168
0
        return 0;
169
#ifdef FIPS_MODULE
170
    if (!ossl_fips_ind_ec_key_check(OSSL_FIPS_IND_GET(pecdhctx),
171
            OSSL_FIPS_IND_SETTABLE0, pecdhctx->libctx,
172
            EC_KEY_get0_group(vecdh), "ECDH Set Peer",
173
            1))
174
        return 0;
175
#endif
176
0
    if (!EC_KEY_up_ref(vecdh))
177
0
        return 0;
178
179
0
    EC_KEY_free(pecdhctx->peerk);
180
0
    pecdhctx->peerk = vecdh;
181
0
    return 1;
182
0
}
183
184
static void ecdh_freectx(void *vpecdhctx)
185
0
{
186
0
    PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
187
188
0
    EC_KEY_free(pecdhctx->k);
189
0
    EC_KEY_free(pecdhctx->peerk);
190
191
0
    EVP_MD_free(pecdhctx->kdf_md);
192
0
    OPENSSL_clear_free(pecdhctx->kdf_ukm, pecdhctx->kdf_ukmlen);
193
194
0
    OPENSSL_free(pecdhctx);
195
0
}
196
197
static void *ecdh_dupctx(void *vpecdhctx)
198
0
{
199
0
    PROV_ECDH_CTX *srcctx = (PROV_ECDH_CTX *)vpecdhctx;
200
0
    PROV_ECDH_CTX *dstctx;
201
202
0
    if (!ossl_prov_is_running())
203
0
        return NULL;
204
205
0
    dstctx = OPENSSL_zalloc(sizeof(*srcctx));
206
0
    if (dstctx == NULL)
207
0
        return NULL;
208
209
0
    *dstctx = *srcctx;
210
211
    /* clear all pointers */
212
213
0
    dstctx->k = NULL;
214
0
    dstctx->peerk = NULL;
215
0
    dstctx->kdf_md = NULL;
216
0
    dstctx->kdf_ukm = NULL;
217
218
    /* up-ref all ref-counted objects referenced in dstctx */
219
220
0
    if (srcctx->k != NULL && !EC_KEY_up_ref(srcctx->k))
221
0
        goto err;
222
0
    else
223
0
        dstctx->k = srcctx->k;
224
225
0
    if (srcctx->peerk != NULL && !EC_KEY_up_ref(srcctx->peerk))
226
0
        goto err;
227
0
    else
228
0
        dstctx->peerk = srcctx->peerk;
229
230
0
    if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md))
231
0
        goto err;
232
0
    else
233
0
        dstctx->kdf_md = srcctx->kdf_md;
234
235
    /* Duplicate UKM data if present */
236
0
    if (srcctx->kdf_ukm != NULL && srcctx->kdf_ukmlen > 0) {
237
0
        dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm,
238
0
            srcctx->kdf_ukmlen);
239
0
        if (dstctx->kdf_ukm == NULL)
240
0
            goto err;
241
0
    }
242
243
0
    return dstctx;
244
245
0
err:
246
0
    ecdh_freectx(dstctx);
247
0
    return NULL;
248
0
}
249
250
static int ecdh_set_ctx_params(void *vpecdhctx, const OSSL_PARAM params[])
251
0
{
252
0
    char name[80] = { '\0' }; /* should be big enough */
253
0
    char *str = NULL;
254
0
    PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx;
255
0
    struct ecdh_set_ctx_params_st p;
256
257
0
    if (pectx == NULL || !ecdh_set_ctx_params_decoder(params, &p))
258
0
        return 0;
259
260
0
    if (!OSSL_FIPS_IND_SET_CTX_FROM_PARAM(pectx, OSSL_FIPS_IND_SETTABLE0, p.ind_k))
261
0
        return 0;
262
0
    if (!OSSL_FIPS_IND_SET_CTX_FROM_PARAM(pectx, OSSL_FIPS_IND_SETTABLE1, p.ind_d))
263
0
        return 0;
264
0
    if (!OSSL_FIPS_IND_SET_CTX_FROM_PARAM(pectx, OSSL_FIPS_IND_SETTABLE2, p.ind_cofac))
265
0
        return 0;
266
267
0
    if (p.mode != NULL) {
268
0
        int mode;
269
270
0
        if (!OSSL_PARAM_get_int(p.mode, &mode))
271
0
            return 0;
272
273
0
        if (mode < -1 || mode > 1)
274
0
            return 0;
275
276
0
        pectx->cofactor_mode = mode;
277
0
    }
278
279
0
    if (p.kdf != NULL) {
280
0
        str = name;
281
0
        if (!OSSL_PARAM_get_utf8_string(p.kdf, &str, sizeof(name)))
282
0
            return 0;
283
284
0
        if (name[0] == '\0')
285
0
            pectx->kdf_type = PROV_ECDH_KDF_NONE;
286
0
        else if (strcmp(name, OSSL_KDF_NAME_X963KDF) == 0)
287
0
            pectx->kdf_type = PROV_ECDH_KDF_X9_63;
288
0
        else
289
0
            return 0;
290
0
    }
291
292
0
    if (p.digest != NULL) {
293
0
        char mdprops[80] = { '\0' }; /* should be big enough */
294
295
0
        str = name;
296
0
        if (!OSSL_PARAM_get_utf8_string(p.digest, &str, sizeof(name)))
297
0
            return 0;
298
299
0
        str = mdprops;
300
0
        if (p.propq != NULL) {
301
0
            if (!OSSL_PARAM_get_utf8_string(p.propq, &str, sizeof(mdprops)))
302
0
                return 0;
303
0
        }
304
305
0
        EVP_MD_free(pectx->kdf_md);
306
0
        pectx->kdf_md = EVP_MD_fetch(pectx->libctx, name, mdprops);
307
0
        if (pectx->kdf_md == NULL)
308
0
            return 0;
309
        /* XOF digests are not allowed */
310
0
        if (EVP_MD_xof(pectx->kdf_md)) {
311
0
            ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED);
312
0
            return 0;
313
0
        }
314
#ifdef FIPS_MODULE
315
        if (!ossl_fips_ind_digest_exch_check(OSSL_FIPS_IND_GET(pectx),
316
                OSSL_FIPS_IND_SETTABLE1, pectx->libctx,
317
                pectx->kdf_md, "ECDH Set Ctx")) {
318
            EVP_MD_free(pectx->kdf_md);
319
            pectx->kdf_md = NULL;
320
            return 0;
321
        }
322
#endif
323
0
    }
324
325
0
    if (p.len != NULL) {
326
0
        size_t outlen;
327
328
0
        if (!OSSL_PARAM_get_size_t(p.len, &outlen))
329
0
            return 0;
330
0
        pectx->kdf_outlen = outlen;
331
0
    }
332
333
0
    if (p.ukm != NULL) {
334
0
        void *tmp_ukm = NULL;
335
0
        size_t tmp_ukmlen;
336
337
0
        if (!OSSL_PARAM_get_octet_string(p.ukm, &tmp_ukm, 0, &tmp_ukmlen))
338
0
            return 0;
339
0
        OPENSSL_free(pectx->kdf_ukm);
340
0
        pectx->kdf_ukm = tmp_ukm;
341
0
        pectx->kdf_ukmlen = tmp_ukmlen;
342
0
    }
343
344
0
    return 1;
345
0
}
346
347
static const OSSL_PARAM *ecdh_settable_ctx_params(ossl_unused void *vpecdhctx,
348
    ossl_unused void *provctx)
349
0
{
350
0
    return ecdh_set_ctx_params_list;
351
0
}
352
353
static int ecdh_get_ctx_params(void *vpecdhctx, OSSL_PARAM params[])
354
0
{
355
0
    PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx;
356
0
    struct ecdh_get_ctx_params_st p;
357
358
0
    if (pectx == NULL || !ecdh_get_ctx_params_decoder(params, &p))
359
0
        return 0;
360
361
0
    if (p.mode != NULL) {
362
0
        int mode = pectx->cofactor_mode;
363
364
0
        if (mode == -1) {
365
            /* check what is the default for pecdhctx->k */
366
0
            mode = EC_KEY_get_flags(pectx->k) & EC_FLAG_COFACTOR_ECDH ? 1 : 0;
367
0
        }
368
369
0
        if (!OSSL_PARAM_set_int(p.mode, mode))
370
0
            return 0;
371
0
    }
372
373
0
    if (p.kdf != NULL) {
374
0
        const char *kdf_type = NULL;
375
376
0
        switch (pectx->kdf_type) {
377
0
        case PROV_ECDH_KDF_NONE:
378
0
            kdf_type = "";
379
0
            break;
380
0
        case PROV_ECDH_KDF_X9_63:
381
0
            kdf_type = OSSL_KDF_NAME_X963KDF;
382
0
            break;
383
0
        default:
384
0
            return 0;
385
0
        }
386
387
0
        if (!OSSL_PARAM_set_utf8_string(p.kdf, kdf_type))
388
0
            return 0;
389
0
    }
390
391
0
    if (p.digest != NULL
392
0
        && !OSSL_PARAM_set_utf8_string(p.digest, pectx->kdf_md == NULL ? "" : EVP_MD_get0_name(pectx->kdf_md))) {
393
0
        return 0;
394
0
    }
395
396
0
    if (p.len != NULL && !OSSL_PARAM_set_size_t(p.len, pectx->kdf_outlen))
397
0
        return 0;
398
399
0
    if (p.ukm != NULL && !OSSL_PARAM_set_octet_ptr(p.ukm, pectx->kdf_ukm, pectx->kdf_ukmlen))
400
0
        return 0;
401
402
0
    if (!OSSL_FIPS_IND_GET_CTX_FROM_PARAM(pectx, p.ind))
403
0
        return 0;
404
0
    return 1;
405
0
}
406
407
static const OSSL_PARAM *ecdh_gettable_ctx_params(ossl_unused void *vpecdhctx,
408
    ossl_unused void *provctx)
409
0
{
410
0
    return ecdh_get_ctx_params_list;
411
0
}
412
413
static ossl_inline
414
    size_t
415
    ecdh_size(const EC_KEY *k)
416
0
{
417
0
    size_t degree = 0;
418
0
    const EC_GROUP *group;
419
420
0
    if (k == NULL
421
0
        || (group = EC_KEY_get0_group(k)) == NULL)
422
0
        return 0;
423
424
0
    degree = EC_GROUP_get_degree(group);
425
426
0
    return (degree + 7) / 8;
427
0
}
428
429
static ossl_inline int ecdh_plain_derive(void *vpecdhctx, unsigned char *secret,
430
    size_t *psecretlen, size_t outlen)
431
0
{
432
0
    PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
433
0
    int retlen, ret = 0;
434
0
    size_t ecdhsize, size;
435
0
    const EC_POINT *ppubkey = NULL;
436
0
    EC_KEY *privk = NULL;
437
0
    const EC_GROUP *group;
438
0
    const BIGNUM *cofactor;
439
0
    int key_cofactor_mode;
440
0
    int has_cofactor;
441
#ifdef FIPS_MODULE
442
    int cofactor_approved = 0;
443
#endif
444
445
0
    if (pecdhctx->k == NULL || pecdhctx->peerk == NULL) {
446
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
447
0
        return 0;
448
0
    }
449
450
0
    ecdhsize = ecdh_size(pecdhctx->k);
451
0
    if (secret == NULL) {
452
0
        *psecretlen = ecdhsize;
453
0
        return 1;
454
0
    }
455
456
0
    if ((group = EC_KEY_get0_group(pecdhctx->k)) == NULL
457
0
        || (cofactor = EC_GROUP_get0_cofactor(group)) == NULL)
458
0
        return 0;
459
460
0
    has_cofactor = !BN_is_one(cofactor);
461
462
    /*
463
     * NB: unlike PKCS#3 DH, if outlen is less than maximum size this is not
464
     * an error, the result is truncated.
465
     */
466
0
    size = outlen < ecdhsize ? outlen : ecdhsize;
467
468
    /*
469
     * The ctx->cofactor_mode flag has precedence over the
470
     * cofactor_mode flag set on ctx->k.
471
     *
472
     * - if ctx->cofactor_mode == -1, use ctx->k directly
473
     * - if ctx->cofactor_mode == key_cofactor_mode, use ctx->k directly
474
     * - if ctx->cofactor_mode != key_cofactor_mode:
475
     *     - if ctx->k->cofactor == 1, the cofactor_mode flag is irrelevant, use
476
     *          ctx->k directly
477
     *     - if ctx->k->cofactor != 1, use a duplicate of ctx->k with the flag
478
     *          set to ctx->cofactor_mode
479
     */
480
0
    key_cofactor_mode = (EC_KEY_get_flags(pecdhctx->k) & EC_FLAG_COFACTOR_ECDH) ? 1 : 0;
481
0
    if (pecdhctx->cofactor_mode != -1
482
0
        && pecdhctx->cofactor_mode != key_cofactor_mode
483
0
        && has_cofactor) {
484
0
        if ((privk = EC_KEY_dup(pecdhctx->k)) == NULL)
485
0
            return 0;
486
487
0
        if (pecdhctx->cofactor_mode == 1) {
488
0
            EC_KEY_set_flags(privk, EC_FLAG_COFACTOR_ECDH);
489
#ifdef FIPS_MODULE
490
            cofactor_approved = 1;
491
#endif
492
0
        } else {
493
0
            EC_KEY_clear_flags(privk, EC_FLAG_COFACTOR_ECDH);
494
0
        }
495
0
    } else {
496
0
        privk = pecdhctx->k;
497
#ifdef FIPS_MODULE
498
        cofactor_approved = key_cofactor_mode;
499
#endif
500
0
    }
501
502
#ifdef FIPS_MODULE
503
    /*
504
     * SP800-56A r3 Section 5.7.1.2 requires ECC Cofactor DH to be used.
505
     * This applies to the 'B' and 'K' curves that have cofactors that are not 1.
506
     */
507
    if (has_cofactor && !cofactor_approved) {
508
        if (!OSSL_FIPS_IND_ON_UNAPPROVED(pecdhctx, OSSL_FIPS_IND_SETTABLE2,
509
                pecdhctx->libctx, "ECDH", "Cofactor",
510
                ossl_fips_config_ecdh_cofactor_check)) {
511
            ERR_raise(ERR_LIB_PROV, PROV_R_COFACTOR_REQUIRED);
512
            goto end;
513
        }
514
    }
515
#endif
516
517
0
    ppubkey = EC_KEY_get0_public_key(pecdhctx->peerk);
518
519
0
    retlen = ECDH_compute_key(secret, size, ppubkey, privk, NULL);
520
521
0
    if (retlen <= 0)
522
0
        goto end;
523
524
0
    *psecretlen = retlen;
525
0
    ret = 1;
526
527
0
end:
528
0
    if (privk != pecdhctx->k)
529
0
        EC_KEY_free(privk);
530
0
    return ret;
531
0
}
532
533
static ossl_inline int ecdh_X9_63_kdf_derive(void *vpecdhctx, unsigned char *secret,
534
    size_t *psecretlen, size_t outlen)
535
0
{
536
0
    PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
537
0
    unsigned char *stmp = NULL;
538
0
    size_t stmplen;
539
0
    int ret = 0;
540
541
0
    if (secret == NULL) {
542
0
        *psecretlen = pecdhctx->kdf_outlen;
543
0
        return 1;
544
0
    }
545
546
0
    if (pecdhctx->kdf_outlen > outlen) {
547
0
        ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
548
0
        return 0;
549
0
    }
550
0
    if (!ecdh_plain_derive(vpecdhctx, NULL, &stmplen, 0))
551
0
        return 0;
552
0
    if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL)
553
0
        return 0;
554
0
    if (!ecdh_plain_derive(vpecdhctx, stmp, &stmplen, stmplen))
555
0
        goto err;
556
557
    /* Do KDF stuff */
558
0
    if (!ossl_ecdh_kdf_X9_63(secret, pecdhctx->kdf_outlen,
559
0
            stmp, stmplen,
560
0
            pecdhctx->kdf_ukm,
561
0
            pecdhctx->kdf_ukmlen,
562
0
            pecdhctx->kdf_md,
563
0
            pecdhctx->libctx, NULL))
564
0
        goto err;
565
0
    *psecretlen = pecdhctx->kdf_outlen;
566
0
    ret = 1;
567
568
0
err:
569
0
    OPENSSL_secure_clear_free(stmp, stmplen);
570
0
    return ret;
571
0
}
572
573
static int ecdh_derive(void *vpecdhctx, unsigned char *secret,
574
    size_t *psecretlen, size_t outlen)
575
0
{
576
0
    PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
577
578
0
    switch (pecdhctx->kdf_type) {
579
0
    case PROV_ECDH_KDF_NONE:
580
0
        return ecdh_plain_derive(vpecdhctx, secret, psecretlen, outlen);
581
0
    case PROV_ECDH_KDF_X9_63:
582
0
        return ecdh_X9_63_kdf_derive(vpecdhctx, secret, psecretlen, outlen);
583
0
    default:
584
0
        break;
585
0
    }
586
0
    return 0;
587
0
}
588
589
static void *ecdh_derive_skey(void *vpecdhctx, const char *key_type ossl_unused,
590
    void *provctx, OSSL_FUNC_skeymgmt_import_fn *import,
591
    size_t outlen, const OSSL_PARAM params_in[] ossl_unused)
592
0
{
593
0
    unsigned char *secret = NULL;
594
0
    size_t secretlen = 0;
595
0
    void *ret = NULL;
596
0
    OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
597
598
0
    if (import == NULL || outlen == 0)
599
0
        return NULL;
600
601
0
    if (ecdh_derive(vpecdhctx, secret, &secretlen, outlen) == 0)
602
0
        return NULL;
603
604
0
    if ((secret = OPENSSL_malloc(secretlen)) == NULL)
605
0
        return NULL;
606
607
0
    if (ecdh_derive(vpecdhctx, secret, &secretlen, outlen) == 0
608
0
        || secretlen != outlen) {
609
0
        OPENSSL_clear_free(secret, secretlen);
610
0
        return NULL;
611
0
    }
612
613
0
    params[0] = OSSL_PARAM_construct_octet_string(OSSL_SKEY_PARAM_RAW_BYTES,
614
0
        (void *)secret, outlen);
615
616
    /* This is mandatory, no need to check for its presence */
617
0
    ret = import(provctx, OSSL_SKEYMGMT_SELECT_SECRET_KEY, params);
618
0
    OPENSSL_clear_free(secret, secretlen);
619
620
0
    return ret;
621
0
}
622
623
const OSSL_DISPATCH ossl_ecdh_keyexch_functions[] = {
624
    { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))ecdh_newctx },
625
    { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecdh_init },
626
    { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecdh_derive },
627
    { OSSL_FUNC_KEYEXCH_DERIVE_SKEY, (void (*)(void))ecdh_derive_skey },
628
    { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecdh_set_peer },
629
    { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecdh_freectx },
630
    { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecdh_dupctx },
631
    { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))ecdh_set_ctx_params },
632
    { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS,
633
        (void (*)(void))ecdh_settable_ctx_params },
634
    { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))ecdh_get_ctx_params },
635
    { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS,
636
        (void (*)(void))ecdh_gettable_ctx_params },
637
    OSSL_DISPATCH_END
638
};