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