/src/openssl/crypto/evp/exchange.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2019 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 | | #include <openssl/crypto.h> |
11 | | #include <openssl/evp.h> |
12 | | #include <openssl/err.h> |
13 | | #include "internal/refcount.h" |
14 | | #include "crypto/evp.h" |
15 | | #include "internal/provider.h" |
16 | | #include "internal/numbers.h" /* includes SIZE_MAX */ |
17 | | #include "evp_local.h" |
18 | | |
19 | | static EVP_KEYEXCH *evp_keyexch_new(OSSL_PROVIDER *prov) |
20 | 0 | { |
21 | 0 | EVP_KEYEXCH *exchange = OPENSSL_zalloc(sizeof(EVP_KEYEXCH)); |
22 | |
|
23 | 0 | if (exchange == NULL) { |
24 | 0 | ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); |
25 | 0 | return NULL; |
26 | 0 | } |
27 | | |
28 | 0 | exchange->lock = CRYPTO_THREAD_lock_new(); |
29 | 0 | if (exchange->lock == NULL) { |
30 | 0 | ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); |
31 | 0 | OPENSSL_free(exchange); |
32 | 0 | return NULL; |
33 | 0 | } |
34 | 0 | exchange->prov = prov; |
35 | 0 | ossl_provider_up_ref(prov); |
36 | 0 | exchange->refcnt = 1; |
37 | |
|
38 | 0 | return exchange; |
39 | 0 | } |
40 | | |
41 | | static void *evp_keyexch_from_dispatch(int name_id, |
42 | | const OSSL_DISPATCH *fns, |
43 | | OSSL_PROVIDER *prov) |
44 | 0 | { |
45 | 0 | EVP_KEYEXCH *exchange = NULL; |
46 | 0 | int fncnt = 0, paramfncnt = 0; |
47 | |
|
48 | 0 | if ((exchange = evp_keyexch_new(prov)) == NULL) { |
49 | 0 | ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); |
50 | 0 | goto err; |
51 | 0 | } |
52 | | |
53 | 0 | exchange->name_id = name_id; |
54 | |
|
55 | 0 | for (; fns->function_id != 0; fns++) { |
56 | 0 | switch (fns->function_id) { |
57 | 0 | case OSSL_FUNC_KEYEXCH_NEWCTX: |
58 | 0 | if (exchange->newctx != NULL) |
59 | 0 | break; |
60 | 0 | exchange->newctx = OSSL_get_OP_keyexch_newctx(fns); |
61 | 0 | fncnt++; |
62 | 0 | break; |
63 | 0 | case OSSL_FUNC_KEYEXCH_INIT: |
64 | 0 | if (exchange->init != NULL) |
65 | 0 | break; |
66 | 0 | exchange->init = OSSL_get_OP_keyexch_init(fns); |
67 | 0 | fncnt++; |
68 | 0 | break; |
69 | 0 | case OSSL_FUNC_KEYEXCH_SET_PEER: |
70 | 0 | if (exchange->set_peer != NULL) |
71 | 0 | break; |
72 | 0 | exchange->set_peer = OSSL_get_OP_keyexch_set_peer(fns); |
73 | 0 | break; |
74 | 0 | case OSSL_FUNC_KEYEXCH_DERIVE: |
75 | 0 | if (exchange->derive != NULL) |
76 | 0 | break; |
77 | 0 | exchange->derive = OSSL_get_OP_keyexch_derive(fns); |
78 | 0 | fncnt++; |
79 | 0 | break; |
80 | 0 | case OSSL_FUNC_KEYEXCH_FREECTX: |
81 | 0 | if (exchange->freectx != NULL) |
82 | 0 | break; |
83 | 0 | exchange->freectx = OSSL_get_OP_keyexch_freectx(fns); |
84 | 0 | fncnt++; |
85 | 0 | break; |
86 | 0 | case OSSL_FUNC_KEYEXCH_DUPCTX: |
87 | 0 | if (exchange->dupctx != NULL) |
88 | 0 | break; |
89 | 0 | exchange->dupctx = OSSL_get_OP_keyexch_dupctx(fns); |
90 | 0 | break; |
91 | 0 | case OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS: |
92 | 0 | if (exchange->set_ctx_params != NULL) |
93 | 0 | break; |
94 | 0 | exchange->set_ctx_params = OSSL_get_OP_keyexch_set_ctx_params(fns); |
95 | 0 | paramfncnt++; |
96 | 0 | break; |
97 | 0 | case OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS: |
98 | 0 | if (exchange->settable_ctx_params != NULL) |
99 | 0 | break; |
100 | 0 | exchange->settable_ctx_params |
101 | 0 | = OSSL_get_OP_keyexch_settable_ctx_params(fns); |
102 | 0 | paramfncnt++; |
103 | 0 | break; |
104 | 0 | } |
105 | 0 | } |
106 | 0 | if (fncnt != 4 || (paramfncnt != 0 && paramfncnt != 2)) { |
107 | | /* |
108 | | * In order to be a consistent set of functions we must have at least |
109 | | * a complete set of "exchange" functions: init, derive, newctx, |
110 | | * and freectx. The set_ctx_params and settable_ctx_params functions are |
111 | | * optional, but if one of them is present then the other one must also |
112 | | * be present. The dupctx and set_peer functions are optional. |
113 | | */ |
114 | 0 | EVPerr(EVP_F_EVP_KEYEXCH_FROM_DISPATCH, |
115 | 0 | EVP_R_INVALID_PROVIDER_FUNCTIONS); |
116 | 0 | goto err; |
117 | 0 | } |
118 | | |
119 | 0 | return exchange; |
120 | | |
121 | 0 | err: |
122 | 0 | EVP_KEYEXCH_free(exchange); |
123 | 0 | return NULL; |
124 | 0 | } |
125 | | |
126 | | void EVP_KEYEXCH_free(EVP_KEYEXCH *exchange) |
127 | 0 | { |
128 | 0 | if (exchange != NULL) { |
129 | 0 | int i; |
130 | |
|
131 | 0 | CRYPTO_DOWN_REF(&exchange->refcnt, &i, exchange->lock); |
132 | 0 | if (i > 0) |
133 | 0 | return; |
134 | 0 | ossl_provider_free(exchange->prov); |
135 | 0 | CRYPTO_THREAD_lock_free(exchange->lock); |
136 | 0 | OPENSSL_free(exchange); |
137 | 0 | } |
138 | 0 | } |
139 | | |
140 | | int EVP_KEYEXCH_up_ref(EVP_KEYEXCH *exchange) |
141 | 0 | { |
142 | 0 | int ref = 0; |
143 | |
|
144 | 0 | CRYPTO_UP_REF(&exchange->refcnt, &ref, exchange->lock); |
145 | 0 | return 1; |
146 | 0 | } |
147 | | |
148 | | OSSL_PROVIDER *EVP_KEYEXCH_provider(const EVP_KEYEXCH *exchange) |
149 | 0 | { |
150 | 0 | return exchange->prov; |
151 | 0 | } |
152 | | |
153 | | EVP_KEYEXCH *EVP_KEYEXCH_fetch(OPENSSL_CTX *ctx, const char *algorithm, |
154 | | const char *properties) |
155 | 0 | { |
156 | 0 | return evp_generic_fetch(ctx, OSSL_OP_KEYEXCH, algorithm, properties, |
157 | 0 | evp_keyexch_from_dispatch, |
158 | 0 | (int (*)(void *))EVP_KEYEXCH_up_ref, |
159 | 0 | (void (*)(void *))EVP_KEYEXCH_free); |
160 | 0 | } |
161 | | |
162 | | int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) |
163 | 0 | { |
164 | 0 | int ret; |
165 | 0 | void *provkey = NULL; |
166 | 0 | EVP_KEYEXCH *exchange = NULL; |
167 | 0 | EVP_KEYMGMT *tmp_keymgmt = NULL; |
168 | 0 | const char *supported_exch = NULL; |
169 | |
|
170 | 0 | if (ctx == NULL) { |
171 | 0 | EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
172 | 0 | return -2; |
173 | 0 | } |
174 | | |
175 | 0 | evp_pkey_ctx_free_old_ops(ctx); |
176 | 0 | ctx->operation = EVP_PKEY_OP_DERIVE; |
177 | | |
178 | | /* |
179 | | * TODO when we stop falling back to legacy, this and the ERR_pop_to_mark() |
180 | | * calls can be removed. |
181 | | */ |
182 | 0 | ERR_set_mark(); |
183 | |
|
184 | 0 | if (ctx->engine != NULL || ctx->keytype == NULL) |
185 | 0 | goto legacy; |
186 | | |
187 | | /* Ensure that the key is provided. If not, go legacy */ |
188 | 0 | tmp_keymgmt = ctx->keymgmt; |
189 | 0 | provkey = evp_pkey_make_provided(ctx->pkey, ctx->libctx, |
190 | 0 | &tmp_keymgmt, ctx->propquery); |
191 | 0 | if (provkey == NULL) |
192 | 0 | goto legacy; |
193 | 0 | if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) { |
194 | 0 | ERR_clear_last_mark(); |
195 | 0 | ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); |
196 | 0 | goto err; |
197 | 0 | } |
198 | 0 | EVP_KEYMGMT_free(ctx->keymgmt); |
199 | 0 | ctx->keymgmt = tmp_keymgmt; |
200 | |
|
201 | 0 | if (ctx->keymgmt->query_operation_name != NULL) |
202 | 0 | supported_exch = ctx->keymgmt->query_operation_name(OSSL_OP_KEYEXCH); |
203 | | |
204 | | /* |
205 | | * If we didn't get a supported exch, assume there is one with the |
206 | | * same name as the key type. |
207 | | */ |
208 | 0 | if (supported_exch == NULL) |
209 | 0 | supported_exch = ctx->keytype; |
210 | | |
211 | | /* |
212 | | * Because we cleared out old ops, we shouldn't need to worry about |
213 | | * checking if exchange is already there. |
214 | | */ |
215 | 0 | exchange = EVP_KEYEXCH_fetch(ctx->libctx, supported_exch, ctx->propquery); |
216 | |
|
217 | 0 | if (exchange == NULL |
218 | 0 | || (EVP_KEYMGMT_provider(ctx->keymgmt) |
219 | 0 | != EVP_KEYEXCH_provider(exchange))) { |
220 | | /* |
221 | | * We don't need to free ctx->keymgmt here, as it's not necessarily |
222 | | * tied to this operation. It will be freed by EVP_PKEY_CTX_free(). |
223 | | */ |
224 | 0 | EVP_KEYEXCH_free(exchange); |
225 | 0 | goto legacy; |
226 | 0 | } |
227 | | |
228 | | /* |
229 | | * TODO remove this when legacy is gone |
230 | | * If we don't have the full support we need with provided methods, |
231 | | * let's go see if legacy does. |
232 | | */ |
233 | 0 | ERR_pop_to_mark(); |
234 | | |
235 | | /* No more legacy from here down to legacy: */ |
236 | |
|
237 | 0 | ctx->op.kex.exchange = exchange; |
238 | 0 | ctx->op.kex.exchprovctx = exchange->newctx(ossl_provider_ctx(exchange->prov)); |
239 | 0 | if (ctx->op.kex.exchprovctx == NULL) { |
240 | | /* The provider key can stay in the cache */ |
241 | 0 | EVPerr(0, EVP_R_INITIALIZATION_ERROR); |
242 | 0 | goto err; |
243 | 0 | } |
244 | 0 | ret = exchange->init(ctx->op.kex.exchprovctx, provkey); |
245 | |
|
246 | 0 | return ret ? 1 : 0; |
247 | 0 | err: |
248 | 0 | ctx->operation = EVP_PKEY_OP_UNDEFINED; |
249 | 0 | return 0; |
250 | | |
251 | 0 | legacy: |
252 | | /* |
253 | | * TODO remove this when legacy is gone |
254 | | * If we don't have the full support we need with provided methods, |
255 | | * let's go see if legacy does. |
256 | | */ |
257 | 0 | ERR_pop_to_mark(); |
258 | |
|
259 | | #ifdef FIPS_MODE |
260 | | return 0; |
261 | | #else |
262 | 0 | if (ctx->pmeth == NULL || ctx->pmeth->derive == NULL) { |
263 | 0 | EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
264 | 0 | return -2; |
265 | 0 | } |
266 | | |
267 | 0 | if (ctx->pmeth->derive_init == NULL) |
268 | 0 | return 1; |
269 | 0 | ret = ctx->pmeth->derive_init(ctx); |
270 | 0 | if (ret <= 0) |
271 | 0 | ctx->operation = EVP_PKEY_OP_UNDEFINED; |
272 | 0 | return ret; |
273 | 0 | #endif |
274 | 0 | } |
275 | | |
276 | | int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer) |
277 | 0 | { |
278 | 0 | int ret = 0; |
279 | 0 | void *provkey = NULL; |
280 | |
|
281 | 0 | if (ctx == NULL) { |
282 | 0 | EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, |
283 | 0 | EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
284 | 0 | return -2; |
285 | 0 | } |
286 | | |
287 | 0 | if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx) || ctx->op.kex.exchprovctx == NULL) |
288 | 0 | goto legacy; |
289 | | |
290 | 0 | if (ctx->op.kex.exchange->set_peer == NULL) { |
291 | 0 | EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, |
292 | 0 | EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
293 | 0 | return -2; |
294 | 0 | } |
295 | | |
296 | 0 | provkey = evp_keymgmt_util_export_to_provider(peer, ctx->keymgmt); |
297 | | /* If export failed, legacy may be able to pick it up */ |
298 | 0 | if (provkey == NULL) |
299 | 0 | goto legacy; |
300 | 0 | return ctx->op.kex.exchange->set_peer(ctx->op.kex.exchprovctx, provkey); |
301 | | |
302 | 0 | legacy: |
303 | | #ifdef FIPS_MODE |
304 | | return ret; |
305 | | #else |
306 | 0 | if (ctx->pmeth == NULL |
307 | 0 | || !(ctx->pmeth->derive != NULL |
308 | 0 | || ctx->pmeth->encrypt != NULL |
309 | 0 | || ctx->pmeth->decrypt != NULL) |
310 | 0 | || ctx->pmeth->ctrl == NULL) { |
311 | 0 | EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, |
312 | 0 | EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
313 | 0 | return -2; |
314 | 0 | } |
315 | 0 | if (ctx->operation != EVP_PKEY_OP_DERIVE |
316 | 0 | && ctx->operation != EVP_PKEY_OP_ENCRYPT |
317 | 0 | && ctx->operation != EVP_PKEY_OP_DECRYPT) { |
318 | 0 | EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, |
319 | 0 | EVP_R_OPERATON_NOT_INITIALIZED); |
320 | 0 | return -1; |
321 | 0 | } |
322 | | |
323 | 0 | ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 0, peer); |
324 | |
|
325 | 0 | if (ret <= 0) |
326 | 0 | return ret; |
327 | | |
328 | 0 | if (ret == 2) |
329 | 0 | return 1; |
330 | | |
331 | 0 | if (ctx->pkey == NULL) { |
332 | 0 | EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_NO_KEY_SET); |
333 | 0 | return -1; |
334 | 0 | } |
335 | | |
336 | 0 | if (ctx->pkey->type != peer->type) { |
337 | 0 | EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_DIFFERENT_KEY_TYPES); |
338 | 0 | return -1; |
339 | 0 | } |
340 | | |
341 | | /* |
342 | | * For clarity. The error is if parameters in peer are |
343 | | * present (!missing) but don't match. EVP_PKEY_cmp_parameters may return |
344 | | * 1 (match), 0 (don't match) and -2 (comparison is not defined). -1 |
345 | | * (different key types) is impossible here because it is checked earlier. |
346 | | * -2 is OK for us here, as well as 1, so we can check for 0 only. |
347 | | */ |
348 | 0 | if (!EVP_PKEY_missing_parameters(peer) && |
349 | 0 | !EVP_PKEY_cmp_parameters(ctx->pkey, peer)) { |
350 | 0 | EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_DIFFERENT_PARAMETERS); |
351 | 0 | return -1; |
352 | 0 | } |
353 | | |
354 | 0 | EVP_PKEY_free(ctx->peerkey); |
355 | 0 | ctx->peerkey = peer; |
356 | |
|
357 | 0 | ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer); |
358 | |
|
359 | 0 | if (ret <= 0) { |
360 | 0 | ctx->peerkey = NULL; |
361 | 0 | return ret; |
362 | 0 | } |
363 | | |
364 | 0 | EVP_PKEY_up_ref(peer); |
365 | 0 | return 1; |
366 | 0 | #endif |
367 | 0 | } |
368 | | |
369 | | int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *pkeylen) |
370 | 0 | { |
371 | 0 | int ret; |
372 | |
|
373 | 0 | if (ctx == NULL) { |
374 | 0 | EVPerr(EVP_F_EVP_PKEY_DERIVE, |
375 | 0 | EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
376 | 0 | return -2; |
377 | 0 | } |
378 | | |
379 | 0 | if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) { |
380 | 0 | EVPerr(EVP_F_EVP_PKEY_DERIVE, EVP_R_OPERATON_NOT_INITIALIZED); |
381 | 0 | return -1; |
382 | 0 | } |
383 | | |
384 | 0 | if (ctx->op.kex.exchprovctx == NULL) |
385 | 0 | goto legacy; |
386 | | |
387 | 0 | ret = ctx->op.kex.exchange->derive(ctx->op.kex.exchprovctx, key, pkeylen, |
388 | 0 | SIZE_MAX); |
389 | |
|
390 | 0 | return ret; |
391 | 0 | legacy: |
392 | 0 | if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->derive == NULL) { |
393 | 0 | EVPerr(EVP_F_EVP_PKEY_DERIVE, |
394 | 0 | EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
395 | 0 | return -2; |
396 | 0 | } |
397 | | |
398 | 0 | M_check_autoarg(ctx, key, pkeylen, EVP_F_EVP_PKEY_DERIVE) |
399 | 0 | return ctx->pmeth->derive(ctx, key, pkeylen); |
400 | 0 | } |
401 | | |
402 | | int EVP_KEYEXCH_number(const EVP_KEYEXCH *keyexch) |
403 | 0 | { |
404 | 0 | return keyexch->name_id; |
405 | 0 | } |
406 | | |
407 | | int EVP_KEYEXCH_is_a(const EVP_KEYEXCH *keyexch, const char *name) |
408 | 0 | { |
409 | 0 | return evp_is_a(keyexch->prov, keyexch->name_id, NULL, name); |
410 | 0 | } |
411 | | |
412 | | void EVP_KEYEXCH_do_all_provided(OPENSSL_CTX *libctx, |
413 | | void (*fn)(EVP_KEYEXCH *keyexch, void *arg), |
414 | | void *arg) |
415 | 0 | { |
416 | 0 | evp_generic_do_all(libctx, OSSL_OP_KEYEXCH, |
417 | 0 | (void (*)(void *, void *))fn, arg, |
418 | 0 | evp_keyexch_from_dispatch, |
419 | 0 | (void (*)(void *))EVP_KEYEXCH_free); |
420 | 0 | } |
421 | | |
422 | | void EVP_KEYEXCH_names_do_all(const EVP_KEYEXCH *keyexch, |
423 | | void (*fn)(const char *name, void *data), |
424 | | void *data) |
425 | 0 | { |
426 | 0 | if (keyexch->prov != NULL) |
427 | 0 | evp_names_do_all(keyexch->prov, keyexch->name_id, fn, data); |
428 | 0 | } |