2019-06-27 17:48:17 +08:00
|
|
|
/*
|
2020-04-23 20:55:52 +08:00
|
|
|
* Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
|
2019-06-27 17:48:17 +08:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
|
|
|
* this file except in compliance with the License. You can obtain a copy
|
|
|
|
* in the file LICENSE in the source distribution or at
|
|
|
|
* https://www.openssl.org/source/license.html
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <openssl/crypto.h>
|
|
|
|
#include <openssl/evp.h>
|
|
|
|
#include <openssl/err.h>
|
|
|
|
#include "internal/refcount.h"
|
2019-09-28 06:45:33 +08:00
|
|
|
#include "crypto/evp.h"
|
2019-06-27 17:48:17 +08:00
|
|
|
#include "internal/provider.h"
|
2019-08-09 19:38:42 +08:00
|
|
|
#include "internal/numbers.h" /* includes SIZE_MAX */
|
2019-09-28 06:45:40 +08:00
|
|
|
#include "evp_local.h"
|
2019-06-27 17:48:17 +08:00
|
|
|
|
|
|
|
static EVP_KEYEXCH *evp_keyexch_new(OSSL_PROVIDER *prov)
|
|
|
|
{
|
|
|
|
EVP_KEYEXCH *exchange = OPENSSL_zalloc(sizeof(EVP_KEYEXCH));
|
|
|
|
|
2019-11-27 01:14:08 +08:00
|
|
|
if (exchange == NULL) {
|
|
|
|
ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-06-27 17:48:17 +08:00
|
|
|
exchange->lock = CRYPTO_THREAD_lock_new();
|
|
|
|
if (exchange->lock == NULL) {
|
2019-11-27 01:14:08 +08:00
|
|
|
ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
|
2019-06-27 17:48:17 +08:00
|
|
|
OPENSSL_free(exchange);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
exchange->prov = prov;
|
|
|
|
ossl_provider_up_ref(prov);
|
|
|
|
exchange->refcnt = 1;
|
|
|
|
|
|
|
|
return exchange;
|
|
|
|
}
|
|
|
|
|
In provider implemented methods, save the name number, not the name string
Multiple names per implementation is already supported in the namemap,
but hasn't been used yet. However, as soon as we have multiple names,
we will get an issue with what name should be saved in the method.
The solution is to not save the name itself, but rather the number
it's associated with. This number is supposed to be unique for each
set of names, and we assume that algorithm names are globally unique,
i.e. there can be no name overlap between different algorithm types.
Incidently, it was also found that the 'get' function used by
ossl_construct_method() doesn't need all the parameters it was given;
most of what it needs, it can now get through the data structure given
by the caller of ossl_construct_method(). As a consequence,
ossl_construct_method() itself doesn't need all the parameters it was
given either.
There are some added internal functions that are expected to disappear
as soon as legacy code is removed, such as evp_first_name() and
ossl_namemap_num2name().
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9897)
2019-09-14 22:22:19 +08:00
|
|
|
static void *evp_keyexch_from_dispatch(int name_id,
|
2019-07-11 04:22:16 +08:00
|
|
|
const OSSL_DISPATCH *fns,
|
2019-10-31 19:10:01 +08:00
|
|
|
OSSL_PROVIDER *prov)
|
2019-06-27 17:48:17 +08:00
|
|
|
{
|
|
|
|
EVP_KEYEXCH *exchange = NULL;
|
2019-12-15 06:20:53 +08:00
|
|
|
int fncnt = 0, sparamfncnt = 0, gparamfncnt = 0;
|
2019-06-27 17:48:17 +08:00
|
|
|
|
In provider implemented methods, save the name number, not the name string
Multiple names per implementation is already supported in the namemap,
but hasn't been used yet. However, as soon as we have multiple names,
we will get an issue with what name should be saved in the method.
The solution is to not save the name itself, but rather the number
it's associated with. This number is supposed to be unique for each
set of names, and we assume that algorithm names are globally unique,
i.e. there can be no name overlap between different algorithm types.
Incidently, it was also found that the 'get' function used by
ossl_construct_method() doesn't need all the parameters it was given;
most of what it needs, it can now get through the data structure given
by the caller of ossl_construct_method(). As a consequence,
ossl_construct_method() itself doesn't need all the parameters it was
given either.
There are some added internal functions that are expected to disappear
as soon as legacy code is removed, such as evp_first_name() and
ossl_namemap_num2name().
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9897)
2019-09-14 22:22:19 +08:00
|
|
|
if ((exchange = evp_keyexch_new(prov)) == NULL) {
|
2019-08-23 20:03:28 +08:00
|
|
|
ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
|
|
|
|
goto err;
|
2019-07-11 04:22:16 +08:00
|
|
|
}
|
2019-06-27 17:48:17 +08:00
|
|
|
|
In provider implemented methods, save the name number, not the name string
Multiple names per implementation is already supported in the namemap,
but hasn't been used yet. However, as soon as we have multiple names,
we will get an issue with what name should be saved in the method.
The solution is to not save the name itself, but rather the number
it's associated with. This number is supposed to be unique for each
set of names, and we assume that algorithm names are globally unique,
i.e. there can be no name overlap between different algorithm types.
Incidently, it was also found that the 'get' function used by
ossl_construct_method() doesn't need all the parameters it was given;
most of what it needs, it can now get through the data structure given
by the caller of ossl_construct_method(). As a consequence,
ossl_construct_method() itself doesn't need all the parameters it was
given either.
There are some added internal functions that are expected to disappear
as soon as legacy code is removed, such as evp_first_name() and
ossl_namemap_num2name().
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9897)
2019-09-14 22:22:19 +08:00
|
|
|
exchange->name_id = name_id;
|
2019-08-23 20:03:28 +08:00
|
|
|
|
2019-06-27 17:48:17 +08:00
|
|
|
for (; fns->function_id != 0; fns++) {
|
|
|
|
switch (fns->function_id) {
|
|
|
|
case OSSL_FUNC_KEYEXCH_NEWCTX:
|
|
|
|
if (exchange->newctx != NULL)
|
|
|
|
break;
|
|
|
|
exchange->newctx = OSSL_get_OP_keyexch_newctx(fns);
|
|
|
|
fncnt++;
|
|
|
|
break;
|
|
|
|
case OSSL_FUNC_KEYEXCH_INIT:
|
|
|
|
if (exchange->init != NULL)
|
|
|
|
break;
|
|
|
|
exchange->init = OSSL_get_OP_keyexch_init(fns);
|
|
|
|
fncnt++;
|
|
|
|
break;
|
|
|
|
case OSSL_FUNC_KEYEXCH_SET_PEER:
|
|
|
|
if (exchange->set_peer != NULL)
|
|
|
|
break;
|
|
|
|
exchange->set_peer = OSSL_get_OP_keyexch_set_peer(fns);
|
|
|
|
break;
|
|
|
|
case OSSL_FUNC_KEYEXCH_DERIVE:
|
|
|
|
if (exchange->derive != NULL)
|
|
|
|
break;
|
|
|
|
exchange->derive = OSSL_get_OP_keyexch_derive(fns);
|
|
|
|
fncnt++;
|
|
|
|
break;
|
|
|
|
case OSSL_FUNC_KEYEXCH_FREECTX:
|
|
|
|
if (exchange->freectx != NULL)
|
|
|
|
break;
|
|
|
|
exchange->freectx = OSSL_get_OP_keyexch_freectx(fns);
|
|
|
|
fncnt++;
|
|
|
|
break;
|
|
|
|
case OSSL_FUNC_KEYEXCH_DUPCTX:
|
|
|
|
if (exchange->dupctx != NULL)
|
|
|
|
break;
|
|
|
|
exchange->dupctx = OSSL_get_OP_keyexch_dupctx(fns);
|
|
|
|
break;
|
2019-12-15 06:20:53 +08:00
|
|
|
case OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS:
|
|
|
|
if (exchange->get_ctx_params != NULL)
|
|
|
|
break;
|
|
|
|
exchange->get_ctx_params = OSSL_get_OP_keyexch_get_ctx_params(fns);
|
|
|
|
gparamfncnt++;
|
|
|
|
break;
|
|
|
|
case OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS:
|
|
|
|
if (exchange->gettable_ctx_params != NULL)
|
|
|
|
break;
|
|
|
|
exchange->gettable_ctx_params
|
|
|
|
= OSSL_get_OP_keyexch_gettable_ctx_params(fns);
|
|
|
|
gparamfncnt++;
|
|
|
|
break;
|
2019-09-04 19:46:02 +08:00
|
|
|
case OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS:
|
|
|
|
if (exchange->set_ctx_params != NULL)
|
2019-06-27 23:37:44 +08:00
|
|
|
break;
|
2019-09-04 19:46:02 +08:00
|
|
|
exchange->set_ctx_params = OSSL_get_OP_keyexch_set_ctx_params(fns);
|
2019-12-15 06:20:53 +08:00
|
|
|
sparamfncnt++;
|
2019-09-04 19:46:02 +08:00
|
|
|
break;
|
|
|
|
case OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS:
|
|
|
|
if (exchange->settable_ctx_params != NULL)
|
|
|
|
break;
|
|
|
|
exchange->settable_ctx_params
|
|
|
|
= OSSL_get_OP_keyexch_settable_ctx_params(fns);
|
2019-12-15 06:20:53 +08:00
|
|
|
sparamfncnt++;
|
2019-06-27 23:37:44 +08:00
|
|
|
break;
|
2019-06-27 17:48:17 +08:00
|
|
|
}
|
|
|
|
}
|
2019-12-15 06:20:53 +08:00
|
|
|
if (fncnt != 4
|
|
|
|
|| (gparamfncnt != 0 && gparamfncnt != 2)
|
|
|
|
|| (sparamfncnt != 0 && sparamfncnt != 2)) {
|
2019-06-27 17:48:17 +08:00
|
|
|
/*
|
|
|
|
* In order to be a consistent set of functions we must have at least
|
|
|
|
* a complete set of "exchange" functions: init, derive, newctx,
|
2019-09-04 19:46:02 +08:00
|
|
|
* 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
|
2019-12-15 06:20:53 +08:00
|
|
|
* be present. Same goes for get_ctx_params and gettable_ctx_params.
|
|
|
|
* The dupctx and set_peer functions are optional.
|
2019-06-27 17:48:17 +08:00
|
|
|
*/
|
|
|
|
EVPerr(EVP_F_EVP_KEYEXCH_FROM_DISPATCH,
|
|
|
|
EVP_R_INVALID_PROVIDER_FUNCTIONS);
|
2019-08-23 20:03:28 +08:00
|
|
|
goto err;
|
2019-06-27 17:48:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return exchange;
|
2019-08-23 20:03:28 +08:00
|
|
|
|
|
|
|
err:
|
|
|
|
EVP_KEYEXCH_free(exchange);
|
|
|
|
return NULL;
|
2019-06-27 17:48:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void EVP_KEYEXCH_free(EVP_KEYEXCH *exchange)
|
|
|
|
{
|
|
|
|
if (exchange != NULL) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
CRYPTO_DOWN_REF(&exchange->refcnt, &i, exchange->lock);
|
|
|
|
if (i > 0)
|
|
|
|
return;
|
|
|
|
ossl_provider_free(exchange->prov);
|
|
|
|
CRYPTO_THREAD_lock_free(exchange->lock);
|
|
|
|
OPENSSL_free(exchange);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int EVP_KEYEXCH_up_ref(EVP_KEYEXCH *exchange)
|
|
|
|
{
|
|
|
|
int ref = 0;
|
|
|
|
|
|
|
|
CRYPTO_UP_REF(&exchange->refcnt, &ref, exchange->lock);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-07-07 16:56:46 +08:00
|
|
|
OSSL_PROVIDER *EVP_KEYEXCH_provider(const EVP_KEYEXCH *exchange)
|
|
|
|
{
|
|
|
|
return exchange->prov;
|
|
|
|
}
|
|
|
|
|
2019-06-27 17:48:17 +08:00
|
|
|
EVP_KEYEXCH *EVP_KEYEXCH_fetch(OPENSSL_CTX *ctx, const char *algorithm,
|
|
|
|
const char *properties)
|
|
|
|
{
|
2019-10-31 19:10:01 +08:00
|
|
|
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);
|
2019-06-27 17:48:17 +08:00
|
|
|
}
|
|
|
|
|
2019-10-31 01:03:07 +08:00
|
|
|
int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx)
|
2019-06-27 17:48:17 +08:00
|
|
|
{
|
|
|
|
int ret;
|
2019-07-07 16:56:46 +08:00
|
|
|
void *provkey = NULL;
|
2019-10-31 01:03:07 +08:00
|
|
|
EVP_KEYEXCH *exchange = NULL;
|
2020-01-14 21:11:47 +08:00
|
|
|
EVP_KEYMGMT *tmp_keymgmt = NULL;
|
|
|
|
const char *supported_exch = NULL;
|
2019-10-31 01:03:07 +08:00
|
|
|
|
|
|
|
if (ctx == NULL) {
|
|
|
|
EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
|
|
|
return -2;
|
|
|
|
}
|
2019-06-27 17:48:17 +08:00
|
|
|
|
2019-09-05 06:13:25 +08:00
|
|
|
evp_pkey_ctx_free_old_ops(ctx);
|
2019-06-27 17:48:17 +08:00
|
|
|
ctx->operation = EVP_PKEY_OP_DERIVE;
|
|
|
|
|
2020-01-11 00:50:03 +08:00
|
|
|
/*
|
|
|
|
* TODO when we stop falling back to legacy, this and the ERR_pop_to_mark()
|
|
|
|
* calls can be removed.
|
|
|
|
*/
|
|
|
|
ERR_set_mark();
|
|
|
|
|
2020-03-17 21:37:47 +08:00
|
|
|
if (ctx->keymgmt == NULL)
|
2019-06-27 17:48:17 +08:00
|
|
|
goto legacy;
|
|
|
|
|
2020-02-21 03:26:16 +08:00
|
|
|
/*
|
|
|
|
* Ensure that the key is provided, either natively, or as a cached export.
|
|
|
|
* If not, go legacy
|
|
|
|
*/
|
2020-01-14 21:11:47 +08:00
|
|
|
tmp_keymgmt = ctx->keymgmt;
|
2020-02-21 03:26:16 +08:00
|
|
|
provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx,
|
|
|
|
&tmp_keymgmt, ctx->propquery);
|
2020-01-14 21:11:47 +08:00
|
|
|
if (provkey == NULL)
|
|
|
|
goto legacy;
|
|
|
|
if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) {
|
2020-01-11 00:50:03 +08:00
|
|
|
ERR_clear_last_mark();
|
2020-01-14 21:11:47 +08:00
|
|
|
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
|
|
|
goto err;
|
2019-10-31 01:03:07 +08:00
|
|
|
}
|
2020-01-14 21:11:47 +08:00
|
|
|
EVP_KEYMGMT_free(ctx->keymgmt);
|
|
|
|
ctx->keymgmt = tmp_keymgmt;
|
|
|
|
|
|
|
|
if (ctx->keymgmt->query_operation_name != NULL)
|
|
|
|
supported_exch = ctx->keymgmt->query_operation_name(OSSL_OP_KEYEXCH);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we didn't get a supported exch, assume there is one with the
|
|
|
|
* same name as the key type.
|
|
|
|
*/
|
|
|
|
if (supported_exch == NULL)
|
|
|
|
supported_exch = ctx->keytype;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Because we cleared out old ops, we shouldn't need to worry about
|
|
|
|
* checking if exchange is already there.
|
|
|
|
*/
|
|
|
|
exchange = EVP_KEYEXCH_fetch(ctx->libctx, supported_exch, ctx->propquery);
|
|
|
|
|
|
|
|
if (exchange == NULL
|
2019-10-31 01:03:07 +08:00
|
|
|
|| (EVP_KEYMGMT_provider(ctx->keymgmt)
|
|
|
|
!= EVP_KEYEXCH_provider(exchange))) {
|
2019-06-27 17:48:17 +08:00
|
|
|
/*
|
2020-01-11 00:50:03 +08:00
|
|
|
* We don't need to free ctx->keymgmt here, as it's not necessarily
|
|
|
|
* tied to this operation. It will be freed by EVP_PKEY_CTX_free().
|
2019-06-27 17:48:17 +08:00
|
|
|
*/
|
2019-10-31 01:03:07 +08:00
|
|
|
EVP_KEYEXCH_free(exchange);
|
|
|
|
goto legacy;
|
2019-06-27 17:48:17 +08:00
|
|
|
}
|
|
|
|
|
2020-01-11 00:50:03 +08:00
|
|
|
/*
|
|
|
|
* TODO remove this when legacy is gone
|
|
|
|
* If we don't have the full support we need with provided methods,
|
|
|
|
* let's go see if legacy does.
|
|
|
|
*/
|
|
|
|
ERR_pop_to_mark();
|
|
|
|
|
|
|
|
/* No more legacy from here down to legacy: */
|
2019-10-31 01:03:07 +08:00
|
|
|
|
2019-09-05 06:13:25 +08:00
|
|
|
ctx->op.kex.exchange = exchange;
|
|
|
|
ctx->op.kex.exchprovctx = exchange->newctx(ossl_provider_ctx(exchange->prov));
|
|
|
|
if (ctx->op.kex.exchprovctx == NULL) {
|
2019-07-07 16:56:46 +08:00
|
|
|
/* The provider key can stay in the cache */
|
2019-10-31 01:03:07 +08:00
|
|
|
EVPerr(0, EVP_R_INITIALIZATION_ERROR);
|
2019-06-27 17:48:17 +08:00
|
|
|
goto err;
|
|
|
|
}
|
2019-09-05 06:13:25 +08:00
|
|
|
ret = exchange->init(ctx->op.kex.exchprovctx, provkey);
|
2019-06-27 17:48:17 +08:00
|
|
|
|
|
|
|
return ret ? 1 : 0;
|
|
|
|
err:
|
2020-05-07 02:48:25 +08:00
|
|
|
evp_pkey_ctx_free_old_ops(ctx);
|
2019-06-27 17:48:17 +08:00
|
|
|
ctx->operation = EVP_PKEY_OP_UNDEFINED;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
legacy:
|
2020-01-11 00:50:03 +08:00
|
|
|
/*
|
|
|
|
* TODO remove this when legacy is gone
|
|
|
|
* If we don't have the full support we need with provided methods,
|
|
|
|
* let's go see if legacy does.
|
|
|
|
*/
|
|
|
|
ERR_pop_to_mark();
|
|
|
|
|
2020-04-14 04:34:56 +08:00
|
|
|
#ifdef FIPS_MODULE
|
2020-01-23 18:33:28 +08:00
|
|
|
return 0;
|
|
|
|
#else
|
2020-01-07 18:49:08 +08:00
|
|
|
if (ctx->pmeth == NULL || ctx->pmeth->derive == NULL) {
|
2019-10-31 01:03:07 +08:00
|
|
|
EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
2019-06-27 17:48:17 +08:00
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->pmeth->derive_init == NULL)
|
|
|
|
return 1;
|
|
|
|
ret = ctx->pmeth->derive_init(ctx);
|
|
|
|
if (ret <= 0)
|
|
|
|
ctx->operation = EVP_PKEY_OP_UNDEFINED;
|
|
|
|
return ret;
|
2020-01-23 18:33:28 +08:00
|
|
|
#endif
|
2019-06-27 17:48:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer)
|
|
|
|
{
|
2020-01-23 18:33:28 +08:00
|
|
|
int ret = 0;
|
2019-07-07 16:56:46 +08:00
|
|
|
void *provkey = NULL;
|
2019-06-27 17:48:17 +08:00
|
|
|
|
|
|
|
if (ctx == NULL) {
|
|
|
|
EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
|
|
|
|
EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
2019-09-05 06:13:25 +08:00
|
|
|
if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx) || ctx->op.kex.exchprovctx == NULL)
|
2019-06-27 17:48:17 +08:00
|
|
|
goto legacy;
|
|
|
|
|
2019-09-05 06:13:25 +08:00
|
|
|
if (ctx->op.kex.exchange->set_peer == NULL) {
|
2019-06-27 17:48:17 +08:00
|
|
|
EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
|
|
|
|
EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
2020-02-21 03:26:16 +08:00
|
|
|
provkey = evp_pkey_export_to_provider(peer, ctx->libctx, &ctx->keymgmt,
|
|
|
|
ctx->propquery);
|
2020-02-12 21:28:50 +08:00
|
|
|
/*
|
|
|
|
* If making the key provided wasn't possible, legacy may be able to pick
|
|
|
|
* it up
|
|
|
|
*/
|
2020-01-07 18:49:08 +08:00
|
|
|
if (provkey == NULL)
|
|
|
|
goto legacy;
|
2019-09-05 06:13:25 +08:00
|
|
|
return ctx->op.kex.exchange->set_peer(ctx->op.kex.exchprovctx, provkey);
|
2019-06-27 17:48:17 +08:00
|
|
|
|
|
|
|
legacy:
|
2020-04-14 04:34:56 +08:00
|
|
|
#ifdef FIPS_MODULE
|
2020-01-23 18:33:28 +08:00
|
|
|
return ret;
|
|
|
|
#else
|
2020-02-12 21:28:50 +08:00
|
|
|
/*
|
|
|
|
* TODO(3.0) investigate the case where the operation is deemed legacy,
|
|
|
|
* but the given peer key is provider only.
|
|
|
|
*/
|
2019-06-27 17:48:17 +08:00
|
|
|
if (ctx->pmeth == NULL
|
|
|
|
|| !(ctx->pmeth->derive != NULL
|
|
|
|
|| ctx->pmeth->encrypt != NULL
|
|
|
|
|| ctx->pmeth->decrypt != NULL)
|
|
|
|
|| ctx->pmeth->ctrl == NULL) {
|
|
|
|
EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
|
|
|
|
EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
if (ctx->operation != EVP_PKEY_OP_DERIVE
|
|
|
|
&& ctx->operation != EVP_PKEY_OP_ENCRYPT
|
|
|
|
&& ctx->operation != EVP_PKEY_OP_DECRYPT) {
|
|
|
|
EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
|
|
|
|
EVP_R_OPERATON_NOT_INITIALIZED);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 0, peer);
|
|
|
|
|
|
|
|
if (ret <= 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (ret == 2)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (ctx->pkey == NULL) {
|
|
|
|
EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_NO_KEY_SET);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->pkey->type != peer->type) {
|
|
|
|
EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_DIFFERENT_KEY_TYPES);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For clarity. The error is if parameters in peer are
|
2020-05-25 19:17:51 +08:00
|
|
|
* present (!missing) but don't match. EVP_PKEY_parameters_eq may return
|
2019-06-27 17:48:17 +08:00
|
|
|
* 1 (match), 0 (don't match) and -2 (comparison is not defined). -1
|
|
|
|
* (different key types) is impossible here because it is checked earlier.
|
|
|
|
* -2 is OK for us here, as well as 1, so we can check for 0 only.
|
|
|
|
*/
|
|
|
|
if (!EVP_PKEY_missing_parameters(peer) &&
|
2020-05-25 19:17:51 +08:00
|
|
|
!EVP_PKEY_parameters_eq(ctx->pkey, peer)) {
|
2019-06-27 17:48:17 +08:00
|
|
|
EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_DIFFERENT_PARAMETERS);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
EVP_PKEY_free(ctx->peerkey);
|
|
|
|
ctx->peerkey = peer;
|
|
|
|
|
|
|
|
ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer);
|
|
|
|
|
|
|
|
if (ret <= 0) {
|
|
|
|
ctx->peerkey = NULL;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
EVP_PKEY_up_ref(peer);
|
|
|
|
return 1;
|
2020-01-23 18:33:28 +08:00
|
|
|
#endif
|
2019-06-27 17:48:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *pkeylen)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (ctx == NULL) {
|
|
|
|
EVPerr(EVP_F_EVP_PKEY_DERIVE,
|
|
|
|
EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
2019-09-05 06:13:25 +08:00
|
|
|
if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
|
2019-06-27 17:48:17 +08:00
|
|
|
EVPerr(EVP_F_EVP_PKEY_DERIVE, EVP_R_OPERATON_NOT_INITIALIZED);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-09-05 06:13:25 +08:00
|
|
|
if (ctx->op.kex.exchprovctx == NULL)
|
2019-06-27 17:48:17 +08:00
|
|
|
goto legacy;
|
|
|
|
|
2019-09-05 06:13:25 +08:00
|
|
|
ret = ctx->op.kex.exchange->derive(ctx->op.kex.exchprovctx, key, pkeylen,
|
|
|
|
SIZE_MAX);
|
2019-06-27 17:48:17 +08:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
legacy:
|
|
|
|
if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->derive == NULL) {
|
|
|
|
EVPerr(EVP_F_EVP_PKEY_DERIVE,
|
|
|
|
EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
M_check_autoarg(ctx, key, pkeylen, EVP_F_EVP_PKEY_DERIVE)
|
|
|
|
return ctx->pmeth->derive(ctx, key, pkeylen);
|
|
|
|
}
|
EVP: add missing common functionality
This adds the missing functions that should be common for all
fetchable EVP sub-APIs:
EVP_KEYMGMT_is_a(), EVP_KEYMGMT_do_all_provided(), EVP_KEYEXCH_is_a(),
EVP_KEYEXCH_do_all_provided(), EVP_KDF_is_a(), EVP_MD_is_a(),
EVP_SIGNATURE_do_all_provided(), EVP_SIGNATURE_is_a().
This also renames EVP_MD_do_all_ex(), EVP_CIPHER_do_all_ex(),
EVP_KDF_do_all_ex(), EVP_MAC_do_all_ex() to change '_ex'
to '_provided'.
Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/9979)
2019-09-23 16:33:26 +08:00
|
|
|
|
2019-09-23 17:16:21 +08:00
|
|
|
int EVP_KEYEXCH_number(const EVP_KEYEXCH *keyexch)
|
|
|
|
{
|
|
|
|
return keyexch->name_id;
|
|
|
|
}
|
|
|
|
|
EVP: add missing common functionality
This adds the missing functions that should be common for all
fetchable EVP sub-APIs:
EVP_KEYMGMT_is_a(), EVP_KEYMGMT_do_all_provided(), EVP_KEYEXCH_is_a(),
EVP_KEYEXCH_do_all_provided(), EVP_KDF_is_a(), EVP_MD_is_a(),
EVP_SIGNATURE_do_all_provided(), EVP_SIGNATURE_is_a().
This also renames EVP_MD_do_all_ex(), EVP_CIPHER_do_all_ex(),
EVP_KDF_do_all_ex(), EVP_MAC_do_all_ex() to change '_ex'
to '_provided'.
Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/9979)
2019-09-23 16:33:26 +08:00
|
|
|
int EVP_KEYEXCH_is_a(const EVP_KEYEXCH *keyexch, const char *name)
|
|
|
|
{
|
2020-01-15 08:04:37 +08:00
|
|
|
return evp_is_a(keyexch->prov, keyexch->name_id, NULL, name);
|
EVP: add missing common functionality
This adds the missing functions that should be common for all
fetchable EVP sub-APIs:
EVP_KEYMGMT_is_a(), EVP_KEYMGMT_do_all_provided(), EVP_KEYEXCH_is_a(),
EVP_KEYEXCH_do_all_provided(), EVP_KDF_is_a(), EVP_MD_is_a(),
EVP_SIGNATURE_do_all_provided(), EVP_SIGNATURE_is_a().
This also renames EVP_MD_do_all_ex(), EVP_CIPHER_do_all_ex(),
EVP_KDF_do_all_ex(), EVP_MAC_do_all_ex() to change '_ex'
to '_provided'.
Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/9979)
2019-09-23 16:33:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void EVP_KEYEXCH_do_all_provided(OPENSSL_CTX *libctx,
|
|
|
|
void (*fn)(EVP_KEYEXCH *keyexch, void *arg),
|
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
evp_generic_do_all(libctx, OSSL_OP_KEYEXCH,
|
|
|
|
(void (*)(void *, void *))fn, arg,
|
2019-10-31 19:10:01 +08:00
|
|
|
evp_keyexch_from_dispatch,
|
EVP: add missing common functionality
This adds the missing functions that should be common for all
fetchable EVP sub-APIs:
EVP_KEYMGMT_is_a(), EVP_KEYMGMT_do_all_provided(), EVP_KEYEXCH_is_a(),
EVP_KEYEXCH_do_all_provided(), EVP_KDF_is_a(), EVP_MD_is_a(),
EVP_SIGNATURE_do_all_provided(), EVP_SIGNATURE_is_a().
This also renames EVP_MD_do_all_ex(), EVP_CIPHER_do_all_ex(),
EVP_KDF_do_all_ex(), EVP_MAC_do_all_ex() to change '_ex'
to '_provided'.
Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/9979)
2019-09-23 16:33:26 +08:00
|
|
|
(void (*)(void *))EVP_KEYEXCH_free);
|
|
|
|
}
|
2019-09-23 16:56:13 +08:00
|
|
|
|
|
|
|
void EVP_KEYEXCH_names_do_all(const EVP_KEYEXCH *keyexch,
|
|
|
|
void (*fn)(const char *name, void *data),
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
if (keyexch->prov != NULL)
|
|
|
|
evp_names_do_all(keyexch->prov, keyexch->name_id, fn, data);
|
|
|
|
}
|