2 * Copyright 2020 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 "prov/provider_ctx.h"
25 #include "prov/implementations.h"
26 #include "crypto/ec.h" /* ecdh_KDF_X9_63() */
28 static OSSL_OP_keyexch_newctx_fn ecdh_newctx
;
29 static OSSL_OP_keyexch_init_fn ecdh_init
;
30 static OSSL_OP_keyexch_set_peer_fn ecdh_set_peer
;
31 static OSSL_OP_keyexch_derive_fn ecdh_derive
;
32 static OSSL_OP_keyexch_freectx_fn ecdh_freectx
;
33 static OSSL_OP_keyexch_dupctx_fn ecdh_dupctx
;
34 static OSSL_OP_keyexch_set_ctx_params_fn ecdh_set_ctx_params
;
35 static OSSL_OP_keyexch_settable_ctx_params_fn ecdh_settable_ctx_params
;
36 static OSSL_OP_keyexch_get_ctx_params_fn ecdh_get_ctx_params
;
37 static OSSL_OP_keyexch_gettable_ctx_params_fn ecdh_gettable_ctx_params
;
40 PROV_ECDH_KDF_NONE
= 0,
45 * What's passed as an actual key is defined by the KEYMGMT interface.
46 * We happen to know that our KEYMGMT simply passes EC_KEY structures, so
47 * we use that here too.
61 * . -1 use cofactor mode set for k
68 /* KDF (if any) to use for ECDH */
69 enum kdf_type kdf_type
;
70 /* Message digest to use for key derivation */
72 /* User key material */
73 unsigned char *kdf_ukm
;
75 /* KDF output length */
80 void *ecdh_newctx(void *provctx
)
82 PROV_ECDH_CTX
*pectx
= OPENSSL_zalloc(sizeof(*pectx
));
87 pectx
->libctx
= PROV_LIBRARY_CONTEXT_OF(provctx
);
88 pectx
->cofactor_mode
= -1;
89 pectx
->kdf_type
= PROV_ECDH_KDF_NONE
;
95 int ecdh_init(void *vpecdhctx
, void *vecdh
)
97 PROV_ECDH_CTX
*pecdhctx
= (PROV_ECDH_CTX
*)vpecdhctx
;
99 if (pecdhctx
== NULL
|| vecdh
== NULL
|| !EC_KEY_up_ref(vecdh
))
101 EC_KEY_free(pecdhctx
->k
);
103 pecdhctx
->cofactor_mode
= -1;
104 pecdhctx
->kdf_type
= PROV_ECDH_KDF_NONE
;
109 int ecdh_set_peer(void *vpecdhctx
, void *vecdh
)
111 PROV_ECDH_CTX
*pecdhctx
= (PROV_ECDH_CTX
*)vpecdhctx
;
113 if (pecdhctx
== NULL
|| vecdh
== NULL
|| !EC_KEY_up_ref(vecdh
))
115 EC_KEY_free(pecdhctx
->peerk
);
116 pecdhctx
->peerk
= vecdh
;
121 void ecdh_freectx(void *vpecdhctx
)
123 PROV_ECDH_CTX
*pecdhctx
= (PROV_ECDH_CTX
*)vpecdhctx
;
125 EC_KEY_free(pecdhctx
->k
);
126 EC_KEY_free(pecdhctx
->peerk
);
128 EVP_MD_free(pecdhctx
->kdf_md
);
129 OPENSSL_clear_free(pecdhctx
->kdf_ukm
, pecdhctx
->kdf_ukmlen
);
131 OPENSSL_free(pecdhctx
);
135 void *ecdh_dupctx(void *vpecdhctx
)
137 PROV_ECDH_CTX
*srcctx
= (PROV_ECDH_CTX
*)vpecdhctx
;
138 PROV_ECDH_CTX
*dstctx
;
140 dstctx
= OPENSSL_zalloc(sizeof(*srcctx
));
146 /* clear all pointers */
149 dstctx
->peerk
= NULL
;
150 dstctx
->kdf_md
= NULL
;
151 dstctx
->kdf_ukm
= NULL
;
153 /* up-ref all ref-counted objects referenced in dstctx */
155 if (srcctx
->k
!= NULL
&& !EC_KEY_up_ref(srcctx
->k
))
158 dstctx
->k
= srcctx
->k
;
160 if (srcctx
->peerk
!= NULL
&& !EC_KEY_up_ref(srcctx
->peerk
))
163 dstctx
->peerk
= srcctx
->peerk
;
165 if (srcctx
->kdf_md
!= NULL
&& !EVP_MD_up_ref(srcctx
->kdf_md
))
168 dstctx
->kdf_md
= srcctx
->kdf_md
;
170 /* Duplicate UKM data if present */
171 if (srcctx
->kdf_ukm
!= NULL
&& srcctx
->kdf_ukmlen
> 0) {
172 dstctx
->kdf_ukm
= OPENSSL_memdup(srcctx
->kdf_ukm
,
174 if (dstctx
->kdf_ukm
== NULL
)
181 ecdh_freectx(dstctx
);
186 int ecdh_set_ctx_params(void *vpecdhctx
, const OSSL_PARAM params
[])
188 char name
[80] = { '\0' }; /* should be big enough */
190 PROV_ECDH_CTX
*pectx
= (PROV_ECDH_CTX
*)vpecdhctx
;
193 if (pectx
== NULL
|| params
== NULL
)
196 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE
);
200 if (!OSSL_PARAM_get_int(p
, &mode
))
203 if (mode
< -1 || mode
> 1)
206 pectx
->cofactor_mode
= mode
;
209 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_TYPE
);
212 if (!OSSL_PARAM_get_utf8_string(p
, &str
, sizeof(name
)))
216 pectx
->kdf_type
= PROV_ECDH_KDF_NONE
;
217 else if (strcmp(name
, OSSL_KDF_NAME_X963KDF
) == 0)
218 pectx
->kdf_type
= PROV_ECDH_KDF_X9_63
;
223 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_DIGEST
);
225 char mdprops
[80] = { '\0' }; /* should be big enough */
228 if (!OSSL_PARAM_get_utf8_string(p
, &str
, sizeof(name
)))
232 p
= OSSL_PARAM_locate_const(params
,
233 OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS
);
236 if (!OSSL_PARAM_get_utf8_string(p
, &str
, sizeof(mdprops
)))
240 EVP_MD_free(pectx
->kdf_md
);
241 pectx
->kdf_md
= EVP_MD_fetch(pectx
->libctx
, name
, mdprops
);
243 if (pectx
->kdf_md
== NULL
)
247 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_OUTLEN
);
251 if (!OSSL_PARAM_get_size_t(p
, &outlen
))
253 pectx
->kdf_outlen
= outlen
;
256 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_UKM
);
258 void *tmp_ukm
= NULL
;
261 if (!OSSL_PARAM_get_octet_string(p
, &tmp_ukm
, 0, &tmp_ukmlen
))
263 OPENSSL_free(pectx
->kdf_ukm
);
264 pectx
->kdf_ukm
= tmp_ukm
;
265 pectx
->kdf_ukmlen
= tmp_ukmlen
;
271 static const OSSL_PARAM known_settable_ctx_params
[] = {
272 OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE
, NULL
),
273 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE
, NULL
, 0),
274 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST
, NULL
, 0),
275 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS
, NULL
, 0),
276 OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN
, NULL
),
277 OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM
, NULL
, 0),
282 const OSSL_PARAM
*ecdh_settable_ctx_params(void)
284 return known_settable_ctx_params
;
288 int ecdh_get_ctx_params(void *vpecdhctx
, OSSL_PARAM params
[])
290 PROV_ECDH_CTX
*pectx
= (PROV_ECDH_CTX
*)vpecdhctx
;
293 if (pectx
== NULL
|| params
== NULL
)
296 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE
);
298 int mode
= pectx
->cofactor_mode
;
301 /* check what is the default for pecdhctx->k */
302 mode
= EC_KEY_get_flags(pectx
->k
) & EC_FLAG_COFACTOR_ECDH
? 1 : 0;
305 if (!OSSL_PARAM_set_int(p
, mode
))
309 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_TYPE
);
311 const char *kdf_type
= NULL
;
313 switch (pectx
->kdf_type
) {
314 case PROV_ECDH_KDF_NONE
:
317 case PROV_ECDH_KDF_X9_63
:
318 kdf_type
= OSSL_KDF_NAME_X963KDF
;
324 if (!OSSL_PARAM_set_utf8_string(p
, kdf_type
))
328 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_DIGEST
);
330 && !OSSL_PARAM_set_utf8_string(p
, pectx
->kdf_md
== NULL
332 : EVP_MD_name(pectx
->kdf_md
))){
336 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_OUTLEN
);
337 if (p
!= NULL
&& !OSSL_PARAM_set_size_t(p
, pectx
->kdf_outlen
))
340 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_UKM
);
341 if (p
!= NULL
&& !OSSL_PARAM_set_octet_ptr(p
, pectx
->kdf_ukm
, 0))
344 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_UKM_LEN
);
345 if (p
!= NULL
&& !OSSL_PARAM_set_size_t(p
, pectx
->kdf_ukmlen
))
351 static const OSSL_PARAM known_gettable_ctx_params
[] = {
352 OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE
, NULL
),
353 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE
, NULL
, 0),
354 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST
, NULL
, 0),
355 OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN
, NULL
),
356 OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM
, OSSL_PARAM_OCTET_PTR
,
358 OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_UKM_LEN
, NULL
),
363 const OSSL_PARAM
*ecdh_gettable_ctx_params(void)
365 return known_gettable_ctx_params
;
369 size_t ecdh_size(const EC_KEY
*k
)
372 const EC_GROUP
*group
;
375 || (group
= EC_KEY_get0_group(k
)) == NULL
)
378 degree
= EC_GROUP_get_degree(group
);
380 return (degree
+ 7) / 8;
384 int ecdh_plain_derive(void *vpecdhctx
, unsigned char *secret
,
385 size_t *psecretlen
, size_t outlen
)
387 PROV_ECDH_CTX
*pecdhctx
= (PROV_ECDH_CTX
*)vpecdhctx
;
389 size_t ecdhsize
, size
;
390 const EC_POINT
*ppubkey
= NULL
;
391 EC_KEY
*privk
= NULL
;
392 const EC_GROUP
*group
;
393 const BIGNUM
*cofactor
;
394 int key_cofactor_mode
;
396 if (pecdhctx
->k
== NULL
|| pecdhctx
->peerk
== NULL
) {
397 ERR_raise(ERR_LIB_PROV
, EC_R_KEYS_NOT_SET
);
401 ecdhsize
= ecdh_size(pecdhctx
->k
);
402 if (secret
== NULL
) {
403 *psecretlen
= ecdhsize
;
407 if ((group
= EC_KEY_get0_group(pecdhctx
->k
)) == NULL
408 || (cofactor
= EC_GROUP_get0_cofactor(group
)) == NULL
)
412 * NB: unlike PKCS#3 DH, if outlen is less than maximum size this is not
413 * an error, the result is truncated.
415 size
= outlen
< ecdhsize
? outlen
: ecdhsize
;
418 * The ctx->cofactor_mode flag has precedence over the
419 * cofactor_mode flag set on ctx->k.
421 * - if ctx->cofactor_mode == -1, use ctx->k directly
422 * - if ctx->cofactor_mode == key_cofactor_mode, use ctx->k directly
423 * - if ctx->cofactor_mode != key_cofactor_mode:
424 * - if ctx->k->cofactor == 1, the cofactor_mode flag is irrelevant, use
426 * - if ctx->k->cofactor != 1, use a duplicate of ctx->k with the flag
427 * set to ctx->cofactor_mode
430 (EC_KEY_get_flags(pecdhctx
->k
) & EC_FLAG_COFACTOR_ECDH
) ? 1 : 0;
431 if (pecdhctx
->cofactor_mode
!= -1
432 && pecdhctx
->cofactor_mode
!= key_cofactor_mode
433 && !BN_is_one(cofactor
)) {
434 if ((privk
= EC_KEY_dup(pecdhctx
->k
)) == NULL
)
437 if (pecdhctx
->cofactor_mode
== 1)
438 EC_KEY_set_flags(privk
, EC_FLAG_COFACTOR_ECDH
);
440 EC_KEY_clear_flags(privk
, EC_FLAG_COFACTOR_ECDH
);
445 ppubkey
= EC_KEY_get0_public_key(pecdhctx
->peerk
);
447 retlen
= ECDH_compute_key(secret
, size
, ppubkey
, privk
, NULL
);
452 *psecretlen
= retlen
;
456 if (privk
!= pecdhctx
->k
)
463 int ecdh_X9_63_kdf_derive(void *vpecdhctx
, unsigned char *secret
,
464 size_t *psecretlen
, size_t outlen
)
466 PROV_ECDH_CTX
*pecdhctx
= (PROV_ECDH_CTX
*)vpecdhctx
;
467 unsigned char *stmp
= NULL
;
471 if (secret
== NULL
) {
472 *psecretlen
= pecdhctx
->kdf_outlen
;
476 if (pecdhctx
->kdf_outlen
> outlen
)
478 if (!ecdh_plain_derive(vpecdhctx
, NULL
, &stmplen
, 0))
480 if ((stmp
= OPENSSL_secure_malloc(stmplen
)) == NULL
) {
481 ERR_raise(ERR_LIB_PROV
, ERR_R_MALLOC_FAILURE
);
484 if (!ecdh_plain_derive(vpecdhctx
, stmp
, &stmplen
, stmplen
))
488 if (!ecdh_KDF_X9_63(secret
, pecdhctx
->kdf_outlen
,
491 pecdhctx
->kdf_ukmlen
,
494 *psecretlen
= pecdhctx
->kdf_outlen
;
498 OPENSSL_secure_clear_free(stmp
, stmplen
);
501 #endif /* FIPS_MODULE */
504 int ecdh_derive(void *vpecdhctx
, unsigned char *secret
,
505 size_t *psecretlen
, size_t outlen
)
507 PROV_ECDH_CTX
*pecdhctx
= (PROV_ECDH_CTX
*)vpecdhctx
;
509 switch (pecdhctx
->kdf_type
) {
510 case PROV_ECDH_KDF_NONE
:
511 return ecdh_plain_derive(vpecdhctx
, secret
, psecretlen
, outlen
);
513 case PROV_ECDH_KDF_X9_63
:
514 return ecdh_X9_63_kdf_derive(vpecdhctx
, secret
, psecretlen
, outlen
);
516 #endif /* FIPS_MODULE */
526 const OSSL_DISPATCH ecdh_keyexch_functions
[] = {
527 { OSSL_FUNC_KEYEXCH_NEWCTX
, (void (*)(void))ecdh_newctx
},
528 { OSSL_FUNC_KEYEXCH_INIT
, (void (*)(void))ecdh_init
},
529 { OSSL_FUNC_KEYEXCH_DERIVE
, (void (*)(void))ecdh_derive
},
530 { OSSL_FUNC_KEYEXCH_SET_PEER
, (void (*)(void))ecdh_set_peer
},
531 { OSSL_FUNC_KEYEXCH_FREECTX
, (void (*)(void))ecdh_freectx
},
532 { OSSL_FUNC_KEYEXCH_DUPCTX
, (void (*)(void))ecdh_dupctx
},
533 { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS
, (void (*)(void))ecdh_set_ctx_params
},
534 { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS
,
535 (void (*)(void))ecdh_settable_ctx_params
},
536 { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS
, (void (*)(void))ecdh_get_ctx_params
},
537 { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS
,
538 (void (*)(void))ecdh_gettable_ctx_params
},