Commit 09c11fe5 authored by Billy Brumley's avatar Billy Brumley Committed by Nicola Tuveri
Browse files

SCA hardening for mod. field inversion in EC_GROUP



This commit adds a dedicated function in `EC_METHOD` to access a modular
field inversion implementation suitable for the specifics of the
implemented curve, featuring SCA countermeasures.

The new pointer is defined as:
`int (*field_inv)(const EC_GROUP*, BIGNUM *r, const BIGNUM *a, BN_CTX*)`
and computes the multiplicative inverse of `a` in the underlying field,
storing the result in `r`.

Three implementations are included, each including specific SCA
countermeasures:
  - `ec_GFp_simple_field_inv()`, featuring SCA hardening through
    blinding.
  - `ec_GFp_mont_field_inv()`, featuring SCA hardening through Fermat's
    Little Theorem (FLT) inversion.
  - `ec_GF2m_simple_field_inv()`, that uses `BN_GF2m_mod_inv()` which
    already features SCA hardening through blinding.

From a security point of view, this also helps addressing a leakage
previously affecting conversions from projective to affine coordinates.

This commit also adds a new error reason code (i.e.,
`EC_R_CANNOT_INVERT`) to improve consistency between the three
implementations as all of them could fail for the same reason but
through different code paths resulting in inconsistent error stack
states.

Co-authored-by: default avatarNicola Tuveri <nic.tuv@gmail.com>

(cherry picked from commit e0033efc)

Reviewed-by: default avatarMatt Caswell <matt@openssl.org>
Reviewed-by: default avatarNicola Tuveri <nic.tuv@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/8263)
parent 68be523d
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -9,6 +9,12 @@
 Changes between 1.1.0j and 1.1.0k [xx XXX xxxx]
  *) Added SCA hardening for modular field inversion in EC_GROUP through
     a new dedicated field_inv() pointer in EC_METHOD.
     This also addresses a leakage affecting conversions from projective
     to affine coordinates.
     [Billy Bob Brumley, Nicola Tuveri]
  *) Fix a use after free bug in d2i_X509_PUBKEY when overwriting a
     re-used X509_PUBKEY object if the second PUBKEY is malformed.
     [Bernd Edlinger]
+78 −62
Original line number Diff line number Diff line
/*
 * Copyright 2002-2018 The OpenSSL Project Authors. All Rights Reserved.
 * Copyright 2002-2019 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
@@ -29,67 +29,6 @@

#ifndef OPENSSL_NO_EC2M

const EC_METHOD *EC_GF2m_simple_method(void)
{
    static const EC_METHOD ret = {
        EC_FLAGS_DEFAULT_OCT,
        NID_X9_62_characteristic_two_field,
        ec_GF2m_simple_group_init,
        ec_GF2m_simple_group_finish,
        ec_GF2m_simple_group_clear_finish,
        ec_GF2m_simple_group_copy,
        ec_GF2m_simple_group_set_curve,
        ec_GF2m_simple_group_get_curve,
        ec_GF2m_simple_group_get_degree,
        ec_group_simple_order_bits,
        ec_GF2m_simple_group_check_discriminant,
        ec_GF2m_simple_point_init,
        ec_GF2m_simple_point_finish,
        ec_GF2m_simple_point_clear_finish,
        ec_GF2m_simple_point_copy,
        ec_GF2m_simple_point_set_to_infinity,
        0 /* set_Jprojective_coordinates_GFp */ ,
        0 /* get_Jprojective_coordinates_GFp */ ,
        ec_GF2m_simple_point_set_affine_coordinates,
        ec_GF2m_simple_point_get_affine_coordinates,
        0, 0, 0,
        ec_GF2m_simple_add,
        ec_GF2m_simple_dbl,
        ec_GF2m_simple_invert,
        ec_GF2m_simple_is_at_infinity,
        ec_GF2m_simple_is_on_curve,
        ec_GF2m_simple_cmp,
        ec_GF2m_simple_make_affine,
        ec_GF2m_simple_points_make_affine,

        /*
         * the following three method functions are defined in ec2_mult.c
         */
        ec_GF2m_simple_mul,
        ec_GF2m_precompute_mult,
        ec_GF2m_have_precompute_mult,

        ec_GF2m_simple_field_mul,
        ec_GF2m_simple_field_sqr,
        ec_GF2m_simple_field_div,
        0 /* field_encode */ ,
        0 /* field_decode */ ,
        0,                      /* field_set_to_one */
        ec_key_simple_priv2oct,
        ec_key_simple_oct2priv,
        0, /* set private */
        ec_key_simple_generate_key,
        ec_key_simple_check_key,
        ec_key_simple_generate_public_key,
        0, /* keycopy */
        0, /* keyfinish */
        ecdh_simple_compute_key,
        0  /* blind_coordinates */
    };

    return &ret;
}

/*
 * Initialize a GF(2^m)-based EC_GROUP structure. Note that all other members
 * are handled by EC_GROUP_new.
@@ -757,4 +696,81 @@ int ec_GF2m_simple_field_div(const EC_GROUP *group, BIGNUM *r,
    return BN_GF2m_mod_div(r, a, b, group->field, ctx);
}

/*-
 * Computes the multiplicative inverse of a in GF(2^m), storing the result in r.
 * If a is zero (or equivalent), you'll get a EC_R_CANNOT_INVERT error.
 * SCA hardening is with blinding: BN_GF2m_mod_inv does that.
 */
static int ec_GF2m_simple_field_inv(const EC_GROUP *group, BIGNUM *r,
                                    const BIGNUM *a, BN_CTX *ctx)
{
    int ret;

    if (!(ret = BN_GF2m_mod_inv(r, a, group->field, ctx)))
        ECerr(EC_F_EC_GF2M_SIMPLE_FIELD_INV, EC_R_CANNOT_INVERT);
    return ret;
}

const EC_METHOD *EC_GF2m_simple_method(void)
{
    static const EC_METHOD ret = {
        EC_FLAGS_DEFAULT_OCT,
        NID_X9_62_characteristic_two_field,
        ec_GF2m_simple_group_init,
        ec_GF2m_simple_group_finish,
        ec_GF2m_simple_group_clear_finish,
        ec_GF2m_simple_group_copy,
        ec_GF2m_simple_group_set_curve,
        ec_GF2m_simple_group_get_curve,
        ec_GF2m_simple_group_get_degree,
        ec_group_simple_order_bits,
        ec_GF2m_simple_group_check_discriminant,
        ec_GF2m_simple_point_init,
        ec_GF2m_simple_point_finish,
        ec_GF2m_simple_point_clear_finish,
        ec_GF2m_simple_point_copy,
        ec_GF2m_simple_point_set_to_infinity,
        0 /* set_Jprojective_coordinates_GFp */ ,
        0 /* get_Jprojective_coordinates_GFp */ ,
        ec_GF2m_simple_point_set_affine_coordinates,
        ec_GF2m_simple_point_get_affine_coordinates,
        0, 0, 0,
        ec_GF2m_simple_add,
        ec_GF2m_simple_dbl,
        ec_GF2m_simple_invert,
        ec_GF2m_simple_is_at_infinity,
        ec_GF2m_simple_is_on_curve,
        ec_GF2m_simple_cmp,
        ec_GF2m_simple_make_affine,
        ec_GF2m_simple_points_make_affine,

        /*
         * the following three method functions are defined in ec2_mult.c
         */
        ec_GF2m_simple_mul,
        ec_GF2m_precompute_mult,
        ec_GF2m_have_precompute_mult,

        ec_GF2m_simple_field_mul,
        ec_GF2m_simple_field_sqr,
        ec_GF2m_simple_field_div,
        ec_GF2m_simple_field_inv,
        0 /* field_encode */ ,
        0 /* field_decode */ ,
        0,                      /* field_set_to_one */
        ec_key_simple_priv2oct,
        ec_key_simple_oct2priv,
        0, /* set private */
        ec_key_simple_generate_key,
        ec_key_simple_check_key,
        ec_key_simple_generate_public_key,
        0, /* keycopy */
        0, /* keyfinish */
        ecdh_simple_compute_key,
        0  /* blind_coordinates */
    };

    return &ret;
}

#endif
+5 −1
Original line number Diff line number Diff line
/*
 * Generated by util/mkerr.pl DO NOT EDIT
 * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
 * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
@@ -58,6 +58,7 @@ static ERR_STRING_DATA EC_str_functs[] = {
    {ERR_FUNC(EC_F_EC_ASN1_GROUP2FIELDID), "ec_asn1_group2fieldid"},
    {ERR_FUNC(EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY),
     "ec_GF2m_montgomery_point_multiply"},
    {ERR_FUNC(EC_F_EC_GF2M_SIMPLE_FIELD_INV), "ec_GF2m_simple_field_inv"},
    {ERR_FUNC(EC_F_EC_GF2M_SIMPLE_GROUP_CHECK_DISCRIMINANT),
     "ec_GF2m_simple_group_check_discriminant"},
    {ERR_FUNC(EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE),
@@ -72,6 +73,7 @@ static ERR_STRING_DATA EC_str_functs[] = {
     "ec_GF2m_simple_set_compressed_coordinates"},
    {ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_DECODE), "ec_GFp_mont_field_decode"},
    {ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_ENCODE), "ec_GFp_mont_field_encode"},
    {ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_INV), "ec_GFp_mont_field_inv"},
    {ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_MUL), "ec_GFp_mont_field_mul"},
    {ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_SET_TO_ONE),
     "ec_GFp_mont_field_set_to_one"},
@@ -99,6 +101,7 @@ static ERR_STRING_DATA EC_str_functs[] = {
     "ec_GFp_nist_group_set_curve"},
    {ERR_FUNC(EC_F_EC_GFP_SIMPLE_BLIND_COORDINATES),
     "ec_GFp_simple_blind_coordinates"},
    {ERR_FUNC(EC_F_EC_GFP_SIMPLE_FIELD_INV), "ec_GFp_simple_field_inv"},
    {ERR_FUNC(EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT),
     "ec_GFp_simple_group_check_discriminant"},
    {ERR_FUNC(EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE),
@@ -211,6 +214,7 @@ static ERR_STRING_DATA EC_str_reasons[] = {
    {ERR_REASON(EC_R_BAD_SIGNATURE), "bad signature"},
    {ERR_REASON(EC_R_BIGNUM_OUT_OF_RANGE), "bignum out of range"},
    {ERR_REASON(EC_R_BUFFER_TOO_SMALL), "buffer too small"},
    {ERR_REASON(EC_R_CANNOT_INVERT), "cannot invert"},
    {ERR_REASON(EC_R_COORDINATES_OUT_OF_RANGE), "coordinates out of range"},
    {ERR_REASON(EC_R_CURVE_DOES_NOT_SUPPORT_ECDH),
     "curve does not support ecdh"},
+12 −1
Original line number Diff line number Diff line
/*
 * Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
 * Copyright 2001-2019 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
@@ -150,6 +150,13 @@ struct ec_method_st {
    int (*field_sqr) (const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
    int (*field_div) (const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
                      const BIGNUM *b, BN_CTX *);
    /*-
     * 'field_inv' computes the multipicative inverse of a in the field,
     * storing the result in r.
     *
     * If 'a' is zero (or equivalent), you'll get an EC_R_CANNOT_INVERT error.
     */
    int (*field_inv) (const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
    /* e.g. to Montgomery */
    int (*field_encode) (const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
                         BN_CTX *);
@@ -376,6 +383,8 @@ int ec_GFp_simple_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
                            const BIGNUM *b, BN_CTX *);
int ec_GFp_simple_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
                            BN_CTX *);
int ec_GFp_simple_field_inv(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
                            BN_CTX *);
int ec_GFp_simple_blind_coordinates(const EC_GROUP *group, EC_POINT *p,
                                    BN_CTX *ctx);

@@ -390,6 +399,8 @@ int ec_GFp_mont_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
                          const BIGNUM *b, BN_CTX *);
int ec_GFp_mont_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
                          BN_CTX *);
int ec_GFp_mont_field_inv(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
                          BN_CTX *);
int ec_GFp_mont_field_encode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
                             BN_CTX *);
int ec_GFp_mont_field_decode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
+50 −1
Original line number Diff line number Diff line
/*
 * Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
 * Copyright 2001-2019 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
@@ -55,6 +55,7 @@ const EC_METHOD *EC_GFp_mont_method(void)
        ec_GFp_mont_field_mul,
        ec_GFp_mont_field_sqr,
        0 /* field_div */ ,
        ec_GFp_mont_field_inv,
        ec_GFp_mont_field_encode,
        ec_GFp_mont_field_decode,
        ec_GFp_mont_field_set_to_one,
@@ -207,6 +208,54 @@ int ec_GFp_mont_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
    return BN_mod_mul_montgomery(r, a, a, group->field_data1, ctx);
}

/*-
 * Computes the multiplicative inverse of a in GF(p), storing the result in r.
 * If a is zero (or equivalent), you'll get a EC_R_CANNOT_INVERT error.
 * We have a Mont structure, so SCA hardening is FLT inversion.
 */
int ec_GFp_mont_field_inv(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
                            BN_CTX *ctx)
{
    BIGNUM *e = NULL;
    BN_CTX *new_ctx = NULL;
    int ret = 0;

    if (group->field_data1 == NULL)
        return 0;

    if (ctx == NULL && (ctx = new_ctx = BN_CTX_secure_new()) == NULL)
        return 0;

    BN_CTX_start(ctx);
    if ((e = BN_CTX_get(ctx)) == NULL)
        goto err;

    /* Inverse in constant time with Fermats Little Theorem */
    if (!BN_set_word(e, 2))
        goto err;
    if (!BN_sub(e, group->field, e))
        goto err;
    /*-
     * Exponent e is public.
     * No need for scatter-gather or BN_FLG_CONSTTIME.
     */
    if (!BN_mod_exp_mont(r, a, e, group->field, ctx, group->field_data1))
        goto err;

    /* throw an error on zero */
    if (BN_is_zero(r)) {
        ECerr(EC_F_EC_GFP_MONT_FIELD_INV, EC_R_CANNOT_INVERT);
        goto err;
    }

    ret = 1;

  err:
    BN_CTX_end(ctx);
    BN_CTX_free(new_ctx);
    return ret;
}

int ec_GFp_mont_field_encode(const EC_GROUP *group, BIGNUM *r,
                             const BIGNUM *a, BN_CTX *ctx)
{
Loading