]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/evp/kem.c
EVP: Allow a fallback for operations that work with an EVP_PKEY
[thirdparty/openssl.git] / crypto / evp / kem.c
CommitLineData
80f4fd18 1/*
8020d79b 2 * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved.
80f4fd18
SL
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 <stdio.h>
11#include <stdlib.h>
12#include <openssl/objects.h>
13#include <openssl/evp.h>
14#include "internal/cryptlib.h"
80f4fd18 15#include "internal/provider.h"
6c9bc258
TM
16#include "internal/core.h"
17#include "crypto/evp.h"
80f4fd18
SL
18#include "evp_local.h"
19
4b58d9b4
P
20static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation,
21 const OSSL_PARAM params[])
80f4fd18
SL
22{
23 int ret = 0;
24 EVP_KEM *kem = NULL;
25 EVP_KEYMGMT *tmp_keymgmt = NULL;
839ffdd1 26 const OSSL_PROVIDER *tmp_prov = NULL;
80f4fd18
SL
27 void *provkey = NULL;
28 const char *supported_kem = NULL;
839ffdd1 29 int iter;
80f4fd18
SL
30
31 if (ctx == NULL || ctx->keytype == NULL) {
32 ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
33 return 0;
34 }
35
36 evp_pkey_ctx_free_old_ops(ctx);
37 ctx->operation = operation;
38
39 /*
5246183e 40 * Try to derive the supported kem from |ctx->keymgmt|.
80f4fd18 41 */
5246183e
RL
42 if (!ossl_assert(ctx->pkey->keymgmt == NULL
43 || ctx->pkey->keymgmt == ctx->keymgmt)) {
44 ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
45 goto err;
46 }
47 supported_kem = evp_keymgmt_util_query_operation_name(ctx->keymgmt,
48 OSSL_OP_KEM);
49 if (supported_kem == NULL) {
80f4fd18
SL
50 ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
51 goto err;
52 }
80f4fd18 53
5246183e 54 /*
839ffdd1
RL
55 * Because we cleared out old ops, we shouldn't need to worry about
56 * checking if kem is already there.
57 * We perform two iterations:
58 *
59 * 1. Do the normal kem fetch, using the fetching data given by
60 * the EVP_PKEY_CTX.
61 * 2. Do the provider specific kem fetch, from the same provider
62 * as |ctx->keymgmt|
63 *
64 * We then try to fetch the keymgmt from the same provider as the
65 * kem, and try to export |ctx->pkey| to that keymgmt (when this
66 * keymgmt happens to be the same as |ctx->keymgmt|, the export is
67 * a no-op, but we call it anyway to not complicate the code even
68 * more).
69 * If the export call succeeds (returns a non-NULL provider key pointer),
70 * we're done and can perform the operation itself. If not, we perform
71 * the second iteration, or jump to legacy.
5246183e 72 */
839ffdd1
RL
73 for (iter = 1, provkey = NULL; iter < 3 && provkey == NULL; iter++) {
74 EVP_KEYMGMT *tmp_keymgmt_tofree;
75
76 /*
77 * If we're on the second iteration, free the results from the first.
78 * They are NULL on the first iteration, so no need to check what
79 * iteration we're on.
80 */
81 EVP_KEM_free(kem);
82 EVP_KEYMGMT_free(tmp_keymgmt);
83
84 switch (iter) {
85 case 1:
86 kem = EVP_KEM_fetch(ctx->libctx, supported_kem, ctx->propquery);
87 if (kem != NULL)
88 tmp_prov = EVP_KEM_get0_provider(kem);
89 break;
90 case 2:
91 tmp_prov = EVP_KEYMGMT_get0_provider(ctx->keymgmt);
92 kem = evp_kem_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
93 supported_kem, ctx->propquery);
94
95 if (kem == NULL) {
96 ERR_raise(ERR_LIB_EVP,
97 EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
98 ret = -2;
99 goto err;
100 }
101 }
102 if (kem == NULL)
103 continue;
104
105 /*
106 * Ensure that the key is provided, either natively, or as a cached
107 * export. We start by fetching the keymgmt with the same name as
108 * |ctx->pkey|, but from the provider of the kem method, using the
109 * same property query as when fetching the kem method.
110 * With the keymgmt we found (if we did), we try to export |ctx->pkey|
111 * to it (evp_pkey_export_to_provider() is smart enough to only actually
112
113 * export it if |tmp_keymgmt| is different from |ctx->pkey|'s keymgmt)
114 */
115 tmp_keymgmt_tofree = tmp_keymgmt =
116 evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
117 EVP_KEYMGMT_get0_name(ctx->keymgmt),
118 ctx->propquery);
119 if (tmp_keymgmt != NULL)
120 provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx,
121 &tmp_keymgmt, ctx->propquery);
122 if (tmp_keymgmt == NULL)
123 EVP_KEYMGMT_free(tmp_keymgmt_tofree);
124 }
125
5246183e 126 if (provkey == NULL) {
839ffdd1 127 EVP_KEM_free(kem);
5246183e
RL
128 ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
129 goto err;
130 }
131
80f4fd18 132 ctx->op.encap.kem = kem;
7c14d0c1
SL
133 ctx->op.encap.algctx = kem->newctx(ossl_provider_ctx(kem->prov));
134 if (ctx->op.encap.algctx == NULL) {
80f4fd18
SL
135 /* The provider key can stay in the cache */
136 ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
137 goto err;
138 }
139
140 switch (operation) {
141 case EVP_PKEY_OP_ENCAPSULATE:
142 if (kem->encapsulate_init == NULL) {
143 ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
144 ret = -2;
145 goto err;
146 }
7c14d0c1 147 ret = kem->encapsulate_init(ctx->op.encap.algctx, provkey, params);
80f4fd18
SL
148 break;
149 case EVP_PKEY_OP_DECAPSULATE:
150 if (kem->decapsulate_init == NULL) {
151 ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
152 ret = -2;
153 goto err;
154 }
7c14d0c1 155 ret = kem->decapsulate_init(ctx->op.encap.algctx, provkey, params);
80f4fd18
SL
156 break;
157 default:
158 ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
159 goto err;
160 }
161
5246183e
RL
162 EVP_KEYMGMT_free(tmp_keymgmt);
163 tmp_keymgmt = NULL;
164
80f4fd18
SL
165 if (ret > 0)
166 return 1;
167 err:
168 if (ret <= 0) {
169 evp_pkey_ctx_free_old_ops(ctx);
170 ctx->operation = EVP_PKEY_OP_UNDEFINED;
171 }
5246183e 172 EVP_KEYMGMT_free(tmp_keymgmt);
80f4fd18
SL
173 return ret;
174}
175
4b58d9b4 176int EVP_PKEY_encapsulate_init(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[])
80f4fd18 177{
4b58d9b4 178 return evp_kem_init(ctx, EVP_PKEY_OP_ENCAPSULATE, params);
80f4fd18
SL
179}
180
181int EVP_PKEY_encapsulate(EVP_PKEY_CTX *ctx,
182 unsigned char *out, size_t *outlen,
183 unsigned char *secret, size_t *secretlen)
184{
185 if (ctx == NULL)
186 return 0;
187
188 if (ctx->operation != EVP_PKEY_OP_ENCAPSULATE) {
bf23b9a1 189 ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
80f4fd18
SL
190 return -1;
191 }
192
7c14d0c1 193 if (ctx->op.encap.algctx == NULL) {
9311d0c4 194 ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
80f4fd18
SL
195 return -2;
196 }
197
198 if (out != NULL && secret == NULL)
199 return 0;
200
7c14d0c1 201 return ctx->op.encap.kem->encapsulate(ctx->op.encap.algctx,
80f4fd18
SL
202 out, outlen, secret, secretlen);
203}
204
4b58d9b4 205int EVP_PKEY_decapsulate_init(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[])
80f4fd18 206{
4b58d9b4 207 return evp_kem_init(ctx, EVP_PKEY_OP_DECAPSULATE, params);
80f4fd18
SL
208}
209
210int EVP_PKEY_decapsulate(EVP_PKEY_CTX *ctx,
211 unsigned char *secret, size_t *secretlen,
212 const unsigned char *in, size_t inlen)
213{
214 if (ctx == NULL
215 || (in == NULL || inlen == 0)
216 || (secret == NULL && secretlen == NULL))
217 return 0;
218
219 if (ctx->operation != EVP_PKEY_OP_DECAPSULATE) {
bf23b9a1 220 ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
80f4fd18
SL
221 return -1;
222 }
223
7c14d0c1 224 if (ctx->op.encap.algctx == NULL) {
9311d0c4 225 ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
80f4fd18
SL
226 return -2;
227 }
7c14d0c1 228 return ctx->op.encap.kem->decapsulate(ctx->op.encap.algctx,
80f4fd18
SL
229 secret, secretlen, in, inlen);
230}
231
232static EVP_KEM *evp_kem_new(OSSL_PROVIDER *prov)
233{
234 EVP_KEM *kem = OPENSSL_zalloc(sizeof(EVP_KEM));
235
236 if (kem == NULL) {
237 ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
238 return NULL;
239 }
240
241 kem->lock = CRYPTO_THREAD_lock_new();
242 if (kem->lock == NULL) {
243 ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
244 OPENSSL_free(kem);
245 return NULL;
246 }
247 kem->prov = prov;
248 ossl_provider_up_ref(prov);
249 kem->refcnt = 1;
250
251 return kem;
252}
253
309a78aa
RL
254static void *evp_kem_from_algorithm(int name_id, const OSSL_ALGORITHM *algodef,
255 OSSL_PROVIDER *prov)
80f4fd18 256{
309a78aa 257 const OSSL_DISPATCH *fns = algodef->implementation;
80f4fd18
SL
258 EVP_KEM *kem = NULL;
259 int ctxfncnt = 0, encfncnt = 0, decfncnt = 0;
260 int gparamfncnt = 0, sparamfncnt = 0;
261
262 if ((kem = evp_kem_new(prov)) == NULL) {
263 ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
264 goto err;
265 }
266
267 kem->name_id = name_id;
6c9bc258
TM
268 if ((kem->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
269 goto err;
309a78aa 270 kem->description = algodef->algorithm_description;
80f4fd18
SL
271
272 for (; fns->function_id != 0; fns++) {
273 switch (fns->function_id) {
274 case OSSL_FUNC_KEM_NEWCTX:
275 if (kem->newctx != NULL)
276 break;
277 kem->newctx = OSSL_FUNC_kem_newctx(fns);
278 ctxfncnt++;
279 break;
280 case OSSL_FUNC_KEM_ENCAPSULATE_INIT:
281 if (kem->encapsulate_init != NULL)
282 break;
283 kem->encapsulate_init = OSSL_FUNC_kem_encapsulate_init(fns);
284 encfncnt++;
285 break;
286 case OSSL_FUNC_KEM_ENCAPSULATE:
287 if (kem->encapsulate != NULL)
288 break;
289 kem->encapsulate = OSSL_FUNC_kem_encapsulate(fns);
290 encfncnt++;
291 break;
292 case OSSL_FUNC_KEM_DECAPSULATE_INIT:
293 if (kem->decapsulate_init != NULL)
294 break;
295 kem->decapsulate_init = OSSL_FUNC_kem_decapsulate_init(fns);
296 decfncnt++;
297 break;
298 case OSSL_FUNC_KEM_DECAPSULATE:
299 if (kem->decapsulate != NULL)
300 break;
301 kem->decapsulate = OSSL_FUNC_kem_decapsulate(fns);
302 decfncnt++;
303 break;
304 case OSSL_FUNC_KEM_FREECTX:
305 if (kem->freectx != NULL)
306 break;
307 kem->freectx = OSSL_FUNC_kem_freectx(fns);
308 ctxfncnt++;
309 break;
310 case OSSL_FUNC_KEM_DUPCTX:
311 if (kem->dupctx != NULL)
312 break;
313 kem->dupctx = OSSL_FUNC_kem_dupctx(fns);
314 break;
315 case OSSL_FUNC_KEM_GET_CTX_PARAMS:
316 if (kem->get_ctx_params != NULL)
317 break;
318 kem->get_ctx_params
319 = OSSL_FUNC_kem_get_ctx_params(fns);
320 gparamfncnt++;
321 break;
322 case OSSL_FUNC_KEM_GETTABLE_CTX_PARAMS:
323 if (kem->gettable_ctx_params != NULL)
324 break;
325 kem->gettable_ctx_params
326 = OSSL_FUNC_kem_gettable_ctx_params(fns);
327 gparamfncnt++;
328 break;
329 case OSSL_FUNC_KEM_SET_CTX_PARAMS:
330 if (kem->set_ctx_params != NULL)
331 break;
332 kem->set_ctx_params
333 = OSSL_FUNC_kem_set_ctx_params(fns);
334 sparamfncnt++;
335 break;
336 case OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS:
337 if (kem->settable_ctx_params != NULL)
338 break;
339 kem->settable_ctx_params
340 = OSSL_FUNC_kem_settable_ctx_params(fns);
341 sparamfncnt++;
342 break;
343 }
344 }
345 if (ctxfncnt != 2
346 || (encfncnt != 0 && encfncnt != 2)
347 || (decfncnt != 0 && decfncnt != 2)
348 || (encfncnt != 2 && decfncnt != 2)
349 || (gparamfncnt != 0 && gparamfncnt != 2)
350 || (sparamfncnt != 0 && sparamfncnt != 2)) {
351 /*
352 * In order to be a consistent set of functions we must have at least
353 * a set of context functions (newctx and freectx) as well as a pair of
354 * "kem" functions: (encapsulate_init, encapsulate) or
355 * (decapsulate_init, decapsulate). set_ctx_params and settable_ctx_params are
356 * optional, but if one of them is present then the other one must also
357 * be present. The same applies to get_ctx_params and
358 * gettable_ctx_params. The dupctx function is optional.
359 */
360 ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
361 goto err;
362 }
363
364 return kem;
365 err:
366 EVP_KEM_free(kem);
367 return NULL;
368}
369
370void EVP_KEM_free(EVP_KEM *kem)
371{
543e740b
RS
372 int i;
373
374 if (kem == NULL)
375 return;
376
377 CRYPTO_DOWN_REF(&kem->refcnt, &i, kem->lock);
378 if (i > 0)
379 return;
6c9bc258 380 OPENSSL_free(kem->type_name);
543e740b
RS
381 ossl_provider_free(kem->prov);
382 CRYPTO_THREAD_lock_free(kem->lock);
383 OPENSSL_free(kem);
80f4fd18
SL
384}
385
386int EVP_KEM_up_ref(EVP_KEM *kem)
387{
388 int ref = 0;
389
390 CRYPTO_UP_REF(&kem->refcnt, &ref, kem->lock);
391 return 1;
392}
393
ed576acd 394OSSL_PROVIDER *EVP_KEM_get0_provider(const EVP_KEM *kem)
80f4fd18
SL
395{
396 return kem->prov;
397}
398
b4250010 399EVP_KEM *EVP_KEM_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
80f4fd18
SL
400 const char *properties)
401{
402 return evp_generic_fetch(ctx, OSSL_OP_KEM, algorithm, properties,
309a78aa 403 evp_kem_from_algorithm,
80f4fd18
SL
404 (int (*)(void *))EVP_KEM_up_ref,
405 (void (*)(void *))EVP_KEM_free);
406}
407
ff778146
RL
408EVP_KEM *evp_kem_fetch_from_prov(OSSL_PROVIDER *prov, const char *algorithm,
409 const char *properties)
410{
411 return evp_generic_fetch_from_prov(prov, OSSL_OP_KEM, algorithm, properties,
412 evp_kem_from_algorithm,
413 (int (*)(void *))EVP_KEM_up_ref,
414 (void (*)(void *))EVP_KEM_free);
415}
416
80f4fd18
SL
417int EVP_KEM_is_a(const EVP_KEM *kem, const char *name)
418{
419 return evp_is_a(kem->prov, kem->name_id, NULL, name);
420}
421
bcd5d3a2 422int evp_kem_get_number(const EVP_KEM *kem)
80f4fd18
SL
423{
424 return kem->name_id;
425}
426
ed576acd 427const char *EVP_KEM_get0_name(const EVP_KEM *kem)
6c9bc258
TM
428{
429 return kem->type_name;
430}
431
ed576acd 432const char *EVP_KEM_get0_description(const EVP_KEM *kem)
03888233
RL
433{
434 return kem->description;
435}
436
b4250010 437void EVP_KEM_do_all_provided(OSSL_LIB_CTX *libctx,
80f4fd18
SL
438 void (*fn)(EVP_KEM *kem, void *arg),
439 void *arg)
440{
441 evp_generic_do_all(libctx, OSSL_OP_KEM, (void (*)(void *, void *))fn, arg,
309a78aa 442 evp_kem_from_algorithm,
cd770738 443 (int (*)(void *))EVP_KEM_up_ref,
80f4fd18
SL
444 (void (*)(void *))EVP_KEM_free);
445}
446
d84f5515
MC
447int EVP_KEM_names_do_all(const EVP_KEM *kem,
448 void (*fn)(const char *name, void *data),
449 void *data)
80f4fd18
SL
450{
451 if (kem->prov != NULL)
d84f5515
MC
452 return evp_names_do_all(kem->prov, kem->name_id, fn, data);
453
454 return 1;
80f4fd18 455}
5a950048
SL
456
457const OSSL_PARAM *EVP_KEM_gettable_ctx_params(const EVP_KEM *kem)
458{
459 void *provctx;
460
461 if (kem == NULL || kem->gettable_ctx_params == NULL)
462 return NULL;
463
ed576acd 464 provctx = ossl_provider_ctx(EVP_KEM_get0_provider(kem));
fb67126e 465 return kem->gettable_ctx_params(NULL, provctx);
5a950048
SL
466}
467
468const OSSL_PARAM *EVP_KEM_settable_ctx_params(const EVP_KEM *kem)
469{
470 void *provctx;
471
472 if (kem == NULL || kem->settable_ctx_params == NULL)
473 return NULL;
474
ed576acd 475 provctx = ossl_provider_ctx(EVP_KEM_get0_provider(kem));
fb67126e 476 return kem->settable_ctx_params(NULL, provctx);
5a950048 477}