]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Pass low level RSA objects to the default provider
authorMatt Caswell <matt@openssl.org>
Fri, 6 Feb 2026 14:51:42 +0000 (14:51 +0000)
committerTomas Mraz <tomas@openssl.org>
Fri, 13 Feb 2026 07:57:58 +0000 (08:57 +0100)
If a low level RSA object has been assigned a custom RSA_METHOD and is
then assigned to an EVP_PKEY object, then we still want the default
provider to use that RSA_METHOD. To ensure this occurs we pass the low
level object across the provider boundary. We can only get away with this
because it is the default provider.

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
MergeDate: Fri Feb 13 07:58:21 2026
(Merged from https://github.com/openssl/openssl/pull/29960)

crypto/evp/p_lib.c
include/internal/threads_common.h
providers/implementations/keymgmt/rsa_kmgmt.c

index b784e243df0103bb3a4257ed6ae9f4d471c28ee0..b91094504b8a9f85a19a0d5793dafb04ae9d9439 100644 (file)
@@ -46,6 +46,7 @@
 #endif
 #include "internal/provider.h"
 #include "internal/common.h"
+#include "internal/threads_common.h"
 #include "evp_local.h"
 
 static int pkey_set_type(EVP_PKEY *pkey, int type, const char *str,
@@ -1897,11 +1898,23 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OSSL_LIB_CTX *libctx,
         if (!EVP_KEYMGMT_is_a(tmp_keymgmt, OBJ_nid2sn(pk->type)))
             goto end;
 
-        if ((keydata = evp_keymgmt_newdata(tmp_keymgmt)) == NULL)
+        /* We attempt to pass the low-level object to the keymgmt via a thread
+         * local. This will actually only succeed in the case that we are using
+         * the default provider. Otherwise it will export in the normal way.
+         */
+        if (!CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_LOW_LEVEL_OBJECT, libctx, pk->pkey.ptr))
+            goto end;
+        keydata = evp_keymgmt_newdata(tmp_keymgmt);
+        if (!CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_LOW_LEVEL_OBJECT, libctx, NULL))
+            goto end;
+        if (keydata == NULL)
             goto end;
 
-        if (!pk->ameth->export_to(pk, keydata, tmp_keymgmt->import,
-                libctx, propquery)) {
+        /*
+         * We skip the export if the key data we got back is actually the same
+         * as the low level object we passed in
+         */
+        if (keydata != pk->pkey.ptr && !pk->ameth->export_to(pk, keydata, tmp_keymgmt->import, libctx, propquery)) {
             evp_keymgmt_freedata(tmp_keymgmt, keydata);
             keydata = NULL;
             goto end;
index 660fb1e5c65fbb9111663f0680cf420c09fa0cee..6c9a5c271d29f69dc9d6561ea30f775273945b8d 100644 (file)
@@ -20,6 +20,7 @@ typedef enum {
     CRYPTO_THREAD_LOCAL_TEVENT_KEY,
     CRYPTO_THREAD_LOCAL_TANDEM_ID_KEY,
     CRYPTO_THREAD_LOCAL_FIPS_DEFERRED_KEY,
+    CRYPTO_THREAD_LOCAL_LOW_LEVEL_OBJECT,
     CRYPTO_THREAD_LOCAL_KEY_MAX
 } CRYPTO_THREAD_LOCAL_KEY_ID;
 
index f8e72b0f19ea2f132c11443392dc4fbff06f2036..2d768823b84f5d061d9ea928497f8f4f9e1bbbe9 100644 (file)
@@ -27,6 +27,7 @@
 #include "crypto/cryptlib.h"
 #include "internal/fips.h"
 #include "internal/param_build_set.h"
+#include "internal/threads_common.h"
 
 static OSSL_FUNC_keymgmt_new_fn rsa_newdata;
 static OSSL_FUNC_keymgmt_new_fn rsapss_newdata;
@@ -75,35 +76,74 @@ static int pss_params_fromdata(RSA_PSS_PARAMS_30 *pss_params, int *defaults_set,
     return 1;
 }
 
+/*
+ * If the application actually created a legacy RSA object and assigned it to
+ * the EVP_PKEY, then we get hold of that object here. We return 0 if we hit
+ * a fatal error or 1 otherwise. We may return 1 but with *rsa set to NULL.
+ */
+static int get_legacy_rsa_object(OSSL_LIB_CTX *libctx, RSA **rsa)
+{
+#ifndef FIPS_MODULE
+    /*
+     * This only works because we are in the default provider. We are not
+     * normally allowed to pass complex objects across the provider boundary
+     * like this.
+     */
+    *rsa = CRYPTO_THREAD_get_local_ex(CRYPTO_THREAD_LOCAL_LOW_LEVEL_OBJECT, libctx);
+    if (*rsa != NULL) {
+        if (ossl_lib_ctx_get_concrete(ossl_rsa_get0_libctx(*rsa)) != ossl_lib_ctx_get_concrete(libctx)) {
+            *rsa = NULL;
+            return 1;
+        }
+        if (!RSA_up_ref(*rsa))
+            return 0;
+    }
+#endif
+
+    return 1;
+}
+
 static void *rsa_newdata(void *provctx)
 {
     OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx);
-    RSA *rsa;
+    RSA *rsa = NULL;
 
     if (!ossl_prov_is_running())
         return NULL;
 
-    rsa = ossl_rsa_new_with_ctx(libctx);
-    if (rsa != NULL) {
-        RSA_clear_flags(rsa, RSA_FLAG_TYPE_MASK);
-        RSA_set_flags(rsa, RSA_FLAG_TYPE_RSA);
+    if (!get_legacy_rsa_object(libctx, &rsa))
+        return NULL;
+
+    if (rsa == NULL) {
+        rsa = ossl_rsa_new_with_ctx(libctx);
+        if (rsa != NULL) {
+            RSA_clear_flags(rsa, RSA_FLAG_TYPE_MASK);
+            RSA_set_flags(rsa, RSA_FLAG_TYPE_RSA);
+        }
     }
+
     return rsa;
 }
 
 static void *rsapss_newdata(void *provctx)
 {
     OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx);
-    RSA *rsa;
+    RSA *rsa = NULL;
 
     if (!ossl_prov_is_running())
         return NULL;
 
-    rsa = ossl_rsa_new_with_ctx(libctx);
-    if (rsa != NULL) {
-        RSA_clear_flags(rsa, RSA_FLAG_TYPE_MASK);
-        RSA_set_flags(rsa, RSA_FLAG_TYPE_RSASSAPSS);
+    if (!get_legacy_rsa_object(libctx, &rsa))
+        return NULL;
+
+    if (rsa == NULL) {
+        rsa = ossl_rsa_new_with_ctx(libctx);
+        if (rsa != NULL) {
+            RSA_clear_flags(rsa, RSA_FLAG_TYPE_MASK);
+            RSA_set_flags(rsa, RSA_FLAG_TYPE_RSASSAPSS);
+        }
     }
+
     return rsa;
 }