2 * Copyright 2019-2021 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 * DH 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/core_dispatch.h>
19 #include <openssl/core_names.h>
20 #include <openssl/dh.h>
21 #include <openssl/err.h>
22 #include <openssl/proverr.h>
23 #include <openssl/params.h>
24 #include "prov/providercommon.h"
25 #include "prov/implementations.h"
26 #include "prov/provider_ctx.h"
27 #include "prov/securitycheck.h"
28 #include "crypto/dh.h"
30 static OSSL_FUNC_keyexch_newctx_fn dh_newctx
;
31 static OSSL_FUNC_keyexch_init_fn dh_init
;
32 static OSSL_FUNC_keyexch_set_peer_fn dh_set_peer
;
33 static OSSL_FUNC_keyexch_derive_fn dh_derive
;
34 static OSSL_FUNC_keyexch_freectx_fn dh_freectx
;
35 static OSSL_FUNC_keyexch_dupctx_fn dh_dupctx
;
36 static OSSL_FUNC_keyexch_set_ctx_params_fn dh_set_ctx_params
;
37 static OSSL_FUNC_keyexch_settable_ctx_params_fn dh_settable_ctx_params
;
38 static OSSL_FUNC_keyexch_get_ctx_params_fn dh_get_ctx_params
;
39 static OSSL_FUNC_keyexch_gettable_ctx_params_fn dh_gettable_ctx_params
;
42 * This type is only really used to handle some legacy related functionality.
43 * If you need to use other KDF's (such as SSKDF) just use PROV_DH_KDF_NONE
44 * here and then create and run a KDF after the key is derived.
45 * Note that X942 has 2 variants of key derivation:
46 * (1) DH_KDF_X9_42_ASN1 - which contains an ANS1 encoded object that has
47 * the counter embedded in it.
48 * (2) DH_KDF_X941_CONCAT - which is the same as ECDH_X963_KDF (which can be
49 * done by creating a "X963KDF".
53 PROV_DH_KDF_X9_42_ASN1
57 * What's passed as an actual key is defined by the KEYMGMT interface.
58 * We happen to know that our KEYMGMT simply passes DH structures, so
59 * we use that here too.
69 /* KDF (if any) to use for DH */
70 enum kdf_type kdf_type
;
71 /* Message digest to use for key derivation */
73 /* User key material */
74 unsigned char *kdf_ukm
;
76 /* KDF output length */
81 static void *dh_newctx(void *provctx
)
85 if (!ossl_prov_is_running())
88 pdhctx
= OPENSSL_zalloc(sizeof(PROV_DH_CTX
));
91 pdhctx
->libctx
= PROV_LIBCTX_OF(provctx
);
92 pdhctx
->kdf_type
= PROV_DH_KDF_NONE
;
96 static int dh_init(void *vpdhctx
, void *vdh
, const OSSL_PARAM params
[])
98 PROV_DH_CTX
*pdhctx
= (PROV_DH_CTX
*)vpdhctx
;
100 if (!ossl_prov_is_running()
107 pdhctx
->kdf_type
= PROV_DH_KDF_NONE
;
108 return dh_set_ctx_params(pdhctx
, params
) && ossl_dh_check_key(vdh
);
111 /* The 2 parties must share the same domain parameters */
112 static int dh_match_params(DH
*priv
, DH
*peer
)
115 FFC_PARAMS
*dhparams_priv
= ossl_dh_get0_params(priv
);
116 FFC_PARAMS
*dhparams_peer
= ossl_dh_get0_params(peer
);
118 ret
= dhparams_priv
!= NULL
119 && dhparams_peer
!= NULL
120 && ossl_ffc_params_cmp(dhparams_priv
, dhparams_peer
, 1);
122 ERR_raise(ERR_LIB_PROV
, PROV_R_MISMATCHING_DOMAIN_PARAMETERS
);
126 static int dh_set_peer(void *vpdhctx
, void *vdh
)
128 PROV_DH_CTX
*pdhctx
= (PROV_DH_CTX
*)vpdhctx
;
130 if (!ossl_prov_is_running()
133 || !dh_match_params(vdh
, pdhctx
->dh
)
136 DH_free(pdhctx
->dhpeer
);
137 pdhctx
->dhpeer
= vdh
;
141 static int dh_plain_derive(void *vpdhctx
,
142 unsigned char *secret
, size_t *secretlen
,
145 PROV_DH_CTX
*pdhctx
= (PROV_DH_CTX
*)vpdhctx
;
148 const BIGNUM
*pub_key
= NULL
;
150 if (pdhctx
->dh
== NULL
|| pdhctx
->dhpeer
== NULL
) {
151 ERR_raise(ERR_LIB_PROV
, PROV_R_MISSING_KEY
);
155 dhsize
= (size_t)DH_size(pdhctx
->dh
);
156 if (secret
== NULL
) {
160 if (outlen
< dhsize
) {
161 ERR_raise(ERR_LIB_PROV
, PROV_R_OUTPUT_BUFFER_TOO_SMALL
);
165 DH_get0_key(pdhctx
->dhpeer
, &pub_key
, NULL
);
167 ret
= DH_compute_key_padded(secret
, pub_key
, pdhctx
->dh
);
169 ret
= DH_compute_key(secret
, pub_key
, pdhctx
->dh
);
177 static int dh_X9_42_kdf_derive(void *vpdhctx
, unsigned char *secret
,
178 size_t *secretlen
, size_t outlen
)
180 PROV_DH_CTX
*pdhctx
= (PROV_DH_CTX
*)vpdhctx
;
181 unsigned char *stmp
= NULL
;
185 if (secret
== NULL
) {
186 *secretlen
= pdhctx
->kdf_outlen
;
190 if (pdhctx
->kdf_outlen
> outlen
) {
191 ERR_raise(ERR_LIB_PROV
, PROV_R_OUTPUT_BUFFER_TOO_SMALL
);
194 if (!dh_plain_derive(pdhctx
, NULL
, &stmplen
, 0))
196 if ((stmp
= OPENSSL_secure_malloc(stmplen
)) == NULL
) {
197 ERR_raise(ERR_LIB_PROV
, ERR_R_MALLOC_FAILURE
);
200 if (!dh_plain_derive(pdhctx
, stmp
, &stmplen
, stmplen
))
204 if (pdhctx
->kdf_type
== PROV_DH_KDF_X9_42_ASN1
) {
205 if (!ossl_dh_kdf_X9_42_asn1(secret
, pdhctx
->kdf_outlen
,
211 pdhctx
->libctx
, NULL
))
214 *secretlen
= pdhctx
->kdf_outlen
;
217 OPENSSL_secure_clear_free(stmp
, stmplen
);
221 static int dh_derive(void *vpdhctx
, unsigned char *secret
,
222 size_t *psecretlen
, size_t outlen
)
224 PROV_DH_CTX
*pdhctx
= (PROV_DH_CTX
*)vpdhctx
;
226 if (!ossl_prov_is_running())
229 switch (pdhctx
->kdf_type
) {
230 case PROV_DH_KDF_NONE
:
231 return dh_plain_derive(pdhctx
, secret
, psecretlen
, outlen
);
232 case PROV_DH_KDF_X9_42_ASN1
:
233 return dh_X9_42_kdf_derive(pdhctx
, secret
, psecretlen
, outlen
);
241 static void dh_freectx(void *vpdhctx
)
243 PROV_DH_CTX
*pdhctx
= (PROV_DH_CTX
*)vpdhctx
;
245 OPENSSL_free(pdhctx
->kdf_cekalg
);
247 DH_free(pdhctx
->dhpeer
);
248 EVP_MD_free(pdhctx
->kdf_md
);
249 OPENSSL_clear_free(pdhctx
->kdf_ukm
, pdhctx
->kdf_ukmlen
);
251 OPENSSL_free(pdhctx
);
254 static void *dh_dupctx(void *vpdhctx
)
256 PROV_DH_CTX
*srcctx
= (PROV_DH_CTX
*)vpdhctx
;
259 if (!ossl_prov_is_running())
262 dstctx
= OPENSSL_zalloc(sizeof(*srcctx
));
268 dstctx
->dhpeer
= NULL
;
269 dstctx
->kdf_md
= NULL
;
270 dstctx
->kdf_ukm
= NULL
;
271 dstctx
->kdf_cekalg
= NULL
;
273 if (dstctx
->dh
!= NULL
&& !DH_up_ref(srcctx
->dh
))
276 dstctx
->dh
= srcctx
->dh
;
278 if (dstctx
->dhpeer
!= NULL
&& !DH_up_ref(srcctx
->dhpeer
))
281 dstctx
->dhpeer
= srcctx
->dhpeer
;
283 if (srcctx
->kdf_md
!= NULL
&& !EVP_MD_up_ref(srcctx
->kdf_md
))
286 dstctx
->kdf_md
= srcctx
->kdf_md
;
288 /* Duplicate UKM data if present */
289 if (srcctx
->kdf_ukm
!= NULL
&& srcctx
->kdf_ukmlen
> 0) {
290 dstctx
->kdf_ukm
= OPENSSL_memdup(srcctx
->kdf_ukm
,
292 if (dstctx
->kdf_ukm
== NULL
)
295 dstctx
->kdf_cekalg
= OPENSSL_strdup(srcctx
->kdf_cekalg
);
303 static int dh_set_ctx_params(void *vpdhctx
, const OSSL_PARAM params
[])
305 PROV_DH_CTX
*pdhctx
= (PROV_DH_CTX
*)vpdhctx
;
308 char name
[80] = { '\0' }; /* should be big enough */
316 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_TYPE
);
319 if (!OSSL_PARAM_get_utf8_string(p
, &str
, sizeof(name
)))
323 pdhctx
->kdf_type
= PROV_DH_KDF_NONE
;
324 else if (strcmp(name
, OSSL_KDF_NAME_X942KDF_ASN1
) == 0)
325 pdhctx
->kdf_type
= PROV_DH_KDF_X9_42_ASN1
;
329 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_DIGEST
);
331 char mdprops
[80] = { '\0' }; /* should be big enough */
334 if (!OSSL_PARAM_get_utf8_string(p
, &str
, sizeof(name
)))
338 p
= OSSL_PARAM_locate_const(params
,
339 OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS
);
342 if (!OSSL_PARAM_get_utf8_string(p
, &str
, sizeof(mdprops
)))
346 EVP_MD_free(pdhctx
->kdf_md
);
347 pdhctx
->kdf_md
= EVP_MD_fetch(pdhctx
->libctx
, name
, mdprops
);
348 if (!ossl_digest_is_allowed(pdhctx
->kdf_md
)) {
349 EVP_MD_free(pdhctx
->kdf_md
);
350 pdhctx
->kdf_md
= NULL
;
352 if (pdhctx
->kdf_md
== NULL
)
356 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_OUTLEN
);
360 if (!OSSL_PARAM_get_size_t(p
, &outlen
))
362 pdhctx
->kdf_outlen
= outlen
;
365 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_UKM
);
367 void *tmp_ukm
= NULL
;
370 OPENSSL_free(pdhctx
->kdf_ukm
);
371 pdhctx
->kdf_ukm
= NULL
;
372 pdhctx
->kdf_ukmlen
= 0;
373 /* ukm is an optional field so it can be NULL */
374 if (p
->data
!= NULL
&& p
->data_size
!= 0) {
375 if (!OSSL_PARAM_get_octet_string(p
, &tmp_ukm
, 0, &tmp_ukmlen
))
377 pdhctx
->kdf_ukm
= tmp_ukm
;
378 pdhctx
->kdf_ukmlen
= tmp_ukmlen
;
382 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_PAD
);
384 if (!OSSL_PARAM_get_uint(p
, &pad
))
386 pdhctx
->pad
= pad
? 1 : 0;
389 p
= OSSL_PARAM_locate_const(params
, OSSL_KDF_PARAM_CEK_ALG
);
392 if (!OSSL_PARAM_get_utf8_string(p
, &str
, sizeof(name
)))
394 pdhctx
->kdf_cekalg
= OPENSSL_strdup(name
);
399 static const OSSL_PARAM known_settable_ctx_params
[] = {
400 OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_PAD
, NULL
),
401 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE
, NULL
, 0),
402 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST
, NULL
, 0),
403 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS
, NULL
, 0),
404 OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN
, NULL
),
405 OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM
, NULL
, 0),
406 OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG
, NULL
, 0),
410 static const OSSL_PARAM
*dh_settable_ctx_params(ossl_unused
void *vpdhctx
,
411 ossl_unused
void *provctx
)
413 return known_settable_ctx_params
;
416 static const OSSL_PARAM known_gettable_ctx_params
[] = {
417 OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE
, NULL
),
418 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE
, NULL
, 0),
419 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST
, NULL
, 0),
420 OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN
, NULL
),
421 OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM
, OSSL_PARAM_OCTET_PTR
,
426 static const OSSL_PARAM
*dh_gettable_ctx_params(ossl_unused
void *vpdhctx
,
427 ossl_unused
void *provctx
)
429 return known_gettable_ctx_params
;
432 static int dh_get_ctx_params(void *vpdhctx
, OSSL_PARAM params
[])
434 PROV_DH_CTX
*pdhctx
= (PROV_DH_CTX
*)vpdhctx
;
440 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_TYPE
);
442 const char *kdf_type
= NULL
;
444 switch (pdhctx
->kdf_type
) {
445 case PROV_DH_KDF_NONE
:
448 case PROV_DH_KDF_X9_42_ASN1
:
449 kdf_type
= OSSL_KDF_NAME_X942KDF_ASN1
;
455 if (!OSSL_PARAM_set_utf8_string(p
, kdf_type
))
459 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_DIGEST
);
461 && !OSSL_PARAM_set_utf8_string(p
, pdhctx
->kdf_md
== NULL
463 : EVP_MD_name(pdhctx
->kdf_md
))){
467 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_OUTLEN
);
468 if (p
!= NULL
&& !OSSL_PARAM_set_size_t(p
, pdhctx
->kdf_outlen
))
471 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_UKM
);
473 && !OSSL_PARAM_set_octet_ptr(p
, pdhctx
->kdf_ukm
, pdhctx
->kdf_ukmlen
))
476 p
= OSSL_PARAM_locate(params
, OSSL_KDF_PARAM_CEK_ALG
);
478 && !OSSL_PARAM_set_utf8_string(p
, pdhctx
->kdf_cekalg
== NULL
479 ? "" : pdhctx
->kdf_cekalg
))
485 const OSSL_DISPATCH ossl_dh_keyexch_functions
[] = {
486 { OSSL_FUNC_KEYEXCH_NEWCTX
, (void (*)(void))dh_newctx
},
487 { OSSL_FUNC_KEYEXCH_INIT
, (void (*)(void))dh_init
},
488 { OSSL_FUNC_KEYEXCH_DERIVE
, (void (*)(void))dh_derive
},
489 { OSSL_FUNC_KEYEXCH_SET_PEER
, (void (*)(void))dh_set_peer
},
490 { OSSL_FUNC_KEYEXCH_FREECTX
, (void (*)(void))dh_freectx
},
491 { OSSL_FUNC_KEYEXCH_DUPCTX
, (void (*)(void))dh_dupctx
},
492 { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS
, (void (*)(void))dh_set_ctx_params
},
493 { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS
,
494 (void (*)(void))dh_settable_ctx_params
},
495 { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS
, (void (*)(void))dh_get_ctx_params
},
496 { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS
,
497 (void (*)(void))dh_gettable_ctx_params
},