Skip to content

Commit 7c1709c

Browse files
bbbrumleyromen
authored andcommitted
[crypto/ec] for ECC parameters with NULL or zero cofactor, compute it
The cofactor argument to EC_GROUP_set_generator is optional, and SCA mitigations for ECC currently use it. So the library currently falls back to very old SCA-vulnerable code if the cofactor is not present. This PR allows EC_GROUP_set_generator to compute the cofactor for all curves of cryptographic interest. Steering scalar multiplication to more SCA-robust code. This issue affects persisted private keys in explicit parameter form, where the (optional) cofactor field is zero or absent. It also affects curves not built-in to the library, but constructed programatically with explicit parameters, then calling EC_GROUP_set_generator with a nonsensical value (NULL, zero). The very old scalar multiplication code is known to be vulnerable to local uarch attacks, outside of the OpenSSL threat model. New results suggest the code path is also vulnerable to traditional wall clock timing attacks. CVE-2019-1547 Reviewed-by: Nicola Tuveri <nic.tuv@gmail.com> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from #9795)
1 parent 207a564 commit 7c1709c

File tree

4 files changed

+105
-8
lines changed

4 files changed

+105
-8
lines changed

Diff for: CHANGES

+7-1
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,20 @@
99

1010
Changes between 1.1.0k and 1.1.0l [xx XXX xxxx]
1111

12+
*) Compute ECC cofactors if not provided during EC_GROUP construction. Before
13+
this change, EC_GROUP_set_generator would accept order and/or cofactor as
14+
NULL. After this change, only the cofactor parameter can be NULL. It also
15+
does some minimal sanity checks on the passed order.
16+
(CVE-2019-1547)
17+
[Billy Bob Brumley]
18+
1219
*) Use Windows installation paths in the mingw builds
1320

1421
Mingw isn't a POSIX environment per se, which means that Windows
1522
paths should be used for installation.
1623
(CVE-2019-1552)
1724
[Richard Levitte]
1825

19-
2026
Changes between 1.1.0j and 1.1.0k [28 May 2019]
2127

2228
*) Change the default RSA, DSA and DH size to 2048 bit instead of 1024.

Diff for: crypto/ec/ec_err.c

+1
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ static ERR_STRING_DATA EC_str_reasons[] = {
273273
{ERR_REASON(EC_R_SLOT_FULL), "slot full"},
274274
{ERR_REASON(EC_R_UNDEFINED_GENERATOR), "undefined generator"},
275275
{ERR_REASON(EC_R_UNDEFINED_ORDER), "undefined order"},
276+
{ERR_REASON(EC_R_UNKNOWN_COFACTOR), "unknown cofactor"},
276277
{ERR_REASON(EC_R_UNKNOWN_GROUP), "unknown group"},
277278
{ERR_REASON(EC_R_UNKNOWN_ORDER), "unknown order"},
278279
{ERR_REASON(EC_R_UNSUPPORTED_FIELD), "unsupported field"},

Diff for: crypto/ec/ec_lib.c

+96-7
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,67 @@ int EC_METHOD_get_field_type(const EC_METHOD *meth)
257257
return meth->field_type;
258258
}
259259

260+
/*-
261+
* Try computing cofactor from the generator order (n) and field cardinality (q).
262+
* This works for all curves of cryptographic interest.
263+
*
264+
* Hasse thm: q + 1 - 2*sqrt(q) <= n*h <= q + 1 + 2*sqrt(q)
265+
* h_min = (q + 1 - 2*sqrt(q))/n
266+
* h_max = (q + 1 + 2*sqrt(q))/n
267+
* h_max - h_min = 4*sqrt(q)/n
268+
* So if n > 4*sqrt(q) holds, there is only one possible value for h:
269+
* h = \lfloor (h_min + h_max)/2 \rceil = \lfloor (q + 1)/n \rceil
270+
*
271+
* Otherwise, zero cofactor and return success.
272+
*/
273+
static int ec_guess_cofactor(EC_GROUP *group) {
274+
int ret = 0;
275+
BN_CTX *ctx = NULL;
276+
BIGNUM *q = NULL;
277+
278+
/*-
279+
* If the cofactor is too large, we cannot guess it.
280+
* The RHS of below is a strict overestimate of lg(4 * sqrt(q))
281+
*/
282+
if (BN_num_bits(group->order) <= (BN_num_bits(group->field) + 1) / 2 + 3) {
283+
/* default to 0 */
284+
BN_zero(group->cofactor);
285+
/* return success */
286+
return 1;
287+
}
288+
289+
if ((ctx = BN_CTX_new()) == NULL)
290+
return 0;
291+
292+
BN_CTX_start(ctx);
293+
if ((q = BN_CTX_get(ctx)) == NULL)
294+
goto err;
295+
296+
/* set q = 2**m for binary fields; q = p otherwise */
297+
if (group->meth->field_type == NID_X9_62_characteristic_two_field) {
298+
BN_zero(q);
299+
if (!BN_set_bit(q, BN_num_bits(group->field) - 1))
300+
goto err;
301+
} else {
302+
if (!BN_copy(q, group->field))
303+
goto err;
304+
}
305+
306+
/* compute h = \lfloor (q + 1)/n \rceil = \lfloor (q + 1 + n/2)/n \rfloor */
307+
if (!BN_rshift1(group->cofactor, group->order) /* n/2 */
308+
|| !BN_add(group->cofactor, group->cofactor, q) /* q + n/2 */
309+
/* q + 1 + n/2 */
310+
|| !BN_add(group->cofactor, group->cofactor, BN_value_one())
311+
/* (q + 1 + n/2)/n */
312+
|| !BN_div(group->cofactor, NULL, group->cofactor, group->order, ctx))
313+
goto err;
314+
ret = 1;
315+
err:
316+
BN_CTX_end(ctx);
317+
BN_CTX_free(ctx);
318+
return ret;
319+
}
320+
260321
int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
261322
const BIGNUM *order, const BIGNUM *cofactor)
262323
{
@@ -265,6 +326,34 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
265326
return 0;
266327
}
267328

329+
/* require group->field >= 1 */
330+
if (group->field == NULL || BN_is_zero(group->field)
331+
|| BN_is_negative(group->field)) {
332+
ECerr(EC_F_EC_GROUP_SET_GENERATOR, EC_R_INVALID_FIELD);
333+
return 0;
334+
}
335+
336+
/*-
337+
* - require order >= 1
338+
* - enforce upper bound due to Hasse thm: order can be no more than one bit
339+
* longer than field cardinality
340+
*/
341+
if (order == NULL || BN_is_zero(order) || BN_is_negative(order)
342+
|| BN_num_bits(order) > BN_num_bits(group->field) + 1) {
343+
ECerr(EC_F_EC_GROUP_SET_GENERATOR, EC_R_INVALID_GROUP_ORDER);
344+
return 0;
345+
}
346+
347+
/*-
348+
* Unfortunately the cofactor is an optional field in many standards.
349+
* Internally, the lib uses 0 cofactor as a marker for "unknown cofactor".
350+
* So accept cofactor == NULL or cofactor >= 0.
351+
*/
352+
if (cofactor != NULL && BN_is_negative(cofactor)) {
353+
ECerr(EC_F_EC_GROUP_SET_GENERATOR, EC_R_UNKNOWN_COFACTOR);
354+
return 0;
355+
}
356+
268357
if (group->generator == NULL) {
269358
group->generator = EC_POINT_new(group);
270359
if (group->generator == NULL)
@@ -273,17 +362,17 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
273362
if (!EC_POINT_copy(group->generator, generator))
274363
return 0;
275364

276-
if (order != NULL) {
277-
if (!BN_copy(group->order, order))
278-
return 0;
279-
} else
280-
BN_zero(group->order);
365+
if (!BN_copy(group->order, order))
366+
return 0;
281367

282-
if (cofactor != NULL) {
368+
/* Either take the provided positive cofactor, or try to compute it */
369+
if (cofactor != NULL && !BN_is_zero(cofactor)) {
283370
if (!BN_copy(group->cofactor, cofactor))
284371
return 0;
285-
} else
372+
} else if (!ec_guess_cofactor(group)) {
286373
BN_zero(group->cofactor);
374+
return 0;
375+
}
287376

288377
/*
289378
* Some groups have an order with

Diff for: include/openssl/ec.h

+1
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,7 @@ int ERR_load_EC_strings(void);
15681568
# define EC_R_SLOT_FULL 108
15691569
# define EC_R_UNDEFINED_GENERATOR 113
15701570
# define EC_R_UNDEFINED_ORDER 128
1571+
# define EC_R_UNKNOWN_COFACTOR 164
15711572
# define EC_R_UNKNOWN_GROUP 129
15721573
# define EC_R_UNKNOWN_ORDER 114
15731574
# define EC_R_UNSUPPORTED_FIELD 131

0 commit comments

Comments
 (0)