EVP: Downgrade keys rather than upgrade
authorRichard Levitte <levitte@openssl.org>
Sat, 21 Mar 2020 05:21:26 +0000 (06:21 +0100)
committerRichard Levitte <levitte@openssl.org>
Wed, 25 Mar 2020 16:01:10 +0000 (17:01 +0100)
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)

CHANGES.md
crypto/err/openssl.txt
crypto/evp/evp_err.c
crypto/evp/p_lib.c
crypto/evp/pmeth_gn.c
include/crypto/asn1.h
include/crypto/evp.h
include/openssl/evperr.h
test/keymgmt_internal_test.c

index ba2569bf62ae63b6a4a543ca8cd67a365eed11e3..82c186a6cd33f011d76c66af9ad92bd7f0be82e5 100644 (file)
@@ -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.
 
index cb106e23b1e54872d3f846e7a69e32aa3fc4818e..1a21faa1e1b6e3250f1ee80ee7716e532b087a31 100644 (file)
@@ -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
index 20921710eebcb81f6eb1c1d29e4658e97c7b00a1..3f2b814f18ce343a322f9a5009b59c3ada1a9d19 100644 (file)
@@ -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"},
index 9c11da697efd0590b7bc5e331a5b028159fc51f9..92d65d9f437b95fc8037e40c0288fde4413de000 100644 (file)
@@ -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 */
index 1bf95af2ac3ab34e803e32f1cc35bfe36beb70e7..67800282dee19d436e4f31a895fa258683355b28 100644 (file)
@@ -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)
index 0e7e9ba3d4c72b6295a9bfd8f583ac82bb245678..20732c2251424d20baf58fb29a5f641c354e4ac5 100644 (file)
@@ -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)
index e5f9aad010e302d463b94cfee5d946ea53f0b4ac..63b6dad9c61b6ee53c49b9a4a27b538a5fd984f9 100644 (file)
@@ -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
 
index 994268af91882340fbf46fae11647b3635d824f9..9290cfff9456eb9fedc3c53a7fdcf05e6eee3cc1 100644 (file)
 
 #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
index 5ef238ccf1d7eef89e3943ba5068896014f79a80..fd60893a4559dd9a463e33f18b247a9d2686e4fa 100644 (file)
@@ -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;
 
     /*