From 02f060d17e667a2805eb0c71266c35de9e7e3864 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Mon, 14 Oct 2019 08:41:17 +0200 Subject: [PATCH] PKEY: adapt the export_to_provider funtions to handle domain params too Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/10169) --- crypto/evp/exchange.c | 7 ++-- crypto/evp/keymgmt_lib.c | 69 ++++++++++++++++++++++++++++------------ crypto/evp/m_sigver.c | 3 +- crypto/evp/pmeth_fn.c | 3 +- include/crypto/asn1.h | 3 +- include/crypto/evp.h | 13 +++++--- 6 files changed, 66 insertions(+), 32 deletions(-) diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c index faece8af3c..dfc309ecd7 100644 --- a/crypto/evp/exchange.c +++ b/crypto/evp/exchange.c @@ -224,7 +224,8 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, EVP_KEYEXCH *exchange) ctx->op.kex.exchange = exchange; if (ctx->pkey != NULL) { - provkey = evp_keymgmt_export_to_provider(ctx->pkey, exchange->keymgmt); + provkey = + evp_keymgmt_export_to_provider(ctx->pkey, exchange->keymgmt, 0); if (provkey == NULL) { EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX, EVP_R_INITIALIZATION_ERROR); goto err; @@ -283,8 +284,8 @@ int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer) return -2; } - provkey = evp_keymgmt_export_to_provider(peer, - ctx->op.kex.exchange->keymgmt); + provkey = + evp_keymgmt_export_to_provider(peer, ctx->op.kex.exchange->keymgmt, 0); if (provkey == NULL) { EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, ERR_R_INTERNAL_ERROR); return 0; diff --git a/crypto/evp/keymgmt_lib.c b/crypto/evp/keymgmt_lib.c index 0eb12ca317..87629157e2 100644 --- a/crypto/evp/keymgmt_lib.c +++ b/crypto/evp/keymgmt_lib.c @@ -52,6 +52,9 @@ static void *allocate_params_space(OSSL_PARAM *params) 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); for (space = 0, p = params; p->key != NULL; p++) { @@ -62,9 +65,10 @@ static void *allocate_params_space(OSSL_PARAM *params) return data; } -void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt) +void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt, + int want_domainparams) { - void *provkey = NULL; + void *provdata = NULL; size_t i, j; /* @@ -90,8 +94,9 @@ void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt) for (i = 0; i < OSSL_NELEM(pk->pkeys) && pk->pkeys[i].keymgmt != NULL; i++) { - if (keymgmt == pk->pkeys[i].keymgmt) - return pk->pkeys[i].provkey; + if (keymgmt == pk->pkeys[i].keymgmt + && want_domainparams == pk->pkeys[i].domainparams) + return pk->pkeys[i].provdata; } if (pk->pkey.ptr != NULL) { @@ -101,11 +106,11 @@ void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt) if (pk->ameth->export_to == NULL) return NULL; - /* Otherwise, simply use it */ - provkey = pk->ameth->export_to(pk, keymgmt); + /* Otherwise, simply use it. */ + provdata = pk->ameth->export_to(pk, keymgmt, want_domainparams); /* Synchronize the dirty count, but only if we exported successfully */ - if (provkey != NULL) + if (provdata != NULL) pk->dirty_cnt_copy = pk->ameth->dirty_cnt(pk); } else { @@ -116,10 +121,13 @@ void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt) * the new provider. */ + void *(*importfn)(void *provctx, const OSSL_PARAM params[]) = + want_domainparams ? keymgmt->importdomparams : keymgmt->importkey; + /* * If the given keymgmt doesn't have an import function, give up */ - if (keymgmt->importkey == NULL) + if (importfn == NULL) return NULL; for (j = 0; j < i && pk->pkeys[j].keymgmt != NULL; j++) { @@ -129,6 +137,14 @@ void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt) 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; + + exportfn = want_domainparams + ? pk->pkeys[j].keymgmt->exportdomparams + : pk->pkeys[j].keymgmt->exportkey; paramdefs = pk->pkeys[j].keymgmt->exportkey_types(); /* @@ -138,29 +154,35 @@ void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt) */ params = paramdefs_to_params(paramdefs); /* Get 'return_size' filled */ - pk->pkeys[j].keymgmt->exportkey(pk->pkeys[j].provkey, params); + exportfn(pk->pkeys[j].provdata, params); /* * Allocate space and assign 'data' to point into the - * data block + * data block. + * If something goes wrong, go to the next cached key. */ - data = allocate_params_space(params); + if ((data = allocate_params_space(params)) == NULL) + goto cont; /* * Call the exportkey function a second time, to get - * the data filled + * the data filled. + * If something goes wrong, go to the next cached key. */ - pk->pkeys[j].keymgmt->exportkey(pk->pkeys[j].provkey, params); + if (!exportfn(pk->pkeys[j].provdata, params)) + goto cont; /* * We should have all the data at this point, so import * into the new provider and hope to get a key back. */ - provkey = keymgmt->importkey(provctx, params); + provdata = importfn(provctx, params); + + cont: OPENSSL_free(params); OPENSSL_free(data); - if (provkey != NULL) + if (provdata != NULL) break; } } @@ -173,12 +195,14 @@ void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt) */ j = ossl_assert(i < OSSL_NELEM(pk->pkeys)); - if (provkey != NULL) { + if (provdata != NULL) { EVP_KEYMGMT_up_ref(keymgmt); pk->pkeys[i].keymgmt = keymgmt; - pk->pkeys[i].provkey = provkey; + pk->pkeys[i].provdata = provdata; + pk->pkeys[i].domainparams = want_domainparams; } - return provkey; + + return provdata; } void evp_keymgmt_clear_pkey_cache(EVP_PKEY *pk) @@ -190,11 +214,14 @@ void evp_keymgmt_clear_pkey_cache(EVP_PKEY *pk) i < OSSL_NELEM(pk->pkeys) && pk->pkeys[i].keymgmt != NULL; i++) { EVP_KEYMGMT *keymgmt = pk->pkeys[i].keymgmt; - void *provkey = pk->pkeys[i].provkey; + void *provdata = pk->pkeys[i].provdata; pk->pkeys[i].keymgmt = NULL; - pk->pkeys[i].provkey = NULL; - keymgmt->freekey(provkey); + pk->pkeys[i].provdata = NULL; + if (pk->pkeys[i].domainparams) + keymgmt->freedomparams(provdata); + else + keymgmt->freekey(provdata); EVP_KEYMGMT_free(keymgmt); } } diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c index 7912c8dd59..c02325cf6b 100644 --- a/crypto/evp/m_sigver.c +++ b/crypto/evp/m_sigver.c @@ -94,7 +94,8 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); goto err; } - provkey = evp_keymgmt_export_to_provider(locpctx->pkey, signature->keymgmt); + provkey = + evp_keymgmt_export_to_provider(locpctx->pkey, signature->keymgmt, 0); if (provkey == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); goto err; diff --git a/crypto/evp/pmeth_fn.c b/crypto/evp/pmeth_fn.c index a78839b992..d06edb218b 100644 --- a/crypto/evp/pmeth_fn.c +++ b/crypto/evp/pmeth_fn.c @@ -393,7 +393,8 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature, ctx->op.sig.signature = signature; if (ctx->pkey != NULL) { - provkey = evp_keymgmt_export_to_provider(ctx->pkey, signature->keymgmt); + provkey = + evp_keymgmt_export_to_provider(ctx->pkey, signature->keymgmt, 0); if (provkey == NULL) { EVPerr(0, EVP_R_INITIALIZATION_ERROR); goto err; diff --git a/include/crypto/asn1.h b/include/crypto/asn1.h index 674fa704a1..2581619831 100644 --- a/include/crypto/asn1.h +++ b/include/crypto/asn1.h @@ -70,7 +70,8 @@ struct evp_pkey_asn1_method_st { */ /* Exports to providers */ size_t (*dirty_cnt) (const EVP_PKEY *pk); - void *(*export_to) (const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt); + void *(*export_to) (const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt, + int want_domainparams); } /* EVP_PKEY_ASN1_METHOD */ ; DEFINE_STACK_OF_CONST(EVP_PKEY_ASN1_METHOD) diff --git a/include/crypto/evp.h b/include/crypto/evp.h index 22ef7e5602..dad7174bc5 100644 --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -538,13 +538,15 @@ struct evp_pkey_st { /* * To support transparent export/import between providers that * support the methods for it, and still not having to do the - * export/import every time a key is used, we maintain a cache - * of imported key, indexed by provider address. - * pkeys[0] is *always* the "original" key. + * export/import every time a key or domain params are used, we + * maintain a cache of imported key / domain params, indexed by + * provider address. pkeys[0] is *always* the "original" data. */ struct { EVP_KEYMGMT *keymgmt; - void *provkey; + void *provdata; + /* 0 = provdata is a key, 1 = provdata is domain params */ + int domainparams; } pkeys[10]; /* * If there is a legacy key assigned to this structure, we keep @@ -569,7 +571,8 @@ void evp_cleanup_int(void); void evp_app_cleanup_int(void); /* KEYMGMT helper functions */ -void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt); +void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt, + int domainparams); void evp_keymgmt_clear_pkey_cache(EVP_PKEY *pk); /* KEYMGMT provider interface functions */ -- 2.25.1