Coverage Report

Created: 2024-07-27 06:36

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