Coverage Report

Created: 2025-09-05 07:01

/src/openssl/providers/implementations/exchange/ecdh_exch.c
Line
Count
Source (jump to first uncovered line)
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
/*
12
 * ECDH low level APIs are deprecated for public use, but still ok for
13
 * internal use.
14
 */
15
#include "internal/deprecated.h"
16
17
#include <string.h>
18
#include <openssl/crypto.h>
19
#include <openssl/evp.h>
20
#include <openssl/core_dispatch.h>
21
#include <openssl/core_names.h>
22
#include <openssl/ec.h>
23
#include <openssl/params.h>
24
#include <openssl/err.h>
25
#include <openssl/proverr.h>
26
#include "internal/cryptlib.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
33
static OSSL_FUNC_keyexch_newctx_fn ecdh_newctx;
34
static OSSL_FUNC_keyexch_init_fn ecdh_init;
35
static OSSL_FUNC_keyexch_set_peer_fn ecdh_set_peer;
36
static OSSL_FUNC_keyexch_derive_fn ecdh_derive;
37
static OSSL_FUNC_keyexch_derive_skey_fn ecdh_derive_skey;
38
static OSSL_FUNC_keyexch_freectx_fn ecdh_freectx;
39
static OSSL_FUNC_keyexch_dupctx_fn ecdh_dupctx;
40
static OSSL_FUNC_keyexch_set_ctx_params_fn ecdh_set_ctx_params;
41
static OSSL_FUNC_keyexch_settable_ctx_params_fn ecdh_settable_ctx_params;
42
static OSSL_FUNC_keyexch_get_ctx_params_fn ecdh_get_ctx_params;
43
static OSSL_FUNC_keyexch_gettable_ctx_params_fn ecdh_gettable_ctx_params;
44
45
enum kdf_type {
46
    PROV_ECDH_KDF_NONE = 0,
47
    PROV_ECDH_KDF_X9_63
48
};
49
50
/*
51
 * What's passed as an actual key is defined by the KEYMGMT interface.
52
 * We happen to know that our KEYMGMT simply passes EC_KEY structures, so
53
 * we use that here too.
54
 */
55
56
typedef struct {
57
    OSSL_LIB_CTX *libctx;
58
59
    EC_KEY *k;
60
    EC_KEY *peerk;
61
62
    /*
63
     * ECDH cofactor mode:
64
     *
65
     *  . 0  disabled
66
     *  . 1  enabled
67
     *  . -1 use cofactor mode set for k
68
     */
69
    int cofactor_mode;
70
71
    /************
72
     * ECDH KDF *
73
     ************/
74
    /* KDF (if any) to use for ECDH */
75
    enum kdf_type kdf_type;
76
    /* Message digest to use for key derivation */
77
    EVP_MD *kdf_md;
78
    /* User key material */
79
    unsigned char *kdf_ukm;
80
    size_t kdf_ukmlen;
81
    /* KDF output length */
82
    size_t kdf_outlen;
83
    OSSL_FIPS_IND_DECLARE
84
} PROV_ECDH_CTX;
85
86
static
87
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
0
    pectx = OPENSSL_zalloc(sizeof(*pectx));
95
0
    if (pectx == NULL)
96
0
        return NULL;
97
98
0
    pectx->libctx = PROV_LIBCTX_OF(provctx);
99
0
    pectx->cofactor_mode = -1;
100
0
    pectx->kdf_type = PROV_ECDH_KDF_NONE;
101
0
    OSSL_FIPS_IND_INIT(pectx)
102
103
0
    return (void *)pectx;
104
0
}
105
106
static
107
int ecdh_init(void *vpecdhctx, void *vecdh, const OSSL_PARAM params[])
108
0
{
109
0
    PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
110
111
0
    if (!ossl_prov_is_running()
112
0
            || pecdhctx == NULL
113
0
            || vecdh == NULL
114
0
            || (EC_KEY_get0_group(vecdh) == NULL)
115
0
            || !EC_KEY_up_ref(vecdh))
116
0
        return 0;
117
0
    EC_KEY_free(pecdhctx->k);
118
0
    pecdhctx->k = vecdh;
119
0
    pecdhctx->cofactor_mode = -1;
120
0
    pecdhctx->kdf_type = PROV_ECDH_KDF_NONE;
121
122
0
    OSSL_FIPS_IND_SET_APPROVED(pecdhctx)
123
0
    if (!ecdh_set_ctx_params(pecdhctx, params))
124
0
        return 0;
125
#ifdef FIPS_MODULE
126
    if (!ossl_fips_ind_ec_key_check(OSSL_FIPS_IND_GET(pecdhctx),
127
                                    OSSL_FIPS_IND_SETTABLE0, pecdhctx->libctx,
128
                                    EC_KEY_get0_group(vecdh), "ECDH Init", 1))
129
        return 0;
130
#endif
131
0
    return 1;
132
0
}
133
134
static
135
int ecdh_match_params(const EC_KEY *priv, const EC_KEY *peer)
136
0
{
137
0
    int ret;
138
0
    BN_CTX *ctx = NULL;
139
0
    const EC_GROUP *group_priv = EC_KEY_get0_group(priv);
140
0
    const EC_GROUP *group_peer = EC_KEY_get0_group(peer);
141
142
0
    ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(priv));
143
0
    if (ctx == NULL) {
144
0
        ERR_raise(ERR_LIB_PROV, ERR_R_BN_LIB);
145
0
        return 0;
146
0
    }
147
0
    ret = group_priv != NULL
148
0
          && group_peer != NULL
149
0
          && EC_GROUP_cmp(group_priv, group_peer, ctx) == 0;
150
0
    if (!ret)
151
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS);
152
0
    BN_CTX_free(ctx);
153
0
    return ret;
154
0
}
155
156
static
157
int ecdh_set_peer(void *vpecdhctx, void *vecdh)
158
0
{
159
0
    PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
160
161
0
    if (!ossl_prov_is_running()
162
0
            || pecdhctx == NULL
163
0
            || vecdh == NULL
164
0
            || !ecdh_match_params(pecdhctx->k, vecdh))
165
0
        return 0;
166
#ifdef FIPS_MODULE
167
    if (!ossl_fips_ind_ec_key_check(OSSL_FIPS_IND_GET(pecdhctx),
168
                                    OSSL_FIPS_IND_SETTABLE0, pecdhctx->libctx,
169
                                    EC_KEY_get0_group(vecdh), "ECDH Set Peer",
170
                                    1))
171
        return 0;
172
#endif
173
0
    if (!EC_KEY_up_ref(vecdh))
174
0
        return 0;
175
176
0
    EC_KEY_free(pecdhctx->peerk);
177
0
    pecdhctx->peerk = vecdh;
178
0
    return 1;
179
0
}
180
181
static
182
void ecdh_freectx(void *vpecdhctx)
183
0
{
184
0
    PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
185
186
0
    EC_KEY_free(pecdhctx->k);
187
0
    EC_KEY_free(pecdhctx->peerk);
188
189
0
    EVP_MD_free(pecdhctx->kdf_md);
190
0
    OPENSSL_clear_free(pecdhctx->kdf_ukm, pecdhctx->kdf_ukmlen);
191
192
0
    OPENSSL_free(pecdhctx);
193
0
}
194
195
static
196
void *ecdh_dupctx(void *vpecdhctx)
197
0
{
198
0
    PROV_ECDH_CTX *srcctx = (PROV_ECDH_CTX *)vpecdhctx;
199
0
    PROV_ECDH_CTX *dstctx;
200
201
0
    if (!ossl_prov_is_running())
202
0
        return NULL;
203
204
0
    dstctx = OPENSSL_zalloc(sizeof(*srcctx));
205
0
    if (dstctx == NULL)
206
0
        return NULL;
207
208
0
    *dstctx = *srcctx;
209
210
    /* clear all pointers */
211
212
0
    dstctx->k= NULL;
213
0
    dstctx->peerk = NULL;
214
0
    dstctx->kdf_md = NULL;
215
0
    dstctx->kdf_ukm = NULL;
216
217
    /* up-ref all ref-counted objects referenced in dstctx */
218
219
0
    if (srcctx->k != NULL && !EC_KEY_up_ref(srcctx->k))
220
0
        goto err;
221
0
    else
222
0
        dstctx->k = srcctx->k;
223
224
0
    if (srcctx->peerk != NULL && !EC_KEY_up_ref(srcctx->peerk))
225
0
        goto err;
226
0
    else
227
0
        dstctx->peerk = srcctx->peerk;
228
229
0
    if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md))
230
0
        goto err;
231
0
    else
232
0
        dstctx->kdf_md = srcctx->kdf_md;
233
234
    /* Duplicate UKM data if present */
235
0
    if (srcctx->kdf_ukm != NULL && srcctx->kdf_ukmlen > 0) {
236
0
        dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm,
237
0
                                         srcctx->kdf_ukmlen);
238
0
        if (dstctx->kdf_ukm == NULL)
239
0
            goto err;
240
0
    }
241
242
0
    return dstctx;
243
244
0
 err:
245
0
    ecdh_freectx(dstctx);
246
0
    return NULL;
247
0
}
248
249
/* Machine generated by util/perl/OpenSSL/paramnames.pm */
250
#ifndef ecdh_set_ctx_params_list
251
static const OSSL_PARAM ecdh_set_ctx_params_list[] = {
252
    OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL),
253
    OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),
254
    OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),
255
    OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0),
256
    OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),
257
    OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0),
258
# if defined(FIPS_MODULE)
259
    OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_FIPS_KEY_CHECK, NULL),
260
# endif
261
# if defined(FIPS_MODULE)
262
    OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_FIPS_DIGEST_CHECK, NULL),
263
# endif
264
# if defined(FIPS_MODULE)
265
    OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_FIPS_ECDH_COFACTOR_CHECK, NULL),
266
# endif
267
    OSSL_PARAM_END
268
};
269
#endif
270
271
#ifndef ecdh_set_ctx_params_st
272
struct ecdh_set_ctx_params_st {
273
    OSSL_PARAM *digest;
274
# if defined(FIPS_MODULE)
275
    OSSL_PARAM *ind_cofac;
276
# endif
277
# if defined(FIPS_MODULE)
278
    OSSL_PARAM *ind_d;
279
# endif
280
# if defined(FIPS_MODULE)
281
    OSSL_PARAM *ind_k;
282
# endif
283
    OSSL_PARAM *kdf;
284
    OSSL_PARAM *len;
285
    OSSL_PARAM *mode;
286
    OSSL_PARAM *propq;
287
    OSSL_PARAM *ukm;
288
};
289
#endif
290
291
#ifndef ecdh_set_ctx_params_decoder
292
static int ecdh_set_ctx_params_decoder
293
    (const OSSL_PARAM *p, struct ecdh_set_ctx_params_st *r)
294
0
{
295
0
    const char *s;
296
297
0
    memset(r, 0, sizeof(*r));
298
0
    if (p != NULL)
299
0
        for (; (s = p->key) != NULL; p++)
300
0
            switch(s[0]) {
301
0
            default:
302
0
                break;
303
0
            case 'd':
304
# if defined(FIPS_MODULE)
305
                if (ossl_likely(strcmp("igest-check", s + 1) == 0)) {
306
                    /* EXCHANGE_PARAM_FIPS_DIGEST_CHECK */
307
                    if (ossl_unlikely(r->ind_d != NULL)) {
308
                        ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
309
                                       "param %s is repeated", s);
310
                        return 0;
311
                    }
312
                    r->ind_d = (OSSL_PARAM *)p;
313
                }
314
# endif
315
0
                break;
316
0
            case 'e':
317
0
                switch(s[1]) {
318
0
                default:
319
0
                    break;
320
0
                case 'c':
321
0
                    switch(s[2]) {
322
0
                    default:
323
0
                        break;
324
0
                    case 'd':
325
0
                        switch(s[3]) {
326
0
                        default:
327
0
                            break;
328
0
                        case 'h':
329
0
                            switch(s[4]) {
330
0
                            default:
331
0
                                break;
332
0
                            case '-':
333
0
                                switch(s[5]) {
334
0
                                default:
335
0
                                    break;
336
0
                                case 'c':
337
0
                                    switch(s[6]) {
338
0
                                    default:
339
0
                                        break;
340
0
                                    case 'o':
341
0
                                        switch(s[7]) {
342
0
                                        default:
343
0
                                            break;
344
0
                                        case 'f':
345
0
                                            switch(s[8]) {
346
0
                                            default:
347
0
                                                break;
348
0
                                            case 'a':
349
0
                                                switch(s[9]) {
350
0
                                                default:
351
0
                                                    break;
352
0
                                                case 'c':
353
0
                                                    switch(s[10]) {
354
0
                                                    default:
355
0
                                                        break;
356
0
                                                    case 't':
357
0
                                                        switch(s[11]) {
358
0
                                                        default:
359
0
                                                            break;
360
0
                                                        case 'o':
361
0
                                                            switch(s[12]) {
362
0
                                                            default:
363
0
                                                                break;
364
0
                                                            case 'r':
365
0
                                                                switch(s[13]) {
366
0
                                                                default:
367
0
                                                                    break;
368
0
                                                                case '-':
369
0
                                                                    switch(s[14]) {
370
0
                                                                    default:
371
0
                                                                        break;
372
0
                                                                    case 'c':
373
# if defined(FIPS_MODULE)
374
                                                                        if (ossl_likely(strcmp("heck", s + 15) == 0)) {
375
                                                                            /* EXCHANGE_PARAM_FIPS_ECDH_COFACTOR_CHECK */
376
                                                                            if (ossl_unlikely(r->ind_cofac != NULL)) {
377
                                                                                ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
378
                                                                                               "param %s is repeated", s);
379
                                                                                return 0;
380
                                                                            }
381
                                                                            r->ind_cofac = (OSSL_PARAM *)p;
382
                                                                        }
383
# endif
384
0
                                                                        break;
385
0
                                                                    case 'm':
386
0
                                                                        if (ossl_likely(strcmp("ode", s + 15) == 0)) {
387
                                                                            /* EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE */
388
0
                                                                            if (ossl_unlikely(r->mode != NULL)) {
389
0
                                                                                ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
390
0
                                                                                               "param %s is repeated", s);
391
0
                                                                                return 0;
392
0
                                                                            }
393
0
                                                                            r->mode = (OSSL_PARAM *)p;
394
0
                                                                        }
395
0
                                                                    }
396
0
                                                                }
397
0
                                                            }
398
0
                                                        }
399
0
                                                    }
400
0
                                                }
401
0
                                            }
402
0
                                        }
403
0
                                    }
404
0
                                }
405
0
                            }
406
0
                        }
407
0
                    }
408
0
                }
409
0
                break;
410
0
            case 'k':
411
0
                switch(s[1]) {
412
0
                default:
413
0
                    break;
414
0
                case 'd':
415
0
                    switch(s[2]) {
416
0
                    default:
417
0
                        break;
418
0
                    case 'f':
419
0
                        switch(s[3]) {
420
0
                        default:
421
0
                            break;
422
0
                        case '-':
423
0
                            switch(s[4]) {
424
0
                            default:
425
0
                                break;
426
0
                            case 'd':
427
0
                                switch(s[5]) {
428
0
                                default:
429
0
                                    break;
430
0
                                case 'i':
431
0
                                    switch(s[6]) {
432
0
                                    default:
433
0
                                        break;
434
0
                                    case 'g':
435
0
                                        switch(s[7]) {
436
0
                                        default:
437
0
                                            break;
438
0
                                        case 'e':
439
0
                                            switch(s[8]) {
440
0
                                            default:
441
0
                                                break;
442
0
                                            case 's':
443
0
                                                switch(s[9]) {
444
0
                                                default:
445
0
                                                    break;
446
0
                                                case 't':
447
0
                                                    switch(s[10]) {
448
0
                                                    default:
449
0
                                                        break;
450
0
                                                    case '-':
451
0
                                                        if (ossl_likely(strcmp("props", s + 11) == 0)) {
452
                                                            /* EXCHANGE_PARAM_KDF_DIGEST_PROPS */
453
0
                                                            if (ossl_unlikely(r->propq != NULL)) {
454
0
                                                                ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
455
0
                                                                               "param %s is repeated", s);
456
0
                                                                return 0;
457
0
                                                            }
458
0
                                                            r->propq = (OSSL_PARAM *)p;
459
0
                                                        }
460
0
                                                        break;
461
0
                                                    case '\0':
462
0
                                                        if (ossl_unlikely(r->digest != NULL)) {
463
0
                                                            ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
464
0
                                                                           "param %s is repeated", s);
465
0
                                                            return 0;
466
0
                                                        }
467
0
                                                        r->digest = (OSSL_PARAM *)p;
468
0
                                                    }
469
0
                                                }
470
0
                                            }
471
0
                                        }
472
0
                                    }
473
0
                                }
474
0
                                break;
475
0
                            case 'o':
476
0
                                if (ossl_likely(strcmp("utlen", s + 5) == 0)) {
477
                                    /* EXCHANGE_PARAM_KDF_OUTLEN */
478
0
                                    if (ossl_unlikely(r->len != NULL)) {
479
0
                                        ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
480
0
                                                       "param %s is repeated", s);
481
0
                                        return 0;
482
0
                                    }
483
0
                                    r->len = (OSSL_PARAM *)p;
484
0
                                }
485
0
                                break;
486
0
                            case 't':
487
0
                                if (ossl_likely(strcmp("ype", s + 5) == 0)) {
488
                                    /* EXCHANGE_PARAM_KDF_TYPE */
489
0
                                    if (ossl_unlikely(r->kdf != NULL)) {
490
0
                                        ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
491
0
                                                       "param %s is repeated", s);
492
0
                                        return 0;
493
0
                                    }
494
0
                                    r->kdf = (OSSL_PARAM *)p;
495
0
                                }
496
0
                                break;
497
0
                            case 'u':
498
0
                                if (ossl_likely(strcmp("km", s + 5) == 0)) {
499
                                    /* EXCHANGE_PARAM_KDF_UKM */
500
0
                                    if (ossl_unlikely(r->ukm != NULL)) {
501
0
                                        ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
502
0
                                                       "param %s is repeated", s);
503
0
                                        return 0;
504
0
                                    }
505
0
                                    r->ukm = (OSSL_PARAM *)p;
506
0
                                }
507
0
                            }
508
0
                        }
509
0
                    }
510
0
                    break;
511
0
                case 'e':
512
# if defined(FIPS_MODULE)
513
                    if (ossl_likely(strcmp("y-check", s + 2) == 0)) {
514
                        /* EXCHANGE_PARAM_FIPS_KEY_CHECK */
515
                        if (ossl_unlikely(r->ind_k != NULL)) {
516
                            ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
517
                                           "param %s is repeated", s);
518
                            return 0;
519
                        }
520
                        r->ind_k = (OSSL_PARAM *)p;
521
                    }
522
# endif
523
0
                    break;
524
0
                }
525
0
                break;
526
0
            }
527
0
    return 1;
528
0
}
529
#endif
530
/* End of machine generated */
531
532
static
533
int ecdh_set_ctx_params(void *vpecdhctx, const OSSL_PARAM params[])
534
0
{
535
0
    char name[80] = { '\0' }; /* should be big enough */
536
0
    char *str = NULL;
537
0
    PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx;
538
0
    struct ecdh_set_ctx_params_st p;
539
540
0
    if (pectx == NULL || !ecdh_set_ctx_params_decoder(params, &p))
541
0
        return 0;
542
543
0
    if (!OSSL_FIPS_IND_SET_CTX_FROM_PARAM(pectx, OSSL_FIPS_IND_SETTABLE0, p.ind_k))
544
0
        return 0;
545
0
    if (!OSSL_FIPS_IND_SET_CTX_FROM_PARAM(pectx, OSSL_FIPS_IND_SETTABLE1, p.ind_d))
546
0
        return 0;
547
0
    if (!OSSL_FIPS_IND_SET_CTX_FROM_PARAM(pectx, OSSL_FIPS_IND_SETTABLE2, p.ind_cofac))
548
0
        return 0;
549
550
0
    if (p.mode != NULL) {
551
0
        int mode;
552
553
0
        if (!OSSL_PARAM_get_int(p.mode, &mode))
554
0
            return 0;
555
556
0
        if (mode < -1 || mode > 1)
557
0
            return 0;
558
559
0
        pectx->cofactor_mode = mode;
560
0
    }
561
562
0
    if (p.kdf != NULL) {
563
0
        str = name;
564
0
        if (!OSSL_PARAM_get_utf8_string(p.kdf, &str, sizeof(name)))
565
0
            return 0;
566
567
0
        if (name[0] == '\0')
568
0
            pectx->kdf_type = PROV_ECDH_KDF_NONE;
569
0
        else if (strcmp(name, OSSL_KDF_NAME_X963KDF) == 0)
570
0
            pectx->kdf_type = PROV_ECDH_KDF_X9_63;
571
0
        else
572
0
            return 0;
573
0
    }
574
575
0
    if (p.digest != NULL) {
576
0
        char mdprops[80] = { '\0' }; /* should be big enough */
577
578
0
        str = name;
579
0
        if (!OSSL_PARAM_get_utf8_string(p.digest, &str, sizeof(name)))
580
0
            return 0;
581
582
0
        str = mdprops;
583
0
        if (p.propq != NULL) {
584
0
            if (!OSSL_PARAM_get_utf8_string(p.propq, &str, sizeof(mdprops)))
585
0
                return 0;
586
0
        }
587
588
0
        EVP_MD_free(pectx->kdf_md);
589
0
        pectx->kdf_md = EVP_MD_fetch(pectx->libctx, name, mdprops);
590
0
        if (pectx->kdf_md == NULL)
591
0
            return 0;
592
        /* XOF digests are not allowed */
593
0
        if (EVP_MD_xof(pectx->kdf_md)) {
594
0
            ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED);
595
0
            return 0;
596
0
        }
597
#ifdef FIPS_MODULE
598
        if (!ossl_fips_ind_digest_exch_check(OSSL_FIPS_IND_GET(pectx),
599
                                             OSSL_FIPS_IND_SETTABLE1, pectx->libctx,
600
                                             pectx->kdf_md, "ECDH Set Ctx")) {
601
            EVP_MD_free(pectx->kdf_md);
602
            pectx->kdf_md = NULL;
603
            return 0;
604
        }
605
#endif
606
0
    }
607
608
0
    if (p.len != NULL) {
609
0
        size_t outlen;
610
611
0
        if (!OSSL_PARAM_get_size_t(p.len, &outlen))
612
0
            return 0;
613
0
        pectx->kdf_outlen = outlen;
614
0
    }
615
616
0
    if (p.ukm != NULL) {
617
0
        void *tmp_ukm = NULL;
618
0
        size_t tmp_ukmlen;
619
620
0
        if (!OSSL_PARAM_get_octet_string(p.ukm, &tmp_ukm, 0, &tmp_ukmlen))
621
0
            return 0;
622
0
        OPENSSL_free(pectx->kdf_ukm);
623
0
        pectx->kdf_ukm = tmp_ukm;
624
0
        pectx->kdf_ukmlen = tmp_ukmlen;
625
0
    }
626
627
0
    return 1;
628
0
}
629
630
static
631
const OSSL_PARAM *ecdh_settable_ctx_params(ossl_unused void *vpecdhctx,
632
                                           ossl_unused void *provctx)
633
0
{
634
0
    return ecdh_set_ctx_params_list;
635
0
}
636
637
/* Machine generated by util/perl/OpenSSL/paramnames.pm */
638
#ifndef ecdh_get_ctx_params_list
639
static const OSSL_PARAM ecdh_get_ctx_params_list[] = {
640
    OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL),
641
    OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),
642
    OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),
643
    OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),
644
    OSSL_PARAM_octet_ptr(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0),
645
# if defined(FIPS_MODULE)
646
    OSSL_PARAM_int(OSSL_ALG_PARAM_FIPS_APPROVED_INDICATOR, NULL),
647
# endif
648
    OSSL_PARAM_END
649
};
650
#endif
651
652
#ifndef ecdh_get_ctx_params_st
653
struct ecdh_get_ctx_params_st {
654
    OSSL_PARAM *digest;
655
# if defined(FIPS_MODULE)
656
    OSSL_PARAM *ind;
657
# endif
658
    OSSL_PARAM *kdf;
659
    OSSL_PARAM *len;
660
    OSSL_PARAM *mode;
661
    OSSL_PARAM *ukm;
662
};
663
#endif
664
665
#ifndef ecdh_get_ctx_params_decoder
666
static int ecdh_get_ctx_params_decoder
667
    (const OSSL_PARAM *p, struct ecdh_get_ctx_params_st *r)
668
0
{
669
0
    const char *s;
670
671
0
    memset(r, 0, sizeof(*r));
672
0
    if (p != NULL)
673
0
        for (; (s = p->key) != NULL; p++)
674
0
            switch(s[0]) {
675
0
            default:
676
0
                break;
677
0
            case 'e':
678
0
                if (ossl_likely(strcmp("cdh-cofactor-mode", s + 1) == 0)) {
679
                    /* EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE */
680
0
                    if (ossl_unlikely(r->mode != NULL)) {
681
0
                        ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
682
0
                                       "param %s is repeated", s);
683
0
                        return 0;
684
0
                    }
685
0
                    r->mode = (OSSL_PARAM *)p;
686
0
                }
687
0
                break;
688
0
            case 'f':
689
# if defined(FIPS_MODULE)
690
                if (ossl_likely(strcmp("ips-indicator", s + 1) == 0)) {
691
                    /* ALG_PARAM_FIPS_APPROVED_INDICATOR */
692
                    if (ossl_unlikely(r->ind != NULL)) {
693
                        ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
694
                                       "param %s is repeated", s);
695
                        return 0;
696
                    }
697
                    r->ind = (OSSL_PARAM *)p;
698
                }
699
# endif
700
0
                break;
701
0
            case 'k':
702
0
                switch(s[1]) {
703
0
                default:
704
0
                    break;
705
0
                case 'd':
706
0
                    switch(s[2]) {
707
0
                    default:
708
0
                        break;
709
0
                    case 'f':
710
0
                        switch(s[3]) {
711
0
                        default:
712
0
                            break;
713
0
                        case '-':
714
0
                            switch(s[4]) {
715
0
                            default:
716
0
                                break;
717
0
                            case 'd':
718
0
                                if (ossl_likely(strcmp("igest", s + 5) == 0)) {
719
                                    /* EXCHANGE_PARAM_KDF_DIGEST */
720
0
                                    if (ossl_unlikely(r->digest != NULL)) {
721
0
                                        ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
722
0
                                                       "param %s is repeated", s);
723
0
                                        return 0;
724
0
                                    }
725
0
                                    r->digest = (OSSL_PARAM *)p;
726
0
                                }
727
0
                                break;
728
0
                            case 'o':
729
0
                                if (ossl_likely(strcmp("utlen", s + 5) == 0)) {
730
                                    /* EXCHANGE_PARAM_KDF_OUTLEN */
731
0
                                    if (ossl_unlikely(r->len != NULL)) {
732
0
                                        ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
733
0
                                                       "param %s is repeated", s);
734
0
                                        return 0;
735
0
                                    }
736
0
                                    r->len = (OSSL_PARAM *)p;
737
0
                                }
738
0
                                break;
739
0
                            case 't':
740
0
                                if (ossl_likely(strcmp("ype", s + 5) == 0)) {
741
                                    /* EXCHANGE_PARAM_KDF_TYPE */
742
0
                                    if (ossl_unlikely(r->kdf != NULL)) {
743
0
                                        ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
744
0
                                                       "param %s is repeated", s);
745
0
                                        return 0;
746
0
                                    }
747
0
                                    r->kdf = (OSSL_PARAM *)p;
748
0
                                }
749
0
                                break;
750
0
                            case 'u':
751
0
                                if (ossl_likely(strcmp("km", s + 5) == 0)) {
752
                                    /* EXCHANGE_PARAM_KDF_UKM */
753
0
                                    if (ossl_unlikely(r->ukm != NULL)) {
754
0
                                        ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
755
0
                                                       "param %s is repeated", s);
756
0
                                        return 0;
757
0
                                    }
758
0
                                    r->ukm = (OSSL_PARAM *)p;
759
0
                                }
760
0
                            }
761
0
                        }
762
0
                    }
763
0
                }
764
0
            }
765
0
    return 1;
766
0
}
767
#endif
768
/* End of machine generated */
769
770
static
771
int ecdh_get_ctx_params(void *vpecdhctx, OSSL_PARAM params[])
772
0
{
773
0
    PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx;
774
0
    struct ecdh_get_ctx_params_st p;
775
776
0
    if (pectx == NULL || !ecdh_get_ctx_params_decoder(params, &p))
777
0
        return 0;
778
779
0
    if (p.mode != NULL) {
780
0
        int mode = pectx->cofactor_mode;
781
782
0
        if (mode == -1) {
783
            /* check what is the default for pecdhctx->k */
784
0
            mode = EC_KEY_get_flags(pectx->k) & EC_FLAG_COFACTOR_ECDH ? 1 : 0;
785
0
        }
786
787
0
        if (!OSSL_PARAM_set_int(p.mode, mode))
788
0
            return 0;
789
0
    }
790
791
0
    if (p.kdf != NULL) {
792
0
        const char *kdf_type = NULL;
793
794
0
        switch (pectx->kdf_type) {
795
0
            case PROV_ECDH_KDF_NONE:
796
0
                kdf_type = "";
797
0
                break;
798
0
            case PROV_ECDH_KDF_X9_63:
799
0
                kdf_type = OSSL_KDF_NAME_X963KDF;
800
0
                break;
801
0
            default:
802
0
                return 0;
803
0
        }
804
805
0
        if (!OSSL_PARAM_set_utf8_string(p.kdf, kdf_type))
806
0
            return 0;
807
0
    }
808
809
0
    if (p.digest != NULL
810
0
            && !OSSL_PARAM_set_utf8_string(p.digest, pectx->kdf_md == NULL
811
0
                                           ? ""
812
0
                                           : EVP_MD_get0_name(pectx->kdf_md))) {
813
0
        return 0;
814
0
    }
815
816
0
    if (p.len != NULL && !OSSL_PARAM_set_size_t(p.len, pectx->kdf_outlen))
817
0
        return 0;
818
819
0
    if (p.ukm != NULL &&
820
0
        !OSSL_PARAM_set_octet_ptr(p.ukm, pectx->kdf_ukm, pectx->kdf_ukmlen))
821
0
        return 0;
822
823
0
    if (!OSSL_FIPS_IND_GET_CTX_FROM_PARAM(pectx, p.ind))
824
0
        return 0;
825
0
    return 1;
826
0
}
827
828
static
829
const OSSL_PARAM *ecdh_gettable_ctx_params(ossl_unused void *vpecdhctx,
830
                                           ossl_unused void *provctx)
831
0
{
832
0
    return ecdh_get_ctx_params_list;
833
0
}
834
835
static ossl_inline
836
size_t ecdh_size(const EC_KEY *k)
837
0
{
838
0
    size_t degree = 0;
839
0
    const EC_GROUP *group;
840
841
0
    if (k == NULL
842
0
            || (group = EC_KEY_get0_group(k)) == NULL)
843
0
        return 0;
844
845
0
    degree = EC_GROUP_get_degree(group);
846
847
0
    return (degree + 7) / 8;
848
0
}
849
850
static ossl_inline
851
int ecdh_plain_derive(void *vpecdhctx, unsigned char *secret,
852
                      size_t *psecretlen, size_t outlen)
853
0
{
854
0
    PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
855
0
    int retlen, ret = 0;
856
0
    size_t ecdhsize, size;
857
0
    const EC_POINT *ppubkey = NULL;
858
0
    EC_KEY *privk = NULL;
859
0
    const EC_GROUP *group;
860
0
    const BIGNUM *cofactor;
861
0
    int key_cofactor_mode;
862
0
    int has_cofactor;
863
#ifdef FIPS_MODULE
864
    int cofactor_approved = 0;
865
#endif
866
867
0
    if (pecdhctx->k == NULL || pecdhctx->peerk == NULL) {
868
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
869
0
        return 0;
870
0
    }
871
872
0
    ecdhsize = ecdh_size(pecdhctx->k);
873
0
    if (secret == NULL) {
874
0
        *psecretlen = ecdhsize;
875
0
        return 1;
876
0
    }
877
878
0
    if ((group = EC_KEY_get0_group(pecdhctx->k)) == NULL
879
0
            || (cofactor = EC_GROUP_get0_cofactor(group)) == NULL)
880
0
        return 0;
881
882
0
    has_cofactor = !BN_is_one(cofactor);
883
884
    /*
885
     * NB: unlike PKCS#3 DH, if outlen is less than maximum size this is not
886
     * an error, the result is truncated.
887
     */
888
0
    size = outlen < ecdhsize ? outlen : ecdhsize;
889
890
    /*
891
     * The ctx->cofactor_mode flag has precedence over the
892
     * cofactor_mode flag set on ctx->k.
893
     *
894
     * - if ctx->cofactor_mode == -1, use ctx->k directly
895
     * - if ctx->cofactor_mode == key_cofactor_mode, use ctx->k directly
896
     * - if ctx->cofactor_mode != key_cofactor_mode:
897
     *     - if ctx->k->cofactor == 1, the cofactor_mode flag is irrelevant, use
898
     *          ctx->k directly
899
     *     - if ctx->k->cofactor != 1, use a duplicate of ctx->k with the flag
900
     *          set to ctx->cofactor_mode
901
     */
902
0
    key_cofactor_mode =
903
0
        (EC_KEY_get_flags(pecdhctx->k) & EC_FLAG_COFACTOR_ECDH) ? 1 : 0;
904
0
    if (pecdhctx->cofactor_mode != -1
905
0
            && pecdhctx->cofactor_mode != key_cofactor_mode
906
0
            && has_cofactor) {
907
0
        if ((privk = EC_KEY_dup(pecdhctx->k)) == NULL)
908
0
            return 0;
909
910
0
        if (pecdhctx->cofactor_mode == 1) {
911
0
            EC_KEY_set_flags(privk, EC_FLAG_COFACTOR_ECDH);
912
#ifdef FIPS_MODULE
913
            cofactor_approved = 1;
914
#endif
915
0
        } else {
916
0
            EC_KEY_clear_flags(privk, EC_FLAG_COFACTOR_ECDH);
917
0
        }
918
0
    } else {
919
0
        privk = pecdhctx->k;
920
#ifdef FIPS_MODULE
921
        cofactor_approved = key_cofactor_mode;
922
#endif
923
0
    }
924
925
#ifdef FIPS_MODULE
926
    /*
927
     * SP800-56A r3 Section 5.7.1.2 requires ECC Cofactor DH to be used.
928
     * This applies to the 'B' and 'K' curves that have cofactors that are not 1.
929
     */
930
    if (has_cofactor && !cofactor_approved) {
931
        if (!OSSL_FIPS_IND_ON_UNAPPROVED(pecdhctx, OSSL_FIPS_IND_SETTABLE2,
932
                                         pecdhctx->libctx, "ECDH", "Cofactor",
933
                                         ossl_fips_config_ecdh_cofactor_check)) {
934
            ERR_raise(ERR_LIB_PROV, PROV_R_COFACTOR_REQUIRED);
935
            goto end;
936
        }
937
    }
938
#endif
939
940
0
    ppubkey = EC_KEY_get0_public_key(pecdhctx->peerk);
941
942
0
    retlen = ECDH_compute_key(secret, size, ppubkey, privk, NULL);
943
944
0
    if (retlen <= 0)
945
0
        goto end;
946
947
0
    *psecretlen = retlen;
948
0
    ret = 1;
949
950
0
 end:
951
0
    if (privk != pecdhctx->k)
952
0
        EC_KEY_free(privk);
953
0
    return ret;
954
0
}
955
956
static ossl_inline
957
int ecdh_X9_63_kdf_derive(void *vpecdhctx, unsigned char *secret,
958
                          size_t *psecretlen, size_t outlen)
959
0
{
960
0
    PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
961
0
    unsigned char *stmp = NULL;
962
0
    size_t stmplen;
963
0
    int ret = 0;
964
965
0
    if (secret == NULL) {
966
0
        *psecretlen = pecdhctx->kdf_outlen;
967
0
        return 1;
968
0
    }
969
970
0
    if (pecdhctx->kdf_outlen > outlen) {
971
0
        ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
972
0
        return 0;
973
0
    }
974
0
    if (!ecdh_plain_derive(vpecdhctx, NULL, &stmplen, 0))
975
0
        return 0;
976
0
    if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL)
977
0
        return 0;
978
0
    if (!ecdh_plain_derive(vpecdhctx, stmp, &stmplen, stmplen))
979
0
        goto err;
980
981
    /* Do KDF stuff */
982
0
    if (!ossl_ecdh_kdf_X9_63(secret, pecdhctx->kdf_outlen,
983
0
                             stmp, stmplen,
984
0
                             pecdhctx->kdf_ukm,
985
0
                             pecdhctx->kdf_ukmlen,
986
0
                             pecdhctx->kdf_md,
987
0
                             pecdhctx->libctx, NULL))
988
0
        goto err;
989
0
    *psecretlen = pecdhctx->kdf_outlen;
990
0
    ret = 1;
991
992
0
 err:
993
0
    OPENSSL_secure_clear_free(stmp, stmplen);
994
0
    return ret;
995
0
}
996
997
static
998
int ecdh_derive(void *vpecdhctx, unsigned char *secret,
999
                size_t *psecretlen, size_t outlen)
1000
0
{
1001
0
    PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
1002
1003
0
    switch (pecdhctx->kdf_type) {
1004
0
        case PROV_ECDH_KDF_NONE:
1005
0
            return ecdh_plain_derive(vpecdhctx, secret, psecretlen, outlen);
1006
0
        case PROV_ECDH_KDF_X9_63:
1007
0
            return ecdh_X9_63_kdf_derive(vpecdhctx, secret, psecretlen, outlen);
1008
0
        default:
1009
0
            break;
1010
0
    }
1011
0
    return 0;
1012
0
}
1013
1014
static
1015
void *ecdh_derive_skey(void *vpecdhctx, void *provctx, OSSL_FUNC_skeymgmt_import_fn *import,
1016
                       size_t outlen, const OSSL_PARAM params_in[] ossl_unused)
1017
0
{
1018
0
    unsigned char *secret = NULL;
1019
0
    size_t secretlen = 0;
1020
0
    void *ret = NULL;
1021
0
    OSSL_PARAM params[2] = {OSSL_PARAM_END, OSSL_PARAM_END};
1022
1023
0
    if (import == NULL || outlen == 0)
1024
0
        return NULL;
1025
1026
0
    if (ecdh_derive(vpecdhctx, secret, &secretlen, outlen) == 0)
1027
0
        return NULL;
1028
1029
0
    if ((secret = OPENSSL_malloc(secretlen)) == NULL)
1030
0
        return NULL;
1031
1032
0
    if (ecdh_derive(vpecdhctx, secret, &secretlen, outlen) == 0
1033
0
        || secretlen != outlen) {
1034
0
        OPENSSL_clear_free(secret, secretlen);
1035
0
        return NULL;
1036
0
    }
1037
1038
0
    params[0] = OSSL_PARAM_construct_octet_string(OSSL_SKEY_PARAM_RAW_BYTES,
1039
0
                                                  (void *)secret, outlen);
1040
1041
    /* This is mandatory, no need to check for its presence */
1042
0
    ret = import(provctx, OSSL_SKEYMGMT_SELECT_SECRET_KEY, params);
1043
0
    OPENSSL_clear_free(secret, secretlen);
1044
1045
0
    return ret;
1046
0
}
1047
1048
const OSSL_DISPATCH ossl_ecdh_keyexch_functions[] = {
1049
    { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))ecdh_newctx },
1050
    { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecdh_init },
1051
    { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecdh_derive },
1052
    { OSSL_FUNC_KEYEXCH_DERIVE_SKEY, (void (*)(void))ecdh_derive_skey },
1053
    { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecdh_set_peer },
1054
    { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecdh_freectx },
1055
    { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecdh_dupctx },
1056
    { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))ecdh_set_ctx_params },
1057
    { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS,
1058
      (void (*)(void))ecdh_settable_ctx_params },
1059
    { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))ecdh_get_ctx_params },
1060
    { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS,
1061
      (void (*)(void))ecdh_gettable_ctx_params },
1062
    OSSL_DISPATCH_END
1063
};