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