From 7f9822a48213dd2feca845dbbb6bcb8beb9550de Mon Sep 17 00:00:00 2001
From: Matt Caswell <matt@openssl.org>
Date: Tue, 19 Jun 2018 15:07:02 +0100
Subject: [PATCH] Add blinding to a DSA signature

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/6522)
---
 CHANGES                |  4 +--
 crypto/dsa/dsa_ossl.c  | 66 +++++++++++++++++++++++++++++++++++++-------------
 crypto/ec/ecdsa_ossl.c | 14 +++++------
 3 files changed, 58 insertions(+), 26 deletions(-)

Index: openssl-1.1.0h/crypto/dsa/dsa_ossl.c
===================================================================
--- openssl-1.1.0h.orig/crypto/dsa/dsa_ossl.c
+++ openssl-1.1.0h/crypto/dsa/dsa_ossl.c
@@ -64,8 +64,7 @@ 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;
@@ -84,12 +83,7 @@ static DSA_SIG *dsa_do_sign(const unsign
     }
 #endif
 
-    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;
     }
@@ -105,6 +99,13 @@ static DSA_SIG *dsa_do_sign(const unsign
     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;
@@ -119,17 +120,50 @@ static DSA_SIG *dsa_do_sign(const unsign
     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.
@@ -146,8 +180,6 @@ static DSA_SIG *dsa_do_sign(const unsign
         ret = NULL;
     }
     BN_CTX_free(ctx);
-    BN_clear_free(m);
-    BN_clear_free(xr);
     BN_clear_free(kinv);
     return ret;
 }
Index: openssl-1.1.0h/crypto/ec/ecdsa_ossl.c
===================================================================
--- openssl-1.1.0h.orig/crypto/ec/ecdsa_ossl.c
+++ openssl-1.1.0h/crypto/ec/ecdsa_ossl.c
@@ -313,7 +313,7 @@ ECDSA_SIG *ossl_ecdsa_sign_sig(const uns
          *
          * 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 */
@@ -348,18 +348,18 @@ ECDSA_SIG *ossl_ecdsa_sign_sig(const uns
             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;
         }
