/*
 * libseckey - Secure key library
 *
 * Copyright IBM Corp. 2021
 *
 * s390-tools is free software; you can redistribute it and/or modify
 * it under the terms of the MIT license. See LICENSE for details.
 */
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <err.h>
#include <stdbool.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <sys/time.h>

#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/sha.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/rsa.h>
#include <openssl/x509v3.h>

#include "lib/zt_common.h"

#include "libseckey/sk_openssl.h"
#include "libseckey/sk_utilities.h"

/*
 * This source file is only used with OpenSSL >= 3.0
 */
#if OPENSSL_VERSION_PREREQ(3, 0)

#include <openssl/provider.h>
#include <openssl/core.h>
#include <openssl/core_dispatch.h>
#include <openssl/core_names.h>
#include <openssl/params.h>
#include "openssl/param_build.h"
#include <openssl/decoder.h>

static OSSL_LIB_CTX *sk_prov_securekey_libctx;
static OSSL_LIB_CTX *sk_prov_previous_libctx;
static OSSL_PROVIDER *sk_prov_securekey_provider;
static OSSL_PROVIDER *sk_prov_default_provider;

#define SK_PROV_NAME				"securekey"
#define SK_PROV_DESCRIPTION			"Secure key provider"
#define SK_PROV_VERSION				"1.0"

#define SK_PROV_RSA_DEFAULT_MD			"SHA-1"
#define SK_PROV_EC_DEFAULT_MD_NID		"SHA-1"
#define SK_PROV_PKEY_PARAM_SK_BLOB		"sk-blob"
#define SK_PROV_PKEY_PARAM_SK_FUNCS		"sk-funcs"
#define SK_PROV_PKEY_PARAM_SK_PRIVATE		"sk-private"

#define SK_CONF_CACHED_PARAMS_OP_KEY_EXPORT	0  /* 16 possible selections */
#define SK_CONF_CACHED_PARAMS_OP_KEY_IMPORT	16 /* 16 possible selections */
#define SK_CONF_CACHED_PARAMS_OP_KEY_GET	32
#define SK_CONF_CACHED_PARAMS_OP_KEY_SET	33
#define SK_CONF_CACHED_PARAMS_OP_COUNT		34

#define SK_CONF_CACHED_PARAMS_ALGO_RSA		0
#define SK_CONF_CACHED_PARAMS_ALGO_RSA_PSS	1
#define SK_CONF_CACHED_PARAMS_ALGO_EC		2
#define SK_CONF_CACHED_PARAMS_ALGO_COUNT	3

#define SK_PROV_CACHED_PARAMS_COUNT					\
	(SK_CONF_CACHED_PARAMS_ALGO_COUNT * SK_CONF_CACHED_PARAMS_OP_COUNT)

struct sk_prov_ctx {
	const OSSL_CORE_HANDLE *handle;
	OSSL_FUNC_core_get_libctx_fn *c_get_libctx;
	OSSL_FUNC_core_new_error_fn *c_new_error;
	OSSL_FUNC_core_set_error_debug_fn *c_set_error_debug;
	OSSL_FUNC_core_vset_error_fn *c_vset_error;
	OSSL_PROVIDER *default_provider;
	void *default_provctx;
	const OSSL_ALGORITHM *cached_default_algos[OSSL_OP__HIGHEST];
	const OSSL_PARAM *cached_parms[SK_PROV_CACHED_PARAMS_COUNT];
	bool debug;
};

struct sk_prov_key {
	struct sk_prov_ctx *provctx;
	int type; /* EVP_PKEY_xxx types */
	void *default_key; /* shadow key of default provider */
	unsigned char *secure_key;
	size_t secure_key_size;
	struct sk_funcs *funcs;
	void *private;
	unsigned int ref_count;
};

struct sk_prov_op_ctx {
	struct sk_prov_ctx *provctx;
	int type; /* EVP_PKEY_xxx types */
	const char *propq;
	void *default_op_ctx; /* shadow context of default provider */
	void (*default_op_ctx_free)(void *default_op_ctx);
	struct sk_prov_key *key;
	int operation;
	OSSL_FUNC_signature_sign_fn *sign_fn;
	EVP_MD_CTX *mdctx;
	EVP_MD *md;
};

#define sk_debug_ctx(ctx, fmt...)	sk_debug(ctx->debug, fmt)
#define sk_debug_key(key, fmt...)	sk_debug(key->provctx->debug, fmt)
#define sk_debug_op_ctx(ctx, fmt...)	sk_debug(ctx->provctx->debug, fmt)

int sk_openssl_get_pkey_ec(const unsigned char *secure_key,
			   size_t secure_key_size, int nid, size_t prime_len,
			   const unsigned char *x, const unsigned char *y,
			   const struct sk_funcs *sk_funcs, const void *private,
			   EVP_PKEY **pkey, bool debug);

int sk_openssl_get_pkey_rsa(const unsigned char *secure_key,
			    size_t secure_key_size,
			    const unsigned char *modulus, size_t modulus_length,
			    const unsigned char *pub_exp, size_t pub_exp_length,
			    int pkey_type, const struct sk_funcs *sk_funcs,
			    const void *private, EVP_PKEY **pkey, bool debug);


static OSSL_FUNC_provider_teardown_fn		sk_prov_teardown;
static OSSL_FUNC_provider_gettable_params_fn	sk_prov_gettable_params;
static OSSL_FUNC_provider_get_params_fn		sk_prov_get_params;
static OSSL_FUNC_provider_query_operation_fn	sk_prov_query;
static OSSL_FUNC_provider_get_reason_strings_fn	sk_prov_get_reason_strings;
static OSSL_FUNC_provider_get_capabilities_fn	sk_prov_prov_get_capabilities;

static OSSL_FUNC_keymgmt_free_fn		sk_prov_keymgmt_free;
static OSSL_FUNC_keymgmt_gen_cleanup_fn		sk_prov_keymgmt_gen_cleanup;
static OSSL_FUNC_keymgmt_load_fn		sk_prov_keymgmt_load;
static OSSL_FUNC_keymgmt_gen_set_template_fn
					sk_prov_keymgmt_gen_set_template;
static OSSL_FUNC_keymgmt_gen_set_params_fn	sk_prov_keymgmt_gen_set_params;
static OSSL_FUNC_keymgmt_gen_fn			sk_prov_keymgmt_gen;
static OSSL_FUNC_keymgmt_get_params_fn		sk_prov_keymgmt_get_params;
static OSSL_FUNC_keymgmt_set_params_fn		sk_prov_keymgmt_set_params;
static OSSL_FUNC_keymgmt_has_fn			sk_prov_keymgmt_has;
static OSSL_FUNC_keymgmt_match_fn		sk_prov_keymgmt_match;
static OSSL_FUNC_keymgmt_validate_fn		sk_prov_keymgmt_validate;
static OSSL_FUNC_keymgmt_export_fn		sk_prov_keymgmt_export;
static OSSL_FUNC_keymgmt_import_fn		sk_prov_keymgmt_import;
static OSSL_FUNC_keymgmt_new_fn			sk_prov_keymgmt_rsa_new;
static OSSL_FUNC_keymgmt_new_fn			sk_prov_keymgmt_rsa_pss_new;
static OSSL_FUNC_keymgmt_new_fn			sk_prov_keymgmt_ec_new;
static OSSL_FUNC_keymgmt_gen_init_fn		sk_prov_keymgmt_rsa_gen_init;
static OSSL_FUNC_keymgmt_gen_init_fn	sk_prov_keymgmt_rsa_pss_gen_init;
static OSSL_FUNC_keymgmt_gen_init_fn		sk_prov_keymgmt_ec_gen_init;
static OSSL_FUNC_keymgmt_gen_settable_params_fn
					sk_prov_keymgmt_rsa_gen_settable_params;
static OSSL_FUNC_keymgmt_gen_settable_params_fn
				sk_prov_keymgmt_rsa_pss_gen_settable_params;
static OSSL_FUNC_keymgmt_gen_settable_params_fn
					sk_prov_keymgmt_ec_gen_settable_params;
static OSSL_FUNC_keymgmt_query_operation_name_fn
				sk_prov_keymgmt_rsa_query_operation_name;
static OSSL_FUNC_keymgmt_query_operation_name_fn
				sk_prov_keymgmt_ec_query_operation_name;
static OSSL_FUNC_keymgmt_gettable_params_fn
					sk_prov_keymgmt_rsa_gettable_params;
static OSSL_FUNC_keymgmt_gettable_params_fn
					sk_prov_keymgmt_rsa_pss_gettable_params;
static OSSL_FUNC_keymgmt_gettable_params_fn
					sk_prov_keymgmt_ec_gettable_params;
static OSSL_FUNC_keymgmt_settable_params_fn
					sk_prov_keymgmt_rsa_settable_params;
static OSSL_FUNC_keymgmt_settable_params_fn
					sk_prov_keymgmt_rsa_pss_settable_params;
static OSSL_FUNC_keymgmt_settable_params_fn
					sk_prov_keymgmt_ec_settable_params;
#ifdef OSSL_FUNC_KEYMGMT_EXPORT_TYPES_EX
static OSSL_FUNC_keymgmt_export_types_ex_fn
					sk_prov_keymgmt_rsa_export_types_ex;
static OSSL_FUNC_keymgmt_export_types_ex_fn
					sk_prov_keymgmt_rsa_pss_export_types_ex;
static OSSL_FUNC_keymgmt_export_types_ex_fn
					sk_prov_keymgmt_ec_export_types_ex;
static OSSL_FUNC_keymgmt_import_types_ex_fn
					sk_prov_keymgmt_rsa_import_types_ex;
static OSSL_FUNC_keymgmt_import_types_ex_fn
					sk_prov_keymgmt_rsa_pss_import_types_ex;
static OSSL_FUNC_keymgmt_import_types_ex_fn
					sk_prov_keymgmt_ec_import_types_ex;
#else
static OSSL_FUNC_keymgmt_export_types_fn
					sk_prov_keymgmt_rsa_export_types;
static OSSL_FUNC_keymgmt_export_types_fn
					sk_prov_keymgmt_rsa_pss_export_types;
static OSSL_FUNC_keymgmt_export_types_fn
					sk_prov_keymgmt_ec_export_types;
static OSSL_FUNC_keymgmt_import_types_fn
					sk_prov_keymgmt_rsa_import_types;
static OSSL_FUNC_keymgmt_import_types_fn
					sk_prov_keymgmt_rsa_pss_import_types;
static OSSL_FUNC_keymgmt_import_types_fn	sk_prov_keymgmt_ec_import_types;
#endif

static OSSL_FUNC_keyexch_newctx_fn		sk_prov_keyexch_ec_newctx;
static OSSL_FUNC_keyexch_dupctx_fn		sk_prov_keyexch_ec_dupctx;
static OSSL_FUNC_keyexch_init_fn		sk_prov_keyexch_ec_init;
static OSSL_FUNC_keyexch_set_peer_fn		sk_prov_keyexch_ec_set_peer;
static OSSL_FUNC_keyexch_derive_fn		sk_prov_keyexch_ec_derive;
static OSSL_FUNC_keyexch_set_ctx_params_fn
					sk_prov_keyexch_ec_set_ctx_params;
static OSSL_FUNC_keyexch_settable_ctx_params_fn
					sk_prov_keyexch_ec_settable_ctx_params;
static OSSL_FUNC_keyexch_get_ctx_params_fn sk_prov_keyexch_ec_get_ctx_params;
static OSSL_FUNC_keyexch_gettable_ctx_params_fn
					sk_prov_keyexch_ec_gettable_ctx_params;

static OSSL_FUNC_signature_newctx_fn		sk_prov_sign_rsa_newctx;
static OSSL_FUNC_signature_newctx_fn		sk_prov_sign_ec_newctx;
static OSSL_FUNC_signature_dupctx_fn		sk_prov_sign_op_dupctx;
static OSSL_FUNC_signature_sign_init_fn		sk_prov_sign_op_sign_init;
static OSSL_FUNC_signature_sign_fn		sk_prov_sign_rsa_sign;
static OSSL_FUNC_signature_sign_fn		sk_prov_sign_ec_sign;
static OSSL_FUNC_signature_verify_init_fn	sk_prov_sign_op_verify_init;
static OSSL_FUNC_signature_verify_fn		sk_prov_sign_op_verify;
static OSSL_FUNC_signature_verify_recover_init_fn
					sk_prov_sign_op_verify_recover_init;
static OSSL_FUNC_signature_verify_recover_fn	sk_prov_sign_op_verify_recover;
static OSSL_FUNC_signature_digest_sign_init_fn
					sk_prov_sign_rsa_digest_sign_init;
static OSSL_FUNC_signature_digest_sign_init_fn
					sk_prov_sign_ec_digest_sign_init;
static OSSL_FUNC_signature_digest_sign_update_fn
					sk_prov_sign_op_digest_sign_update;
static OSSL_FUNC_signature_digest_sign_final_fn
					sk_prov_sign_op_digest_sign_final;
static OSSL_FUNC_signature_digest_verify_init_fn
					sk_prov_sign_op_digest_verify_init;
static OSSL_FUNC_signature_digest_verify_update_fn
					sk_prov_sign_op_digest_verify_update;
static OSSL_FUNC_signature_digest_verify_final_fn
					sk_prov_sign_op_digest_verify_final;
static OSSL_FUNC_signature_get_ctx_params_fn	sk_prov_sign_op_get_ctx_params;
static OSSL_FUNC_signature_gettable_ctx_params_fn
					sk_prov_sign_rsa_gettable_ctx_params;
static OSSL_FUNC_signature_gettable_ctx_params_fn
					sk_prov_sign_ec_gettable_ctx_params;
static OSSL_FUNC_signature_set_ctx_params_fn	sk_prov_sign_op_set_ctx_params;
static OSSL_FUNC_signature_settable_ctx_params_fn
					sk_prov_sign_rsa_settable_ctx_params;
static OSSL_FUNC_signature_settable_ctx_params_fn
					sk_prov_sign_ec_settable_ctx_params;
static OSSL_FUNC_signature_get_ctx_md_params_fn
					sk_prov_sign_op_get_ctx_md_params;
static OSSL_FUNC_signature_gettable_ctx_md_params_fn
					sk_prov_sign_rsa_gettable_ctx_md_params;
static OSSL_FUNC_signature_gettable_ctx_md_params_fn
					sk_prov_sign_ec_gettable_ctx_md_params;
static OSSL_FUNC_signature_set_ctx_md_params_fn
					sk_prov_sign_op_set_ctx_md_params;
static OSSL_FUNC_signature_settable_ctx_md_params_fn
					sk_prov_sign_rsa_settable_ctx_md_params;
static OSSL_FUNC_signature_settable_ctx_md_params_fn
					sk_prov_sign_ec_settable_ctx_md_params;

static OSSL_FUNC_asym_cipher_newctx_fn		sk_prov_asym_rsa_newctx;
static OSSL_FUNC_asym_cipher_dupctx_fn		sk_prov_asym_op_dupctx;
static OSSL_FUNC_asym_cipher_freectx_fn		sk_prov_op_freectx;
static OSSL_FUNC_asym_cipher_get_ctx_params_fn	sk_prov_asym_op_get_ctx_params;
static OSSL_FUNC_asym_cipher_gettable_ctx_params_fn
					sk_prov_asym_rsa_gettable_ctx_params;
static OSSL_FUNC_asym_cipher_set_ctx_params_fn	sk_prov_asym_op_set_ctx_params;
static OSSL_FUNC_asym_cipher_settable_ctx_params_fn
					sk_prov_asym_rsa_settable_ctx_params;
static OSSL_FUNC_asym_cipher_encrypt_init_fn	sk_prov_asym_op_encrypt_init;
static OSSL_FUNC_asym_cipher_encrypt_fn		sk_prov_asym_op_encrypt;
static OSSL_FUNC_asym_cipher_decrypt_init_fn	sk_prov_asym_op_decrypt_init;
static OSSL_FUNC_asym_cipher_decrypt_fn		sk_prov_asym_rsa_decrypt;

#define SK_PROV_ERR_INTERNAL_ERROR		1
#define SK_PROV_ERR_MALLOC_FAILED		2
#define SK_PROV_ERR_INVALID_PARAM		3
#define SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING	4
#define SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED	5
#define SK_PROV_ERR_OPRATION_NOT_INITIALIZED	6
#define SK_PROV_ERR_MISSING_PARAMETER		7
#define SK_PROV_ERR_INVALID_PADDING		8
#define SK_PROV_ERR_INVALID_MD			9
#define SK_PROV_ERR_INVALID_SALTLEN		10
#define SK_PROV_ERR_SECURE_KEY_FUNC_FAILED	11

static const OSSL_ITEM sk_prov_reason_strings[] = {
	{ SK_PROV_ERR_INTERNAL_ERROR,	"Internal error" },
	{ SK_PROV_ERR_MALLOC_FAILED,	"Memory allocation failed" },
	{ SK_PROV_ERR_INVALID_PARAM,	"Invalid parameter encountered" },
	{ SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
		"A function inherited from default provider is missing" },
	{ SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
		"A function inherited from default provider has failed" },
	{ SK_PROV_ERR_OPRATION_NOT_INITIALIZED,
		"An operation context has not been initialized" },
	{ SK_PROV_ERR_MISSING_PARAMETER,
		"A parameter of a key or a context is missing" },
	{ SK_PROV_ERR_INVALID_PADDING,
		"An invalid or unknown padding is used" },
	{ SK_PROV_ERR_INVALID_MD, "An invalid or unknown digest is used" },
	{ SK_PROV_ERR_INVALID_SALTLEN, "An invalid salt length is used" },
	{ SK_PROV_ERR_SECURE_KEY_FUNC_FAILED,
		"A secure key function has failed" },
	{0, NULL }
};

static void sk_prov_put_error(struct sk_prov_ctx *provctx, int err,
			      const char *file, int line, const char *func,
			      char *fmt, ...)
{
	va_list ap;

	if (provctx == NULL)
		return;

	va_start(ap, fmt);
	provctx->c_new_error(provctx->handle);
	provctx->c_set_error_debug(provctx->handle, file, line, func);
	provctx->c_vset_error(provctx->handle, err, fmt, ap);
	va_end(ap);
}

#define put_error_ctx(ctx, err, fmt...)					\
			do {						\
				sk_debug_ctx(ctx, "ERROR: "fmt);	\
				sk_prov_put_error(ctx, err, __FILE__,	\
					__LINE__, __func__, fmt);	\
			} while (0)
#define put_error_key(key, err, fmt...)					\
			put_error_ctx(key->provctx, err, fmt)
#define put_error_op_ctx(ctx, err, fmt...)				\
			put_error_ctx(ctx->provctx, err, fmt)

static void sk_prov_keymgmt_upref(struct sk_prov_key *key);
static struct sk_prov_key *sk_prov_keymgmt_new(struct sk_prov_ctx *provctx,
					       int type);
static int sk_prov_keymgmt_get_bits(struct sk_prov_key *key);

typedef void (*func_t)(void);

static func_t sk_prov_get_default_func(struct sk_prov_ctx *provctx,
				       int operation_id,
				       const char *algorithm,
				       int function_id)
{
	const OSSL_ALGORITHM *default_algos, *algs;
	const OSSL_DISPATCH *default_impl, *impl;
	int algolen = strlen(algorithm);
	int no_cache = 0, query = 0;
	func_t func = NULL;
	const char *found;

	if (provctx == NULL || provctx->default_provider == NULL ||
	    operation_id <= 0 || operation_id > OSSL_OP__HIGHEST)
		return NULL;

	sk_debug_ctx(provctx, "operation_id: %d, algo: %s, func: %d",
		     operation_id, algorithm, function_id);

	default_algos = provctx->cached_default_algos[operation_id];
	if (default_algos == NULL) {
		default_algos = OSSL_PROVIDER_query_operation(
				provctx->default_provider,
				operation_id, &no_cache);
		query = 1;
	}

	for (algs = default_algos; algs != NULL &&
				   algs->algorithm_names != NULL; algs++) {
		found = strcasestr(algs->algorithm_names, algorithm);
		if (found == NULL)
			continue;
		if (found[algolen] != '\0' && found[algolen] != ':')
			continue;
		if (found != algs->algorithm_names && found[-1] != ':')
			continue;

		default_impl = algs->implementation;
		for (impl = default_impl; impl->function_id != 0; impl++) {
			if (impl->function_id == function_id) {
				func = impl->function;
				break;
			}
		}
		break;
	}

	if (query == 1 && default_algos != NULL)
		OSSL_PROVIDER_unquery_operation(provctx->default_provider,
						operation_id,
						default_algos);

	if (no_cache == 0 &&
	    provctx->cached_default_algos[operation_id] == NULL)
		provctx->cached_default_algos[operation_id] = default_algos;

	sk_debug_ctx(provctx, "func: %p", func);
	return func;
}

static const char *sk_prov_get_algo(int pkey_type, bool sign)
{
	switch (pkey_type) {
	case EVP_PKEY_RSA:
		return "RSA";
	case EVP_PKEY_RSA_PSS:
		return "RSA-PSS";
	case EVP_PKEY_EC:
		if (sign)
			return "ECDSA";
		else
			return "EC";
	default:
		return NULL;
	}
}

static func_t sk_prov_get_default_keymgmt_func(struct sk_prov_ctx *provctx,
					       int pkey_type, int function_id)
{
	return sk_prov_get_default_func(provctx, OSSL_OP_KEYMGMT,
					sk_prov_get_algo(pkey_type, false),
					function_id);
}

static func_t sk_prov_get_default_keyexch_func(struct sk_prov_ctx *provctx,
					       int function_id)
{
	return sk_prov_get_default_func(provctx, OSSL_OP_KEYEXCH, "ECDH",
					function_id);
}

static func_t sk_prov_get_default_asym_func(struct sk_prov_ctx *provctx,
					    int pkey_type, int function_id)
{
	return sk_prov_get_default_func(provctx, OSSL_OP_ASYM_CIPHER,
					sk_prov_get_algo(pkey_type, false),
					function_id);
}

static func_t sk_prov_get_default_sign_func(struct sk_prov_ctx *provctx,
					    int pkey_type, int function_id)
{
	return sk_prov_get_default_func(provctx, OSSL_OP_SIGNATURE,
					sk_prov_get_algo(pkey_type, true),
					function_id);
}

static int sk_prov_get_cached_params_index(int pkey_type, int operation,
					   int selection)
{
	int ofs = 0;

	if (operation < 0 || operation >= SK_CONF_CACHED_PARAMS_OP_COUNT)
		return -1;

	switch (operation) {
	case SK_CONF_CACHED_PARAMS_OP_KEY_EXPORT:
	case SK_CONF_CACHED_PARAMS_OP_KEY_IMPORT:
		if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
			ofs += 1;
		if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
			ofs += 2;
		if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
			ofs += 4;
		if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0)
			ofs += 8;
		break;
	}

	switch (pkey_type) {
	case EVP_PKEY_RSA:
		return (SK_CONF_CACHED_PARAMS_ALGO_RSA *
				SK_CONF_CACHED_PARAMS_OP_COUNT) +
							operation + ofs;
	case EVP_PKEY_RSA_PSS:
		return (SK_CONF_CACHED_PARAMS_ALGO_RSA_PSS *
				SK_CONF_CACHED_PARAMS_OP_COUNT) +
							operation + ofs;
	case EVP_PKEY_EC:
		return (SK_CONF_CACHED_PARAMS_ALGO_EC *
				SK_CONF_CACHED_PARAMS_OP_COUNT) +
							operation + ofs;
	}

	return -1;
}

static const OSSL_PARAM *sk_prov_get_cached_params(struct sk_prov_ctx *provctx,
						   int pkey_type, int operation,
						   int selection)
{
	int index;

	sk_debug_ctx(provctx, "pkey_type: %d operation: %d selection: %x",
		     pkey_type, operation, selection);

	index = sk_prov_get_cached_params_index(pkey_type, operation,
						selection);
	if (index < 0) {
		put_error_ctx(provctx, SK_PROV_ERR_INTERNAL_ERROR,
			      "Invalid type, operation or selection");
		return NULL;
	}

	return provctx->cached_parms[index];
}

static const OSSL_PARAM *sk_prov_cached_params_build(
						struct sk_prov_ctx *provctx,
						int pkey_type,
						int operation,
						int selection,
						const OSSL_PARAM *params1,
						const OSSL_PARAM *params2)
{
	int index, count = 0, i, k = 0;
	OSSL_PARAM *params;

	sk_debug_ctx(provctx, "pkey_type: %d operation: %d selection: %x",
		     pkey_type, operation, selection);

	index = sk_prov_get_cached_params_index(pkey_type, operation,
						selection);
	if (index < 0) {
		put_error_ctx(provctx, SK_PROV_ERR_INTERNAL_ERROR,
			      "Invalid type, operation or selection");
		return NULL;
	}

	if (provctx->cached_parms[index] != NULL) {
		OPENSSL_free((void *)provctx->cached_parms[index]);
		provctx->cached_parms[index] = NULL;
	}

	for (i = 0; params1 != NULL && params1[i].key != NULL; i++, count++)
		;
	for (i = 0; params2 != NULL && params2[i].key != NULL; i++, count++)
		;
	sk_debug_ctx(provctx, "count: %d", count);

	count++; /* End marker */

	params = OPENSSL_zalloc(sizeof(OSSL_PARAM) * count);
	if (params == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_MALLOC_FAILED,
			      "OPENSSL_zalloc failed");
		return NULL;
	}

	for (i = 0; params1 != NULL && params1[i].key != NULL; i++, k++) {
		params[k] = params1[i];
		sk_debug_ctx(provctx, "param %d: %s", k, params[k].key);
	}
	for (i = 0; params2 != NULL && params2[i].key != NULL; i++, k++) {
		params[k] = params2[i];
		sk_debug_ctx(provctx, "param %d: %s", k, params[k].key);
	}
	params[k] = OSSL_PARAM_construct_end();

	provctx->cached_parms[index] = params;
	return provctx->cached_parms[index];
}

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
static bool sk_prov_check_uint_param(const OSSL_PARAM params[],
				     const char *param_name,
				     const struct sk_prov_key *key,
				     int key_type,
				     unsigned int expected_value)
{
	const OSSL_PARAM *p;
	unsigned int value;

	if (key == NULL)
		return true;
	if (key->type != key_type)
		return true;

	p = OSSL_PARAM_locate_const(params, param_name);
	if (p == NULL)
		return true;

	if (OSSL_PARAM_get_uint(p, &value) != 1)
		return true;

	return value == expected_value;
}
#pragma GCC diagnostic pop

static struct sk_prov_op_ctx *sk_prov_op_newctx(struct sk_prov_ctx *provctx,
						const char *propq,
						int type)
{
	struct sk_prov_op_ctx *ctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "propq: %s type: %d",
		     propq != NULL ? propq : "", type);

	ctx = OPENSSL_zalloc(sizeof(struct sk_prov_op_ctx));
	if (ctx == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_MALLOC_FAILED,
			      "OPENSSL_zalloc failed");
		return NULL;
	}

	ctx->provctx = provctx;
	ctx->type = type;

	if (propq != NULL) {
		ctx->propq = OPENSSL_strdup(propq);
		if (ctx->propq == NULL) {
			put_error_ctx(provctx, SK_PROV_ERR_MALLOC_FAILED,
				      "OPENSSL_strdup failed");
			OPENSSL_free(ctx);
			return NULL;
		}
	}

	sk_debug_ctx(provctx, "ctx: %p", ctx);
	return ctx;
}

static void sk_prov_op_freectx(void *vctx)
{
	struct sk_prov_op_ctx *ctx = vctx;

	if (ctx == NULL)
		return;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);

	if (ctx->default_op_ctx != NULL && ctx->default_op_ctx_free != NULL)
		ctx->default_op_ctx_free(ctx->default_op_ctx);

	if (ctx->key != NULL)
		sk_prov_keymgmt_free(ctx->key);

	if (ctx->propq != NULL)
		OPENSSL_free((void *)ctx->propq);

	if (ctx->mdctx != NULL)
		EVP_MD_CTX_free(ctx->mdctx);
	if (ctx->md != NULL)
		EVP_MD_free(ctx->md);

	OPENSSL_free(ctx);
}

static struct sk_prov_op_ctx *sk_prov_op_dupctx(struct sk_prov_op_ctx *ctx)
{
	struct sk_prov_op_ctx *new_ctx;

	if (ctx == NULL)
		return NULL;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);

	new_ctx = sk_prov_op_newctx(ctx->provctx, ctx->propq, ctx->type);
	if (new_ctx == NULL) {
		sk_debug_op_ctx(ctx, "ERROR: sk_prov_op_newctx failed");
		return NULL;
	}

	new_ctx->operation = ctx->operation;
	new_ctx->default_op_ctx_free = ctx->default_op_ctx_free;
	new_ctx->sign_fn = ctx->sign_fn;

	if (ctx->mdctx != NULL) {
		new_ctx->mdctx = EVP_MD_CTX_new();
		if (new_ctx->mdctx == NULL) {
			put_error_op_ctx(ctx, SK_PROV_ERR_MALLOC_FAILED,
					 "EVP_MD_CTX_new failed");
			sk_prov_op_freectx(new_ctx);
			return NULL;
		}

		if (!EVP_MD_CTX_copy_ex(new_ctx->mdctx, ctx->mdctx)) {
			sk_debug_op_ctx(ctx,
					"ERROR: EVP_MD_CTX_copy_ex failed");
			sk_prov_op_freectx(new_ctx);
			return NULL;
		}
	};

	if (ctx->md != NULL) {
		new_ctx->md = ctx->md;
		EVP_MD_up_ref(ctx->md);
	}

	if (ctx->key != NULL) {
		new_ctx->key = ctx->key;
		sk_prov_keymgmt_upref(ctx->key);
	}

	sk_debug_op_ctx(ctx, "new_ctx: %p", new_ctx);
	return new_ctx;
}

static int sk_prov_op_init(struct sk_prov_op_ctx *ctx, struct sk_prov_key *key,
			   int operation)
{
	if (ctx == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p operation: %d", ctx, key,
			operation);

	if (key != NULL) {
		switch (ctx->type) {
		case EVP_PKEY_RSA:
		case EVP_PKEY_RSA_PSS:
			if (key->type != EVP_PKEY_RSA &&
			    key->type != EVP_PKEY_RSA_PSS) {
				put_error_op_ctx(ctx,
						 SK_PROV_ERR_INTERNAL_ERROR,
						 "key type mismatch: ctx type: "
						 "%d key type: %d",
						 ctx->type, key->type);
				return 0;
			}
			break;
		case EVP_PKEY_EC:
			if (key->type != EVP_PKEY_EC) {
				put_error_op_ctx(ctx,
						 SK_PROV_ERR_INTERNAL_ERROR,
						 "key type mismatch: ctx type: "
						 "%d key type: %d",
						 ctx->type, key->type);
				return 0;
			}
			break;
		default:
			put_error_op_ctx(ctx, SK_PROV_ERR_INTERNAL_ERROR,
					 "key type unknown: ctx type: "
					 "%d key type: %d",
					 ctx->type, key->type);
			return 0;
		}
	}

	if (key != NULL)
		sk_prov_keymgmt_upref(key);

	if (ctx->key != NULL)
		sk_prov_keymgmt_free(ctx->key);

	ctx->key = key;
	ctx->operation = operation;

	return 1;
}

static struct sk_prov_op_ctx *sk_prov_asym_op_newctx(
					struct sk_prov_ctx *provctx,
					int pkey_type)
{
	OSSL_FUNC_asym_cipher_freectx_fn *default_freectx_fn;
	OSSL_FUNC_asym_cipher_newctx_fn *default_newctx_fn;
	struct sk_prov_op_ctx *ctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "pkey_type: %d", pkey_type);

	default_newctx_fn = (OSSL_FUNC_asym_cipher_newctx_fn *)
			sk_prov_get_default_asym_func(provctx, pkey_type,
					OSSL_FUNC_ASYM_CIPHER_NEWCTX);
	if (default_newctx_fn == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
			      "no default newctx_fn");
		return NULL;
	}

	default_freectx_fn = (OSSL_FUNC_asym_cipher_freectx_fn *)
			sk_prov_get_default_asym_func(provctx, pkey_type,
					OSSL_FUNC_ASYM_CIPHER_FREECTX);
	if (default_freectx_fn == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
			      "no default freectx_fn");
		return NULL;
	}

	ctx = sk_prov_op_newctx(provctx, NULL, pkey_type);
	if (ctx == NULL) {
		sk_debug_ctx(provctx, "ERROR: sk_prov_op_newctx failed");
		return NULL;
	}

	ctx->default_op_ctx = default_newctx_fn(provctx->default_provctx);
	if (ctx->default_op_ctx == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
			      "default_newctx_fn failed");
		sk_prov_op_freectx(ctx);
		return NULL;
	}
	ctx->default_op_ctx_free = default_freectx_fn;

	sk_debug_ctx(provctx, "ctx: %p", ctx);
	return ctx;
}

static void *sk_prov_asym_op_dupctx(void *vctx)
{
	OSSL_FUNC_asym_cipher_dupctx_fn *default_dupctx_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_op_ctx *new_ctx;

	if (ctx == NULL)
		return NULL;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);

	default_dupctx_fn = (OSSL_FUNC_asym_cipher_dupctx_fn *)
			sk_prov_get_default_asym_func(ctx->provctx,
				ctx->type, OSSL_FUNC_ASYM_CIPHER_DUPCTX);
	if (default_dupctx_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default dupctx_fn");
		return NULL;
	}

	new_ctx = sk_prov_op_dupctx(ctx);
	if (new_ctx == NULL) {
		sk_debug_op_ctx(ctx, "ERROR: sk_prov_op_dupctx failed");
		return NULL;
	}

	new_ctx->default_op_ctx = default_dupctx_fn(ctx->default_op_ctx);
	if (new_ctx->default_op_ctx == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_dupctx_fn failed");
		sk_prov_op_freectx(new_ctx);
		return NULL;
	}

	sk_debug_op_ctx(ctx, "new_ctx: %p", new_ctx);
	return new_ctx;
}

static int sk_prov_asym_op_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
	OSSL_FUNC_asym_cipher_get_ctx_params_fn *default_get_params_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	const OSSL_PARAM *p;

	if (ctx == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

	default_get_params_fn = (OSSL_FUNC_asym_cipher_get_ctx_params_fn *)
			sk_prov_get_default_asym_func(ctx->provctx,
				ctx->type,
				OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS);

	/* default_get_params_fn is optional */
	if (default_get_params_fn != NULL) {
		if (!default_get_params_fn(ctx->default_op_ctx, params)) {
			put_error_op_ctx(ctx,
					 SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
					 "default_get_params_fn failed");
			return 0;
		}
	}

	return 1;
}

static int sk_prov_asym_op_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
	OSSL_FUNC_asym_cipher_set_ctx_params_fn *default_set_params_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	const OSSL_PARAM *p;

	if (ctx == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

#ifdef OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION
	/* OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION is for RSA decrypt only */
	if (!sk_prov_check_uint_param(params,
				      OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION,
				      ctx->key, EVP_PKEY_RSA, 0) ||
	    !sk_prov_check_uint_param(params,
				      OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION,
				      ctx->key, EVP_PKEY_RSA_PSS, 0)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PARAM,
				 "Implicit rejection is not supported");
		return 0;
	}
#endif

	default_set_params_fn = (OSSL_FUNC_asym_cipher_set_ctx_params_fn *)
			sk_prov_get_default_asym_func(ctx->provctx,
				ctx->type,
				OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS);

	/* default_set_params_fn is optional */
	if (default_set_params_fn != NULL) {
		if (!default_set_params_fn(ctx->default_op_ctx, params)) {
			put_error_op_ctx(ctx,
					 SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
					 "default_set_params_fn failed");
			return 0;
		}
	}

	return 1;
}

static const OSSL_PARAM *sk_prov_asym_op_gettable_ctx_params(
				struct sk_prov_op_ctx *ctx,
				struct sk_prov_ctx *provctx, int pkey_type)
{
	OSSL_FUNC_asym_cipher_gettable_ctx_params_fn
						*default_gettable_params_fn;
	const OSSL_PARAM *params = NULL, *p;

	if (ctx == NULL || provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "pkey_type: %d", pkey_type);

	default_gettable_params_fn =
		(OSSL_FUNC_asym_cipher_gettable_ctx_params_fn *)
			sk_prov_get_default_asym_func(provctx, pkey_type,
				OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS);

	/* default_gettable_params_fn is optional */
	if (default_gettable_params_fn != NULL)
		params = default_gettable_params_fn(ctx->default_op_ctx,
						    provctx->default_provctx);

	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_ctx(provctx, "param: %s", p->key);

	return params;
}

static const OSSL_PARAM *sk_prov_asym_op_settable_ctx_params(
				struct sk_prov_op_ctx *ctx,
				struct sk_prov_ctx *provctx, int pkey_type)
{
	OSSL_FUNC_asym_cipher_settable_ctx_params_fn
						*default_settable_params_fn;
	const OSSL_PARAM *params = NULL, *p;

	if (ctx == NULL || provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "pkey_type: %d", pkey_type);

	default_settable_params_fn =
		(OSSL_FUNC_asym_cipher_settable_ctx_params_fn *)
			sk_prov_get_default_asym_func(provctx, pkey_type,
				OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS);

	/* default_settable_params_fn is optional */
	if (default_settable_params_fn != NULL)
		params = default_settable_params_fn(ctx->default_op_ctx,
						    provctx->default_provctx);

	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_ctx(provctx, "param: %s", p->key);

	return params;
}

static EVP_MD *sk_prov_asym_op_get_oaep_md(struct sk_prov_op_ctx *ctx)
{
	char mdprops[256], mdname[50];
	OSSL_PARAM ctx_params[] = {
		OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST,
				&mdname, sizeof(mdname)),
		OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS,
				&mdprops, sizeof(mdprops)),
		OSSL_PARAM_END
	};
	EVP_MD *md;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);

	if (!sk_prov_asym_op_get_ctx_params(ctx, ctx_params) ||
	    !OSSL_PARAM_modified(&ctx_params[0]) ||
	    !OSSL_PARAM_modified(&ctx_params[1])) {
		sk_debug_op_ctx(ctx, "sk_prov_asym_op_get_ctx_params failed");
		if (ctx->md != NULL) {
			sk_debug_op_ctx(ctx, "use digest from context: %s",
					EVP_MD_name(ctx->md));
			EVP_MD_up_ref(ctx->md);
			return ctx->md;
		}

		sk_debug_op_ctx(ctx, "use default");
		strcpy(mdname, SK_PROV_RSA_DEFAULT_MD);
		strcpy(mdprops, "");
	}

	md = EVP_MD_fetch((OSSL_LIB_CTX *)ctx->provctx->c_get_libctx(
							ctx->provctx->handle),
			  mdname, mdprops[0] != '\0' ? mdprops : ctx->propq);
	if (md == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
				 "EVP_MD_fetch failed to fetch '%s' using "
				 "property query '%s'", mdname,
				 mdprops[0] != '\0' ? mdprops :
					ctx->propq != NULL ? ctx->propq : "");
		return NULL;
	}

	sk_debug_op_ctx(ctx, "md: %s", EVP_MD_name(md));
	return md;
}

static EVP_MD *sk_prov_asym_op_get_mgf_md(struct sk_prov_op_ctx *ctx)
{
	char mdprops[256], mdname[50];
	OSSL_PARAM ctx_params[] = {
		OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST,
				&mdname, sizeof(mdname)),
		OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS,
				&mdprops, sizeof(mdprops)),
		OSSL_PARAM_END
	};
	EVP_MD *md;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);

	if (!sk_prov_asym_op_get_ctx_params(ctx, ctx_params) ||
	    !OSSL_PARAM_modified(&ctx_params[0]) ||
	    !OSSL_PARAM_modified(&ctx_params[1])) {
		sk_debug_op_ctx(ctx, "sk_prov_asym_op_get_ctx_params failed, "
				"using oaep digest");
		return sk_prov_asym_op_get_oaep_md(ctx);
	}

	md = EVP_MD_fetch((OSSL_LIB_CTX *)ctx->provctx->c_get_libctx(
							ctx->provctx->handle),
			  mdname, mdprops[0] != '\0' ? mdprops : ctx->propq);
	if (md == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
				 "EVP_MD_fetch failed to fetch '%s' using "
				 "property query '%s'", mdname,
				 mdprops[0] != '\0' ? mdprops :
					ctx->propq != NULL ? ctx->propq : "");
		return NULL;
	}

	sk_debug_op_ctx(ctx, "md: %s", EVP_MD_name(md));
	return md;
}

static int sk_prov_asym_op_get_oaep_label(struct sk_prov_op_ctx *ctx,
					  unsigned char **label)
{
	OSSL_PARAM ctx_params[] = {
		OSSL_PARAM_octet_ptr(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL,
				label, 0),
		OSSL_PARAM_END
	};
	int oaep_label_len;


	sk_debug_op_ctx(ctx, "ctx: %p", ctx);

	if (!sk_prov_asym_op_get_ctx_params(ctx, ctx_params) ||
	    !OSSL_PARAM_modified(&ctx_params[0])) {
		put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
				 "sk_prov_asym_op_get_ctx_params failed to "
				 "get OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL");
		return -1;
	}

	oaep_label_len = ctx_params[0].return_size;
	sk_debug_op_ctx(ctx, "oaep_label: %p oaep_label_len: %d", *label,
			oaep_label_len);

	return oaep_label_len;
}

static int sk_prov_parse_padding(const char *padding)
{
	if (strcmp(padding, OSSL_PKEY_RSA_PAD_MODE_NONE) == 0)
		return RSA_NO_PADDING;
	if (strcmp(padding, OSSL_PKEY_RSA_PAD_MODE_PKCSV15) == 0)
		return RSA_PKCS1_PADDING;
	if (strcmp(padding, OSSL_PKEY_RSA_PAD_MODE_OAEP) == 0)
		return RSA_PKCS1_OAEP_PADDING;
	if (strcmp(padding, OSSL_PKEY_RSA_PAD_MODE_X931) == 0)
		return RSA_X931_PADDING;
	if (strcmp(padding, OSSL_PKEY_RSA_PAD_MODE_PSS) == 0)
		return RSA_PKCS1_PSS_PADDING;

	return -1;
}

static int sk_prov_asym_op_get_padding(struct sk_prov_op_ctx *ctx)
{
	char padding[50];
	OSSL_PARAM ctx_params[] = {
		OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_PAD_MODE,
				&padding, sizeof(padding)),
		OSSL_PARAM_END
	};

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);

	if (!sk_prov_asym_op_get_ctx_params(ctx, ctx_params) ||
	    !OSSL_PARAM_modified(&ctx_params[0])) {
		put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
				 "sk_prov_asym_op_get_ctx_params failed to "
				 "get OSSL_PKEY_PARAM_PAD_MODE");
		return -1;
	}

	sk_debug_op_ctx(ctx, "padding: %s", padding);

	return sk_prov_parse_padding(padding);
}

static int sk_prov_asym_op_encrypt_init(void *vctx, void *vkey,
					const OSSL_PARAM params[])
{
	OSSL_FUNC_asym_cipher_encrypt_init_fn *default_encrypt_init_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_key *key = vkey;
	const OSSL_PARAM *p;

	if (ctx == NULL || key == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p", ctx, key);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

	default_encrypt_init_fn = (OSSL_FUNC_asym_cipher_encrypt_init_fn *)
				sk_prov_get_default_asym_func(ctx->provctx,
					ctx->type,
					OSSL_FUNC_ASYM_CIPHER_ENCRYPT_INIT);
	if (default_encrypt_init_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default encrypt_init_fn");
		return 0;
	}

	if (!sk_prov_op_init(ctx, key, EVP_PKEY_OP_ENCRYPT)) {
		sk_debug_op_ctx(ctx, "ERROR: sk_prov_op_init failed");
		return 0;
	}

	if (!default_encrypt_init_fn(ctx->default_op_ctx, key->default_key,
				     params)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_encrypt_init_fn failed");
		return 0;
	}

	return 1;
}

static int sk_prov_asym_op_decrypt_init(void *vctx, void *vkey,
					const OSSL_PARAM params[])
{
	OSSL_FUNC_asym_cipher_decrypt_init_fn *default_decrypt_init_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_key *key = vkey;
	const OSSL_PARAM *p;
#ifdef OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION
	unsigned int implicit_rejection = 0;
	OSSL_PARAM set_params[] = {
		OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION,
				&implicit_rejection),
		OSSL_PARAM_END
	};
#endif

	if (ctx == NULL || key == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p", ctx, key);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

#ifdef OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION
	/* OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION is for RSA decrypt only */
	if (!sk_prov_check_uint_param(params,
				      OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION,
				      key, EVP_PKEY_RSA, 0) ||
	    !sk_prov_check_uint_param(params,
				      OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION,
				      key, EVP_PKEY_RSA_PSS, 0)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PARAM,
				 "Implicit rejection is not supported");
		return 0;
	}
#endif

	default_decrypt_init_fn = (OSSL_FUNC_asym_cipher_decrypt_init_fn *)
				sk_prov_get_default_asym_func(ctx->provctx,
					ctx->type,
					OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT);
	if (default_decrypt_init_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default decrypt_init_fn");
		return 0;
	}

	if (!sk_prov_op_init(ctx, key, EVP_PKEY_OP_DECRYPT)) {
		sk_debug_op_ctx(ctx, "ERROR: sk_prov_op_init failed");
		return 0;
	}

	if (!default_decrypt_init_fn(ctx->default_op_ctx, key->default_key,
				     params)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_decrypt_init_fn failed");
		return 0;
	}

#ifdef OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION
	if ((key->type == EVP_PKEY_RSA || key->type == EVP_PKEY_RSA_PSS) &&
	    key->secure_key != NULL) {
		/*
		 * By default, implicit rejection is enabled for the default
		 * provider. We currently do not support implicit rejection with
		 * secure keys, so disable implicit rejection in the default
		 * provider operation context to report its status correctly
		 * with get-params.
		 */
		implicit_rejection = 0;
		if (!sk_prov_asym_op_set_ctx_params(ctx, set_params)) {
			sk_debug_op_ctx(ctx,
					"ERROR: sk_prov_asym_op_set_ctx_params "
					"failed");
			return 0;
		}
	}
#endif

	return 1;
}

static int sk_prov_asym_op_encrypt(void *vctx,
				   unsigned char *out, size_t *outlen,
				   size_t outsize, const unsigned char *in,
				   size_t inlen)
{
	OSSL_FUNC_asym_cipher_encrypt_fn *default_encrypt_fn;
	struct sk_prov_op_ctx *ctx = vctx;

	if (ctx == NULL || in == NULL || outlen == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p inlen: %lu outsize: %lu",
			ctx, ctx->key, inlen, outsize);

	default_encrypt_fn = (OSSL_FUNC_asym_cipher_encrypt_fn *)
			sk_prov_get_default_asym_func(ctx->provctx,
				ctx->type, OSSL_FUNC_ASYM_CIPHER_ENCRYPT);
	if (default_encrypt_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default encrypt_fn");
		return 0;
	}

	if (!default_encrypt_fn(ctx->default_op_ctx, out, outlen, outsize,
				in, inlen)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_encrypt_fn failed");
		return 0;
	}

	sk_debug_op_ctx(ctx, "outlen: %lu", *outlen);

	return 1;
}

static int sk_prov_asym_op_decrypt(struct sk_prov_op_ctx *ctx,
				   unsigned char *out, size_t *outlen,
				   size_t outsize, const unsigned char *in,
				   size_t inlen)
{
	OSSL_FUNC_asym_cipher_decrypt_fn *default_decrypt_fn;

	if (ctx == NULL || in == NULL || outlen == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p inlen: %lu outsize: %lu",
			ctx, ctx->key, inlen, outsize);

	default_decrypt_fn = (OSSL_FUNC_asym_cipher_decrypt_fn *)
			sk_prov_get_default_asym_func(ctx->provctx,
				ctx->type, OSSL_FUNC_ASYM_CIPHER_DECRYPT);
	if (default_decrypt_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default decrypt_fn");
		return 0;
	}

	if (!default_decrypt_fn(ctx->default_op_ctx, out, outlen, outsize,
				in, inlen)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_decrypt_fn failed");
		return 0;
	}

	sk_debug_op_ctx(ctx, "outlen: %lu", *outlen);

	return 1;
}

static struct sk_prov_op_ctx *sk_prov_sign_op_newctx(
					struct sk_prov_ctx *provctx,
					const char *propq,
					int pkey_type)
{
	OSSL_FUNC_signature_freectx_fn *default_freectx_fn;
	OSSL_FUNC_signature_newctx_fn *default_newctx_fn;
	struct sk_prov_op_ctx *ctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "propq: %s pkey_type: %d",
		     propq != NULL ? propq : "", pkey_type);

	default_newctx_fn = (OSSL_FUNC_signature_newctx_fn *)
			sk_prov_get_default_sign_func(provctx, pkey_type,
					OSSL_FUNC_SIGNATURE_NEWCTX);
	if (default_newctx_fn == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
			      "no default newctx_fn");
		return NULL;
	}

	default_freectx_fn = (OSSL_FUNC_signature_freectx_fn *)
			sk_prov_get_default_sign_func(provctx, pkey_type,
					OSSL_FUNC_SIGNATURE_FREECTX);
	if (default_freectx_fn == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
			      "no default freectx_fn");
		return NULL;
	}

	ctx = sk_prov_op_newctx(provctx, propq, pkey_type);
	if (ctx == NULL) {
		sk_debug_ctx(provctx, "ERROR: sk_prov_op_newctx failed");
		return NULL;
	}

	ctx->default_op_ctx = default_newctx_fn(provctx->default_provctx,
						propq);
	if (ctx->default_op_ctx == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
			      "default_newctx_fn failed");
		sk_prov_op_freectx(ctx);
		return NULL;
	}
	ctx->default_op_ctx_free = default_freectx_fn;

	sk_debug_ctx(provctx, "ctx: %p", ctx);
	return ctx;
}

static void *sk_prov_sign_op_dupctx(void *vctx)
{
	OSSL_FUNC_signature_dupctx_fn *default_dupctx_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_op_ctx *new_ctx;

	if (ctx == NULL)
		return NULL;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);

	default_dupctx_fn = (OSSL_FUNC_signature_dupctx_fn *)
			sk_prov_get_default_sign_func(ctx->provctx,
				ctx->type, OSSL_FUNC_SIGNATURE_DUPCTX);
	if (default_dupctx_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default dupctx_fn");
		return NULL;
	}

	new_ctx = sk_prov_op_dupctx(ctx);
	if (new_ctx == NULL) {
		sk_debug_op_ctx(ctx, "ERROR: sk_prov_op_dupctx failed");
		return NULL;
	}

	new_ctx->default_op_ctx = default_dupctx_fn(ctx->default_op_ctx);
	if (new_ctx->default_op_ctx == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_dupctx_fn failed");
		sk_prov_op_freectx(new_ctx);
		return NULL;
	}

	sk_debug_op_ctx(ctx, "new_ctx: %p", new_ctx);
	return new_ctx;
}

static int sk_prov_sign_op_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
	OSSL_FUNC_signature_get_ctx_params_fn *default_get_params_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	const OSSL_PARAM *p;

	if (ctx == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

	default_get_params_fn = (OSSL_FUNC_signature_get_ctx_params_fn *)
			sk_prov_get_default_sign_func(ctx->provctx,
				ctx->type, OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS);

	/* default_get_params_fn is optional */
	if (default_get_params_fn != NULL) {
		if (!default_get_params_fn(ctx->default_op_ctx, params)) {
			put_error_op_ctx(ctx,
					 SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
					 "default_get_params_fn failed");
			return 0;
		}
	}

	return 1;
}

static int sk_prov_sign_op_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
	OSSL_FUNC_signature_set_ctx_params_fn *default_set_params_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	const OSSL_PARAM *p;

	if (ctx == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

#ifdef OSSL_SIGNATURE_PARAM_NONCE_TYPE
	/* OSSL_SIGNATURE_PARAM_NONCE_TYPE is used for EC sign ops only */
	if (!sk_prov_check_uint_param(params, OSSL_SIGNATURE_PARAM_NONCE_TYPE,
				      ctx->key, EVP_PKEY_EC, 0)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PARAM,
				 "Deterministic signature is not supported");
		return 0;
	}
#endif

	default_set_params_fn = (OSSL_FUNC_signature_set_ctx_params_fn *)
			sk_prov_get_default_sign_func(ctx->provctx,
				ctx->type, OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS);

	/* default_set_params_fn is optional */
	if (default_set_params_fn != NULL) {
		if (!default_set_params_fn(ctx->default_op_ctx, params)) {
			put_error_op_ctx(ctx,
					 SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
					 "default_set_params_fn failed");
			return 0;
		}
	}

	return 1;
}

static const OSSL_PARAM *sk_prov_sign_op_gettable_ctx_params(
				struct sk_prov_op_ctx *ctx,
				struct sk_prov_ctx *provctx, int pkey_type)
{
	OSSL_FUNC_signature_gettable_ctx_params_fn *default_gettable_params_fn;
	const OSSL_PARAM *params = NULL, *p;

	if (ctx == NULL || provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "pkey_type: %d", pkey_type);

	default_gettable_params_fn =
		(OSSL_FUNC_signature_gettable_ctx_params_fn *)
			sk_prov_get_default_sign_func(provctx, pkey_type,
				OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS);

	/* default_gettable_params_fn is optional */
	if (default_gettable_params_fn != NULL)
		params = default_gettable_params_fn(ctx->default_op_ctx,
						    provctx->default_provctx);

	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_ctx(provctx, "param: %s", p->key);

	return params;
}

static const OSSL_PARAM *sk_prov_sign_op_settable_ctx_params(
				struct sk_prov_op_ctx *ctx,
				struct sk_prov_ctx *provctx, int pkey_type)
{
	OSSL_FUNC_signature_settable_ctx_params_fn *default_settable_params_fn;
	const OSSL_PARAM *params = NULL, *p;

	if (ctx == NULL || provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "pkey_type: %d", pkey_type);

	default_settable_params_fn =
		(OSSL_FUNC_signature_settable_ctx_params_fn *)
			sk_prov_get_default_sign_func(provctx, pkey_type,
				OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS);

	/* default_settable_params_fn is optional */
	if (default_settable_params_fn != NULL)
		params = default_settable_params_fn(ctx->default_op_ctx,
						    provctx->default_provctx);

	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_ctx(provctx, "param: %s", p->key);

	return params;
}

static int sk_prov_sign_op_get_ctx_md_params(void *vctx, OSSL_PARAM params[])
{
	OSSL_FUNC_signature_get_ctx_md_params_fn *default_get_md_params_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	const OSSL_PARAM *p;

	if (ctx == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

	default_get_md_params_fn = (OSSL_FUNC_signature_get_ctx_md_params_fn *)
			sk_prov_get_default_sign_func(ctx->provctx,
				ctx->type,
				OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS);

	/* default_get_md_params_fn is optional */
	if (default_get_md_params_fn != NULL) {
		if (!default_get_md_params_fn(ctx->default_op_ctx, params)) {
			put_error_op_ctx(ctx,
					 SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
					 "default_get_md_params_fn failed");
			return 0;
		}
	}

	return 1;
}

static int sk_prov_sign_op_set_ctx_md_params(void *vctx,
					     const OSSL_PARAM params[])
{
	OSSL_FUNC_signature_set_ctx_md_params_fn *default_set_md_params_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	const OSSL_PARAM *p;

	if (ctx == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

	default_set_md_params_fn = (OSSL_FUNC_signature_set_ctx_md_params_fn *)
			sk_prov_get_default_sign_func(ctx->provctx,
				ctx->type,
				OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS);

	/* default_set_md_params_fn is optional */
	if (default_set_md_params_fn != NULL) {
		if (!default_set_md_params_fn(ctx->default_op_ctx, params)) {
			put_error_op_ctx(ctx,
					 SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
					 "default_set_md_params_fn failed");
			return 0;
		}
	}

	/* Also set parameters in own MD context */
	if (ctx->mdctx)
		return EVP_MD_CTX_set_params(ctx->mdctx, params);

	return 1;
}

static const OSSL_PARAM *sk_prov_sign_op_gettable_ctx_md_params(
				struct sk_prov_op_ctx *ctx, int pkey_type)
{
	OSSL_FUNC_signature_gettable_ctx_md_params_fn
						*default_gettable_md_params_fn;
	const OSSL_PARAM *params = NULL, *p;

	if (ctx == NULL)
		return NULL;

	sk_debug_op_ctx(ctx, "pkey_type: %d", pkey_type);

	default_gettable_md_params_fn =
		(OSSL_FUNC_signature_gettable_ctx_md_params_fn *)
			sk_prov_get_default_sign_func(ctx->provctx, pkey_type,
				OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS);

	/* default_gettable_params_fn is optional */
	if (default_gettable_md_params_fn != NULL)
		params = default_gettable_md_params_fn(ctx->default_op_ctx);

	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

	return params;
}

static const OSSL_PARAM *sk_prov_sign_op_settable_ctx_md_params(
				struct sk_prov_op_ctx *ctx, int pkey_type)
{
	OSSL_FUNC_signature_settable_ctx_md_params_fn
						*default_settable_md_params_fn;
	const OSSL_PARAM *params = NULL, *p;

	if (ctx == NULL)
		return NULL;

	sk_debug_op_ctx(ctx, "pkey_type: %d", pkey_type);

	default_settable_md_params_fn =
		(OSSL_FUNC_signature_settable_ctx_md_params_fn *)
			sk_prov_get_default_sign_func(ctx->provctx, pkey_type,
				OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS);

	/* default_settable_md_params_fn is optional */
	if (default_settable_md_params_fn != NULL)
		params = default_settable_md_params_fn(ctx->default_op_ctx);

	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

	return params;
}

static EVP_MD *sk_prov_sign_op_get_md(struct sk_prov_op_ctx *ctx)
{
	char mdprops[256], mdname[50];
	OSSL_PARAM ctx_params[] = {
		OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST,
				&mdname, sizeof(mdname)),
		OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PROPERTIES,
				&mdprops, sizeof(mdprops)),
		OSSL_PARAM_END
	};
	EVP_MD *md;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);

	if (!sk_prov_sign_op_get_ctx_params(ctx, ctx_params) ||
	    !OSSL_PARAM_modified(&ctx_params[0]) ||
	    !OSSL_PARAM_modified(&ctx_params[1])) {
		sk_debug_op_ctx(ctx, "sk_prov_sign_op_get_ctx_params failed");
		if (ctx->md != NULL) {
			sk_debug_op_ctx(ctx, "use digest from context: %s",
					EVP_MD_name(ctx->md));
			EVP_MD_up_ref(ctx->md);
			return ctx->md;
		}

		sk_debug_op_ctx(ctx, "use default");
		strcpy(mdname, SK_PROV_RSA_DEFAULT_MD);
		strcpy(mdprops, "");
	}

	md = EVP_MD_fetch((OSSL_LIB_CTX *)ctx->provctx->c_get_libctx(
							ctx->provctx->handle),
			  mdname, mdprops[0] != '\0' ? mdprops : ctx->propq);
	if (md == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
				 "EVP_MD_fetch failed to fetch '%s' using "
				 "property query '%s'", mdname,
				 mdprops[0] != '\0' ? mdprops :
					ctx->propq != NULL ? ctx->propq : "");
		return NULL;
	}

	sk_debug_op_ctx(ctx, "md: %s", EVP_MD_name(md));
	return md;
}

static EVP_MD *sk_prov_sign_op_get_mgf_md(struct sk_prov_op_ctx *ctx)
{
	char mdprops[256], mdname[50];
	OSSL_PARAM ctx_params[] = {
		OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST,
				&mdname, sizeof(mdname)),
		OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_PROPERTIES,
				&mdprops, sizeof(mdprops)),
		OSSL_PARAM_END
	};
	EVP_MD *md;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);

	if (!sk_prov_sign_op_get_ctx_params(ctx, ctx_params) ||
	    !OSSL_PARAM_modified(&ctx_params[0]) ||
	    !OSSL_PARAM_modified(&ctx_params[1])) {
		sk_debug_op_ctx(ctx, "sk_prov_sign_op_get_ctx_params failed, "
				"using signature digest");
		return sk_prov_sign_op_get_md(ctx);
	}

	md = EVP_MD_fetch((OSSL_LIB_CTX *)ctx->provctx->c_get_libctx(
							ctx->provctx->handle),
			  mdname, mdprops[0] != '\0' ? mdprops : ctx->propq);
	if (md == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
				 "EVP_MD_fetch failed to fetch '%s' using "
				 "property query '%s'", mdname,
				 mdprops[0] != '\0' ? mdprops :
					ctx->propq != NULL ? ctx->propq : "");
		return NULL;
	}

	sk_debug_op_ctx(ctx, "md: %s", EVP_MD_name(md));
	return md;
}

static int sk_prov_sign_op_get_padding(struct sk_prov_op_ctx *ctx)
{
	char padding[50];
	OSSL_PARAM ctx_params[] = {
		OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_PAD_MODE,
				&padding, sizeof(padding)),
		OSSL_PARAM_END
	};

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);

	if (!sk_prov_sign_op_get_ctx_params(ctx, ctx_params) ||
	    !OSSL_PARAM_modified(&ctx_params[0])) {
		put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
				 "sk_prov_sign_op_get_ctx_params failed to "
				 "get OSSL_PKEY_PARAM_PAD_MODE");
		return -1;
	}

	sk_debug_op_ctx(ctx, "padding: %s", padding);
	return sk_prov_parse_padding(padding);
}

static int sk_prov_sign_op_get_pss_saltlen(struct sk_prov_op_ctx *ctx,
					   struct sk_prov_key *key,
					   EVP_MD *mgf_md)
{
	char saltlen[50];
	OSSL_PARAM ctx_params[] = {
		OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN,
				&saltlen, sizeof(saltlen)),
		OSSL_PARAM_END
	};
	int salt_len, rsa_bits, max_saltlen;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);

	if (!sk_prov_sign_op_get_ctx_params(ctx, ctx_params) ||
	    !OSSL_PARAM_modified(&ctx_params[0])) {
		put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
				 "sk_prov_sign_op_get_ctx_params failed to "
				 "get OSSL_SIGNATURE_PARAM_PSS_SALTLEN");
		return -1;
	}

	sk_debug_op_ctx(ctx, "saltlen: %s", saltlen);

	rsa_bits = sk_prov_keymgmt_get_bits(key);
	if (rsa_bits <= 0) {
		sk_debug_op_ctx(ctx,
			"ERROR: sk_prov_keymgmt_get_bits failed");
		return -1;
	}

	max_saltlen = rsa_bits / 8 - EVP_MD_size(mgf_md) - 2;

	if (strcmp(saltlen, OSSL_PKEY_RSA_PSS_SALT_LEN_DIGEST) == 0)
		salt_len = EVP_MD_size(mgf_md);
	else if (strcmp(saltlen, OSSL_PKEY_RSA_PSS_SALT_LEN_MAX) == 0)
		salt_len = max_saltlen;
	else if (strcmp(saltlen, OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO) == 0)
		salt_len = max_saltlen;
#ifdef OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO_DIGEST_MAX
	else if (strcmp(saltlen,
			OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO_DIGEST_MAX) == 0)
		salt_len = MIN(max_saltlen, EVP_MD_size(mgf_md));
#endif
	else
		salt_len = atoi(saltlen);

	if (salt_len > max_saltlen || salt_len < 0) {
		put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_SALTLEN,
				 "invalid salt len: %d", saltlen);
		return -1;
	}

	sk_debug_op_ctx(ctx, "salt_len: %d", salt_len);
	return salt_len;
}

static int sk_prov_sign_op_sign_init(void *vctx, void *vkey,
				     const OSSL_PARAM params[])
{
	OSSL_FUNC_signature_sign_init_fn *default_sign_init_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_key *key = vkey;
	const OSSL_PARAM *p;

	if (ctx == NULL || key == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p", ctx, key);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

#ifdef OSSL_SIGNATURE_PARAM_NONCE_TYPE
	/* OSSL_SIGNATURE_PARAM_NONCE_TYPE is used for EC sign ops only */
	if (!sk_prov_check_uint_param(params, OSSL_SIGNATURE_PARAM_NONCE_TYPE,
				      key, EVP_PKEY_EC, 0)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PARAM,
				 "Deterministic signature is not supported");
		return 0;
	}
#endif

	default_sign_init_fn = (OSSL_FUNC_signature_sign_init_fn *)
				sk_prov_get_default_sign_func(ctx->provctx,
					ctx->type,
					OSSL_FUNC_SIGNATURE_SIGN_INIT);
	if (default_sign_init_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default sign_init_fn");
		return 0;
	}

	if (!sk_prov_op_init(ctx, key, EVP_PKEY_OP_SIGN)) {
		sk_debug_op_ctx(ctx, "ERROR: sk_prov_op_init failed");
		return 0;
	}

	if (!default_sign_init_fn(ctx->default_op_ctx, key->default_key,
				  params)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_sign_init_fn failed");
		return 0;
	}

	return 1;
}

static int sk_prov_sign_op_verify_init(void *vctx, void *vkey,
				       const OSSL_PARAM params[])
{
	OSSL_FUNC_signature_verify_init_fn *default_verify_init_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_key *key = vkey;
	const OSSL_PARAM *p;

	if (ctx == NULL || key == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p", ctx, key);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

	default_verify_init_fn = (OSSL_FUNC_signature_verify_init_fn *)
			sk_prov_get_default_sign_func(ctx->provctx,
				ctx->type, OSSL_FUNC_SIGNATURE_VERIFY_INIT);
	if (default_verify_init_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default verify_init_fn");
		return 0;
	}

	if (!sk_prov_op_init(ctx, key, EVP_PKEY_OP_VERIFY)) {
		sk_debug_op_ctx(ctx, "ERROR: sk_prov_op_init failed");
		return 0;
	}

	if (!default_verify_init_fn(ctx->default_op_ctx, key->default_key,
				    params)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_verify_init_fn failed");
		return 0;
	}

	return 1;
}

static int sk_prov_sign_op_verify_recover_init(void *vctx, void *vkey,
					       const OSSL_PARAM params[])
{
	OSSL_FUNC_signature_verify_recover_init_fn
					*default_verify_recover_init_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_key *key = vkey;
	const OSSL_PARAM *p;

	if (ctx == NULL || key == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p", ctx, key);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

	default_verify_recover_init_fn =
		(OSSL_FUNC_signature_verify_recover_init_fn *)
			sk_prov_get_default_sign_func(ctx->provctx,
				ctx->type,
				OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT);
	if (default_verify_recover_init_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default verify_recover_init_fn");
		return 0;
	}

	if (!sk_prov_op_init(ctx, key, EVP_PKEY_OP_VERIFYRECOVER)) {
		sk_debug_op_ctx(ctx, "ERROR: sk_prov_op_init failed");
		return 0;
	}

	if (!default_verify_recover_init_fn(ctx->default_op_ctx,
					    key->default_key,
					    params)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_verify_recover_init_fn failed");
		return 0;
	}

	return 1;
}

static int sk_prov_sign_op_sign(struct sk_prov_op_ctx *ctx,
				unsigned char *sig, size_t *siglen,
				size_t sigsize,
				const unsigned char *tbs, size_t tbslen)
{
	OSSL_FUNC_signature_sign_fn *default_sign_fn;

	if (ctx == NULL || tbs == NULL || siglen == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p tbslen: %lu sigsize: %lu",
			ctx, ctx->key, tbslen, sigsize);

	default_sign_fn = (OSSL_FUNC_signature_sign_fn *)
			sk_prov_get_default_sign_func(ctx->provctx,
				ctx->type, OSSL_FUNC_SIGNATURE_SIGN);
	if (default_sign_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default sign_fn");
		return 0;
	}

	if (!default_sign_fn(ctx->default_op_ctx, sig, siglen, sigsize,
			     tbs, tbslen)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_sign_fn failed");
		return 0;
	}

	sk_debug_op_ctx(ctx, "siglen: %lu", *siglen);

	return 1;
}

static int sk_prov_sign_op_verify(void *vctx,
				  const unsigned char *sig, size_t siglen,
				  const unsigned char *tbs, size_t tbslen)
{
	OSSL_FUNC_signature_verify_fn *default_verify_fn;
	struct sk_prov_op_ctx *ctx = vctx;

	if (ctx == NULL || tbs == NULL || sig == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p tbslen: %lu siglen: %lu",
			ctx, ctx->key, tbslen, siglen);

	default_verify_fn = (OSSL_FUNC_signature_verify_fn *)
			sk_prov_get_default_sign_func(ctx->provctx,
				ctx->type, OSSL_FUNC_SIGNATURE_VERIFY);
	if (default_verify_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default verify_fn");
		return 0;
	}

	if (!default_verify_fn(ctx->default_op_ctx, sig, siglen, tbs, tbslen)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_verify_fn failed");
		return 0;
	}

	return 1;
}

static int sk_prov_sign_op_verify_recover(void *vctx,
					  unsigned char *rout, size_t *routlen,
					  size_t routsize,
					  const unsigned char *sig,
					  size_t siglen)
{
	OSSL_FUNC_signature_verify_recover_fn *default_verify_recover_fn;
	struct sk_prov_op_ctx *ctx = vctx;

	if (ctx == NULL || routlen == NULL || sig == NULL)
		return 0;

	sk_debug_op_ctx(ctx,
			"ctx: %p key: %p routsize: %lu siglen: %lu",
			ctx, ctx->key, routsize, siglen);

	default_verify_recover_fn = (OSSL_FUNC_signature_verify_recover_fn *)
			sk_prov_get_default_sign_func(ctx->provctx,
				ctx->type, OSSL_FUNC_SIGNATURE_VERIFY_RECOVER);
	if (default_verify_recover_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default verify_recover_fn");
		return 0;
	}

	if (!default_verify_recover_fn(ctx->default_op_ctx, rout, routlen,
				       routsize, sig, siglen)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_verify_recover_fn failed");
		return 0;
	}

	sk_debug_op_ctx(ctx, "routlen: %lu", *routlen);

	return 1;
}

static int sk_prov_sign_op_digest_sign_init(struct sk_prov_op_ctx *ctx,
					    const char *mdname,
					    struct sk_prov_key *key,
					    const OSSL_PARAM params[],
					  OSSL_FUNC_signature_sign_fn *sign_fn)
{
	OSSL_FUNC_signature_digest_sign_init_fn *default_digest_sign_init_fn;
	const OSSL_PARAM *p;

	if (ctx == NULL || key == NULL || sign_fn == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p mdname: %s key: %p", ctx,
			mdname != NULL ? mdname : "", key);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

#ifdef OSSL_SIGNATURE_PARAM_NONCE_TYPE
	/* OSSL_SIGNATURE_PARAM_NONCE_TYPE is used for EC sign ops only */
	if (!sk_prov_check_uint_param(params, OSSL_SIGNATURE_PARAM_NONCE_TYPE,
				      key, EVP_PKEY_EC, 0)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PARAM,
				 "Deterministic signature is not supported");
		return 0;
	}
#endif

	default_digest_sign_init_fn =
			(OSSL_FUNC_signature_digest_sign_init_fn *)
				sk_prov_get_default_sign_func(ctx->provctx,
					ctx->type,
					OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT);
	if (default_digest_sign_init_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default digest_sign_init_fn");
		return 0;
	}

	if (!sk_prov_op_init(ctx, key, EVP_PKEY_OP_SIGN)) {
		sk_debug_op_ctx(ctx, "ERROR: sk_prov_op_init failed");
		return 0;
	}

	if (!default_digest_sign_init_fn(ctx->default_op_ctx, mdname,
					 key->default_key, params)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_digest_sign_init_fn failed");
		return 0;
	}

	/* For clear key, the default provider has already handled it */
	if (ctx->key->secure_key == NULL)
		return 1;

	ctx->sign_fn = sign_fn;

	if (ctx->mdctx != NULL)
		EVP_MD_CTX_free(ctx->mdctx);
	ctx->mdctx = EVP_MD_CTX_new();
	if (ctx->mdctx == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_MALLOC_FAILED,
				 "EVP_MD_CTX_new failed");
		return 0;
	}

	if (ctx->md != NULL)
		EVP_MD_free(ctx->md);
	if (mdname != NULL)
		ctx->md = EVP_MD_fetch(
				(OSSL_LIB_CTX *)ctx->provctx->c_get_libctx(
							ctx->provctx->handle),
				mdname, ctx->propq);
	else
		ctx->md = sk_prov_sign_op_get_md(ctx);
	if (ctx->md == NULL) {
		sk_debug_op_ctx(ctx, "ERROR: Failed to get digest sign digest");
		EVP_MD_CTX_free(ctx->mdctx);
		ctx->mdctx = NULL;
		return 0;
	}

	return EVP_DigestInit_ex2(ctx->mdctx, ctx->md, params);
}

static int sk_prov_sign_op_digest_sign_update(void *vctx,
					      const unsigned char *data,
					      size_t datalen)
{
	OSSL_FUNC_signature_digest_sign_update_fn
					*default_digest_sign_update_fn;
	struct sk_prov_op_ctx *ctx = vctx;

	if (ctx == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p datalen: %lu", ctx, ctx->key,
			datalen);

	if (ctx->key == NULL || ctx->operation != EVP_PKEY_OP_SIGN) {
		put_error_op_ctx(ctx, SK_PROV_ERR_OPRATION_NOT_INITIALIZED,
				 "digest sign operation not initialized");
		return 0;
	}

	/* For secure key, don't pass it to the default provider */
	if (ctx->key->secure_key != NULL)
		goto secure_key;

	default_digest_sign_update_fn =
			(OSSL_FUNC_signature_digest_sign_update_fn *)
				sk_prov_get_default_sign_func(ctx->provctx,
					ctx->type,
					OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE);
	if (default_digest_sign_update_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default digest_sign_update_fn");
		return 0;
	}

	if (!default_digest_sign_update_fn(ctx->default_op_ctx, data,
					   datalen)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_digest_sign_update_fn failed");
		return 0;
	}

	return 1;

secure_key:
	if (ctx->mdctx == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_OPRATION_NOT_INITIALIZED,
				 "digest sign operation not initialized");
		return 0;
	}

	return EVP_DigestUpdate(ctx->mdctx, data, datalen);
}

static int sk_prov_sign_op_digest_sign_final(void *vctx,
					     unsigned char *sig,
					     size_t *siglen, size_t sigsize)
{
	OSSL_FUNC_signature_digest_sign_final_fn *default_digest_sign_final_fn;
	unsigned char digest[EVP_MAX_MD_SIZE];
	struct sk_prov_op_ctx *ctx = vctx;
	unsigned int dlen = 0;

	if (ctx == NULL || siglen == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p sigsize: %lu", ctx, ctx->key,
			sigsize);

	if (ctx->key == NULL || ctx->operation != EVP_PKEY_OP_SIGN) {
		put_error_op_ctx(ctx, SK_PROV_ERR_OPRATION_NOT_INITIALIZED,
				 "digest sign operation not initialized");
		return 0;
	}

	/* For secure key, don't pass it to the default provider */
	if (ctx->key->secure_key != NULL)
		goto secure_key;

	default_digest_sign_final_fn =
			(OSSL_FUNC_signature_digest_sign_final_fn *)
				sk_prov_get_default_sign_func(ctx->provctx,
					ctx->type,
					OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL);
	if (default_digest_sign_final_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default digest_sign_final_fn");
		return 0;
	}

	if (!default_digest_sign_final_fn(ctx->default_op_ctx, sig, siglen,
					  sigsize)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_digest_sign_final_fn failed");
		return 0;
	}

	sk_debug_op_ctx(ctx, "siglen: %lu", *siglen);
	return 1;

secure_key:
	if (ctx->mdctx == NULL || ctx->sign_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_OPRATION_NOT_INITIALIZED,
				 "digest sign operation not initialized");
		return 0;
	}

	if (sig != NULL) {
		if (!EVP_DigestFinal_ex(ctx->mdctx, digest, &dlen)) {
			sk_debug_op_ctx(ctx,
					"ERROR: EVP_DigestFinal_ex failed");
			return 0;
		}
	}

	if (!ctx->sign_fn(ctx, sig, siglen, sigsize, digest, (size_t)dlen)) {
		sk_debug_op_ctx(ctx, "ERROR: sign_fn failed");
		return 0;
	}

	sk_debug_op_ctx(ctx, "siglen: %lu", *siglen);
	return 1;
}

static int sk_prov_sign_op_digest_verify_init(void *vctx,
					      const char *mdname,
					      void *vkey,
					      const OSSL_PARAM params[])
{
	OSSL_FUNC_signature_digest_verify_init_fn
					*default_digest_verify_init_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_key *key = vkey;
	const OSSL_PARAM *p;

	if (ctx == NULL || key == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p mdname: %s key: %p", ctx,
			mdname != NULL ? mdname : "", key);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

	default_digest_verify_init_fn =
			(OSSL_FUNC_signature_digest_verify_init_fn *)
				sk_prov_get_default_sign_func(ctx->provctx,
					ctx->type,
					OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT);
	if (default_digest_verify_init_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default digest_verify_init_fn");
		return 0;
	}

	if (!sk_prov_op_init(ctx, key, EVP_PKEY_OP_VERIFY)) {
		sk_debug_op_ctx(ctx, "ERROR: sk_prov_op_init failed");
		return 0;
	}

	if (!default_digest_verify_init_fn(ctx->default_op_ctx, mdname,
					 key->default_key, params)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_digest_verify_init_fn failed");
		return 0;
	}

	return 1;
}

static int sk_prov_sign_op_digest_verify_update(void *vctx,
						const unsigned char *data,
						size_t datalen)
{
	OSSL_FUNC_signature_digest_verify_update_fn
					*default_digest_verify_update_fn;
	struct sk_prov_op_ctx *ctx = vctx;

	if (ctx == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p datalen: %lu", ctx, ctx->key,
			datalen);

	default_digest_verify_update_fn =
		(OSSL_FUNC_signature_digest_verify_update_fn *)
			sk_prov_get_default_sign_func(ctx->provctx, ctx->type,
				OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE);
	if (default_digest_verify_update_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default digest_verify_update_fn");
		return 0;
	}

	if (!default_digest_verify_update_fn(ctx->default_op_ctx,
					     data, datalen)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_digest_verify_update_fn failed");
		return 0;
	}

	return 1;
}

static int sk_prov_sign_op_digest_verify_final(void *vctx,
					       const unsigned char *sig,
					       size_t siglen)
{
	OSSL_FUNC_signature_digest_verify_final_fn
					*default_digest_verify_final_fn;
	struct sk_prov_op_ctx *ctx = vctx;

	if (ctx == NULL || sig == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p siglen: %lu", ctx, ctx->key,
			siglen);

	default_digest_verify_final_fn =
		(OSSL_FUNC_signature_digest_verify_final_fn *)
			sk_prov_get_default_sign_func(ctx->provctx, ctx->type,
				OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL);
	if (default_digest_verify_final_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default digest_verify_final_fn");
		return 0;
	}

	if (!default_digest_verify_final_fn(ctx->default_op_ctx, sig, siglen)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_digest_verify_final_fn failed");
		return 0;
	}

	return 1;
}


static void sk_prov_keymgmt_upref(struct sk_prov_key *key)
{
	sk_debug_key(key, "key: %p", key);

	key->ref_count++;

	sk_debug_key(key, "ref_count: %u", key->ref_count);
}

static unsigned int sk_prov_keymgmt_downref(struct sk_prov_key *key)
{
	sk_debug_key(key, "key: %p ", key);

	if (key->ref_count > 0)
		key->ref_count--;

	sk_debug_key(key, "ref_count: %u", key->ref_count);

	return key->ref_count;
}

static struct sk_prov_key *sk_prov_keymgmt_new(struct sk_prov_ctx *provctx,
					       int type)
{
	OSSL_FUNC_keymgmt_new_fn *default_new_fn;
	struct sk_prov_key *key;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p type: %d", provctx,
		     type);

	default_new_fn = (OSSL_FUNC_keymgmt_new_fn *)
			sk_prov_get_default_keymgmt_func(provctx, type,
						OSSL_FUNC_KEYMGMT_NEW);
	if (default_new_fn == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
			      "no default new_fn");
		return NULL;
	}

	key = OPENSSL_zalloc(sizeof(struct sk_prov_key));
	if (key == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_MALLOC_FAILED,
			      "OPENSSL_zalloc failed");
		return NULL;
	}

	key->provctx = provctx;
	key->type = type;

	key->default_key = default_new_fn(provctx->default_provctx);
	if (key->default_key == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
			      "default_new_fn failed");
		OPENSSL_free(key);
		return NULL;
	}

	sk_prov_keymgmt_upref(key);

	sk_debug_ctx(provctx, "key: %p", key);

	return key;
}

static void sk_prov_keymgmt_free(void *vkey)
{
	OSSL_FUNC_keymgmt_free_fn *default_free_fn;
	struct sk_prov_key *key = vkey;

	if (key == NULL)
		return;

	sk_debug_key(key, "key: %p", key);

	if (sk_prov_keymgmt_downref(key) > 0)
		return;

	sk_debug_key(key, "free key: %p", key);

	default_free_fn = (OSSL_FUNC_keymgmt_free_fn *)
			sk_prov_get_default_keymgmt_func(key->provctx,
					key->type, OSSL_FUNC_KEYMGMT_FREE);
	if (default_free_fn == NULL)
		sk_debug_key(key, "no default free_fn");
	else
		default_free_fn(key->default_key);

	if (key->secure_key != NULL)
		OPENSSL_free(key->secure_key);
	OPENSSL_free(key);
}

static int sk_prov_keymgmt_match(const void *vkey1, const void *vkey2,
				 int selection)
{
	OSSL_FUNC_keymgmt_match_fn *default_match_fn;
	const struct sk_prov_key *key1 = vkey1;
	const struct sk_prov_key *key2 = vkey2;

	if (key1 == NULL || key2 == NULL)
		return 0;

	sk_debug_key(key1, "key1: %p key2: %p", key1, key2);

	default_match_fn = (OSSL_FUNC_keymgmt_match_fn *)
			sk_prov_get_default_keymgmt_func(key1->provctx,
					key1->type, OSSL_FUNC_KEYMGMT_MATCH);
	if (default_match_fn == NULL) {
		put_error_key(key1, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
			      "no default match_fn");
		return 0;
	}

	if (key1->type != key2->type)
		return 0;

	if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) {
		/* match everything except private key */
		return default_match_fn(key1->default_key, key2->default_key,
					selection &
					    (~OSSL_KEYMGMT_SELECT_PRIVATE_KEY));
	}

	if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) {
		if (key1->secure_key_size != key2->secure_key_size)
			return 0;
		if (key1->secure_key_size > 0) {
			if (memcmp(key1->secure_key, key2->secure_key,
				   key1->secure_key_size) != 0)
				return 0;
			selection &= (~OSSL_KEYMGMT_SELECT_PRIVATE_KEY);
		}
	}

	return default_match_fn(key1->default_key, key2->default_key,
				selection);
}

static int sk_prov_keymgmt_validate(const void *vkey,
				    int selection, int checktype)
{
	OSSL_FUNC_keymgmt_validate_fn *default_validate_fn;
	const struct sk_prov_key *key = vkey;
	int default_selection = selection;

	if (key == NULL)
		return 0;

	sk_debug_key(key, "key: %p selection: %x checktype: %x", key,
		     selection, checktype);

	default_validate_fn = (OSSL_FUNC_keymgmt_validate_fn *)
			sk_prov_get_default_keymgmt_func(key->provctx,
					key->type, OSSL_FUNC_KEYMGMT_VALIDATE);
	if (default_validate_fn == NULL) {
		put_error_key(key, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
			      "no default validate_fn");
		return 0;
	}

	/* A secure key doesn't have the private parts in the default key */
	if (key->secure_key != NULL)
		default_selection &= (~OSSL_KEYMGMT_SELECT_PRIVATE_KEY);

	return default_validate_fn(key->default_key, default_selection,
				   checktype);
}

static int sk_prov_keymgmt_get_params(void *vkey, OSSL_PARAM params[])
{
	OSSL_FUNC_keymgmt_get_params_fn *default_get_params_fn;
	struct sk_prov_key *key = vkey;
	OSSL_PARAM *p;

	if (key == NULL)
		return 0;

	sk_debug_key(key, "key: %p", key);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_key(key, "param: %s", p->key);

	default_get_params_fn = (OSSL_FUNC_keymgmt_get_params_fn *)
			sk_prov_get_default_keymgmt_func(key->provctx,
				key->type, OSSL_FUNC_KEYMGMT_GET_PARAMS);

	/* default_get_params_fn is optional */
	if (default_get_params_fn != NULL) {
		if (!default_get_params_fn(key->default_key, params)) {
			put_error_key(key, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				      "default_get_params_fn failed");
			return 0;
		}
	}

	if (key->secure_key == NULL)
		return 1;

	p = OSSL_PARAM_locate(params, SK_PROV_PKEY_PARAM_SK_BLOB);
	if (p != NULL && !OSSL_PARAM_set_octet_string(p, key->secure_key,
						      key->secure_key_size)) {
		put_error_key(key, SK_PROV_ERR_INTERNAL_ERROR,
			      "OSSL_PARAM_set_octet_string failed");
		return 0;
	}
	p = OSSL_PARAM_locate(params, SK_PROV_PKEY_PARAM_SK_FUNCS);
	if (p != NULL && !OSSL_PARAM_set_octet_ptr(p, key->funcs,
						   sizeof(struct sk_funcs))) {
		put_error_key(key, SK_PROV_ERR_INTERNAL_ERROR,
			      "OSSL_PARAM_set_octet_ptr failed");
		return 0;
	}
	p = OSSL_PARAM_locate(params, SK_PROV_PKEY_PARAM_SK_PRIVATE);
	if (p != NULL && !OSSL_PARAM_set_octet_ptr(p, key->private, 0)) {
		put_error_key(key, SK_PROV_ERR_INTERNAL_ERROR,
			      "OSSL_PARAM_set_octet_ptr failed");
		return 0;
	}

	return 1;
}


static int sk_prov_keymgmt_set_params(void *vkey, const OSSL_PARAM params[])
{
	OSSL_FUNC_keymgmt_set_params_fn *default_set_params_fn;
	struct sk_prov_key *key = vkey;
	const OSSL_PARAM *p;
	size_t len;

	if (key == NULL)
		return 0;

	sk_debug_key(key, "key: %p", key);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_key(key, "param: %s",  p->key);

	default_set_params_fn = (OSSL_FUNC_keymgmt_set_params_fn *)
			sk_prov_get_default_keymgmt_func(key->provctx,
				key->type, OSSL_FUNC_KEYMGMT_SET_PARAMS);

	/* default_set_params_fn is optional */
	if (default_set_params_fn != NULL) {
		if (!default_set_params_fn(key->default_key, params)) {
			put_error_key(key, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				      "default_set_params_fn failed");
			return 0;
		}
	}

	if (key->secure_key == NULL)
		return 1;

	p = OSSL_PARAM_locate_const(params, SK_PROV_PKEY_PARAM_SK_FUNCS);
	if (p != NULL && !OSSL_PARAM_get_octet_string_ptr(p,
				(const void **)&key->funcs, &len)) {
		put_error_key(key, SK_PROV_ERR_INTERNAL_ERROR,
			      "OSSL_PARAM_get_octet_string_ptr failed");
		return 0;
	}

	p = OSSL_PARAM_locate_const(params, SK_PROV_PKEY_PARAM_SK_PRIVATE);
	if (p != NULL && !OSSL_PARAM_get_octet_string_ptr(p,
				(const void **)&key->private, &len)) {
		put_error_key(key, SK_PROV_ERR_INTERNAL_ERROR,
			      "OSSL_PARAM_get_octet_string_ptr failed");
		return 0;
	}

	return 1;
}

#define SK_PROV_SECURE_KEY_FUNC_PARMS					\
	OSSL_PARAM_octet_ptr(SK_PROV_PKEY_PARAM_SK_FUNCS, NULL, 0),	\
	OSSL_PARAM_octet_ptr(SK_PROV_PKEY_PARAM_SK_PRIVATE, NULL, 0)

#define SK_PROV_SECURE_KEY_PARMS					\
	OSSL_PARAM_octet_string(SK_PROV_PKEY_PARAM_SK_BLOB, NULL, 0),	\
	SK_PROV_SECURE_KEY_FUNC_PARMS


static const OSSL_PARAM sk_prov_key_settable_params[] = {
	SK_PROV_SECURE_KEY_FUNC_PARMS,
	OSSL_PARAM_END
};

static const OSSL_PARAM sk_prov_key_gettable_params[] = {
	SK_PROV_SECURE_KEY_PARMS,
	OSSL_PARAM_END
};

static const OSSL_PARAM *sk_prov_keymgmt_gettable_params(
				struct sk_prov_ctx *provctx, int pkey_type)
{
	OSSL_FUNC_keymgmt_gettable_params_fn *default_gettable_params_fn;
	const OSSL_PARAM *default_parms = NULL, *params, *p;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "pkey_type: %d", pkey_type);

	params = sk_prov_get_cached_params(provctx, pkey_type,
					   SK_CONF_CACHED_PARAMS_OP_KEY_GET, 0);
	if (params != NULL) {
		for (p = params; p != NULL && p->key != NULL; p++)
			sk_debug_ctx(provctx, "param: %s", p->key);
		return params;
	}

	default_gettable_params_fn = (OSSL_FUNC_keymgmt_gettable_params_fn *)
			sk_prov_get_default_keymgmt_func(provctx, pkey_type,
					OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS);

	/* default_gettable_params_fn is optional */
	if (default_gettable_params_fn != NULL)
		default_parms =
			default_gettable_params_fn(provctx->default_provctx);

	return sk_prov_cached_params_build(provctx, pkey_type,
					   SK_CONF_CACHED_PARAMS_OP_KEY_GET, 0,
					   default_parms,
					   sk_prov_key_gettable_params);
}

static const OSSL_PARAM *sk_prov_keymgmt_settable_params(
				struct sk_prov_ctx *provctx, int pkey_type)
{
	OSSL_FUNC_keymgmt_settable_params_fn *default_settable_params_fn;
	const OSSL_PARAM *default_parms = NULL, *params, *p;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "pkey_type: %d", pkey_type);

	params = sk_prov_get_cached_params(provctx, pkey_type,
					   SK_CONF_CACHED_PARAMS_OP_KEY_SET, 0);
	if (params != NULL) {
		for (p = params; p != NULL && p->key != NULL; p++)
			sk_debug_ctx(provctx, "param: %s", p->key);
		return params;
	}

	default_settable_params_fn = (OSSL_FUNC_keymgmt_settable_params_fn *)
			sk_prov_get_default_keymgmt_func(provctx, pkey_type,
					OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS);

	/* default_settable_params_fn is optional */
	if (default_settable_params_fn != NULL)
		default_parms =
			default_settable_params_fn(provctx->default_provctx);

	return sk_prov_cached_params_build(provctx, pkey_type,
					   SK_CONF_CACHED_PARAMS_OP_KEY_SET, 0,
					   default_parms,
					   sk_prov_key_settable_params);
}

static int sk_prov_keymgmt_has(const void *vkey, int selection)
{
	OSSL_FUNC_keymgmt_has_fn *default_has_fn;
	const struct sk_prov_key *key = vkey;
	int default_selection = selection;

	if (key == NULL)
		return 0;

	sk_debug_key(key, "key: %p selection: %x", key,
		     selection);

	default_has_fn = (OSSL_FUNC_keymgmt_has_fn *)
			sk_prov_get_default_keymgmt_func(key->provctx,
					key->type, OSSL_FUNC_KEYMGMT_HAS);
	if (default_has_fn == NULL) {
		put_error_key(key, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
			      "no default has_fn");
		return 0;
	}

	/* A secure key doesn't have the private parts in the default key */
	if (key->secure_key != NULL)
		default_selection &= (~OSSL_KEYMGMT_SELECT_PRIVATE_KEY);

	return default_has_fn(key->default_key, default_selection);
}

struct sk_prov_export_cb {
	struct sk_prov_key *key;
	OSSL_CALLBACK *param_callback;
	void *cbarg;
};

static int sk_prov_keymgmt_export_cb(const OSSL_PARAM params[], void *arg)
{
	struct sk_prov_export_cb *cb_data = arg;
	OSSL_PARAM *np, *new_params;
	struct sk_prov_key *key;
	const OSSL_PARAM *p;
	int rc, count, i;

	if (cb_data == NULL)
		return 0;

	key = cb_data->key;

	sk_debug_key(key, "key: %p", key);

	for (count = 0, p = params; p != NULL && p->key != NULL; p++, count++)
		;
	count += 3 + 1; /* 3 addl params plus end marker */

	new_params = OPENSSL_zalloc(count * sizeof(OSSL_PARAM));
	if (new_params == NULL) {
		put_error_key(key, SK_PROV_ERR_MALLOC_FAILED,
			      "OPENSSL_zalloc failed");
		return 0;
	}

	for (i = 0, p = params; p != NULL && p->key != NULL; p++, i++) {
		sk_debug_key(key, "param: key: %s", p->key);
		new_params[i] = *p;
	}

	np = &new_params[i++];
	*np = OSSL_PARAM_construct_octet_string(SK_PROV_PKEY_PARAM_SK_BLOB,
						key->secure_key,
						key->secure_key_size);
	sk_debug_key(key, "param: key: %s", np->key);

	np = &new_params[i++];
	*np = OSSL_PARAM_construct_octet_ptr(SK_PROV_PKEY_PARAM_SK_FUNCS,
					     (void **)key->funcs,
					     sizeof(struct sk_funcs));
	sk_debug_key(key, "param: key: %s", np->key);

	np = &new_params[i++];
	*np = OSSL_PARAM_construct_octet_ptr(SK_PROV_PKEY_PARAM_SK_PRIVATE,
					     key->private, 0);
	sk_debug_key(key, "param: key: %s", np->key);

	np = &new_params[i++];
	*np = OSSL_PARAM_construct_end();

	rc = cb_data->param_callback(new_params, cb_data->cbarg);
	if (rc != 1)
		sk_debug_key(key, "ERROR: param_callback failed");

	OPENSSL_free(new_params);

	return rc;
}

static int sk_prov_keymgmt_export(void *vkey, int selection,
				  OSSL_CALLBACK *param_callback, void *cbarg)
{
	OSSL_FUNC_keymgmt_export_fn *default_export_fn;
	struct sk_prov_export_cb cb_data;
	struct sk_prov_key *key = vkey;

	if (key == NULL || param_callback == NULL)
		return 0;

	sk_debug_key(key, "key: %p selection: %x", key, selection);

	default_export_fn = (OSSL_FUNC_keymgmt_export_fn *)
			sk_prov_get_default_keymgmt_func(key->provctx,
					key->type, OSSL_FUNC_KEYMGMT_EXPORT);
	if (default_export_fn == NULL) {
		put_error_key(key, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
			      "no default export_fn");
		return 0;
	}

	if (key->secure_key == NULL ||
	    (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) == 0) {
		/*
		 * Clear key, or no private key selected, call default_export_fn
		 *  with original callback
		 */
		if (!default_export_fn(key->default_key, selection,
				       param_callback, cbarg)) {
			put_error_key(key, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				      "default_export_fn failed");
			return 0;
		}
		return 1;
	}

	/* Let the callback add our 3 addl. params */
	cb_data.key = key;
	cb_data.param_callback = param_callback;
	cb_data.cbarg = cbarg;
	if (!default_export_fn(key->default_key, selection,
			       sk_prov_keymgmt_export_cb, &cb_data)) {
		put_error_key(key, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
			      "default_export_fn failed");
		return 0;
	}

	return 1;
}

static int sk_prov_keymgmt_import(void *vkey, int selection,
				  const OSSL_PARAM params[])
{
	const OSSL_PARAM *p_blob, *p_funcs, *p_private, *p;
	OSSL_FUNC_keymgmt_import_fn *default_import_fn;
	struct sk_prov_key *key = vkey;
	size_t len;

	if (key == NULL)
		return 0;

	sk_debug_key(key, "key: %p selection: %x", key,
		     selection);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_key(key, "param: %s", p->key);

	default_import_fn = (OSSL_FUNC_keymgmt_import_fn *)
			sk_prov_get_default_keymgmt_func(key->provctx,
					key->type, OSSL_FUNC_KEYMGMT_IMPORT);
	if (default_import_fn == NULL) {
		put_error_key(key, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
			      "no default import_fn");
		return 0;
	}

	if (!default_import_fn(key->default_key, selection, params)) {
		put_error_key(key, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
			      "default_import_fn failed");
		return 0;
	}

	if (key->secure_key != NULL)
		OPENSSL_free(key->secure_key);
	key->secure_key = NULL;
	key->secure_key_size = 0;
	key->funcs = NULL;
	key->private = NULL;

	p_blob = OSSL_PARAM_locate_const(params, SK_PROV_PKEY_PARAM_SK_BLOB);
	p_funcs = OSSL_PARAM_locate_const(params, SK_PROV_PKEY_PARAM_SK_FUNCS);
	p_private = OSSL_PARAM_locate_const(params,
					    SK_PROV_PKEY_PARAM_SK_PRIVATE);

	if (p_blob != NULL && p_funcs != NULL && p_private != NULL) {
		if (!OSSL_PARAM_get_octet_string(p_blob,
						 (void **)&key->secure_key, 0,
						 &key->secure_key_size)) {
			put_error_key(key, SK_PROV_ERR_INTERNAL_ERROR,
				      "OSSL_PARAM_get_octet_string failed");
			return 0;
		}

		if (!OSSL_PARAM_get_octet_string_ptr(p_funcs,
					(const void **)&key->funcs, &len)) {
			put_error_key(key, SK_PROV_ERR_INTERNAL_ERROR,
				      "OSSL_PARAM_get_octet_string_ptr failed");
			return 0;
		}

		if (!OSSL_PARAM_get_octet_string_ptr(p_private,
				(const void **)&key->private, &len)) {
			put_error_key(key, SK_PROV_ERR_INTERNAL_ERROR,
				      "OSSL_PARAM_get_octet_string_ptr failed");
			return 0;
		}
	}

	return 1;
}

static const OSSL_PARAM sk_prov_imexport_types[] = {
	SK_PROV_SECURE_KEY_PARMS,
	OSSL_PARAM_END
};

static const OSSL_PARAM *sk_prov_keymgmt_export_types(
						struct sk_prov_ctx *provctx,
						int selection,
						int pkey_type)
{
	OSSL_FUNC_keymgmt_export_types_fn *default_export_types_fn;
	const OSSL_PARAM *default_parms = NULL, *params;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "selection: %d pkey_type: %d", selection,
		     pkey_type);

	params = sk_prov_get_cached_params(provctx, pkey_type,
					   SK_CONF_CACHED_PARAMS_OP_KEY_EXPORT,
					   selection);
	if (params != NULL)
		return params;

	default_export_types_fn = (OSSL_FUNC_keymgmt_export_types_fn *)
			sk_prov_get_default_keymgmt_func(provctx, pkey_type,
					OSSL_FUNC_KEYMGMT_EXPORT_TYPES);

	/* default_export_types_fn is optional */
	if (default_export_types_fn != NULL)
		default_parms = default_export_types_fn(selection);

	return sk_prov_cached_params_build(provctx, pkey_type,
					   SK_CONF_CACHED_PARAMS_OP_KEY_EXPORT,
					   selection,
					   default_parms,
					   sk_prov_imexport_types);
}

static const OSSL_PARAM *sk_prov_keymgmt_import_types(
						struct sk_prov_ctx *provctx,
						int selection,
						int pkey_type)
{
	OSSL_FUNC_keymgmt_import_types_fn *default_import_types_fn;
	const OSSL_PARAM *default_parms = NULL, *params;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "selection: %d pkey_type: %d", selection,
		     pkey_type);

	params = sk_prov_get_cached_params(provctx, pkey_type,
					   SK_CONF_CACHED_PARAMS_OP_KEY_IMPORT,
					   selection);
	if (params != NULL)
		return params;

	default_import_types_fn = (OSSL_FUNC_keymgmt_import_types_fn *)
			sk_prov_get_default_keymgmt_func(provctx, pkey_type,
					OSSL_FUNC_KEYMGMT_EXPORT_TYPES);

	/* default_import_types_fn is optional */
	if (default_import_types_fn != NULL)
		default_parms = default_import_types_fn(selection);

	return sk_prov_cached_params_build(provctx, pkey_type,
					   SK_CONF_CACHED_PARAMS_OP_KEY_IMPORT,
					   selection,
					   default_parms,
					   sk_prov_imexport_types);
}

static struct sk_prov_op_ctx *sk_prov_keymgmt_gen_init(
				struct sk_prov_ctx *provctx, int selection,
				const OSSL_PARAM params[], int pkey_type)
{
	OSSL_FUNC_keymgmt_gen_cleanup_fn *default_gen_cleanup_fn;
	OSSL_FUNC_keymgmt_gen_init_fn *default_gen_init_fn;
	struct sk_prov_op_ctx *genctx;
	const OSSL_PARAM *p;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "selection: %x type: %d", selection, pkey_type);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_ctx(provctx, "param: %s", p->key);

	default_gen_init_fn = (OSSL_FUNC_keymgmt_gen_init_fn *)
			sk_prov_get_default_keymgmt_func(provctx, pkey_type,
					OSSL_FUNC_KEYMGMT_GEN_INIT);
	if (default_gen_init_fn == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
			      "no default gen_init_fn");
		return NULL;
	}

	default_gen_cleanup_fn = (OSSL_FUNC_keymgmt_gen_cleanup_fn *)
			sk_prov_get_default_keymgmt_func(provctx, pkey_type,
					OSSL_FUNC_KEYMGMT_GEN_CLEANUP);
	if (default_gen_cleanup_fn == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
			      "no default gen_cleanup_fn");
		return NULL;
	}

	genctx = sk_prov_op_newctx(provctx, NULL, pkey_type);
	if (genctx == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_INTERNAL_ERROR,
			      "sk_prov_op_newctx failed");
		return NULL;
	}

	if (!sk_prov_op_init(genctx, NULL, EVP_PKEY_OP_KEYGEN)) {
		put_error_ctx(provctx, SK_PROV_ERR_INTERNAL_ERROR,
			      "sk_prov_op_init failed");
		sk_prov_op_freectx(genctx);
		return NULL;
	}

	genctx->default_op_ctx = default_gen_init_fn(provctx->default_provctx,
						     selection, params);
	if (genctx->default_op_ctx == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
			      "default_gen_init_fn failed");
		sk_prov_op_freectx(genctx);
		return NULL;
	}
	genctx->default_op_ctx_free = default_gen_cleanup_fn;

	sk_debug_ctx(provctx, "genctx: %p", genctx);
	return genctx;
}

static void sk_prov_keymgmt_gen_cleanup(void *vgenctx)
{
	struct sk_prov_op_ctx *genctx = vgenctx;

	if (genctx == NULL)
		return;

	sk_debug_op_ctx(genctx, "genctx: %p", genctx);
	sk_prov_op_freectx(genctx);
}

static int sk_prov_keymgmt_gen_set_params(void *vgenctx,
					  const OSSL_PARAM params[])
{
	OSSL_FUNC_keymgmt_gen_set_params_fn *default_gen_set_params_fn;
	struct sk_prov_op_ctx *genctx = vgenctx;
	const OSSL_PARAM *p;

	if (genctx == NULL)
		return 0;

	sk_debug_op_ctx(genctx, "genctx: %p", genctx);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(genctx, "param: %s", p->key);

	default_gen_set_params_fn = (OSSL_FUNC_keymgmt_gen_set_params_fn *)
			sk_prov_get_default_keymgmt_func(genctx->provctx,
				genctx->type, OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS);

	/* default_gen_set_params_fn is optional */
	if (default_gen_set_params_fn != NULL) {
		if (!default_gen_set_params_fn(genctx->default_op_ctx,
					       params)) {
			put_error_op_ctx(genctx,
					 SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
					 "default_gen_set_params_fn failed");
			return 0;
		}
	}

	return 1;
}

static const OSSL_PARAM *sk_prov_keymgmt_gen_settable_params(
					struct sk_prov_op_ctx *genctx,
					struct sk_prov_ctx *provctx,
					int pkey_type)
{
	OSSL_FUNC_keymgmt_gen_settable_params_fn
						*default_gen_settable_params_fn;
	const OSSL_PARAM *params = NULL, *p;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "pkey_type: %d", pkey_type);

	default_gen_settable_params_fn =
		(OSSL_FUNC_keymgmt_gen_settable_params_fn *)
			sk_prov_get_default_keymgmt_func(provctx,
				pkey_type,
				OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS);

	/* default_gen_settable_params_fn is optional */
	if (default_gen_settable_params_fn != NULL)
		params = default_gen_settable_params_fn(genctx->default_op_ctx,
						   provctx->default_provctx);

	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_ctx(provctx, "param: %s", p->key);

	return params;
}

static int sk_prov_keymgmt_gen_set_template(void *vgenctx, void *vtempl)
{
	OSSL_FUNC_keymgmt_gen_set_template_fn *default_gen_set_template_fn;
	struct sk_prov_op_ctx *genctx = vgenctx;
	struct sk_prov_key *templ = vtempl;

	if (genctx == NULL || templ == NULL)
		return 0;

	sk_debug_op_ctx(genctx, "genctx: %p templ: %p", genctx, templ);

	default_gen_set_template_fn = (OSSL_FUNC_keymgmt_gen_set_template_fn *)
			sk_prov_get_default_keymgmt_func(genctx->provctx,
					genctx->type,
					OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE);

	if (default_gen_set_template_fn == NULL) {
		put_error_op_ctx(genctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default get_set_template_fn");
		return 0;
	}

	return default_gen_set_template_fn(genctx->default_op_ctx,
					   templ->default_key);
}

static void *sk_prov_keymgmt_gen(void *vgenctx,
				 OSSL_CALLBACK *osslcb, void *cbarg)
{
	OSSL_FUNC_keymgmt_gen_fn *default_gen_fn;
	struct sk_prov_op_ctx *genctx = vgenctx;
	struct sk_prov_key *key;

	if (genctx == NULL)
		return NULL;

	sk_debug_op_ctx(genctx, "genctx: %p", genctx);

	default_gen_fn = (OSSL_FUNC_keymgmt_gen_fn *)
			sk_prov_get_default_keymgmt_func(genctx->provctx,
					genctx->type, OSSL_FUNC_KEYMGMT_GEN);

	if (default_gen_fn == NULL) {
		put_error_op_ctx(genctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default gen_fn");
		return NULL;
	}

	key = OPENSSL_zalloc(sizeof(struct sk_prov_key));
	if (key == NULL) {
		put_error_op_ctx(genctx, SK_PROV_ERR_MALLOC_FAILED,
				 "OPENSSL_zalloc failed");
		return NULL;
	}

	key->provctx = genctx->provctx;
	key->type = genctx->type;

	key->default_key = default_gen_fn(genctx->default_op_ctx,
					  osslcb, cbarg);
	if (key->default_key == NULL) {
		put_error_op_ctx(genctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_gen_fn failed");
		OPENSSL_free(key);
		return NULL;
	}

	sk_prov_keymgmt_upref(key);

	sk_debug_op_ctx(genctx, "key: %p", key);

	return key;
}

static void *sk_prov_keymgmt_load(const void *reference, size_t reference_sz)
{
	struct sk_prov_key *key;

	if (reference == NULL)
		return NULL;

	if (reference_sz == sizeof(struct sk_prov_key)) {
		/* The contents of the reference is the address to our object */
		key = *(struct sk_prov_key **)reference;

		/* We grabbed, so we detach it */
		*(struct sk_prov_key **)reference = NULL;
		return key;
	}

	return NULL;
}

static int sk_prov_keymgmt_get_size(struct sk_prov_key *key)
{
	int size = 0;
	OSSL_PARAM key_params[] = {
		OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, &size),
		OSSL_PARAM_END
	};

	sk_debug_key(key, "key: %p", key);

	if (!sk_prov_keymgmt_get_params(key, key_params) ||
	    !OSSL_PARAM_modified(&key_params[0]) ||
	    size <= 0) {
		put_error_key(key, SK_PROV_ERR_MISSING_PARAMETER,
				 "sk_prov_keymgmt_get_params failed to "
				 "get OSSL_PKEY_PARAM_MAX_SIZE");
		return -1;
	}

	sk_debug_key(key, "size: %d", size);
	return size;
}

static int sk_prov_keymgmt_get_bits(struct sk_prov_key *key)
{
	int bits = 0;
	OSSL_PARAM key_params[] = {
		OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, &bits),
		OSSL_PARAM_END
	};

	sk_debug_key(key, "key: %p", key);

	if (!sk_prov_keymgmt_get_params(key, key_params) ||
	    !OSSL_PARAM_modified(&key_params[0]) ||
	    bits <= 0) {
		put_error_key(key, SK_PROV_ERR_MISSING_PARAMETER,
				 "sk_prov_keymgmt_get_params failed to "
				 "get OSSL_PKEY_PARAM_BITS");
		return -1;
	}

	sk_debug_key(key, "bits: %d", bits);
	return bits;
}

static void *sk_prov_keymgmt_rsa_new(void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);

	return sk_prov_keymgmt_new(provctx, EVP_PKEY_RSA);
}

static const char *sk_prov_keymgmt_rsa_query_operation_name(int operation_id)
{
	switch (operation_id) {
	case OSSL_OP_SIGNATURE:
	case OSSL_OP_ASYM_CIPHER:
		return "RSA";
	}

	return NULL;
}

static const OSSL_PARAM *sk_prov_keymgmt_rsa_gettable_params(void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_keymgmt_gettable_params(provctx, EVP_PKEY_RSA);
}

static const OSSL_PARAM *sk_prov_keymgmt_rsa_settable_params(void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_keymgmt_settable_params(provctx, EVP_PKEY_RSA);
}

#ifdef OSSL_FUNC_KEYMGMT_EXPORT_TYPES_EX
static const OSSL_PARAM *sk_prov_keymgmt_rsa_export_types_ex(void *vprovctx,
							     int selection)
{
	struct sk_prov_ctx *provctx = vprovctx;

	return sk_prov_keymgmt_export_types(provctx, selection, EVP_PKEY_RSA);
}

static const OSSL_PARAM *sk_prov_keymgmt_rsa_import_types_ex(void *vprovctx,
							     int selection)
{
	struct sk_prov_ctx *provctx = vprovctx;

	return sk_prov_keymgmt_import_types(provctx, selection, EVP_PKEY_RSA);
}
#else
static const OSSL_PARAM *sk_prov_keymgmt_rsa_export_types(int selection)
{
	struct sk_prov_ctx *provctx =
		OSSL_PROVIDER_get0_provider_ctx(sk_prov_securekey_provider);

	return sk_prov_keymgmt_export_types(provctx, selection, EVP_PKEY_RSA);
}

static const OSSL_PARAM *sk_prov_keymgmt_rsa_import_types(int selection)
{
	struct sk_prov_ctx *provctx =
		OSSL_PROVIDER_get0_provider_ctx(sk_prov_securekey_provider);

	return sk_prov_keymgmt_import_types(provctx, selection, EVP_PKEY_RSA);
}
#endif

static void *sk_prov_keymgmt_rsa_gen_init(void *vprovctx, int selection,
					  const OSSL_PARAM params[])
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_keymgmt_gen_init(provctx, selection, params,
					EVP_PKEY_RSA);
}

static const OSSL_PARAM *sk_prov_keymgmt_rsa_gen_settable_params(void *vgenctx,
								 void *vprovctx)
{
	struct sk_prov_op_ctx *genctx = vgenctx;
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_keymgmt_gen_settable_params(genctx, provctx,
						   EVP_PKEY_RSA);
}

static void *sk_prov_keymgmt_rsa_pss_new(void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_keymgmt_new(provctx, EVP_PKEY_RSA_PSS);
}

static const OSSL_PARAM *sk_prov_keymgmt_rsa_pss_gettable_params(void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_keymgmt_gettable_params(provctx, EVP_PKEY_RSA_PSS);
}

static const OSSL_PARAM *sk_prov_keymgmt_rsa_pss_settable_params(void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_keymgmt_settable_params(provctx, EVP_PKEY_RSA_PSS);
}

#ifdef OSSL_FUNC_KEYMGMT_EXPORT_TYPES_EX
static const OSSL_PARAM *sk_prov_keymgmt_rsa_pss_export_types_ex(void *vprovctx,
								 int selection)
{
	struct sk_prov_ctx *provctx = vprovctx;

	return sk_prov_keymgmt_export_types(provctx, selection,
					    EVP_PKEY_RSA_PSS);
}

static const OSSL_PARAM *sk_prov_keymgmt_rsa_pss_import_types_ex(void *vprovctx,
								 int selection)
{
	struct sk_prov_ctx *provctx = vprovctx;

	return sk_prov_keymgmt_import_types(provctx, selection,
					    EVP_PKEY_RSA_PSS);
}
#else
static const OSSL_PARAM *sk_prov_keymgmt_rsa_pss_export_types(int selection)
{
	struct sk_prov_ctx *provctx =
		OSSL_PROVIDER_get0_provider_ctx(sk_prov_securekey_provider);

	return sk_prov_keymgmt_export_types(provctx, selection,
					    EVP_PKEY_RSA_PSS);
}

static const OSSL_PARAM *sk_prov_keymgmt_rsa_pss_import_types(int selection)
{
	struct sk_prov_ctx *provctx =
		OSSL_PROVIDER_get0_provider_ctx(sk_prov_securekey_provider);

	return sk_prov_keymgmt_import_types(provctx, selection,
					    EVP_PKEY_RSA_PSS);
}
#endif

static void *sk_prov_keymgmt_rsa_pss_gen_init(void *vprovctx, int selection,
					      const OSSL_PARAM params[])
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_keymgmt_gen_init(provctx, selection, params,
					EVP_PKEY_RSA_PSS);
}

static const OSSL_PARAM *sk_prov_keymgmt_rsa_pss_gen_settable_params(
								void *vgenctx,
								void *vprovctx)
{
	struct sk_prov_op_ctx *genctx = vgenctx;
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_keymgmt_gen_settable_params(genctx, provctx,
						   EVP_PKEY_RSA_PSS);
}

static void *sk_prov_keymgmt_ec_new(void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_keymgmt_new(provctx, EVP_PKEY_EC);
}

static const char *sk_prov_keymgmt_ec_query_operation_name(int operation_id)
{
	switch (operation_id) {
	case OSSL_OP_KEYEXCH:
		return "ECDH";
	case OSSL_OP_SIGNATURE:
		return "ECDSA";
	}

	return NULL;
}

static const OSSL_PARAM *sk_prov_keymgmt_ec_gettable_params(void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_keymgmt_gettable_params(provctx, EVP_PKEY_EC);
}

static const OSSL_PARAM *sk_prov_keymgmt_ec_settable_params(void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_keymgmt_settable_params(provctx, EVP_PKEY_EC);
}

#ifdef OSSL_FUNC_KEYMGMT_EXPORT_TYPES_EX
static const OSSL_PARAM *sk_prov_keymgmt_ec_export_types_ex(void *vprovctx,
							    int selection)
{
	struct sk_prov_ctx *provctx = vprovctx;

	return sk_prov_keymgmt_export_types(provctx, selection, EVP_PKEY_EC);
}

static const OSSL_PARAM *sk_prov_keymgmt_ec_import_types_ex(void *vprovctx,
							    int selection)
{
	struct sk_prov_ctx *provctx = vprovctx;

	return sk_prov_keymgmt_import_types(provctx, selection, EVP_PKEY_EC);
}
#else
static const OSSL_PARAM *sk_prov_keymgmt_ec_export_types(int selection)
{
	struct sk_prov_ctx *provctx =
		OSSL_PROVIDER_get0_provider_ctx(sk_prov_securekey_provider);

	return sk_prov_keymgmt_export_types(provctx, selection, EVP_PKEY_EC);
}

static const OSSL_PARAM *sk_prov_keymgmt_ec_import_types(int selection)
{
	struct sk_prov_ctx *provctx =
		OSSL_PROVIDER_get0_provider_ctx(sk_prov_securekey_provider);

	return sk_prov_keymgmt_import_types(provctx, selection, EVP_PKEY_EC);
}
#endif

static void *sk_prov_keymgmt_ec_gen_init(void *vprovctx, int selection,
					 const OSSL_PARAM params[])
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_keymgmt_gen_init(provctx, selection, params,
					EVP_PKEY_EC);
}

static const OSSL_PARAM *sk_prov_keymgmt_ec_gen_settable_params(void *vgenctx,
								void *vprovctx)
{
	struct sk_prov_op_ctx *genctx = vgenctx;
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_keymgmt_gen_settable_params(genctx, provctx,
						   EVP_PKEY_EC);
}

static void *sk_prov_keyexch_ec_newctx(void *vprovctx)
{
	OSSL_FUNC_keyexch_freectx_fn *default_freectx_fn;
	OSSL_FUNC_keyexch_newctx_fn *default_newctx_fn;
	struct sk_prov_ctx *provctx = vprovctx;
	struct sk_prov_op_ctx *ctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);

	default_newctx_fn = (OSSL_FUNC_keyexch_newctx_fn *)
		sk_prov_get_default_keyexch_func(provctx,
						 OSSL_FUNC_KEYEXCH_NEWCTX);
	if (default_newctx_fn == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
			      "no default newctx_fn");
		return NULL;
	}

	default_freectx_fn = (OSSL_FUNC_keyexch_freectx_fn *)
		sk_prov_get_default_keyexch_func(provctx,
						 OSSL_FUNC_KEYEXCH_FREECTX);
	if (default_freectx_fn == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
			      "no default freectx_fn");
		return NULL;
	}

	ctx = sk_prov_op_newctx(provctx, NULL, EVP_PKEY_EC);
	if (ctx == NULL) {
		sk_debug_ctx(provctx, "ERROR: sk_prov_op_newctx failed");
		return NULL;
	}

	ctx->default_op_ctx = default_newctx_fn(provctx->default_provctx);
	if (ctx->default_op_ctx == NULL) {
		put_error_ctx(provctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
			      "default_newctx_fn failed");
		sk_prov_op_freectx(ctx);
		return NULL;
	}
	ctx->default_op_ctx_free = default_freectx_fn;

	sk_debug_ctx(provctx, "ctx: %p", ctx);

	return ctx;
}

static void *sk_prov_keyexch_ec_dupctx(void *vctx)
{
	OSSL_FUNC_keyexch_dupctx_fn *default_dupctx_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_op_ctx *new_ctx;

	if (ctx == NULL)
		return NULL;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);

	default_dupctx_fn = (OSSL_FUNC_keyexch_dupctx_fn *)
			sk_prov_get_default_keyexch_func(ctx->provctx,
					OSSL_FUNC_KEYEXCH_DUPCTX);
	if (default_dupctx_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default dupctx_fn");
		return NULL;
	}

	new_ctx = sk_prov_op_dupctx(ctx);
	if (new_ctx == NULL) {
		sk_debug_op_ctx(ctx, "ERROR: sk_prov_op_dupctx failed");
		return NULL;
	}

	new_ctx->default_op_ctx = default_dupctx_fn(ctx->default_op_ctx);
	if (new_ctx->default_op_ctx == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_dupctx_fn failed");
		sk_prov_op_freectx(new_ctx);
		return NULL;
	}

	sk_debug_op_ctx(ctx, "new_ctx: %p", new_ctx);
	return new_ctx;
}

static int sk_prov_keyexch_ec_init(void *vctx, void *vkey,
				   const OSSL_PARAM params[])
{
	OSSL_FUNC_keyexch_init_fn *default_init_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_key *key = vkey;
	const OSSL_PARAM *p;

	if (ctx == NULL || key == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p", ctx, key);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

	default_init_fn = (OSSL_FUNC_keyexch_init_fn *)
			sk_prov_get_default_keyexch_func(ctx->provctx,
					OSSL_FUNC_KEYEXCH_INIT);
	if (default_init_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default init_fn");
		return 0;
	}

	if (!sk_prov_op_init(ctx, key, EVP_PKEY_OP_DERIVE)) {
		sk_debug_op_ctx(ctx, "ERROR: sk_prov_op_init failed");
		return 0;
	}

	if (!default_init_fn(ctx->default_op_ctx, key->default_key, params)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_init_fn failed");
		return 0;
	}

	return 1;
}

static int sk_prov_keyexch_ec_set_peer(void *vctx, void *vpeerkey)

{
	OSSL_FUNC_keyexch_set_peer_fn *default_set_peer_fn;
	struct sk_prov_key *peerkey = vpeerkey;
	struct sk_prov_op_ctx *ctx = vctx;

	if (ctx == NULL || peerkey == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p peerkey: %p", ctx, ctx->key,
			peerkey);

	default_set_peer_fn = (OSSL_FUNC_keyexch_set_peer_fn *)
			sk_prov_get_default_keyexch_func(ctx->provctx,
					OSSL_FUNC_KEYEXCH_SET_PEER);
	if (default_set_peer_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default set_peer_fn");
		return 0;
	}

	if (ctx->key == NULL || ctx->operation != EVP_PKEY_OP_DERIVE) {
		put_error_op_ctx(ctx, SK_PROV_ERR_OPRATION_NOT_INITIALIZED,
				 "derive operation not initialized");
		return 0;
	}

	if (!default_set_peer_fn(ctx->default_op_ctx, peerkey->default_key)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_set_peer_fn failed");
		return 0;
	}

	return 1;
}

static int sk_prov_keyexch_ec_derive(void *vctx,
				     unsigned char *secret, size_t *secretlen,
				     size_t outlen)
{
	OSSL_FUNC_keyexch_derive_fn *default_derive_fn;
	struct sk_prov_op_ctx *ctx = vctx;

	if (ctx == NULL || secretlen == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p outlen: %lu", ctx, ctx->key,
			outlen);

	default_derive_fn = (OSSL_FUNC_keyexch_derive_fn *)
			sk_prov_get_default_keyexch_func(ctx->provctx,
					OSSL_FUNC_KEYEXCH_DERIVE);
	if (default_derive_fn == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_MISSING,
				 "no default derive_fn");
		return 0;
	}

	if (ctx->key == NULL || ctx->operation != EVP_PKEY_OP_DERIVE) {
		put_error_op_ctx(ctx, SK_PROV_ERR_OPRATION_NOT_INITIALIZED,
				 "derive operation not initialized");
		return 0;
	}

	if (!default_derive_fn(ctx->default_op_ctx, secret, secretlen,
			       outlen)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
				 "default_derive_fn failed");
		return 0;
	}

	sk_debug_op_ctx(ctx, "secretlen: %lu", *secretlen);

	return 1;
}

static int sk_prov_keyexch_ec_set_ctx_params(void *vctx,
					     const OSSL_PARAM params[])
{
	OSSL_FUNC_keyexch_set_ctx_params_fn *default_set_params_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	const OSSL_PARAM *p;

	if (ctx == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

	default_set_params_fn = (OSSL_FUNC_keyexch_set_ctx_params_fn *)
			sk_prov_get_default_keyexch_func(ctx->provctx,
				OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS);

	/* default_set_params_fn is optional */
	if (default_set_params_fn != NULL) {
		if (!default_set_params_fn(ctx->default_op_ctx, params)) {
			put_error_op_ctx(ctx,
					 SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
					 "default_set_params_fn failed");
			return 0;
		}
	}

	return 1;

}

static const OSSL_PARAM *sk_prov_keyexch_ec_settable_ctx_params(void *vctx,
								void *vprovctx)
{
	OSSL_FUNC_keyexch_settable_ctx_params_fn
						*default_settable_params_fn;
	struct sk_prov_ctx *provctx = vprovctx;
	const OSSL_PARAM *params = NULL, *p;
	struct sk_prov_op_ctx *ctx = vctx;

	if (ctx == NULL || provctx == NULL)
		return NULL;

	default_settable_params_fn =
		(OSSL_FUNC_keyexch_settable_ctx_params_fn *)
			sk_prov_get_default_keyexch_func(provctx,
				OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS);

	/* default_settable_params_fn is optional */
	if (default_settable_params_fn != NULL)
		params = default_settable_params_fn(ctx->default_op_ctx,
						    provctx->default_provctx);

	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_ctx(provctx, "param: %s", p->key);

	return params;
}

static int sk_prov_keyexch_ec_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
	OSSL_FUNC_keyexch_get_ctx_params_fn *default_get_params_fn;
	struct sk_prov_op_ctx *ctx = vctx;
	const OSSL_PARAM *p;

	if (ctx == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);
	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_op_ctx(ctx, "param: %s", p->key);

	default_get_params_fn = (OSSL_FUNC_keyexch_get_ctx_params_fn *)
			sk_prov_get_default_keyexch_func(ctx->provctx,
					OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS);

	/* default_get_params_fn is optional */
	if (default_get_params_fn != NULL) {
		if (!default_get_params_fn(ctx->default_op_ctx, params)) {
			put_error_op_ctx(ctx,
					 SK_PROV_ERR_DEFAULT_PROV_FUNC_FAILED,
					 "default_get_params_fn failed");
			return 0;
		}
	}

	return 1;
}

static const OSSL_PARAM *sk_prov_keyexch_ec_gettable_ctx_params(void *vctx,
								void *vprovctx)
{
	OSSL_FUNC_keyexch_gettable_ctx_params_fn
						*default_gettable_params_fn;
	struct sk_prov_ctx *provctx = vprovctx;
	const OSSL_PARAM *params = NULL, *p;
	struct sk_prov_op_ctx *ctx = vctx;

	if (ctx == NULL || provctx == NULL)
		return NULL;

	default_gettable_params_fn =
		(OSSL_FUNC_keyexch_gettable_ctx_params_fn *)
			sk_prov_get_default_keyexch_func(provctx,
				OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS);

	/* default_settable_params_fn is optional */
	if (default_gettable_params_fn != NULL)
		params = default_gettable_params_fn(ctx->default_op_ctx,
						    provctx->default_provctx);

	for (p = params; p != NULL && p->key != NULL; p++)
		sk_debug_ctx(provctx, "param: %s", p->key);

	return params;
}

static void *sk_prov_asym_rsa_newctx(void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_asym_op_newctx(provctx, EVP_PKEY_RSA);
}

static const OSSL_PARAM *sk_prov_asym_rsa_gettable_ctx_params(void *vctx,
							      void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;
	struct sk_prov_op_ctx *ctx = vctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_asym_op_gettable_ctx_params(ctx, provctx, EVP_PKEY_RSA);
}

static const OSSL_PARAM *sk_prov_asym_rsa_settable_ctx_params(void *vctx,
							      void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;
	struct sk_prov_op_ctx *ctx = vctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_asym_op_settable_ctx_params(ctx, provctx, EVP_PKEY_RSA);
}

static int sk_prov_asym_rsa_decrypt(void *vctx,
				    unsigned char *out, size_t *outlen,
				    size_t outsize, const unsigned char *in,
				    size_t inlen)
{
	int rsa_size, pad_mode, oaep_label_len = 0, rc;
	EVP_MD *oaep_md = NULL, *mgf_md = NULL;
	struct sk_prov_op_ctx *ctx = vctx;
	unsigned char *oaep_label = NULL;
	unsigned char *tmp = NULL;
	struct sk_prov_key *key;
	struct sk_funcs *funcs;

	if (ctx == NULL || in == NULL || outlen == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p inlen: %lu outsize: %lu",
			ctx, ctx->key, inlen, outsize);

	if (ctx->key == NULL || ctx->operation != EVP_PKEY_OP_DECRYPT) {
		put_error_op_ctx(ctx, SK_PROV_ERR_OPRATION_NOT_INITIALIZED,
				 "decrypt operation not initialized");
		return 0;
	}

	/* For clear key, let the default provider handle it */
	if (ctx->key->secure_key == NULL)
		return sk_prov_asym_op_decrypt(ctx, out, outlen, outsize,
					    in, inlen);

	funcs = ctx->key->funcs;
	if (funcs == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
				 "no secure key funcs");
		return 0;
	}

	key = ctx->key;

	rsa_size = sk_prov_keymgmt_get_size(key);
	if (rsa_size <= 0) {
		sk_debug_op_ctx(ctx, "sk_prov_keymgmt_get_size failed");
		return 0;
	}

	if (out == NULL) {
		tmp = OPENSSL_zalloc(rsa_size);
		if (tmp == NULL) {
			put_error_op_ctx(ctx, SK_PROV_ERR_MALLOC_FAILED,
					 "OPENSSL_zalloc failed");
			return 0;
		}
		out = tmp;
		outsize = rsa_size;
	}

	if (outsize < (size_t)rsa_size) {
		put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PARAM,
				 "output buffer length invalid");
		return 0;
	}

	pad_mode = sk_prov_asym_op_get_padding(ctx);
	switch (pad_mode) {
	case RSA_NO_PADDING:
	case RSA_PKCS1_PADDING:
	case RSA_X931_PADDING:
		break;

	case RSA_PKCS1_OAEP_PADDING:
		oaep_label_len = sk_prov_asym_op_get_oaep_label(ctx,
								&oaep_label);
		if (oaep_label_len < 0) {
			sk_debug_op_ctx(ctx,
				"ERROR: sk_prov_rsa_asym_get_oaep_label failed");
			rc = 0;
			goto out;
		}

		oaep_md = sk_prov_asym_op_get_oaep_md(ctx);
		if (oaep_md == NULL) {
			sk_debug_op_ctx(ctx,
				"ERROR: sk_prov_asym_op_get_oaep_md failed");
			rc = 0;
			goto out;
		}

		mgf_md = sk_prov_asym_op_get_mgf_md(ctx);
		if (mgf_md == NULL) {
			sk_debug_op_ctx(ctx,
				"ERROR: sk_prov_asym_op_get_mgf_md failed");
			rc = 0;
			goto out;
		}
		break;
	default:
		put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PADDING,
				 "unknown/unsupported padding: %d", pad_mode);
		return 0;
	}

	*outlen = outsize;

	switch (pad_mode) {
	case RSA_PKCS1_OAEP_PADDING:
		if (funcs->rsa_decrypt_oaep == NULL) {
			put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
					 "no secure key decrypt function");
			rc = 0;
			goto out;
		}

		rc = funcs->rsa_decrypt_oaep(key->secure_key,
					     key->secure_key_size,
					     out, outlen, in, inlen,
					     EVP_MD_type(oaep_md),
					     EVP_MD_type(mgf_md),
					     oaep_label, oaep_label_len,
					     key->private, ctx->provctx->debug);
		break;

	default:
		if (funcs->rsa_decrypt == NULL) {
			put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
					 "no secure key decrypt function");
			rc = 0;
			goto out;
		}

		rc = funcs->rsa_decrypt(key->secure_key, key->secure_key_size,
					out, outlen, in, inlen, pad_mode,
					key->private, ctx->provctx->debug);
		break;
	}

	if (tmp != NULL) {
		OPENSSL_cleanse(tmp, outsize);
		OPENSSL_free(tmp);
	}

	if (rc != 0) {
		put_error_op_ctx(ctx, SK_PROV_ERR_SECURE_KEY_FUNC_FAILED,
				 "Secure key encrypt operation failed: rc: %d",
				 rc);
		rc = 0;
		goto out;
	}

	rc = 1;

	sk_debug_op_ctx(ctx, "outlen: %lu", *outlen);

out:
	if (oaep_md != NULL)
		EVP_MD_free(oaep_md);
	if (mgf_md != NULL)
		EVP_MD_free(mgf_md);

	return rc;
}

static void *sk_prov_sign_rsa_newctx(void *vprovctx, const char *propq)
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p propq: %s", provctx,
		     propq != NULL ? propq : "");
	return sk_prov_sign_op_newctx(provctx, propq, EVP_PKEY_RSA);
}

static const OSSL_PARAM *sk_prov_sign_rsa_gettable_ctx_params(void *vctx,
							      void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;
	struct sk_prov_op_ctx *ctx = vctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_sign_op_gettable_ctx_params(ctx, provctx, EVP_PKEY_RSA);
}

static const OSSL_PARAM *sk_prov_sign_rsa_settable_ctx_params(void *vctx,
							      void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;
	struct sk_prov_op_ctx *ctx = vctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_sign_op_settable_ctx_params(ctx, provctx, EVP_PKEY_RSA);
}

static const OSSL_PARAM *sk_prov_sign_rsa_gettable_ctx_md_params(void *vctx)
{
	struct sk_prov_op_ctx *ctx = vctx;

	if (ctx == NULL)
		return NULL;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);
	return sk_prov_sign_op_gettable_ctx_md_params(ctx, EVP_PKEY_RSA);
}

static const OSSL_PARAM *sk_prov_sign_rsa_settable_ctx_md_params(void *vctx)
{
	struct sk_prov_op_ctx *ctx = vctx;

	if (ctx == NULL)
		return NULL;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);
	return sk_prov_sign_op_settable_ctx_md_params(ctx, EVP_PKEY_RSA);
}

static int sk_prov_sign_rsa_sign(void *vctx,
				 unsigned char *sig, size_t *siglen,
				 size_t sigsize,
				 const unsigned char *tbs, size_t tbslen)
{
	EVP_MD *sign_md = NULL, *mgf_md = NULL;
	int rsa_size, pad_mode, salt_len, rc;
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_key *key;
	struct sk_funcs *funcs;

	if (ctx == NULL || siglen == NULL || tbs == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p tbslen: %lu sigsize: %lu",
			ctx, ctx->key, tbslen, sigsize);

	if (ctx->key == NULL || ctx->operation != EVP_PKEY_OP_SIGN) {
		put_error_op_ctx(ctx, SK_PROV_ERR_OPRATION_NOT_INITIALIZED,
				 "sign operation not initialized");
		return 0;
	}

	/* For clear key, let the default provider handle it */
	if (ctx->key->secure_key == NULL)
		return sk_prov_sign_op_sign(ctx, sig, siglen, sigsize,
					    tbs, tbslen);

	key = ctx->key;

	rsa_size = sk_prov_keymgmt_get_size(key);
	if (rsa_size <= 0) {
		sk_debug_op_ctx(ctx, "ERROR: sk_prov_keymgmt_get_size failed");
		return 0;
	}

	if (sig == NULL) {
		*siglen = rsa_size;
		sk_debug_op_ctx(ctx, "siglen: %lu", *siglen);
		return 1;
	}

	if (sigsize < (size_t)rsa_size) {
		put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PARAM,
				 "signature length invalid");
		return 0;
	}

	funcs = ctx->key->funcs;
	if (funcs == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
				 "no secure key funcs");
		return 0;
	}

	sign_md = sk_prov_sign_op_get_md(ctx);
	pad_mode = sk_prov_sign_op_get_padding(ctx);

	if (sign_md == NULL) {
		/* Sign without a signature digest, fall back to no padding */
		pad_mode = RSA_NO_PADDING;
	} else {
		if (tbslen != (size_t)EVP_MD_size(sign_md)) {
			put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PARAM,
					 "tbslen must be size of digest");
			rc = 0;
			goto out;
		}
	}

	*siglen = rsa_size;

	switch (pad_mode) {
	case RSA_PKCS1_PADDING:
	case RSA_X931_PADDING:
		if (sign_md == NULL) {
			put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
					 "padding needs a signature digest");
			rc = 0;
			goto out;
		}
		/* fall through */

	case RSA_NO_PADDING:
		if (funcs->rsa_sign == NULL) {
			put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
					 "no secure key sign function");
			rc = 0;
			goto out;

		}

		rc = funcs->rsa_sign(key->secure_key, key->secure_key_size,
				     sig, siglen, tbs, tbslen, pad_mode,
				     sign_md != NULL ?
					EVP_MD_type(sign_md) : NID_undef,
				     key->private, ctx->provctx->debug);
		break;

	case RSA_PKCS1_PSS_PADDING:
		if (sign_md == NULL) {
			put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
					 "PSS padding needs a signature digest");
			rc = 0;
			goto out;
		}

		mgf_md = sk_prov_sign_op_get_mgf_md(ctx);
		if (mgf_md == NULL) {
			sk_debug_op_ctx(ctx,
				"ERROR sk_prov_sign_op_get_mgf_md failed");
			rc = 0;
			goto out;
		}

		salt_len = sk_prov_sign_op_get_pss_saltlen(ctx, key, mgf_md);
		if (salt_len < 0) {
			sk_debug_op_ctx(ctx,
				"ERROR: sk_prov_sign_op_get_pss_saltlen failed");
			rc = 0;
			goto out;
		}

		if (funcs->rsa_pss_sign == NULL) {
			put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
					 "no secure key sign function");
			rc = 0;
			goto out;
		}

		rc = funcs->rsa_pss_sign(key->secure_key, key->secure_key_size,
					 sig, siglen, tbs, tbslen,
					 EVP_MD_type(sign_md),
					 EVP_MD_type(mgf_md),
					 salt_len, key->private,
					 ctx->provctx->debug);
		break;
	default:
		put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PADDING,
				 "unknown/unsupported padding: %d", pad_mode);
		rc = 0;
		goto out;
	}

	if (rc != 0) {
		put_error_op_ctx(ctx, SK_PROV_ERR_SECURE_KEY_FUNC_FAILED,
				 "Secure key sign operation failed: rc: %d",
				 rc);
		rc = 0;
		goto out;
	}

	rc = 1;

	sk_debug_op_ctx(ctx, "siglen: %lu", *siglen);

out:
	if (sign_md != NULL)
		EVP_MD_free(sign_md);
	if (mgf_md != NULL)
		EVP_MD_free(mgf_md);

	return rc;
}

static int sk_prov_sign_rsa_digest_sign_init(void *vctx,
					     const char *mdname,
					     void *vkey,
					     const OSSL_PARAM params[])
{
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_key *key = vkey;

	sk_debug_op_ctx(ctx, "ctx: %p mdname: %s key: %p", ctx,
			mdname != NULL ? mdname : "", key);
	return sk_prov_sign_op_digest_sign_init(ctx, mdname, key, params,
						sk_prov_sign_rsa_sign);
}

static void *sk_prov_sign_ec_newctx(void *vprovctx, const char *propq)
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p propq: %s", provctx,
		     propq != NULL ? propq : "");
	return sk_prov_sign_op_newctx(provctx, propq, EVP_PKEY_EC);
}

static const OSSL_PARAM *sk_prov_sign_ec_gettable_ctx_params(void *vctx,
							     void *vprovctx)
{
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_sign_op_gettable_ctx_params(ctx, provctx, EVP_PKEY_EC);
}

static const OSSL_PARAM *sk_prov_sign_ec_settable_ctx_params(void *vctx,
							     void *vprovctx)
{
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_sign_op_settable_ctx_params(ctx, provctx, EVP_PKEY_EC);
}

static const OSSL_PARAM *sk_prov_sign_ec_gettable_ctx_md_params(void *vctx)
{
	struct sk_prov_op_ctx *ctx = vctx;

	if (ctx == NULL)
		return NULL;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);
	return sk_prov_sign_op_gettable_ctx_md_params(ctx, EVP_PKEY_EC);
}

static const OSSL_PARAM *sk_prov_sign_ec_settable_ctx_md_params(void *vctx)
{
	struct sk_prov_op_ctx *ctx = vctx;

	if (ctx == NULL)
		return NULL;

	sk_debug_op_ctx(ctx, "ctx: %p", ctx);
	return sk_prov_sign_op_settable_ctx_md_params(ctx, EVP_PKEY_EC);
}

static int sk_prov_sign_ec_sign(void *vctx,
				unsigned char *sig, size_t *siglen,
				size_t sigsize,
				const unsigned char *tbs, size_t tbslen)
{
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_key *key;
	EVP_MD *sign_md = NULL;
	struct sk_funcs *funcs;
	int ec_size, rc;

	if (ctx == NULL || siglen == NULL || tbs == NULL)
		return 0;

	sk_debug_op_ctx(ctx, "ctx: %p key: %p tbslen: %lu sigsize: %lu",
			ctx, ctx->key, tbslen, sigsize);

	if (ctx->key == NULL || ctx->operation != EVP_PKEY_OP_SIGN) {
		put_error_op_ctx(ctx, SK_PROV_ERR_OPRATION_NOT_INITIALIZED,
				 "sign operation not initialized");
		return 0;
	}

	/* For clear key, let the default provider handle it */
	if (ctx->key->secure_key == NULL)
		return sk_prov_sign_op_sign(ctx, sig, siglen, sigsize,
					    tbs, tbslen);

	key = ctx->key;

	ec_size = sk_prov_keymgmt_get_size(key);
	if (ec_size <= 0) {
		sk_debug_op_ctx(ctx, "ERROR: sk_prov_keymgmt_get_size failed");
		return 0;
	}

	if (sig == NULL) {
		*siglen = ec_size;
		sk_debug_op_ctx(ctx, "siglen: %lu", *siglen);
		return 1;
	}

	if (sigsize < (size_t)ec_size) {
		put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PARAM,
				 "signature length invalid");
		return 0;
	}

	funcs = ctx->key->funcs;
	if (funcs == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
				 "no secure key funcs");
		return 0;
	}

	sign_md = sk_prov_sign_op_get_md(ctx);
	if (sign_md == NULL) {
		sk_debug_op_ctx(ctx, "ERROR: sk_prov_sign_op_get_md failed");
		return 0;
	}

	if (tbslen != (size_t)EVP_MD_size(sign_md)) {
		put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PARAM,
				 "tbslen must be size of digest");
		rc = 0;
		goto out;
	}

	*siglen = ec_size;

	if (funcs->ecdsa_sign == NULL) {
		put_error_op_ctx(ctx, SK_PROV_ERR_MISSING_PARAMETER,
				 "no secure key sign function");
		rc = 0;
		goto out;
	}

	rc = funcs->ecdsa_sign(key->secure_key, key->secure_key_size,
				 sig, siglen, tbs, tbslen,
				 EVP_MD_type(sign_md), key->private,
				 ctx->provctx->debug);
	if (rc != 0) {
		put_error_op_ctx(ctx, SK_PROV_ERR_SECURE_KEY_FUNC_FAILED,
				 "Secure key sign operation failed: rc: %d",
				 rc);
		rc = 0;
		goto out;
	}

	rc = 1;

	sk_debug_op_ctx(ctx, "siglen: %lu", *siglen);

out:
	if (sign_md != NULL)
		EVP_MD_free(sign_md);

	return rc;
}

static int sk_prov_sign_ec_digest_sign_init(void *vctx,
					    const char *mdname,
					    void *vkey,
					    const OSSL_PARAM params[])
{
	struct sk_prov_op_ctx *ctx = vctx;
	struct sk_prov_key *key = vkey;

	sk_debug_op_ctx(ctx, "ctx: %p mdname: %s key: %p", ctx,
			mdname != NULL ? mdname : "", key);
	return sk_prov_sign_op_digest_sign_init(ctx, mdname, key, params,
						sk_prov_sign_ec_sign);
}

static const OSSL_DISPATCH sk_prov_rsa_signature_functions[] = {
	/* Signature context constructor, descructor */
	{ OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))sk_prov_sign_rsa_newctx },
	{ OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))sk_prov_op_freectx },
	{ OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))sk_prov_sign_op_dupctx },
	/* Signing */
	{ OSSL_FUNC_SIGNATURE_SIGN_INIT,
			(void (*)(void))sk_prov_sign_op_sign_init },
	{ OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))sk_prov_sign_rsa_sign },
	/* Verifying */
	{ OSSL_FUNC_SIGNATURE_VERIFY_INIT,
			(void (*)(void))sk_prov_sign_op_verify_init },
	{ OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))sk_prov_sign_op_verify },
	/* Verify recover */
	{ OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT,
			(void (*)(void))sk_prov_sign_op_verify_recover_init },
	{ OSSL_FUNC_SIGNATURE_VERIFY_RECOVER,
			(void (*)(void))sk_prov_sign_op_verify_recover },
	/* Digest Sign */
	{ OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT,
			(void (*)(void))sk_prov_sign_rsa_digest_sign_init },
	{ OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE,
			(void (*)(void))sk_prov_sign_op_digest_sign_update },
	{ OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL,
			(void (*)(void))sk_prov_sign_op_digest_sign_final },
	/* Digest Verify */
	{ OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT,
			(void (*)(void))sk_prov_sign_op_digest_verify_init },
	{ OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE,
			(void (*)(void))sk_prov_sign_op_digest_verify_update },
	{ OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL,
			(void (*)(void))sk_prov_sign_op_digest_verify_final },
	/* Signature parameters */
	{ OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS,
			(void (*)(void))sk_prov_sign_op_get_ctx_params },
	{ OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS,
			(void (*)(void))sk_prov_sign_rsa_gettable_ctx_params },
	{ OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void
			(*)(void))sk_prov_sign_op_set_ctx_params },
	{ OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS,
			(void (*)(void))sk_prov_sign_rsa_settable_ctx_params },
	/* MD parameters */
	{ OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS,
			(void (*)(void))sk_prov_sign_op_get_ctx_md_params },
	{ OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS,
		(void (*)(void))sk_prov_sign_rsa_gettable_ctx_md_params },
	{ OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS,
			(void (*)(void))sk_prov_sign_op_set_ctx_md_params },
	{ OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS,
		(void (*)(void))sk_prov_sign_rsa_settable_ctx_md_params },
	{ 0, NULL }
};

static const OSSL_DISPATCH sk_prov_ecdsa_signature_functions[] = {
	/* Signature context constructor, descructor */
	{ OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))sk_prov_sign_ec_newctx },
	{ OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))sk_prov_op_freectx },
	{ OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))sk_prov_sign_op_dupctx },
	/* Signing */
	{ OSSL_FUNC_SIGNATURE_SIGN_INIT,
			(void (*)(void))sk_prov_sign_op_sign_init },
	{ OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))sk_prov_sign_ec_sign },
	/* Verifying */
	{ OSSL_FUNC_SIGNATURE_VERIFY_INIT,
			(void (*)(void))sk_prov_sign_op_verify_init },
	{ OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))sk_prov_sign_op_verify },
	/* Verify recover */
	{ OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT,
			(void (*)(void))sk_prov_sign_op_verify_recover_init },
	{ OSSL_FUNC_SIGNATURE_VERIFY_RECOVER,
			(void (*)(void))sk_prov_sign_op_verify_recover },
	/* Digest Sign */
	{ OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT,
			(void (*)(void))sk_prov_sign_ec_digest_sign_init },
	{ OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE,
			(void (*)(void))sk_prov_sign_op_digest_sign_update },
	{ OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL,
			(void (*)(void))sk_prov_sign_op_digest_sign_final },
	/* Digest Verify */
	{ OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT,
			(void (*)(void))sk_prov_sign_op_digest_verify_init },
	{ OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE,
			(void (*)(void))sk_prov_sign_op_digest_verify_update },
	{ OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL,
			(void (*)(void))sk_prov_sign_op_digest_verify_final },
	/* Signature parameters */
	{ OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS,
			(void (*)(void))sk_prov_sign_op_get_ctx_params },
	{ OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS,
			(void (*)(void))sk_prov_sign_ec_gettable_ctx_params },
	{ OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void
			(*)(void))sk_prov_sign_op_set_ctx_params },
	{ OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS,
			(void (*)(void))sk_prov_sign_ec_settable_ctx_params },
	/* MD parameters */
	{ OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS,
			(void (*)(void))sk_prov_sign_op_get_ctx_md_params },
	{ OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS,
		(void (*)(void))sk_prov_sign_ec_gettable_ctx_md_params },
	{ OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS,
			(void (*)(void))sk_prov_sign_op_set_ctx_md_params },
	{ OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS,
		(void (*)(void))sk_prov_sign_ec_settable_ctx_md_params },
	{ 0, NULL }
};

static const OSSL_ALGORITHM sk_prov_signature[] = {
	{ "RSA:rsaEncryption", "provider="SK_PROV_NAME,
				sk_prov_rsa_signature_functions, NULL },
	{ "ECDSA", "provider="SK_PROV_NAME,
				sk_prov_ecdsa_signature_functions, NULL },
	{ NULL, NULL, NULL, NULL }
};

static const OSSL_DISPATCH sk_prov_rsa_asym_cipher_functions[] = {
	/* RSA context constructor, descructor */
	{ OSSL_FUNC_ASYM_CIPHER_NEWCTX,
			(void (*)(void))sk_prov_asym_rsa_newctx },
	{ OSSL_FUNC_ASYM_CIPHER_FREECTX, (void (*)(void))sk_prov_op_freectx },
	{ OSSL_FUNC_ASYM_CIPHER_DUPCTX,
			(void (*)(void))sk_prov_asym_op_dupctx },
	/* RSA context set/get parameters */
	{ OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS,
			(void (*)(void))sk_prov_asym_op_get_ctx_params },
	{ OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS,
			(void (*)(void))sk_prov_asym_rsa_gettable_ctx_params },
	{ OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS,
			(void (*)(void))sk_prov_asym_op_set_ctx_params },
	{ OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS,
			(void (*)(void))sk_prov_asym_rsa_settable_ctx_params },
	/* RSA encrypt */
	{ OSSL_FUNC_ASYM_CIPHER_ENCRYPT_INIT,
			(void (*)(void))sk_prov_asym_op_encrypt_init },
	{ OSSL_FUNC_ASYM_CIPHER_ENCRYPT,
			(void (*)(void))sk_prov_asym_op_encrypt },
	/* RSA decrypt */
	{ OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT,
			(void (*)(void))sk_prov_asym_op_decrypt_init },
	{ OSSL_FUNC_ASYM_CIPHER_DECRYPT,
			(void (*)(void))sk_prov_asym_rsa_decrypt },
	{ 0, NULL }
};

static const OSSL_ALGORITHM sk_prov_asym_cipher[] = {
	{ "RSA:rsaEncryption", "provider="SK_PROV_NAME,
				sk_prov_rsa_asym_cipher_functions, NULL },
	{ NULL, NULL, NULL, NULL }
};


static const OSSL_DISPATCH sk_prov_rsa_keymgmt_functions[] = {
	/* Constructor, destructor */
	{ OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))sk_prov_keymgmt_rsa_new },
	{ OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))sk_prov_keymgmt_free },

	/* Key generation and loading */
	{ OSSL_FUNC_KEYMGMT_GEN_INIT,
			(void (*)(void))sk_prov_keymgmt_rsa_gen_init },
	{ OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE,
			(void (*)(void))sk_prov_keymgmt_gen_set_template },
	{ OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS,
			(void (*)(void))sk_prov_keymgmt_gen_set_params },
	{ OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS,
		(void (*)(void))sk_prov_keymgmt_rsa_gen_settable_params },
	{ OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))sk_prov_keymgmt_gen },
	{ OSSL_FUNC_KEYMGMT_GEN_CLEANUP,
			(void (*)(void))sk_prov_keymgmt_gen_cleanup },
	{ OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))sk_prov_keymgmt_load },

	/* Key object checking */
	{ OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))sk_prov_keymgmt_has },
	{ OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))sk_prov_keymgmt_match },
	{ OSSL_FUNC_KEYMGMT_VALIDATE,
			(void (*)(void))sk_prov_keymgmt_validate },
	{ OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME,
		(void (*)(void))sk_prov_keymgmt_rsa_query_operation_name },

	/* Key object information */
	{ OSSL_FUNC_KEYMGMT_GET_PARAMS,
			(void (*) (void))sk_prov_keymgmt_get_params },
	{ OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS,
			(void (*) (void))sk_prov_keymgmt_rsa_gettable_params },
	{ OSSL_FUNC_KEYMGMT_SET_PARAMS,
			(void (*) (void))sk_prov_keymgmt_set_params },
	{ OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS,
			(void (*) (void))sk_prov_keymgmt_rsa_settable_params },

	/* Import and export routines */
	{ OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))sk_prov_keymgmt_export },
#ifdef OSSL_FUNC_KEYMGMT_EXPORT_TYPES_EX
	{ OSSL_FUNC_KEYMGMT_EXPORT_TYPES_EX,
			(void (*)(void))sk_prov_keymgmt_rsa_export_types_ex },
#else
	{ OSSL_FUNC_KEYMGMT_EXPORT_TYPES,
			(void (*)(void))sk_prov_keymgmt_rsa_export_types },
#endif
	{ OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))sk_prov_keymgmt_import },
#ifdef OSSL_FUNC_KEYMGMT_EXPORT_TYPES_EX
	{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES_EX,
			(void (*)(void))sk_prov_keymgmt_rsa_import_types_ex },
#else
	{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES,
			(void (*)(void))sk_prov_keymgmt_rsa_import_types },
#endif
	/* No copy function, OpenSSL will use export/import to copy instead */

	{ 0, NULL }
};

static const OSSL_DISPATCH sk_prov_rsapss_keymgmt_functions[] = {
	/* Constructor, destructor */
	{ OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))sk_prov_keymgmt_rsa_pss_new },
	{ OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))sk_prov_keymgmt_free },

	/* Key generation and loading */
	{ OSSL_FUNC_KEYMGMT_GEN_INIT,
			(void (*)(void))sk_prov_keymgmt_rsa_pss_gen_init },
	{ OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE,
			(void (*)(void))sk_prov_keymgmt_gen_set_template },
	{ OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS,
			(void (*)(void))sk_prov_keymgmt_gen_set_params },
	{ OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS,
		(void (*)(void))sk_prov_keymgmt_rsa_pss_gen_settable_params },
	{ OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))sk_prov_keymgmt_gen },
	{ OSSL_FUNC_KEYMGMT_GEN_CLEANUP,
			(void (*)(void))sk_prov_keymgmt_gen_cleanup },
	{ OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))sk_prov_keymgmt_load },

	/* Key object checking */
	{ OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))sk_prov_keymgmt_has },
	{ OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))sk_prov_keymgmt_match },
	{ OSSL_FUNC_KEYMGMT_VALIDATE,
			(void (*)(void))sk_prov_keymgmt_validate },
	{ OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME,
		(void (*)(void))sk_prov_keymgmt_rsa_query_operation_name },

	/* Key object information */
	{ OSSL_FUNC_KEYMGMT_GET_PARAMS,
			(void (*) (void))sk_prov_keymgmt_get_params },
	{ OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS,
		(void (*) (void))sk_prov_keymgmt_rsa_pss_gettable_params },
	{ OSSL_FUNC_KEYMGMT_SET_PARAMS,
			(void (*) (void))sk_prov_keymgmt_set_params },
	{ OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS,
		(void (*) (void))sk_prov_keymgmt_rsa_pss_settable_params },

	/* Import and export routines */
	{ OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))sk_prov_keymgmt_export },
#ifdef OSSL_FUNC_KEYMGMT_EXPORT_TYPES_EX
	{ OSSL_FUNC_KEYMGMT_EXPORT_TYPES_EX,
		(void (*)(void))sk_prov_keymgmt_rsa_pss_export_types_ex },
#else
	{ OSSL_FUNC_KEYMGMT_EXPORT_TYPES,
			(void (*)(void))sk_prov_keymgmt_rsa_pss_export_types },
#endif
	{ OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))sk_prov_keymgmt_import },
#ifdef OSSL_FUNC_KEYMGMT_EXPORT_TYPES_EX
	{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES_EX,
		(void (*)(void))sk_prov_keymgmt_rsa_pss_import_types_ex },
#else
	{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES,
			(void (*)(void))sk_prov_keymgmt_rsa_pss_import_types },
#endif
	/* No copy function, OpenSSL will use export/import to copy instead */

	{ 0, NULL }
};

static const OSSL_DISPATCH sk_prov_ec_keymgmt_functions[] = {
	/* Constructor, destructor */
	{ OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))sk_prov_keymgmt_ec_new },
	{ OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))sk_prov_keymgmt_free },

	/* Key generation and loading */
	{ OSSL_FUNC_KEYMGMT_GEN_INIT,
			(void (*)(void))sk_prov_keymgmt_ec_gen_init },
	{ OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE,
			(void (*)(void))sk_prov_keymgmt_gen_set_template },
	{ OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS,
			(void (*)(void))sk_prov_keymgmt_gen_set_params },
	{ OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS,
		(void (*)(void))sk_prov_keymgmt_ec_gen_settable_params },
	{ OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))sk_prov_keymgmt_gen },
	{ OSSL_FUNC_KEYMGMT_GEN_CLEANUP,
			(void (*)(void))sk_prov_keymgmt_gen_cleanup },
	{ OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))sk_prov_keymgmt_load },

	/* Key object checking */
	{ OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))sk_prov_keymgmt_has },
	{ OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))sk_prov_keymgmt_match },
	{ OSSL_FUNC_KEYMGMT_VALIDATE,
			(void (*)(void))sk_prov_keymgmt_validate },
	{ OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME,
		(void (*)(void))sk_prov_keymgmt_ec_query_operation_name },

	/* Key object information */
	{ OSSL_FUNC_KEYMGMT_GET_PARAMS,
			(void (*) (void))sk_prov_keymgmt_get_params },
	{ OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS,
			(void (*) (void))sk_prov_keymgmt_ec_gettable_params },
	{ OSSL_FUNC_KEYMGMT_SET_PARAMS,
			(void (*) (void))sk_prov_keymgmt_set_params },
	{ OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS,
			(void (*) (void))sk_prov_keymgmt_ec_settable_params },

	/* Import and export routines */
	{ OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))sk_prov_keymgmt_export },
#ifdef OSSL_FUNC_KEYMGMT_EXPORT_TYPES_EX
	{ OSSL_FUNC_KEYMGMT_EXPORT_TYPES_EX,
			(void (*)(void))sk_prov_keymgmt_ec_export_types_ex },
#else
	{ OSSL_FUNC_KEYMGMT_EXPORT_TYPES,
			(void (*)(void))sk_prov_keymgmt_ec_export_types },
#endif
	{ OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))sk_prov_keymgmt_import },
#ifdef OSSL_FUNC_KEYMGMT_EXPORT_TYPES_EX
	{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES_EX,
			(void (*)(void))sk_prov_keymgmt_ec_import_types_ex },
#else
	{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES,
			(void (*)(void))sk_prov_keymgmt_ec_import_types },
#endif
	/* No copy function, OpenSSL will use export/import to copy instead */

	{ 0, NULL }
};

static const OSSL_ALGORITHM sk_prov_keymgmt[] = {
	{ "RSA:rsaEncryption", "provider="SK_PROV_NAME,
				sk_prov_rsa_keymgmt_functions, NULL },
	{ "RSA-PSS:RSASSA-PSS", "provider="SK_PROV_NAME,
				sk_prov_rsapss_keymgmt_functions, NULL },
	{ "EC:id-ecPublicKey", "provider="SK_PROV_NAME,
				sk_prov_ec_keymgmt_functions, NULL },
	{ NULL, NULL, NULL, NULL }
};

static const OSSL_DISPATCH sk_prov_ec_keyexch_functions[] = {
	/* Context management */
	{ OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))sk_prov_keyexch_ec_newctx },
	{ OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))sk_prov_op_freectx },
	{ OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))sk_prov_keyexch_ec_dupctx },

	/* Shared secret derivation */
	{ OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))sk_prov_keyexch_ec_init },
	{ OSSL_FUNC_KEYEXCH_SET_PEER,
		(void (*)(void))sk_prov_keyexch_ec_set_peer },
	{ OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))sk_prov_keyexch_ec_derive },

	/* Key Exchange parameters */
	{ OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS,
		(void (*)(void))sk_prov_keyexch_ec_set_ctx_params },
	{ OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS,
		(void (*)(void))sk_prov_keyexch_ec_settable_ctx_params },
	{ OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS,
			(void (*)(void))sk_prov_keyexch_ec_get_ctx_params },
	{ OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS,
		(void (*)(void))sk_prov_keyexch_ec_gettable_ctx_params },

	{ 0, NULL }
};

/*
 * Although ECDH key derivation is not supported for secure keys (would result
 * in a secure symmetric key, which OpenSSL can't handle), the provider still
 * must implement the ECDH key exchange functions and proxy them all to the
 * default provider. OpenSSL common code requires that the key management
 * provider and the key exchange provider for a derive operation is the same.
 * So for clear EC keys created with this provider, we do support the ECDH
 * operation by proxy'ing it to the default provider.
 */
static const OSSL_ALGORITHM sk_prov_keyexch[] = {
	{ "ECDH", "provider="SK_PROV_NAME, sk_prov_ec_keyexch_functions, NULL },
	{ NULL, NULL, NULL, NULL }
};

static const OSSL_PARAM sk_prov_param_types[] = {
	OSSL_PARAM_DEFN(OSSL_PROV_PARAM_NAME, OSSL_PARAM_UTF8_PTR, NULL, 0),
	OSSL_PARAM_DEFN(OSSL_PROV_PARAM_VERSION, OSSL_PARAM_UTF8_PTR, NULL, 0),
	OSSL_PARAM_DEFN(OSSL_PROV_PARAM_BUILDINFO, OSSL_PARAM_UTF8_PTR, NULL,
									0),
	OSSL_PARAM_DEFN(OSSL_PROV_PARAM_STATUS, OSSL_PARAM_INTEGER, NULL, 0),
	OSSL_PARAM_END
};

static const OSSL_PARAM *sk_prov_gettable_params(void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_param_types;
}

static int sk_prov_get_params(void *vprovctx, OSSL_PARAM params[])
{
	struct sk_prov_ctx *provctx = vprovctx;
	OSSL_PARAM *p;

	if (provctx == NULL)
		return 0;

	sk_debug_ctx(provctx, "provctx: %p", provctx);

	p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_NAME);
	if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, SK_PROV_DESCRIPTION)) {
		put_error_ctx(provctx, SK_PROV_ERR_INTERNAL_ERROR,
			      "OSSL_PARAM_set_utf8_ptr failed");
		return 0;
	}
	p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_VERSION);
	if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, SK_PROV_VERSION)) {
		put_error_ctx(provctx, SK_PROV_ERR_INTERNAL_ERROR,
			      "OSSL_PARAM_set_utf8_ptr failed");
	return 0;
	}
	p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_BUILDINFO);
	if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, SK_PROV_VERSION)) {
		put_error_ctx(provctx, SK_PROV_ERR_INTERNAL_ERROR,
			      "OSSL_PARAM_set_utf8_ptr failed");
		return 0;
	}
	p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_STATUS);
	if (p != NULL && !OSSL_PARAM_set_int(p, 1)) {
		put_error_ctx(provctx, SK_PROV_ERR_INTERNAL_ERROR,
			      "OSSL_PARAM_set_int failed");
		return 0;
	}

	return 1;
}

static const OSSL_ALGORITHM *sk_prov_query(void *vprovctx,
					   int operation_id, int *no_cache)
{
	struct sk_prov_ctx *provctx = vprovctx;

	if (provctx == NULL)
		return NULL;

	*no_cache = 0;

	sk_debug_ctx(provctx, "provctx: %p operation_id: %d", provctx,
		     operation_id);

	switch (operation_id) {
	case OSSL_OP_KEYMGMT:
		return sk_prov_keymgmt;
	case OSSL_OP_KEYEXCH:
		return sk_prov_keyexch;
	case OSSL_OP_SIGNATURE:
		return sk_prov_signature;
	case OSSL_OP_ASYM_CIPHER:
		return sk_prov_asym_cipher;
	}

	return NULL;
}

static void sk_prov_teardown(void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;
	int i;

	if (provctx == NULL)
		return;

	sk_debug_ctx(provctx, "provctx: %p", provctx);

	for (i = 0; i < SK_PROV_CACHED_PARAMS_COUNT; i++) {
		if (provctx->cached_parms[i] != NULL)
			OPENSSL_free((void *)provctx->cached_parms[i]);
	}

	OPENSSL_free(provctx);
}

static const OSSL_ITEM *sk_prov_get_reason_strings(void *vprovctx)
{
	struct sk_prov_ctx *provctx = vprovctx;

	sk_debug_ctx(provctx, "provctx: %p", provctx);
	return sk_prov_reason_strings;
}

static int sk_prov_prov_get_capabilities(void *vprovctx,
					 const char *capability,
					 OSSL_CALLBACK *cb, void *arg)
{
	struct sk_prov_ctx *provctx = vprovctx;

	sk_debug_ctx(provctx, "provctx: %p capability: %s", provctx,
		     capability);

	if (provctx->default_provider == NULL)
		return 0;

	return OSSL_PROVIDER_get_capabilities(provctx->default_provider,
					      capability, cb, arg);
}

/* Functions we provide to the core */
static const OSSL_DISPATCH sk_prov_dispatch_table[] = {
	{ OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))sk_prov_teardown },
	{ OSSL_FUNC_PROVIDER_GETTABLE_PARAMS,
				(void (*)(void))sk_prov_gettable_params },
	{ OSSL_FUNC_PROVIDER_GET_PARAMS, (void (*)(void))sk_prov_get_params },
	{ OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))sk_prov_query },
	{ OSSL_FUNC_PROVIDER_GET_REASON_STRINGS,
				(void (*)(void))sk_prov_get_reason_strings },
	{ OSSL_FUNC_PROVIDER_GET_CAPABILITIES,
				(void (*)(void))sk_prov_prov_get_capabilities },
	{ 0, NULL }
};

static int sk_provider_init(const OSSL_CORE_HANDLE *handle,
			    const OSSL_DISPATCH *in,
			    const OSSL_DISPATCH **out, void **provctx)
{
	OSSL_FUNC_core_set_error_debug_fn *c_set_error_debug = NULL;
	OSSL_FUNC_core_get_libctx_fn *c_get_libctx = NULL;
	OSSL_FUNC_core_vset_error_fn *c_vset_error = NULL;
	OSSL_FUNC_core_new_error_fn *c_new_error = NULL;
	struct sk_prov_ctx *ctx;

	if (handle == NULL || in == NULL || out == NULL || provctx == NULL)
		return 0;

	for (; in->function_id != 0; in++) {
		switch (in->function_id) {
		case OSSL_FUNC_CORE_GET_LIBCTX:
			c_get_libctx = OSSL_FUNC_core_get_libctx(in);
			break;
		case OSSL_FUNC_CORE_NEW_ERROR:
			c_new_error = OSSL_FUNC_core_new_error(in);
			break;
		case OSSL_FUNC_CORE_SET_ERROR_DEBUG:
			c_set_error_debug = OSSL_FUNC_core_set_error_debug(in);
			break;
		case OSSL_FUNC_CORE_VSET_ERROR:
			c_vset_error = OSSL_FUNC_core_vset_error(in);
			break;
		default:
			/* Just ignore anything we don't understand */
			break;
		}
	}

	if (c_get_libctx == NULL)
		return 0;

	ctx = OPENSSL_zalloc(sizeof(struct sk_prov_ctx));
	if (ctx == NULL) {
		c_new_error(handle);
		c_set_error_debug(handle, __FILE__, __LINE__, __func__);
		c_vset_error(handle, SK_PROV_ERR_MALLOC_FAILED,
			     "Failed to allocate provider context", NULL);
		return 0;
	}

	ctx->handle = handle;
	ctx->c_get_libctx = c_get_libctx;
	ctx->c_new_error = c_new_error;
	ctx->c_set_error_debug = c_set_error_debug;
	ctx->c_vset_error = c_vset_error;
	*provctx = ctx;

	*out = sk_prov_dispatch_table;
	return 1;
}

/**
 * Initializes the secure key support for OpenSSL.
 *
 * @param debug             true to enable internal debugging
 *
 * @returns zero for success, a negative errno in case of an error:
 *          -ENOMEM: failed to allocate memory
 *          -EIO: OpenSSL failed for various reasons
 */
int SK_OPENSSL_init(bool debug)
{
	struct sk_prov_ctx *provctx;

	if (sk_prov_securekey_libctx == NULL)
		sk_prov_securekey_libctx = OSSL_LIB_CTX_new();
	if (sk_prov_securekey_libctx == NULL) {
		sk_debug(debug, "ERROR: OSSL_LIB_CTX_new failed");
		return -ENOMEM;
	}

	if (OSSL_PROVIDER_add_builtin(sk_prov_securekey_libctx, SK_PROV_NAME,
				      sk_provider_init) != 1) {
		sk_debug(debug, "ERROR: OSSL_PROVIDER_add_builtin failed");
		return -EIO;
	}

	if (sk_prov_securekey_provider == NULL) {
		sk_prov_securekey_provider =
				OSSL_PROVIDER_load(sk_prov_securekey_libctx,
						   SK_PROV_NAME);
		if (sk_prov_securekey_provider == NULL) {
			sk_debug(debug, "ERROR: OSSL_PROVIDER_load("
				SK_PROV_NAME") failed");
			return -EIO;
		}
	}
	provctx = OSSL_PROVIDER_get0_provider_ctx(sk_prov_securekey_provider);
	provctx->debug = debug;

	if (sk_prov_default_provider == NULL) {
		sk_prov_default_provider =
				OSSL_PROVIDER_load(sk_prov_securekey_libctx,
						      "default");
		if (sk_prov_default_provider == NULL) {
			sk_debug(debug,
				 "ERROR: OSSL_PROVIDER_load(default) failed");
			SK_OPENSSL_term();
			return -EIO;
		}
	}
	provctx->default_provider = sk_prov_default_provider;
	provctx->default_provctx =
		OSSL_PROVIDER_get0_provider_ctx(sk_prov_default_provider);

	sk_prov_previous_libctx =
			OSSL_LIB_CTX_set0_default(sk_prov_securekey_libctx);
	if (sk_prov_previous_libctx == NULL) {
		sk_debug(debug, "ERROR: OSSL_LIB_CTX_set0_default failed");
		SK_OPENSSL_term();
		return -EIO;
	}

	/* Prefer the secure key provider, but allow to fall back to default */
	if (!EVP_set_default_properties(sk_prov_securekey_libctx,
					"?provider="SK_PROV_NAME)) {
		sk_debug(debug, "ERROR: EVP_set_default_properties failed");
		SK_OPENSSL_term();
		return -EIO;
	}

	sk_debug(debug, "sk_provider support initialized, provctx: %p",
		 provctx);
	return 0;
}

/**
 * Terminate the secure key support for OpenSSL.
 */
void SK_OPENSSL_term(void)
{
	if (sk_prov_securekey_provider != NULL)
		OSSL_PROVIDER_unload(sk_prov_securekey_provider);
	sk_prov_securekey_provider = NULL;

	if (sk_prov_default_provider != NULL)
		OSSL_PROVIDER_unload(sk_prov_default_provider);
	sk_prov_default_provider = NULL;

	if (sk_prov_previous_libctx != NULL)
		OSSL_LIB_CTX_set0_default(sk_prov_previous_libctx);
	sk_prov_previous_libctx = NULL;

	if (sk_prov_securekey_libctx != NULL)
		OSSL_LIB_CTX_free(sk_prov_securekey_libctx);
	sk_prov_securekey_libctx = NULL;
}

static int sk_openssl_pkey_from_data(OSSL_PARAM_BLD *bld, int pkey_type,
				     EVP_PKEY **pkey, bool debug)
{
	OSSL_PARAM *params = NULL;
	EVP_PKEY_CTX *pctx = NULL;
	const char *key_name;
	int rc = 0;

	switch (pkey_type) {
	case EVP_PKEY_EC:
		key_name = "EC";
		break;
	case EVP_PKEY_RSA:
		key_name = "RSA";
		break;
	case EVP_PKEY_RSA_PSS:
		key_name = "RSA-PSS";
		break;
	default:
		sk_debug(debug, "ERROR: unsupported PKEY type");
		return -EINVAL;
	}

	params = OSSL_PARAM_BLD_to_param(bld);
	if (params == NULL) {
		sk_debug(debug, "ERROR: OSSL_PARAM_BLD_to_param failed");
		rc = -EIO;
		goto out;
	}

	pctx = EVP_PKEY_CTX_new_from_name(NULL, key_name,
					  "provider="SK_PROV_NAME);
	if (pctx == NULL) {
		sk_debug(debug, "ERROR: EVP_PKEY_CTX_new_from_name failed");
		return -EIO;
	}

	if (EVP_PKEY_fromdata_init(pctx) <= 0) {
		sk_debug(debug, "ERROR: EVP_PKEY_fromdata_init failed");
		rc = -EIO;
		goto out;
	}

	if (EVP_PKEY_fromdata(pctx, pkey, EVP_PKEY_KEYPAIR, params) <= 0) {
		sk_debug(debug, "ERROR: EVP_PKEY_fromdata failed");
		rc = -EIO;
		goto out;
	}

out:
	if (pctx != NULL)
		EVP_PKEY_CTX_free(pctx);
	if (params != NULL)
		OSSL_PARAM_free(params);

	return rc;
}

/**
 * Converts an EC key given by the nid and the x and y coordinates into an
 * OpenSSL PKEY and attaches the secure key together with secure key functions
 * and private pointer to it. If no secure key is provided, a public EC key
 * only PKEY is returned.
 *
 * @param secure_key        the secure key blob.
 *                          If NULL, a clear key PKEY is created.
 * @param secure_key_size   the size of the secure key blob (ignored if
 *                          secure_key is NULL)
 * @param nid               the OpenSSL nid of the EC curve used
 * @param prime_len         the length of the prime in bytes. This is also the
 *                          length of the x and y coordinates.
 * @param x                 the x coordinate as big endian binary number in
 *                          prime_len size
 * @param y                 the y coordinate as big endian binary number in
 *                          prime_len size
 * @param sk_funcs          the secure key functions to operate with the key.
 *                          Ignored if secure_key is NULL, required otherwise.
 * @param private           a private pointer that is passed to the secure key
 *                          functions (can be NULL)
 * @param pkey              On return: A PKEY containing the EC public key.
 * @param debug             true to enable internal debugging
 *
 * @returns zero for success, a negative errno in case of an error:
 *          -EINVAL: a function parameter is invalid
 *          -ENOMEM: failed to allocate memory
 *          -EIO: OpenSSL failed to generate the PKEY
 *          -ENOENT: OpenSSL does not know/support the curve (nid)
 */
int sk_openssl_get_pkey_ec(const unsigned char *secure_key,
			   size_t secure_key_size, int nid, size_t prime_len,
			   const unsigned char *x, const unsigned char *y,
			   const struct sk_funcs *sk_funcs, const void *private,
			   EVP_PKEY **pkey, bool debug)
{
	BIGNUM *bn_x = NULL, *bn_y = NULL;
	point_conversion_form_t form;
	unsigned char *pub_key = NULL;
	OSSL_PARAM_BLD *bld = NULL;
	EC_GROUP *group = NULL;
	EC_POINT *point = NULL;
	size_t pub_key_len;
	int rc;

	if (pkey == NULL || x == NULL || y == NULL)
		return -EINVAL;
	if (secure_key != NULL && (secure_key_size == 0 || sk_funcs == NULL))
		return -EINVAL;

	*pkey = NULL;

	group = EC_GROUP_new_by_curve_name(nid);
	if (group == NULL) {
		sk_debug(debug, "ERROR: EC_GROUP_new_by_curve_name failed");
		rc = -ENOENT;
		goto out;
	}

	bn_x = BN_bin2bn(x, prime_len, NULL);
	bn_y = BN_bin2bn(y, prime_len, NULL);
	if (bn_x == NULL || bn_y == NULL) {
		sk_debug(debug, "ERROR: BN_bin2bn failed");
		rc = -ENOMEM;
		goto out;
	}

	point = EC_POINT_new(group);
	if (point == NULL) {
		sk_debug(debug, "ERROR: EC_POINT_new failed");
		rc = -ENOMEM;
		goto out;
	}

	if (!EC_POINT_set_affine_coordinates(group, point, bn_x, bn_y, NULL)) {
		sk_debug(debug, "ERROR: EC_POINT_set_affine_coordinates failed");
		rc = -EIO;
		goto out;
	}

	form = EC_GROUP_get_point_conversion_form(group);
	pub_key_len = EC_POINT_point2buf(group, point, form, &pub_key, NULL);
	if (pub_key_len == 0) {
		sk_debug(debug, "ERROR: EC_POINT_point2buf failed");
		rc = -EIO;
		goto out;
	}

	bld = OSSL_PARAM_BLD_new();
	if (bld == NULL) {
		sk_debug(debug, "ERROR: OSSL_PARAM_BLD_new failed");
		rc = -ENOMEM;
		goto out;
	}

	if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME,
					     OBJ_nid2sn(nid), 0)
	    || !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_PUB_X, bn_x)
	    || !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_PUB_Y, bn_y)
	    || !OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY,
						 pub_key, pub_key_len)) {
		sk_debug(debug, "ERROR: OSSL_PARAM_BLD_push_xxx failed");
		rc = -EIO;
		goto out;
	}

	if (secure_key != NULL) {
		if (!OSSL_PARAM_BLD_push_octet_string(bld,
						SK_PROV_PKEY_PARAM_SK_BLOB,
						secure_key, secure_key_size)
		    || !OSSL_PARAM_BLD_push_octet_ptr(bld,
						SK_PROV_PKEY_PARAM_SK_FUNCS,
						(void *)sk_funcs,
						sizeof(struct sk_funcs))
		    || !OSSL_PARAM_BLD_push_octet_ptr(bld,
						SK_PROV_PKEY_PARAM_SK_PRIVATE,
						(void *)private, 0)) {
			sk_debug(debug,
				 "ERROR: OSSL_PARAM_BLD_push_xxx failed");
			rc = -EIO;
			goto out;
		}
	}

	rc = sk_openssl_pkey_from_data(bld, EVP_PKEY_EC, pkey, debug);
	if (rc != 0)
		goto out;

	rc = 0;
	sk_debug(debug, "pkey created: %p", *pkey);

out:
	if (group != NULL)
		EC_GROUP_free(group);
	if (point != NULL)
		EC_POINT_free(point);
	if (bn_x != NULL)
		BN_free(bn_x);
	if (bn_y != NULL)
		BN_free(bn_y);
	if (bld != NULL)
		OSSL_PARAM_BLD_free(bld);
	if (pub_key != NULL)
		OPENSSL_free(pub_key);

	return rc;
}

/**
 * Converts an RSA key given by the modulus and public exponent into an
 * OpenSSL PKEY and attaches the secure key together with secure key functions
 * and private pointer to it. If no secure key is provided, a public RSA key
 * only PKEY is returned.
 *
 * @param secure_key        the secure key blob.
 *                          If NULL, a clear key PKEY is created.
 * @param secure_key_size   the size of the secure key blob (ignored if
 *                          secure_key is NULL)
 * @param modulus           the modulus as big endian number
 * @param modulus_length    the length of the modulus in bytes
 * @param pub_exp           the public exponent as big endian number
 * @param pub_exp_length    the length of the public exponent in bytes
 * @param pkey_type         the PKEY type (EVP_PKEY_RSA or EVP_PKEY_RSA_PSS)
 * @param sk_funcs          the secure key functions to operate with the key.
 *                          Ignored if secure_key is NULL, required otherwise.
 * @param private           a private pointer that is passed to the secure key
 *                          functions (can be NULL)
 * @param pkey              On return: A PKEY containing the RSA public key.
 * @param debug             true to enable internal debugging
 *
 * @returns zero for success, a negative errno in case of an error:
 *          -EINVAL: a function parameter is invalid
 *          -ENOMEM: failed to allocate memory
 *          -EIO: OpenSSL failed to generate the PKEY
 */
int sk_openssl_get_pkey_rsa(const unsigned char *secure_key,
			    size_t secure_key_size,
			    const unsigned char *modulus, size_t modulus_length,
			    const unsigned char *pub_exp, size_t pub_exp_length,
			    int pkey_type, const struct sk_funcs *sk_funcs,
			    const void *private, EVP_PKEY **pkey, bool debug)
{
	BIGNUM *bn_modulus = NULL, *bn_pub_exp = NULL;
	OSSL_PARAM_BLD *bld = NULL;
	int rc;

	if (pkey == NULL || modulus == NULL || pub_exp == NULL)
		return -EINVAL;
	if (secure_key != NULL && (secure_key_size == 0 || sk_funcs == NULL))
		return -EINVAL;
	if (pkey_type != EVP_PKEY_RSA && pkey_type != EVP_PKEY_RSA_PSS)
		return -EINVAL;

	*pkey = NULL;

	bn_modulus = BN_bin2bn(modulus, modulus_length, NULL);
	bn_pub_exp = BN_bin2bn(pub_exp, pub_exp_length, NULL);
	if (bn_modulus == NULL || bn_pub_exp == NULL) {
		sk_debug(debug, "ERROR: BN_bin2bn failed");
		rc = -ENOMEM;
		goto out;
	}

	bld = OSSL_PARAM_BLD_new();
	if (bld == NULL) {
		sk_debug(debug, "ERROR: OSSL_PARAM_BLD_new failed");
		rc = -ENOMEM;
		goto out;
	}

	if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, bn_modulus) ||
	    !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, bn_pub_exp)) {
		sk_debug(debug, "ERROR: OSSL_PARAM_BLD_push_xxx failed");
		rc = -EIO;
		goto out;
	}

	if (secure_key != NULL) {
		if (!OSSL_PARAM_BLD_push_octet_string(bld,
						SK_PROV_PKEY_PARAM_SK_BLOB,
						secure_key, secure_key_size)
		    || !OSSL_PARAM_BLD_push_octet_ptr(bld,
						SK_PROV_PKEY_PARAM_SK_FUNCS,
						(void *)sk_funcs,
						sizeof(struct sk_funcs))
		    || !OSSL_PARAM_BLD_push_octet_ptr(bld,
						SK_PROV_PKEY_PARAM_SK_PRIVATE,
						(void *)private, 0)) {
			sk_debug(debug,
				 "ERROR: OSSL_PARAM_BLD_push_xxx failed");
			rc = -EIO;
			goto out;
		}
	}

	rc = sk_openssl_pkey_from_data(bld, pkey_type, pkey, debug);
	if (rc != 0)
		goto out;

	rc = 0;
	sk_debug(debug, "pkey created: %p", *pkey);

out:
	if (bn_modulus != NULL)
		BN_free(bn_modulus);
	if (bn_pub_exp != NULL)
		BN_free(bn_pub_exp);
	if (bld != NULL)
		OSSL_PARAM_BLD_free(bld);

	return rc;
}

/**
 * Get the curve NID of the EC pkey
 */
int SK_OPENSSL_get_curve_from_ec_pkey(EVP_PKEY *pkey)
{
	size_t curve_len;
	char curve[80];

	if (EVP_PKEY_id(pkey) != EVP_PKEY_EC)
		return NID_undef;

	if (!EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME,
					    curve, sizeof(curve), &curve_len))
		return NID_undef;

	return OBJ_sn2nid(curve);
}

#endif
