Coverage Report

Created: 2025-08-25 06:30

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