summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorRichard Levitte <levitte@openssl.org>2019-11-08 15:24:42 +0100
committerRichard Levitte <levitte@openssl.org>2019-11-14 10:53:14 +0100
commit1640d48c5b4ee0a3ff5a2a5015ee17ac163d9cd4 (patch)
tree24fb95a9c51ec8fac457e00b924b853ad098bffc /crypto
parent726ad13c4e720daeda5f56326aebcd27b4615d6c (diff)
CORE & PROV: make export of key data leaner through callback
Exporting data from a provider owned domainparams or key is quite an ordeal, with having to figure out what parameter keys an implementation supports, call the export function a first time to find out how large each parameter buffer must be, allocate the necessary space for it, and call the export function again. So how about letting the export function build up the key data params and call back with that? This change implements exactly such a mechanism. Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/10414)
Diffstat (limited to 'crypto')
-rw-r--r--crypto/evp/keymgmt_lib.c169
1 files changed, 44 insertions, 125 deletions
diff --git a/crypto/evp/keymgmt_lib.c b/crypto/evp/keymgmt_lib.c
index 583e8b362a..4163bca5bb 100644
--- a/crypto/evp/keymgmt_lib.c
+++ b/crypto/evp/keymgmt_lib.c
@@ -11,84 +11,24 @@
#include "internal/nelem.h"
#include "crypto/evp.h"
#include "crypto/asn1.h"
+#include "internal/core.h"
#include "internal/provider.h"
#include "evp_local.h"
-static OSSL_PARAM *paramdefs_to_params(const OSSL_PARAM *paramdefs)
-{
- size_t cnt;
- const OSSL_PARAM *p;
- OSSL_PARAM *params = NULL, *q;
-
- for (cnt = 1, p = paramdefs; p->key != NULL; p++, cnt++)
- continue;
-
- params = OPENSSL_zalloc(cnt * sizeof(*params));
- if (params == NULL)
- return NULL;
-
- for (p = paramdefs, q = params; ; p++, q++) {
- *q = *p;
- if (p->key == NULL)
- break;
-
- q->data = NULL; /* In case the provider used it */
- q->return_size = 0;
- }
+struct import_data_st {
+ void *provctx;
+ void *(*importfn)(void *provctx, const OSSL_PARAM params[]);
- return params;
-}
+ /* Result */
+ void *provdata;
+};
-static OSSL_PARAM *reduce_params(OSSL_PARAM *params)
+static int try_import(const OSSL_PARAM params[], void *arg)
{
- OSSL_PARAM *curr, *next;
- size_t cnt;
-
- for (cnt = 0, curr = next = params; next->key != NULL; next++) {
- if (next->return_size == 0)
- continue;
- if (curr != next)
- *curr = *next;
- curr++;
- cnt++;
- }
- *curr = *next; /* Terminating record */
- cnt++;
-
- curr = OPENSSL_realloc(params, cnt * sizeof(*params));
- if (curr == NULL)
- return params;
- return curr;
-}
-
-typedef union align_block_un {
- OSSL_UNION_ALIGN;
-} ALIGN_BLOCK;
-
-#define ALIGN_SIZE sizeof(ALIGN_BLOCK)
-
-static void *allocate_params_space(OSSL_PARAM *params)
-{
- unsigned char *data = NULL;
- size_t space;
- OSSL_PARAM *p;
-
- for (space = 0, p = params; p->key != NULL; p++)
- space += ((p->return_size + ALIGN_SIZE - 1) / ALIGN_SIZE) * ALIGN_SIZE;
-
- if (space == 0)
- return NULL;
-
- data = OPENSSL_zalloc(space);
- if (data == NULL)
- return NULL;
-
- for (space = 0, p = params; p->key != NULL; p++) {
- p->data = data + space;
- space += ((p->return_size + ALIGN_SIZE - 1) / ALIGN_SIZE) * ALIGN_SIZE;
- }
+ struct import_data_st *data = arg;
- return data;
+ data->provdata = data->importfn(data->provctx, params);
+ return data->provdata != NULL;
}
void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt,
@@ -147,69 +87,39 @@ void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt,
* the new provider.
*/
- void *(*importfn)(void *provctx, const OSSL_PARAM params[]) =
+ /* Setup for the export callback */
+ struct import_data_st import_data;
+
+ import_data.importfn =
want_domainparams ? keymgmt->importdomparams : keymgmt->importkey;
+ import_data.provdata = NULL;
/*
* If the given keymgmt doesn't have an import function, give up
*/
- if (importfn == NULL)
+ if (import_data.importfn == NULL)
return NULL;
for (j = 0; j < i && pk->pkeys[j].keymgmt != NULL; j++) {
- if (pk->pkeys[j].keymgmt->exportkey != NULL) {
- const OSSL_PARAM *paramdefs = NULL;
- OSSL_PARAM *params = NULL;
- void *data = NULL;
- void *provctx =
- ossl_provider_ctx(EVP_KEYMGMT_provider(keymgmt));
- int (*exportfn)(void *provctx, OSSL_PARAM params[]) = NULL;
-
- if (pk->pkeys[j].domainparams != want_domainparams)
- continue;
+ int (*exportfn)(void *provctx, OSSL_CALLBACK *cb, void *cbarg) =
+ want_domainparams
+ ? pk->pkeys[j].keymgmt->exportdomparams
+ : pk->pkeys[j].keymgmt->exportkey;
- exportfn = want_domainparams
- ? pk->pkeys[j].keymgmt->exportdomparams
- : pk->pkeys[j].keymgmt->exportkey;
-
- paramdefs = pk->pkeys[j].keymgmt->exportkey_types();
- /*
- * All params have 'data' set to NULL. In that case,
- * the exportkey call should just fill in 'return_size'
- * in all applicable params.
- */
- params = paramdefs_to_params(paramdefs);
- /* Get 'return_size' filled */
- exportfn(pk->pkeys[j].provdata, params);
-
- /*
- * Reduce the params by removing any entry that got return
- * size zero, then allocate space and assign 'data' to point
- * into the data block
- */
- params = reduce_params(params);
- if ((data = allocate_params_space(params)) == NULL)
- goto cont;
+ if (exportfn != NULL) {
+ import_data.provctx =
+ ossl_provider_ctx(EVP_KEYMGMT_provider(keymgmt));
/*
- * Call the exportkey function a second time, to get
- * the data filled.
- * If something goes wrong, go to the next cached key.
- */
- if (!exportfn(pk->pkeys[j].provdata, params))
- goto cont;
+ * The export function calls the callback (try_import), which
+ * does the import for us.
+ * Even though we got a success return, we double check that
+ * we actually got something, just in case some implementation
+ * forgets to check the return value.
- /*
- * We should have all the data at this point, so import
- * into the new provider and hope to get a key back.
*/
- provdata = importfn(provctx, params);
-
- cont:
- OPENSSL_free(params);
- OPENSSL_free(data);
-
- if (provdata != NULL)
+ if (exportfn(pk->pkeys[j].provdata, &try_import, &import_data)
+ && (provdata = import_data.provdata) != NULL)
break;
}
}
@@ -298,9 +208,10 @@ void evp_keymgmt_freedomparams(const EVP_KEYMGMT *keymgmt,
}
int evp_keymgmt_exportdomparams(const EVP_KEYMGMT *keymgmt,
- void *provdomparams, OSSL_PARAM params[])
+ void *provdomparams,
+ OSSL_CALLBACK *param_cb, void *cbarg)
{
- return keymgmt->exportdomparams(provdomparams, params);
+ return keymgmt->exportdomparams(provdomparams, param_cb, cbarg);
}
const OSSL_PARAM *evp_keymgmt_importdomparam_types(const EVP_KEYMGMT *keymgmt)
@@ -308,6 +219,10 @@ const OSSL_PARAM *evp_keymgmt_importdomparam_types(const EVP_KEYMGMT *keymgmt)
return keymgmt->importdomparam_types();
}
+/*
+ * TODO(v3.0) investigate if we need this function. 'openssl provider' may
+ * be a caller...
+ */
const OSSL_PARAM *evp_keymgmt_exportdomparam_types(const EVP_KEYMGMT *keymgmt)
{
return keymgmt->exportdomparam_types();
@@ -344,9 +259,9 @@ void evp_keymgmt_freekey(const EVP_KEYMGMT *keymgmt, void *provkey)
}
int evp_keymgmt_exportkey(const EVP_KEYMGMT *keymgmt, void *provkey,
- OSSL_PARAM params[])
+ OSSL_CALLBACK *param_cb, void *cbarg)
{
- return keymgmt->exportkey(provkey, params);
+ return keymgmt->exportkey(provkey, param_cb, cbarg);
}
const OSSL_PARAM *evp_keymgmt_importkey_types(const EVP_KEYMGMT *keymgmt)
@@ -354,6 +269,10 @@ const OSSL_PARAM *evp_keymgmt_importkey_types(const EVP_KEYMGMT *keymgmt)
return keymgmt->importkey_types();
}
+/*
+ * TODO(v3.0) investigate if we need this function. 'openssl provider' may
+ * be a caller...
+ */
const OSSL_PARAM *evp_keymgmt_exportkey_types(const EVP_KEYMGMT *keymgmt)
{
return keymgmt->exportkey_types();