xref: /freebsd/crypto/openssl/crypto/evp/kem.c (revision 10a428653ee7216475f1ddce3fb4cbf1200319f8)
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