]>
Commit | Line | Data |
---|---|---|
ff64702b | 1 | /* |
fecb3aae | 2 | * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. |
ff64702b 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 | ||
10 | #include <openssl/crypto.h> | |
11 | #include <openssl/evp.h> | |
12 | #include <openssl/err.h> | |
5246183e | 13 | #include "internal/cryptlib.h" |
ff64702b | 14 | #include "internal/refcount.h" |
ff64702b | 15 | #include "internal/provider.h" |
6c9bc258 | 16 | #include "internal/core.h" |
ac5a61ca | 17 | #include "internal/numbers.h" /* includes SIZE_MAX */ |
6c9bc258 | 18 | #include "crypto/evp.h" |
706457b7 | 19 | #include "evp_local.h" |
ff64702b MC |
20 | |
21 | static EVP_KEYEXCH *evp_keyexch_new(OSSL_PROVIDER *prov) | |
22 | { | |
23 | EVP_KEYEXCH *exchange = OPENSSL_zalloc(sizeof(EVP_KEYEXCH)); | |
24 | ||
e077455e | 25 | if (exchange == NULL) |
c1ff5994 | 26 | return NULL; |
c1ff5994 | 27 | |
ff64702b MC |
28 | exchange->lock = CRYPTO_THREAD_lock_new(); |
29 | if (exchange->lock == NULL) { | |
e077455e | 30 | ERR_raise(ERR_LIB_EVP, ERR_R_CRYPTO_LIB); |
ff64702b MC |
31 | OPENSSL_free(exchange); |
32 | return NULL; | |
33 | } | |
34 | exchange->prov = prov; | |
35 | ossl_provider_up_ref(prov); | |
36 | exchange->refcnt = 1; | |
37 | ||
38 | return exchange; | |
39 | } | |
40 | ||
309a78aa RL |
41 | static void *evp_keyexch_from_algorithm(int name_id, |
42 | const OSSL_ALGORITHM *algodef, | |
43 | OSSL_PROVIDER *prov) | |
ff64702b | 44 | { |
309a78aa | 45 | const OSSL_DISPATCH *fns = algodef->implementation; |
ff64702b | 46 | EVP_KEYEXCH *exchange = NULL; |
4fe54d67 | 47 | int fncnt = 0, sparamfncnt = 0, gparamfncnt = 0; |
ff64702b | 48 | |
f7c16d48 | 49 | if ((exchange = evp_keyexch_new(prov)) == NULL) { |
e077455e | 50 | ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB); |
3ca9d210 | 51 | goto err; |
6b9e3724 | 52 | } |
ff64702b | 53 | |
f7c16d48 | 54 | exchange->name_id = name_id; |
6c9bc258 TM |
55 | if ((exchange->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL) |
56 | goto err; | |
309a78aa | 57 | exchange->description = algodef->algorithm_description; |
3ca9d210 | 58 | |
ff64702b MC |
59 | for (; fns->function_id != 0; fns++) { |
60 | switch (fns->function_id) { | |
61 | case OSSL_FUNC_KEYEXCH_NEWCTX: | |
62 | if (exchange->newctx != NULL) | |
63 | break; | |
363b1e5d | 64 | exchange->newctx = OSSL_FUNC_keyexch_newctx(fns); |
ff64702b MC |
65 | fncnt++; |
66 | break; | |
67 | case OSSL_FUNC_KEYEXCH_INIT: | |
68 | if (exchange->init != NULL) | |
69 | break; | |
363b1e5d | 70 | exchange->init = OSSL_FUNC_keyexch_init(fns); |
ff64702b MC |
71 | fncnt++; |
72 | break; | |
73 | case OSSL_FUNC_KEYEXCH_SET_PEER: | |
74 | if (exchange->set_peer != NULL) | |
75 | break; | |
363b1e5d | 76 | exchange->set_peer = OSSL_FUNC_keyexch_set_peer(fns); |
ff64702b MC |
77 | break; |
78 | case OSSL_FUNC_KEYEXCH_DERIVE: | |
79 | if (exchange->derive != NULL) | |
80 | break; | |
363b1e5d | 81 | exchange->derive = OSSL_FUNC_keyexch_derive(fns); |
ff64702b MC |
82 | fncnt++; |
83 | break; | |
84 | case OSSL_FUNC_KEYEXCH_FREECTX: | |
85 | if (exchange->freectx != NULL) | |
86 | break; | |
363b1e5d | 87 | exchange->freectx = OSSL_FUNC_keyexch_freectx(fns); |
ff64702b MC |
88 | fncnt++; |
89 | break; | |
90 | case OSSL_FUNC_KEYEXCH_DUPCTX: | |
91 | if (exchange->dupctx != NULL) | |
92 | break; | |
363b1e5d | 93 | exchange->dupctx = OSSL_FUNC_keyexch_dupctx(fns); |
ff64702b | 94 | break; |
4fe54d67 NT |
95 | case OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS: |
96 | if (exchange->get_ctx_params != NULL) | |
97 | break; | |
363b1e5d | 98 | exchange->get_ctx_params = OSSL_FUNC_keyexch_get_ctx_params(fns); |
4fe54d67 NT |
99 | gparamfncnt++; |
100 | break; | |
101 | case OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS: | |
102 | if (exchange->gettable_ctx_params != NULL) | |
103 | break; | |
104 | exchange->gettable_ctx_params | |
363b1e5d | 105 | = OSSL_FUNC_keyexch_gettable_ctx_params(fns); |
4fe54d67 NT |
106 | gparamfncnt++; |
107 | break; | |
9c45222d MC |
108 | case OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS: |
109 | if (exchange->set_ctx_params != NULL) | |
35aca9ec | 110 | break; |
363b1e5d | 111 | exchange->set_ctx_params = OSSL_FUNC_keyexch_set_ctx_params(fns); |
4fe54d67 | 112 | sparamfncnt++; |
9c45222d MC |
113 | break; |
114 | case OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS: | |
115 | if (exchange->settable_ctx_params != NULL) | |
116 | break; | |
117 | exchange->settable_ctx_params | |
363b1e5d | 118 | = OSSL_FUNC_keyexch_settable_ctx_params(fns); |
4fe54d67 | 119 | sparamfncnt++; |
35aca9ec | 120 | break; |
ff64702b MC |
121 | } |
122 | } | |
4fe54d67 NT |
123 | if (fncnt != 4 |
124 | || (gparamfncnt != 0 && gparamfncnt != 2) | |
125 | || (sparamfncnt != 0 && sparamfncnt != 2)) { | |
ff64702b MC |
126 | /* |
127 | * In order to be a consistent set of functions we must have at least | |
128 | * a complete set of "exchange" functions: init, derive, newctx, | |
9c45222d MC |
129 | * and freectx. The set_ctx_params and settable_ctx_params functions are |
130 | * optional, but if one of them is present then the other one must also | |
4fe54d67 NT |
131 | * be present. Same goes for get_ctx_params and gettable_ctx_params. |
132 | * The dupctx and set_peer functions are optional. | |
ff64702b | 133 | */ |
9311d0c4 | 134 | ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS); |
3ca9d210 | 135 | goto err; |
ff64702b MC |
136 | } |
137 | ||
138 | return exchange; | |
3ca9d210 RL |
139 | |
140 | err: | |
141 | EVP_KEYEXCH_free(exchange); | |
3ca9d210 | 142 | return NULL; |
ff64702b MC |
143 | } |
144 | ||
145 | void EVP_KEYEXCH_free(EVP_KEYEXCH *exchange) | |
146 | { | |
543e740b RS |
147 | int i; |
148 | ||
149 | if (exchange == NULL) | |
150 | return; | |
151 | CRYPTO_DOWN_REF(&exchange->refcnt, &i, exchange->lock); | |
152 | if (i > 0) | |
153 | return; | |
6c9bc258 | 154 | OPENSSL_free(exchange->type_name); |
543e740b RS |
155 | ossl_provider_free(exchange->prov); |
156 | CRYPTO_THREAD_lock_free(exchange->lock); | |
157 | OPENSSL_free(exchange); | |
ff64702b MC |
158 | } |
159 | ||
160 | int EVP_KEYEXCH_up_ref(EVP_KEYEXCH *exchange) | |
161 | { | |
162 | int ref = 0; | |
163 | ||
164 | CRYPTO_UP_REF(&exchange->refcnt, &ref, exchange->lock); | |
165 | return 1; | |
166 | } | |
167 | ||
ed576acd | 168 | OSSL_PROVIDER *EVP_KEYEXCH_get0_provider(const EVP_KEYEXCH *exchange) |
8b84b075 RL |
169 | { |
170 | return exchange->prov; | |
171 | } | |
172 | ||
b4250010 | 173 | EVP_KEYEXCH *EVP_KEYEXCH_fetch(OSSL_LIB_CTX *ctx, const char *algorithm, |
ff64702b MC |
174 | const char *properties) |
175 | { | |
0ddf74bf | 176 | return evp_generic_fetch(ctx, OSSL_OP_KEYEXCH, algorithm, properties, |
309a78aa | 177 | evp_keyexch_from_algorithm, |
0ddf74bf RL |
178 | (int (*)(void *))EVP_KEYEXCH_up_ref, |
179 | (void (*)(void *))EVP_KEYEXCH_free); | |
ff64702b MC |
180 | } |
181 | ||
ff778146 RL |
182 | EVP_KEYEXCH *evp_keyexch_fetch_from_prov(OSSL_PROVIDER *prov, |
183 | const char *algorithm, | |
184 | const char *properties) | |
185 | { | |
186 | return evp_generic_fetch_from_prov(prov, OSSL_OP_KEYEXCH, | |
187 | algorithm, properties, | |
188 | evp_keyexch_from_algorithm, | |
189 | (int (*)(void *))EVP_KEYEXCH_up_ref, | |
190 | (void (*)(void *))EVP_KEYEXCH_free); | |
191 | } | |
192 | ||
c0e0984f | 193 | int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) |
4b58d9b4 P |
194 | { |
195 | return EVP_PKEY_derive_init_ex(ctx, NULL); | |
196 | } | |
197 | ||
198 | int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[]) | |
ff64702b MC |
199 | { |
200 | int ret; | |
8b84b075 | 201 | void *provkey = NULL; |
c0e0984f | 202 | EVP_KEYEXCH *exchange = NULL; |
f6aa5774 | 203 | EVP_KEYMGMT *tmp_keymgmt = NULL; |
839ffdd1 | 204 | const OSSL_PROVIDER *tmp_prov = NULL; |
f6aa5774 | 205 | const char *supported_exch = NULL; |
839ffdd1 | 206 | int iter; |
c0e0984f RL |
207 | |
208 | if (ctx == NULL) { | |
6d9a54c6 | 209 | ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER); |
c0e0984f RL |
210 | return -2; |
211 | } | |
ff64702b | 212 | |
864b89ce | 213 | evp_pkey_ctx_free_old_ops(ctx); |
ff64702b MC |
214 | ctx->operation = EVP_PKEY_OP_DERIVE; |
215 | ||
0b9dd384 RL |
216 | ERR_set_mark(); |
217 | ||
f21c9c64 | 218 | if (evp_pkey_ctx_is_legacy(ctx)) |
ff64702b MC |
219 | goto legacy; |
220 | ||
3c6ed955 | 221 | /* |
5246183e RL |
222 | * Some algorithms (e.g. legacy KDFs) don't have a pkey - so we create |
223 | * a blank one. | |
3c6ed955 | 224 | */ |
ac2d58c7 | 225 | if (ctx->pkey == NULL) { |
ac2d58c7 MC |
226 | EVP_PKEY *pkey = EVP_PKEY_new(); |
227 | ||
5246183e RL |
228 | if (pkey == NULL |
229 | || !EVP_PKEY_set_type_by_keymgmt(pkey, ctx->keymgmt) | |
230 | || (pkey->keydata = evp_keymgmt_newdata(ctx->keymgmt)) == NULL) { | |
ac2d58c7 MC |
231 | ERR_clear_last_mark(); |
232 | EVP_PKEY_free(pkey); | |
233 | ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); | |
234 | goto err; | |
235 | } | |
5246183e | 236 | ctx->pkey = pkey; |
ac2d58c7 | 237 | } |
5246183e RL |
238 | |
239 | /* | |
240 | * Try to derive the supported exch from |ctx->keymgmt|. | |
241 | */ | |
242 | if (!ossl_assert(ctx->pkey->keymgmt == NULL | |
243 | || ctx->pkey->keymgmt == ctx->keymgmt)) { | |
244 | ERR_clear_last_mark(); | |
245 | ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); | |
246 | goto err; | |
247 | } | |
248 | supported_exch = evp_keymgmt_util_query_operation_name(ctx->keymgmt, | |
249 | OSSL_OP_KEYEXCH); | |
250 | if (supported_exch == NULL) { | |
0b9dd384 | 251 | ERR_clear_last_mark(); |
f6aa5774 RL |
252 | ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); |
253 | goto err; | |
c0e0984f | 254 | } |
f6aa5774 | 255 | |
f6aa5774 RL |
256 | |
257 | /* | |
839ffdd1 RL |
258 | * We perform two iterations: |
259 | * | |
260 | * 1. Do the normal exchange fetch, using the fetching data given by | |
261 | * the EVP_PKEY_CTX. | |
262 | * 2. Do the provider specific exchange fetch, from the same provider | |
263 | * as |ctx->keymgmt| | |
264 | * | |
265 | * We then try to fetch the keymgmt from the same provider as the | |
266 | * exchange, and try to export |ctx->pkey| to that keymgmt (when | |
267 | * this keymgmt happens to be the same as |ctx->keymgmt|, the export | |
268 | * is a no-op, but we call it anyway to not complicate the code even | |
269 | * more). | |
270 | * If the export call succeeds (returns a non-NULL provider key pointer), | |
271 | * we're done and can perform the operation itself. If not, we perform | |
272 | * the second iteration, or jump to legacy. | |
f6aa5774 | 273 | */ |
839ffdd1 | 274 | for (iter = 1, provkey = NULL; iter < 3 && provkey == NULL; iter++) { |
dc010ca6 | 275 | EVP_KEYMGMT *tmp_keymgmt_tofree = NULL; |
ff64702b | 276 | |
839ffdd1 RL |
277 | /* |
278 | * If we're on the second iteration, free the results from the first. | |
279 | * They are NULL on the first iteration, so no need to check what | |
280 | * iteration we're on. | |
281 | */ | |
282 | EVP_KEYEXCH_free(exchange); | |
283 | EVP_KEYMGMT_free(tmp_keymgmt); | |
284 | ||
285 | switch (iter) { | |
286 | case 1: | |
287 | exchange = | |
288 | EVP_KEYEXCH_fetch(ctx->libctx, supported_exch, ctx->propquery); | |
289 | if (exchange != NULL) | |
290 | tmp_prov = EVP_KEYEXCH_get0_provider(exchange); | |
291 | break; | |
292 | case 2: | |
293 | tmp_prov = EVP_KEYMGMT_get0_provider(ctx->keymgmt); | |
294 | exchange = | |
295 | evp_keyexch_fetch_from_prov((OSSL_PROVIDER *)tmp_prov, | |
296 | supported_exch, ctx->propquery); | |
297 | if (exchange == NULL) | |
298 | goto legacy; | |
299 | break; | |
300 | } | |
301 | if (exchange == NULL) | |
302 | continue; | |
303 | ||
304 | /* | |
305 | * Ensure that the key is provided, either natively, or as a cached | |
306 | * export. We start by fetching the keymgmt with the same name as | |
64a8f600 | 307 | * |ctx->keymgmt|, but from the provider of the exchange method, using |
839ffdd1 RL |
308 | * the same property query as when fetching the exchange method. |
309 | * With the keymgmt we found (if we did), we try to export |ctx->pkey| | |
310 | * to it (evp_pkey_export_to_provider() is smart enough to only actually | |
311 | * export it if |tmp_keymgmt| is different from |ctx->pkey|'s keymgmt) | |
312 | */ | |
313 | tmp_keymgmt_tofree = tmp_keymgmt = | |
314 | evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *)tmp_prov, | |
315 | EVP_KEYMGMT_get0_name(ctx->keymgmt), | |
316 | ctx->propquery); | |
317 | if (tmp_keymgmt != NULL) | |
318 | provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx, | |
319 | &tmp_keymgmt, ctx->propquery); | |
320 | if (tmp_keymgmt == NULL) | |
321 | EVP_KEYMGMT_free(tmp_keymgmt_tofree); | |
322 | } | |
323 | ||
324 | if (provkey == NULL) { | |
325 | EVP_KEYEXCH_free(exchange); | |
5246183e | 326 | goto legacy; |
839ffdd1 | 327 | } |
5246183e | 328 | |
0b9dd384 RL |
329 | ERR_pop_to_mark(); |
330 | ||
331 | /* No more legacy from here down to legacy: */ | |
c0e0984f | 332 | |
a3818974 P |
333 | /* A Coverity false positive with up_ref/down_ref and free */ |
334 | /* coverity[use_after_free] */ | |
864b89ce | 335 | ctx->op.kex.exchange = exchange; |
a3818974 P |
336 | /* A Coverity false positive with up_ref/down_ref and free */ |
337 | /* coverity[deref_arg] */ | |
7c14d0c1 SL |
338 | ctx->op.kex.algctx = exchange->newctx(ossl_provider_ctx(exchange->prov)); |
339 | if (ctx->op.kex.algctx == NULL) { | |
8b84b075 | 340 | /* The provider key can stay in the cache */ |
9311d0c4 | 341 | ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); |
ff64702b MC |
342 | goto err; |
343 | } | |
7c14d0c1 | 344 | ret = exchange->init(ctx->op.kex.algctx, provkey, params); |
ff64702b | 345 | |
5246183e | 346 | EVP_KEYMGMT_free(tmp_keymgmt); |
ff64702b MC |
347 | return ret ? 1 : 0; |
348 | err: | |
c7fa9297 | 349 | evp_pkey_ctx_free_old_ops(ctx); |
ff64702b | 350 | ctx->operation = EVP_PKEY_OP_UNDEFINED; |
5246183e | 351 | EVP_KEYMGMT_free(tmp_keymgmt); |
ff64702b MC |
352 | return 0; |
353 | ||
354 | legacy: | |
0b9dd384 | 355 | /* |
0b9dd384 RL |
356 | * If we don't have the full support we need with provided methods, |
357 | * let's go see if legacy does. | |
358 | */ | |
359 | ERR_pop_to_mark(); | |
360 | ||
f844f9eb | 361 | #ifdef FIPS_MODULE |
62f49b90 SL |
362 | return 0; |
363 | #else | |
e0d8523e | 364 | if (ctx->pmeth == NULL || ctx->pmeth->derive == NULL) { |
9311d0c4 | 365 | ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
ff64702b MC |
366 | return -2; |
367 | } | |
368 | ||
369 | if (ctx->pmeth->derive_init == NULL) | |
370 | return 1; | |
371 | ret = ctx->pmeth->derive_init(ctx); | |
372 | if (ret <= 0) | |
373 | ctx->operation = EVP_PKEY_OP_UNDEFINED; | |
5246183e | 374 | EVP_KEYMGMT_free(tmp_keymgmt); |
ff64702b | 375 | return ret; |
62f49b90 | 376 | #endif |
ff64702b MC |
377 | } |
378 | ||
e454a393 SL |
379 | int EVP_PKEY_derive_set_peer_ex(EVP_PKEY_CTX *ctx, EVP_PKEY *peer, |
380 | int validate_peer) | |
ff64702b | 381 | { |
e454a393 | 382 | int ret = 0, check; |
8b84b075 | 383 | void *provkey = NULL; |
e454a393 | 384 | EVP_PKEY_CTX *check_ctx = NULL; |
64a8f600 | 385 | EVP_KEYMGMT *tmp_keymgmt = NULL, *tmp_keymgmt_tofree = NULL; |
ff64702b MC |
386 | |
387 | if (ctx == NULL) { | |
6d9a54c6 TM |
388 | ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER); |
389 | return -1; | |
ff64702b MC |
390 | } |
391 | ||
7c14d0c1 | 392 | if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx) || ctx->op.kex.algctx == NULL) |
ff64702b MC |
393 | goto legacy; |
394 | ||
864b89ce | 395 | if (ctx->op.kex.exchange->set_peer == NULL) { |
9311d0c4 | 396 | ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
ff64702b MC |
397 | return -2; |
398 | } | |
399 | ||
e454a393 SL |
400 | if (validate_peer) { |
401 | check_ctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, peer, ctx->propquery); | |
402 | if (check_ctx == NULL) | |
403 | return -1; | |
404 | check = EVP_PKEY_public_check(check_ctx); | |
405 | EVP_PKEY_CTX_free(check_ctx); | |
406 | if (check <= 0) | |
407 | return -1; | |
408 | } | |
409 | ||
64a8f600 TM |
410 | /* |
411 | * Ensure that the |peer| is provided, either natively, or as a cached | |
412 | * export. We start by fetching the keymgmt with the same name as | |
413 | * |ctx->keymgmt|, but from the provider of the exchange method, using | |
414 | * the same property query as when fetching the exchange method. | |
415 | * With the keymgmt we found (if we did), we try to export |peer| | |
416 | * to it (evp_pkey_export_to_provider() is smart enough to only actually | |
417 | * export it if |tmp_keymgmt| is different from |peer|'s keymgmt) | |
418 | */ | |
419 | tmp_keymgmt_tofree = tmp_keymgmt = | |
420 | evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *) | |
421 | EVP_KEYEXCH_get0_provider(ctx->op.kex.exchange), | |
422 | EVP_KEYMGMT_get0_name(ctx->keymgmt), | |
423 | ctx->propquery); | |
424 | if (tmp_keymgmt != NULL) | |
a3818974 P |
425 | /* A Coverity issue with up_ref/down_ref and free */ |
426 | /* coverity[pass_freed_arg] */ | |
64a8f600 TM |
427 | provkey = evp_pkey_export_to_provider(peer, ctx->libctx, |
428 | &tmp_keymgmt, ctx->propquery); | |
429 | EVP_KEYMGMT_free(tmp_keymgmt_tofree); | |
430 | ||
3f7ce7f1 RL |
431 | /* |
432 | * If making the key provided wasn't possible, legacy may be able to pick | |
433 | * it up | |
434 | */ | |
e0d8523e RL |
435 | if (provkey == NULL) |
436 | goto legacy; | |
7c14d0c1 | 437 | return ctx->op.kex.exchange->set_peer(ctx->op.kex.algctx, provkey); |
ff64702b MC |
438 | |
439 | legacy: | |
f844f9eb | 440 | #ifdef FIPS_MODULE |
62f49b90 SL |
441 | return ret; |
442 | #else | |
ff64702b MC |
443 | if (ctx->pmeth == NULL |
444 | || !(ctx->pmeth->derive != NULL | |
445 | || ctx->pmeth->encrypt != NULL | |
446 | || ctx->pmeth->decrypt != NULL) | |
447 | || ctx->pmeth->ctrl == NULL) { | |
9311d0c4 | 448 | ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
ff64702b MC |
449 | return -2; |
450 | } | |
451 | if (ctx->operation != EVP_PKEY_OP_DERIVE | |
452 | && ctx->operation != EVP_PKEY_OP_ENCRYPT | |
453 | && ctx->operation != EVP_PKEY_OP_DECRYPT) { | |
bf23b9a1 | 454 | ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED); |
ff64702b MC |
455 | return -1; |
456 | } | |
457 | ||
458 | ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 0, peer); | |
459 | ||
460 | if (ret <= 0) | |
461 | return ret; | |
462 | ||
463 | if (ret == 2) | |
464 | return 1; | |
465 | ||
466 | if (ctx->pkey == NULL) { | |
9311d0c4 | 467 | ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEY_SET); |
ff64702b MC |
468 | return -1; |
469 | } | |
470 | ||
471 | if (ctx->pkey->type != peer->type) { | |
9311d0c4 | 472 | ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES); |
ff64702b MC |
473 | return -1; |
474 | } | |
475 | ||
476 | /* | |
477 | * For clarity. The error is if parameters in peer are | |
c74aaa39 | 478 | * present (!missing) but don't match. EVP_PKEY_parameters_eq may return |
ff64702b MC |
479 | * 1 (match), 0 (don't match) and -2 (comparison is not defined). -1 |
480 | * (different key types) is impossible here because it is checked earlier. | |
481 | * -2 is OK for us here, as well as 1, so we can check for 0 only. | |
482 | */ | |
483 | if (!EVP_PKEY_missing_parameters(peer) && | |
c74aaa39 | 484 | !EVP_PKEY_parameters_eq(ctx->pkey, peer)) { |
9311d0c4 | 485 | ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_PARAMETERS); |
ff64702b MC |
486 | return -1; |
487 | } | |
488 | ||
489 | EVP_PKEY_free(ctx->peerkey); | |
490 | ctx->peerkey = peer; | |
491 | ||
492 | ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer); | |
493 | ||
494 | if (ret <= 0) { | |
495 | ctx->peerkey = NULL; | |
496 | return ret; | |
497 | } | |
498 | ||
499 | EVP_PKEY_up_ref(peer); | |
500 | return 1; | |
62f49b90 | 501 | #endif |
ff64702b MC |
502 | } |
503 | ||
e454a393 SL |
504 | int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer) |
505 | { | |
506 | return EVP_PKEY_derive_set_peer_ex(ctx, peer, 1); | |
507 | } | |
508 | ||
ff64702b MC |
509 | int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *pkeylen) |
510 | { | |
511 | int ret; | |
512 | ||
6d9a54c6 TM |
513 | if (ctx == NULL || pkeylen == NULL) { |
514 | ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER); | |
515 | return -1; | |
ff64702b MC |
516 | } |
517 | ||
864b89ce | 518 | if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) { |
bf23b9a1 | 519 | ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED); |
ff64702b MC |
520 | return -1; |
521 | } | |
522 | ||
7c14d0c1 | 523 | if (ctx->op.kex.algctx == NULL) |
ff64702b MC |
524 | goto legacy; |
525 | ||
7c14d0c1 | 526 | ret = ctx->op.kex.exchange->derive(ctx->op.kex.algctx, key, pkeylen, |
6d9a54c6 | 527 | key != NULL ? *pkeylen : 0); |
ff64702b MC |
528 | |
529 | return ret; | |
530 | legacy: | |
6d9a54c6 | 531 | if (ctx->pmeth == NULL || ctx->pmeth->derive == NULL) { |
9311d0c4 | 532 | ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
ff64702b MC |
533 | return -2; |
534 | } | |
535 | ||
536 | M_check_autoarg(ctx, key, pkeylen, EVP_F_EVP_PKEY_DERIVE) | |
537 | return ctx->pmeth->derive(ctx, key, pkeylen); | |
538 | } | |
251e610c | 539 | |
bcd5d3a2 | 540 | int evp_keyexch_get_number(const EVP_KEYEXCH *keyexch) |
506cb0f6 RL |
541 | { |
542 | return keyexch->name_id; | |
543 | } | |
544 | ||
ed576acd | 545 | const char *EVP_KEYEXCH_get0_name(const EVP_KEYEXCH *keyexch) |
6c9bc258 TM |
546 | { |
547 | return keyexch->type_name; | |
548 | } | |
549 | ||
ed576acd | 550 | const char *EVP_KEYEXCH_get0_description(const EVP_KEYEXCH *keyexch) |
03888233 RL |
551 | { |
552 | return keyexch->description; | |
553 | } | |
554 | ||
251e610c RL |
555 | int EVP_KEYEXCH_is_a(const EVP_KEYEXCH *keyexch, const char *name) |
556 | { | |
ee8db8c5 P |
557 | return keyexch != NULL |
558 | && evp_is_a(keyexch->prov, keyexch->name_id, NULL, name); | |
251e610c RL |
559 | } |
560 | ||
b4250010 | 561 | void EVP_KEYEXCH_do_all_provided(OSSL_LIB_CTX *libctx, |
251e610c RL |
562 | void (*fn)(EVP_KEYEXCH *keyexch, void *arg), |
563 | void *arg) | |
564 | { | |
251e610c RL |
565 | evp_generic_do_all(libctx, OSSL_OP_KEYEXCH, |
566 | (void (*)(void *, void *))fn, arg, | |
309a78aa | 567 | evp_keyexch_from_algorithm, |
cd770738 | 568 | (int (*)(void *))EVP_KEYEXCH_up_ref, |
251e610c RL |
569 | (void (*)(void *))EVP_KEYEXCH_free); |
570 | } | |
f651c727 | 571 | |
d84f5515 MC |
572 | int EVP_KEYEXCH_names_do_all(const EVP_KEYEXCH *keyexch, |
573 | void (*fn)(const char *name, void *data), | |
574 | void *data) | |
f651c727 RL |
575 | { |
576 | if (keyexch->prov != NULL) | |
d84f5515 MC |
577 | return evp_names_do_all(keyexch->prov, keyexch->name_id, fn, data); |
578 | ||
579 | return 1; | |
f651c727 | 580 | } |
e3efe7a5 SL |
581 | |
582 | const OSSL_PARAM *EVP_KEYEXCH_gettable_ctx_params(const EVP_KEYEXCH *keyexch) | |
583 | { | |
584 | void *provctx; | |
585 | ||
586 | if (keyexch == NULL || keyexch->gettable_ctx_params == NULL) | |
587 | return NULL; | |
588 | ||
ed576acd | 589 | provctx = ossl_provider_ctx(EVP_KEYEXCH_get0_provider(keyexch)); |
fb67126e | 590 | return keyexch->gettable_ctx_params(NULL, provctx); |
e3efe7a5 SL |
591 | } |
592 | ||
593 | const OSSL_PARAM *EVP_KEYEXCH_settable_ctx_params(const EVP_KEYEXCH *keyexch) | |
594 | { | |
595 | void *provctx; | |
596 | ||
597 | if (keyexch == NULL || keyexch->settable_ctx_params == NULL) | |
598 | return NULL; | |
ed576acd | 599 | provctx = ossl_provider_ctx(EVP_KEYEXCH_get0_provider(keyexch)); |
fb67126e | 600 | return keyexch->settable_ctx_params(NULL, provctx); |
e3efe7a5 | 601 | } |