From 41d23d435221411b4d70c08b6c5424d0afcf4c19 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>
Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6524)
---
 CHANGES                 |  4 +--
 crypto/dsa/dsa_ossl.c   | 73 +++++++++++++++++++++++++++++++++++--------------
 crypto/ecdsa/ecs_ossl.c | 14 +++++-----
 3 files changed, 61 insertions(+), 30 deletions(-)

Index: openssl-1.0.1i/crypto/dsa/dsa_ossl.c
===================================================================
--- openssl-1.0.1i.orig/crypto/dsa/dsa_ossl.c
+++ openssl-1.0.1i/crypto/dsa/dsa_ossl.c
@@ -5,21 +5,21 @@
  * This package is an SSL implementation written
  * by Eric Young (eay@cryptsoft.com).
  * The implementation was written so as to conform with Netscapes SSL.
- * 
+ *
  * This library is free for commercial and non-commercial use as long as
  * the following conditions are aheared to.  The following conditions
  * apply to all code found in this distribution, be it the RC4, RSA,
  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
  * included with this distribution is covered by the same copyright terms
  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- * 
+ *
  * Copyright remains Eric Young's, and as such any Copyright notices in
  * the code are not to be removed.
  * If this package is used in a product, Eric Young should be given attribution
  * as the author of the parts of the library used.
  * This can be in the form of a textual message at program startup or
  * in documentation (online or textual) provided with the package.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -34,10 +34,10 @@
  *     Eric Young (eay@cryptsoft.com)"
  *    The word 'cryptographic' can be left out if the rouines from the library
  *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from 
+ * 4. If you include any Windows specific code (or a derivative thereof) from
  *    the apps directory (application code) you must include an acknowledgement:
  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -49,7 +49,7 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- * 
+ *
  * The licence and distribution terms for any publically available version or
  * derivative of this code cannot be changed.  i.e. this code cannot simply be
  * copied and put under another distribution licence
@@ -94,7 +94,7 @@ NULL
 /* These macro wrappers replace attempts to use the dsa_mod_exp() and
  * bn_mod_exp() handlers in the DSA_METHOD structure. We avoid the problem of
  * having a the macro work as an expression by bundling an "err_instr". So;
- * 
+ *
  *     if (!dsa->meth->bn_mod_exp(dsa, r,dsa->g,&k,dsa->p,ctx,
  *                 dsa->method_mont_p)) goto err;
  *
@@ -134,8 +134,7 @@ const DSA_METHOD *DSA_OpenSSL(void)
 static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
 	{
 	BIGNUM *kinv=NULL,*r=NULL,*s=NULL;
-	BIGNUM m;
-	BIGNUM xr;
+	BIGNUM *m, *blind, *blindm, *tmp;
 	BN_CTX *ctx=NULL;
 	int reason=ERR_R_BN_LIB;
 	DSA_SIG *ret=NULL;
@@ -148,7 +147,7 @@ static DSA_SIG *dsa_do_sign(const unsign
 	    return NULL;
 	    }
 
-	if (FIPS_mode() && !(dsa->flags & DSA_FLAG_NON_FIPS_ALLOW) 
+	if (FIPS_mode() && !(dsa->flags & DSA_FLAG_NON_FIPS_ALLOW)
 		&& (BN_num_bits(dsa->p) < OPENSSL_DSA_FIPS_MIN_MODULUS_BITS))
 		{
 		DSAerr(DSA_F_DSA_DO_SIGN, DSA_R_KEY_SIZE_TOO_SMALL);
@@ -156,10 +155,7 @@ static DSA_SIG *dsa_do_sign(const unsign
 		}
 #endif
 
-	BN_init(&m);
-	BN_init(&xr);
-
-	if (!dsa->p || !dsa->q || !dsa->g)
+	if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL)
 		{
 		reason=DSA_R_MISSING_PARAMETERS;
 		goto err;
@@ -169,6 +165,12 @@ static DSA_SIG *dsa_do_sign(const unsign
 	if (s == NULL) goto err;
 	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->kinv == NULL) || (dsa->r == NULL))
 		{
@@ -183,24 +185,57 @@ redo:
 		noredo = 1;
 		}
 
-	
+
 	if (dlen > BN_num_bytes(dsa->q))
 		/* if the digest length is greater than the size of q use the
 		 * BN_num_bits(dsa->q) leftmost bits of the digest, see
 		 * fips 186-3, 4.2 */
 		dlen = BN_num_bytes(dsa->q);
-	if (BN_bin2bn(dgst,dlen,&m) == NULL)
+	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,r,dsa->q,ctx)) goto err;/* s = xr */
-	if (!BN_add(s, &xr, &m)) goto err;		/* s = m + xr */
-	if (BN_cmp(s,dsa->q) > 0)
-		if (!BN_sub(s,s,dsa->q)) goto err;
+	/*
+	 * 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, -1, 0))
+	        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, 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(s, tmp, blindm, dsa->q))
+       goto err;
+
+  /* s := s * k^-1 mod q */
 	if (!BN_mod_mul(s,s,kinv,dsa->q,ctx)) goto err;
 
-	ret=DSA_SIG_new();
-	if (ret == NULL) goto err;
+  /* s:= s * blind^-1 mod q */
+  if (BN_mod_inverse(blind, blind, dsa->q, ctx) == NULL)
+     goto err;
+if (!BN_mod_mul(s, s, blind, dsa->q, ctx))
+    goto err;
+
 	/* Redo if r or s is zero as required by FIPS 186-3: this is
 	 * very unlikely.
 	 */
@@ -213,9 +248,11 @@ redo:
 			}
 		goto redo;
 		}
+	ret=DSA_SIG_new();
+	if (ret == NULL) goto err;
 	ret->r = r;
 	ret->s = s;
-	
+
 err:
 	if (!ret)
 		{
@@ -223,11 +260,8 @@ err:
 		BN_free(r);
 		BN_free(s);
 		}
-	if (ctx != NULL) BN_CTX_free(ctx);
-	BN_clear_free(&m);
-	BN_clear_free(&xr);
-	if (kinv != NULL) /* dsa->kinv is NULL now if we used it */
-	    BN_clear_free(kinv);
+	BN_CTX_free(ctx);
+	BN_clear_free(kinv);
 	return(ret);
 	}
 
@@ -351,7 +385,7 @@ static int dsa_do_verify(const unsigned
 	    return -1;
 	    }
 
-	if (FIPS_mode() && !(dsa->flags & DSA_FLAG_NON_FIPS_ALLOW) 
+	if (FIPS_mode() && !(dsa->flags & DSA_FLAG_NON_FIPS_ALLOW)
 		&& (BN_num_bits(dsa->p) < OPENSSL_DSA_FIPS_MIN_MODULUS_BITS))
 		{
 		DSAerr(DSA_F_DSA_DO_VERIFY, DSA_R_KEY_SIZE_TOO_SMALL);
@@ -446,4 +480,3 @@ static int dsa_finish(DSA *dsa)
 		BN_MONT_CTX_free(dsa->method_mont_p);
 	return(1);
 }
-
Index: openssl-1.0.1i/crypto/ecdsa/ecs_ossl.c
===================================================================
--- openssl-1.0.1i.orig/crypto/ecdsa/ecs_ossl.c
+++ openssl-1.0.1i/crypto/ecdsa/ecs_ossl.c
@@ -255,7 +255,7 @@ static ECDSA_SIG *ecdsa_do_sign(const un
 	}
 
 	ret = ECDSA_SIG_new();
-	if (!ret)
+	if (ret == NULL)
 	{
 		ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_MALLOC_FAILURE);
 		return NULL;
