Add blinding to a DSA signature
authorMatt Caswell <matt@openssl.org>
Tue, 19 Jun 2018 14:07:02 +0000 (15:07 +0100)
committerMatt Caswell <matt@openssl.org>
Thu, 21 Jun 2018 09:24:31 +0000 (10:24 +0100)
This extends the recently added ECDSA signature blinding to blind DSA too.

This is based on side channel attacks demonstrated by Keegan Ryan (NCC
Group) for ECDSA which are likely to be able to be applied to DSA.

Normally, as in ECDSA, during signing the signer calculates:

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

In ECDSA, 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.

This commit also tweaks the previous ECDSA blinding so that blinding is
only removed at the last possible step.

Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6523)

CHANGES
crypto/dsa/dsa_ossl.c
crypto/ec/ecdsa_ossl.c

diff --git a/CHANGES b/CHANGES
index b749d9ed966e2fd0c5da074b2547fcc98beedf93..b16a1be7dda5ad4bba587c0d371d1f53f6b6e8b3 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -9,8 +9,8 @@
 
  Changes between 1.1.0h and 1.1.0i [xx XXX xxxx]
 
-  *) Add blinding to an ECDSA signature to protect against side channel attacks
-     discovered by Keegan Ryan (NCC Group).
+  *) Add blinding to ECDSA and DSA signatures to protect against side channel
+     attacks discovered by Keegan Ryan (NCC Group).
      [Matt Caswell]
 
   *) When unlocking a pass phrase protected PEM file or PKCS#8 container, we
index 7f48cf2e3326d3857a36ac424d296b4b81a84801..f60ce70370dca5c31f0bc00907af12054d968084 100644 (file)
@@ -61,19 +61,13 @@ const DSA_METHOD *DSA_OpenSSL(void)
 static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
 {
     BIGNUM *kinv = NULL;
-    BIGNUM *m;
-    BIGNUM *xr;
+    BIGNUM *m, *blind, *blindm, *tmp;
     BN_CTX *ctx = NULL;
     int reason = ERR_R_BN_LIB;
     DSA_SIG *ret = NULL;
     int rv = 0;
 
-    m = BN_new();
-    xr = BN_new();
-    if (m == NULL || xr == NULL)
-        goto err;
-
-    if (!dsa->p || !dsa->q || !dsa->g) {
+    if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL) {
         reason = DSA_R_MISSING_PARAMETERS;
         goto err;
     }
@@ -89,6 +83,13 @@ static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
     ctx = BN_CTX_new();
     if (ctx == NULL)
         goto err;
+    m = BN_CTX_get(ctx);
+    blind = BN_CTX_get(ctx);
+    blindm = BN_CTX_get(ctx);
+    tmp = BN_CTX_get(ctx);
+    if (tmp == NULL)
+        goto err;
+
  redo:
     if (!dsa_sign_setup(dsa, ctx, &kinv, &ret->r, dgst, dlen))
         goto err;
@@ -103,17 +104,50 @@ static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
     if (BN_bin2bn(dgst, dlen, m) == NULL)
         goto err;
 
-    /* Compute  s = inv(k) (m + xr) mod q */
-    if (!BN_mod_mul(xr, dsa->priv_key, ret->r, dsa->q, ctx))
-        goto err;               /* s = xr */
-    if (!BN_add(ret->s, xr, m))
-        goto err;               /* s = m + xr */
-    if (BN_cmp(ret->s, dsa->q) > 0)
-        if (!BN_sub(ret->s, ret->s, dsa->q))
+    /*
+     * The normal signature calculation is:
+     *
+     *   s := k^-1 * (m + r * priv_key) mod q
+     *
+     * We will blind this to protect against side channel attacks
+     *
+     *   s := blind^-1 * k^-1 * (blind * m + blind * r * priv_key) mod q
+     */
+
+    /* Generate a blinding value */
+    do {
+        if (!BN_rand(blind, BN_num_bits(dsa->q) - 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 q */
+    if (!BN_mod_mul(tmp, blind, dsa->priv_key, dsa->q, ctx))
+        goto err;
+    if (!BN_mod_mul(tmp, tmp, ret->r, dsa->q, ctx))
+        goto err;
+
+    /* blindm := blind * m mod q */
+    if (!BN_mod_mul(blindm, blind, m, dsa->q, ctx))
+        goto err;
+
+    /* s : = (blind * priv_key * r) + (blind * m) mod q */
+    if (!BN_mod_add_quick(ret->s, tmp, blindm, dsa->q))
+        goto err;
+
+    /* s := s * k^-1 mod q */
     if (!BN_mod_mul(ret->s, ret->s, kinv, dsa->q, ctx))
         goto err;
 
+    /* s:= s * blind^-1 mod q */
+    if (BN_mod_inverse(blind, blind, dsa->q, ctx) == NULL)
+        goto err;
+    if (!BN_mod_mul(ret->s, ret->s, blind, dsa->q, ctx))
+        goto err;
+
     /*
      * Redo if r or s is zero as required by FIPS 186-3: this is very
      * unlikely.
@@ -130,8 +164,6 @@ static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
         ret = NULL;
     }
     BN_CTX_free(ctx);
-    BN_clear_free(m);
-    BN_clear_free(xr);
     BN_clear_free(kinv);
     return ret;
 }
index 449be0e92a601bddc1a9616f899d4b4daaf32ce3..c103917e76af7bdb6e567feb6a8151728ab89a32 100644 (file)
@@ -302,7 +302,7 @@ ECDSA_SIG *ossl_ecdsa_sign_sig(const unsigned char *dgst, int dgst_len,
          *
          * We will blind this to protect against side channel attacks
          *
-         *   s := k^-1 * blind^-1 * (blind * m + blind * r * priv_key) mod order
+         *   s := blind^-1 * k^-1 * (blind * m + blind * r * priv_key) mod order
          */
 
         /* Generate a blinding value */
@@ -337,18 +337,18 @@ ECDSA_SIG *ossl_ecdsa_sign_sig(const unsigned char *dgst, int dgst_len,
             goto err;
         }
 
-        /* s:= s * blind^-1 mod order */
-        if (BN_mod_inverse(blind, blind, order, ctx) == NULL) {
+        /* s := s * k^-1 mod order */
+        if (!BN_mod_mul(s, s, ckinv, order, ctx)) {
             ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
             goto err;
         }
-        if (!BN_mod_mul(s, s, blind, order, ctx)) {
+
+        /* 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;
         }
-
-        /* s := s * k^-1 mod order */
-        if (!BN_mod_mul(s, s, ckinv, order, ctx)) {
+        if (!BN_mod_mul(s, s, blind, order, ctx)) {
             ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
             goto err;
         }