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