2019-07-07 03:57:15 +08:00
|
|
|
/*
|
2020-04-23 20:55:52 +08:00
|
|
|
* Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
|
2019-07-07 03:57:15 +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
|
|
|
|
*/
|
|
|
|
|
2020-01-08 10:44:28 +08:00
|
|
|
#include <openssl/core_names.h>
|
2019-07-07 03:57:15 +08:00
|
|
|
#include "internal/cryptlib.h"
|
|
|
|
#include "internal/nelem.h"
|
2019-09-28 06:45:33 +08:00
|
|
|
#include "crypto/evp.h"
|
|
|
|
#include "crypto/asn1.h"
|
2019-11-08 22:24:42 +08:00
|
|
|
#include "internal/core.h"
|
2019-07-07 03:57:15 +08:00
|
|
|
#include "internal/provider.h"
|
2019-09-28 06:45:40 +08:00
|
|
|
#include "evp_local.h"
|
2019-07-07 03:57:15 +08:00
|
|
|
|
2020-02-12 21:28:50 +08:00
|
|
|
/*
|
|
|
|
* match_type() checks if two EVP_KEYMGMT are matching key types. This
|
|
|
|
* function assumes that the caller has made all the necessary NULL checks.
|
|
|
|
*/
|
|
|
|
static int match_type(const EVP_KEYMGMT *keymgmt1, const EVP_KEYMGMT *keymgmt2)
|
|
|
|
{
|
|
|
|
const OSSL_PROVIDER *prov2 = EVP_KEYMGMT_provider(keymgmt2);
|
|
|
|
const char *name2 = evp_first_name(prov2, EVP_KEYMGMT_number(keymgmt2));
|
|
|
|
|
|
|
|
return EVP_KEYMGMT_is_a(keymgmt1, name2);
|
|
|
|
}
|
|
|
|
|
2020-07-09 04:09:32 +08:00
|
|
|
int evp_keymgmt_util_try_import(const OSSL_PARAM params[], void *arg)
|
2019-10-17 06:32:20 +08:00
|
|
|
{
|
2020-07-09 04:09:32 +08:00
|
|
|
struct evp_keymgmt_util_try_import_data_st *data = arg;
|
2019-07-07 03:57:15 +08:00
|
|
|
|
2020-05-21 18:33:53 +08:00
|
|
|
/* Just in time creation of keydata */
|
|
|
|
if (data->keydata == NULL
|
|
|
|
&& (data->keydata = evp_keymgmt_newdata(data->keymgmt)) == NULL) {
|
|
|
|
ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-03-21 13:03:39 +08:00
|
|
|
/*
|
|
|
|
* It's fine if there was no data to transfer, we just end up with an
|
|
|
|
* empty destination key.
|
|
|
|
*/
|
|
|
|
if (params[0].key == NULL)
|
|
|
|
return 1;
|
|
|
|
|
Redesign the KEYMGMT libcrypto <-> provider interface - the basics
The KEYMGMT libcrypto <-> provider interface currently makes a few
assumptions:
1. provider side domain parameters and key data isn't mutable. In
other words, as soon as a key has been created in any (loaded,
imported data, ...), it's set in stone.
2. provider side domain parameters can be strictly separated from the
key data.
This does work for the most part, but there are places where that's a
bit too rigid for the functionality that the EVP_PKEY API delivers.
Key data needs to be mutable to allow the flexibility that functions
like EVP_PKEY_copy_parameters promise, as well as to provide the
combinations of data that an EVP_PKEY is generally assumed to be able
to hold:
- domain parameters only
- public key only
- public key + private key
- domain parameters + public key
- domain parameters + public key + private key
To remedy all this, we:
1. let go of the distinction between domain parameters and key
material proper in the libcrypto <-> provider interface.
As a consequence, functions that still need it gain a selection
argument, which is a set of bits that indicate what parts of the
key object are to be considered in a specific call. This allows
a reduction of very similar functions into one.
2. Rework the libcrypto <-> provider interface so provider side key
objects are created and destructed with a separate function, and
get their data filled and extracted in through import and export.
(future work will see other key object constructors and other
functions to fill them with data)
Fixes #10979
squash! Redesign the KEYMGMT libcrypto <-> provider interface - the basics
Remedy 1 needs a rewrite:
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/11006)
2020-02-03 01:56:07 +08:00
|
|
|
return evp_keymgmt_import(data->keymgmt, data->keydata, data->selection,
|
|
|
|
params);
|
2019-07-07 03:57:15 +08:00
|
|
|
}
|
|
|
|
|
2020-07-09 04:09:32 +08:00
|
|
|
int evp_keymgmt_util_assign_pkey(EVP_PKEY *pkey, EVP_KEYMGMT *keymgmt,
|
|
|
|
void *keydata)
|
|
|
|
{
|
|
|
|
if (pkey == NULL || keymgmt == NULL || keydata == NULL
|
|
|
|
|| !EVP_PKEY_set_type_by_keymgmt(pkey, keymgmt)) {
|
|
|
|
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
pkey->keydata = keydata;
|
|
|
|
evp_keymgmt_util_cache_keyinfo(pkey);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
EVP_PKEY *evp_keymgmt_util_make_pkey(EVP_KEYMGMT *keymgmt, void *keydata)
|
|
|
|
{
|
|
|
|
EVP_PKEY *pkey = NULL;
|
|
|
|
|
|
|
|
if (keymgmt == NULL
|
|
|
|
|| keydata == NULL
|
|
|
|
|| (pkey = EVP_PKEY_new()) == NULL
|
|
|
|
|| !evp_keymgmt_util_assign_pkey(pkey, keymgmt, keydata)) {
|
|
|
|
EVP_PKEY_free(pkey);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return pkey;
|
|
|
|
}
|
|
|
|
|
2020-09-11 14:35:26 +08:00
|
|
|
int evp_keymgmt_util_export(const EVP_PKEY *pk, int selection,
|
|
|
|
OSSL_CALLBACK *export_cb, void *export_cbarg)
|
|
|
|
{
|
|
|
|
return evp_keymgmt_export(pk->keymgmt, pk->keydata, selection,
|
|
|
|
export_cb, export_cbarg);
|
|
|
|
}
|
|
|
|
|
Redesign the KEYMGMT libcrypto <-> provider interface - the basics
The KEYMGMT libcrypto <-> provider interface currently makes a few
assumptions:
1. provider side domain parameters and key data isn't mutable. In
other words, as soon as a key has been created in any (loaded,
imported data, ...), it's set in stone.
2. provider side domain parameters can be strictly separated from the
key data.
This does work for the most part, but there are places where that's a
bit too rigid for the functionality that the EVP_PKEY API delivers.
Key data needs to be mutable to allow the flexibility that functions
like EVP_PKEY_copy_parameters promise, as well as to provide the
combinations of data that an EVP_PKEY is generally assumed to be able
to hold:
- domain parameters only
- public key only
- public key + private key
- domain parameters + public key
- domain parameters + public key + private key
To remedy all this, we:
1. let go of the distinction between domain parameters and key
material proper in the libcrypto <-> provider interface.
As a consequence, functions that still need it gain a selection
argument, which is a set of bits that indicate what parts of the
key object are to be considered in a specific call. This allows
a reduction of very similar functions into one.
2. Rework the libcrypto <-> provider interface so provider side key
objects are created and destructed with a separate function, and
get their data filled and extracted in through import and export.
(future work will see other key object constructors and other
functions to fill them with data)
Fixes #10979
squash! Redesign the KEYMGMT libcrypto <-> provider interface - the basics
Remedy 1 needs a rewrite:
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/11006)
2020-02-03 01:56:07 +08:00
|
|
|
void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
|
2019-07-07 03:57:15 +08:00
|
|
|
{
|
2020-07-09 04:09:32 +08:00
|
|
|
struct evp_keymgmt_util_try_import_data_st import_data;
|
2020-02-21 03:26:16 +08:00
|
|
|
size_t i = 0;
|
2019-07-07 03:57:15 +08:00
|
|
|
|
2020-02-12 21:28:50 +08:00
|
|
|
/* Export to where? */
|
|
|
|
if (keymgmt == NULL)
|
|
|
|
return NULL;
|
2019-07-07 03:57:15 +08:00
|
|
|
|
2020-02-12 21:28:50 +08:00
|
|
|
/* If we have an unassigned key, give up */
|
2020-03-21 13:03:39 +08:00
|
|
|
if (pk->keydata == NULL)
|
2020-02-12 21:28:50 +08:00
|
|
|
return NULL;
|
2019-07-07 03:57:15 +08:00
|
|
|
|
2020-02-21 03:26:16 +08:00
|
|
|
/* If |keymgmt| matches the "origin" |keymgmt|, no more to do */
|
|
|
|
if (pk->keymgmt == keymgmt)
|
|
|
|
return pk->keydata;
|
|
|
|
|
|
|
|
/* If this key is already exported to |keymgmt|, no more to do */
|
|
|
|
i = evp_keymgmt_util_find_operation_cache_index(pk, keymgmt);
|
|
|
|
if (i < OSSL_NELEM(pk->operation_cache)
|
|
|
|
&& pk->operation_cache[i].keymgmt != NULL)
|
|
|
|
return pk->operation_cache[i].keydata;
|
|
|
|
|
|
|
|
/* If the "origin" |keymgmt| doesn't support exporting, give up */
|
2019-07-07 03:57:15 +08:00
|
|
|
/*
|
2020-02-21 03:26:16 +08:00
|
|
|
* TODO(3.0) consider an evp_keymgmt_export() return value that indicates
|
|
|
|
* that the method is unsupported.
|
2019-07-07 03:57:15 +08:00
|
|
|
*/
|
2020-02-21 03:26:16 +08:00
|
|
|
if (pk->keymgmt->export == NULL)
|
|
|
|
return NULL;
|
2020-02-12 21:28:50 +08:00
|
|
|
|
2020-02-21 03:26:16 +08:00
|
|
|
/* Check that we have found an empty slot in the export cache */
|
|
|
|
/*
|
|
|
|
* TODO(3.0) Right now, we assume we have ample space. We will have to
|
|
|
|
* think about a cache aging scheme, though, if |i| indexes outside the
|
|
|
|
* array.
|
|
|
|
*/
|
|
|
|
if (!ossl_assert(i < OSSL_NELEM(pk->operation_cache)))
|
|
|
|
return NULL;
|
2020-02-12 21:28:50 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure that the type of the keymgmt to export to matches the type
|
2020-02-21 03:26:16 +08:00
|
|
|
* of the "origin"
|
2020-02-12 21:28:50 +08:00
|
|
|
*/
|
2020-02-21 03:26:16 +08:00
|
|
|
if (!ossl_assert(match_type(pk->keymgmt, keymgmt)))
|
2020-02-12 21:28:50 +08:00
|
|
|
return NULL;
|
2019-07-07 03:57:15 +08:00
|
|
|
|
2020-02-12 21:28:50 +08:00
|
|
|
/*
|
|
|
|
* We look at the already cached provider keys, and import from the
|
|
|
|
* first that supports it (i.e. use its export function), and export
|
|
|
|
* the imported data to the new provider.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Setup for the export callback */
|
2020-07-09 04:09:32 +08:00
|
|
|
import_data.keydata = NULL; /* evp_keymgmt_util_try_import will create it */
|
2020-02-12 21:28:50 +08:00
|
|
|
import_data.keymgmt = keymgmt;
|
|
|
|
import_data.selection = OSSL_KEYMGMT_SELECT_ALL;
|
|
|
|
|
2020-02-21 03:26:16 +08:00
|
|
|
/*
|
2020-07-09 04:09:32 +08:00
|
|
|
* The export function calls the callback (evp_keymgmt_util_try_import),
|
|
|
|
* which does the import for us. If successful, we're done.
|
2020-02-21 03:26:16 +08:00
|
|
|
*/
|
2020-09-11 14:35:26 +08:00
|
|
|
if (!evp_keymgmt_util_export(pk, OSSL_KEYMGMT_SELECT_ALL,
|
|
|
|
&evp_keymgmt_util_try_import, &import_data)) {
|
2020-02-12 21:28:50 +08:00
|
|
|
/* If there was an error, bail out */
|
2020-03-21 13:03:39 +08:00
|
|
|
evp_keymgmt_freedata(keymgmt, import_data.keydata);
|
2020-02-12 21:28:50 +08:00
|
|
|
return NULL;
|
2019-07-07 03:57:15 +08:00
|
|
|
}
|
|
|
|
|
2020-02-21 03:26:16 +08:00
|
|
|
/* Add the new export to the operation cache */
|
2020-03-21 13:03:39 +08:00
|
|
|
if (!evp_keymgmt_util_cache_keydata(pk, i, keymgmt, import_data.keydata)) {
|
|
|
|
evp_keymgmt_freedata(keymgmt, import_data.keydata);
|
2020-02-04 11:50:51 +08:00
|
|
|
return NULL;
|
2020-02-21 03:26:16 +08:00
|
|
|
}
|
2019-10-14 14:41:17 +08:00
|
|
|
|
2020-03-21 13:03:39 +08:00
|
|
|
return import_data.keydata;
|
2019-07-07 03:57:15 +08:00
|
|
|
}
|
2019-07-10 20:30:55 +08:00
|
|
|
|
2020-02-21 03:26:16 +08:00
|
|
|
void evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk)
|
2019-07-10 20:30:55 +08:00
|
|
|
{
|
2020-02-21 03:26:16 +08:00
|
|
|
size_t i, end = OSSL_NELEM(pk->operation_cache);
|
2019-07-10 20:30:55 +08:00
|
|
|
|
|
|
|
if (pk != NULL) {
|
2020-02-21 03:26:16 +08:00
|
|
|
for (i = 0; i < end && pk->operation_cache[i].keymgmt != NULL; i++) {
|
|
|
|
EVP_KEYMGMT *keymgmt = pk->operation_cache[i].keymgmt;
|
|
|
|
void *keydata = pk->operation_cache[i].keydata;
|
2019-07-10 20:30:55 +08:00
|
|
|
|
2020-02-21 03:26:16 +08:00
|
|
|
pk->operation_cache[i].keymgmt = NULL;
|
|
|
|
pk->operation_cache[i].keydata = NULL;
|
Redesign the KEYMGMT libcrypto <-> provider interface - the basics
The KEYMGMT libcrypto <-> provider interface currently makes a few
assumptions:
1. provider side domain parameters and key data isn't mutable. In
other words, as soon as a key has been created in any (loaded,
imported data, ...), it's set in stone.
2. provider side domain parameters can be strictly separated from the
key data.
This does work for the most part, but there are places where that's a
bit too rigid for the functionality that the EVP_PKEY API delivers.
Key data needs to be mutable to allow the flexibility that functions
like EVP_PKEY_copy_parameters promise, as well as to provide the
combinations of data that an EVP_PKEY is generally assumed to be able
to hold:
- domain parameters only
- public key only
- public key + private key
- domain parameters + public key
- domain parameters + public key + private key
To remedy all this, we:
1. let go of the distinction between domain parameters and key
material proper in the libcrypto <-> provider interface.
As a consequence, functions that still need it gain a selection
argument, which is a set of bits that indicate what parts of the
key object are to be considered in a specific call. This allows
a reduction of very similar functions into one.
2. Rework the libcrypto <-> provider interface so provider side key
objects are created and destructed with a separate function, and
get their data filled and extracted in through import and export.
(future work will see other key object constructors and other
functions to fill them with data)
Fixes #10979
squash! Redesign the KEYMGMT libcrypto <-> provider interface - the basics
Remedy 1 needs a rewrite:
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/11006)
2020-02-03 01:56:07 +08:00
|
|
|
evp_keymgmt_freedata(keymgmt, keydata);
|
2019-07-10 20:30:55 +08:00
|
|
|
EVP_KEYMGMT_free(keymgmt);
|
|
|
|
}
|
2020-01-08 10:44:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-21 03:26:16 +08:00
|
|
|
size_t evp_keymgmt_util_find_operation_cache_index(EVP_PKEY *pk,
|
|
|
|
EVP_KEYMGMT *keymgmt)
|
2020-02-12 21:28:50 +08:00
|
|
|
{
|
2020-02-21 03:26:16 +08:00
|
|
|
size_t i, end = OSSL_NELEM(pk->operation_cache);
|
2020-02-12 21:28:50 +08:00
|
|
|
|
2020-02-21 03:26:16 +08:00
|
|
|
for (i = 0; i < end && pk->operation_cache[i].keymgmt != NULL; i++) {
|
|
|
|
if (keymgmt == pk->operation_cache[i].keymgmt)
|
2020-02-12 21:28:50 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2020-02-21 03:26:16 +08:00
|
|
|
int evp_keymgmt_util_cache_keydata(EVP_PKEY *pk, size_t index,
|
|
|
|
EVP_KEYMGMT *keymgmt, void *keydata)
|
2020-01-08 10:44:28 +08:00
|
|
|
{
|
Redesign the KEYMGMT libcrypto <-> provider interface - the basics
The KEYMGMT libcrypto <-> provider interface currently makes a few
assumptions:
1. provider side domain parameters and key data isn't mutable. In
other words, as soon as a key has been created in any (loaded,
imported data, ...), it's set in stone.
2. provider side domain parameters can be strictly separated from the
key data.
This does work for the most part, but there are places where that's a
bit too rigid for the functionality that the EVP_PKEY API delivers.
Key data needs to be mutable to allow the flexibility that functions
like EVP_PKEY_copy_parameters promise, as well as to provide the
combinations of data that an EVP_PKEY is generally assumed to be able
to hold:
- domain parameters only
- public key only
- public key + private key
- domain parameters + public key
- domain parameters + public key + private key
To remedy all this, we:
1. let go of the distinction between domain parameters and key
material proper in the libcrypto <-> provider interface.
As a consequence, functions that still need it gain a selection
argument, which is a set of bits that indicate what parts of the
key object are to be considered in a specific call. This allows
a reduction of very similar functions into one.
2. Rework the libcrypto <-> provider interface so provider side key
objects are created and destructed with a separate function, and
get their data filled and extracted in through import and export.
(future work will see other key object constructors and other
functions to fill them with data)
Fixes #10979
squash! Redesign the KEYMGMT libcrypto <-> provider interface - the basics
Remedy 1 needs a rewrite:
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/11006)
2020-02-03 01:56:07 +08:00
|
|
|
if (keydata != NULL) {
|
2020-02-21 03:26:16 +08:00
|
|
|
if (!EVP_KEYMGMT_up_ref(keymgmt))
|
|
|
|
return 0;
|
|
|
|
pk->operation_cache[index].keydata = keydata;
|
|
|
|
pk->operation_cache[index].keymgmt = keymgmt;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void evp_keymgmt_util_cache_keyinfo(EVP_PKEY *pk)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Cache information about the provider "origin" key.
|
|
|
|
*
|
|
|
|
* This services functions like EVP_PKEY_size, EVP_PKEY_bits, etc
|
|
|
|
*/
|
2020-03-21 13:03:39 +08:00
|
|
|
if (pk->keydata != NULL) {
|
2020-02-21 03:26:16 +08:00
|
|
|
int bits = 0;
|
|
|
|
int security_bits = 0;
|
|
|
|
int size = 0;
|
|
|
|
OSSL_PARAM params[4];
|
|
|
|
|
|
|
|
params[0] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_BITS, &bits);
|
|
|
|
params[1] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_SECURITY_BITS,
|
|
|
|
&security_bits);
|
|
|
|
params[2] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_MAX_SIZE, &size);
|
|
|
|
params[3] = OSSL_PARAM_construct_end();
|
|
|
|
if (evp_keymgmt_get_params(pk->keymgmt, pk->keydata, params)) {
|
|
|
|
pk->cache.size = size;
|
|
|
|
pk->cache.bits = bits;
|
|
|
|
pk->cache.security_bits = security_bits;
|
2020-01-08 10:44:28 +08:00
|
|
|
}
|
2019-07-10 20:30:55 +08:00
|
|
|
}
|
|
|
|
}
|
2019-07-11 18:52:16 +08:00
|
|
|
|
2020-02-03 12:42:48 +08:00
|
|
|
void *evp_keymgmt_util_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
|
Redesign the KEYMGMT libcrypto <-> provider interface - the basics
The KEYMGMT libcrypto <-> provider interface currently makes a few
assumptions:
1. provider side domain parameters and key data isn't mutable. In
other words, as soon as a key has been created in any (loaded,
imported data, ...), it's set in stone.
2. provider side domain parameters can be strictly separated from the
key data.
This does work for the most part, but there are places where that's a
bit too rigid for the functionality that the EVP_PKEY API delivers.
Key data needs to be mutable to allow the flexibility that functions
like EVP_PKEY_copy_parameters promise, as well as to provide the
combinations of data that an EVP_PKEY is generally assumed to be able
to hold:
- domain parameters only
- public key only
- public key + private key
- domain parameters + public key
- domain parameters + public key + private key
To remedy all this, we:
1. let go of the distinction between domain parameters and key
material proper in the libcrypto <-> provider interface.
As a consequence, functions that still need it gain a selection
argument, which is a set of bits that indicate what parts of the
key object are to be considered in a specific call. This allows
a reduction of very similar functions into one.
2. Rework the libcrypto <-> provider interface so provider side key
objects are created and destructed with a separate function, and
get their data filled and extracted in through import and export.
(future work will see other key object constructors and other
functions to fill them with data)
Fixes #10979
squash! Redesign the KEYMGMT libcrypto <-> provider interface - the basics
Remedy 1 needs a rewrite:
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/11006)
2020-02-03 01:56:07 +08:00
|
|
|
int selection, const OSSL_PARAM params[])
|
2019-10-15 20:50:35 +08:00
|
|
|
{
|
2020-03-21 13:14:25 +08:00
|
|
|
void *keydata = NULL;
|
2019-10-15 20:50:35 +08:00
|
|
|
|
2020-03-21 13:14:25 +08:00
|
|
|
if ((keydata = evp_keymgmt_newdata(keymgmt)) == NULL
|
|
|
|
|| !evp_keymgmt_import(keymgmt, keydata, selection, params)
|
2020-07-09 04:09:32 +08:00
|
|
|
|| !evp_keymgmt_util_assign_pkey(target, keymgmt, keydata)) {
|
2020-03-21 13:14:25 +08:00
|
|
|
evp_keymgmt_freedata(keymgmt, keydata);
|
|
|
|
keydata = NULL;
|
|
|
|
}
|
Redesign the KEYMGMT libcrypto <-> provider interface - the basics
The KEYMGMT libcrypto <-> provider interface currently makes a few
assumptions:
1. provider side domain parameters and key data isn't mutable. In
other words, as soon as a key has been created in any (loaded,
imported data, ...), it's set in stone.
2. provider side domain parameters can be strictly separated from the
key data.
This does work for the most part, but there are places where that's a
bit too rigid for the functionality that the EVP_PKEY API delivers.
Key data needs to be mutable to allow the flexibility that functions
like EVP_PKEY_copy_parameters promise, as well as to provide the
combinations of data that an EVP_PKEY is generally assumed to be able
to hold:
- domain parameters only
- public key only
- public key + private key
- domain parameters + public key
- domain parameters + public key + private key
To remedy all this, we:
1. let go of the distinction between domain parameters and key
material proper in the libcrypto <-> provider interface.
As a consequence, functions that still need it gain a selection
argument, which is a set of bits that indicate what parts of the
key object are to be considered in a specific call. This allows
a reduction of very similar functions into one.
2. Rework the libcrypto <-> provider interface so provider side key
objects are created and destructed with a separate function, and
get their data filled and extracted in through import and export.
(future work will see other key object constructors and other
functions to fill them with data)
Fixes #10979
squash! Redesign the KEYMGMT libcrypto <-> provider interface - the basics
Remedy 1 needs a rewrite:
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/11006)
2020-02-03 01:56:07 +08:00
|
|
|
return keydata;
|
2019-10-15 20:50:35 +08:00
|
|
|
}
|
2020-02-05 17:18:51 +08:00
|
|
|
|
|
|
|
int evp_keymgmt_util_has(EVP_PKEY *pk, int selection)
|
|
|
|
{
|
|
|
|
/* Check if key is even assigned */
|
|
|
|
if (pk->keymgmt == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return evp_keymgmt_has(pk->keymgmt, pk->keydata, selection);
|
|
|
|
}
|
2020-02-05 19:55:43 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* evp_keymgmt_util_match() doesn't just look at the provider side "origin",
|
|
|
|
* but also in the operation cache to see if there's any common keymgmt that
|
|
|
|
* supplies OP_keymgmt_match.
|
|
|
|
*
|
2020-05-25 19:17:51 +08:00
|
|
|
* evp_keymgmt_util_match() adheres to the return values that EVP_PKEY_eq()
|
|
|
|
* and EVP_PKEY_parameters_eq() return, i.e.:
|
2020-02-05 19:55:43 +08:00
|
|
|
*
|
|
|
|
* 1 same key
|
|
|
|
* 0 not same key
|
|
|
|
* -1 not same key type
|
|
|
|
* -2 unsupported operation
|
|
|
|
*/
|
|
|
|
int evp_keymgmt_util_match(EVP_PKEY *pk1, EVP_PKEY *pk2, int selection)
|
|
|
|
{
|
|
|
|
EVP_KEYMGMT *keymgmt1 = NULL, *keymgmt2 = NULL;
|
|
|
|
void *keydata1 = NULL, *keydata2 = NULL;
|
|
|
|
|
|
|
|
if (pk1 == NULL || pk2 == NULL) {
|
|
|
|
if (pk1 == NULL && pk2 == NULL)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
keymgmt1 = pk1->keymgmt;
|
|
|
|
keydata1 = pk1->keydata;
|
|
|
|
keymgmt2 = pk2->keymgmt;
|
|
|
|
keydata2 = pk2->keydata;
|
|
|
|
|
|
|
|
if (keymgmt1 != keymgmt2) {
|
2020-03-21 13:03:39 +08:00
|
|
|
/*
|
|
|
|
* The condition for a successful cross export is that the
|
|
|
|
* keydata to be exported is NULL (typed, but otherwise empty
|
|
|
|
* EVP_PKEY), or that it was possible to export it with
|
|
|
|
* evp_keymgmt_util_export_to_provider().
|
|
|
|
*
|
|
|
|
* We use |ok| to determine if it's ok to cross export one way,
|
|
|
|
* but also to determine if we should attempt a cross export
|
|
|
|
* the other way. There's no point doing it both ways.
|
|
|
|
*/
|
|
|
|
int ok = 1;
|
2020-02-05 19:55:43 +08:00
|
|
|
|
|
|
|
/* Complex case, where the keymgmt differ */
|
|
|
|
if (keymgmt1 != NULL
|
|
|
|
&& keymgmt2 != NULL
|
|
|
|
&& !match_type(keymgmt1, keymgmt2)) {
|
|
|
|
ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES);
|
|
|
|
return -1; /* Not the same type */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The key types are determined to match, so we try cross export,
|
|
|
|
* but only to keymgmt's that supply a matching function.
|
|
|
|
*/
|
|
|
|
if (keymgmt2 != NULL
|
|
|
|
&& keymgmt2->match != NULL) {
|
2020-03-21 13:03:39 +08:00
|
|
|
void *tmp_keydata = NULL;
|
|
|
|
|
|
|
|
ok = 1;
|
|
|
|
if (keydata1 != NULL) {
|
|
|
|
tmp_keydata =
|
|
|
|
evp_keymgmt_util_export_to_provider(pk1, keymgmt2);
|
|
|
|
ok = (tmp_keydata != NULL);
|
|
|
|
}
|
|
|
|
if (ok) {
|
2020-02-05 19:55:43 +08:00
|
|
|
keymgmt1 = keymgmt2;
|
|
|
|
keydata1 = tmp_keydata;
|
|
|
|
}
|
|
|
|
}
|
2020-03-21 13:03:39 +08:00
|
|
|
/*
|
2020-03-21 13:14:25 +08:00
|
|
|
* If we've successfully cross exported one way, there's no point
|
2020-03-21 13:03:39 +08:00
|
|
|
* doing it the other way, hence the |!ok| check.
|
|
|
|
*/
|
|
|
|
if (!ok
|
2020-02-05 19:55:43 +08:00
|
|
|
&& keymgmt1 != NULL
|
|
|
|
&& keymgmt1->match != NULL) {
|
2020-03-21 13:03:39 +08:00
|
|
|
void *tmp_keydata = NULL;
|
|
|
|
|
|
|
|
ok = 1;
|
|
|
|
if (keydata2 != NULL) {
|
|
|
|
tmp_keydata =
|
|
|
|
evp_keymgmt_util_export_to_provider(pk2, keymgmt1);
|
|
|
|
ok = (tmp_keydata != NULL);
|
|
|
|
}
|
|
|
|
if (ok) {
|
2020-02-05 19:55:43 +08:00
|
|
|
keymgmt2 = keymgmt1;
|
|
|
|
keydata2 = tmp_keydata;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we still don't have matching keymgmt implementations, we give up */
|
|
|
|
if (keymgmt1 != keymgmt2)
|
|
|
|
return -2;
|
|
|
|
|
2020-03-21 13:03:39 +08:00
|
|
|
/* If both keydata are NULL, then they're the same key */
|
|
|
|
if (keydata1 == NULL && keydata2 == NULL)
|
|
|
|
return 1;
|
|
|
|
/* If only one of the keydata is NULL, then they're different keys */
|
|
|
|
if (keydata1 == NULL || keydata2 == NULL)
|
|
|
|
return 0;
|
|
|
|
/* If both keydata are non-NULL, we let the backend decide */
|
2020-02-05 19:55:43 +08:00
|
|
|
return evp_keymgmt_match(keymgmt1, keydata1, keydata2, selection);
|
|
|
|
}
|
2020-02-05 23:30:21 +08:00
|
|
|
|
|
|
|
int evp_keymgmt_util_copy(EVP_PKEY *to, EVP_PKEY *from, int selection)
|
|
|
|
{
|
|
|
|
/* Save copies of pointers we want to play with without affecting |to| */
|
|
|
|
EVP_KEYMGMT *to_keymgmt = to->keymgmt;
|
|
|
|
void *to_keydata = to->keydata, *alloc_keydata = NULL;
|
|
|
|
|
|
|
|
/* An unassigned key can't be copied */
|
2020-03-21 13:03:39 +08:00
|
|
|
if (from == NULL || from->keydata == NULL)
|
2020-02-05 23:30:21 +08:00
|
|
|
return 0;
|
|
|
|
|
2020-04-28 14:41:20 +08:00
|
|
|
/*
|
|
|
|
* If |to| is unassigned, ensure it gets the same KEYMGMT as |from|,
|
|
|
|
* Note that the final setting of KEYMGMT is done further down, with
|
|
|
|
* EVP_PKEY_set_type_by_keymgmt(); we don't want to do that prematurely.
|
|
|
|
*/
|
|
|
|
if (to_keymgmt == NULL)
|
|
|
|
to_keymgmt = from->keymgmt;
|
|
|
|
|
2020-03-21 13:03:39 +08:00
|
|
|
if (to_keymgmt == from->keymgmt && to_keymgmt->copy != NULL) {
|
|
|
|
/* Make sure there's somewhere to copy to */
|
|
|
|
if (to_keydata == NULL
|
2020-04-28 14:41:20 +08:00
|
|
|
&& ((to_keydata = alloc_keydata = evp_keymgmt_newdata(to_keymgmt))
|
|
|
|
== NULL)) {
|
2020-03-21 13:03:39 +08:00
|
|
|
ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
|
2020-02-05 23:30:21 +08:00
|
|
|
return 0;
|
2020-03-21 13:03:39 +08:00
|
|
|
}
|
2020-02-05 23:30:21 +08:00
|
|
|
|
2020-03-21 13:03:39 +08:00
|
|
|
/*
|
|
|
|
* |to| and |from| have the same keymgmt, and the copy function is
|
|
|
|
* implemented, so just copy and be done
|
|
|
|
*/
|
2020-02-05 23:30:21 +08:00
|
|
|
if (!evp_keymgmt_copy(to_keymgmt, to_keydata, from->keydata,
|
|
|
|
selection))
|
|
|
|
return 0;
|
|
|
|
} else if (match_type(to_keymgmt, from->keymgmt)) {
|
2020-07-09 04:09:32 +08:00
|
|
|
struct evp_keymgmt_util_try_import_data_st import_data;
|
2020-02-05 23:30:21 +08:00
|
|
|
|
|
|
|
import_data.keymgmt = to_keymgmt;
|
|
|
|
import_data.keydata = to_keydata;
|
|
|
|
import_data.selection = selection;
|
|
|
|
|
2020-09-11 14:35:26 +08:00
|
|
|
if (!evp_keymgmt_util_export(from, selection,
|
|
|
|
&evp_keymgmt_util_try_import,
|
|
|
|
&import_data)) {
|
2020-02-05 23:30:21 +08:00
|
|
|
evp_keymgmt_freedata(to_keymgmt, alloc_keydata);
|
|
|
|
return 0;
|
|
|
|
}
|
2020-03-21 13:03:39 +08:00
|
|
|
|
|
|
|
/*
|
2020-07-09 04:09:32 +08:00
|
|
|
* In case to_keydata was previously unallocated,
|
|
|
|
* evp_keymgmt_util_try_import() may have created it for us.
|
2020-03-21 13:03:39 +08:00
|
|
|
*/
|
2020-04-28 14:41:20 +08:00
|
|
|
if (to_keydata == NULL)
|
|
|
|
to_keydata = alloc_keydata = import_data.keydata;
|
2020-02-05 23:30:21 +08:00
|
|
|
} else {
|
|
|
|
ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-07-09 04:09:32 +08:00
|
|
|
/*
|
|
|
|
* We only need to set the |to| type when its |keymgmt| isn't set.
|
|
|
|
* We can then just set its |keydata| to what we have, which might
|
|
|
|
* be exactly what it had when entering this function.
|
|
|
|
* This is a bit different from using evp_keymgmt_util_assign_pkey(),
|
|
|
|
* which isn't as careful with |to|'s original |keymgmt|, since it's
|
|
|
|
* meant to forcibly reassign an EVP_PKEY no matter what, which is
|
|
|
|
* why we don't use that one here.
|
|
|
|
*/
|
2020-02-05 23:30:21 +08:00
|
|
|
if (to->keymgmt == NULL
|
2020-03-21 13:14:25 +08:00
|
|
|
&& !EVP_PKEY_set_type_by_keymgmt(to, to_keymgmt)) {
|
2020-02-05 23:30:21 +08:00
|
|
|
evp_keymgmt_freedata(to_keymgmt, alloc_keydata);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
to->keydata = to_keydata;
|
|
|
|
evp_keymgmt_util_cache_keyinfo(to);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
2019-10-27 22:09:26 +08:00
|
|
|
|
|
|
|
void *evp_keymgmt_util_gen(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
|
|
|
|
void *genctx, OSSL_CALLBACK *cb, void *cbarg)
|
|
|
|
{
|
2020-03-21 13:14:25 +08:00
|
|
|
void *keydata = NULL;
|
2019-10-27 22:09:26 +08:00
|
|
|
|
2020-03-21 13:14:25 +08:00
|
|
|
if ((keydata = evp_keymgmt_gen(keymgmt, genctx, cb, cbarg)) == NULL
|
2020-07-09 04:09:32 +08:00
|
|
|
|| !evp_keymgmt_util_assign_pkey(target, keymgmt, keydata)) {
|
2020-03-21 13:14:25 +08:00
|
|
|
evp_keymgmt_freedata(keymgmt, keydata);
|
|
|
|
keydata = NULL;
|
|
|
|
}
|
2019-10-27 22:09:26 +08:00
|
|
|
|
|
|
|
return keydata;
|
|
|
|
}
|
2020-04-20 15:14:59 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns the same numbers as EVP_PKEY_get_default_digest_name()
|
|
|
|
* When the string from the EVP_KEYMGMT implementation is "", we use
|
|
|
|
* SN_undef, since that corresponds to what EVP_PKEY_get_default_nid()
|
|
|
|
* returns for no digest.
|
|
|
|
*/
|
|
|
|
int evp_keymgmt_util_get_deflt_digest_name(EVP_KEYMGMT *keymgmt,
|
|
|
|
void *keydata,
|
|
|
|
char *mdname, size_t mdname_sz)
|
|
|
|
{
|
|
|
|
OSSL_PARAM params[3];
|
|
|
|
char mddefault[100] = "";
|
|
|
|
char mdmandatory[100] = "";
|
|
|
|
char *result = NULL;
|
|
|
|
int rv = -2;
|
|
|
|
|
|
|
|
params[0] =
|
|
|
|
OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST,
|
|
|
|
mddefault, sizeof(mddefault));
|
|
|
|
params[1] =
|
|
|
|
OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_MANDATORY_DIGEST,
|
|
|
|
mdmandatory,
|
|
|
|
sizeof(mdmandatory));
|
|
|
|
params[2] = OSSL_PARAM_construct_end();
|
|
|
|
|
|
|
|
if (!evp_keymgmt_get_params(keymgmt, keydata, params))
|
|
|
|
return 0;
|
|
|
|
|
2020-04-23 18:31:12 +08:00
|
|
|
if (OSSL_PARAM_modified(params + 1)) {
|
|
|
|
if (params[1].return_size <= 1) /* Only a NUL byte */
|
2020-04-20 15:14:59 +08:00
|
|
|
result = SN_undef;
|
|
|
|
else
|
|
|
|
result = mdmandatory;
|
|
|
|
rv = 2;
|
2020-04-23 18:31:12 +08:00
|
|
|
} else if (OSSL_PARAM_modified(params)) {
|
|
|
|
if (params[0].return_size <= 1) /* Only a NUL byte */
|
2020-04-20 15:14:59 +08:00
|
|
|
result = SN_undef;
|
|
|
|
else
|
|
|
|
result = mddefault;
|
|
|
|
rv = 1;
|
|
|
|
}
|
|
|
|
if (rv > 0)
|
|
|
|
OPENSSL_strlcpy(mdname, result, mdname_sz);
|
|
|
|
return rv;
|
|
|
|
}
|