X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fevp%2Fexchange.c;h=7c61a12b3bae2fdbaa8c39d19910a57a81bc9eff;hp=208bb9885a3de082486735eb484477feab8d0e9b;hb=864b89ce497c57207d04a83e23f96f50dae9d164;hpb=35aca9eccbaf0abbd0d7f350e199a7c97274845a diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c index 208bb9885a..7c61a12b3b 100644 --- a/crypto/evp/exchange.c +++ b/crypto/evp/exchange.c @@ -13,6 +13,7 @@ #include "internal/refcount.h" #include "internal/evp_int.h" #include "internal/provider.h" +#include "internal/numbers.h" /* includes SIZE_MAX */ #include "evp_locl.h" static EVP_KEYEXCH *evp_keyexch_new(OSSL_PROVIDER *prov) @@ -31,14 +32,39 @@ static EVP_KEYEXCH *evp_keyexch_new(OSSL_PROVIDER *prov) return exchange; } -static void *evp_keyexch_from_dispatch(const OSSL_DISPATCH *fns, - OSSL_PROVIDER *prov) +static void *evp_keyexch_from_dispatch(const char *name, + const OSSL_DISPATCH *fns, + OSSL_PROVIDER *prov, + void *vkeymgmt_data) { + /* + * Key exchange cannot work without a key, and key management + * from the same provider to manage its keys. We therefore fetch + * a key management method using the same algorithm and properties + * and pass that down to evp_generic_fetch to be passed on to our + * evp_keyexch_from_dispatch, which will attach the key management + * method to the newly created key exchange method as long as the + * provider matches. + */ + struct keymgmt_data_st *keymgmt_data = vkeymgmt_data; + EVP_KEYMGMT *keymgmt = EVP_KEYMGMT_fetch(keymgmt_data->ctx, name, + keymgmt_data->properties); EVP_KEYEXCH *exchange = NULL; - int fncnt = 0; + int fncnt = 0, paramfncnt = 0; - if ((exchange = evp_keyexch_new(prov)) == NULL) - return NULL; + if (keymgmt == NULL || EVP_KEYMGMT_provider(keymgmt) != prov) { + ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEYMGMT_AVAILABLE); + goto err; + } + + if ((exchange = evp_keyexch_new(prov)) == NULL + || (exchange->name = OPENSSL_strdup(name)) == NULL) { + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + + exchange->keymgmt = keymgmt; + keymgmt = NULL; /* avoid double free on failure below */ for (; fns->function_id != 0; fns++) { switch (fns->function_id) { @@ -76,27 +102,40 @@ static void *evp_keyexch_from_dispatch(const OSSL_DISPATCH *fns, break; exchange->dupctx = OSSL_get_OP_keyexch_dupctx(fns); break; - case OSSL_FUNC_KEYEXCH_SET_PARAMS: - if (exchange->set_params != NULL) + case OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS: + if (exchange->set_ctx_params != NULL) + break; + exchange->set_ctx_params = OSSL_get_OP_keyexch_set_ctx_params(fns); + paramfncnt++; + break; + case OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS: + if (exchange->settable_ctx_params != NULL) break; - exchange->set_params = OSSL_get_OP_keyexch_set_params(fns); + exchange->settable_ctx_params + = OSSL_get_OP_keyexch_settable_ctx_params(fns); + paramfncnt++; break; } } - if (fncnt != 4) { + if (fncnt != 4 || (paramfncnt != 0 && paramfncnt != 2)) { /* * In order to be a consistent set of functions we must have at least * a complete set of "exchange" functions: init, derive, newctx, - * and freectx. The dupctx, set_peer and set_params functions are - * optional. + * and freectx. The set_ctx_params and settable_ctx_params functions are + * optional, but if one of them is present then the other one must also + * be present. The dupctx and set_peer functions are optional. */ - EVP_KEYEXCH_free(exchange); EVPerr(EVP_F_EVP_KEYEXCH_FROM_DISPATCH, EVP_R_INVALID_PROVIDER_FUNCTIONS); - return NULL; + goto err; } return exchange; + + err: + EVP_KEYEXCH_free(exchange); + EVP_KEYMGMT_free(keymgmt); + return NULL; } void EVP_KEYEXCH_free(EVP_KEYEXCH *exchange) @@ -107,7 +146,9 @@ void EVP_KEYEXCH_free(EVP_KEYEXCH *exchange) CRYPTO_DOWN_REF(&exchange->refcnt, &i, exchange->lock); if (i > 0) return; + EVP_KEYMGMT_free(exchange->keymgmt); ossl_provider_free(exchange->prov); + OPENSSL_free(exchange->name); CRYPTO_THREAD_lock_free(exchange->lock); OPENSSL_free(exchange); } @@ -121,21 +162,33 @@ int EVP_KEYEXCH_up_ref(EVP_KEYEXCH *exchange) return 1; } +OSSL_PROVIDER *EVP_KEYEXCH_provider(const EVP_KEYEXCH *exchange) +{ + return exchange->prov; +} + EVP_KEYEXCH *EVP_KEYEXCH_fetch(OPENSSL_CTX *ctx, const char *algorithm, const char *properties) { - return evp_generic_fetch(ctx, OSSL_OP_KEYEXCH, algorithm, properties, - evp_keyexch_from_dispatch, - (int (*)(void *))EVP_KEYEXCH_up_ref, - (void (*)(void *))EVP_KEYEXCH_free); + EVP_KEYEXCH *keyexch = NULL; + struct keymgmt_data_st keymgmt_data; + + keymgmt_data.ctx = ctx; + keymgmt_data.properties = properties; + keyexch = evp_generic_fetch(ctx, OSSL_OP_KEYEXCH, algorithm, properties, + evp_keyexch_from_dispatch, &keymgmt_data, + (int (*)(void *))EVP_KEYEXCH_up_ref, + (void (*)(void *))EVP_KEYEXCH_free); + + return keyexch; } int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, EVP_KEYEXCH *exchange) { int ret; - OSSL_PARAM *param = NULL; - size_t paramsz = 0; + void *provkey = NULL; + evp_pkey_ctx_free_old_ops(ctx); ctx->operation = EVP_PKEY_OP_DERIVE; if (ctx->engine != NULL) @@ -169,31 +222,21 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, EVP_KEYEXCH *exchange) } } - if (ctx->exchprovctx != NULL && ctx->exchange != NULL) - ctx->exchange->freectx(ctx->exchprovctx); - EVP_KEYEXCH_free(ctx->exchange); - ctx->exchange = exchange; + ctx->op.kex.exchange = exchange; if (ctx->pkey != NULL) { - param = evp_pkey_to_param(ctx->pkey, ¶msz); - if (param == NULL) { + provkey = evp_keymgmt_export_to_provider(ctx->pkey, exchange->keymgmt); + if (provkey == NULL) { EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX, EVP_R_INITIALIZATION_ERROR); goto err; } } - ctx->exchprovctx = exchange->newctx(ossl_provider_ctx(exchange->prov)); - if (ctx->exchprovctx == NULL) { - OPENSSL_secure_clear_free(param, paramsz); + ctx->op.kex.exchprovctx = exchange->newctx(ossl_provider_ctx(exchange->prov)); + if (ctx->op.kex.exchprovctx == NULL) { + /* The provider key can stay in the cache */ EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX, EVP_R_INITIALIZATION_ERROR); goto err; } - ret = exchange->init(ctx->exchprovctx, param); - /* - * TODO(3.0): Really we should detect whether to call OPENSSL_free or - * OPENSSL_secure_clear_free based on the presence of a private key or not. - * Since we always expect a private key to be present we just call - * OPENSSL_secure_clear_free for now. - */ - OPENSSL_secure_clear_free(param, paramsz); + ret = exchange->init(ctx->op.kex.exchprovctx, provkey); return ret ? 1 : 0; err: @@ -223,7 +266,7 @@ int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer) { int ret; - OSSL_PARAM *param = NULL; + void *provkey = NULL; if (ctx == NULL) { EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, @@ -231,36 +274,22 @@ int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer) return -2; } - if (ctx->exchprovctx == NULL) + if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx) || ctx->op.kex.exchprovctx == NULL) goto legacy; - if (ctx->operation != EVP_PKEY_OP_DERIVE) { - EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, - EVP_R_OPERATON_NOT_INITIALIZED); - return -1; - } - - if (ctx->exchange->set_peer == NULL) { + if (ctx->op.kex.exchange->set_peer == NULL) { EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return -2; } - param = evp_pkey_to_param(peer, NULL); - if (param == NULL) { + provkey = evp_keymgmt_export_to_provider(peer, + ctx->op.kex.exchange->keymgmt); + if (provkey == NULL) { EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, ERR_R_INTERNAL_ERROR); return 0; } - ret = ctx->exchange->set_peer(ctx->exchprovctx, param); - /* - * TODO(3.0): Really we should detect whether to call OPENSSL_free or - * OPENSSL_secure_clear_free based on the presence of a private key or not. - * Since we always expect a public key to be present we just call - * OPENSSL_free for now. - */ - OPENSSL_free(param); - - return ret; + return ctx->op.kex.exchange->set_peer(ctx->op.kex.exchprovctx, provkey); legacy: if (ctx->pmeth == NULL @@ -335,15 +364,16 @@ int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *pkeylen) return -2; } - if (ctx->operation != EVP_PKEY_OP_DERIVE) { + if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) { EVPerr(EVP_F_EVP_PKEY_DERIVE, EVP_R_OPERATON_NOT_INITIALIZED); return -1; } - if (ctx->exchprovctx == NULL) + if (ctx->op.kex.exchprovctx == NULL) goto legacy; - ret = ctx->exchange->derive(ctx->exchprovctx, key, pkeylen, SIZE_MAX); + ret = ctx->op.kex.exchange->derive(ctx->op.kex.exchprovctx, key, pkeylen, + SIZE_MAX); return ret; legacy: