summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Polyakov <appro@openssl.org>2018-07-06 15:55:34 +0200
committerAndy Polyakov <appro@openssl.org>2018-08-01 16:15:17 +0200
commit83325a68ad5fdfc359ab9d82a0e0da8e5fe7ede1 (patch)
treead32da61ff030b8846054e614e5cc402b09cb629
parentc9046a05ec0fc3377e1077b401652d76ee5ce908 (diff)
ecdsa/ecs_ossl.c: revert blinding in ECDSA signature.
Originally suggested solution for "Return Of the Hidden Number Problem" is arguably too expensive. While it has marginal impact on slower curves, none to ~6%, optimized implementations suffer real penalties. Most notably sign with P-256 went more than 2 times[!] slower. Instead, just implement constant-time BN_mod_add_quick. Reviewed-by: Rich Salz <rsalz@openssl.org> (Merged from https://github.com/openssl/openssl/pull/6810) (cherry picked from commit 3fc7a9b96cbed0c3da6f53c08e34d8d0c982745f) Resolved onflicts: crypto/ec/ecdsa_ossl.c crypto/include/internal/bn_int.h
-rw-r--r--crypto/bn/bn_mod.c66
-rw-r--r--crypto/bn_int.h2
-rw-r--r--crypto/ecdsa/ecs_ossl.c82
3 files changed, 77 insertions, 73 deletions
diff --git a/crypto/bn/bn_mod.c b/crypto/bn/bn_mod.c
index ffbce890cf..df6f1e2452 100644
--- a/crypto/bn/bn_mod.c
+++ b/crypto/bn/bn_mod.c
@@ -149,18 +149,72 @@ int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
/*
* BN_mod_add variant that may be used if both a and b are non-negative and
- * less than m
+ * less than m. The original algorithm was
+ *
+ * if (!BN_uadd(r, a, b))
+ * return 0;
+ * if (BN_ucmp(r, m) >= 0)
+ * return BN_usub(r, r, m);
+ *
+ * which is replaced with addition, subtracting modulus, and conditional
+ * move depending on whether or not subtraction borrowed.
*/
-int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
- const BIGNUM *m)
+int bn_mod_add_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const BIGNUM *m)
{
- if (!BN_uadd(r, a, b))
+ size_t i, ai, bi, mtop = m->top;
+ BN_ULONG storage[1024 / BN_BITS2];
+ BN_ULONG carry, temp, mask, *rp, *tp = storage;
+ const BN_ULONG *ap, *bp;
+
+ if (bn_wexpand(r, m->top) == NULL)
return 0;
- if (BN_ucmp(r, m) >= 0)
- return BN_usub(r, r, m);
+
+ if (mtop > sizeof(storage) / sizeof(storage[0])
+ && (tp = OPENSSL_malloc(mtop * sizeof(BN_ULONG))) == NULL)
+ return 0;
+
+ ap = a->d != NULL ? a->d : tp;
+ bp = b->d != NULL ? b->d : tp;
+
+ for (i = 0, ai = 0, bi = 0, carry = 0; i < mtop;) {
+ mask = (BN_ULONG)0 - ((i - a->top) >> (8 * sizeof(i) - 1));
+ temp = ((ap[ai] & mask) + carry) & BN_MASK2;
+ carry = (temp < carry);
+
+ mask = (BN_ULONG)0 - ((i - b->top) >> (8 * sizeof(i) - 1));
+ tp[i] = ((bp[bi] & mask) + temp) & BN_MASK2;
+ carry += (tp[i] < temp);
+
+ i++;
+ ai += (i - a->dmax) >> (8 * sizeof(i) - 1);
+ bi += (i - b->dmax) >> (8 * sizeof(i) - 1);
+ }
+ rp = r->d;
+ carry -= bn_sub_words(rp, tp, m->d, mtop);
+ for (i = 0; i < mtop; i++) {
+ rp[i] = (carry & tp[i]) | (~carry & rp[i]);
+ ((volatile BN_ULONG *)tp)[i] = 0;
+ }
+ r->top = mtop;
+
+ if (tp != storage)
+ OPENSSL_free(tp);
+
return 1;
}
+int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const BIGNUM *m)
+{
+ int ret = bn_mod_add_fixed_top(r, a, b, m);
+
+ if (ret)
+ bn_correct_top(r);
+
+ return ret;
+}
+
int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
BN_CTX *ctx)
{
diff --git a/crypto/bn_int.h b/crypto/bn_int.h
index a3b0fa7960..9683e5f60c 100644
--- a/crypto/bn_int.h
+++ b/crypto/bn_int.h
@@ -9,3 +9,5 @@ int bn_mul_mont_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
BN_MONT_CTX *mont, BN_CTX *ctx);
int bn_to_mont_fixed_top(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mont,
BN_CTX *ctx);
+int bn_mod_add_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const BIGNUM *m);
diff --git a/crypto/ecdsa/ecs_ossl.c b/crypto/ecdsa/ecs_ossl.c
index 6115df7407..16d4f59b9b 100644
--- a/crypto/ecdsa/ecs_ossl.c
+++ b/crypto/ecdsa/ecs_ossl.c
@@ -252,7 +252,6 @@ static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dgst_len,
{
int ok = 0, i;
BIGNUM *kinv = NULL, *s, *m = NULL, *tmp = NULL, *order = NULL;
- BIGNUM *blind = NULL, *blindm = NULL;
const BIGNUM *ckinv;
BN_CTX *ctx = NULL;
const EC_GROUP *group;
@@ -270,25 +269,14 @@ static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dgst_len,
}
ret = ECDSA_SIG_new();
- if (ret == NULL) {
+ if (!ret) {
ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_MALLOC_FAILURE);
return NULL;
}
s = ret->s;
- ctx = BN_CTX_new();
- if (ctx == NULL) {
- ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- BN_CTX_start(ctx);
- order = BN_CTX_get(ctx);
- tmp = BN_CTX_get(ctx);
- m = BN_CTX_get(ctx);
- blind = BN_CTX_get(ctx);
- blindm = BN_CTX_get(ctx);
- if (blindm == NULL) {
+ if ((ctx = BN_CTX_new()) == NULL || (order = BN_new()) == NULL ||
+ (tmp = BN_new()) == NULL || (m = BN_new()) == NULL) {
ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -327,70 +315,26 @@ static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dgst_len,
}
}
- /*
- * The normal signature calculation is:
- *
- * s := k^-1 * (m + r * priv_key) mod order
- *
- * We will blind this to protect against side channel attacks
- *
- * s := blind^-1 * k^-1 * (blind * m + blind * r * priv_key) mod order
- */
-
- /* Generate a blinding value */
- do {
- if (!BN_rand(blind, BN_num_bits(order) - 1, -1, 0))
- goto err;
- } while (BN_is_zero(blind));
- BN_set_flags(blind, BN_FLG_CONSTTIME);
- BN_set_flags(blindm, BN_FLG_CONSTTIME);
- BN_set_flags(tmp, BN_FLG_CONSTTIME);
-
- /* tmp := blind * priv_key * r mod order */
- if (!BN_mod_mul(tmp, blind, priv_key, order, ctx)) {
- ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
- goto err;
- }
- if (!BN_mod_mul(tmp, tmp, ret->r, order, ctx)) {
- ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
- goto err;
- }
-
- /* blindm := blind * m mod order */
- if (!BN_mod_mul(blindm, blind, m, order, ctx)) {
+ if (!BN_mod_mul(tmp, priv_key, ret->r, order, ctx)) {
ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
goto err;
}
-
- /* s : = (blind * priv_key * r) + (blind * m) mod order */
- if (!BN_mod_add_quick(s, tmp, blindm, order)) {
+ if (!BN_mod_add_quick(s, tmp, m, order)) {
ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
goto err;
}
-
- /* s := s * k^-1 mod order */
if (!BN_mod_mul(s, s, ckinv, order, ctx)) {
ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
goto err;
}
-
- /* s:= s * blind^-1 mod order */
- if (BN_mod_inverse(blind, blind, order, ctx) == NULL) {
- ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
- goto err;
- }
- if (!BN_mod_mul(s, s, blind, order, ctx)) {
- ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
- goto err;
- }
-
if (BN_is_zero(s)) {
/*
* if kinv and r have been supplied by the caller don't to
* generate new kinv and r values
*/
if (in_kinv != NULL && in_r != NULL) {
- ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ECDSA_R_NEED_NEW_SETUP_VALUES);
+ ECDSAerr(ECDSA_F_ECDSA_DO_SIGN,
+ ECDSA_R_NEED_NEW_SETUP_VALUES);
goto err;
}
} else
@@ -405,11 +349,15 @@ static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dgst_len,
ECDSA_SIG_free(ret);
ret = NULL;
}
- if (ctx != NULL) {
- BN_CTX_end(ctx);
+ if (ctx)
BN_CTX_free(ctx);
- }
- if (kinv != NULL)
+ if (m)
+ BN_clear_free(m);
+ if (tmp)
+ BN_clear_free(tmp);
+ if (order)
+ BN_free(order);
+ if (kinv)
BN_clear_free(kinv);
return ret;
}