Convert more things to scopers

This was just focused around BN_CTX right now.

Change-Id: I9a8bf0b3d6d5b92901fc0afe8162e2e690ebe25c
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/78571
Auto-Submit: David Benjamin <davidben@google.com>
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
David Benjamin
2025-04-15 13:53:53 -04:00
committed by Boringssl LUCI CQ
parent 13a1db17c6
commit eac08c808f
6 changed files with 236 additions and 304 deletions

View File

@@ -55,13 +55,11 @@ int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *out_flags) {
return 0;
}
BN_CTX *ctx = BN_CTX_new();
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
if (ctx == NULL) {
return 0;
}
BN_CTX_start(ctx);
int ok = 0;
bssl::BN_CTXScope scope(ctx.get());
// Check |pub_key| is greater than 1.
if (BN_cmp(pub_key, BN_value_one()) <= 0) {
@@ -69,11 +67,11 @@ int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *out_flags) {
}
// Check |pub_key| is less than |dh->p| - 1.
BIGNUM *tmp = BN_CTX_get(ctx);
BIGNUM *tmp = BN_CTX_get(ctx.get());
if (tmp == NULL ||
!BN_copy(tmp, dh->p) ||
!BN_sub_word(tmp, 1)) {
goto err;
return 0;
}
if (BN_cmp(pub_key, tmp) >= 0) {
*out_flags |= DH_CHECK_PUBKEY_TOO_LARGE;
@@ -83,23 +81,17 @@ int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *out_flags) {
// Check |pub_key|^|dh->q| is 1 mod |dh->p|. This is necessary for RFC 5114
// groups which are not safe primes but pick a generator on a prime-order
// subgroup of size |dh->q|.
if (!BN_mod_exp_mont(tmp, pub_key, dh->q, dh->p, ctx, NULL)) {
goto err;
if (!BN_mod_exp_mont(tmp, pub_key, dh->q, dh->p, ctx.get(), NULL)) {
return 0;
}
if (!BN_is_one(tmp)) {
*out_flags |= DH_CHECK_PUBKEY_INVALID;
}
}
ok = 1;
err:
BN_CTX_end(ctx);
BN_CTX_free(ctx);
return ok;
return 1;
}
int DH_check(const DH *dh, int *out_flags) {
*out_flags = 0;
if (!dh_check_params_fast(dh)) {
@@ -112,23 +104,18 @@ int DH_check(const DH *dh, int *out_flags) {
// for 3, p mod 12 == 5
// for 5, p mod 10 == 3 or 7
// should hold.
int ok = 0, r;
BN_CTX *ctx = NULL;
BN_ULONG l;
BIGNUM *t1 = NULL, *t2 = NULL;
ctx = BN_CTX_new();
if (ctx == NULL) {
goto err;
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
if (ctx == nullptr) {
return 0;
}
BN_CTX_start(ctx);
t1 = BN_CTX_get(ctx);
if (t1 == NULL) {
goto err;
bssl::BN_CTXScope scope(ctx.get());
BIGNUM *t1 = BN_CTX_get(ctx.get());
if (t1 == nullptr) {
return 0;
}
t2 = BN_CTX_get(ctx);
if (t2 == NULL) {
goto err;
BIGNUM *t2 = BN_CTX_get(ctx.get());
if (t2 == nullptr) {
return 0;
}
if (dh->q) {
@@ -138,39 +125,40 @@ int DH_check(const DH *dh, int *out_flags) {
*out_flags |= DH_CHECK_NOT_SUITABLE_GENERATOR;
} else {
// Check g^q == 1 mod p
if (!BN_mod_exp_mont(t1, dh->g, dh->q, dh->p, ctx, NULL)) {
goto err;
if (!BN_mod_exp_mont(t1, dh->g, dh->q, dh->p, ctx.get(), nullptr)) {
return 0;
}
if (!BN_is_one(t1)) {
*out_flags |= DH_CHECK_NOT_SUITABLE_GENERATOR;
}
}
r = BN_is_prime_ex(dh->q, BN_prime_checks_for_validation, ctx, NULL);
int r = BN_is_prime_ex(dh->q, BN_prime_checks_for_validation, ctx.get(),
nullptr);
if (r < 0) {
goto err;
return 0;
}
if (!r) {
*out_flags |= DH_CHECK_Q_NOT_PRIME;
}
// Check p == 1 mod q i.e. q divides p - 1
if (!BN_div(t1, t2, dh->p, dh->q, ctx)) {
goto err;
if (!BN_div(t1, t2, dh->p, dh->q, ctx.get())) {
return 0;
}
if (!BN_is_one(t2)) {
*out_flags |= DH_CHECK_INVALID_Q_VALUE;
}
} else if (BN_is_word(dh->g, DH_GENERATOR_2)) {
l = BN_mod_word(dh->p, 24);
BN_ULONG l = BN_mod_word(dh->p, 24);
if (l == (BN_ULONG)-1) {
goto err;
return 0;
}
if (l != 11) {
*out_flags |= DH_CHECK_NOT_SUITABLE_GENERATOR;
}
} else if (BN_is_word(dh->g, DH_GENERATOR_5)) {
l = BN_mod_word(dh->p, 10);
BN_ULONG l = BN_mod_word(dh->p, 10);
if (l == (BN_ULONG)-1) {
goto err;
return 0;
}
if (l != 3 && l != 7) {
*out_flags |= DH_CHECK_NOT_SUITABLE_GENERATOR;
@@ -179,30 +167,24 @@ int DH_check(const DH *dh, int *out_flags) {
*out_flags |= DH_CHECK_UNABLE_TO_CHECK_GENERATOR;
}
r = BN_is_prime_ex(dh->p, BN_prime_checks_for_validation, ctx, NULL);
int r =
BN_is_prime_ex(dh->p, BN_prime_checks_for_validation, ctx.get(), nullptr);
if (r < 0) {
goto err;
return 0;
}
if (!r) {
*out_flags |= DH_CHECK_P_NOT_PRIME;
} else if (!dh->q) {
if (!BN_rshift1(t1, dh->p)) {
goto err;
return 0;
}
r = BN_is_prime_ex(t1, BN_prime_checks_for_validation, ctx, NULL);
r = BN_is_prime_ex(t1, BN_prime_checks_for_validation, ctx.get(), nullptr);
if (r < 0) {
goto err;
return 0;
}
if (!r) {
*out_flags |= DH_CHECK_P_NOT_SAFE_PRIME;
}
}
ok = 1;
err:
if (ctx != NULL) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
return ok;
return 1;
}

View File

@@ -147,28 +147,27 @@ int DH_generate_key(DH *dh) {
}
int ok = 0;
int generate_new_key = 0;
BN_CTX *ctx = NULL;
BIGNUM *pub_key = NULL, *priv_key = NULL, *priv_key_limit = NULL;
bool generate_new_key = false;
BIGNUM *pub_key = nullptr, *priv_key = nullptr;
ctx = BN_CTX_new();
if (ctx == NULL) {
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
if (ctx == nullptr) {
goto err;
}
if (dh->priv_key == NULL) {
if (dh->priv_key == nullptr) {
priv_key = BN_new();
if (priv_key == NULL) {
if (priv_key == nullptr) {
goto err;
}
generate_new_key = 1;
generate_new_key = true;
} else {
priv_key = dh->priv_key;
}
if (dh->pub_key == NULL) {
if (dh->pub_key == nullptr) {
pub_key = BN_new();
if (pub_key == NULL) {
if (pub_key == nullptr) {
goto err;
}
} else {
@@ -176,7 +175,7 @@ int DH_generate_key(DH *dh) {
}
if (!BN_MONT_CTX_set_locked(&dh->method_mont_p, &dh->method_mont_p_lock,
dh->p, ctx)) {
dh->p, ctx.get())) {
goto err;
}
@@ -202,30 +201,30 @@ int DH_generate_key(DH *dh) {
// clamp |dh->priv_length| before invoking the algorithm.
// Compute M = min(2^N, q).
priv_key_limit = BN_new();
if (priv_key_limit == NULL) {
bssl::UniquePtr<BIGNUM> priv_key_limit(BN_new());
if (priv_key_limit == nullptr) {
goto err;
}
if (dh->priv_length == 0 || dh->priv_length >= BN_num_bits(dh->p) - 1) {
// M = q = (p - 1) / 2.
if (!BN_rshift1(priv_key_limit, dh->p)) {
if (!BN_rshift1(priv_key_limit.get(), dh->p)) {
goto err;
}
} else {
// M = 2^N.
if (!BN_set_bit(priv_key_limit, dh->priv_length)) {
if (!BN_set_bit(priv_key_limit.get(), dh->priv_length)) {
goto err;
}
}
// Choose a private key uniformly from [1, M-1].
if (!BN_rand_range_ex(priv_key, 1, priv_key_limit)) {
if (!BN_rand_range_ex(priv_key, 1, priv_key_limit.get())) {
goto err;
}
}
}
if (!BN_mod_exp_mont_consttime(pub_key, dh->g, priv_key, dh->p, ctx,
if (!BN_mod_exp_mont_consttime(pub_key, dh->g, priv_key, dh->p, ctx.get(),
dh->method_mont_p)) {
goto err;
}
@@ -239,14 +238,12 @@ err:
OPENSSL_PUT_ERROR(DH, ERR_R_BN_LIB);
}
if (dh->pub_key == NULL) {
if (dh->pub_key == nullptr) {
BN_free(pub_key);
}
if (dh->priv_key == NULL) {
if (dh->priv_key == nullptr) {
BN_free(priv_key);
}
BN_free(priv_key_limit);
BN_CTX_free(ctx);
return ok;
}
@@ -267,56 +264,46 @@ static int dh_compute_key(DH *dh, BIGNUM *out_shared_key,
return 0;
}
int ret = 0;
BN_CTX_start(ctx);
bssl::BN_CTXScope scope(ctx);
BIGNUM *p_minus_1 = BN_CTX_get(ctx);
if (!p_minus_1 ||
!BN_MONT_CTX_set_locked(&dh->method_mont_p, &dh->method_mont_p_lock,
dh->p, ctx)) {
goto err;
return 0;
}
if (!BN_mod_exp_mont_consttime(out_shared_key, peers_key, dh->priv_key, dh->p,
ctx, dh->method_mont_p) ||
!BN_copy(p_minus_1, dh->p) || !BN_sub_word(p_minus_1, 1)) {
OPENSSL_PUT_ERROR(DH, ERR_R_BN_LIB);
goto err;
return 0;
}
// This performs the check required by SP 800-56Ar3 section 5.7.1.1 step two.
if (BN_cmp_word(out_shared_key, 1) <= 0 ||
BN_cmp(out_shared_key, p_minus_1) == 0) {
OPENSSL_PUT_ERROR(DH, DH_R_INVALID_PUBKEY);
goto err;
return 0;
}
ret = 1;
err:
BN_CTX_end(ctx);
return ret;
return 1;
}
int dh_compute_key_padded_no_self_test(unsigned char *out,
const BIGNUM *peers_key, DH *dh) {
BN_CTX *ctx = BN_CTX_new();
if (ctx == NULL) {
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
if (ctx == nullptr) {
return -1;
}
BN_CTX_start(ctx);
bssl::BN_CTXScope scope(ctx.get());
int dh_size = DH_size(dh);
int ret = -1;
BIGNUM *shared_key = BN_CTX_get(ctx);
if (shared_key && dh_compute_key(dh, shared_key, peers_key, ctx) &&
BN_bn2bin_padded(out, dh_size, shared_key)) {
ret = dh_size;
BIGNUM *shared_key = BN_CTX_get(ctx.get());
if (shared_key == nullptr ||
!dh_compute_key(dh, shared_key, peers_key, ctx.get()) ||
!BN_bn2bin_padded(out, dh_size, shared_key)) {
return -1;
}
BN_CTX_end(ctx);
BN_CTX_free(ctx);
return ret;
return dh_size;
}
int DH_compute_key_padded(unsigned char *out, const BIGNUM *peers_key, DH *dh) {
@@ -328,22 +315,18 @@ int DH_compute_key_padded(unsigned char *out, const BIGNUM *peers_key, DH *dh) {
int DH_compute_key(unsigned char *out, const BIGNUM *peers_key, DH *dh) {
boringssl_ensure_ffdh_self_test();
BN_CTX *ctx = BN_CTX_new();
if (ctx == NULL) {
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
if (ctx == nullptr) {
return -1;
}
BN_CTX_start(ctx);
int ret = -1;
BIGNUM *shared_key = BN_CTX_get(ctx);
if (shared_key && dh_compute_key(dh, shared_key, peers_key, ctx)) {
// A |BIGNUM|'s byte count fits in |int|.
ret = (int)BN_bn2bin(shared_key, out);
bssl::BN_CTXScope scope(ctx.get());
BIGNUM *shared_key = BN_CTX_get(ctx.get());
if (shared_key == nullptr ||
!dh_compute_key(dh, shared_key, peers_key, ctx.get())) {
return -1;
}
BN_CTX_end(ctx);
BN_CTX_free(ctx);
return ret;
// A |BIGNUM|'s byte count fits in |int|.
return static_cast<int>(BN_bn2bin(shared_key, out));
}
int DH_compute_key_hashed(DH *dh, uint8_t *out, size_t *out_len,
@@ -415,29 +398,27 @@ DH *DH_get_rfc7919_2048(void) {
TOBN(0xadf85458, 0xa2bb4a9a), TOBN(0xffffffff, 0xffffffff),
};
BIGNUM *const ffdhe2048_p = BN_new();
BIGNUM *const ffdhe2048_q = BN_new();
BIGNUM *const ffdhe2048_g = BN_new();
DH *const dh = DH_new();
bssl::UniquePtr<BIGNUM> ffdhe2048_p(BN_new());
bssl::UniquePtr<BIGNUM> ffdhe2048_q(BN_new());
bssl::UniquePtr<BIGNUM> ffdhe2048_g(BN_new());
bssl::UniquePtr<DH> dh(DH_new());
if (!ffdhe2048_p || !ffdhe2048_q || !ffdhe2048_g || !dh) {
goto err;
return nullptr;
}
bn_set_static_words(ffdhe2048_p, kFFDHE2048Data,
bn_set_static_words(ffdhe2048_p.get(), kFFDHE2048Data,
OPENSSL_ARRAY_SIZE(kFFDHE2048Data));
if (!BN_rshift1(ffdhe2048_q, ffdhe2048_p) || !BN_set_word(ffdhe2048_g, 2) ||
!DH_set0_pqg(dh, ffdhe2048_p, ffdhe2048_q, ffdhe2048_g)) {
goto err;
if (!BN_rshift1(ffdhe2048_q.get(), ffdhe2048_p.get()) ||
!BN_set_word(ffdhe2048_g.get(), 2) ||
!DH_set0_pqg(dh.get(), ffdhe2048_p.get(), ffdhe2048_q.get(),
ffdhe2048_g.get())) {
return nullptr;
}
// |DH_set0_pqg| takes ownership on success.
ffdhe2048_p.release();
ffdhe2048_q.release();
ffdhe2048_g.release();
return dh;
err:
BN_free(ffdhe2048_p);
BN_free(ffdhe2048_q);
BN_free(ffdhe2048_g);
DH_free(dh);
return NULL;
return dh.release();
}

View File

@@ -655,12 +655,10 @@ static int arbitrary_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
ERR_clear_error();
// This is an unusual input, so we do not guarantee constant-time processing.
BN_CTX_start(ctx);
bssl::BN_CTXScope scope(ctx);
BIGNUM *tmp = BN_CTX_get(ctx);
int ok = tmp != NULL && BN_nnmod(tmp, in, EC_GROUP_get0_order(group), ctx) &&
ec_bignum_to_scalar(group, out, tmp);
BN_CTX_end(ctx);
return ok;
return tmp != nullptr && BN_nnmod(tmp, in, EC_GROUP_get0_order(group), ctx) &&
ec_bignum_to_scalar(group, out, tmp);
}
int ec_point_mul_no_self_test(const EC_GROUP *group, EC_POINT *r,

View File

@@ -718,15 +718,15 @@ static int check_mod_inverse(int *out_ok, const BIGNUM *a, const BIGNUM *ainv,
// Note |bn_mul_consttime| and |bn_div_consttime| do not scale linearly, but
// checking |ainv| is in range bounds the running time, assuming |m|'s bounds
// were checked by the caller.
BN_CTX_start(ctx);
bssl::BN_CTXScope scope(ctx);
BIGNUM *tmp = BN_CTX_get(ctx);
int ret = tmp != NULL && bn_mul_consttime(tmp, a, ainv, ctx) &&
bn_div_consttime(NULL, tmp, tmp, m, m_min_bits, ctx);
if (ret) {
*out_ok = constant_time_declassify_int(BN_is_one(tmp));
if (tmp == nullptr || //
!bn_mul_consttime(tmp, a, ainv, ctx) ||
!bn_div_consttime(NULL, tmp, tmp, m, m_min_bits, ctx)) {
return 0;
}
BN_CTX_end(ctx);
return ret;
*out_ok = constant_time_declassify_int(BN_is_one(tmp));
return 1;
}
int RSA_check_key(const RSA *key) {

View File

@@ -446,8 +446,6 @@ int rsa_verify_raw_no_self_test(RSA *rsa, size_t *out_len, uint8_t *out,
}
const unsigned rsa_size = RSA_size(rsa);
BIGNUM *f, *result;
if (max_out < rsa_size) {
OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
@@ -458,18 +456,17 @@ int rsa_verify_raw_no_self_test(RSA *rsa, size_t *out_len, uint8_t *out,
return 0;
}
BN_CTX *ctx = BN_CTX_new();
if (ctx == NULL) {
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
if (ctx == nullptr) {
return 0;
}
int ret = 0;
uint8_t *buf = NULL;
BN_CTX_start(ctx);
f = BN_CTX_get(ctx);
result = BN_CTX_get(ctx);
if (f == NULL || result == NULL) {
uint8_t *buf = nullptr;
bssl::BN_CTXScope scope(ctx.get());
BIGNUM *f = BN_CTX_get(ctx.get());
BIGNUM *result = BN_CTX_get(ctx.get());
if (f == nullptr || result == nullptr) {
goto err;
}
@@ -478,12 +475,12 @@ int rsa_verify_raw_no_self_test(RSA *rsa, size_t *out_len, uint8_t *out,
} else {
// Allocate a temporary buffer to hold the padded plaintext.
buf = reinterpret_cast<uint8_t *>(OPENSSL_malloc(rsa_size));
if (buf == NULL) {
if (buf == nullptr) {
goto err;
}
}
if (BN_bin2bn(in, in_len, f) == NULL) {
if (BN_bin2bn(in, in_len, f) == nullptr) {
goto err;
}
@@ -492,8 +489,9 @@ int rsa_verify_raw_no_self_test(RSA *rsa, size_t *out_len, uint8_t *out,
goto err;
}
if (!BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) ||
!BN_mod_exp_mont(result, f, rsa->e, &rsa->mont_n->N, ctx, rsa->mont_n)) {
if (!BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx.get()) ||
!BN_mod_exp_mont(result, f, rsa->e, &rsa->mont_n->N, ctx.get(),
rsa->mont_n)) {
goto err;
}
@@ -522,8 +520,6 @@ int rsa_verify_raw_no_self_test(RSA *rsa, size_t *out_len, uint8_t *out,
}
err:
BN_CTX_end(ctx);
BN_CTX_free(ctx);
if (buf != out) {
OPENSSL_free(buf);
}
@@ -539,32 +535,28 @@ int RSA_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
int rsa_default_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
size_t len) {
if (rsa->n == NULL || rsa->d == NULL) {
if (rsa->n == nullptr || rsa->d == nullptr) {
OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING);
return 0;
}
BIGNUM *f, *result;
BN_CTX *ctx = NULL;
size_t blinding_index = 0;
BN_BLINDING *blinding = NULL;
int ret = 0, do_blinding;
ctx = BN_CTX_new();
if (ctx == NULL) {
goto err;
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
if (ctx == nullptr) {
return 0;
}
BN_CTX_start(ctx);
f = BN_CTX_get(ctx);
result = BN_CTX_get(ctx);
if (f == NULL || result == NULL) {
size_t blinding_index = 0;
BN_BLINDING *blinding = nullptr;
int ret = 0, do_blinding;
bssl::BN_CTXScope scope(ctx.get());
BIGNUM *f = BN_CTX_get(ctx.get());
BIGNUM *result = BN_CTX_get(ctx.get());
if (f == nullptr || result == nullptr) {
goto err;
}
// The caller should have ensured this.
assert(len == BN_num_bytes(rsa->n));
if (BN_bin2bn(in, len, f) == NULL) {
if (BN_bin2bn(in, len, f) == nullptr) {
goto err;
}
@@ -576,7 +568,7 @@ int rsa_default_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
goto err;
}
if (!freeze_private_key(rsa, ctx)) {
if (!freeze_private_key(rsa, ctx.get())) {
OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
@@ -584,7 +576,7 @@ int rsa_default_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
do_blinding =
(rsa->flags & (RSA_FLAG_NO_BLINDING | RSA_FLAG_NO_PUBLIC_EXPONENT)) == 0;
if (rsa->e == NULL && do_blinding) {
if (rsa->e == nullptr && do_blinding) {
// We cannot do blinding or verification without |e|, and continuing without
// those countermeasures is dangerous. However, the Java/Android RSA API
// requires support for keys where only |d| and |n| (and not |e|) are known.
@@ -598,29 +590,29 @@ int rsa_default_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
}
if (do_blinding) {
blinding = rsa_blinding_get(rsa, &blinding_index, ctx);
if (blinding == NULL) {
blinding = rsa_blinding_get(rsa, &blinding_index, ctx.get());
if (blinding == nullptr) {
OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
if (!BN_BLINDING_convert(f, blinding, rsa->e, rsa->mont_n, ctx)) {
if (!BN_BLINDING_convert(f, blinding, rsa->e, rsa->mont_n, ctx.get())) {
goto err;
}
}
if (rsa->p != NULL && rsa->q != NULL && rsa->e != NULL && rsa->dmp1 != NULL &&
rsa->dmq1 != NULL && rsa->iqmp != NULL &&
if (rsa->p != nullptr && rsa->q != nullptr && rsa->e != nullptr &&
rsa->dmp1 != nullptr && rsa->dmq1 != nullptr && rsa->iqmp != nullptr &&
// Require that we can reduce |f| by |rsa->p| and |rsa->q| in constant
// time, which requires primes be the same size, rounded to the Montgomery
// coefficient. (See |mod_montgomery|.) This is not required by RFC 8017,
// but it is true for keys generated by us and all common implementations.
bn_less_than_montgomery_R(rsa->q, rsa->mont_p) &&
bn_less_than_montgomery_R(rsa->p, rsa->mont_q)) {
if (!rsa_mod_exp_crt(result, f, rsa, ctx)) {
if (!rsa_mod_exp_crt(result, f, rsa, ctx.get())) {
goto err;
}
} else if (!BN_mod_exp_mont_consttime(result, f, rsa->d_fixed, rsa->n, ctx,
rsa->mont_n)) {
} else if (!BN_mod_exp_mont_consttime(result, f, rsa->d_fixed, rsa->n,
ctx.get(), rsa->mont_n)) {
goto err;
}
@@ -634,17 +626,19 @@ int rsa_default_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
//
// This check is cheap assuming |e| is small, which we require in
// |rsa_check_public_key|.
if (rsa->e != NULL) {
BIGNUM *vrfy = BN_CTX_get(ctx);
if (vrfy == NULL ||
!BN_mod_exp_mont(vrfy, result, rsa->e, rsa->n, ctx, rsa->mont_n) ||
if (rsa->e != nullptr) {
BIGNUM *vrfy = BN_CTX_get(ctx.get());
if (vrfy == nullptr ||
!BN_mod_exp_mont(vrfy, result, rsa->e, rsa->n, ctx.get(),
rsa->mont_n) ||
!constant_time_declassify_int(BN_equal_consttime(vrfy, f))) {
OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
}
if (do_blinding && !BN_BLINDING_invert(result, blinding, rsa->mont_n, ctx)) {
if (do_blinding &&
!BN_BLINDING_invert(result, blinding, rsa->mont_n, ctx.get())) {
goto err;
}
@@ -663,11 +657,7 @@ int rsa_default_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
ret = 1;
err:
if (ctx != NULL) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
if (blinding != NULL) {
if (blinding != nullptr) {
rsa_blinding_release(rsa, blinding, blinding_index);
}
@@ -717,23 +707,19 @@ static int rsa_mod_exp_crt(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) {
assert(rsa->dmq1 != NULL);
assert(rsa->iqmp != NULL);
BIGNUM *r1, *m1;
int ret = 0;
BN_CTX_start(ctx);
r1 = BN_CTX_get(ctx);
m1 = BN_CTX_get(ctx);
BIGNUM *n, *p, *q;
bssl::BN_CTXScope scope(ctx);
BIGNUM *r1 = BN_CTX_get(ctx);
BIGNUM *m1 = BN_CTX_get(ctx);
if (r1 == NULL || m1 == NULL) {
goto err;
return 0;
}
// Use the minimal-width versions of |n|, |p|, and |q|. Either works, but if
// someone gives us non-minimal values, these will be slightly more efficient
// on the non-Montgomery operations.
n = &rsa->mont_n->N;
p = &rsa->mont_p->N;
q = &rsa->mont_q->N;
BIGNUM *n = &rsa->mont_n->N;
BIGNUM *p = &rsa->mont_p->N;
BIGNUM *q = &rsa->mont_q->N;
// This is a pre-condition for |mod_montgomery|. It was already checked by the
// caller.
@@ -766,7 +752,7 @@ static int rsa_mod_exp_crt(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) {
// [0, n).
!bn_mul_consttime(r0, r0, q, ctx) || //
!bn_uadd_consttime(r0, r0, m1)) {
goto err;
return 0;
}
// The result should be bounded by |n|, but fixed-width operations may
@@ -776,14 +762,10 @@ static int rsa_mod_exp_crt(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) {
declassify_assert(BN_cmp(r0, n) < 0);
bn_assert_fits_in_bytes(r0, BN_num_bytes(n));
if (!bn_resize_words(r0, n->width)) {
goto err;
return 0;
}
ret = 1;
err:
BN_CTX_end(ctx);
return ret;
return 1;
}
static int ensure_bignum(BIGNUM **out) {
@@ -914,11 +896,11 @@ static int generate_prime(BIGNUM *out, int bits, const BIGNUM *e,
}
int limit = BN_is_word(e, 3) ? bits * 8 : bits * 5;
int ret = 0, tries = 0, rand_tries = 0;
BN_CTX_start(ctx);
int tries = 0, rand_tries = 0;
bssl::BN_CTXScope scope(ctx);
BIGNUM *tmp = BN_CTX_get(ctx);
if (tmp == NULL) {
goto err;
return 0;
}
for (;;) {
@@ -927,13 +909,13 @@ static int generate_prime(BIGNUM *out, int bits, const BIGNUM *e,
// bound checked below in steps 4.4 and 5.5).
if (!BN_rand(out, bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ODD) ||
!BN_GENCB_call(cb, BN_GENCB_GENERATED, rand_tries++)) {
goto err;
return 0;
}
if (p != NULL) {
// If |p| and |out| are too close, try again (step 5.4).
if (!bn_abs_sub_consttime(tmp, out, p, ctx)) {
goto err;
return 0;
}
if (BN_cmp(tmp, pow2_bits_100) <= 0) {
continue;
@@ -963,18 +945,17 @@ static int generate_prime(BIGNUM *out, int bits, const BIGNUM *e,
int relatively_prime;
if (!bn_usub_consttime(tmp, out, BN_value_one()) ||
!bn_is_relatively_prime(&relatively_prime, tmp, e, ctx)) {
goto err;
return 0;
}
if (constant_time_declassify_int(relatively_prime)) {
// Test |out| for primality (steps 4.5.1 and 5.6.1).
int is_probable_prime;
if (!BN_primality_test(&is_probable_prime, out,
BN_prime_checks_for_generation, ctx, 0, cb)) {
goto err;
return 0;
}
if (is_probable_prime) {
ret = 1;
goto err;
return 1;
}
}
}
@@ -984,16 +965,12 @@ static int generate_prime(BIGNUM *out, int bits, const BIGNUM *e,
tries++;
if (tries >= limit) {
OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_MANY_ITERATIONS);
goto err;
return 0;
}
if (!BN_GENCB_call(cb, 2, tries)) {
goto err;
return 0;
}
}
err:
BN_CTX_end(ctx);
return ret;
}
// rsa_generate_key_impl generates an RSA key using a generalized version of
@@ -1029,29 +1006,31 @@ static int rsa_generate_key_impl(RSA *rsa, int bits, const BIGNUM *e_value,
return 0;
}
int ret = 0;
int prime_bits = bits / 2;
BN_CTX *ctx = BN_CTX_new();
BIGNUM *totient, *pm1, *qm1, *sqrt2, *pow2_prime_bits_100, *pow2_prime_bits;
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
int sqrt2_bits;
if (ctx == NULL) {
goto bn_err;
}
BN_CTX_start(ctx);
totient = BN_CTX_get(ctx);
pm1 = BN_CTX_get(ctx);
qm1 = BN_CTX_get(ctx);
sqrt2 = BN_CTX_get(ctx);
pow2_prime_bits_100 = BN_CTX_get(ctx);
pow2_prime_bits = BN_CTX_get(ctx);
if (totient == NULL || pm1 == NULL || qm1 == NULL || sqrt2 == NULL ||
pow2_prime_bits_100 == NULL || pow2_prime_bits == NULL ||
!BN_set_bit(pow2_prime_bits_100, prime_bits - 100) ||
!BN_set_bit(pow2_prime_bits, prime_bits)) {
goto bn_err;
if (ctx == nullptr) {
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
return 0;
}
// We need the RSA components non-NULL.
int prime_bits = bits / 2;
bssl::BN_CTXScope scope(ctx.get());
BIGNUM *totient = BN_CTX_get(ctx.get());
BIGNUM *pm1 = BN_CTX_get(ctx.get());
BIGNUM *qm1 = BN_CTX_get(ctx.get());
BIGNUM *sqrt2 = BN_CTX_get(ctx.get());
BIGNUM *pow2_prime_bits_100 = BN_CTX_get(ctx.get());
BIGNUM *pow2_prime_bits = BN_CTX_get(ctx.get());
if (totient == nullptr || pm1 == nullptr || qm1 == nullptr ||
sqrt2 == nullptr || pow2_prime_bits_100 == nullptr ||
pow2_prime_bits == nullptr ||
!BN_set_bit(pow2_prime_bits_100, prime_bits - 100) ||
!BN_set_bit(pow2_prime_bits, prime_bits)) {
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
return 0;
}
// We need the RSA components non-null.
if (!ensure_bignum(&rsa->n) || //
!ensure_bignum(&rsa->d) || //
!ensure_bignum(&rsa->e) || //
@@ -1060,16 +1039,19 @@ static int rsa_generate_key_impl(RSA *rsa, int bits, const BIGNUM *e_value,
!ensure_bignum(&rsa->dmp1) || //
!ensure_bignum(&rsa->dmq1) || //
!ensure_bignum(&rsa->iqmp)) {
goto bn_err;
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
return 0;
}
if (!BN_copy(rsa->e, e_value)) {
goto bn_err;
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
return 0;
}
// Compute sqrt2 >= ⌊2^(prime_bits-1)×√2⌋.
if (!bn_set_words(sqrt2, kBoringSSLRSASqrtTwo, kBoringSSLRSASqrtTwoLen)) {
goto bn_err;
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
return 0;
}
sqrt2_bits = kBoringSSLRSASqrtTwoLen * BN_BITS2;
assert(sqrt2_bits == (int)BN_num_bits(sqrt2));
@@ -1077,14 +1059,16 @@ static int rsa_generate_key_impl(RSA *rsa, int bits, const BIGNUM *e_value,
// For key sizes up to 4096 (prime_bits = 2048), this is exactly
// ⌊2^(prime_bits-1)×√2⌋.
if (!BN_rshift(sqrt2, sqrt2, sqrt2_bits - prime_bits)) {
goto bn_err;
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
return 0;
}
} else if (prime_bits > sqrt2_bits) {
// For key sizes beyond 4096, this is approximate. We err towards retrying
// to ensure our key is the right size and round up.
if (!BN_add_word(sqrt2, 1) ||
!BN_lshift(sqrt2, sqrt2, prime_bits - sqrt2_bits)) {
goto bn_err;
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
return 0;
}
}
assert(prime_bits == (int)BN_num_bits(sqrt2));
@@ -1095,13 +1079,14 @@ static int rsa_generate_key_impl(RSA *rsa, int bits, const BIGNUM *e_value,
//
// Each call to |generate_prime| fails with probability p = 2^-21. The
// probability that either call fails is 1 - (1-p)^2, which is around 2^-20.
if (!generate_prime(rsa->p, prime_bits, rsa->e, NULL, sqrt2,
pow2_prime_bits_100, ctx, cb) ||
if (!generate_prime(rsa->p, prime_bits, rsa->e, nullptr, sqrt2,
pow2_prime_bits_100, ctx.get(), cb) ||
!BN_GENCB_call(cb, 3, 0) ||
!generate_prime(rsa->q, prime_bits, rsa->e, rsa->p, sqrt2,
pow2_prime_bits_100, ctx, cb) ||
pow2_prime_bits_100, ctx.get(), cb) ||
!BN_GENCB_call(cb, 3, 1)) {
goto bn_err;
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
return 0;
}
if (BN_cmp(rsa->p, rsa->q) < 0) {
@@ -1120,9 +1105,11 @@ static int rsa_generate_key_impl(RSA *rsa, int bits, const BIGNUM *e_value,
int no_inverse;
if (!bn_usub_consttime(pm1, rsa->p, BN_value_one()) ||
!bn_usub_consttime(qm1, rsa->q, BN_value_one()) ||
!bn_lcm_consttime(totient, pm1, qm1, ctx) ||
!bn_mod_inverse_consttime(rsa->d, &no_inverse, rsa->e, totient, ctx)) {
goto bn_err;
!bn_lcm_consttime(totient, pm1, qm1, ctx.get()) ||
!bn_mod_inverse_consttime(rsa->d, &no_inverse, rsa->e, totient,
ctx.get())) {
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
return 0;
}
// Retry if |rsa->d| <= 2^|prime_bits|. See appendix B.3.1's guidance on
@@ -1133,12 +1120,15 @@ static int rsa_generate_key_impl(RSA *rsa, int bits, const BIGNUM *e_value,
assert(BN_num_bits(pm1) == (unsigned)prime_bits);
assert(BN_num_bits(qm1) == (unsigned)prime_bits);
if ( // Calculate n.
!bn_mul_consttime(rsa->n, rsa->p, rsa->q, ctx) ||
!bn_mul_consttime(rsa->n, rsa->p, rsa->q, ctx.get()) ||
// Calculate d mod (p-1).
!bn_div_consttime(NULL, rsa->dmp1, rsa->d, pm1, prime_bits, ctx) ||
!bn_div_consttime(nullptr, rsa->dmp1, rsa->d, pm1, prime_bits,
ctx.get()) ||
// Calculate d mod (q-1)
!bn_div_consttime(NULL, rsa->dmq1, rsa->d, qm1, prime_bits, ctx)) {
goto bn_err;
!bn_div_consttime(nullptr, rsa->dmq1, rsa->d, qm1, prime_bits,
ctx.get())) {
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
return 0;
}
bn_set_minimal_width(rsa->n);
@@ -1146,41 +1136,30 @@ static int rsa_generate_key_impl(RSA *rsa, int bits, const BIGNUM *e_value,
bn_declassify(rsa->n);
// Calculate q^-1 mod p.
rsa->mont_p = BN_MONT_CTX_new_consttime(rsa->p, ctx);
if (rsa->mont_p == NULL || //
!bn_mod_inverse_secret_prime(rsa->iqmp, rsa->q, rsa->p, ctx,
rsa->mont_p = BN_MONT_CTX_new_consttime(rsa->p, ctx.get());
if (rsa->mont_p == nullptr || //
!bn_mod_inverse_secret_prime(rsa->iqmp, rsa->q, rsa->p, ctx.get(),
rsa->mont_p)) {
goto bn_err;
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
return 0;
}
// Sanity-check that |rsa->n| has the specified size. This is implied by
// |generate_prime|'s bounds.
if (BN_num_bits(rsa->n) != (unsigned)bits) {
OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
goto err;
return 0;
}
// The key generation process is complex and thus error-prone. It could be
// disastrous to generate and then use a bad key so double-check that the key
// makes sense. Also, while |rsa| is mutable, fill in the cached components.
if (!RSA_check_key(rsa) ||
!freeze_private_key(rsa, ctx)) {
if (!RSA_check_key(rsa) || !freeze_private_key(rsa, ctx.get())) {
OPENSSL_PUT_ERROR(RSA, RSA_R_INTERNAL_ERROR);
goto err;
return 0;
}
ret = 1;
bn_err:
if (!ret) {
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
}
err:
if (ctx != NULL) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
return ret;
return 1;
}
static void replace_bignum(BIGNUM **out, BIGNUM **in) {

View File

@@ -349,25 +349,21 @@ int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
}
const unsigned rsa_size = RSA_size(rsa);
BIGNUM *f, *result;
uint8_t *buf = NULL;
BN_CTX *ctx = NULL;
int i, ret = 0;
if (max_out < rsa_size) {
OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
ctx = BN_CTX_new();
if (ctx == NULL) {
goto err;
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
if (ctx == nullptr) {
return 0;
}
BN_CTX_start(ctx);
f = BN_CTX_get(ctx);
result = BN_CTX_get(ctx);
buf = reinterpret_cast<uint8_t *>(OPENSSL_malloc(rsa_size));
bssl::BN_CTXScope scope(ctx.get());
BIGNUM *f = BN_CTX_get(ctx.get());
BIGNUM *result = BN_CTX_get(ctx.get());
uint8_t *buf = reinterpret_cast<uint8_t *>(OPENSSL_malloc(rsa_size));
int i, ret = 0;
if (!f || !result || !buf) {
goto err;
}
@@ -378,8 +374,8 @@ int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
break;
case RSA_PKCS1_OAEP_PADDING:
// Use the default parameters: SHA-1 for both hashes and no label.
i = RSA_padding_add_PKCS1_OAEP_mgf1(buf, rsa_size, in, in_len, NULL, 0,
NULL, NULL);
i = RSA_padding_add_PKCS1_OAEP_mgf1(buf, rsa_size, in, in_len, nullptr, 0,
nullptr, nullptr);
break;
case RSA_NO_PADDING:
i = RSA_padding_add_none(buf, rsa_size, in, in_len);
@@ -393,7 +389,7 @@ int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
goto err;
}
if (BN_bin2bn(buf, rsa_size, f) == NULL) {
if (BN_bin2bn(buf, rsa_size, f) == nullptr) {
goto err;
}
@@ -403,8 +399,9 @@ int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
goto err;
}
if (!BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) ||
!BN_mod_exp_mont(result, f, rsa->e, &rsa->mont_n->N, ctx, rsa->mont_n)) {
if (!BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx.get()) ||
!BN_mod_exp_mont(result, f, rsa->e, &rsa->mont_n->N, ctx.get(),
rsa->mont_n)) {
goto err;
}
@@ -419,12 +416,7 @@ int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
ret = 1;
err:
if (ctx != NULL) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
OPENSSL_free(buf);
return ret;
}