From f53479f98a2f2a6149192c5e3ef4ddf0926dceba Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 12 May 2023 17:06:10 +0100 Subject: [PATCH] Optimise locking in rsa_get_blinding() We optimise locking in rsa_get_blinding() so that we normally take a read lock, and only fallback to a write lock if we need to. This will be very slightly slower in the case of single use RSA objects, but should be significantly better when an RSA object is reused in a multi-threaded environment. It's probably worth the trade off. Partially fixes #20286 Reviewed-by: Tomas Mraz Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/20953) --- crypto/rsa/rsa_ossl.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/crypto/rsa/rsa_ossl.c b/crypto/rsa/rsa_ossl.c index 0dcb02bfa9..8b9ebbb9dd 100644 --- a/crypto/rsa/rsa_ossl.c +++ b/crypto/rsa/rsa_ossl.c @@ -186,11 +186,21 @@ static BN_BLINDING *rsa_get_blinding(RSA *rsa, int *local, BN_CTX *ctx) { BN_BLINDING *ret; - if (!CRYPTO_THREAD_write_lock(rsa->lock)) + if (!CRYPTO_THREAD_read_lock(rsa->lock)) return NULL; if (rsa->blinding == NULL) { - rsa->blinding = RSA_setup_blinding(rsa, ctx); + /* + * This dance with upgrading the lock from read to write will be + * slower in cases of a single use RSA object, but should be + * significantly better in multi-thread cases (e.g. servers). It's + * probably worth it. + */ + CRYPTO_THREAD_unlock(rsa->lock); + if (!CRYPTO_THREAD_write_lock(rsa->lock)) + return NULL; + if (rsa->blinding == NULL) + rsa->blinding = RSA_setup_blinding(rsa, ctx); } ret = rsa->blinding; @@ -212,7 +222,11 @@ static BN_BLINDING *rsa_get_blinding(RSA *rsa, int *local, BN_CTX *ctx) *local = 0; if (rsa->mt_blinding == NULL) { - rsa->mt_blinding = RSA_setup_blinding(rsa, ctx); + CRYPTO_THREAD_unlock(rsa->lock); + if (!CRYPTO_THREAD_write_lock(rsa->lock)) + return NULL; + if (rsa->mt_blinding == NULL) + rsa->mt_blinding = RSA_setup_blinding(rsa, ctx); } ret = rsa->mt_blinding; }