Commit a3e9d5aa authored by Matt Caswell's avatar Matt Caswell
Browse files

Add blinding to an ECDSA signature



Keegan Ryan (NCC Group) has demonstrated a side channel attack on an
ECDSA signature operation. During signing the signer calculates:

s:= k^-1 * (m + r * priv_key) mod order

The addition operation above provides a sufficient signal for a
flush+reload attack to derive the private key given sufficient signature
operations.

As a mitigation (based on a suggestion from Keegan) we add blinding to
the operation so that:

s := k^-1 * blind^-1 (blind * m + blind * r * priv_key) mod order

Since this attack is a localhost side channel only no CVE is assigned.

Reviewed-by: default avatarRich Salz <rsalz@openssl.org>
parent d3273ef6
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -8,6 +8,10 @@
 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 blinding to an ECDSA signature to protect against side channel attacks
     discovered by Keegan Ryan (NCC Group).
     [Matt Caswell]
  *) Enforce checking in the pkeyutl command line app to ensure that the input
  *) Enforce checking in the pkeyutl command line app to ensure that the input
     length does not exceed the maximum supported digest length when performing
     length does not exceed the maximum supported digest length when performing
     a sign, verify or verifyrecover operation.
     a sign, verify or verifyrecover operation.
+63 −7
Original line number Original line Diff line number Diff line
@@ -196,7 +196,8 @@ ECDSA_SIG *ossl_ecdsa_sign_sig(const unsigned char *dgst, int dgst_len,
                               EC_KEY *eckey)
                               EC_KEY *eckey)
{
{
    int ok = 0, i;
    int ok = 0, i;
    BIGNUM *kinv = NULL, *s, *m = NULL, *tmp = NULL;
    BIGNUM *kinv = NULL, *s, *m = NULL, *tmp = NULL, *blind = NULL;
    BIGNUM *blindm = NULL;
    const BIGNUM *order, *ckinv;
    const BIGNUM *order, *ckinv;
    BN_CTX *ctx = NULL;
    BN_CTX *ctx = NULL;
    const EC_GROUP *group;
    const EC_GROUP *group;
@@ -229,8 +230,18 @@ ECDSA_SIG *ossl_ecdsa_sign_sig(const unsigned char *dgst, int dgst_len,
    }
    }
    s = ret->s;
    s = ret->s;


    if ((ctx = BN_CTX_new()) == NULL ||
    ctx = BN_CTX_secure_new();
        (tmp = BN_new()) == NULL || (m = BN_new()) == NULL) {
    if (ctx == NULL) {
        ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_MALLOC_FAILURE);
        goto err;
    }

    BN_CTX_start(ctx);
    tmp = BN_CTX_get(ctx);
    m = BN_CTX_get(ctx);
    blind = BN_CTX_get(ctx);
    blindm = BN_CTX_get(ctx);
    if (blindm == NULL) {
        ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_MALLOC_FAILURE);
        ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_MALLOC_FAILURE);
        goto err;
        goto err;
    }
    }
@@ -270,18 +281,64 @@ ECDSA_SIG *ossl_ecdsa_sign_sig(const unsigned char *dgst, int dgst_len,
            }
            }
        }
        }


        if (!BN_mod_mul(tmp, priv_key, ret->r, order, ctx)) {
        /*
         * The normal signature calculation is:
         *
         *   s := k^-1 * (m + r * priv_key) mod order
         *
         * We will blind this to protect against side channel attacks
         *
         *   s := k^-1 * blind^-1 * (blind * m + blind * r * priv_key) mod order
         */

        /* Generate a blinding value */
        do {
            if (!BN_priv_rand(blind, BN_num_bits(order) - 1,
                              BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY))
                goto err;
        } while (BN_is_zero(blind));
        BN_set_flags(blind, BN_FLG_CONSTTIME);
        BN_set_flags(blindm, BN_FLG_CONSTTIME);
        BN_set_flags(tmp, BN_FLG_CONSTTIME);

        /* tmp := blind * priv_key * r mod order */
        if (!BN_mod_mul(tmp, blind, priv_key, order, ctx)) {
            ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
            goto err;
        }
        if (!BN_mod_mul(tmp, tmp, ret->r, order, ctx)) {
            ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
            goto err;
        }

        /* blindm := blind * m mod order */
        if (!BN_mod_mul(blindm, blind, m, order, ctx)) {
            ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
            ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
            goto err;
            goto err;
        }
        }
        if (!BN_mod_add_quick(s, tmp, m, order)) {

        /* s : = (blind * priv_key * r) + (blind * m) mod order */
        if (!BN_mod_add_quick(s, tmp, blindm, order)) {
            ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
            ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
            goto err;
            goto err;
        }
        }

        /* s:= s * blind^-1 mod order */
        if (BN_mod_inverse(blind, blind, order, ctx) == NULL) {
            ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
            goto err;
        }
        if (!BN_mod_mul(s, s, blind, order, ctx)) {
            ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
            goto err;
        }

        /* s := s * k^-1 mod order */
        if (!BN_mod_mul(s, s, ckinv, order, ctx)) {
        if (!BN_mod_mul(s, s, ckinv, order, ctx)) {
            ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
            ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
            goto err;
            goto err;
        }
        }

        if (BN_is_zero(s)) {
        if (BN_is_zero(s)) {
            /*
            /*
             * if kinv and r have been supplied by the caller, don't
             * if kinv and r have been supplied by the caller, don't
@@ -303,9 +360,8 @@ ECDSA_SIG *ossl_ecdsa_sign_sig(const unsigned char *dgst, int dgst_len,
        ECDSA_SIG_free(ret);
        ECDSA_SIG_free(ret);
        ret = NULL;
        ret = NULL;
    }
    }
    BN_CTX_end(ctx);
    BN_CTX_free(ctx);
    BN_CTX_free(ctx);
    BN_clear_free(m);
    BN_clear_free(tmp);
    BN_clear_free(kinv);
    BN_clear_free(kinv);
    return ret;
    return ret;
}
}