2 * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved.
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
11 * ECDH low level APIs are deprecated for public use, but still ok for
14 #include "internal/deprecated.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() */
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
;
43 PROV_ECDH_KDF_NONE
= 0,
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.
64 * . -1 use cofactor mode set for k
71 /* KDF (if any) to use for ECDH */
72 enum kdf_type kdf_type
;
73 /* Message digest to use for key derivation */
75 /* User key material */
76 unsigned char *kdf_ukm
;
78 /* KDF output length */
83 void *ecdh_newctx(void *provctx
)
87 if (!ossl_prov_is_running())
90 pectx
= OPENSSL_zalloc(sizeof(*pectx
));
94 pectx
->libctx
= PROV_LIBCTX_OF(provctx
);
95 pectx
->cofactor_mode
= -1;
96 pectx
->kdf_type
= PROV_ECDH_KDF_NONE
;
102 int ecdh_init(void *vpecdhctx
, void *vecdh
, const OSSL_PARAM params
[])
104 PROV_ECDH_CTX
*pecdhctx
= (PROV_ECDH_CTX
*)vpecdhctx
;
106 if (!ossl_prov_is_running()
109 || !EC_KEY_up_ref(vecdh
))
111 EC_KEY_free(pecdhctx
->k
);
113 pecdhctx
->cofactor_mode
= -1;
114 pecdhctx
->kdf_type
= PROV_ECDH_KDF_NONE
;
115 return ecdh_set_ctx_params(pecdhctx
, params
)
116 && ossl_ec_check_key(pecdhctx
->libctx
, vecdh
, 1);
120 int ecdh_match_params(const EC_KEY
*priv
, const EC_KEY
*peer
)
124 const EC_GROUP
*group_priv
= EC_KEY_get0_group(priv
);
125 const EC_GROUP
*group_peer
= EC_KEY_get0_group(peer
);
127 ctx
= BN_CTX_new_ex(ossl_ec_key_get_libctx(priv
));
129 ERR_raise(ERR_LIB_PROV
, ERR_R_BN_LIB
);
132 ret
= group_priv
!= NULL
133 && group_peer
!= NULL
134 && EC_GROUP_cmp(group_priv
, group_peer
, ctx
) == 0;
136 ERR_raise(ERR_LIB_PROV
, PROV_R_MISMATCHING_DOMAIN_PARAMETERS
);
142 int ecdh_set_peer(void *vpecdhctx
, void *vecdh
)
144 PROV_ECDH_CTX
*pecdhctx
= (PROV_ECDH_CTX
*)vpecdhctx
;
146 if (!ossl_prov_is_running()
149 || !ecdh_match_params(pecdhctx
->k
, vecdh
)
150 || !ossl_ec_check_key(pecdhctx
->libctx
, vecdh
, 1)
151 || !EC_KEY_up_ref(vecdh
))
154 EC_KEY_free(pecdhctx
->peerk
);
155 pecdhctx
->peerk
= vecdh
;
160 void ecdh_freectx(void *vpecdhctx
)
162 PROV_ECDH_CTX
*pecdhctx
= (PROV_ECDH_CTX
*)vpecdhctx
;
164 EC_KEY_free(pecdhctx
->k
);
165 EC_KEY_free(pecdhctx
->peerk
);
167 EVP_MD_free(pecdhctx
->kdf_md
);
168 OPENSSL_clear_free(pecdhctx
->kdf_ukm
, pecdhctx
->kdf_ukmlen
);
170 OPENSSL_free(pecdhctx
);
174 void *ecdh_dupctx(void *vpecdhctx
)
176 PROV_ECDH_CTX
*srcctx
= (PROV_ECDH_CTX
*)vpecdhctx
;
177 PROV_ECDH_CTX
*dstctx
;
179 if (!ossl_prov_is_running())
182 dstctx
= OPENSSL_zalloc(sizeof(*srcctx
));
188 /* clear all pointers */
191 dstctx
->peerk
= NULL
;
192 dstctx
->kdf_md
= NULL
;
193 dstctx
->kdf_ukm
= NULL
;
195 /* up-ref all ref-counted objects referenced in dstctx */
197 if (srcctx
->k
!= NULL
&& !EC_KEY_up_ref(srcctx
->k
))
200 dstctx
->k
= srcctx
->k
;
202 if (srcctx
->peerk
!= NULL
&& !EC_KEY_up_ref(srcctx
->peerk
))
205 dstctx
->peerk
= srcctx
->peerk
;
207 if (srcctx
->kdf_md
!= NULL
&& !EVP_MD_up_ref(srcctx
->kdf_md
))
210 dstctx
->kdf_md
= srcctx
->kdf_md
;
212 /* Duplicate UKM data if present */
213 if (srcctx
->kdf_ukm
!= NULL
&& srcctx
->kdf_ukmlen
> 0) {
214 dstctx
->kdf_ukm
= OPENSSL_memdup(srcctx
->kdf_ukm
,
216 if (dstctx
->kdf_ukm
== NULL
)
223 ecdh_freectx(dstctx
);
228 int ecdh_set_ctx_params(void *vpecdhctx
, const OSSL_PARAM params
[])
230 char name
[80] = { '\0' }; /* should be big enough */
232 PROV_ECDH_CTX
*pectx
= (PROV_ECDH_CTX
*)vpecdhctx
;
240 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE
);
244 if (!OSSL_PARAM_get_int(p
, &mode
))
247 if (mode
< -1 || mode
> 1)
250 pectx
->cofactor_mode
= mode
;
253 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_TYPE
);
256 if (!OSSL_PARAM_get_utf8_string(p
, &str
, sizeof(name
)))
260 pectx
->kdf_type
= PROV_ECDH_KDF_NONE
;
261 else if (strcmp(name
, OSSL_KDF_NAME_X963KDF
) == 0)
262 pectx
->kdf_type
= PROV_ECDH_KDF_X9_63
;
267 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_DIGEST
);
269 char mdprops
[80] = { '\0' }; /* should be big enough */
272 if (!OSSL_PARAM_get_utf8_string(p
, &str
, sizeof(name
)))
276 p
= OSSL_PARAM_locate_const(params
,
277 OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS
);
280 if (!OSSL_PARAM_get_utf8_string(p
, &str
, sizeof(mdprops
)))
284 EVP_MD_free(pectx
->kdf_md
);
285 pectx
->kdf_md
= EVP_MD_fetch(pectx
->libctx
, name
, mdprops
);
286 if (pectx
->kdf_md
== NULL
)
288 if (!ossl_digest_is_allowed(pectx
->libctx
, pectx
->kdf_md
)) {
289 EVP_MD_free(pectx
->kdf_md
);
290 pectx
->kdf_md
= NULL
;
295 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_OUTLEN
);
299 if (!OSSL_PARAM_get_size_t(p
, &outlen
))
301 pectx
->kdf_outlen
= outlen
;
304 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_UKM
);
306 void *tmp_ukm
= NULL
;
309 if (!OSSL_PARAM_get_octet_string(p
, &tmp_ukm
, 0, &tmp_ukmlen
))
311 OPENSSL_free(pectx
->kdf_ukm
);
312 pectx
->kdf_ukm
= tmp_ukm
;
313 pectx
->kdf_ukmlen
= tmp_ukmlen
;
319 static const OSSL_PARAM known_settable_ctx_params
[] = {
320 OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE
, NULL
),
321 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE
, NULL
, 0),
322 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST
, NULL
, 0),
323 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS
, NULL
, 0),
324 OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN
, NULL
),
325 OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM
, NULL
, 0),
330 const OSSL_PARAM
*ecdh_settable_ctx_params(ossl_unused
void *vpecdhctx
,
331 ossl_unused
void *provctx
)
333 return known_settable_ctx_params
;
337 int ecdh_get_ctx_params(void *vpecdhctx
, OSSL_PARAM params
[])
339 PROV_ECDH_CTX
*pectx
= (PROV_ECDH_CTX
*)vpecdhctx
;
345 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE
);
347 int mode
= pectx
->cofactor_mode
;
350 /* check what is the default for pecdhctx->k */
351 mode
= EC_KEY_get_flags(pectx
->k
) & EC_FLAG_COFACTOR_ECDH
? 1 : 0;
354 if (!OSSL_PARAM_set_int(p
, mode
))
358 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_TYPE
);
360 const char *kdf_type
= NULL
;
362 switch (pectx
->kdf_type
) {
363 case PROV_ECDH_KDF_NONE
:
366 case PROV_ECDH_KDF_X9_63
:
367 kdf_type
= OSSL_KDF_NAME_X963KDF
;
373 if (!OSSL_PARAM_set_utf8_string(p
, kdf_type
))
377 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_DIGEST
);
379 && !OSSL_PARAM_set_utf8_string(p
, pectx
->kdf_md
== NULL
381 : EVP_MD_get0_name(pectx
->kdf_md
))) {
385 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_OUTLEN
);
386 if (p
!= NULL
&& !OSSL_PARAM_set_size_t(p
, pectx
->kdf_outlen
))
389 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_UKM
);
391 !OSSL_PARAM_set_octet_ptr(p
, pectx
->kdf_ukm
, pectx
->kdf_ukmlen
))
397 static const OSSL_PARAM known_gettable_ctx_params
[] = {
398 OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE
, NULL
),
399 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE
, NULL
, 0),
400 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST
, NULL
, 0),
401 OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN
, NULL
),
402 OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM
, OSSL_PARAM_OCTET_PTR
,
408 const OSSL_PARAM
*ecdh_gettable_ctx_params(ossl_unused
void *vpecdhctx
,
409 ossl_unused
void *provctx
)
411 return known_gettable_ctx_params
;
415 size_t ecdh_size(const EC_KEY
*k
)
418 const EC_GROUP
*group
;
421 || (group
= EC_KEY_get0_group(k
)) == NULL
)
424 degree
= EC_GROUP_get_degree(group
);
426 return (degree
+ 7) / 8;
430 int ecdh_plain_derive(void *vpecdhctx
, unsigned char *secret
,
431 size_t *psecretlen
, size_t outlen
)
433 PROV_ECDH_CTX
*pecdhctx
= (PROV_ECDH_CTX
*)vpecdhctx
;
435 size_t ecdhsize
, size
;
436 const EC_POINT
*ppubkey
= NULL
;
437 EC_KEY
*privk
= NULL
;
438 const EC_GROUP
*group
;
439 const BIGNUM
*cofactor
;
440 int key_cofactor_mode
;
442 if (pecdhctx
->k
== NULL
|| pecdhctx
->peerk
== NULL
) {
443 ERR_raise(ERR_LIB_PROV
, PROV_R_MISSING_KEY
);
447 ecdhsize
= ecdh_size(pecdhctx
->k
);
448 if (secret
== NULL
) {
449 *psecretlen
= ecdhsize
;
453 if ((group
= EC_KEY_get0_group(pecdhctx
->k
)) == NULL
454 || (cofactor
= EC_GROUP_get0_cofactor(group
)) == NULL
)
458 * NB: unlike PKCS#3 DH, if outlen is less than maximum size this is not
459 * an error, the result is truncated.
461 size
= outlen
< ecdhsize
? outlen
: ecdhsize
;
464 * The ctx->cofactor_mode flag has precedence over the
465 * cofactor_mode flag set on ctx->k.
467 * - if ctx->cofactor_mode == -1, use ctx->k directly
468 * - if ctx->cofactor_mode == key_cofactor_mode, use ctx->k directly
469 * - if ctx->cofactor_mode != key_cofactor_mode:
470 * - if ctx->k->cofactor == 1, the cofactor_mode flag is irrelevant, use
472 * - if ctx->k->cofactor != 1, use a duplicate of ctx->k with the flag
473 * set to ctx->cofactor_mode
476 (EC_KEY_get_flags(pecdhctx
->k
) & EC_FLAG_COFACTOR_ECDH
) ? 1 : 0;
477 if (pecdhctx
->cofactor_mode
!= -1
478 && pecdhctx
->cofactor_mode
!= key_cofactor_mode
479 && !BN_is_one(cofactor
)) {
480 if ((privk
= EC_KEY_dup(pecdhctx
->k
)) == NULL
)
483 if (pecdhctx
->cofactor_mode
== 1)
484 EC_KEY_set_flags(privk
, EC_FLAG_COFACTOR_ECDH
);
486 EC_KEY_clear_flags(privk
, EC_FLAG_COFACTOR_ECDH
);
491 ppubkey
= EC_KEY_get0_public_key(pecdhctx
->peerk
);
493 retlen
= ECDH_compute_key(secret
, size
, ppubkey
, privk
, NULL
);
498 *psecretlen
= retlen
;
502 if (privk
!= pecdhctx
->k
)
508 int ecdh_X9_63_kdf_derive(void *vpecdhctx
, unsigned char *secret
,
509 size_t *psecretlen
, size_t outlen
)
511 PROV_ECDH_CTX
*pecdhctx
= (PROV_ECDH_CTX
*)vpecdhctx
;
512 unsigned char *stmp
= NULL
;
516 if (secret
== NULL
) {
517 *psecretlen
= pecdhctx
->kdf_outlen
;
521 if (pecdhctx
->kdf_outlen
> outlen
) {
522 ERR_raise(ERR_LIB_PROV
, PROV_R_OUTPUT_BUFFER_TOO_SMALL
);
525 if (!ecdh_plain_derive(vpecdhctx
, NULL
, &stmplen
, 0))
527 if ((stmp
= OPENSSL_secure_malloc(stmplen
)) == NULL
)
529 if (!ecdh_plain_derive(vpecdhctx
, stmp
, &stmplen
, stmplen
))
533 if (!ossl_ecdh_kdf_X9_63(secret
, pecdhctx
->kdf_outlen
,
536 pecdhctx
->kdf_ukmlen
,
538 pecdhctx
->libctx
, NULL
))
540 *psecretlen
= pecdhctx
->kdf_outlen
;
544 OPENSSL_secure_clear_free(stmp
, stmplen
);
549 int ecdh_derive(void *vpecdhctx
, unsigned char *secret
,
550 size_t *psecretlen
, size_t outlen
)
552 PROV_ECDH_CTX
*pecdhctx
= (PROV_ECDH_CTX
*)vpecdhctx
;
554 switch (pecdhctx
->kdf_type
) {
555 case PROV_ECDH_KDF_NONE
:
556 return ecdh_plain_derive(vpecdhctx
, secret
, psecretlen
, outlen
);
557 case PROV_ECDH_KDF_X9_63
:
558 return ecdh_X9_63_kdf_derive(vpecdhctx
, secret
, psecretlen
, outlen
);
565 const OSSL_DISPATCH ossl_ecdh_keyexch_functions
[] = {
566 { OSSL_FUNC_KEYEXCH_NEWCTX
, (void (*)(void))ecdh_newctx
},
567 { OSSL_FUNC_KEYEXCH_INIT
, (void (*)(void))ecdh_init
},
568 { OSSL_FUNC_KEYEXCH_DERIVE
, (void (*)(void))ecdh_derive
},
569 { OSSL_FUNC_KEYEXCH_SET_PEER
, (void (*)(void))ecdh_set_peer
},
570 { OSSL_FUNC_KEYEXCH_FREECTX
, (void (*)(void))ecdh_freectx
},
571 { OSSL_FUNC_KEYEXCH_DUPCTX
, (void (*)(void))ecdh_dupctx
},
572 { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS
, (void (*)(void))ecdh_set_ctx_params
},
573 { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS
,
574 (void (*)(void))ecdh_settable_ctx_params
},
575 { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS
, (void (*)(void))ecdh_get_ctx_params
},
576 { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS
,
577 (void (*)(void))ecdh_gettable_ctx_params
},