mirror of
https://github.com/openssl/openssl.git
synced 2025-01-18 13:44:20 +08:00
acb90ba8ff
Upgrading EVP_PKEYs from containing legacy keys to containing provider side keys proved to be risky, with a number of unpleasant corner cases, and with functions like EVP_PKEY_get0_DSA() failing unexpectedly. We therefore change course, and instead of upgrading legacy internal keys to provider side internal keys, we downgrade provider side internal keys to legacy ones. To be able to do this, we add |import_from| and make it a callback function designed for evp_keymgmt_export(). This means that evp_pkey_upgrade_to_provider() is replaced with evp_pkey_downgrade(). EVP_PKEY_copy_parameters() is the most deeply affected function of this change. Fixes #11366 Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/11375)
387 lines
9.7 KiB
C
387 lines
9.7 KiB
C
/*
|
|
* Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved.
|
|
*
|
|
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
|
* this file except in compliance with the License. You can obtain a copy
|
|
* in the file LICENSE in the source distribution or at
|
|
* https://www.openssl.org/source/license.html
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <openssl/core.h>
|
|
#include <openssl/core_names.h>
|
|
#include "internal/cryptlib.h"
|
|
#include "internal/core.h"
|
|
#include <openssl/objects.h>
|
|
#include <openssl/evp.h>
|
|
#include "crypto/bn.h"
|
|
#include "crypto/asn1.h"
|
|
#include "crypto/evp.h"
|
|
#include "evp_local.h"
|
|
|
|
static int gen_init(EVP_PKEY_CTX *ctx, int operation)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (ctx == NULL)
|
|
goto not_supported;
|
|
|
|
evp_pkey_ctx_free_old_ops(ctx);
|
|
ctx->operation = operation;
|
|
|
|
if (ctx->keymgmt == NULL || ctx->keymgmt->gen_init == NULL)
|
|
goto legacy;
|
|
|
|
switch (operation) {
|
|
case EVP_PKEY_OP_PARAMGEN:
|
|
ctx->op.keymgmt.genctx =
|
|
evp_keymgmt_gen_init(ctx->keymgmt,
|
|
OSSL_KEYMGMT_SELECT_ALL_PARAMETERS);
|
|
break;
|
|
case EVP_PKEY_OP_KEYGEN:
|
|
ctx->op.keymgmt.genctx =
|
|
evp_keymgmt_gen_init(ctx->keymgmt, OSSL_KEYMGMT_SELECT_KEYPAIR);
|
|
break;
|
|
}
|
|
|
|
if (ctx->op.keymgmt.genctx == NULL)
|
|
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
|
else
|
|
ret = 1;
|
|
goto end;
|
|
|
|
legacy:
|
|
#ifdef FIPS_MODE
|
|
goto not_supported;
|
|
#else
|
|
if (ctx->pmeth == NULL
|
|
|| (operation == EVP_PKEY_OP_PARAMGEN
|
|
&& ctx->pmeth->paramgen == NULL)
|
|
|| (operation == EVP_PKEY_OP_KEYGEN
|
|
&& ctx->pmeth->keygen == NULL))
|
|
goto not_supported;
|
|
|
|
ret = 1;
|
|
switch (operation) {
|
|
case EVP_PKEY_OP_PARAMGEN:
|
|
if (ctx->pmeth->paramgen_init != NULL)
|
|
ret = ctx->pmeth->paramgen_init(ctx);
|
|
break;
|
|
case EVP_PKEY_OP_KEYGEN:
|
|
if (ctx->pmeth->keygen_init != NULL)
|
|
ret = ctx->pmeth->keygen_init(ctx);
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
end:
|
|
if (ret <= 0)
|
|
ctx->operation = EVP_PKEY_OP_UNDEFINED;
|
|
return ret;
|
|
|
|
not_supported:
|
|
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
|
ret = -2;
|
|
goto end;
|
|
}
|
|
|
|
int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx)
|
|
{
|
|
return gen_init(ctx, EVP_PKEY_OP_PARAMGEN);
|
|
}
|
|
|
|
int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx)
|
|
{
|
|
return gen_init(ctx, EVP_PKEY_OP_KEYGEN);
|
|
}
|
|
|
|
static int ossl_callback_to_pkey_gencb(const OSSL_PARAM params[], void *arg)
|
|
{
|
|
EVP_PKEY_CTX *ctx = arg;
|
|
const OSSL_PARAM *param = NULL;
|
|
int p = -1, n = -1;
|
|
|
|
if (ctx->pkey_gencb == NULL)
|
|
return 1; /* No callback? That's fine */
|
|
|
|
if ((param = OSSL_PARAM_locate_const(params, OSSL_GEN_PARAM_POTENTIAL))
|
|
== NULL
|
|
|| !OSSL_PARAM_get_int(param, &p))
|
|
return 0;
|
|
if ((param = OSSL_PARAM_locate_const(params, OSSL_GEN_PARAM_ITERATION))
|
|
== NULL
|
|
|| !OSSL_PARAM_get_int(param, &n))
|
|
return 0;
|
|
|
|
ctx->keygen_info[0] = p;
|
|
ctx->keygen_info[1] = n;
|
|
|
|
return ctx->pkey_gencb(ctx);
|
|
}
|
|
|
|
int EVP_PKEY_gen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
|
|
{
|
|
int ret = 0;
|
|
OSSL_CALLBACK cb;
|
|
EVP_PKEY *allocated_pkey = NULL;
|
|
|
|
if (ppkey == NULL)
|
|
return -1;
|
|
|
|
if (ctx == NULL)
|
|
goto not_supported;
|
|
|
|
if ((ctx->operation & EVP_PKEY_OP_TYPE_GEN) == 0)
|
|
goto not_initialized;
|
|
|
|
if (*ppkey == NULL)
|
|
*ppkey = allocated_pkey = EVP_PKEY_new();
|
|
|
|
if (*ppkey == NULL) {
|
|
ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
|
|
return -1;
|
|
}
|
|
|
|
if (ctx->keymgmt == NULL || ctx->op.keymgmt.genctx == NULL)
|
|
goto legacy;
|
|
|
|
ret = 1;
|
|
if (ctx->pkey != NULL) {
|
|
EVP_KEYMGMT *tmp_keymgmt = ctx->keymgmt;
|
|
void *keydata =
|
|
evp_pkey_export_to_provider(ctx->pkey, ctx->libctx,
|
|
&tmp_keymgmt, ctx->propquery);
|
|
|
|
if (keydata == NULL)
|
|
goto not_supported;
|
|
ret = evp_keymgmt_gen_set_template(ctx->keymgmt,
|
|
ctx->op.keymgmt.genctx, keydata);
|
|
}
|
|
|
|
/*
|
|
* the returned value from evp_keymgmt_util_gen() is cached in *ppkey,
|
|
* so we so not need to save it, just check it.
|
|
*/
|
|
ret = ret
|
|
&& (evp_keymgmt_util_gen(*ppkey, ctx->keymgmt, ctx->op.keymgmt.genctx,
|
|
ossl_callback_to_pkey_gencb, ctx)
|
|
!= NULL);
|
|
|
|
#ifndef FIPS_MODE
|
|
/* In case |*ppkey| was originally a legacy key */
|
|
if (ret)
|
|
evp_pkey_free_legacy(*ppkey);
|
|
#endif
|
|
|
|
goto end;
|
|
|
|
legacy:
|
|
#ifdef FIPS_MODE
|
|
goto not_supported;
|
|
#else
|
|
if (ctx->pkey && !evp_pkey_downgrade(ctx->pkey))
|
|
goto not_accessible;
|
|
switch (ctx->operation) {
|
|
case EVP_PKEY_OP_PARAMGEN:
|
|
ret = ctx->pmeth->paramgen(ctx, *ppkey);
|
|
break;
|
|
case EVP_PKEY_OP_KEYGEN:
|
|
ret = ctx->pmeth->keygen(ctx, *ppkey);
|
|
break;
|
|
default:
|
|
goto not_supported;
|
|
}
|
|
#endif
|
|
|
|
end:
|
|
if (ret <= 0) {
|
|
if (allocated_pkey != NULL)
|
|
*ppkey = NULL;
|
|
EVP_PKEY_free(allocated_pkey);
|
|
}
|
|
return ret;
|
|
|
|
not_supported:
|
|
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
|
ret = -2;
|
|
goto end;
|
|
not_initialized:
|
|
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATON_NOT_INITIALIZED);
|
|
ret = -1;
|
|
goto end;
|
|
#ifndef FIPS_MODE
|
|
not_accessible:
|
|
ERR_raise(ERR_LIB_EVP, EVP_R_INACCESSIBLE_DOMAIN_PARAMETERS);
|
|
ret = -1;
|
|
goto end;
|
|
#endif
|
|
}
|
|
|
|
int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
|
|
{
|
|
if (ctx->operation != EVP_PKEY_OP_PARAMGEN) {
|
|
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATON_NOT_INITIALIZED);
|
|
return -1;
|
|
}
|
|
return EVP_PKEY_gen(ctx, ppkey);
|
|
}
|
|
|
|
int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
|
|
{
|
|
if (ctx->operation != EVP_PKEY_OP_KEYGEN) {
|
|
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATON_NOT_INITIALIZED);
|
|
return -1;
|
|
}
|
|
return EVP_PKEY_gen(ctx, ppkey);
|
|
}
|
|
|
|
void EVP_PKEY_CTX_set_cb(EVP_PKEY_CTX *ctx, EVP_PKEY_gen_cb *cb)
|
|
{
|
|
ctx->pkey_gencb = cb;
|
|
}
|
|
|
|
EVP_PKEY_gen_cb *EVP_PKEY_CTX_get_cb(EVP_PKEY_CTX *ctx)
|
|
{
|
|
return ctx->pkey_gencb;
|
|
}
|
|
|
|
/*
|
|
* "translation callback" to call EVP_PKEY_CTX callbacks using BN_GENCB style
|
|
* callbacks.
|
|
*/
|
|
|
|
static int trans_cb(int a, int b, BN_GENCB *gcb)
|
|
{
|
|
EVP_PKEY_CTX *ctx = BN_GENCB_get_arg(gcb);
|
|
ctx->keygen_info[0] = a;
|
|
ctx->keygen_info[1] = b;
|
|
return ctx->pkey_gencb(ctx);
|
|
}
|
|
|
|
void evp_pkey_set_cb_translate(BN_GENCB *cb, EVP_PKEY_CTX *ctx)
|
|
{
|
|
BN_GENCB_set(cb, trans_cb, ctx);
|
|
}
|
|
|
|
int EVP_PKEY_CTX_get_keygen_info(EVP_PKEY_CTX *ctx, int idx)
|
|
{
|
|
if (idx == -1)
|
|
return ctx->keygen_info_count;
|
|
if (idx < 0 || idx > ctx->keygen_info_count)
|
|
return 0;
|
|
return ctx->keygen_info[idx];
|
|
}
|
|
|
|
#ifndef FIPS_MODE
|
|
|
|
EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *e,
|
|
const unsigned char *key, int keylen)
|
|
{
|
|
EVP_PKEY_CTX *mac_ctx = NULL;
|
|
EVP_PKEY *mac_key = NULL;
|
|
mac_ctx = EVP_PKEY_CTX_new_id(type, e);
|
|
if (!mac_ctx)
|
|
return NULL;
|
|
if (EVP_PKEY_keygen_init(mac_ctx) <= 0)
|
|
goto merr;
|
|
if (EVP_PKEY_CTX_set_mac_key(mac_ctx, key, keylen) <= 0)
|
|
goto merr;
|
|
if (EVP_PKEY_keygen(mac_ctx, &mac_key) <= 0)
|
|
goto merr;
|
|
merr:
|
|
EVP_PKEY_CTX_free(mac_ctx);
|
|
return mac_key;
|
|
}
|
|
|
|
#endif /* FIPS_MODE */
|
|
|
|
/*- All methods below can also be used in FIPS_MODE */
|
|
|
|
static int fromdata_init(EVP_PKEY_CTX *ctx, int operation)
|
|
{
|
|
if (ctx == NULL || ctx->keytype == NULL)
|
|
goto not_supported;
|
|
|
|
evp_pkey_ctx_free_old_ops(ctx);
|
|
if (ctx->keymgmt == NULL)
|
|
goto not_supported;
|
|
|
|
ctx->operation = operation;
|
|
return 1;
|
|
|
|
not_supported:
|
|
ctx->operation = EVP_PKEY_OP_UNDEFINED;
|
|
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
|
return -2;
|
|
}
|
|
|
|
int EVP_PKEY_param_fromdata_init(EVP_PKEY_CTX *ctx)
|
|
{
|
|
return fromdata_init(ctx, EVP_PKEY_OP_PARAMFROMDATA);
|
|
}
|
|
|
|
int EVP_PKEY_key_fromdata_init(EVP_PKEY_CTX *ctx)
|
|
{
|
|
return fromdata_init(ctx, EVP_PKEY_OP_KEYFROMDATA);
|
|
}
|
|
|
|
int EVP_PKEY_fromdata(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey, OSSL_PARAM params[])
|
|
{
|
|
void *keydata = NULL;
|
|
int selection;
|
|
|
|
if (ctx == NULL || (ctx->operation & EVP_PKEY_OP_TYPE_FROMDATA) == 0) {
|
|
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
|
return -2;
|
|
}
|
|
|
|
if (ppkey == NULL)
|
|
return -1;
|
|
|
|
if (*ppkey == NULL)
|
|
*ppkey = EVP_PKEY_new();
|
|
|
|
if (*ppkey == NULL) {
|
|
ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
|
|
return -1;
|
|
}
|
|
|
|
if (ctx->operation == EVP_PKEY_OP_PARAMFROMDATA)
|
|
selection = OSSL_KEYMGMT_SELECT_ALL_PARAMETERS;
|
|
else
|
|
selection = OSSL_KEYMGMT_SELECT_ALL;
|
|
keydata = evp_keymgmt_util_fromdata(*ppkey, ctx->keymgmt, selection,
|
|
params);
|
|
|
|
if (keydata == NULL)
|
|
return 0;
|
|
/* keydata is cached in *ppkey, so we need not bother with it further */
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* TODO(3.0) Re-evaluate the names, it's possible that we find these to be
|
|
* better:
|
|
*
|
|
* EVP_PKEY_param_settable()
|
|
* EVP_PKEY_param_gettable()
|
|
*/
|
|
const OSSL_PARAM *EVP_PKEY_param_fromdata_settable(EVP_PKEY_CTX *ctx)
|
|
{
|
|
/* We call fromdata_init to get ctx->keymgmt populated */
|
|
if (fromdata_init(ctx, EVP_PKEY_OP_UNDEFINED))
|
|
return evp_keymgmt_import_types(ctx->keymgmt,
|
|
OSSL_KEYMGMT_SELECT_ALL_PARAMETERS);
|
|
return NULL;
|
|
}
|
|
|
|
const OSSL_PARAM *EVP_PKEY_key_fromdata_settable(EVP_PKEY_CTX *ctx)
|
|
{
|
|
/* We call fromdata_init to get ctx->keymgmt populated */
|
|
if (fromdata_init(ctx, EVP_PKEY_OP_UNDEFINED))
|
|
return evp_keymgmt_import_types(ctx->keymgmt,
|
|
OSSL_KEYMGMT_SELECT_ALL);
|
|
return NULL;
|
|
}
|