From f23bc0b770efd229e27519786d9f28da56752d0a Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Wed, 18 Dec 2019 13:24:27 +0100 Subject: [PATCH] EVP: Adapt KEYEXCH, SIGNATURE and ASYM_CIPHER to handle key types better The adaptation is to handle the case when key types and operations that use these keys have different names. For example, EC keys can be used for ECDSA and ECDH. Reviewed-by: Shane Lontis (Merged from https://github.com/openssl/openssl/pull/10647) --- crypto/evp/exchange.c | 34 +++++++++++------ crypto/evp/m_sigver.c | 34 +++++++++++------ crypto/evp/pmeth_fn.c | 69 +++++++++++++++++++++++------------ crypto/evp/pmeth_gn.c | 4 +- crypto/evp/pmeth_lib.c | 4 +- doc/man3/EVP_PKEY_CTX_new.pod | 20 ++++++++-- include/crypto/evp.h | 4 +- 7 files changed, 114 insertions(+), 55 deletions(-) diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c index 3e7c00103c..ade1dc373d 100644 --- a/crypto/evp/exchange.c +++ b/crypto/evp/exchange.c @@ -173,20 +173,32 @@ int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) evp_pkey_ctx_free_old_ops(ctx); ctx->operation = EVP_PKEY_OP_DERIVE; - if (ctx->engine != NULL || ctx->algorithm == NULL) + if (ctx->engine != NULL || ctx->keytype == NULL) goto legacy; - /* - * Because we cleared out old ops, we shouldn't need to worry about - * checking if exchange is already there. Keymgmt is a different - * matter, as it isn't tied to a specific EVP_PKEY op. - */ - exchange = EVP_KEYEXCH_fetch(ctx->libctx, ctx->algorithm, ctx->propquery); - if (exchange != NULL && ctx->keymgmt == NULL) { - int name_id = EVP_KEYEXCH_number(exchange); - + if (ctx->keymgmt == NULL) ctx->keymgmt = - evp_keymgmt_fetch_by_number(ctx->libctx, name_id, ctx->propquery); + EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, ctx->propquery); + if (ctx->keymgmt != NULL) { + const char *supported_exch = NULL; + + if (ctx->keymgmt->query_operation_name != NULL) + supported_exch = + ctx->keymgmt->query_operation_name(OSSL_OP_KEYEXCH); + + /* + * If we didn't get a supported exch, assume there is one with the + * same name as the key type. + */ + if (supported_exch == NULL) + supported_exch = ctx->keytype; + + /* + * Because we cleared out old ops, we shouldn't need to worry about + * checking if exchange is already there. + */ + exchange = + EVP_KEYEXCH_fetch(ctx->libctx, supported_exch, ctx->propquery); } if (ctx->keymgmt == NULL diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c index 9d12e9b96a..ff94063181 100644 --- a/crypto/evp/m_sigver.c +++ b/crypto/evp/m_sigver.c @@ -52,7 +52,7 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, locpctx = ctx->pctx; evp_pkey_ctx_free_old_ops(locpctx); - if (locpctx->algorithm == NULL) + if (locpctx->keytype == NULL) goto legacy; if (mdname == NULL) { @@ -71,18 +71,28 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, } } - /* - * Because we cleared out old ops, we shouldn't need to worry about - * checking if signature is already there. Keymgmt is a different - * matter, as it isn't tied to a specific EVP_PKEY op. - */ - signature = EVP_SIGNATURE_fetch(locpctx->libctx, locpctx->algorithm, - locpctx->propquery); - if (signature != NULL && locpctx->keymgmt == NULL) { - int name_id = EVP_SIGNATURE_number(signature); + if (locpctx->keymgmt == NULL) + locpctx->keymgmt = EVP_KEYMGMT_fetch(locpctx->libctx, locpctx->keytype, + locpctx->propquery); + if (locpctx->keymgmt != NULL) { + const char *supported_sig = NULL; + + if (locpctx->keymgmt->query_operation_name != NULL) + supported_sig = + locpctx->keymgmt->query_operation_name(OSSL_OP_SIGNATURE); + + /* + * If we didn't get a supported sig, assume there is one with the + * same name as the key type. + */ + if (supported_sig == NULL) + supported_sig = locpctx->keytype; - locpctx->keymgmt = - evp_keymgmt_fetch_by_number(locpctx->libctx, name_id, + /* + * Because we cleared out old ops, we shouldn't need to worry about + * checking if signature is already there. + */ + signature = EVP_SIGNATURE_fetch(locpctx->libctx, supported_sig, locpctx->propquery); } diff --git a/crypto/evp/pmeth_fn.c b/crypto/evp/pmeth_fn.c index 0ce4ff9522..3d0ee2e646 100644 --- a/crypto/evp/pmeth_fn.c +++ b/crypto/evp/pmeth_fn.c @@ -331,21 +331,32 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation) evp_pkey_ctx_free_old_ops(ctx); ctx->operation = operation; - if (ctx->algorithm == NULL) + if (ctx->keytype == NULL) goto legacy; - /* - * Because we cleared out old ops, we shouldn't need to worry about - * checking if signature is already there. Keymgmt is a different - * matter, as it isn't tied to a specific EVP_PKEY op. - */ - signature = EVP_SIGNATURE_fetch(ctx->libctx, ctx->algorithm, - ctx->propquery); - if (signature != NULL && ctx->keymgmt == NULL) { - int name_id = EVP_SIGNATURE_number(signature); + if (ctx->keymgmt == NULL) + ctx->keymgmt = + EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, ctx->propquery); + if (ctx->keymgmt != NULL) { + const char *supported_sig = NULL; + + if (ctx->keymgmt->query_operation_name != NULL) + supported_sig = + ctx->keymgmt->query_operation_name(OSSL_OP_SIGNATURE); + + /* + * If we didn't get a supported sig, assume there is one with the + * same name as the key type. + */ + if (supported_sig == NULL) + supported_sig = ctx->keytype; - ctx->keymgmt = evp_keymgmt_fetch_by_number(ctx->libctx, name_id, - ctx->propquery); + /* + * Because we cleared out old ops, we shouldn't need to worry about + * checking if signature is already there. + */ + signature = + EVP_SIGNATURE_fetch(ctx->libctx, supported_sig, ctx->propquery); } if (ctx->keymgmt == NULL @@ -582,20 +593,32 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation) evp_pkey_ctx_free_old_ops(ctx); ctx->operation = operation; - if (ctx->algorithm == NULL || ctx->engine != NULL) + if (ctx->keytype == NULL || ctx->engine != NULL) goto legacy; - /* - * Because we cleared out old ops, we shouldn't need to worry about - * checking if exchange is already there. Keymgmt is a different - * matter, as it isn't tied to a specific EVP_PKEY op. - */ - cipher = EVP_ASYM_CIPHER_fetch(ctx->libctx, ctx->algorithm, ctx->propquery); - if (cipher != NULL && ctx->keymgmt == NULL) { - int name_id = EVP_ASYM_CIPHER_number(cipher); - + if (ctx->keymgmt == NULL) ctx->keymgmt = - evp_keymgmt_fetch_by_number(ctx->libctx, name_id, ctx->propquery); + EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, ctx->propquery); + if (ctx->keymgmt != NULL) { + const char *supported_ciph = NULL; + + if (ctx->keymgmt->query_operation_name != NULL) + supported_ciph = + ctx->keymgmt->query_operation_name(OSSL_OP_ASYM_CIPHER); + + /* + * If we didn't get a supported ciph, assume there is one with the + * same name as the key type. + */ + if (supported_ciph == NULL) + supported_ciph = ctx->keytype; + + /* + * Because we cleared out old ops, we shouldn't need to worry about + * checking if cipher is already there. + */ + cipher = + EVP_ASYM_CIPHER_fetch(ctx->libctx, supported_ciph, ctx->propquery); } if (ctx->keymgmt == NULL diff --git a/crypto/evp/pmeth_gn.c b/crypto/evp/pmeth_gn.c index a5f7dbaf53..100931cda7 100644 --- a/crypto/evp/pmeth_gn.c +++ b/crypto/evp/pmeth_gn.c @@ -19,13 +19,13 @@ static int fromdata_init(EVP_PKEY_CTX *ctx, int operation) { - if (ctx == NULL || ctx->algorithm == NULL) + if (ctx == NULL || ctx->keytype == NULL) goto not_supported; evp_pkey_ctx_free_old_ops(ctx); ctx->operation = operation; if (ctx->keymgmt == NULL) - ctx->keymgmt = EVP_KEYMGMT_fetch(NULL, ctx->algorithm, ctx->propquery); + ctx->keymgmt = EVP_KEYMGMT_fetch(NULL, ctx->keytype, ctx->propquery); if (ctx->keymgmt == NULL) goto not_supported; diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index 8b49baf6ab..2ecc17734e 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -221,7 +221,7 @@ static EVP_PKEY_CTX *int_ctx_new(OPENSSL_CTX *libctx, return NULL; } ret->libctx = libctx; - ret->algorithm = name; + ret->keytype = name; ret->propquery = propquery; ret->engine = e; ret->pmeth = pmeth; @@ -382,7 +382,7 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *pctx) rctx->pkey = pctx->pkey; rctx->operation = pctx->operation; rctx->libctx = pctx->libctx; - rctx->algorithm = pctx->algorithm; + rctx->keytype = pctx->keytype; rctx->propquery = pctx->propquery; if (EVP_PKEY_CTX_IS_DERIVE_OP(pctx)) { diff --git a/doc/man3/EVP_PKEY_CTX_new.pod b/doc/man3/EVP_PKEY_CTX_new.pod index 5d18a04344..90486ae0dc 100644 --- a/doc/man3/EVP_PKEY_CTX_new.pod +++ b/doc/man3/EVP_PKEY_CTX_new.pod @@ -21,14 +21,14 @@ EVP_PKEY_CTX_dup, EVP_PKEY_CTX_free =head1 DESCRIPTION The EVP_PKEY_CTX_new() function allocates public key algorithm context using -the algorithm specified in I and ENGINE I. +the I key type and ENGINE I. The EVP_PKEY_CTX_new_id() function allocates public key algorithm context -using the algorithm specified by I and ENGINE I. +using the key type specified by I and ENGINE I. The EVP_PKEY_CTX_new_provided() function allocates a public key algorithm context using the library context I (see L), the -algorithm specified by I and the property query I. None +key type specified by I and the property query I. None of the arguments are duplicated, so they must remain unchanged for the lifetime of the returned B or of any of its duplicates. @@ -44,11 +44,25 @@ If I is NULL, nothing is done. =head1 NOTES +=over 4 + +=item 1. + The B structure is an opaque public key algorithm context used by the OpenSSL high level public key API. Contexts B be shared between threads: that is it is not permissible to use the same context simultaneously in two threads. +=item 2. + +We mention "key type" in this manual, which is the same +as "algorithm" in most cases, allowing either term to be used +interchangeably. There are algorithms where the I and the +I of the operations that use the keys are not the same, +such as EC keys being used for ECDSA and ECDH operations. + +=back + =head1 RETURN VALUES EVP_PKEY_CTX_new(), EVP_PKEY_CTX_new_id(), EVP_PKEY_CTX_dup() returns either diff --git a/include/crypto/evp.h b/include/crypto/evp.h index 592cbdd536..973ef203ba 100644 --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -22,11 +22,11 @@ struct evp_pkey_ctx_st { int operation; /* - * Library context, Algorithm name and properties associated + * Library context, Key type name and properties associated * with this context */ OPENSSL_CTX *libctx; - const char *algorithm; + const char *keytype; const char *propquery; /* cached key manager */ -- 2.25.1