xref: /freebsd/crypto/openssl/crypto/evp/kem.c (revision e7be843b4a162e68651d3911f0357ed464915629)
1 /*
2  * Copyright 2020-2025 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 =
133             evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
134                                         EVP_KEYMGMT_get0_name(ctx->keymgmt),
135                                         ctx->propquery);
136         if (tmp_keymgmt != NULL) {
137             provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx,
138                                                   &tmp_keymgmt, ctx->propquery);
139             if (provkey != NULL && authkey != NULL) {
140                 provauthkey = evp_pkey_export_to_provider(authkey, ctx->libctx,
141                                                           &tmp_keymgmt,
142                                                           ctx->propquery);
143                 if (provauthkey == NULL) {
144                     EVP_KEM_free(kem);
145                     ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
146                     goto err;
147                 }
148             }
149         }
150         if (tmp_keymgmt == NULL)
151             EVP_KEYMGMT_free(tmp_keymgmt_tofree);
152     }
153 
154     if (provkey == NULL) {
155         EVP_KEM_free(kem);
156         ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
157         goto err;
158     }
159 
160     ctx->op.encap.kem = kem;
161     ctx->op.encap.algctx = kem->newctx(ossl_provider_ctx(kem->prov));
162     if (ctx->op.encap.algctx == NULL) {
163         /* The provider key can stay in the cache */
164         ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
165         goto err;
166     }
167 
168     switch (operation) {
169     case EVP_PKEY_OP_ENCAPSULATE:
170         if (provauthkey != NULL && kem->auth_encapsulate_init != NULL) {
171             ret = kem->auth_encapsulate_init(ctx->op.encap.algctx, provkey,
172                                              provauthkey, params);
173         } else if (provauthkey == NULL && kem->encapsulate_init != NULL) {
174             ret = kem->encapsulate_init(ctx->op.encap.algctx, provkey, params);
175         } else {
176             ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
177             ret = -2;
178             goto err;
179         }
180         break;
181     case EVP_PKEY_OP_DECAPSULATE:
182         if (provauthkey != NULL && kem->auth_decapsulate_init != NULL) {
183             ret = kem->auth_decapsulate_init(ctx->op.encap.algctx, provkey,
184                                              provauthkey, params);
185         } else if (provauthkey == NULL && kem->encapsulate_init != NULL) {
186             ret = kem->decapsulate_init(ctx->op.encap.algctx, provkey, params);
187         } else {
188             ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
189             ret = -2;
190             goto err;
191         }
192         break;
193     default:
194         ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
195         goto err;
196     }
197 
198     EVP_KEYMGMT_free(tmp_keymgmt);
199     tmp_keymgmt = NULL;
200 
201     if (ret > 0)
202         return 1;
203  err:
204     if (ret <= 0) {
205         evp_pkey_ctx_free_old_ops(ctx);
206         ctx->operation = EVP_PKEY_OP_UNDEFINED;
207     }
208     EVP_KEYMGMT_free(tmp_keymgmt);
209     return ret;
210 }
211 
EVP_PKEY_auth_encapsulate_init(EVP_PKEY_CTX * ctx,EVP_PKEY * authpriv,const OSSL_PARAM params[])212 int EVP_PKEY_auth_encapsulate_init(EVP_PKEY_CTX *ctx, EVP_PKEY *authpriv,
213                                    const OSSL_PARAM params[])
214 {
215     if (authpriv == NULL)
216         return 0;
217     return evp_kem_init(ctx, EVP_PKEY_OP_ENCAPSULATE, params, authpriv);
218 }
219 
EVP_PKEY_encapsulate_init(EVP_PKEY_CTX * ctx,const OSSL_PARAM params[])220 int EVP_PKEY_encapsulate_init(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[])
221 {
222     return evp_kem_init(ctx, EVP_PKEY_OP_ENCAPSULATE, params, NULL);
223 }
224 
EVP_PKEY_encapsulate(EVP_PKEY_CTX * ctx,unsigned char * out,size_t * outlen,unsigned char * secret,size_t * secretlen)225 int EVP_PKEY_encapsulate(EVP_PKEY_CTX *ctx,
226                          unsigned char *out, size_t *outlen,
227                          unsigned char *secret, size_t *secretlen)
228 {
229     if (ctx == NULL)
230         return 0;
231 
232     if (ctx->operation != EVP_PKEY_OP_ENCAPSULATE) {
233         ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
234         return -1;
235     }
236 
237     if (ctx->op.encap.algctx == NULL) {
238         ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
239         return -2;
240     }
241 
242     if (out != NULL && secret == NULL)
243         return 0;
244 
245     return ctx->op.encap.kem->encapsulate(ctx->op.encap.algctx,
246                                           out, outlen, secret, secretlen);
247 }
248 
EVP_PKEY_decapsulate_init(EVP_PKEY_CTX * ctx,const OSSL_PARAM params[])249 int EVP_PKEY_decapsulate_init(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[])
250 {
251     return evp_kem_init(ctx, EVP_PKEY_OP_DECAPSULATE, params, NULL);
252 }
253 
EVP_PKEY_auth_decapsulate_init(EVP_PKEY_CTX * ctx,EVP_PKEY * authpub,const OSSL_PARAM params[])254 int EVP_PKEY_auth_decapsulate_init(EVP_PKEY_CTX *ctx, EVP_PKEY *authpub,
255                                    const OSSL_PARAM params[])
256 {
257     if (authpub == NULL)
258         return 0;
259     return evp_kem_init(ctx, EVP_PKEY_OP_DECAPSULATE, params, authpub);
260 }
261 
EVP_PKEY_decapsulate(EVP_PKEY_CTX * ctx,unsigned char * secret,size_t * secretlen,const unsigned char * in,size_t inlen)262 int EVP_PKEY_decapsulate(EVP_PKEY_CTX *ctx,
263                          unsigned char *secret, size_t *secretlen,
264                          const unsigned char *in, size_t inlen)
265 {
266     if (ctx == NULL
267         || (in == NULL || inlen == 0)
268         || (secret == NULL && secretlen == NULL))
269         return 0;
270 
271     if (ctx->operation != EVP_PKEY_OP_DECAPSULATE) {
272         ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
273         return -1;
274     }
275 
276     if (ctx->op.encap.algctx == NULL) {
277         ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
278         return -2;
279     }
280     return ctx->op.encap.kem->decapsulate(ctx->op.encap.algctx,
281                                           secret, secretlen, in, inlen);
282 }
283 
evp_kem_new(OSSL_PROVIDER * prov)284 static EVP_KEM *evp_kem_new(OSSL_PROVIDER *prov)
285 {
286     EVP_KEM *kem = OPENSSL_zalloc(sizeof(EVP_KEM));
287 
288     if (kem == NULL)
289         return NULL;
290 
291     if (!CRYPTO_NEW_REF(&kem->refcnt, 1)
292         || !ossl_provider_up_ref(prov)) {
293         CRYPTO_FREE_REF(&kem->refcnt);
294         OPENSSL_free(kem);
295         return NULL;
296     }
297     kem->prov = prov;
298 
299     return kem;
300 }
301 
evp_kem_from_algorithm(int name_id,const OSSL_ALGORITHM * algodef,OSSL_PROVIDER * prov)302 static void *evp_kem_from_algorithm(int name_id, const OSSL_ALGORITHM *algodef,
303                                     OSSL_PROVIDER *prov)
304 {
305     const OSSL_DISPATCH *fns = algodef->implementation;
306     EVP_KEM *kem = NULL;
307     int ctxfncnt = 0, encfncnt = 0, decfncnt = 0;
308     int gparamfncnt = 0, sparamfncnt = 0;
309 
310     if ((kem = evp_kem_new(prov)) == NULL) {
311         ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
312         goto err;
313     }
314 
315     kem->name_id = name_id;
316     if ((kem->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
317         goto err;
318     kem->description = algodef->algorithm_description;
319 
320     for (; fns->function_id != 0; fns++) {
321         switch (fns->function_id) {
322         case OSSL_FUNC_KEM_NEWCTX:
323             if (kem->newctx != NULL)
324                 break;
325             kem->newctx = OSSL_FUNC_kem_newctx(fns);
326             ctxfncnt++;
327             break;
328         case OSSL_FUNC_KEM_ENCAPSULATE_INIT:
329             if (kem->encapsulate_init != NULL)
330                 break;
331             kem->encapsulate_init = OSSL_FUNC_kem_encapsulate_init(fns);
332             encfncnt++;
333             break;
334         case OSSL_FUNC_KEM_AUTH_ENCAPSULATE_INIT:
335             if (kem->auth_encapsulate_init != NULL)
336                 break;
337             kem->auth_encapsulate_init = OSSL_FUNC_kem_auth_encapsulate_init(fns);
338             encfncnt++;
339             break;
340         case OSSL_FUNC_KEM_ENCAPSULATE:
341             if (kem->encapsulate != NULL)
342                 break;
343             kem->encapsulate = OSSL_FUNC_kem_encapsulate(fns);
344             encfncnt++;
345             break;
346         case OSSL_FUNC_KEM_DECAPSULATE_INIT:
347             if (kem->decapsulate_init != NULL)
348                 break;
349             kem->decapsulate_init = OSSL_FUNC_kem_decapsulate_init(fns);
350             decfncnt++;
351             break;
352         case OSSL_FUNC_KEM_AUTH_DECAPSULATE_INIT:
353             if (kem->auth_decapsulate_init != NULL)
354                 break;
355             kem->auth_decapsulate_init = OSSL_FUNC_kem_auth_decapsulate_init(fns);
356             decfncnt++;
357             break;
358         case OSSL_FUNC_KEM_DECAPSULATE:
359             if (kem->decapsulate != NULL)
360                 break;
361             kem->decapsulate = OSSL_FUNC_kem_decapsulate(fns);
362             decfncnt++;
363             break;
364         case OSSL_FUNC_KEM_FREECTX:
365             if (kem->freectx != NULL)
366                 break;
367             kem->freectx = OSSL_FUNC_kem_freectx(fns);
368             ctxfncnt++;
369             break;
370         case OSSL_FUNC_KEM_DUPCTX:
371             if (kem->dupctx != NULL)
372                 break;
373             kem->dupctx = OSSL_FUNC_kem_dupctx(fns);
374             break;
375         case OSSL_FUNC_KEM_GET_CTX_PARAMS:
376             if (kem->get_ctx_params != NULL)
377                 break;
378             kem->get_ctx_params
379                 = OSSL_FUNC_kem_get_ctx_params(fns);
380             gparamfncnt++;
381             break;
382         case OSSL_FUNC_KEM_GETTABLE_CTX_PARAMS:
383             if (kem->gettable_ctx_params != NULL)
384                 break;
385             kem->gettable_ctx_params
386                 = OSSL_FUNC_kem_gettable_ctx_params(fns);
387             gparamfncnt++;
388             break;
389         case OSSL_FUNC_KEM_SET_CTX_PARAMS:
390             if (kem->set_ctx_params != NULL)
391                 break;
392             kem->set_ctx_params
393                 = OSSL_FUNC_kem_set_ctx_params(fns);
394             sparamfncnt++;
395             break;
396         case OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS:
397             if (kem->settable_ctx_params != NULL)
398                 break;
399             kem->settable_ctx_params
400                 = OSSL_FUNC_kem_settable_ctx_params(fns);
401             sparamfncnt++;
402             break;
403         }
404     }
405     if (ctxfncnt != 2
406         || (encfncnt != 0 && encfncnt != 2 && encfncnt != 3)
407         || (decfncnt != 0 && decfncnt != 2 && decfncnt != 3)
408         || (encfncnt != decfncnt)
409         || (gparamfncnt != 0 && gparamfncnt != 2)
410         || (sparamfncnt != 0 && sparamfncnt != 2)) {
411         /*
412          * In order to be a consistent set of functions we must have at least
413          * a set of context functions (newctx and freectx) as well as a pair
414          * (or triplet) of "kem" functions:
415          * (encapsulate_init, (and/or auth_encapsulate_init), encapsulate) or
416          * (decapsulate_init, (and/or auth_decapsulate_init), decapsulate).
417          * set_ctx_params and settable_ctx_params are optional, but if one of
418          * them is present then the other one must also be present. The same
419          * applies to get_ctx_params and gettable_ctx_params.
420          * The dupctx function is optional.
421          */
422         ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
423         goto err;
424     }
425 
426     return kem;
427  err:
428     EVP_KEM_free(kem);
429     return NULL;
430 }
431 
EVP_KEM_free(EVP_KEM * kem)432 void EVP_KEM_free(EVP_KEM *kem)
433 {
434     int i;
435 
436     if (kem == NULL)
437         return;
438 
439     CRYPTO_DOWN_REF(&kem->refcnt, &i);
440     if (i > 0)
441         return;
442     OPENSSL_free(kem->type_name);
443     ossl_provider_free(kem->prov);
444     CRYPTO_FREE_REF(&kem->refcnt);
445     OPENSSL_free(kem);
446 }
447 
EVP_KEM_up_ref(EVP_KEM * kem)448 int EVP_KEM_up_ref(EVP_KEM *kem)
449 {
450     int ref = 0;
451 
452     CRYPTO_UP_REF(&kem->refcnt, &ref);
453     return 1;
454 }
455 
EVP_KEM_get0_provider(const EVP_KEM * kem)456 OSSL_PROVIDER *EVP_KEM_get0_provider(const EVP_KEM *kem)
457 {
458     return kem->prov;
459 }
460 
EVP_KEM_fetch(OSSL_LIB_CTX * ctx,const char * algorithm,const char * properties)461 EVP_KEM *EVP_KEM_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
462                        const char *properties)
463 {
464     return evp_generic_fetch(ctx, OSSL_OP_KEM, algorithm, properties,
465                              evp_kem_from_algorithm,
466                              evp_kem_up_ref,
467                              evp_kem_free);
468 }
469 
evp_kem_fetch_from_prov(OSSL_PROVIDER * prov,const char * algorithm,const char * properties)470 EVP_KEM *evp_kem_fetch_from_prov(OSSL_PROVIDER *prov, const char *algorithm,
471                                  const char *properties)
472 {
473     return evp_generic_fetch_from_prov(prov, OSSL_OP_KEM, algorithm, properties,
474                                        evp_kem_from_algorithm,
475                                        evp_kem_up_ref,
476                                        evp_kem_free);
477 }
478 
EVP_KEM_is_a(const EVP_KEM * kem,const char * name)479 int EVP_KEM_is_a(const EVP_KEM *kem, const char *name)
480 {
481     return kem != NULL && evp_is_a(kem->prov, kem->name_id, NULL, name);
482 }
483 
evp_kem_get_number(const EVP_KEM * kem)484 int evp_kem_get_number(const EVP_KEM *kem)
485 {
486     return kem->name_id;
487 }
488 
EVP_KEM_get0_name(const EVP_KEM * kem)489 const char *EVP_KEM_get0_name(const EVP_KEM *kem)
490 {
491     return kem->type_name;
492 }
493 
EVP_KEM_get0_description(const EVP_KEM * kem)494 const char *EVP_KEM_get0_description(const EVP_KEM *kem)
495 {
496     return kem->description;
497 }
498 
EVP_KEM_do_all_provided(OSSL_LIB_CTX * libctx,void (* fn)(EVP_KEM * kem,void * arg),void * arg)499 void EVP_KEM_do_all_provided(OSSL_LIB_CTX *libctx,
500                              void (*fn)(EVP_KEM *kem, void *arg),
501                              void *arg)
502 {
503     evp_generic_do_all(libctx, OSSL_OP_KEM, (void (*)(void *, void *))fn, arg,
504                        evp_kem_from_algorithm,
505                        evp_kem_up_ref,
506                        evp_kem_free);
507 }
508 
EVP_KEM_names_do_all(const EVP_KEM * kem,void (* fn)(const char * name,void * data),void * data)509 int EVP_KEM_names_do_all(const EVP_KEM *kem,
510                          void (*fn)(const char *name, void *data),
511                          void *data)
512 {
513     if (kem->prov != NULL)
514         return evp_names_do_all(kem->prov, kem->name_id, fn, data);
515 
516     return 1;
517 }
518 
EVP_KEM_gettable_ctx_params(const EVP_KEM * kem)519 const OSSL_PARAM *EVP_KEM_gettable_ctx_params(const EVP_KEM *kem)
520 {
521     void *provctx;
522 
523     if (kem == NULL || kem->gettable_ctx_params == NULL)
524         return NULL;
525 
526     provctx = ossl_provider_ctx(EVP_KEM_get0_provider(kem));
527     return kem->gettable_ctx_params(NULL, provctx);
528 }
529 
EVP_KEM_settable_ctx_params(const EVP_KEM * kem)530 const OSSL_PARAM *EVP_KEM_settable_ctx_params(const EVP_KEM *kem)
531 {
532     void *provctx;
533 
534     if (kem == NULL || kem->settable_ctx_params == NULL)
535         return NULL;
536 
537     provctx = ossl_provider_ctx(EVP_KEM_get0_provider(kem));
538     return kem->settable_ctx_params(NULL, provctx);
539 }
540