]> git.ipfire.org Git - thirdparty/openssl.git/blob - 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
1 /*
2 * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
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
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
16 #include <string.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"
29
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;
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 */
51 enum kdf_type {
52 PROV_DH_KDF_NONE = 0,
53 PROV_DH_KDF_X9_42_ASN1
54 };
55
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 */
61
62 typedef struct {
63 OSSL_LIB_CTX *libctx;
64 DH *dh;
65 DH *dhpeer;
66 unsigned int pad : 1;
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;
79 } PROV_DH_CTX;
80
81 static void *dh_newctx(void *provctx)
82 {
83 PROV_DH_CTX *pdhctx;
84
85 if (!ossl_prov_is_running())
86 return NULL;
87
88 pdhctx = OPENSSL_zalloc(sizeof(PROV_DH_CTX));
89 if (pdhctx == NULL)
90 return NULL;
91 pdhctx->libctx = PROV_LIBCTX_OF(provctx);
92 pdhctx->kdf_type = PROV_DH_KDF_NONE;
93 return pdhctx;
94 }
95
96 static int dh_init(void *vpdhctx, void *vdh, const OSSL_PARAM params[])
97 {
98 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
99
100 if (!ossl_prov_is_running()
101 || pdhctx == NULL
102 || vdh == NULL
103 || !DH_up_ref(vdh))
104 return 0;
105 DH_free(pdhctx->dh);
106 pdhctx->dh = vdh;
107 pdhctx->kdf_type = PROV_DH_KDF_NONE;
108 return dh_set_ctx_params(pdhctx, params) && ossl_dh_check_key(vdh);
109 }
110
111 /* The 2 parties must share the same domain parameters */
112 static 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
126 static int dh_set_peer(void *vpdhctx, void *vdh)
127 {
128 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
129
130 if (!ossl_prov_is_running()
131 || pdhctx == NULL
132 || vdh == NULL
133 || !dh_match_params(vdh, pdhctx->dh)
134 || !DH_up_ref(vdh))
135 return 0;
136 DH_free(pdhctx->dhpeer);
137 pdhctx->dhpeer = vdh;
138 return 1;
139 }
140
141 static int dh_plain_derive(void *vpdhctx,
142 unsigned char *secret, size_t *secretlen,
143 size_t outlen)
144 {
145 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
146 int ret;
147 size_t dhsize;
148 const BIGNUM *pub_key = NULL;
149
150 if (pdhctx->dh == NULL || pdhctx->dhpeer == NULL) {
151 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
152 return 0;
153 }
154
155 dhsize = (size_t)DH_size(pdhctx->dh);
156 if (secret == NULL) {
157 *secretlen = dhsize;
158 return 1;
159 }
160 if (outlen < dhsize) {
161 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
162 return 0;
163 }
164
165 DH_get0_key(pdhctx->dhpeer, &pub_key, NULL);
166 if (pdhctx->pad)
167 ret = DH_compute_key_padded(secret, pub_key, pdhctx->dh);
168 else
169 ret = DH_compute_key(secret, pub_key, pdhctx->dh);
170 if (ret <= 0)
171 return 0;
172
173 *secretlen = ret;
174 return 1;
175 }
176
177 static 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
190 if (pdhctx->kdf_outlen > outlen) {
191 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
192 return 0;
193 }
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) {
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))
212 goto err;
213 }
214 *secretlen = pdhctx->kdf_outlen;
215 ret = 1;
216 err:
217 OPENSSL_secure_clear_free(stmp, stmplen);
218 return ret;
219 }
220
221 static 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
226 if (!ossl_prov_is_running())
227 return 0;
228
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
241 static void dh_freectx(void *vpdhctx)
242 {
243 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
244
245 OPENSSL_free(pdhctx->kdf_cekalg);
246 DH_free(pdhctx->dh);
247 DH_free(pdhctx->dhpeer);
248 EVP_MD_free(pdhctx->kdf_md);
249 OPENSSL_clear_free(pdhctx->kdf_ukm, pdhctx->kdf_ukmlen);
250
251 OPENSSL_free(pdhctx);
252 }
253
254 static void *dh_dupctx(void *vpdhctx)
255 {
256 PROV_DH_CTX *srcctx = (PROV_DH_CTX *)vpdhctx;
257 PROV_DH_CTX *dstctx;
258
259 if (!ossl_prov_is_running())
260 return NULL;
261
262 dstctx = OPENSSL_zalloc(sizeof(*srcctx));
263 if (dstctx == NULL)
264 return NULL;
265
266 *dstctx = *srcctx;
267 dstctx->dh = NULL;
268 dstctx->dhpeer = NULL;
269 dstctx->kdf_md = NULL;
270 dstctx->kdf_ukm = NULL;
271 dstctx->kdf_cekalg = NULL;
272
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;
294 }
295 dstctx->kdf_cekalg = OPENSSL_strdup(srcctx->kdf_cekalg);
296
297 return dstctx;
298 err:
299 dh_freectx(dstctx);
300 return NULL;
301 }
302
303 static int dh_set_ctx_params(void *vpdhctx, const OSSL_PARAM params[])
304 {
305 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
306 const OSSL_PARAM *p;
307 unsigned int pad;
308 char name[80] = { '\0' }; /* should be big enough */
309 char *str = NULL;
310
311 if (pdhctx == NULL)
312 return 0;
313 if (params == NULL)
314 return 1;
315
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;
324 else if (strcmp(name, OSSL_KDF_NAME_X942KDF_ASN1) == 0)
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);
348 if (!ossl_digest_is_allowed(pdhctx->kdf_md)) {
349 EVP_MD_free(pdhctx->kdf_md);
350 pdhctx->kdf_md = NULL;
351 }
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
382 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_PAD);
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 }
396 return 1;
397 }
398
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),
407 OSSL_PARAM_END
408 };
409
410 static const OSSL_PARAM *dh_settable_ctx_params(ossl_unused void *vpdhctx,
411 ossl_unused void *provctx)
412 {
413 return known_settable_ctx_params;
414 }
415
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,
422 NULL, 0),
423 OSSL_PARAM_END
424 };
425
426 static const OSSL_PARAM *dh_gettable_ctx_params(ossl_unused void *vpdhctx,
427 ossl_unused void *provctx)
428 {
429 return known_gettable_ctx_params;
430 }
431
432 static 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
437 if (pdhctx == NULL)
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:
449 kdf_type = OSSL_KDF_NAME_X942KDF_ASN1;
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);
472 if (p != NULL
473 && !OSSL_PARAM_set_octet_ptr(p, pdhctx->kdf_ukm, pdhctx->kdf_ukmlen))
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
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 },
498 { 0, NULL }
499 };