Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/boringssl.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crypto/bn/gcd.c67
-rw-r--r--crypto/rsa/blinding.c35
-rw-r--r--include/openssl/bn.h31
3 files changed, 90 insertions, 43 deletions
diff --git a/crypto/bn/gcd.c b/crypto/bn/gcd.c
index 52db5698..0cc18d91 100644
--- a/crypto/bn/gcd.c
+++ b/crypto/bn/gcd.c
@@ -227,17 +227,13 @@ static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse,
const BIGNUM *a, const BIGNUM *n,
BN_CTX *ctx);
-BIGNUM *BN_mod_inverse_ex(BIGNUM *out, int *out_no_inverse, const BIGNUM *a,
- const BIGNUM *n, BN_CTX *ctx) {
+static BIGNUM *bn_mod_inverse_ex(BIGNUM *out, int *out_no_inverse,
+ const BIGNUM *a, const BIGNUM *n,
+ BN_CTX *ctx) {
BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL;
BIGNUM *ret = NULL;
int sign;
- if ((a->flags & BN_FLG_CONSTTIME) != 0 ||
- (n->flags & BN_FLG_CONSTTIME) != 0) {
- return BN_mod_inverse_no_branch(out, out_no_inverse, a, n, ctx);
- }
-
*out_no_inverse = 0;
BN_CTX_start(ctx);
@@ -266,11 +262,6 @@ BIGNUM *BN_mod_inverse_ex(BIGNUM *out, int *out_no_inverse, const BIGNUM *a,
goto err;
}
A->neg = 0;
- if (B->neg || (BN_ucmp(B, A) >= 0)) {
- if (!BN_nnmod(B, B, A, ctx)) {
- goto err;
- }
- }
sign = -1;
/* From B = a mod |n|, A = |n| it follows that
*
@@ -543,7 +534,57 @@ err:
BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, const BIGNUM *n,
BN_CTX *ctx) {
int no_inverse;
- return BN_mod_inverse_ex(out, &no_inverse, a, n, ctx);
+
+ if ((a->flags & BN_FLG_CONSTTIME) != 0 ||
+ (n->flags & BN_FLG_CONSTTIME) != 0) {
+ return BN_mod_inverse_no_branch(out, &no_inverse, a, n, ctx);
+ }
+
+ if (!a->neg && BN_ucmp(a, n) < 0) {
+ return bn_mod_inverse_ex(out, &no_inverse, a, n, ctx);
+ }
+
+ BIGNUM a_reduced;
+ BN_init(&a_reduced);
+ BIGNUM *ret = NULL;
+
+ if (!BN_nnmod(&a_reduced, a, n, ctx)) {
+ goto err;
+ }
+
+ ret = bn_mod_inverse_ex(out, &no_inverse, &a_reduced, n, ctx);
+
+err:
+ BN_free(&a_reduced);
+ return ret;
+}
+
+int BN_mod_inverse_blinded(BIGNUM *out, int *out_no_inverse, const BIGNUM *a,
+ const BN_MONT_CTX *mont, BN_CTX *ctx) {
+ *out_no_inverse = 0;
+
+ if (BN_is_negative(a) || BN_cmp(a, &mont->N) >= 0) {
+ OPENSSL_PUT_ERROR(BN, BN_R_INPUT_NOT_REDUCED);
+ return 0;
+ }
+
+ int ret = 0;
+ BIGNUM blinding_factor;
+ BN_init(&blinding_factor);
+
+ if (!BN_rand_range_ex(&blinding_factor, 1, &mont->N) ||
+ !BN_mod_mul_montgomery(out, &blinding_factor, a, mont, ctx) ||
+ bn_mod_inverse_ex(out, out_no_inverse, out, &mont->N, ctx) == NULL ||
+ !BN_mod_mul_montgomery(out, &blinding_factor, out, mont, ctx)) {
+ OPENSSL_PUT_ERROR(BN, ERR_R_BN_LIB);
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ BN_free(&blinding_factor);
+ return ret;
}
/* BN_mod_inverse_no_branch is a special version of BN_mod_inverse.
diff --git a/crypto/rsa/blinding.c b/crypto/rsa/blinding.c
index 71f2e6f8..0a485ee9 100644
--- a/crypto/rsa/blinding.c
+++ b/crypto/rsa/blinding.c
@@ -216,9 +216,6 @@ int BN_BLINDING_invert(BIGNUM *n, const BN_BLINDING *b, BN_MONT_CTX *mont,
static int bn_blinding_create_param(BN_BLINDING *b, const BIGNUM *e,
const BN_MONT_CTX *mont, BN_CTX *ctx) {
- BIGNUM mont_N_consttime;
- BN_init(&mont_N_consttime);
- BN_with_flags(&mont_N_consttime, &mont->N, BN_FLG_CONSTTIME);
int retry_counter = 32;
do {
@@ -227,30 +224,30 @@ static int bn_blinding_create_param(BN_BLINDING *b, const BIGNUM *e,
return 0;
}
- /* |BN_from_montgomery| + |BN_mod_inverse_no_branch| is equivalent to, but
- * more efficient than, |BN_mod_inverse_no_branch| + |BN_to_montgomery|. */
+ /* |BN_from_montgomery| + |BN_mod_inverse_blinded| is equivalent to, but
+ * more efficient than, |BN_mod_inverse_blinded| + |BN_to_montgomery|. */
if (!BN_from_montgomery(b->Ai, b->A, mont, ctx)) {
OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
return 0;
}
int no_inverse;
- if (BN_mod_inverse_ex(b->Ai, &no_inverse, b->Ai, &mont_N_consttime, ctx) ==
- NULL) {
- /* this should almost never happen for good RSA keys */
- if (no_inverse) {
- if (retry_counter-- == 0) {
- OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_MANY_ITERATIONS);
- return 0;
- }
- ERR_clear_error();
- } else {
- OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- } else {
+ if (BN_mod_inverse_blinded(b->Ai, &no_inverse, b->Ai, mont, ctx)) {
break;
}
+
+ if (!no_inverse) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ /* For reasonably-sized RSA keys, it should almost never be the case that a
+ * random value doesn't have an inverse. */
+ if (retry_counter-- == 0) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_MANY_ITERATIONS);
+ return 0;
+ }
+ ERR_clear_error();
} while (1);
if (!BN_mod_exp_mont(b->A, b->A, e, &mont->N, ctx, mont)) {
diff --git a/include/openssl/bn.h b/include/openssl/bn.h
index 0b5af6a0..a8536ef3 100644
--- a/include/openssl/bn.h
+++ b/include/openssl/bn.h
@@ -722,20 +722,29 @@ OPENSSL_EXPORT int BN_is_prime_ex(const BIGNUM *candidate, int checks,
OPENSSL_EXPORT int BN_gcd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
BN_CTX *ctx);
-/* BN_mod_inverse sets |out| equal to |a|^-1, mod |n|. If either of |a| or |n|
- * have |BN_FLG_CONSTTIME| set then the operation is performed in constant
- * time. If |out| is NULL, a fresh BIGNUM is allocated. It returns the result
- * or NULL on error. */
+/* BN_mod_inverse sets |out| equal to |a|^-1, mod |n|. If |out| is NULL, a
+ * fresh BIGNUM is allocated. It returns the result or NULL on error.
+ *
+ * If either of |a| or |n| have |BN_FLG_CONSTTIME| set then the operation is
+ * performed using an algorithm that avoids some branches but which isn't
+ * constant-time. This function shouldn't be used for secret values, even
+ * with |BN_FLG_CONSTTIME|; use |BN_mod_inverse_blinded| instead. Or, if
+ * |n| is guaranteed to be prime, use
+ * |BN_mod_exp_mont_consttime(out, a, m_minus_2, m, ctx, m_mont)|, taking
+ * advantage of Fermat's Little Theorem. */
OPENSSL_EXPORT BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a,
const BIGNUM *n, BN_CTX *ctx);
-/* BN_mod_inverse_ex acts like |BN_mod_inverse| except that, when it returns
- * zero, it will set |*out_no_inverse| to one if the failure was caused because
- * |a| has no inverse mod |n|. Otherwise it will set |*out_no_inverse| to
- * zero. */
-OPENSSL_EXPORT BIGNUM *BN_mod_inverse_ex(BIGNUM *out, int *out_no_inverse,
- const BIGNUM *a, const BIGNUM *n,
- BN_CTX *ctx);
+/* BN_mod_inverse_blinded sets |out| equal to |a|^-1, mod |n|, where |n| is the
+ * Montgomery modulus for |mont|. |a| must be non-negative and must be less
+ * than |n|. |n| must be greater than 1. |a| is blinded (masked by a random
+ * value) to protect it against side-channel attacks. |BN_mod_inverse_blinded|
+ * may or may not ignore the |BN_FLG_CONSTTIME| flag on any/all of its inputs.
+ * It returns one on success or zero on failure. On failure, if the failure was
+ * caused by |a| having no inverse mod |n| then |*out_no_inverse| will be set
+ * to one; otherwise it will be set to zero. */
+int BN_mod_inverse_blinded(BIGNUM *out, int *out_no_inverse, const BIGNUM *a,
+ const BN_MONT_CTX *mont, BN_CTX *ctx);
/* BN_kronecker returns the Kronecker symbol of |a| and |b| (which is -1, 0 or
* 1), or -2 on error. */