Coverage Report

Created: 2025-12-31 06:58

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