summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crypto/evp/build.info2
-rw-r--r--crypto/evp/evp_local.h19
-rw-r--r--crypto/evp/kem.c359
-rw-r--r--crypto/evp/pmeth_lib.c76
-rw-r--r--doc/man3/EVP_KEM_free.pod82
-rw-r--r--doc/man3/EVP_PKEY_CTX_ctrl.pod13
-rw-r--r--doc/man3/EVP_PKEY_decapsulate.pod99
-rw-r--r--doc/man3/EVP_PKEY_encapsulate.pod101
-rw-r--r--doc/man7/EVP_KEM-RSA.pod66
-rw-r--r--doc/man7/OSSL_PROVIDER-FIPS.pod8
-rw-r--r--doc/man7/OSSL_PROVIDER-default.pod8
-rw-r--r--doc/man7/provider-kem.pod207
-rw-r--r--doc/man7/provider.pod6
-rw-r--r--include/crypto/evp.h8
-rw-r--r--include/openssl/core_dispatch.h32
-rw-r--r--include/openssl/core_names.h8
-rw-r--r--include/openssl/evp.h25
-rw-r--r--include/openssl/types.h2
-rw-r--r--providers/defltprov.c7
-rw-r--r--providers/fips/fipsprov.c7
-rw-r--r--providers/implementations/build.info2
-rw-r--r--providers/implementations/include/prov/implementations.h3
-rw-r--r--providers/implementations/kem/build.info6
-rw-r--r--providers/implementations/kem/rsa_kem.c341
-rw-r--r--providers/implementations/keymgmt/rsa_kmgmt.c6
-rw-r--r--test/evp_libctx_test.c181
-rw-r--r--util/libcrypto.num13
27 files changed, 1677 insertions, 10 deletions
diff --git a/crypto/evp/build.info b/crypto/evp/build.info
index 36fac11683..7f1459a15c 100644
--- a/crypto/evp/build.info
+++ b/crypto/evp/build.info
@@ -2,7 +2,7 @@ LIBS=../../libcrypto
$COMMON=digest.c evp_enc.c evp_lib.c evp_fetch.c cmeth_lib.c evp_utils.c \
mac_lib.c mac_meth.c keymgmt_meth.c keymgmt_lib.c kdf_lib.c kdf_meth.c \
m_sigver.c pmeth_lib.c signature.c p_lib.c pmeth_gn.c exchange.c \
- pmeth_check.c evp_rand.c asymcipher.c
+ pmeth_check.c evp_rand.c asymcipher.c kem.c
SOURCE[../../libcrypto]=$COMMON\
encode.c evp_key.c evp_cnf.c \
diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h
index e7f7643d83..3268aa4109 100644
--- a/crypto/evp/evp_local.h
+++ b/crypto/evp/evp_local.h
@@ -181,6 +181,25 @@ struct evp_asym_cipher_st {
OSSL_FUNC_asym_cipher_settable_ctx_params_fn *settable_ctx_params;
} /* EVP_ASYM_CIPHER */;
+struct evp_kem_st {
+ int name_id;
+ OSSL_PROVIDER *prov;
+ CRYPTO_REF_COUNT refcnt;
+ CRYPTO_RWLOCK *lock;
+
+ OSSL_FUNC_kem_newctx_fn *newctx;
+ OSSL_FUNC_kem_encapsulate_init_fn *encapsulate_init;
+ OSSL_FUNC_kem_encapsulate_fn *encapsulate;
+ OSSL_FUNC_kem_decapsulate_init_fn *decapsulate_init;
+ OSSL_FUNC_kem_decapsulate_fn *decapsulate;
+ OSSL_FUNC_kem_freectx_fn *freectx;
+ OSSL_FUNC_kem_dupctx_fn *dupctx;
+ OSSL_FUNC_kem_get_ctx_params_fn *get_ctx_params;
+ OSSL_FUNC_kem_gettable_ctx_params_fn *gettable_ctx_params;
+ OSSL_FUNC_kem_set_ctx_params_fn *set_ctx_params;
+ OSSL_FUNC_kem_settable_ctx_params_fn *settable_ctx_params;
+} /* EVP_KEM */;
+
int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass,
int passlen, ASN1_TYPE *param,
const EVP_CIPHER *c, const EVP_MD *md,
diff --git a/crypto/evp/kem.c b/crypto/evp/kem.c
new file mode 100644
index 0000000000..6f0424075a
--- /dev/null
+++ b/crypto/evp/kem.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include "internal/cryptlib.h"
+#include "crypto/evp.h"
+#include "internal/provider.h"
+#include "evp_local.h"
+
+static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation)
+{
+ int ret = 0;
+ EVP_KEM *kem = NULL;
+ EVP_KEYMGMT *tmp_keymgmt = NULL;
+ void *provkey = NULL;
+ const char *supported_kem = NULL;
+
+ if (ctx == NULL || ctx->keytype == NULL) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+ return 0;
+ }
+
+ evp_pkey_ctx_free_old_ops(ctx);
+ ctx->operation = operation;
+
+ /*
+ * Ensure that the key is provided, either natively, or as a cached export.
+ */
+ tmp_keymgmt = ctx->keymgmt;
+ provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx,
+ &tmp_keymgmt, ctx->propquery);
+ if (provkey == NULL
+ || !EVP_KEYMGMT_up_ref(tmp_keymgmt)) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+ goto err;
+ }
+ EVP_KEYMGMT_free(ctx->keymgmt);
+ ctx->keymgmt = tmp_keymgmt;
+
+ if (ctx->keymgmt->query_operation_name != NULL)
+ supported_kem = ctx->keymgmt->query_operation_name(OSSL_OP_KEM);
+
+ /*
+ * If we didn't get a supported kem, assume there is one with the
+ * same name as the key type.
+ */
+ if (supported_kem == NULL)
+ supported_kem = ctx->keytype;
+
+ kem = EVP_KEM_fetch(ctx->libctx, supported_kem, ctx->propquery);
+ if (kem == NULL
+ || (EVP_KEYMGMT_provider(ctx->keymgmt) != EVP_KEM_provider(kem))) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ ret = -2;
+ goto err;
+ }
+
+ ctx->op.encap.kem = kem;
+ ctx->op.encap.kemprovctx = kem->newctx(ossl_provider_ctx(kem->prov));
+ if (ctx->op.encap.kemprovctx == NULL) {
+ /* The provider key can stay in the cache */
+ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+ goto err;
+ }
+
+ switch (operation) {
+ case EVP_PKEY_OP_ENCAPSULATE:
+ if (kem->encapsulate_init == NULL) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ ret = -2;
+ goto err;
+ }
+ ret = kem->encapsulate_init(ctx->op.encap.kemprovctx, provkey);
+ break;
+ case EVP_PKEY_OP_DECAPSULATE:
+ if (kem->decapsulate_init == NULL) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ ret = -2;
+ goto err;
+ }
+ ret = kem->decapsulate_init(ctx->op.encap.kemprovctx, provkey);
+ break;
+ default:
+ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+ goto err;
+ }
+
+ if (ret > 0)
+ return 1;
+ err:
+ if (ret <= 0) {
+ evp_pkey_ctx_free_old_ops(ctx);
+ ctx->operation = EVP_PKEY_OP_UNDEFINED;
+ }
+ return ret;
+}
+
+int EVP_PKEY_encapsulate_init(EVP_PKEY_CTX *ctx)
+{
+ return evp_kem_init(ctx, EVP_PKEY_OP_ENCAPSULATE);
+}
+
+int EVP_PKEY_encapsulate(EVP_PKEY_CTX *ctx,
+ unsigned char *out, size_t *outlen,
+ unsigned char *secret, size_t *secretlen)
+{
+ if (ctx == NULL)
+ return 0;
+
+ if (ctx->operation != EVP_PKEY_OP_ENCAPSULATE) {
+ EVPerr(0, EVP_R_OPERATON_NOT_INITIALIZED);
+ return -1;
+ }
+
+ if (ctx->op.encap.kemprovctx == NULL) {
+ EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return -2;
+ }
+
+ if (out != NULL && secret == NULL)
+ return 0;
+
+ return ctx->op.encap.kem->encapsulate(ctx->op.encap.kemprovctx,
+ out, outlen, secret, secretlen);
+}
+
+int EVP_PKEY_decapsulate_init(EVP_PKEY_CTX *ctx)
+{
+ return evp_kem_init(ctx, EVP_PKEY_OP_DECAPSULATE);
+}
+
+int EVP_PKEY_decapsulate(EVP_PKEY_CTX *ctx,
+ unsigned char *secret, size_t *secretlen,
+ const unsigned char *in, size_t inlen)
+{
+ if (ctx == NULL
+ || (in == NULL || inlen == 0)
+ || (secret == NULL && secretlen == NULL))
+ return 0;
+
+ if (ctx->operation != EVP_PKEY_OP_DECAPSULATE) {
+ EVPerr(0, EVP_R_OPERATON_NOT_INITIALIZED);
+ return -1;
+ }
+
+ if (ctx->op.encap.kemprovctx == NULL) {
+ EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return -2;
+ }
+ return ctx->op.encap.kem->decapsulate(ctx->op.encap.kemprovctx,
+ secret, secretlen, in, inlen);
+}
+
+static EVP_KEM *evp_kem_new(OSSL_PROVIDER *prov)
+{
+ EVP_KEM *kem = OPENSSL_zalloc(sizeof(EVP_KEM));
+
+ if (kem == NULL) {
+ ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ kem->lock = CRYPTO_THREAD_lock_new();
+ if (kem->lock == NULL) {
+ ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
+ OPENSSL_free(kem);
+ return NULL;
+ }
+ kem->prov = prov;
+ ossl_provider_up_ref(prov);
+ kem->refcnt = 1;
+
+ return kem;
+}
+
+static void *evp_kem_from_dispatch(int name_id, const OSSL_DISPATCH *fns,
+ OSSL_PROVIDER *prov)
+{
+ EVP_KEM *kem = NULL;
+ int ctxfncnt = 0, encfncnt = 0, decfncnt = 0;
+ int gparamfncnt = 0, sparamfncnt = 0;
+
+ if ((kem = evp_kem_new(prov)) == NULL) {
+ ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ kem->name_id = name_id;
+
+ for (; fns->function_id != 0; fns++) {
+ switch (fns->function_id) {
+ case OSSL_FUNC_KEM_NEWCTX:
+ if (kem->newctx != NULL)
+ break;
+ kem->newctx = OSSL_FUNC_kem_newctx(fns);
+ ctxfncnt++;
+ break;
+ case OSSL_FUNC_KEM_ENCAPSULATE_INIT:
+ if (kem->encapsulate_init != NULL)
+ break;
+ kem->encapsulate_init = OSSL_FUNC_kem_encapsulate_init(fns);
+ encfncnt++;
+ break;
+ case OSSL_FUNC_KEM_ENCAPSULATE:
+ if (kem->encapsulate != NULL)
+ break;
+ kem->encapsulate = OSSL_FUNC_kem_encapsulate(fns);
+ encfncnt++;
+ break;
+ case OSSL_FUNC_KEM_DECAPSULATE_INIT:
+ if (kem->decapsulate_init != NULL)
+ break;
+ kem->decapsulate_init = OSSL_FUNC_kem_decapsulate_init(fns);
+ decfncnt++;
+ break;
+ case OSSL_FUNC_KEM_DECAPSULATE:
+ if (kem->decapsulate != NULL)
+ break;
+ kem->decapsulate = OSSL_FUNC_kem_decapsulate(fns);
+ decfncnt++;
+ break;
+ case OSSL_FUNC_KEM_FREECTX:
+ if (kem->freectx != NULL)
+ break;
+ kem->freectx = OSSL_FUNC_kem_freectx(fns);
+ ctxfncnt++;
+ break;
+ case OSSL_FUNC_KEM_DUPCTX:
+ if (kem->dupctx != NULL)
+ break;
+ kem->dupctx = OSSL_FUNC_kem_dupctx(fns);
+ break;
+ case OSSL_FUNC_KEM_GET_CTX_PARAMS:
+ if (kem->get_ctx_params != NULL)
+ break;
+ kem->get_ctx_params
+ = OSSL_FUNC_kem_get_ctx_params(fns);
+ gparamfncnt++;
+ break;
+ case OSSL_FUNC_KEM_GETTABLE_CTX_PARAMS:
+ if (kem->gettable_ctx_params != NULL)
+ break;
+ kem->gettable_ctx_params
+ = OSSL_FUNC_kem_gettable_ctx_params(fns);
+ gparamfncnt++;
+ break;
+ case OSSL_FUNC_KEM_SET_CTX_PARAMS:
+ if (kem->set_ctx_params != NULL)
+ break;
+ kem->set_ctx_params
+ = OSSL_FUNC_kem_set_ctx_params(fns);
+ sparamfncnt++;
+ break;
+ case OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS:
+ if (kem->settable_ctx_params != NULL)
+ break;
+ kem->settable_ctx_params
+ = OSSL_FUNC_kem_settable_ctx_params(fns);
+ sparamfncnt++;
+ break;
+ }
+ }
+ if (ctxfncnt != 2
+ || (encfncnt != 0 && encfncnt != 2)
+ || (decfncnt != 0 && decfncnt != 2)
+ || (encfncnt != 2 && decfncnt != 2)
+ || (gparamfncnt != 0 && gparamfncnt != 2)
+ || (sparamfncnt != 0 && sparamfncnt != 2)) {
+ /*
+ * In order to be a consistent set of functions we must have at least
+ * a set of context functions (newctx and freectx) as well as a pair of
+ * "kem" functions: (encapsulate_init, encapsulate) or
+ * (decapsulate_init, decapsulate). set_ctx_params and settable_ctx_params are
+ * optional, but if one of them is present then the other one must also
+ * be present. The same applies to get_ctx_params and
+ * gettable_ctx_params. The dupctx function is optional.
+ */
+ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
+ goto err;
+ }
+
+ return kem;
+ err:
+ EVP_KEM_free(kem);
+ return NULL;
+}
+
+void EVP_KEM_free(EVP_KEM *kem)
+{
+ if (kem != NULL) {
+ int i;
+
+ CRYPTO_DOWN_REF(&kem->refcnt, &i, kem->lock);
+ if (i > 0)
+ return;
+ ossl_provider_free(kem->prov);
+ CRYPTO_THREAD_lock_free(kem->lock);
+ OPENSSL_free(kem);
+ }
+}
+
+int EVP_KEM_up_ref(EVP_KEM *kem)
+{
+ int ref = 0;
+
+ CRYPTO_UP_REF(&kem->refcnt, &ref, kem->lock);
+ return 1;
+}
+
+OSSL_PROVIDER *EVP_KEM_provider(const EVP_KEM *kem)
+{
+ return kem->prov;
+}
+
+EVP_KEM *EVP_KEM_fetch(OPENSSL_CTX *ctx, const char *algorithm,
+ const char *properties)
+{
+ return evp_generic_fetch(ctx, OSSL_OP_KEM, algorithm, properties,
+ evp_kem_from_dispatch,
+ (int (*)(void *))EVP_KEM_up_ref,
+ (void (*)(void *))EVP_KEM_free);
+}
+
+int EVP_KEM_is_a(const EVP_KEM *kem, const char *name)
+{
+ return evp_is_a(kem->prov, kem->name_id, NULL, name);
+}
+
+int EVP_KEM_number(const EVP_KEM *kem)
+{
+ return kem->name_id;
+}
+
+void EVP_KEM_do_all_provided(OPENSSL_CTX *libctx,
+ void (*fn)(EVP_KEM *kem, void *arg),
+ void *arg)
+{
+ evp_generic_do_all(libctx, OSSL_OP_KEM, (void (*)(void *, void *))fn, arg,
+ evp_kem_from_dispatch,
+ (void (*)(void *))EVP_KEM_free);
+}
+
+
+void EVP_KEM_names_do_all(const EVP_KEM *kem,
+ void (*fn)(const char *name, void *data),
+ void *data)
+{
+ if (kem->prov != NULL)
+ evp_names_do_all(kem->prov, kem->name_id, fn, data);
+}
diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c
index 38f42eca7d..fcd7266975 100644
--- a/crypto/evp/pmeth_lib.c
+++ b/crypto/evp/pmeth_lib.c
@@ -148,7 +148,9 @@ static int evp_pkey_ctx_state(EVP_PKEY_CTX *ctx)
|| (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
&& ctx->op.ciph.ciphprovctx != NULL)
|| (EVP_PKEY_CTX_IS_GEN_OP(ctx)
- && ctx->op.keymgmt.genctx != NULL))
+ && ctx->op.keymgmt.genctx != NULL)
+ || (EVP_PKEY_CTX_IS_KEM_OP(ctx)
+ && ctx->op.encap.kemprovctx != NULL))
return EVP_PKEY_STATE_PROVIDER;
return EVP_PKEY_STATE_LEGACY;
@@ -396,7 +398,14 @@ void evp_pkey_ctx_free_old_ops(EVP_PKEY_CTX *ctx)
EVP_KEYEXCH_free(ctx->op.kex.exchange);
ctx->op.kex.exchprovctx = NULL;
ctx->op.kex.exchange = NULL;
- } else if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) {
+ } else if (EVP_PKEY_CTX_IS_KEM_OP(ctx)) {
+ if (ctx->op.encap.kemprovctx != NULL && ctx->op.encap.kem != NULL)
+ ctx->op.encap.kem->freectx(ctx->op.encap.kemprovctx);
+ EVP_KEM_free(ctx->op.encap.kem);
+ ctx->op.encap.kemprovctx = NULL;
+ ctx->op.encap.kem = NULL;
+ }
+ else if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) {
if (ctx->op.ciph.ciphprovctx != NULL && ctx->op.ciph.cipher != NULL)
ctx->op.ciph.cipher->freectx(ctx->op.ciph.ciphprovctx);
EVP_ASYM_CIPHER_free(ctx->op.ciph.cipher);
@@ -559,6 +568,26 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *pctx)
}
return rctx;
}
+ } else if (EVP_PKEY_CTX_IS_KEM_OP(pctx)) {
+ if (pctx->op.encap.kem != NULL) {
+ rctx->op.encap.kem = pctx->op.encap.kem;
+ if (!EVP_KEM_up_ref(rctx->op.encap.kem)) {
+ OPENSSL_free(rctx);
+ return NULL;
+ }
+ }
+ if (pctx->op.encap.kemprovctx != NULL) {
+ if (!ossl_assert(pctx->op.encap.kem != NULL))
+ return NULL;
+ rctx->op.encap.kemprovctx
+ = pctx->op.encap.kem->dupctx(pctx->op.encap.kemprovctx);
+ if (rctx->op.encap.kemprovctx == NULL) {
+ EVP_KEM_free(rctx->op.encap.kem);
+ OPENSSL_free(rctx);
+ return NULL;
+ }
+ return rctx;
+ }
}
rctx->pmeth = pctx->pmeth;
@@ -659,6 +688,12 @@ int EVP_PKEY_CTX_set_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params)
&& ctx->keymgmt->gen_set_params != NULL)
return evp_keymgmt_gen_set_params(ctx->keymgmt, ctx->op.keymgmt.genctx,
params);
+ if (EVP_PKEY_CTX_IS_KEM_OP(ctx)
+ && ctx->op.encap.kemprovctx != NULL
+ && ctx->op.encap.kem != NULL
+ && ctx->op.encap.kem->set_ctx_params != NULL)
+ return ctx->op.encap.kem->set_ctx_params(ctx->op.encap.kemprovctx,
+ params);
return 0;
}
@@ -682,6 +717,12 @@ int EVP_PKEY_CTX_get_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params)
&& ctx->op.ciph.cipher->get_ctx_params != NULL)
return ctx->op.ciph.cipher->get_ctx_params(ctx->op.ciph.ciphprovctx,
params);
+ if (EVP_PKEY_CTX_IS_KEM_OP(ctx)
+ && ctx->op.encap.kemprovctx != NULL
+ && ctx->op.encap.kem != NULL
+ && ctx->op.encap.kem->get_ctx_params != NULL)
+ return ctx->op.encap.kem->get_ctx_params(ctx->op.encap.kemprovctx,
+ params);
return 0;
}
@@ -710,6 +751,12 @@ const OSSL_PARAM *EVP_PKEY_CTX_gettable_params(EVP_PKEY_CTX *ctx)
EVP_ASYM_CIPHER_provider(ctx->op.ciph.cipher));
return ctx->op.ciph.cipher->gettable_ctx_params(provctx);
}
+ if (EVP_PKEY_CTX_IS_KEM_OP(ctx)
+ && ctx->op.encap.kem != NULL
+ && ctx->op.encap.kem->gettable_ctx_params != NULL) {
+ provctx = ossl_provider_ctx(EVP_KEM_provider(ctx->op.encap.kem));
+ return ctx->op.encap.kem->gettable_ctx_params(provctx);
+ }
return NULL;
}
@@ -740,7 +787,12 @@ const OSSL_PARAM *EVP_PKEY_CTX_settable_params(EVP_PKEY_CTX *ctx)
if (EVP_PKEY_CTX_IS_GEN_OP(ctx)
&& ctx->keymgmt != NULL)
return EVP_KEYMGMT_gen_settable_params(ctx->keymgmt);
-
+ if (EVP_PKEY_CTX_IS_KEM_OP(ctx)
+ && ctx->op.encap.kem != NULL
+ && ctx->op.encap.kem->settable_ctx_params != NULL) {
+ provctx = ossl_provider_ctx(EVP_KEM_provider(ctx->op.encap.kem));
+ return ctx->op.encap.kem->settable_ctx_params(provctx);
+ }
return NULL;
}
@@ -1096,6 +1148,24 @@ int EVP_PKEY_CTX_set_mac_key(EVP_PKEY_CTX *ctx, const unsigned char *key,
key, keylen);
}
+int EVP_PKEY_CTX_set_kem_op(EVP_PKEY_CTX *ctx, const char *op)
+{
+ OSSL_PARAM params[2], *p = params;
+
+ if (ctx == NULL || op == NULL) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_VALUE);
+ return 0;
+ }
+ if (!EVP_PKEY_CTX_IS_KEM_OP(ctx)) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+ return -2;
+ }
+ *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION,
+ (char *)op, 0);
+ *p = OSSL_PARAM_construct_end();
+ return EVP_PKEY_CTX_set_params(ctx, params);
+}
+
int evp_pkey_ctx_set1_id_prov(EVP_PKEY_CTX *ctx, const void *id, int len)
{
OSSL_PARAM params[2], *p = params;
diff --git a/doc/man3/EVP_KEM_free.pod b/doc/man3/EVP_KEM_free.pod
new file mode 100644
index 0000000000..0e3ca12ae3
--- /dev/null
+++ b/doc/man3/EVP_KEM_free.pod
@@ -0,0 +1,82 @@
+=pod
+
+=head1 NAME
+
+EVP_KEM_fetch, EVP_KEM_free, EVP_KEM_up_ref,
+EVP_KEM_number, EVP_KEM_is_a, EVP_KEM_provider,
+EVP_KEM_do_all_provided, EVP_KEM_names_do_all
+- Functions to manage EVP_KEM algorithm objects
+
+=head1 SYNOPSIS
+
+ #include <openssl/evp.h>
+
+ EVP_KEM *EVP_KEM_fetch(OPENSSL_CTX *ctx, const char *algorithm,
+ const char *properties);
+ void EVP_KEM_free(EVP_KEM *kem);
+ int EVP_KEM_up_ref(EVP_KEM *kem);
+ int EVP_KEM_number(const EVP_KEM *kem);
+ int EVP_KEM_is_a(const EVP_KEM *kem, const char *name);
+ OSSL_PROVIDER *EVP_KEM_provider(const EVP_KEM *kem);
+ void EVP_KEM_do_all_provided(OPENSSL_CTX *libctx,
+ void (*fn)(EVP_KEM *kem, void *arg), void *arg);
+ void EVP_KEM_names_do_all(const EVP_KEM *kem,
+ void (*fn)(const char *name, void *data), void *data);
+
+=head1 DESCRIPTION
+
+EVP_KEM_fetch() fetches the implementation for the given B<algorithm> from any
+provider offering it, within the criteria given by the B<properties> and in the
+scope of the given library context B<ctx> (see L<OPENSSL_CTX(3)>). The algorithm
+will be one offering functions for performing asymmetric kem related tasks such
+as key encapsulation and decapsulation.
+See L<provider(7)/Fetching algorithms> for further information.
+
+The returned value must eventually be freed with EVP_KEM_free().
+
+EVP_KEM_free() decrements the reference count for the B<EVP_KEM> structure.
+Typically this structure will have been obtained from an earlier call to
+EVP_KEM_fetch(). If the reference count drops to 0 then the structure is freed.
+
+EVP_KEM_up_ref() increments the reference count for an B<EVP_KEM> structure.
+
+EVP_KEM_is_a() returns 1 if I<kem> is an implementation of an
+algorithm that's identifiable with I<name>, otherwise 0.
+
+EVP_KEM_provider() returns the provider that I<kem> was fetched from.
+
+EVP_KEM_do_all_provided() traverses all EVP_KEMs implemented by all activated
+providers in the given library context I<libctx>, and for each of the
+implementations, calls the given function I<fn> with the implementation method
+and the given I<arg> as argument.
+
+EVP_KEM_number() returns the internal dynamic number assigned to I<kem>.
+
+EVP_KEM_names_do_all() traverses all names for I<kem>, and calls I<fn> with
+each name and I<data>.
+
+=head1 RETURN VALUES
+
+EVP_KEM_fetch() returns a pointer to an B<EVP_KEM> for success or B<NULL> for
+failure.
+
+EVP_KEM_up_ref() returns 1 for success or 0 otherwise.
+
+=head1 SEE ALSO
+
+L<provider(7)/Fetching algorithms>, L<OSSL_PROVIDER(3)>
+
+=head1 HISTORY
+
+The functions described here were added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License"). You may not use
+this file except in compliance with the License. You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man3/EVP_PKEY_CTX_ctrl.pod b/doc/man3/EVP_PKEY_CTX_ctrl.pod
index 794ad2053a..e5c187d950 100644
--- a/doc/man3/EVP_PKEY_CTX_ctrl.pod
+++ b/doc/man3/EVP_PKEY_CTX_ctrl.pod
@@ -67,7 +67,8 @@ EVP_PKEY_CTX_set_ecdh_kdf_outlen,
EVP_PKEY_CTX_get_ecdh_kdf_outlen,
EVP_PKEY_CTX_set0_ecdh_kdf_ukm,
EVP_PKEY_CTX_get0_ecdh_kdf_ukm,
-EVP_PKEY_CTX_set1_id, EVP_PKEY_CTX_get1_id, EVP_PKEY_CTX_get1_id_len
+EVP_PKEY_CTX_set1_id, EVP_PKEY_CTX_get1_id, EVP_PKEY_CTX_get1_id_len,
+EVP_PKEY_CTX_set_kem_op
- algorithm specific control operations
=head1 SYNOPSIS
@@ -91,6 +92,8 @@ EVP_PKEY_CTX_set1_id, EVP_PKEY_CTX_get1_id, EVP_PKEY_CTX_get1_id_len
int EVP_PKEY_CTX_set_group_name(EVP_PKEY_CTX *ctx, const char *name);
int EVP_PKEY_CTX_get_group_name(EVP_PKEY_CTX *ctx, char *name, size_t namelen);
+ int EVP_PKEY_CTX_set_kem_op(EVP_PKEY_CTX *ctx, const char *op);
+
#include <openssl/rsa.h>
int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int pad);
@@ -606,6 +609,12 @@ memory for further calls to EVP_PKEY_CTX_get1_id(). EVP_PKEY_CTX_get1_id()
returns the previously set ID value to caller in I<id>. The caller should
allocate adequate memory space for the I<id> before calling EVP_PKEY_CTX_get1_id().
+EVP_PKEY_CTX_set_kem_op() sets the KEM operation to run. This can be set after
+EVP_PKEY_encapsulate_init() or EVP_PKEY_decapsulate_init() to select the
+kem operation. RSA is the only key type that supports encapsulation currently,
+and as there is no default operation for the RSA type, this function must be
+called before EVP_PKEY_encapsulate() or EVP_PKEY_decapsulate().
+
=head1 RETURN VALUES
All other functions described on this page return a positive value for success
@@ -623,6 +632,8 @@ L<EVP_PKEY_verify(3)>,
L<EVP_PKEY_verify_recover(3)>,
L<EVP_PKEY_derive(3)>,
L<EVP_PKEY_keygen(3)>
+L<EVP_PKEY_encapsulate(3)>
+L<EVP_PKEY_decapsulate(3)>
=head1 HISTORY
diff --git a/doc/man3/EVP_PKEY_decapsulate.pod b/doc/man3/EVP_PKEY_decapsulate.pod
new file mode 100644
index 0000000000..7dd47a1e58
--- /dev/null
+++ b/doc/man3/EVP_PKEY_decapsulate.pod
@@ -0,0 +1,99 @@
+=pod
+
+=head1 NAME
+
+EVP_PKEY_decapsulate_init, EVP_PKEY_decapsulate
+- Key decapsulation using a private key algorithm
+
+=head1 SYNOPSIS
+
+ #include <openssl/evp.h>
+
+ int EVP_PKEY_decapsulate_init(EVP_PKEY_CTX *ctx);
+ int EVP_PKEY_decapsulate(EVP_PKEY_CTX *ctx,
+ unsigned char *secret, size_t *secretlen,
+ const unsigned char *wrapped, size_t wrappedlen);
+
+=head1 DESCRIPTION
+
+The EVP_PKEY_decapsulate_init() function initializes a private key algorithm
+context I<ctx> for a decapsulation operation.
+
+The EVP_PKEY_decapsulate() function performs a private key decapsulation
+operation using I<ctx>. The data to be decapsulated is specified using the
+I<wrapped> and I<wrappedlen> parameters.
+If I<secret> is I<NULL> then the maximum size of the output secret buffer
+is written to the I<*secretlen> parameter. If I<secret> is not B<NULL> and the
+call is successful then the decapsulated secret data is written to I<secret> and
+the amount of data written to I<secretlen>.
+
+=head1 NOTES
+
+After the call to EVP_PKEY_decapsulate_init() algorithm specific parameters
+for the operation may be set using L<EVP_PKEY_CTX_set_params(3)>. There are no
+settable parameters currently.
+
+=head1 RETURN VALUES
+
+EVP_PKEY_decapsulate_init() and EVP_PKEY_decapsulate() return 1 for
+success and 0 or a negative value for failure. In particular a return value of -2
+indicates the operation is not supported by the private key algorithm.
+
+=head1 EXAMPLES
+
+Decapsulate data using RSA:
+
+ #include <openssl/evp.h>
+
+ /*
+ * NB: assumes rsa_priv_key is an RSA private key,
+ * and that in, inlen are already set up to contain encapsulated data.
+ */
+
+ EVP_PKEY_CTX *ctx = NULL;
+ size_t secretlen = 0;
+ unsigned char *secret = NULL;;
+
+ ctx = EVP_PKEY_CTX_new_from_pkey(libctx, rsa_priv_key, NULL);
+ if (ctx = NULL)
+ /* Error */
+ if (EVP_PKEY_decapsulate_init(ctx) <= 0)
+ /* Error */
+
+ /* Set the mode - only 'RSASVE' is currently supported */
+ if (EVP_PKEY_CTX_set_kem_op(ctx, "RSASVE") <= 0)
+ /* Error */
+
+ /* Determine buffer length */
+ if (EVP_PKEY_decapsulate(ctx, NULL, &secretlen, in, inlen) <= 0)
+ /* Error */
+
+ secret = OPENSSL_malloc(secretlen);
+ if (secret == NULL)
+ /* malloc failure */
+
+ /* Decapsulated secret data is secretlen bytes long */
+ if (EVP_PKEY_decapsulaterctx, secret, &secretlen, in, inlen) <= 0)
+ /* Error */
+
+
+=head1 SEE ALSO
+
+L<EVP_PKEY_CTX_new(3)>,
+L<EVP_PKEY_encapsulate(3)>,
+L<EVP_KEM-RSA(7)>,
+
+=head1 HISTORY
+
+These functions were added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License"). You may not use
+this file except in compliance with the License. You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man3/EVP_PKEY_encapsulate.pod b/doc/man3/EVP_PKEY_encapsulate.pod
new file mode 100644
index 0000000000..0e911f71cf
--- /dev/null
+++ b/doc/man3/EVP_PKEY_encapsulate.pod
@@ -0,0 +1,101 @@
+=pod
+
+=head1 NAME
+
+EVP_PKEY_encapsulate_init, EVP_PKEY_encapsulate
+- Key encapsulation using a public key algorithm
+
+=head1 SYNOPSIS
+
+ #include <openssl/evp.h>
+
+ int EVP_PKEY_encapsulate_init(EVP_PKEY_CTX *ctx);
+ int EVP_PKEY_encapsulate(EVP_PKEY_CTX *ctx,
+ unsigned char *out, size_t *outlen,
+ unsigned char *genkey, size_t *genkeylen);
+
+=head1 DESCRIPTION
+
+The EVP_PKEY_encapsulate_init() function initializes a public key algorithm
+context I<c