diff options
author | Richard Levitte <levitte@openssl.org> | 2020-09-02 09:30:42 +0200 |
---|---|---|
committer | Richard Levitte <levitte@openssl.org> | 2020-09-08 06:25:27 +0200 |
commit | 509144964ba69b69a90269da52a2dc3acb3149e6 (patch) | |
tree | 0dacf1c9eb45dd8bf460288ef08f2b410b1f8ae7 /crypto/evp/pmeth_lib.c | |
parent | 884baafba4a5fec6502b828a73188d7133b9179b (diff) |
EVP: Preserve the EVP_PKEY id in a few more spots
As long as there are internal legacy keys for EVP_PKEY, we need to preserve
the EVP_PKEY numeric identity when generating a key, and when creating the
EVP_PKEY_CTX.
For added consistency, the EVP_PKEY_CTX contructor tries a little
harder to find a EVP_PKEY_METHOD. Otherwise, we may run into
situations where the EVP_PKEY_CTX ends up having no associated methods
at all.
Reviewed-by: Paul Yang <kaishen.yy@antfin.com>
(Merged from https://github.com/openssl/openssl/pull/12785)
Diffstat (limited to 'crypto/evp/pmeth_lib.c')
-rw-r--r-- | crypto/evp/pmeth_lib.c | 136 |
1 files changed, 89 insertions, 47 deletions
diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index aef7c39a20..7f144b0afc 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -121,22 +121,36 @@ EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags) pmeth->flags = flags | EVP_PKEY_FLAG_DYNAMIC; return pmeth; } + +static void help_get_legacy_alg_type_from_keymgmt(const char *keytype, + void *arg) +{ + int *type = arg; + + if (*type == NID_undef) + *type = evp_pkey_name2type(keytype); +} + +static int get_legacy_alg_type_from_keymgmt(const EVP_KEYMGMT *keymgmt) +{ + int type = NID_undef; + + EVP_KEYMGMT_names_do_all(keymgmt, help_get_legacy_alg_type_from_keymgmt, + &type); + return type; +} #endif /* FIPS_MODULE */ static int is_legacy_alg(int id, const char *keytype) { #ifndef FIPS_MODULE /* Certain EVP_PKEY keytypes are only available in legacy form */ - if (id == -1) { - id = OBJ_sn2nid(keytype); - if (id == NID_undef) - id = OBJ_ln2nid(keytype); - if (id == NID_undef) - return 0; - } + if (id == -1) + id = evp_pkey_name2type(keytype); + switch (id) { /* - * TODO(3.0): Remove SM2 and DHX when they are converted to have provider + * TODO(3.0): Remove SM2 when they are converted to have provider * support */ case EVP_PKEY_SM2: @@ -155,19 +169,12 @@ static EVP_PKEY_CTX *int_ctx_new(OPENSSL_CTX *libctx, int id) { - EVP_PKEY_CTX *ret; + EVP_PKEY_CTX *ret = NULL; const EVP_PKEY_METHOD *pmeth = NULL; EVP_KEYMGMT *keymgmt = NULL; /* - * When using providers, the context is bound to the algo implementation - * later. - */ - if (pkey == NULL && e == NULL && id == -1) - goto common; - - /* - * If the internal key is provided, we extract the keytype from its + * If the given |pkey| is provided, we extract the keytype from its * keymgmt and skip over the legacy code. */ if (pkey != NULL && evp_pkey_is_provided(pkey)) { @@ -177,14 +184,24 @@ static EVP_PKEY_CTX *int_ctx_new(OPENSSL_CTX *libctx, keytype = evp_first_name(pkey->keymgmt->prov, pkey->keymgmt->name_id); goto common; } + #ifndef FIPS_MODULE - /* TODO(3.0) Legacy code should be removed when all is provider based */ + /* + * TODO(3.0) This legacy code section should be removed when we stop + * supporting engines + */ /* BEGIN legacy */ if (id == -1) { - if (pkey == NULL) - return NULL; - id = pkey->type; + if (pkey != NULL) + id = pkey->type; + else if (keytype != NULL) + id = evp_pkey_name2type(keytype); + if (id == NID_undef) + id = -1; } + /* If no ID was found here, we can only resort to find a keymgmt */ + if (id == -1) + goto common; /* * Here, we extract what information we can for the purpose of @@ -219,24 +236,11 @@ static EVP_PKEY_CTX *int_ctx_new(OPENSSL_CTX *libctx, * If an ENGINE handled this method look it up. Otherwise use internal * tables. */ - if (e != NULL) { + if (e != NULL) pmeth = ENGINE_get_pkey_meth(e, id); - /* - * We are supposed to use an engine, so no point in looking for a - * provided implementation. If pmeth is NULL here we just fail. - */ - if (pmeth == NULL) { - ENGINE_finish(e); - EVPerr(EVP_F_INT_CTX_NEW, EVP_R_UNSUPPORTED_ALGORITHM); - return NULL; - } - } else + else # endif pmeth = EVP_PKEY_meth_find(id); - /* - * if pmeth is NULL here we can keep trying to see if we have a provided - * implementation below. - */ /* END legacy */ #endif /* FIPS_MODULE */ @@ -248,33 +252,71 @@ static EVP_PKEY_CTX *int_ctx_new(OPENSSL_CTX *libctx, if (e == NULL && keytype != NULL) { int legacy = is_legacy_alg(id, keytype); - if (legacy) { - /* This could fail so ignore errors */ + /* This could fail so ignore errors */ + if (legacy) ERR_set_mark(); - } keymgmt = EVP_KEYMGMT_fetch(libctx, keytype, propquery); - if (legacy) { + if (legacy) ERR_pop_to_mark(); - } else if (keymgmt == NULL) { - EVPerr(EVP_F_INT_CTX_NEW, EVP_R_FETCH_FAILED); - return NULL; + else if (keymgmt == NULL) + return NULL; /* EVP_KEYMGMT_fetch() recorded an error */ + +#ifndef FIPS_MODULE + /* + * Chase down the legacy NID, as that might be needed for diverse + * purposes, such as ensure that EVP_PKEY_type() can return sensible + * values, or that there's a better chance to "downgrade" a key when + * needed. We go through all keymgmt names, because the keytype + * that's passed to this function doesn't necessarily translate + * directly. + * TODO: Remove this when #legacy keys are gone. + */ + if (keymgmt != NULL) { + int tmp_id = get_legacy_alg_type_from_keymgmt(keymgmt); + + if (tmp_id != NID_undef) { + if (id == -1) { + id = tmp_id; + } else { + /* + * It really really shouldn't differ. If it still does, + * something is very wrong. + */ + if (!ossl_assert(id == tmp_id)) { + EVPerr(EVP_F_INT_CTX_NEW, ERR_R_INTERNAL_ERROR); + EVP_KEYMGMT_free(keymgmt); + return NULL; + } + } + } } +#endif + } + + if (pmeth == NULL && keymgmt == NULL) { + EVPerr(EVP_F_INT_CTX_NEW, EVP_R_UNSUPPORTED_ALGORITHM); + } else { + ret = OPENSSL_zalloc(sizeof(*ret)); + if (ret == NULL) + EVPerr(EVP_F_INT_CTX_NEW, ERR_R_MALLOC_FAILURE); } - ret = OPENSSL_zalloc(sizeof(*ret)); - if (ret == NULL) { - EVP_KEYMGMT_free(keymgmt); #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + if ((ret == NULL || pmeth == NULL) && e != NULL) ENGINE_finish(e); #endif - EVPerr(EVP_F_INT_CTX_NEW, ERR_R_MALLOC_FAILURE); + + if (ret == NULL) { + EVP_KEYMGMT_free(keymgmt); return NULL; } + ret->libctx = libctx; ret->propquery = propquery; ret->keytype = keytype; ret->keymgmt = keymgmt; + ret->legacy_keytype = id; /* TODO: Remove when #legacy key are gone */ ret->engine = e; ret->pmeth = pmeth; ret->operation = EVP_PKEY_OP_UNDEFINED; |