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