]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/evp/exchange.c
Reorganize local header files
[thirdparty/openssl.git] / crypto / evp / exchange.c
CommitLineData
ff64702b
MC
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"
25f2138b 14#include "crypto/evp.h"
ff64702b 15#include "internal/provider.h"
ac5a61ca 16#include "internal/numbers.h" /* includes SIZE_MAX */
706457b7 17#include "evp_local.h"
ff64702b
MC
18
19static EVP_KEYEXCH *evp_keyexch_new(OSSL_PROVIDER *prov)
20{
21 EVP_KEYEXCH *exchange = OPENSSL_zalloc(sizeof(EVP_KEYEXCH));
22
23 exchange->lock = CRYPTO_THREAD_lock_new();
24 if (exchange->lock == NULL) {
25 OPENSSL_free(exchange);
26 return NULL;
27 }
28 exchange->prov = prov;
29 ossl_provider_up_ref(prov);
30 exchange->refcnt = 1;
31
32 return exchange;
33}
34
f7c16d48 35static void *evp_keyexch_from_dispatch(int name_id,
6b9e3724 36 const OSSL_DISPATCH *fns,
3ca9d210
RL
37 OSSL_PROVIDER *prov,
38 void *vkeymgmt_data)
ff64702b 39{
3ca9d210
RL
40 /*
41 * Key exchange cannot work without a key, and key management
42 * from the same provider to manage its keys. We therefore fetch
43 * a key management method using the same algorithm and properties
44 * and pass that down to evp_generic_fetch to be passed on to our
45 * evp_keyexch_from_dispatch, which will attach the key management
46 * method to the newly created key exchange method as long as the
47 * provider matches.
48 */
49 struct keymgmt_data_st *keymgmt_data = vkeymgmt_data;
f7c16d48
RL
50 EVP_KEYMGMT *keymgmt =
51 evp_keymgmt_fetch_by_number(keymgmt_data->ctx, name_id,
52 keymgmt_data->properties);
ff64702b 53 EVP_KEYEXCH *exchange = NULL;
9c45222d 54 int fncnt = 0, paramfncnt = 0;
ff64702b 55
3ca9d210
RL
56 if (keymgmt == NULL || EVP_KEYMGMT_provider(keymgmt) != prov) {
57 ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEYMGMT_AVAILABLE);
58 goto err;
59 }
60
f7c16d48 61 if ((exchange = evp_keyexch_new(prov)) == NULL) {
3ca9d210
RL
62 ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
63 goto err;
6b9e3724 64 }
ff64702b 65
f7c16d48 66 exchange->name_id = name_id;
3ca9d210
RL
67 exchange->keymgmt = keymgmt;
68 keymgmt = NULL; /* avoid double free on failure below */
69
ff64702b
MC
70 for (; fns->function_id != 0; fns++) {
71 switch (fns->function_id) {
72 case OSSL_FUNC_KEYEXCH_NEWCTX:
73 if (exchange->newctx != NULL)
74 break;
75 exchange->newctx = OSSL_get_OP_keyexch_newctx(fns);
76 fncnt++;
77 break;
78 case OSSL_FUNC_KEYEXCH_INIT:
79 if (exchange->init != NULL)
80 break;
81 exchange->init = OSSL_get_OP_keyexch_init(fns);
82 fncnt++;
83 break;
84 case OSSL_FUNC_KEYEXCH_SET_PEER:
85 if (exchange->set_peer != NULL)
86 break;
87 exchange->set_peer = OSSL_get_OP_keyexch_set_peer(fns);
88 break;
89 case OSSL_FUNC_KEYEXCH_DERIVE:
90 if (exchange->derive != NULL)
91 break;
92 exchange->derive = OSSL_get_OP_keyexch_derive(fns);
93 fncnt++;
94 break;
95 case OSSL_FUNC_KEYEXCH_FREECTX:
96 if (exchange->freectx != NULL)
97 break;
98 exchange->freectx = OSSL_get_OP_keyexch_freectx(fns);
99 fncnt++;
100 break;
101 case OSSL_FUNC_KEYEXCH_DUPCTX:
102 if (exchange->dupctx != NULL)
103 break;
104 exchange->dupctx = OSSL_get_OP_keyexch_dupctx(fns);
105 break;
9c45222d
MC
106 case OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS:
107 if (exchange->set_ctx_params != NULL)
35aca9ec 108 break;
9c45222d
MC
109 exchange->set_ctx_params = OSSL_get_OP_keyexch_set_ctx_params(fns);
110 paramfncnt++;
111 break;
112 case OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS:
113 if (exchange->settable_ctx_params != NULL)
114 break;
115 exchange->settable_ctx_params
116 = OSSL_get_OP_keyexch_settable_ctx_params(fns);
117 paramfncnt++;
35aca9ec 118 break;
ff64702b
MC
119 }
120 }
9c45222d 121 if (fncnt != 4 || (paramfncnt != 0 && paramfncnt != 2)) {
ff64702b
MC
122 /*
123 * In order to be a consistent set of functions we must have at least
124 * a complete set of "exchange" functions: init, derive, newctx,
9c45222d
MC
125 * and freectx. The set_ctx_params and settable_ctx_params functions are
126 * optional, but if one of them is present then the other one must also
127 * be present. The dupctx and set_peer functions are optional.
ff64702b 128 */
ff64702b
MC
129 EVPerr(EVP_F_EVP_KEYEXCH_FROM_DISPATCH,
130 EVP_R_INVALID_PROVIDER_FUNCTIONS);
3ca9d210 131 goto err;
ff64702b
MC
132 }
133
134 return exchange;
3ca9d210
RL
135
136 err:
137 EVP_KEYEXCH_free(exchange);
138 EVP_KEYMGMT_free(keymgmt);
139 return NULL;
ff64702b
MC
140}
141
142void EVP_KEYEXCH_free(EVP_KEYEXCH *exchange)
143{
144 if (exchange != NULL) {
145 int i;
146
147 CRYPTO_DOWN_REF(&exchange->refcnt, &i, exchange->lock);
148 if (i > 0)
149 return;
8b84b075 150 EVP_KEYMGMT_free(exchange->keymgmt);
ff64702b
MC
151 ossl_provider_free(exchange->prov);
152 CRYPTO_THREAD_lock_free(exchange->lock);
153 OPENSSL_free(exchange);
154 }
155}
156
157int EVP_KEYEXCH_up_ref(EVP_KEYEXCH *exchange)
158{
159 int ref = 0;
160
161 CRYPTO_UP_REF(&exchange->refcnt, &ref, exchange->lock);
162 return 1;
163}
164
8b84b075
RL
165OSSL_PROVIDER *EVP_KEYEXCH_provider(const EVP_KEYEXCH *exchange)
166{
167 return exchange->prov;
168}
169
ff64702b
MC
170EVP_KEYEXCH *EVP_KEYEXCH_fetch(OPENSSL_CTX *ctx, const char *algorithm,
171 const char *properties)
172{
3ca9d210
RL
173 EVP_KEYEXCH *keyexch = NULL;
174 struct keymgmt_data_st keymgmt_data;
175
176 keymgmt_data.ctx = ctx;
177 keymgmt_data.properties = properties;
178 keyexch = evp_generic_fetch(ctx, OSSL_OP_KEYEXCH, algorithm, properties,
179 evp_keyexch_from_dispatch, &keymgmt_data,
180 (int (*)(void *))EVP_KEYEXCH_up_ref,
181 (void (*)(void *))EVP_KEYEXCH_free);
8b84b075 182
8b84b075 183 return keyexch;
ff64702b
MC
184}
185
186int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, EVP_KEYEXCH *exchange)
187{
188 int ret;
8b84b075 189 void *provkey = NULL;
ff64702b 190
864b89ce 191 evp_pkey_ctx_free_old_ops(ctx);
ff64702b
MC
192 ctx->operation = EVP_PKEY_OP_DERIVE;
193
194 if (ctx->engine != NULL)
195 goto legacy;
196
197 if (exchange != NULL) {
198 if (!EVP_KEYEXCH_up_ref(exchange))
199 goto err;
200 } else {
201 int nid = ctx->pkey != NULL ? ctx->pkey->type : ctx->pmeth->pkey_id;
202
203 /*
204 * TODO(3.0): Check for legacy handling. Remove this once all all
205 * algorithms are moved to providers.
206 */
207 if (ctx->pkey != NULL) {
208 switch (ctx->pkey->type) {
ff64702b
MC
209 case EVP_PKEY_DH:
210 break;
ff64702b
MC
211 default:
212 goto legacy;
213 }
214 exchange = EVP_KEYEXCH_fetch(NULL, OBJ_nid2sn(nid), NULL);
215 } else {
216 goto legacy;
217 }
218
219 if (exchange == NULL) {
220 EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX, EVP_R_INITIALIZATION_ERROR);
221 goto err;
222 }
223 }
224
864b89ce 225 ctx->op.kex.exchange = exchange;
ff64702b 226 if (ctx->pkey != NULL) {
8b84b075
RL
227 provkey = evp_keymgmt_export_to_provider(ctx->pkey, exchange->keymgmt);
228 if (provkey == NULL) {
ff64702b
MC
229 EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX, EVP_R_INITIALIZATION_ERROR);
230 goto err;
231 }
232 }
864b89ce
MC
233 ctx->op.kex.exchprovctx = exchange->newctx(ossl_provider_ctx(exchange->prov));
234 if (ctx->op.kex.exchprovctx == NULL) {
8b84b075 235 /* The provider key can stay in the cache */
ff64702b
MC
236 EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX, EVP_R_INITIALIZATION_ERROR);
237 goto err;
238 }
864b89ce 239 ret = exchange->init(ctx->op.kex.exchprovctx, provkey);
ff64702b
MC
240
241 return ret ? 1 : 0;
242 err:
243 ctx->operation = EVP_PKEY_OP_UNDEFINED;
244 return 0;
245
246 legacy:
247 if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->derive == NULL) {
248 EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX,
249 EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
250 return -2;
251 }
252
253 if (ctx->pmeth->derive_init == NULL)
254 return 1;
255 ret = ctx->pmeth->derive_init(ctx);
256 if (ret <= 0)
257 ctx->operation = EVP_PKEY_OP_UNDEFINED;
258 return ret;
259}
260
261int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx)
262{
263 return EVP_PKEY_derive_init_ex(ctx, NULL);
264}
265
266int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer)
267{
268 int ret;
8b84b075 269 void *provkey = NULL;
ff64702b
MC
270
271 if (ctx == NULL) {
272 EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
273 EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
274 return -2;
275 }
276
864b89ce 277 if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx) || ctx->op.kex.exchprovctx == NULL)
ff64702b
MC
278 goto legacy;
279
864b89ce 280 if (ctx->op.kex.exchange->set_peer == NULL) {
ff64702b
MC
281 EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
282 EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
283 return -2;
284 }
285
864b89ce
MC
286 provkey = evp_keymgmt_export_to_provider(peer,
287 ctx->op.kex.exchange->keymgmt);
8b84b075 288 if (provkey == NULL) {
ff64702b
MC
289 EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, ERR_R_INTERNAL_ERROR);
290 return 0;
291 }
864b89ce 292 return ctx->op.kex.exchange->set_peer(ctx->op.kex.exchprovctx, provkey);
ff64702b
MC
293
294 legacy:
295 if (ctx->pmeth == NULL
296 || !(ctx->pmeth->derive != NULL
297 || ctx->pmeth->encrypt != NULL
298 || ctx->pmeth->decrypt != NULL)
299 || ctx->pmeth->ctrl == NULL) {
300 EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
301 EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
302 return -2;
303 }
304 if (ctx->operation != EVP_PKEY_OP_DERIVE
305 && ctx->operation != EVP_PKEY_OP_ENCRYPT
306 && ctx->operation != EVP_PKEY_OP_DECRYPT) {
307 EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
308 EVP_R_OPERATON_NOT_INITIALIZED);
309 return -1;
310 }
311
312 ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 0, peer);
313
314 if (ret <= 0)
315 return ret;
316
317 if (ret == 2)
318 return 1;
319
320 if (ctx->pkey == NULL) {
321 EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_NO_KEY_SET);
322 return -1;
323 }
324
325 if (ctx->pkey->type != peer->type) {
326 EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_DIFFERENT_KEY_TYPES);
327 return -1;
328 }
329
330 /*
331 * For clarity. The error is if parameters in peer are
332 * present (!missing) but don't match. EVP_PKEY_cmp_parameters may return
333 * 1 (match), 0 (don't match) and -2 (comparison is not defined). -1
334 * (different key types) is impossible here because it is checked earlier.
335 * -2 is OK for us here, as well as 1, so we can check for 0 only.
336 */
337 if (!EVP_PKEY_missing_parameters(peer) &&
338 !EVP_PKEY_cmp_parameters(ctx->pkey, peer)) {
339 EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_DIFFERENT_PARAMETERS);
340 return -1;
341 }
342
343 EVP_PKEY_free(ctx->peerkey);
344 ctx->peerkey = peer;
345
346 ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer);
347
348 if (ret <= 0) {
349 ctx->peerkey = NULL;
350 return ret;
351 }
352
353 EVP_PKEY_up_ref(peer);
354 return 1;
355}
356
357int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *pkeylen)
358{
359 int ret;
360
361 if (ctx == NULL) {
362 EVPerr(EVP_F_EVP_PKEY_DERIVE,
363 EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
364 return -2;
365 }
366
864b89ce 367 if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
ff64702b
MC
368 EVPerr(EVP_F_EVP_PKEY_DERIVE, EVP_R_OPERATON_NOT_INITIALIZED);
369 return -1;
370 }
371
864b89ce 372 if (ctx->op.kex.exchprovctx == NULL)
ff64702b
MC
373 goto legacy;
374
864b89ce
MC
375 ret = ctx->op.kex.exchange->derive(ctx->op.kex.exchprovctx, key, pkeylen,
376 SIZE_MAX);
ff64702b
MC
377
378 return ret;
379 legacy:
380 if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->derive == NULL) {
381 EVPerr(EVP_F_EVP_PKEY_DERIVE,
382 EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
383 return -2;
384 }
385
386 M_check_autoarg(ctx, key, pkeylen, EVP_F_EVP_PKEY_DERIVE)
387 return ctx->pmeth->derive(ctx, key, pkeylen);
388}