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 | { |
21 | EVP_KEYEXCH *exchange = OPENSSL_zalloc(sizeof(EVP_KEYEXCH)); |
22 | |
23 | if (exchange == NULL) { |
24 | ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); |
25 | return NULL; |
26 | } |
27 | |
28 | exchange->lock = CRYPTO_THREAD_lock_new(); |
29 | if (exchange->lock == NULL) { |
30 | ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); |
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 | |
41 | static void *evp_keyexch_from_dispatch(int name_id, |
42 | const OSSL_DISPATCH *fns, |
43 | OSSL_PROVIDER *prov) |
44 | { |
45 | EVP_KEYEXCH *exchange = NULL; |
46 | int fncnt = 0, paramfncnt = 0; |
47 | |
48 | if ((exchange = evp_keyexch_new(prov)) == NULL) { |
49 | ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); |
50 | goto err; |
51 | } |
52 | |
53 | exchange->name_id = name_id; |
54 | |
55 | for (; fns->function_id != 0; fns++) { |
56 | switch (fns->function_id) { |
57 | case OSSL_FUNC_KEYEXCH_NEWCTX: |
58 | if (exchange->newctx != NULL) |
59 | break; |
60 | exchange->newctx = OSSL_get_OP_keyexch_newctx(fns); |
61 | fncnt++; |
62 | break; |
63 | case OSSL_FUNC_KEYEXCH_INIT: |
64 | if (exchange->init != NULL) |
65 | break; |
66 | exchange->init = OSSL_get_OP_keyexch_init(fns); |
67 | fncnt++; |
68 | break; |
69 | case OSSL_FUNC_KEYEXCH_SET_PEER: |
70 | if (exchange->set_peer != NULL) |
71 | break; |
72 | exchange->set_peer = OSSL_get_OP_keyexch_set_peer(fns); |
73 | break; |
74 | case OSSL_FUNC_KEYEXCH_DERIVE: |
75 | if (exchange->derive != NULL) |
76 | break; |
77 | exchange->derive = OSSL_get_OP_keyexch_derive(fns); |
78 | fncnt++; |
79 | break; |
80 | case OSSL_FUNC_KEYEXCH_FREECTX: |
81 | if (exchange->freectx != NULL) |
82 | break; |
83 | exchange->freectx = OSSL_get_OP_keyexch_freectx(fns); |
84 | fncnt++; |
85 | break; |
86 | case OSSL_FUNC_KEYEXCH_DUPCTX: |
87 | if (exchange->dupctx != NULL) |
88 | break; |
89 | exchange->dupctx = OSSL_get_OP_keyexch_dupctx(fns); |
90 | break; |
91 | case OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS: |
92 | if (exchange->set_ctx_params != NULL) |
93 | break; |
94 | exchange->set_ctx_params = OSSL_get_OP_keyexch_set_ctx_params(fns); |
95 | paramfncnt++; |
96 | break; |
97 | case OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS: |
98 | if (exchange->settable_ctx_params != NULL) |
99 | break; |
100 | exchange->settable_ctx_params |
101 | = OSSL_get_OP_keyexch_settable_ctx_params(fns); |
102 | paramfncnt++; |
103 | break; |
104 | } |
105 | } |
106 | 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 | EVPerr(EVP_F_EVP_KEYEXCH_FROM_DISPATCH, |
115 | EVP_R_INVALID_PROVIDER_FUNCTIONS); |
116 | goto err; |
117 | } |
118 | |
119 | return exchange; |
120 | |
121 | err: |
122 | EVP_KEYEXCH_free(exchange); |
123 | return NULL; |
124 | } |
125 | |
126 | void EVP_KEYEXCH_free(EVP_KEYEXCH *exchange) |
127 | { |
128 | if (exchange != NULL) { |
129 | int i; |
130 | |
131 | CRYPTO_DOWN_REF(&exchange->refcnt, &i, exchange->lock); |
132 | if (i > 0) |
133 | return; |
134 | ossl_provider_free(exchange->prov); |
135 | CRYPTO_THREAD_lock_free(exchange->lock); |
136 | OPENSSL_free(exchange); |
137 | } |
138 | } |
139 | |
140 | int EVP_KEYEXCH_up_ref(EVP_KEYEXCH *exchange) |
141 | { |
142 | int ref = 0; |
143 | |
144 | CRYPTO_UP_REF(&exchange->refcnt, &ref, exchange->lock); |
145 | return 1; |
146 | } |
147 | |
148 | OSSL_PROVIDER *EVP_KEYEXCH_provider(const EVP_KEYEXCH *exchange) |
149 | { |
150 | return exchange->prov; |
151 | } |
152 | |
153 | EVP_KEYEXCH *EVP_KEYEXCH_fetch(OPENSSL_CTX *ctx, const char *algorithm, |
154 | const char *properties) |
155 | { |
156 | return evp_generic_fetch(ctx, OSSL_OP_KEYEXCH, algorithm, properties, |
157 | evp_keyexch_from_dispatch, |
158 | (int (*)(void *))EVP_KEYEXCH_up_ref, |
159 | (void (*)(void *))EVP_KEYEXCH_free); |
160 | } |
161 | |
162 | int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) |
163 | { |
164 | int ret; |
165 | void *provkey = NULL; |
166 | EVP_KEYEXCH *exchange = NULL; |
167 | |
168 | if (ctx == NULL) { |
169 | EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
170 | return -2; |
171 | } |
172 | |
173 | evp_pkey_ctx_free_old_ops(ctx); |
174 | ctx->operation = EVP_PKEY_OP_DERIVE; |
175 | |
176 | if (ctx->engine != NULL || ctx->algorithm == NULL) |
177 | goto legacy; |
178 | |
179 | /* |
180 | * Because we cleared out old ops, we shouldn't need to worry about |
181 | * checking if exchange is already there. Keymgmt is a different |
182 | * matter, as it isn't tied to a specific EVP_PKEY op. |
183 | */ |
184 | exchange = EVP_KEYEXCH_fetch(ctx->libctx, ctx->algorithm, ctx->propquery); |
185 | if (exchange != NULL && ctx->keymgmt == NULL) { |
186 | int name_id = EVP_KEYEXCH_number(exchange); |
187 | |
188 | ctx->keymgmt = |
189 | evp_keymgmt_fetch_by_number(ctx->libctx, name_id, ctx->propquery); |
190 | } |
191 | |
192 | if (ctx->keymgmt == NULL |
193 | || exchange == NULL |
194 | || (EVP_KEYMGMT_provider(ctx->keymgmt) |
195 | != EVP_KEYEXCH_provider(exchange))) { |
196 | /* |
197 | * We don't have the full support we need with provided methods, |
198 | * let's go see if legacy does. Also, we don't need to free |
199 | * ctx->keymgmt here, as it's not necessarily tied to this |
200 | * operation. It will be freed by EVP_PKEY_CTX_free(). |
201 | */ |
202 | EVP_KEYEXCH_free(exchange); |
203 | goto legacy; |
204 | } |
205 | |
206 | |
207 | ctx->op.kex.exchange = exchange; |
208 | |
209 | if (ctx->pkey != NULL) { |
210 | provkey = evp_keymgmt_export_to_provider(ctx->pkey, ctx->keymgmt, 0); |
211 | if (provkey == NULL) { |
212 | EVPerr(0, EVP_R_INITIALIZATION_ERROR); |
213 | goto err; |
214 | } |
215 | } |
216 | ctx->op.kex.exchprovctx = exchange->newctx(ossl_provider_ctx(exchange->prov)); |
217 | if (ctx->op.kex.exchprovctx == NULL) { |
218 | /* The provider key can stay in the cache */ |
219 | EVPerr(0, EVP_R_INITIALIZATION_ERROR); |
220 | goto err; |
221 | } |
222 | ret = exchange->init(ctx->op.kex.exchprovctx, provkey); |
223 | |
224 | return ret ? 1 : 0; |
225 | err: |
226 | ctx->operation = EVP_PKEY_OP_UNDEFINED; |
227 | return 0; |
228 | |
229 | legacy: |
230 | if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->derive == NULL) { |
231 | EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
232 | return -2; |
233 | } |
234 | |
235 | if (ctx->pmeth->derive_init == NULL) |
236 | return 1; |
237 | ret = ctx->pmeth->derive_init(ctx); |
238 | if (ret <= 0) |
239 | ctx->operation = EVP_PKEY_OP_UNDEFINED; |
240 | return ret; |
241 | } |
242 | |
243 | int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer) |
244 | { |
245 | int ret; |
246 | void *provkey = NULL; |
247 | |
248 | if (ctx == NULL) { |
249 | EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, |
250 | EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
251 | return -2; |
252 | } |
253 | |
254 | if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx) || ctx->op.kex.exchprovctx == NULL) |
255 | goto legacy; |
256 | |
257 | if (ctx->op.kex.exchange->set_peer == NULL) { |
258 | EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, |
259 | EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
260 | return -2; |
261 | } |
262 | |
263 | provkey = evp_keymgmt_export_to_provider(peer, ctx->keymgmt, 0); |
264 | if (provkey == NULL) { |
265 | EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, ERR_R_INTERNAL_ERROR); |
266 | return 0; |
267 | } |
268 | return ctx->op.kex.exchange->set_peer(ctx->op.kex.exchprovctx, provkey); |
269 | |
270 | legacy: |
271 | if (ctx->pmeth == NULL |
272 | || !(ctx->pmeth->derive != NULL |
273 | || ctx->pmeth->encrypt != NULL |
274 | || ctx->pmeth->decrypt != NULL) |
275 | || ctx->pmeth->ctrl == NULL) { |
276 | EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, |
277 | EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
278 | return -2; |
279 | } |
280 | if (ctx->operation != EVP_PKEY_OP_DERIVE |
281 | && ctx->operation != EVP_PKEY_OP_ENCRYPT |
282 | && ctx->operation != EVP_PKEY_OP_DECRYPT) { |
283 | EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, |
284 | EVP_R_OPERATON_NOT_INITIALIZED); |
285 | return -1; |
286 | } |
287 | |
288 | ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 0, peer); |
289 | |
290 | if (ret <= 0) |
291 | return ret; |
292 | |
293 | if (ret == 2) |
294 | return 1; |
295 | |
296 | if (ctx->pkey == NULL) { |
297 | EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_NO_KEY_SET); |
298 | return -1; |
299 | } |
300 | |
301 | if (ctx->pkey->type != peer->type) { |
302 | EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_DIFFERENT_KEY_TYPES); |
303 | return -1; |
304 | } |
305 | |
306 | /* |
307 | * For clarity. The error is if parameters in peer are |
308 | * present (!missing) but don't match. EVP_PKEY_cmp_parameters may return |
309 | * 1 (match), 0 (don't match) and -2 (comparison is not defined). -1 |
310 | * (different key types) is impossible here because it is checked earlier. |
311 | * -2 is OK for us here, as well as 1, so we can check for 0 only. |
312 | */ |
313 | if (!EVP_PKEY_missing_parameters(peer) && |
314 | !EVP_PKEY_cmp_parameters(ctx->pkey, peer)) { |
315 | EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_DIFFERENT_PARAMETERS); |
316 | return -1; |
317 | } |
318 | |
319 | EVP_PKEY_free(ctx->peerkey); |
320 | ctx->peerkey = peer; |
321 | |
322 | ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer); |
323 | |
324 | if (ret <= 0) { |
325 | ctx->peerkey = NULL; |
326 | return ret; |
327 | } |
328 | |
329 | EVP_PKEY_up_ref(peer); |
330 | return 1; |
331 | } |
332 | |
333 | int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *pkeylen) |
334 | { |
335 | int ret; |
336 | |
337 | if (ctx == NULL) { |
338 | EVPerr(EVP_F_EVP_PKEY_DERIVE, |
339 | EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
340 | return -2; |
341 | } |
342 | |
343 | if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) { |
344 | EVPerr(EVP_F_EVP_PKEY_DERIVE, EVP_R_OPERATON_NOT_INITIALIZED); |
345 | return -1; |
346 | } |
347 | |
348 | if (ctx->op.kex.exchprovctx == NULL) |
349 | goto legacy; |
350 | |
351 | ret = ctx->op.kex.exchange->derive(ctx->op.kex.exchprovctx, key, pkeylen, |
352 | SIZE_MAX); |
353 | |
354 | return ret; |
355 | legacy: |
356 | if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->derive == NULL) { |
357 | EVPerr(EVP_F_EVP_PKEY_DERIVE, |
358 | EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
359 | return -2; |
360 | } |
361 | |
362 | M_check_autoarg(ctx, key, pkeylen, EVP_F_EVP_PKEY_DERIVE) |
363 | return ctx->pmeth->derive(ctx, key, pkeylen); |
364 | } |
365 | |
366 | int EVP_KEYEXCH_number(const EVP_KEYEXCH *keyexch) |
367 | { |
368 | return keyexch->name_id; |
369 | } |
370 | |
371 | int EVP_KEYEXCH_is_a(const EVP_KEYEXCH *keyexch, const char *name) |
372 | { |
373 | return evp_is_a(keyexch->prov, keyexch->name_id, name); |
374 | } |
375 | |
376 | void EVP_KEYEXCH_do_all_provided(OPENSSL_CTX *libctx, |
377 | void (*fn)(EVP_KEYEXCH *keyexch, void *arg), |
378 | void *arg) |
379 | { |
380 | evp_generic_do_all(libctx, OSSL_OP_KEYEXCH, |
381 | (void (*)(void *, void *))fn, arg, |
382 | evp_keyexch_from_dispatch, |
383 | (void (*)(void *))EVP_KEYEXCH_free); |
384 | } |
385 | |
386 | void EVP_KEYEXCH_names_do_all(const EVP_KEYEXCH *keyexch, |
387 | void (*fn)(const char *name, void *data), |
388 | void *data) |
389 | { |
390 | if (keyexch->prov != NULL) |
391 | evp_names_do_all(keyexch->prov, keyexch->name_id, fn, data); |
392 | } |
393 | |