Skip to content

EVP_KEYMGMT needs a redesign #10979

@levitte

Description

@levitte

The EVP_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. In this API, the EVP_PKEY is commonly assumed to hold any of these combinations (other combinations are probably possible as well, just not very useful with the current functions):

  • domain parameters only
  • public key only
  • public key + private key
  • domain parameters + public key
  • domain parameters + public key + private key

Most of the code using EVP_PKEY objects assumes that it holds either just domain parameters or domain parameters + keypair. Our provided implementations reflect that assumptions, so the strict separation mentioned higher has already slipped.

Then, you stumble on this:

openssl/apps/ca.c

Lines 1922 to 1925 in c98eab8

pktmp = X509_get0_pubkey(ret);
if (EVP_PKEY_missing_parameters(pktmp) &&
!EVP_PKEY_missing_parameters(pkey))
EVP_PKEY_copy_parameters(pktmp, pkey);

For all intents and purposes, this takes the domain parameters from one key and alters another key with them. This is not possible to support in the current KEYMGMT design.

Enabling mutability

The simple way to do this is to introduce two new functions, a new and a free that simply constructs and destructs the provider side key data structure. Other constructors may be added with time (the load function comes to mind).

By consequence, the import functions will no longer be constructed, but rather act on existing key data that gets passed in as an argument.

[TOPIC: mutability]

Merging domain parameters and key data

This is the simplest part on the provider side, we can simply stop pretending that they are separate, and rather see them as attributes of the same object, which reflects the way EVP_PKEY works.

However, there is still code that passes domain parameters specifically, and code that wants just the key data specifically, so we must still be able to support that, even though the provider side object combines all elements. This could be done in two ways:

  1. Have import and export functions for each set of data, i.e. importdomparams, exportdomparams, importkey, exportkey
  2. Have one import and one export that takes an argument indicating what the caller wants, which could be domain parameters, the key itself, or both.

[TOPIC: importing and exporting]

Library code, while I'm at it

libcrypto has a number of small functions that are a direct mapping of the libcrypto <-> provider interface. They all have names starting with evp_keymgmt_.

libcrypto also has a number of utility functions that take care of the more complex interactions between EVP_PKEY and the EVP_KEYMGMT libcrypto <-> provider interface. They all have names starting with evp_keymgmt_.

Quite obviously, there is going to be a mixup between those two sets of functions, so a rename is prudent, such as prefixing the latter set with evp_keymgmt_util_.

[TOPIC: library utility functions]

Metadata

Metadata

Assignees

No one assigned

    Labels

    triaged: refactorThe issue/pr requests/implements refactoring

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions