- if (!ossl_assert(evp_keymgmt_util_assign_pkey(pk, keymgmt, keydata))) {
- /* This should not be impossible */
- ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
- return 0;
+ tmp_copy = *pk;
+
+ if (evp_pkey_reset_unlocked(pk)
+ && evp_pkey_copy_downgraded(&pk, &tmp_copy)) {
+ /* Restore the common attributes, then empty |tmp_copy| */
+ pk->references = tmp_copy.references;
+ pk->lock = tmp_copy.lock;
+ pk->attributes = tmp_copy.attributes;
+ pk->save_parameters = tmp_copy.save_parameters;
+ pk->ex_data = tmp_copy.ex_data;
+
+ /* Ensure that stuff we've copied won't be freed */
+ tmp_copy.lock = NULL;
+ tmp_copy.attributes = NULL;
+ memset(&tmp_copy.ex_data, 0, sizeof(tmp_copy.ex_data));
+
+ /*
+ * Save the provider side data in the operation cache, so they'll
+ * find it again. |pk| is new, so it's safe to assume slot zero
+ * is free.
+ * Note that evp_keymgmt_util_cache_keydata() increments keymgmt's
+ * reference count, so we need to decrement it, or there will be a
+ * leak.
+ */
+ evp_keymgmt_util_cache_keydata(pk, 0, tmp_copy.keymgmt,
+ tmp_copy.keydata);
+ EVP_KEYMGMT_free(tmp_copy.keymgmt);
+
+ /*
+ * Clear keymgmt and keydata from |tmp_copy|, or they'll get
+ * inadvertently freed.
+ */
+ tmp_copy.keymgmt = NULL;
+ tmp_copy.keydata = NULL;
+
+ evp_pkey_free_it(&tmp_copy);
+
+ return 1;