Implement coordinate blinding for EC_POINT

This commit implements coordinate blinding, i.e., it randomizes the
representative of an elliptic curve point in its equivalence class, for
prime curves implemented through EC_GFp_simple_method,
EC_GFp_mont_method, and EC_GFp_nist_method.

This commit is derived from the patch
https://marc.info/?l=openssl-dev&m=131194808413635 by Billy Brumley.

Coordinate blinding is a generally useful side-channel countermeasure
and is (mostly) free. The function itself takes a few field
multiplicationss, but is usually only necessary at the beginning of a
scalar multiplication (as implemented in the patch). When used this way,
it makes the values that variables take (i.e., field elements in an
algorithm state) unpredictable.

For instance, this mitigates chosen EC point side-channel attacks for
settings such as ECDH and EC private key decryption, for the
aforementioned curves.

For EC_METHODs using different coordinate representations this commit
does nothing, but the corresponding coordinate blinding function can be
easily added in the future to extend these changes to such curves.

Co-authored-by: Nicola Tuveri <nic.tuv@gmail.com>
Co-authored-by: Billy Brumley <bbrumley@gmail.com>

Reviewed-by: Andy Polyakov <appro@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6501)
This commit is contained in:
Sohaib ul Hassan 2018-06-16 17:07:40 +03:00 committed by Matt Caswell
parent ddb634fe6f
commit f667820c16
14 changed files with 117 additions and 7 deletions

View file

@ -8,6 +8,11 @@
release branch. release branch.
Changes between 1.1.0h and 1.1.1 [xx XXX xxxx] Changes between 1.1.0h and 1.1.1 [xx XXX xxxx]
*) Add coordinate blinding for EC_POINT and implement projective
coordinate blinding for generic prime curves as a countermeasure to
chosen point SCA attacks.
[Sohaib ul Hassan, Nicola Tuveri, Billy Bob Brumley]
*) Add blinding to an ECDSA signature to protect against side channel attacks *) Add blinding to an ECDSA signature to protect against side channel attacks
discovered by Keegan Ryan (NCC Group). discovered by Keegan Ryan (NCC Group).
[Matt Caswell] [Matt Caswell]

View file

@ -64,7 +64,9 @@ const EC_METHOD *EC_GF2m_simple_method(void)
ec_key_simple_generate_public_key, ec_key_simple_generate_public_key,
0, /* keycopy */ 0, /* keycopy */
0, /* keyfinish */ 0, /* keyfinish */
ecdh_simple_compute_key ecdh_simple_compute_key,
0, /* field_inverse_mod_ord */
0 /* blind_coordinates */
}; };
return &ret; return &ret;

View file

@ -116,6 +116,8 @@ static const ERR_STRING_DATA EC_str_functs[] = {
"ec_GFp_nist_field_sqr"}, "ec_GFp_nist_field_sqr"},
{ERR_PACK(ERR_LIB_EC, EC_F_EC_GFP_NIST_GROUP_SET_CURVE, 0), {ERR_PACK(ERR_LIB_EC, EC_F_EC_GFP_NIST_GROUP_SET_CURVE, 0),
"ec_GFp_nist_group_set_curve"}, "ec_GFp_nist_group_set_curve"},
{ERR_PACK(ERR_LIB_EC, EC_F_EC_GFP_SIMPLE_BLIND_COORDINATES, 0),
"ec_GFp_simple_blind_coordinates"},
{ERR_PACK(ERR_LIB_EC, EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT, 0), {ERR_PACK(ERR_LIB_EC, EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT, 0),
"ec_GFp_simple_group_check_discriminant"}, "ec_GFp_simple_group_check_discriminant"},
{ERR_PACK(ERR_LIB_EC, EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE, 0), {ERR_PACK(ERR_LIB_EC, EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE, 0),

View file

@ -176,6 +176,7 @@ struct ec_method_st {
/* Inverse modulo order */ /* Inverse modulo order */
int (*field_inverse_mod_ord)(const EC_GROUP *, BIGNUM *r, BIGNUM *x, int (*field_inverse_mod_ord)(const EC_GROUP *, BIGNUM *r, BIGNUM *x,
BN_CTX *ctx); BN_CTX *ctx);
int (*blind_coordinates)(const EC_GROUP *group, EC_POINT *p, BN_CTX *ctx);
}; };
/* /*
@ -382,6 +383,8 @@ int ec_GFp_simple_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
const BIGNUM *b, BN_CTX *); const BIGNUM *b, BN_CTX *);
int ec_GFp_simple_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, int ec_GFp_simple_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
BN_CTX *); BN_CTX *);
int ec_GFp_simple_blind_coordinates(const EC_GROUP *group, EC_POINT *p,
BN_CTX *ctx);
/* method functions in ecp_mont.c */ /* method functions in ecp_mont.c */
int ec_GFp_mont_group_init(EC_GROUP *); int ec_GFp_mont_group_init(EC_GROUP *);
@ -635,3 +638,5 @@ void X25519_public_from_private(uint8_t out_public_value[32],
int EC_GROUP_do_inverse_ord(const EC_GROUP *group, BIGNUM *res, int EC_GROUP_do_inverse_ord(const EC_GROUP *group, BIGNUM *res,
BIGNUM *x, BN_CTX *ctx); BIGNUM *x, BN_CTX *ctx);
int ec_point_blind_coordinates(const EC_GROUP *group, EC_POINT *p, BN_CTX *ctx);

View file

@ -1025,3 +1025,21 @@ int EC_GROUP_do_inverse_ord(const EC_GROUP *group, BIGNUM *res,
else else
return 0; return 0;
} }
/*-
* Coordinate blinding for EC_POINT.
*
* The underlying EC_METHOD can optionally implement this function:
* underlying implementations should return 0 on errors, or 1 on
* success.
*
* This wrapper returns 1 in case the underlying EC_METHOD does not
* support coordinate blinding.
*/
int ec_point_blind_coordinates(const EC_GROUP *group, EC_POINT *p, BN_CTX *ctx)
{
if (group->meth->blind_coordinates == NULL)
return 1; /* ignore if not implemented */
return group->meth->blind_coordinates(group, p, ctx);
}

View file

@ -211,6 +211,17 @@ static int ec_mul_consttime(const EC_GROUP *group, EC_POINT *r,
|| (bn_wexpand(r->Z, group_top) == NULL)) || (bn_wexpand(r->Z, group_top) == NULL))
goto err; goto err;
/*-
* Apply coordinate blinding for EC_POINT.
*
* The underlying EC_METHOD can optionally implement this function:
* ec_point_blind_coordinates() returns 0 in case of errors or 1 on
* success or if coordinate blinding is not implemented for this
* group.
*/
if (!ec_point_blind_coordinates(group, s, ctx))
goto err;
/* top bit is a 1, in a fixed pos */ /* top bit is a 1, in a fixed pos */
if (!EC_POINT_copy(r, s)) if (!EC_POINT_copy(r, s))
goto err; goto err;

View file

@ -61,7 +61,9 @@ const EC_METHOD *EC_GFp_mont_method(void)
ec_key_simple_generate_public_key, ec_key_simple_generate_public_key,
0, /* keycopy */ 0, /* keycopy */
0, /* keyfinish */ 0, /* keyfinish */
ecdh_simple_compute_key ecdh_simple_compute_key,
0, /* field_inverse_mod_ord */
ec_GFp_simple_blind_coordinates
}; };
return &ret; return &ret;

View file

@ -63,7 +63,9 @@ const EC_METHOD *EC_GFp_nist_method(void)
ec_key_simple_generate_public_key, ec_key_simple_generate_public_key,
0, /* keycopy */ 0, /* keycopy */
0, /* keyfinish */ 0, /* keyfinish */
ecdh_simple_compute_key ecdh_simple_compute_key,
0, /* field_inverse_mod_ord */
ec_GFp_simple_blind_coordinates
}; };
return &ret; return &ret;

View file

@ -290,7 +290,9 @@ const EC_METHOD *EC_GFp_nistp224_method(void)
ec_key_simple_generate_public_key, ec_key_simple_generate_public_key,
0, /* keycopy */ 0, /* keycopy */
0, /* keyfinish */ 0, /* keyfinish */
ecdh_simple_compute_key ecdh_simple_compute_key,
0, /* field_inverse_mod_ord */
0 /* blind_coordinates */
}; };
return &ret; return &ret;

View file

@ -1658,7 +1658,9 @@ const EC_METHOD *EC_GFp_nistp521_method(void)
ec_key_simple_generate_public_key, ec_key_simple_generate_public_key,
0, /* keycopy */ 0, /* keycopy */
0, /* keyfinish */ 0, /* keyfinish */
ecdh_simple_compute_key ecdh_simple_compute_key,
0, /* field_inverse_mod_ord */
0 /* blind_coordinates */
}; };
return &ret; return &ret;

View file

@ -1730,7 +1730,8 @@ const EC_METHOD *EC_GFp_nistz256_method(void)
0, /* keycopy */ 0, /* keycopy */
0, /* keyfinish */ 0, /* keyfinish */
ecdh_simple_compute_key, ecdh_simple_compute_key,
ecp_nistz256_inv_mod_ord /* can be #define-d NULL */ ecp_nistz256_inv_mod_ord, /* can be #define-d NULL */
0 /* blind_coordinates */
}; };
return &ret; return &ret;

View file

@ -62,7 +62,9 @@ const EC_METHOD *EC_GFp_simple_method(void)
ec_key_simple_generate_public_key, ec_key_simple_generate_public_key,
0, /* keycopy */ 0, /* keycopy */
0, /* keyfinish */ 0, /* keyfinish */
ecdh_simple_compute_key ecdh_simple_compute_key,
0, /* field_inverse_mod_ord */
ec_GFp_simple_blind_coordinates
}; };
return &ret; return &ret;
@ -1363,3 +1365,57 @@ int ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
{ {
return BN_mod_sqr(r, a, group->field, ctx); return BN_mod_sqr(r, a, group->field, ctx);
} }
/*-
* Apply randomization of EC point projective coordinates:
*
* (X, Y ,Z ) = (lambda^2*X, lambda^3*Y, lambda*Z)
* lambda = [1,group->field)
*
*/
int ec_GFp_simple_blind_coordinates(const EC_GROUP *group, EC_POINT *p,
BN_CTX *ctx)
{
int ret = 0;
BIGNUM *lambda = NULL;
BIGNUM *temp = NULL;
BN_CTX_start(ctx);
lambda = BN_CTX_get(ctx);
temp = BN_CTX_get(ctx);
if (temp == NULL) {
ECerr(EC_F_EC_GFP_SIMPLE_BLIND_COORDINATES, ERR_R_MALLOC_FAILURE);
goto err;
}
/* make sure lambda is not zero */
do {
if (!BN_priv_rand_range(lambda, group->field)) {
ECerr(EC_F_EC_GFP_SIMPLE_BLIND_COORDINATES, ERR_R_BN_LIB);
goto err;
}
} while (BN_is_zero(lambda));
/* if field_encode defined convert between representations */
if (group->meth->field_encode != NULL
&& !group->meth->field_encode(group, lambda, lambda, ctx))
goto err;
if (!group->meth->field_mul(group, p->Z, p->Z, lambda, ctx))
goto err;
if (!group->meth->field_sqr(group, temp, lambda, ctx))
goto err;
if (!group->meth->field_mul(group, p->X, p->X, temp, ctx))
goto err;
if (!group->meth->field_mul(group, temp, temp, lambda, ctx))
goto err;
if (!group->meth->field_mul(group, p->Y, p->Y, temp, ctx))
goto err;
p->Z_is_one = 0;
ret = 1;
err:
BN_CTX_end(ctx);
return ret;
}

View file

@ -550,6 +550,7 @@ EC_F_EC_GFP_NISTP521_POINT_GET_AFFINE_COORDINATES:235:\
EC_F_EC_GFP_NIST_FIELD_MUL:200:ec_GFp_nist_field_mul EC_F_EC_GFP_NIST_FIELD_MUL:200:ec_GFp_nist_field_mul
EC_F_EC_GFP_NIST_FIELD_SQR:201:ec_GFp_nist_field_sqr EC_F_EC_GFP_NIST_FIELD_SQR:201:ec_GFp_nist_field_sqr
EC_F_EC_GFP_NIST_GROUP_SET_CURVE:202:ec_GFp_nist_group_set_curve EC_F_EC_GFP_NIST_GROUP_SET_CURVE:202:ec_GFp_nist_group_set_curve
EC_F_EC_GFP_SIMPLE_BLIND_COORDINATES:287:ec_GFp_simple_blind_coordinates
EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT:165:\ EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT:165:\
ec_GFp_simple_group_check_discriminant ec_GFp_simple_group_check_discriminant
EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE:166:ec_GFp_simple_group_set_curve EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE:166:ec_GFp_simple_group_set_curve

View file

@ -87,6 +87,7 @@ int ERR_load_EC_strings(void);
# define EC_F_EC_GFP_NIST_FIELD_MUL 200 # define EC_F_EC_GFP_NIST_FIELD_MUL 200
# define EC_F_EC_GFP_NIST_FIELD_SQR 201 # define EC_F_EC_GFP_NIST_FIELD_SQR 201
# define EC_F_EC_GFP_NIST_GROUP_SET_CURVE 202 # define EC_F_EC_GFP_NIST_GROUP_SET_CURVE 202
# define EC_F_EC_GFP_SIMPLE_BLIND_COORDINATES 287
# define EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT 165 # define EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT 165
# define EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE 166 # define EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE 166
# define EC_F_EC_GFP_SIMPLE_MAKE_AFFINE 102 # define EC_F_EC_GFP_SIMPLE_MAKE_AFFINE 102