Skip to content

Commit 2198be3

Browse files
committed
Fix for CVE-2014-0076
Fix for the attack described in the paper "Recovering OpenSSL ECDSA Nonces Using the FLUSH+RELOAD Cache Side-channel Attack" by Yuval Yarom and Naomi Benger. Details can be obtained from: http://eprint.iacr.org/2014/140 Thanks to Yuval Yarom and Naomi Benger for discovering this flaw and to Yuval Yarom for supplying a fix.
1 parent 6fe4984 commit 2198be3

File tree

4 files changed

+87
-12
lines changed

4 files changed

+87
-12
lines changed

CHANGES

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@
44

55
Changes between 1.0.0l and 1.0.0m [xx XXX xxxx]
66

7-
*)
7+
*) Fix for the attack described in the paper "Recovering OpenSSL
8+
ECDSA Nonces Using the FLUSH+RELOAD Cache Side-channel Attack"
9+
by Yuval Yarom and Naomi Benger. Details can be obtained from:
10+
http://eprint.iacr.org/2014/140
11+
12+
Thanks to Yuval Yarom and Naomi Benger for discovering this
13+
flaw and to Yuval Yarom for supplying a fix (CVE-2014-0076)
14+
[Yuval Yarom and Naomi Benger]
815

916
Changes between 1.0.0k and 1.0.0l [6 Jan 2014]
1017

crypto/bn/bn.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,8 @@ BIGNUM *BN_mod_inverse(BIGNUM *ret,
538538
BIGNUM *BN_mod_sqrt(BIGNUM *ret,
539539
const BIGNUM *a, const BIGNUM *n,BN_CTX *ctx);
540540

541+
void BN_consttime_swap(BN_ULONG swap, BIGNUM *a, BIGNUM *b, int nwords);
542+
541543
/* Deprecated versions */
542544
#ifndef OPENSSL_NO_DEPRECATED
543545
BIGNUM *BN_generate_prime(BIGNUM *ret,int bits,int safe,
@@ -759,11 +761,20 @@ int RAND_pseudo_bytes(unsigned char *buf,int num);
759761

760762
#define bn_fix_top(a) bn_check_top(a)
761763

764+
#define bn_check_size(bn, bits) bn_wcheck_size(bn, ((bits+BN_BITS2-1))/BN_BITS2)
765+
#define bn_wcheck_size(bn, words) \
766+
do { \
767+
const BIGNUM *_bnum2 = (bn); \
768+
assert(words <= (_bnum2)->dmax && words >= (_bnum2)->top); \
769+
} while(0)
770+
762771
#else /* !BN_DEBUG */
763772

764773
#define bn_pollute(a)
765774
#define bn_check_top(a)
766775
#define bn_fix_top(a) bn_correct_top(a)
776+
#define bn_check_size(bn, bits)
777+
#define bn_wcheck_size(bn, words)
767778

768779
#endif
769780

crypto/bn/bn_lib.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,3 +843,55 @@ int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b,
843843
}
844844
return bn_cmp_words(a,b,cl);
845845
}
846+
847+
/*
848+
* Constant-time conditional swap of a and b.
849+
* a and b are swapped if condition is not 0. The code assumes that at most one bit of condition is set.
850+
* nwords is the number of words to swap. The code assumes that at least nwords are allocated in both a and b,
851+
* and that no more than nwords are used by either a or b.
852+
* a and b cannot be the same number
853+
*/
854+
void BN_consttime_swap(BN_ULONG condition, BIGNUM *a, BIGNUM *b, int nwords)
855+
{
856+
BN_ULONG t;
857+
int i;
858+
859+
bn_wcheck_size(a, nwords);
860+
bn_wcheck_size(b, nwords);
861+
862+
assert(a != b);
863+
assert((condition & (condition - 1)) == 0);
864+
assert(sizeof(BN_ULONG) >= sizeof(int));
865+
866+
condition = ((condition - 1) >> (BN_BITS2 - 1)) - 1;
867+
868+
t = (a->top^b->top) & condition;
869+
a->top ^= t;
870+
b->top ^= t;
871+
872+
#define BN_CONSTTIME_SWAP(ind) \
873+
do { \
874+
t = (a->d[ind] ^ b->d[ind]) & condition; \
875+
a->d[ind] ^= t; \
876+
b->d[ind] ^= t; \
877+
} while (0)
878+
879+
880+
switch (nwords) {
881+
default:
882+
for (i = 10; i < nwords; i++)
883+
BN_CONSTTIME_SWAP(i);
884+
/* Fallthrough */
885+
case 10: BN_CONSTTIME_SWAP(9); /* Fallthrough */
886+
case 9: BN_CONSTTIME_SWAP(8); /* Fallthrough */
887+
case 8: BN_CONSTTIME_SWAP(7); /* Fallthrough */
888+
case 7: BN_CONSTTIME_SWAP(6); /* Fallthrough */
889+
case 6: BN_CONSTTIME_SWAP(5); /* Fallthrough */
890+
case 5: BN_CONSTTIME_SWAP(4); /* Fallthrough */
891+
case 4: BN_CONSTTIME_SWAP(3); /* Fallthrough */
892+
case 3: BN_CONSTTIME_SWAP(2); /* Fallthrough */
893+
case 2: BN_CONSTTIME_SWAP(1); /* Fallthrough */
894+
case 1: BN_CONSTTIME_SWAP(0);
895+
}
896+
#undef BN_CONSTTIME_SWAP
897+
}

crypto/ec/ec2_mult.c

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,15 @@ static int gf2m_Mxy(const EC_GROUP *group, const BIGNUM *x, const BIGNUM *y, BIG
206206
return ret;
207207
}
208208

209+
209210
/* Computes scalar*point and stores the result in r.
210211
* point can not equal r.
211-
* Uses algorithm 2P of
212+
* Uses a modified algorithm 2P of
212213
* Lopez, J. and Dahab, R. "Fast multiplication on elliptic curves over
213214
* GF(2^m) without precomputation" (CHES '99, LNCS 1717).
215+
*
216+
* To protect against side-channel attack the function uses constant time swap,
217+
* avoiding conditional branches.
214218
*/
215219
static int ec_GF2m_montgomery_point_multiply(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
216220
const EC_POINT *point, BN_CTX *ctx)
@@ -244,6 +248,11 @@ static int ec_GF2m_montgomery_point_multiply(const EC_GROUP *group, EC_POINT *r,
244248
x2 = &r->X;
245249
z2 = &r->Y;
246250

251+
bn_wexpand(x1, group->field.top);
252+
bn_wexpand(z1, group->field.top);
253+
bn_wexpand(x2, group->field.top);
254+
bn_wexpand(z2, group->field.top);
255+
247256
if (!BN_GF2m_mod_arr(x1, &point->X, group->poly)) goto err; /* x1 = x */
248257
if (!BN_one(z1)) goto err; /* z1 = 1 */
249258
if (!group->meth->field_sqr(group, z2, x1, ctx)) goto err; /* z2 = x1^2 = x^2 */
@@ -268,16 +277,12 @@ static int ec_GF2m_montgomery_point_multiply(const EC_GROUP *group, EC_POINT *r,
268277
word = scalar->d[i];
269278
while (mask)
270279
{
271-
if (word & mask)
272-
{
273-
if (!gf2m_Madd(group, &point->X, x1, z1, x2, z2, ctx)) goto err;
274-
if (!gf2m_Mdouble(group, x2, z2, ctx)) goto err;
275-
}
276-
else
277-
{
278-
if (!gf2m_Madd(group, &point->X, x2, z2, x1, z1, ctx)) goto err;
279-
if (!gf2m_Mdouble(group, x1, z1, ctx)) goto err;
280-
}
280+
BN_consttime_swap(word & mask, x1, x2, group->field.top);
281+
BN_consttime_swap(word & mask, z1, z2, group->field.top);
282+
if (!gf2m_Madd(group, &point->X, x2, z2, x1, z1, ctx)) goto err;
283+
if (!gf2m_Mdouble(group, x1, z1, ctx)) goto err;
284+
BN_consttime_swap(word & mask, x1, x2, group->field.top);
285+
BN_consttime_swap(word & mask, z1, z2, group->field.top);
281286
mask >>= 1;
282287
}
283288
mask = BN_TBIT;

0 commit comments

Comments
 (0)