2 * Copyright 2019-2023 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
)
109 && ossl_dh_check_key(pdhctx
->libctx
, vdh
);
112 /* The 2 parties must share the same domain parameters */
113 static int dh_match_params(DH
*priv
, DH
*peer
)
116 FFC_PARAMS
*dhparams_priv
= ossl_dh_get0_params(priv
);
117 FFC_PARAMS
*dhparams_peer
= ossl_dh_get0_params(peer
);
119 ret
= dhparams_priv
!= NULL
120 && dhparams_peer
!= NULL
121 && ossl_ffc_params_cmp(dhparams_priv
, dhparams_peer
, 1);
123 ERR_raise(ERR_LIB_PROV
, PROV_R_MISMATCHING_DOMAIN_PARAMETERS
);
127 static int dh_set_peer(void *vpdhctx
, void *vdh
)
129 PROV_DH_CTX
*pdhctx
= (PROV_DH_CTX
*)vpdhctx
;
131 if (!ossl_prov_is_running()
134 || !dh_match_params(vdh
, pdhctx
->dh
)
137 DH_free(pdhctx
->dhpeer
);
138 pdhctx
->dhpeer
= vdh
;
142 static int dh_plain_derive(void *vpdhctx
,
143 unsigned char *secret
, size_t *secretlen
,
144 size_t outlen
, unsigned int pad
)
146 PROV_DH_CTX
*pdhctx
= (PROV_DH_CTX
*)vpdhctx
;
149 const BIGNUM
*pub_key
= NULL
;
151 if (pdhctx
->dh
== NULL
|| pdhctx
->dhpeer
== NULL
) {
152 ERR_raise(ERR_LIB_PROV
, PROV_R_MISSING_KEY
);
156 dhsize
= (size_t)DH_size(pdhctx
->dh
);
157 if (secret
== NULL
) {
161 if (outlen
< dhsize
) {
162 ERR_raise(ERR_LIB_PROV
, PROV_R_OUTPUT_BUFFER_TOO_SMALL
);
166 DH_get0_key(pdhctx
->dhpeer
, &pub_key
, NULL
);
168 ret
= DH_compute_key_padded(secret
, pub_key
, pdhctx
->dh
);
170 ret
= DH_compute_key(secret
, pub_key
, pdhctx
->dh
);
178 static int dh_X9_42_kdf_derive(void *vpdhctx
, unsigned char *secret
,
179 size_t *secretlen
, size_t outlen
)
181 PROV_DH_CTX
*pdhctx
= (PROV_DH_CTX
*)vpdhctx
;
182 unsigned char *stmp
= NULL
;
186 if (secret
== NULL
) {
187 *secretlen
= pdhctx
->kdf_outlen
;
191 if (pdhctx
->kdf_outlen
> outlen
) {
192 ERR_raise(ERR_LIB_PROV
, PROV_R_OUTPUT_BUFFER_TOO_SMALL
);
195 if (!dh_plain_derive(pdhctx
, NULL
, &stmplen
, 0, 1))
197 if ((stmp
= OPENSSL_secure_malloc(stmplen
)) == NULL
)
199 if (!dh_plain_derive(pdhctx
, stmp
, &stmplen
, stmplen
, 1))
203 if (pdhctx
->kdf_type
== PROV_DH_KDF_X9_42_ASN1
) {
204 if (!ossl_dh_kdf_X9_42_asn1(secret
, pdhctx
->kdf_outlen
,
210 pdhctx
->libctx
, NULL
))
213 *secretlen
= pdhctx
->kdf_outlen
;
216 OPENSSL_secure_clear_free(stmp
, stmplen
);
220 static int dh_derive(void *vpdhctx
, unsigned char *secret
,
221 size_t *psecretlen
, size_t outlen
)
223 PROV_DH_CTX
*pdhctx
= (PROV_DH_CTX
*)vpdhctx
;
225 if (!ossl_prov_is_running())
228 switch (pdhctx
->kdf_type
) {
229 case PROV_DH_KDF_NONE
:
230 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
);
240 static void dh_freectx(void *vpdhctx
)
242 PROV_DH_CTX
*pdhctx
= (PROV_DH_CTX
*)vpdhctx
;
244 OPENSSL_free(pdhctx
->kdf_cekalg
);
246 DH_free(pdhctx
->dhpeer
);
247 EVP_MD_free(pdhctx
->kdf_md
);
248 OPENSSL_clear_free(pdhctx
->kdf_ukm
, pdhctx
->kdf_ukmlen
);
250 OPENSSL_free(pdhctx
);
253 static void *dh_dupctx(void *vpdhctx
)
255 PROV_DH_CTX
*srcctx
= (PROV_DH_CTX
*)vpdhctx
;
258 if (!ossl_prov_is_running())
261 dstctx
= OPENSSL_zalloc(sizeof(*srcctx
));
267 dstctx
->dhpeer
= NULL
;
268 dstctx
->kdf_md
= NULL
;
269 dstctx
->kdf_ukm
= NULL
;
270 dstctx
->kdf_cekalg
= NULL
;
272 if (srcctx
->dh
!= NULL
&& !DH_up_ref(srcctx
->dh
))
275 dstctx
->dh
= srcctx
->dh
;
277 if (srcctx
->dhpeer
!= NULL
&& !DH_up_ref(srcctx
->dhpeer
))
280 dstctx
->dhpeer
= srcctx
->dhpeer
;
282 if (srcctx
->kdf_md
!= NULL
&& !EVP_MD_up_ref(srcctx
->kdf_md
))
285 dstctx
->kdf_md
= srcctx
->kdf_md
;
287 /* Duplicate UKM data if present */
288 if (srcctx
->kdf_ukm
!= NULL
&& srcctx
->kdf_ukmlen
> 0) {
289 dstctx
->kdf_ukm
= OPENSSL_memdup(srcctx
->kdf_ukm
,
291 if (dstctx
->kdf_ukm
== NULL
)
295 if (srcctx
->kdf_cekalg
!= NULL
) {
296 dstctx
->kdf_cekalg
= OPENSSL_strdup(srcctx
->kdf_cekalg
);
297 if (dstctx
->kdf_cekalg
== NULL
)
307 static int dh_set_ctx_params(void *vpdhctx
, const OSSL_PARAM params
[])
309 PROV_DH_CTX
*pdhctx
= (PROV_DH_CTX
*)vpdhctx
;
312 char name
[80] = { '\0' }; /* should be big enough */
320 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_TYPE
);
323 if (!OSSL_PARAM_get_utf8_string(p
, &str
, sizeof(name
)))
327 pdhctx
->kdf_type
= PROV_DH_KDF_NONE
;
328 else if (strcmp(name
, OSSL_KDF_NAME_X942KDF_ASN1
) == 0)
329 pdhctx
->kdf_type
= PROV_DH_KDF_X9_42_ASN1
;
333 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_DIGEST
);
335 char mdprops
[80] = { '\0' }; /* should be big enough */
338 if (!OSSL_PARAM_get_utf8_string(p
, &str
, sizeof(name
)))
342 p
= OSSL_PARAM_locate_const(params
,
343 OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS
);
346 if (!OSSL_PARAM_get_utf8_string(p
, &str
, sizeof(mdprops
)))
350 EVP_MD_free(pdhctx
->kdf_md
);
351 pdhctx
->kdf_md
= EVP_MD_fetch(pdhctx
->libctx
, name
, mdprops
);
352 if (pdhctx
->kdf_md
== NULL
)
354 if (!ossl_digest_is_allowed(pdhctx
->libctx
, pdhctx
->kdf_md
)) {
355 EVP_MD_free(pdhctx
->kdf_md
);
356 pdhctx
->kdf_md
= NULL
;
361 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_OUTLEN
);
365 if (!OSSL_PARAM_get_size_t(p
, &outlen
))
367 pdhctx
->kdf_outlen
= outlen
;
370 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_KDF_UKM
);
372 void *tmp_ukm
= NULL
;
375 OPENSSL_free(pdhctx
->kdf_ukm
);
376 pdhctx
->kdf_ukm
= NULL
;
377 pdhctx
->kdf_ukmlen
= 0;
378 /* ukm is an optional field so it can be NULL */
379 if (p
->data
!= NULL
&& p
->data_size
!= 0) {
380 if (!OSSL_PARAM_get_octet_string(p
, &tmp_ukm
, 0, &tmp_ukmlen
))
382 pdhctx
->kdf_ukm
= tmp_ukm
;
383 pdhctx
->kdf_ukmlen
= tmp_ukmlen
;
387 p
= OSSL_PARAM_locate_const(params
, OSSL_EXCHANGE_PARAM_PAD
);
389 if (!OSSL_PARAM_get_uint(p
, &pad
))
391 pdhctx
->pad
= pad
? 1 : 0;
394 p
= OSSL_PARAM_locate_const(params
, OSSL_KDF_PARAM_CEK_ALG
);
398 OPENSSL_free(pdhctx
->kdf_cekalg
);
399 pdhctx
->kdf_cekalg
= NULL
;
400 if (p
->data
!= NULL
&& p
->data_size
!= 0) {
401 if (!OSSL_PARAM_get_utf8_string(p
, &str
, sizeof(name
)))
403 pdhctx
->kdf_cekalg
= OPENSSL_strdup(name
);
404 if (pdhctx
->kdf_cekalg
== NULL
)
411 static const OSSL_PARAM known_settable_ctx_params
[] = {
412 OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_PAD
, NULL
),
413 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE
, NULL
, 0),
414 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST
, NULL
, 0),
415 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS
, NULL
, 0),
416 OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN
, NULL
),
417 OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM
, NULL
, 0),
418 OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG
, NULL
, 0),
422 static const OSSL_PARAM
*dh_settable_ctx_params(ossl_unused
void *vpdhctx
,
423 ossl_unused
void *provctx
)
425 return known_settable_ctx_params
;
428 static const OSSL_PARAM known_gettable_ctx_params
[] = {
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
,
434 OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG
, NULL
, 0),
438 static const OSSL_PARAM
*dh_gettable_ctx_params(ossl_unused
void *vpdhctx
,
439 ossl_unused
void *provctx
)
441 return known_gettable_ctx_params
;
444 static int dh_get_ctx_params(void *vpdhctx
, OSSL_PARAM params
[])
446 PROV_DH_CTX
*pdhctx
= (PROV_DH_CTX
*)vpdhctx
;
452 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_TYPE
);
454 const char *kdf_type
= NULL
;
456 switch (pdhctx
->kdf_type
) {
457 case PROV_DH_KDF_NONE
:
460 case PROV_DH_KDF_X9_42_ASN1
:
461 kdf_type
= OSSL_KDF_NAME_X942KDF_ASN1
;
467 if (!OSSL_PARAM_set_utf8_string(p
, kdf_type
))
471 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_DIGEST
);
473 && !OSSL_PARAM_set_utf8_string(p
, pdhctx
->kdf_md
== NULL
475 : EVP_MD_get0_name(pdhctx
->kdf_md
))) {
479 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_OUTLEN
);
480 if (p
!= NULL
&& !OSSL_PARAM_set_size_t(p
, pdhctx
->kdf_outlen
))
483 p
= OSSL_PARAM_locate(params
, OSSL_EXCHANGE_PARAM_KDF_UKM
);
485 && !OSSL_PARAM_set_octet_ptr(p
, pdhctx
->kdf_ukm
, pdhctx
->kdf_ukmlen
))
488 p
= OSSL_PARAM_locate(params
, OSSL_KDF_PARAM_CEK_ALG
);
490 && !OSSL_PARAM_set_utf8_string(p
, pdhctx
->kdf_cekalg
== NULL
491 ? "" : pdhctx
->kdf_cekalg
))
497 const OSSL_DISPATCH ossl_dh_keyexch_functions
[] = {
498 { OSSL_FUNC_KEYEXCH_NEWCTX
, (void (*)(void))dh_newctx
},
499 { OSSL_FUNC_KEYEXCH_INIT
, (void (*)(void))dh_init
},
500 { OSSL_FUNC_KEYEXCH_DERIVE
, (void (*)(void))dh_derive
},
501 { OSSL_FUNC_KEYEXCH_SET_PEER
, (void (*)(void))dh_set_peer
},
502 { OSSL_FUNC_KEYEXCH_FREECTX
, (void (*)(void))dh_freectx
},
503 { OSSL_FUNC_KEYEXCH_DUPCTX
, (void (*)(void))dh_dupctx
},
504 { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS
, (void (*)(void))dh_set_ctx_params
},
505 { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS
,
506 (void (*)(void))dh_settable_ctx_params
},
507 { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS
, (void (*)(void))dh_get_ctx_params
},
508 { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS
,
509 (void (*)(void))dh_gettable_ctx_params
},