openssl/crypto/rsa/rsa_crpt.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

162 lines
3.7 KiB
C
Raw Permalink Normal View History

/*
* Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/*
* RSA low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <stdio.h>
#include <openssl/crypto.h>
#include "internal/cryptlib.h"
#include "crypto/bn.h"
#include <openssl/rand.h>
#include "rsa_local.h"
int RSA_bits(const RSA *r)
{
return BN_num_bits(r->n);
}
int RSA_size(const RSA *r)
{
return BN_num_bytes(r->n);
}
int RSA_public_encrypt(int flen, const unsigned char *from, unsigned char *to,
RSA *rsa, int padding)
{
return rsa->meth->rsa_pub_enc(flen, from, to, rsa, padding);
}
int RSA_private_encrypt(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding)
{
return rsa->meth->rsa_priv_enc(flen, from, to, rsa, padding);
}
int RSA_private_decrypt(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding)
{
return rsa->meth->rsa_priv_dec(flen, from, to, rsa, padding);
}
int RSA_public_decrypt(int flen, const unsigned char *from, unsigned char *to,
RSA *rsa, int padding)
{
return rsa->meth->rsa_pub_dec(flen, from, to, rsa, padding);
}
int RSA_flags(const RSA *r)
{
return r == NULL ? 0 : r->meth->flags;
}
void RSA_blinding_off(RSA *rsa)
{
rsa->flags &= ~RSA_FLAG_BLINDING;
rsa->flags |= RSA_FLAG_NO_BLINDING;
}
int RSA_blinding_on(RSA *rsa, BN_CTX *ctx)
{
rsa->flags |= RSA_FLAG_BLINDING;
rsa->flags &= ~RSA_FLAG_NO_BLINDING;
Remove need for BN_BLINDING lock Issue https://github.com/openssl/project/issues/1245 has identified that we encounter a significant amount of time waiting to acquire the BN_BLINDING_lock when running our handshake perf test with 10 threads using an rsa key. Specifically, with 10 threads we spend about 19327731 usecs just waiting. So it would be great if we could eliminate the need to get the write lock here. Currently, the need for the lock is based off the fact that each rsa key has only a single blinding pointer, for which exclusive access is needed, with an attempt to use a fallback mt_blinding pointer in the shared case. If a key is shared by many threads, then we find ourselves needing to maniuplate this lock quite frequently if we are doing lots of ssl connections. To address this, I've come up with this approach. It replaces the blinding pointer with a pointer to a sparse array. The sparse array is then indexed by thread id. This allows us to do two things: When getting the blinding, we only need to take the read lock in the common case when looking up this threads blinding structure. Only in the first lookup for any thread do we need to take the write side lock when updating the table, and only then for a very brief critical section (i.e. we don't need to hold the lock when allocating/setting the blinding up via RSA_setup_blinding This trades off some extra memory usage for the above significant reduction in execution time. it also allows us to simplify the blinding code quite a bit by eliminating the need to handle shared blindings because blindings are never shared anymore Fixes openssl/project#1245 Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/27913)
2025-06-26 02:26:24 +08:00
return 1;
}
static BIGNUM *rsa_get_public_exp(const BIGNUM *d, const BIGNUM *p,
const BIGNUM *q, BN_CTX *ctx)
{
BIGNUM *ret = NULL, *r0, *r1, *r2;
if (d == NULL || p == NULL || q == NULL)
return NULL;
BN_CTX_start(ctx);
r0 = BN_CTX_get(ctx);
r1 = BN_CTX_get(ctx);
r2 = BN_CTX_get(ctx);
if (r2 == NULL)
goto err;
if (!BN_sub(r1, p, BN_value_one()))
goto err;
if (!BN_sub(r2, q, BN_value_one()))
goto err;
if (!BN_mul(r0, r1, r2, ctx))
goto err;
ret = BN_mod_inverse(NULL, d, r0, ctx);
err:
BN_CTX_end(ctx);
return ret;
}
BN_BLINDING *RSA_setup_blinding(RSA *rsa, BN_CTX *in_ctx)
{
BIGNUM *e;
BN_CTX *ctx;
BN_BLINDING *ret = NULL;
if (in_ctx == NULL) {
if ((ctx = BN_CTX_new_ex(rsa->libctx)) == NULL)
return 0;
} else {
ctx = in_ctx;
}
BN_CTX_start(ctx);
e = BN_CTX_get(ctx);
if (e == NULL) {
ERR_raise(ERR_LIB_RSA, ERR_R_BN_LIB);
goto err;
}
if (rsa->e == NULL) {
e = rsa_get_public_exp(rsa->d, rsa->p, rsa->q, ctx);
if (e == NULL) {
ERR_raise(ERR_LIB_RSA, RSA_R_NO_PUBLIC_EXPONENT);
goto err;
}
} else {
e = rsa->e;
}
{
BIGNUM *n = BN_new();
if (n == NULL) {
ERR_raise(ERR_LIB_RSA, ERR_R_BN_LIB);
goto err;
}
BN_with_flags(n, rsa->n, BN_FLG_CONSTTIME);
ret = BN_BLINDING_create_param(NULL, e, n, ctx, rsa->meth->bn_mod_exp,
rsa->_method_mod_n);
/* We MUST free n before any further use of rsa->n */
BN_free(n);
}
if (ret == NULL) {
ERR_raise(ERR_LIB_RSA, ERR_R_BN_LIB);
goto err;
}
err:
BN_CTX_end(ctx);
if (ctx != in_ctx)
BN_CTX_free(ctx);
if (e != rsa->e)
BN_free(e);
return ret;
}