]> git.ipfire.org Git - thirdparty/openssl.git/blame - providers/implementations/exchange/dh_exch.c
Add domain parameter match check for DH and ECDH key exchange.
[thirdparty/openssl.git] / providers / implementations / exchange / dh_exch.c
CommitLineData
89e29174 1/*
4333b89f 2 * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
89e29174
MC
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
ada66e78
P
10/*
11 * DH low level APIs are deprecated for public use, but still ok for
12 * internal use.
13 */
14#include "internal/deprecated.h"
15
116d2510 16#include <string.h>
89e29174 17#include <openssl/crypto.h>
23c48d94 18#include <openssl/core_dispatch.h>
89e29174
MC
19#include <openssl/core_names.h>
20#include <openssl/dh.h>
116d2510 21#include <openssl/err.h>
77b03f0e 22#include <openssl/proverr.h>
89e29174 23#include <openssl/params.h>
ca94057f 24#include "prov/providercommon.h"
af3e7e1b 25#include "prov/implementations.h"
62f49b90 26#include "prov/provider_ctx.h"
7a810fac 27#include "prov/securitycheck.h"
62f49b90 28#include "crypto/dh.h"
89e29174 29
363b1e5d
DMSP
30static OSSL_FUNC_keyexch_newctx_fn dh_newctx;
31static OSSL_FUNC_keyexch_init_fn dh_init;
32static OSSL_FUNC_keyexch_set_peer_fn dh_set_peer;
33static OSSL_FUNC_keyexch_derive_fn dh_derive;
34static OSSL_FUNC_keyexch_freectx_fn dh_freectx;
35static OSSL_FUNC_keyexch_dupctx_fn dh_dupctx;
36static OSSL_FUNC_keyexch_set_ctx_params_fn dh_set_ctx_params;
37static OSSL_FUNC_keyexch_settable_ctx_params_fn dh_settable_ctx_params;
116d2510
SL
38static OSSL_FUNC_keyexch_get_ctx_params_fn dh_get_ctx_params;
39static OSSL_FUNC_keyexch_gettable_ctx_params_fn dh_gettable_ctx_params;
40
41/*
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".
50 */
51enum kdf_type {
52 PROV_DH_KDF_NONE = 0,
53 PROV_DH_KDF_X9_42_ASN1
54};
89e29174 55
8b84b075
RL
56/*
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.
60 */
89e29174
MC
61
62typedef struct {
b4250010 63 OSSL_LIB_CTX *libctx;
89e29174
MC
64 DH *dh;
65 DH *dhpeer;
1c3ace68 66 unsigned int pad : 1;
116d2510
SL
67
68 /* DH KDF */
69 /* KDF (if any) to use for DH */
70 enum kdf_type kdf_type;
71 /* Message digest to use for key derivation */
72 EVP_MD *kdf_md;
73 /* User key material */
74 unsigned char *kdf_ukm;
75 size_t kdf_ukmlen;
76 /* KDF output length */
77 size_t kdf_outlen;
78 char *kdf_cekalg;
89e29174
MC
79} PROV_DH_CTX;
80
81static void *dh_newctx(void *provctx)
82{
ca94057f 83 PROV_DH_CTX *pdhctx;
62f49b90 84
ca94057f
P
85 if (!ossl_prov_is_running())
86 return NULL;
87
88 pdhctx = OPENSSL_zalloc(sizeof(PROV_DH_CTX));
62f49b90
SL
89 if (pdhctx == NULL)
90 return NULL;
a829b735 91 pdhctx->libctx = PROV_LIBCTX_OF(provctx);
116d2510 92 pdhctx->kdf_type = PROV_DH_KDF_NONE;
62f49b90 93 return pdhctx;
89e29174
MC
94}
95
2b2f4f9b 96static int dh_init(void *vpdhctx, void *vdh, const OSSL_PARAM params[])
89e29174
MC
97{
98 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
99
ca94057f
P
100 if (!ossl_prov_is_running()
101 || pdhctx == NULL
102 || vdh == NULL
103 || !DH_up_ref(vdh))
d753cc33 104 return 0;
89e29174 105 DH_free(pdhctx->dh);
8b84b075 106 pdhctx->dh = vdh;
116d2510 107 pdhctx->kdf_type = PROV_DH_KDF_NONE;
2b2f4f9b 108 return dh_set_ctx_params(pdhctx, params) && ossl_dh_check_key(vdh);
89e29174
MC
109}
110
46eee710
SL
111/* The 2 parties must share the same domain parameters */
112static int dh_match_params(DH *priv, DH *peer)
113{
114 int ret;
115 FFC_PARAMS *dhparams_priv = ossl_dh_get0_params(priv);
116 FFC_PARAMS *dhparams_peer = ossl_dh_get0_params(peer);
117
118 ret = dhparams_priv != NULL
119 && dhparams_peer != NULL
120 && ossl_ffc_params_cmp(dhparams_priv, dhparams_peer, 1);
121 if (!ret)
122 ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS);
123 return ret;
124}
125
8b84b075 126static int dh_set_peer(void *vpdhctx, void *vdh)
89e29174
MC
127{
128 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
129
ca94057f
P
130 if (!ossl_prov_is_running()
131 || pdhctx == NULL
132 || vdh == NULL
46eee710 133 || !dh_match_params(vdh, pdhctx->dh)
ca94057f 134 || !DH_up_ref(vdh))
d753cc33 135 return 0;
89e29174 136 DH_free(pdhctx->dhpeer);
8b84b075 137 pdhctx->dhpeer = vdh;
d753cc33 138 return 1;
89e29174
MC
139}
140
116d2510
SL
141static int dh_plain_derive(void *vpdhctx,
142 unsigned char *secret, size_t *secretlen,
143 size_t outlen)
89e29174
MC
144{
145 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
146 int ret;
147 size_t dhsize;
148 const BIGNUM *pub_key = NULL;
149
77b03f0e
TM
150 if (pdhctx->dh == NULL || pdhctx->dhpeer == NULL) {
151 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
89e29174 152 return 0;
77b03f0e 153 }
89e29174
MC
154
155 dhsize = (size_t)DH_size(pdhctx->dh);
59972370
MC
156 if (secret == NULL) {
157 *secretlen = dhsize;
89e29174
MC
158 return 1;
159 }
77b03f0e
TM
160 if (outlen < dhsize) {
161 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
89e29174 162 return 0;
77b03f0e 163 }
89e29174
MC
164
165 DH_get0_key(pdhctx->dhpeer, &pub_key, NULL);
62f49b90 166 if (pdhctx->pad)
8083fd3a 167 ret = DH_compute_key_padded(secret, pub_key, pdhctx->dh);
62f49b90 168 else
8083fd3a 169 ret = DH_compute_key(secret, pub_key, pdhctx->dh);
89e29174
MC
170 if (ret <= 0)
171 return 0;
172
59972370 173 *secretlen = ret;
89e29174
MC
174 return 1;
175}
176
116d2510
SL
177static int dh_X9_42_kdf_derive(void *vpdhctx, unsigned char *secret,
178 size_t *secretlen, size_t outlen)
179{
180 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
181 unsigned char *stmp = NULL;
182 size_t stmplen;
183 int ret = 0;
184
185 if (secret == NULL) {
186 *secretlen = pdhctx->kdf_outlen;
187 return 1;
188 }
189
77b03f0e
TM
190 if (pdhctx->kdf_outlen > outlen) {
191 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
116d2510 192 return 0;
77b03f0e 193 }
116d2510
SL
194 if (!dh_plain_derive(pdhctx, NULL, &stmplen, 0))
195 return 0;
196 if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL) {
197 ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
198 return 0;
199 }
200 if (!dh_plain_derive(pdhctx, stmp, &stmplen, stmplen))
201 goto err;
202
203 /* Do KDF stuff */
204 if (pdhctx->kdf_type == PROV_DH_KDF_X9_42_ASN1) {
19dbb742
SL
205 if (!ossl_dh_kdf_X9_42_asn1(secret, pdhctx->kdf_outlen,
206 stmp, stmplen,
207 pdhctx->kdf_cekalg,
208 pdhctx->kdf_ukm,
209 pdhctx->kdf_ukmlen,
210 pdhctx->kdf_md,
211 pdhctx->libctx, NULL))
116d2510
SL
212 goto err;
213 }
214 *secretlen = pdhctx->kdf_outlen;
215 ret = 1;
216err:
217 OPENSSL_secure_clear_free(stmp, stmplen);
218 return ret;
219}
220
221static int dh_derive(void *vpdhctx, unsigned char *secret,
222 size_t *psecretlen, size_t outlen)
223{
224 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
225
ca94057f
P
226 if (!ossl_prov_is_running())
227 return 0;
228
116d2510
SL
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);
234 default:
235 break;
236 }
237 return 0;
238}
239
240
89e29174
MC
241static void dh_freectx(void *vpdhctx)
242{
243 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
244
116d2510 245 OPENSSL_free(pdhctx->kdf_cekalg);
89e29174
MC
246 DH_free(pdhctx->dh);
247 DH_free(pdhctx->dhpeer);
116d2510
SL
248 EVP_MD_free(pdhctx->kdf_md);
249 OPENSSL_clear_free(pdhctx->kdf_ukm, pdhctx->kdf_ukmlen);
89e29174
MC
250
251 OPENSSL_free(pdhctx);
252}
253
254static void *dh_dupctx(void *vpdhctx)
255{
256 PROV_DH_CTX *srcctx = (PROV_DH_CTX *)vpdhctx;
257 PROV_DH_CTX *dstctx;
258
ca94057f
P
259 if (!ossl_prov_is_running())
260 return NULL;
261
89e29174 262 dstctx = OPENSSL_zalloc(sizeof(*srcctx));
02c163ea
P
263 if (dstctx == NULL)
264 return NULL;
89e29174
MC
265
266 *dstctx = *srcctx;
116d2510
SL
267 dstctx->dh = NULL;
268 dstctx->dhpeer = NULL;
269 dstctx->kdf_md = NULL;
270 dstctx->kdf_ukm = NULL;
271 dstctx->kdf_cekalg = NULL;
89e29174 272
116d2510
SL
273 if (dstctx->dh != NULL && !DH_up_ref(srcctx->dh))
274 goto err;
275 else
276 dstctx->dh = srcctx->dh;
277
278 if (dstctx->dhpeer != NULL && !DH_up_ref(srcctx->dhpeer))
279 goto err;
280 else
281 dstctx->dhpeer = srcctx->dhpeer;
282
283 if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md))
284 goto err;
285 else
286 dstctx->kdf_md = srcctx->kdf_md;
287
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,
291 srcctx->kdf_ukmlen);
292 if (dstctx->kdf_ukm == NULL)
293 goto err;
89e29174 294 }
116d2510 295 dstctx->kdf_cekalg = OPENSSL_strdup(srcctx->kdf_cekalg);
89e29174
MC
296
297 return dstctx;
116d2510
SL
298err:
299 dh_freectx(dstctx);
300 return NULL;
89e29174
MC
301}
302
9c45222d 303static int dh_set_ctx_params(void *vpdhctx, const OSSL_PARAM params[])
35aca9ec
MC
304{
305 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
306 const OSSL_PARAM *p;
1c3ace68 307 unsigned int pad;
116d2510
SL
308 char name[80] = { '\0' }; /* should be big enough */
309 char *str = NULL;
35aca9ec 310
2b2f4f9b 311 if (pdhctx == NULL)
35aca9ec 312 return 0;
2b2f4f9b
P
313 if (params == NULL)
314 return 1;
35aca9ec 315
116d2510
SL
316 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);
317 if (p != NULL) {
318 str = name;
319 if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))
320 return 0;
321
322 if (name[0] == '\0')
323 pdhctx->kdf_type = PROV_DH_KDF_NONE;
89cccbea 324 else if (strcmp(name, OSSL_KDF_NAME_X942KDF_ASN1) == 0)
116d2510
SL
325 pdhctx->kdf_type = PROV_DH_KDF_X9_42_ASN1;
326 else
327 return 0;
328 }
329 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);
330 if (p != NULL) {
331 char mdprops[80] = { '\0' }; /* should be big enough */
332
333 str = name;
334 if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))
335 return 0;
336
337 str = mdprops;
338 p = OSSL_PARAM_locate_const(params,
339 OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS);
340
341 if (p != NULL) {
342 if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops)))
343 return 0;
344 }
345
346 EVP_MD_free(pdhctx->kdf_md);
347 pdhctx->kdf_md = EVP_MD_fetch(pdhctx->libctx, name, mdprops);
7b676cc8 348 if (!ossl_digest_is_allowed(pdhctx->kdf_md)) {
b8237707
SL
349 EVP_MD_free(pdhctx->kdf_md);
350 pdhctx->kdf_md = NULL;
351 }
116d2510
SL
352 if (pdhctx->kdf_md == NULL)
353 return 0;
354 }
355
356 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);
357 if (p != NULL) {
358 size_t outlen;
359
360 if (!OSSL_PARAM_get_size_t(p, &outlen))
361 return 0;
362 pdhctx->kdf_outlen = outlen;
363 }
364
365 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM);
366 if (p != NULL) {
367 void *tmp_ukm = NULL;
368 size_t tmp_ukmlen;
369
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))
376 return 0;
377 pdhctx->kdf_ukm = tmp_ukm;
378 pdhctx->kdf_ukmlen = tmp_ukmlen;
379 }
380 }
381
8b84b075 382 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_PAD);
116d2510
SL
383 if (p != NULL) {
384 if (!OSSL_PARAM_get_uint(p, &pad))
385 return 0;
386 pdhctx->pad = pad ? 1 : 0;
387 }
388
389 p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_CEK_ALG);
390 if (p != NULL) {
391 str = name;
392 if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))
393 return 0;
394 pdhctx->kdf_cekalg = OPENSSL_strdup(name);
395 }
35aca9ec
MC
396 return 1;
397}
398
9c45222d
MC
399static const OSSL_PARAM known_settable_ctx_params[] = {
400 OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_PAD, NULL),
116d2510
SL
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),
9c45222d
MC
407 OSSL_PARAM_END
408};
409
fb67126e
TM
410static const OSSL_PARAM *dh_settable_ctx_params(ossl_unused void *vpdhctx,
411 ossl_unused void *provctx)
9c45222d
MC
412{
413 return known_settable_ctx_params;
414}
415
116d2510
SL
416static 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,
422 NULL, 0),
116d2510
SL
423 OSSL_PARAM_END
424};
425
fb67126e
TM
426static const OSSL_PARAM *dh_gettable_ctx_params(ossl_unused void *vpdhctx,
427 ossl_unused void *provctx)
116d2510
SL
428{
429 return known_gettable_ctx_params;
430}
431
432static int dh_get_ctx_params(void *vpdhctx, OSSL_PARAM params[])
433{
434 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
435 OSSL_PARAM *p;
436
2b2f4f9b 437 if (pdhctx == NULL)
116d2510
SL
438 return 0;
439
440 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);
441 if (p != NULL) {
442 const char *kdf_type = NULL;
443
444 switch (pdhctx->kdf_type) {
445 case PROV_DH_KDF_NONE:
446 kdf_type = "";
447 break;
448 case PROV_DH_KDF_X9_42_ASN1:
89cccbea 449 kdf_type = OSSL_KDF_NAME_X942KDF_ASN1;
116d2510
SL
450 break;
451 default:
452 return 0;
453 }
454
455 if (!OSSL_PARAM_set_utf8_string(p, kdf_type))
456 return 0;
457 }
458
459 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);
460 if (p != NULL
461 && !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_md == NULL
462 ? ""
463 : EVP_MD_name(pdhctx->kdf_md))){
464 return 0;
465 }
466
467 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);
468 if (p != NULL && !OSSL_PARAM_set_size_t(p, pdhctx->kdf_outlen))
469 return 0;
470
471 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM);
ba0a6d1d
RL
472 if (p != NULL
473 && !OSSL_PARAM_set_octet_ptr(p, pdhctx->kdf_ukm, pdhctx->kdf_ukmlen))
116d2510
SL
474 return 0;
475
476 p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_CEK_ALG);
477 if (p != NULL
478 && !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_cekalg == NULL
479 ? "" : pdhctx->kdf_cekalg))
480 return 0;
481
482 return 1;
483}
484
1be63951 485const OSSL_DISPATCH ossl_dh_keyexch_functions[] = {
89e29174
MC
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 },
9c45222d
MC
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 },
116d2510
SL
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 },
89e29174
MC
498 { 0, NULL }
499};