Skip to content

Commit 774dddd

Browse files
sv3irygregkh
authored andcommitted
crypto: ecc - Fix carry overflow in vli multiplication
commit 27b536a upstream. The carry flag calculation fails when r01.m_high is saturated (0xFFFFFFFFFFFFFFFF) and addition of lower bits overflows. The condition (r01.m_high < product.m_high) doesn't handle the case where r01.m_high == product.m_high and an additional carry exists from lower-bit overflow. When commit 3c4b239 ("crypto: ecdh - Add ECDH software support") introduced crypto/ecc.c, it split the muladd() function in the micro-ecc library into separate mul_64_64() and add_128_128() helpers. It seems the check got lost in translation. Add proper handling for this boundary by accounting for the carry from the lower addition. Fixes: 3c4b239 ("crypto: ecdh - Add ECDH software support") Signed-off-by: Anastasia Tishchenko <sv3iry@gmail.com> Cc: stable@vger.kernel.org # v4.8+ Reviewed-by: Lukas Wunner <lukas@wunner.de> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent ac667f9 commit 774dddd

1 file changed

Lines changed: 20 additions & 11 deletions

File tree

crypto/ecc.c

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -402,14 +402,26 @@ static uint128_t mul_64_64(u64 left, u64 right)
402402
return result;
403403
}
404404

405-
static uint128_t add_128_128(uint128_t a, uint128_t b)
405+
/* Calculate addition with overflow checking. Returns true on wrap-around,
406+
* false otherwise.
407+
*/
408+
static bool check_add_128_128_overflow(uint128_t *result, uint128_t a,
409+
uint128_t b)
406410
{
407-
uint128_t result;
411+
bool carry;
408412

409-
result.m_low = a.m_low + b.m_low;
410-
result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low);
413+
result->m_low = a.m_low + b.m_low;
414+
carry = (result->m_low < a.m_low);
411415

412-
return result;
416+
result->m_high = a.m_high + b.m_high + carry;
417+
418+
/* Using constant-time bitwise arithmetic to prevent timing
419+
* side-channels.
420+
*/
421+
carry = (result->m_high < a.m_high) |
422+
((result->m_high == a.m_high) & carry);
423+
424+
return carry;
413425
}
414426

415427
static void vli_mult(u64 *result, const u64 *left, const u64 *right,
@@ -434,9 +446,7 @@ static void vli_mult(u64 *result, const u64 *left, const u64 *right,
434446
uint128_t product;
435447

436448
product = mul_64_64(left[i], right[k - i]);
437-
438-
r01 = add_128_128(r01, product);
439-
r2 += (r01.m_high < product.m_high);
449+
r2 += check_add_128_128_overflow(&r01, r01, product);
440450
}
441451

442452
result[k] = r01.m_low;
@@ -459,7 +469,7 @@ static void vli_umult(u64 *result, const u64 *left, u32 right,
459469
uint128_t product;
460470

461471
product = mul_64_64(left[k], right);
462-
r01 = add_128_128(r01, product);
472+
check_add_128_128_overflow(&r01, r01, product);
463473
/* no carry */
464474
result[k] = r01.m_low;
465475
r01.m_low = r01.m_high;
@@ -496,8 +506,7 @@ static void vli_square(u64 *result, const u64 *left, unsigned int ndigits)
496506
product.m_low <<= 1;
497507
}
498508

499-
r01 = add_128_128(r01, product);
500-
r2 += (r01.m_high < product.m_high);
509+
r2 += check_add_128_128_overflow(&r01, r01, product);
501510
}
502511

503512
result[k] = r01.m_low;

0 commit comments

Comments
 (0)