diff options
author | Richard Levitte <levitte@openssl.org> | 2020-03-21 06:21:26 +0100 |
---|---|---|
committer | Richard Levitte <levitte@openssl.org> | 2020-03-25 17:01:10 +0100 |
commit | acb90ba8ffe6a27f625607760e82842673eb9378 (patch) | |
tree | e2960e7bf66bf703ec58c26942462a1cbf27ed7b | |
parent | EVP: Add EVP_PKEY_set_type_by_keymgmt() and use it (diff) | |
download | openssl-acb90ba8ffe6a27f625607760e82842673eb9378.tar.xz openssl-acb90ba8ffe6a27f625607760e82842673eb9378.zip |
EVP: Downgrade keys rather than upgrade
Upgrading EVP_PKEYs from containing legacy keys to containing provider
side keys proved to be risky, with a number of unpleasant corner
cases, and with functions like EVP_PKEY_get0_DSA() failing
unexpectedly.
We therefore change course, and instead of upgrading legacy internal
keys to provider side internal keys, we downgrade provider side
internal keys to legacy ones. To be able to do this, we add
|import_from| and make it a callback function designed for
evp_keymgmt_export().
This means that evp_pkey_upgrade_to_provider() is replaced with
evp_pkey_downgrade().
EVP_PKEY_copy_parameters() is the most deeply affected function of
this change.
Fixes #11366
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11375)
-rw-r--r-- | CHANGES.md | 6 | ||||
-rw-r--r-- | crypto/err/openssl.txt | 5 | ||||
-rw-r--r-- | crypto/evp/evp_err.c | 7 | ||||
-rw-r--r-- | crypto/evp/p_lib.c | 254 | ||||
-rw-r--r-- | crypto/evp/pmeth_gn.c | 8 | ||||
-rw-r--r-- | include/crypto/asn1.h | 5 | ||||
-rw-r--r-- | include/crypto/evp.h | 4 | ||||
-rw-r--r-- | include/openssl/evperr.h | 11 | ||||
-rw-r--r-- | test/keymgmt_internal_test.c | 12 |
9 files changed, 173 insertions, 139 deletions
diff --git a/CHANGES.md b/CHANGES.md index ba2569bf62..82c186a6cd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -24,6 +24,12 @@ OpenSSL 3.0 ### Changes between 1.1.1 and 3.0 [xx XXX xxxx] ### + * EVP_PKEY_get0_RSA(), EVP_PKEY_get0_DSA(), EVP_PKEY_get0_DH(), and + EVP_PKEY_get0_EC_KEY() can now handle EVP_PKEYs with provider side + internal keys, if they correspond to one of those built in types. + + *Richard Levitte* + * Added EVP_PKEY_set_type_by_keymgmt(), to initialise an EVP_PKEY to contain a provider side internal key. diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index cb106e23b1..1a21faa1e1 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -2525,6 +2525,8 @@ EVP_R_FINAL_ERROR:188:final error EVP_R_FIPS_MODE_NOT_SUPPORTED:167:fips mode not supported EVP_R_GET_RAW_KEY_FAILED:182:get raw key failed EVP_R_ILLEGAL_SCRYPT_PARAMETERS:171:illegal scrypt parameters +EVP_R_INACCESSIBLE_DOMAIN_PARAMETERS:204:inaccessible domain parameters +EVP_R_INACCESSIBLE_KEY:203:inaccessible key EVP_R_INITIALIZATION_ERROR:134:initialization error EVP_R_INPUT_NOT_INITIALIZED:111:input not initialized EVP_R_INVALID_CUSTOM_LENGTH:185:invalid custom length @@ -2537,6 +2539,7 @@ EVP_R_INVALID_OPERATION:148:invalid operation EVP_R_INVALID_PROVIDER_FUNCTIONS:193:invalid provider functions EVP_R_INVALID_SALT_LENGTH:186:invalid salt length EVP_R_KEYGEN_FAILURE:120:keygen failure +EVP_R_KEYMGMT_EXPORT_FAILURE:205:keymgmt export failure EVP_R_KEY_SETUP_FAILED:180:key setup failed EVP_R_MEMORY_LIMIT_EXCEEDED:172:memory limit exceeded EVP_R_MESSAGE_DIGEST_IS_NULL:159:message digest is null @@ -2547,6 +2550,7 @@ EVP_R_NOT_XOF_OR_INVALID_LENGTH:178:not XOF or invalid length EVP_R_NO_CIPHER_SET:131:no cipher set EVP_R_NO_DEFAULT_DIGEST:158:no default digest EVP_R_NO_DIGEST_SET:139:no digest set +EVP_R_NO_IMPORT_FUNCTION:206:no import function EVP_R_NO_KEYMGMT_AVAILABLE:199:no keymgmt available EVP_R_NO_KEYMGMT_PRESENT:196:no keymgmt present EVP_R_NO_KEY_SET:154:no key set @@ -2566,6 +2570,7 @@ EVP_R_PUBLIC_KEY_NOT_RSA:106:public key not rsa EVP_R_TOO_MANY_RECORDS:183:too many records EVP_R_UNKNOWN_CIPHER:160:unknown cipher EVP_R_UNKNOWN_DIGEST:161:unknown digest +EVP_R_UNKNOWN_KEY_TYPE:207:unknown key type EVP_R_UNKNOWN_OPTION:169:unknown option EVP_R_UNKNOWN_PBE_ALGORITHM:121:unknown pbe algorithm EVP_R_UNSUPPORTED_ALGORITHM:156:unsupported algorithm diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c index 20921710ee..3f2b814f18 100644 --- a/crypto/evp/evp_err.c +++ b/crypto/evp/evp_err.c @@ -71,6 +71,9 @@ static const ERR_STRING_DATA EVP_str_reasons[] = { {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_GET_RAW_KEY_FAILED), "get raw key failed"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_ILLEGAL_SCRYPT_PARAMETERS), "illegal scrypt parameters"}, + {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INACCESSIBLE_DOMAIN_PARAMETERS), + "inaccessible domain parameters"}, + {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INACCESSIBLE_KEY), "inaccessible key"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INITIALIZATION_ERROR), "initialization error"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INPUT_NOT_INITIALIZED), @@ -88,6 +91,8 @@ static const ERR_STRING_DATA EVP_str_reasons[] = { {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_SALT_LENGTH), "invalid salt length"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_KEYGEN_FAILURE), "keygen failure"}, + {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_KEYMGMT_EXPORT_FAILURE), + "keymgmt export failure"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_KEY_SETUP_FAILED), "key setup failed"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_MEMORY_LIMIT_EXCEEDED), "memory limit exceeded"}, @@ -103,6 +108,7 @@ static const ERR_STRING_DATA EVP_str_reasons[] = { {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_CIPHER_SET), "no cipher set"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_DEFAULT_DIGEST), "no default digest"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_DIGEST_SET), "no digest set"}, + {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_IMPORT_FUNCTION), "no import function"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_KEYMGMT_AVAILABLE), "no keymgmt available"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_KEYMGMT_PRESENT), "no keymgmt present"}, @@ -129,6 +135,7 @@ static const ERR_STRING_DATA EVP_str_reasons[] = { {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_TOO_MANY_RECORDS), "too many records"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_CIPHER), "unknown cipher"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_DIGEST), "unknown digest"}, + {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_KEY_TYPE), "unknown key type"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_OPTION), "unknown option"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_PBE_ALGORITHM), "unknown pbe algorithm"}, diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c index 9c11da697e..92d65d9f43 100644 --- a/crypto/evp/p_lib.c +++ b/crypto/evp/p_lib.c @@ -94,16 +94,35 @@ int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) */ /* - * Only check that type match this early when both keys are legacy. - * If either of them is provided, we let evp_keymgmt_util_copy() - * do this check, after having exported either of them that isn't - * provided. + * If |to| is a legacy key and |from| isn't, we must downgrade |from|. + * If that fails, this function fails. */ - if (to->keymgmt == NULL && from->keymgmt == NULL) { - if (to->type == EVP_PKEY_NONE) { + if (to->type != EVP_PKEY_NONE && from->keymgmt != NULL) + if (!evp_pkey_downgrade((EVP_PKEY *)from)) + return 0; + + /* + * Make sure |to| is typed. Content is less important at this early + * stage. + * + * 1. If |to| is untyped, assign |from|'s key type to it. + * 2. If |to| contains a legacy key, compare its |type| to |from|'s. + * (|from| was already downgraded above) + * + * If |to| is a provided key, there's nothing more to do here, functions + * like evp_keymgmt_util_copy() and evp_pkey_export_to_provider() called + * further down help us find out if they are the same or not. + */ + if (to->type == EVP_PKEY_NONE && to->keymgmt == NULL) { + if (from->type != EVP_PKEY_NONE) { if (EVP_PKEY_set_type(to, from->type) == 0) return 0; - } else if (to->type != from->type) { + } else { + if (EVP_PKEY_set_type_by_keymgmt(to, from->keymgmt) == 0) + return 0; + } + } else if (to->type != EVP_PKEY_NONE) { + if (to->type != from->type) { EVPerr(EVP_F_EVP_PKEY_COPY_PARAMETERS, EVP_R_DIFFERENT_KEY_TYPES); goto err; } @@ -121,30 +140,6 @@ int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) return 0; } - /* - * If |from| is provided, we upgrade |to| to be provided as well. - * This drops the legacy key from |to|. - * evp_pkey_upgrade_to_provider() checks if |to| is already provided, - * we don't need to do that here. - * - * TODO(3.0) We should investigate if that's too aggressive and make - * this scenario unsupported instead. - */ - if (from->keymgmt != NULL) { - EVP_KEYMGMT *tmp_keymgmt = from->keymgmt; - - /* - * The returned pointer is known to be cached, so we don't have to - * save it. However, if it's NULL, something went wrong and we can't - * copy. - */ - if (evp_pkey_upgrade_to_provider(to, NULL, - &tmp_keymgmt, NULL) == NULL) { - ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); - return 0; - } - } - /* For purely provided keys, we just call the keymgmt utility */ if (to->keymgmt != NULL && from->keymgmt != NULL) return evp_keymgmt_util_copy(to, (EVP_PKEY *)from, @@ -161,8 +156,12 @@ int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) evp_pkey_export_to_provider((EVP_PKEY *)from, NULL, &to_keymgmt, NULL); + /* + * If we get a NULL, it could be an internal error, or it could be + * that there's a key mismatch. We're pretending the latter... + */ if (from_keydata == NULL) { - ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); + ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES); return 0; } return evp_keymgmt_copy(to->keymgmt, to->keydata, from_keydata, @@ -208,20 +207,25 @@ static int evp_pkey_cmp_any(const EVP_PKEY *a, const EVP_PKEY *b, return evp_keymgmt_util_match((EVP_PKEY *)a, (EVP_PKEY *)b, selection); /* - * Here, we know that we have a mixture of legacy and provided keys. - * Try cross export and compare the resulting key data. + * At this point, one of them is provided, the other not. This allows + * us to compare types using legacy NIDs. + */ + if ((a->type != EVP_PKEY_NONE + && !EVP_KEYMGMT_is_a(b->keymgmt, OBJ_nid2sn(a->type))) + || (b->type != EVP_PKEY_NONE + && !EVP_KEYMGMT_is_a(a->keymgmt, OBJ_nid2sn(b->type)))) + return -1; /* not the same key type */ + + /* + * We've determined that they both are the same keytype, so the next + * step is to do a bit of cross export to ensure we have keydata for + * both keys in the same keymgmt. */ keymgmt1 = a->keymgmt; keydata1 = a->keydata; keymgmt2 = b->keymgmt; keydata2 = b->keydata; - if ((keymgmt1 == NULL - && !EVP_KEYMGMT_is_a(keymgmt2, OBJ_nid2sn(a->type))) - || (keymgmt2 == NULL - && !EVP_KEYMGMT_is_a(keymgmt1, OBJ_nid2sn(b->type)))) - return -1; /* not the same key type */ - if (keymgmt2 != NULL && keymgmt2->match != NULL) { tmp_keydata = evp_pkey_export_to_provider((EVP_PKEY *)a, NULL, &keymgmt2, NULL); @@ -359,6 +363,7 @@ EVP_PKEY *EVP_PKEY_new_raw_public_key(int type, ENGINE *e, int EVP_PKEY_get_raw_private_key(const EVP_PKEY *pkey, unsigned char *priv, size_t *len) { + /* TODO(3.0) Do we need to do anything about provider side keys? */ if (pkey->ameth->get_priv_key == NULL) { EVPerr(EVP_F_EVP_PKEY_GET_RAW_PRIVATE_KEY, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); @@ -376,6 +381,7 @@ int EVP_PKEY_get_raw_private_key(const EVP_PKEY *pkey, unsigned char *priv, int EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub, size_t *len) { + /* TODO(3.0) Do we need to do anything about provider side keys? */ if (pkey->ameth->get_pub_key == NULL) { EVPerr(EVP_F_EVP_PKEY_GET_RAW_PUBLIC_KEY, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); @@ -524,6 +530,10 @@ int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) void *EVP_PKEY_get0(const EVP_PKEY *pkey) { + if (!evp_pkey_downgrade((EVP_PKEY *)pkey)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INACCESSIBLE_KEY); + return NULL; + } return pkey->pkey.ptr; } @@ -579,6 +589,10 @@ int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key) RSA *EVP_PKEY_get0_RSA(const EVP_PKEY *pkey) { + if (!evp_pkey_downgrade((EVP_PKEY *)pkey)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INACCESSIBLE_KEY); + return NULL; + } if (pkey->type != EVP_PKEY_RSA && pkey->type != EVP_PKEY_RSA_PSS) { EVPerr(EVP_F_EVP_PKEY_GET0_RSA, EVP_R_EXPECTING_AN_RSA_KEY); return NULL; @@ -606,6 +620,10 @@ int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, DSA *key) DSA *EVP_PKEY_get0_DSA(const EVP_PKEY *pkey) { + if (!evp_pkey_downgrade((EVP_PKEY *)pkey)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INACCESSIBLE_KEY); + return NULL; + } if (pkey->type != EVP_PKEY_DSA) { EVPerr(EVP_F_EVP_PKEY_GET0_DSA, EVP_R_EXPECTING_A_DSA_KEY); return NULL; @@ -634,6 +652,10 @@ int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, EC_KEY *key) EC_KEY *EVP_PKEY_get0_EC_KEY(const EVP_PKEY *pkey) { + if (!evp_pkey_downgrade((EVP_PKEY *)pkey)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INACCESSIBLE_KEY); + return NULL; + } if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { EVPerr(EVP_F_EVP_PKEY_GET0_EC_KEY, EVP_R_EXPECTING_A_EC_KEY); return NULL; @@ -664,6 +686,10 @@ int EVP_PKEY_set1_DH(EVP_PKEY *pkey, DH *key) DH *EVP_PKEY_get0_DH(const EVP_PKEY *pkey) { + if (!evp_pkey_downgrade((EVP_PKEY *)pkey)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INACCESSIBLE_KEY); + return NULL; + } if (pkey->type != EVP_PKEY_DH && pkey->type != EVP_PKEY_DHX) { EVPerr(EVP_F_EVP_PKEY_GET0_DH, EVP_R_EXPECTING_A_DH_KEY); return NULL; @@ -1349,101 +1375,87 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OPENSSL_CTX *libctx, } #ifndef FIPS_MODE -/* - * This differs from exporting in that it releases the legacy key and assigns - * the export keymgmt and keydata to the "origin" provider side key instead - * of the operation cache. - */ -void *evp_pkey_upgrade_to_provider(EVP_PKEY *pk, OPENSSL_CTX *libctx, - EVP_KEYMGMT **keymgmt, - const char *propquery) +int evp_pkey_downgrade(EVP_PKEY *pk) { - EVP_KEYMGMT *allocated_keymgmt = NULL; - EVP_KEYMGMT *tmp_keymgmt = NULL; - void *keydata = NULL; + EVP_KEYMGMT *keymgmt = pk->keymgmt; + void *keydata = pk->keydata; + int type = pk->save_type; + const char *keytype = NULL; - if (pk == NULL) - return NULL; + /* If this isn't a provider side key, we're done */ + if (keymgmt == NULL) + return 1; + + /* Get the key type name for error reporting */ + if (type != EVP_PKEY_NONE) + keytype = OBJ_nid2sn(type); + else + keytype = + evp_first_name(EVP_KEYMGMT_provider(keymgmt), keymgmt->name_id); /* - * If this key is already "upgraded", this function shouldn't have been - * called. + * |save_type| was set when any of the EVP_PKEY_set_type functions + * was called. It was set to EVP_PKEY_NONE if the key type wasn't + * recognised to be any of the legacy key types, and the downgrade + * isn't possible. */ - if (!ossl_assert(pk->keymgmt == NULL)) - return NULL; - - if (keymgmt != NULL) { - tmp_keymgmt = *keymgmt; - *keymgmt = NULL; + if (type == EVP_PKEY_NONE) { + ERR_raise_data(ERR_LIB_EVP, EVP_R_UNKNOWN_KEY_TYPE, + "key type = %s, can't downgrade", keytype); + return 0; } - /* If the key isn't a legacy one, bail out, but with proper values */ - if (pk->pkey.ptr == NULL) { - tmp_keymgmt = pk->keymgmt; - keydata = pk->keydata; - } else { - /* If the legacy key doesn't have an export function, give up */ - if (pk->ameth->export_to == NULL) - return NULL; - - /* - * If no keymgmt was given or found, get a default keymgmt. We do - * so by letting EVP_PKEY_CTX_new_from_pkey() do it for us, then we - * steal it. - */ - if (tmp_keymgmt == NULL) { - EVP_PKEY_CTX *ctx = - EVP_PKEY_CTX_new_from_pkey(libctx, pk, propquery); - - tmp_keymgmt = ctx->keymgmt; - ctx->keymgmt = NULL; - EVP_PKEY_CTX_free(ctx); - } - - /* If we still don't have a keymgmt, give up */ - if (tmp_keymgmt == NULL) - goto end; - - /* Make sure that the keymgmt key type matches the legacy NID */ - if (!ossl_assert(EVP_KEYMGMT_is_a(tmp_keymgmt, OBJ_nid2sn(pk->type)))) - goto end; + /* + * To be able to downgrade, we steal the provider side "origin" keymgmt + * and keydata. We've already grabbed the pointers, so all we need to + * do is clear those pointers in |pk| and then call evp_pkey_free_it(). + * That way, we can restore |pk| if we need to. + */ + pk->keymgmt = NULL; + pk->keydata = NULL; + evp_pkey_free_it(pk); + if (EVP_PKEY_set_type(pk, type)) { + /* If the key is typed but empty, we're done */ + if (keydata == NULL) + return 1; - if ((keydata = evp_keymgmt_newdata(tmp_keymgmt)) == NULL) - goto end; + if (pk->ameth->import_from == NULL) { + ERR_raise_data(ERR_LIB_EVP, EVP_R_NO_IMPORT_FUNCTION, + "key type = %s", keytype); + } else if (evp_keymgmt_export(keymgmt, keydata, + OSSL_KEYMGMT_SELECT_ALL, + pk->ameth->import_from, pk)) { + /* + * Save the provider side data in the operation cache, so they'll + * find it again. evp_pkey_free_it() cleared the cache, so it's + * safe to assume slot zero is free. + * Note that evp_keymgmt_util_cache_keydata() increments keymgmt's + * reference count. + */ + evp_keymgmt_util_cache_keydata(pk, 0, keymgmt, keydata); - if (!pk->ameth->export_to(pk, keydata, tmp_keymgmt) - || !EVP_KEYMGMT_up_ref(tmp_keymgmt)) { - evp_keymgmt_freedata(tmp_keymgmt, keydata); - keydata = NULL; - goto end; + /* Synchronize the dirty count */ + pk->dirty_cnt_copy = pk->ameth->dirty_cnt(pk); + return 1; } - /* - * Clear the operation cache, all the legacy data, as well as the - * dirty counters - */ - evp_pkey_free_legacy(pk); - pk->dirty_cnt_copy = 0; - - evp_keymgmt_util_clear_operation_cache(pk); - pk->keymgmt = tmp_keymgmt; - pk->keydata = keydata; - evp_keymgmt_util_cache_keyinfo(pk); + ERR_raise_data(ERR_LIB_EVP, EVP_R_KEYMGMT_EXPORT_FAILURE, + "key type = %s", keytype); } - end: /* - * If nothing was upgraded, |tmp_keymgmt| might point at a freed - * EVP_KEYMGMT, so we clear it to be safe. It shouldn't be useful for - * the caller either way in that case. + * Something went wrong. This could for example happen if the keymgmt + * turns out to be an HSM implementation that refuses to let go of some + * of the key data, typically the private bits. In this case, we restore + * the provider side internal "origin" and leave it at that. */ - if (keydata == NULL) - tmp_keymgmt = NULL; - - if (keymgmt != NULL) - *keymgmt = tmp_keymgmt; - - EVP_KEYMGMT_free(allocated_keymgmt); - return keydata; + if (!ossl_assert(EVP_PKEY_set_type_by_keymgmt(pk, keymgmt))) { + /* This should not be impossible */ + ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); + return 0; + } + pk->keydata = keydata; + evp_keymgmt_util_cache_keyinfo(pk); + return 0; /* No downgrade, but at least the key is restored */ } #endif /* FIPS_MODE */ diff --git a/crypto/evp/pmeth_gn.c b/crypto/evp/pmeth_gn.c index 1bf95af2ac..67800282de 100644 --- a/crypto/evp/pmeth_gn.c +++ b/crypto/evp/pmeth_gn.c @@ -180,6 +180,8 @@ int EVP_PKEY_gen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey) #ifdef FIPS_MODE goto not_supported; #else + if (ctx->pkey && !evp_pkey_downgrade(ctx->pkey)) + goto not_accessible; switch (ctx->operation) { case EVP_PKEY_OP_PARAMGEN: ret = ctx->pmeth->paramgen(ctx, *ppkey); @@ -208,6 +210,12 @@ int EVP_PKEY_gen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey) ERR_raise(ERR_LIB_EVP, EVP_R_OPERATON_NOT_INITIALIZED); ret = -1; goto end; +#ifndef FIPS_MODE + not_accessible: + ERR_raise(ERR_LIB_EVP, EVP_R_INACCESSIBLE_DOMAIN_PARAMETERS); + ret = -1; + goto end; +#endif } int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey) diff --git a/include/crypto/asn1.h b/include/crypto/asn1.h index 0e7e9ba3d4..20732c2251 100644 --- a/include/crypto/asn1.h +++ b/include/crypto/asn1.h @@ -11,6 +11,8 @@ /* ASN1 public key method structure */ +#include <openssl/core.h> + struct evp_pkey_asn1_method_st { int pkey_id; int pkey_base_id; @@ -68,10 +70,11 @@ struct evp_pkey_asn1_method_st { * TODO: Make sure these functions are defined for key types that are * implemented in providers. */ - /* Exports to providers */ + /* Exports and imports to / from providers */ size_t (*dirty_cnt) (const EVP_PKEY *pk); int (*export_to) (const EVP_PKEY *pk, void *to_keydata, EVP_KEYMGMT *to_keymgmt); + OSSL_CALLBACK *import_from; } /* 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 e5f9aad010..63b6dad9c6 100644 --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -630,10 +630,8 @@ void evp_app_cleanup_int(void); void *evp_pkey_export_to_provider(EVP_PKEY *pk, OPENSSL_CTX *libctx, EVP_KEYMGMT **keymgmt, const char *propquery); -void *evp_pkey_upgrade_to_provider(EVP_PKEY *pk, OPENSSL_CTX *libctx, - EVP_KEYMGMT **keymgmt, - const char *propquery); #ifndef FIPS_MODE +int evp_pkey_downgrade(EVP_PKEY *pk); void evp_pkey_free_legacy(EVP_PKEY *x); #endif diff --git a/include/openssl/evperr.h b/include/openssl/evperr.h index 994268af91..9290cfff94 100644 --- a/include/openssl/evperr.h +++ b/include/openssl/evperr.h @@ -10,12 +10,6 @@ #ifndef OPENSSL_EVPERR_H # define OPENSSL_EVPERR_H -# pragma once - -# include <openssl/macros.h> -# ifndef OPENSSL_NO_DEPRECATED_3_0 -# define HEADER_EVPERR_H -# endif # include <openssl/opensslconf.h> # include <openssl/symhacks.h> @@ -199,6 +193,8 @@ int ERR_load_EVP_strings(void); # define EVP_R_FIPS_MODE_NOT_SUPPORTED 167 # define EVP_R_GET_RAW_KEY_FAILED 182 # define EVP_R_ILLEGAL_SCRYPT_PARAMETERS 171 +# define EVP_R_INACCESSIBLE_DOMAIN_PARAMETERS 204 +# define EVP_R_INACCESSIBLE_KEY 203 # define EVP_R_INITIALIZATION_ERROR 134 # define EVP_R_INPUT_NOT_INITIALIZED 111 # define EVP_R_INVALID_CUSTOM_LENGTH 185 @@ -211,6 +207,7 @@ int ERR_load_EVP_strings(void); # define EVP_R_INVALID_PROVIDER_FUNCTIONS 193 # define EVP_R_INVALID_SALT_LENGTH 186 # define EVP_R_KEYGEN_FAILURE 120 +# define EVP_R_KEYMGMT_EXPORT_FAILURE 205 # define EVP_R_KEY_SETUP_FAILED 180 # define EVP_R_MEMORY_LIMIT_EXCEEDED 172 # define EVP_R_MESSAGE_DIGEST_IS_NULL 159 @@ -221,6 +218,7 @@ int ERR_load_EVP_strings(void); # define EVP_R_NO_CIPHER_SET 131 # define EVP_R_NO_DEFAULT_DIGEST 158 # define EVP_R_NO_DIGEST_SET 139 +# define EVP_R_NO_IMPORT_FUNCTION 206 # define EVP_R_NO_KEYMGMT_AVAILABLE 199 # define EVP_R_NO_KEYMGMT_PRESENT 196 # define EVP_R_NO_KEY_SET 154 @@ -238,6 +236,7 @@ int ERR_load_EVP_strings(void); # define EVP_R_TOO_MANY_RECORDS 183 # define EVP_R_UNKNOWN_CIPHER 160 # define EVP_R_UNKNOWN_DIGEST 161 +# define EVP_R_UNKNOWN_KEY_TYPE 207 # define EVP_R_UNKNOWN_OPTION 169 # define EVP_R_UNKNOWN_PBE_ALGORITHM 121 # define EVP_R_UNSUPPORTED_ALGORITHM 156 diff --git a/test/keymgmt_internal_test.c b/test/keymgmt_internal_test.c index 5ef238ccf1..fd60893a45 100644 --- a/test/keymgmt_internal_test.c +++ b/test/keymgmt_internal_test.c @@ -207,14 +207,10 @@ static int test_pass_rsa(FIXTURE *fixture) || !TEST_ptr_ne(km1, km2)) goto err; - if (!TEST_ptr(evp_pkey_export_to_provider(pk, NULL, &km1, NULL)) - || !TEST_ptr(evp_pkey_upgrade_to_provider(pk, NULL, &km1, NULL)) - || !TEST_ptr(provkey = evp_keymgmt_util_export_to_provider(pk, km2))) - goto err; - - if (!TEST_true(evp_keymgmt_export(km2, provkey, - OSSL_KEYMGMT_SELECT_KEYPAIR, - &export_cb, keydata))) + if (!TEST_ptr(provkey = evp_pkey_export_to_provider(pk, NULL, &km1, NULL)) + || !TEST_true(evp_keymgmt_export(km2, provkey, + OSSL_KEYMGMT_SELECT_KEYPAIR, + &export_cb, keydata))) goto err; /* |