File openssl-CVE-2016-0702.patch of Package compat-openssl098.14113

From d7a854c055ff22fb7da80c3b0e7cb08d248591d0 Mon Sep 17 00:00:00 2001
From: Andy Polyakov <appro@openssl.org>
Date: Tue, 26 Jan 2016 11:34:41 +0100
Subject: [PATCH] bn/bn_exp.c: constant-time MOD_EXP_CTIME_COPY_FROM_PREBUF.

Performance penalty varies from platform to platform, and even
key length. For rsa2048 sign it was observed to reach almost 10%.

CVE-2016-0702

Reviewed-by: Richard Levitte <levitte@openssl.org>
---
 crypto/bn/bn_exp.c | 75 +++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 57 insertions(+), 18 deletions(-)

Index: openssl-0.9.8j/crypto/bn/bn_exp.c
===================================================================
--- openssl-0.9.8j.orig/crypto/bn/bn_exp.c	2016-04-29 14:04:43.807285727 +0200
+++ openssl-0.9.8j/crypto/bn/bn_exp.c	2016-04-29 14:04:47.714344454 +0200
@@ -111,6 +111,7 @@
 
 
 #include "cryptlib.h"
+#include "constant_time_locl.h"
 #include "bn_lcl.h"
 
 /* maximum precomputation table size for *variable* sliding windows */
@@ -521,9 +522,11 @@ err:
  * as cache lines are concerned.  The following functions are used to transfer a BIGNUM
  * from/to that table. */
 
-static int MOD_EXP_CTIME_COPY_TO_PREBUF(BIGNUM *b, int top, unsigned char *buf, int idx, int width)
+static int MOD_EXP_CTIME_COPY_TO_PREBUF(BIGNUM *b, int top, unsigned char *buf, int idx, int window)
 	{
-	size_t i, j;
+	int i, j;
+	int width = 1 << window;
+	BN_ULONG *table = (BN_ULONG *)buf;
 
 	if (bn_wexpand(b, top) == NULL)
 		return 0;
@@ -532,26 +535,60 @@ static int MOD_EXP_CTIME_COPY_TO_PREBUF(
 		b->d[b->top++] = 0;
 		}
 	
-	for (i = 0, j=idx; i < top * sizeof b->d[0]; i++, j+=width)
-		{
-		buf[j] = ((unsigned char*)b->d)[i];
+	for (i = 0, j = idx; i < top; i++, j += width) {
+		table[j] = b->d[i];
 		}
 
 	bn_correct_top(b);
 	return 1;
 	}
 
-static int MOD_EXP_CTIME_COPY_FROM_PREBUF(BIGNUM *b, int top, unsigned char *buf, int idx, int width)
+static int MOD_EXP_CTIME_COPY_FROM_PREBUF(BIGNUM *b, int top, unsigned char *buf, int idx, int window)
 	{
-	size_t i, j;
+	int i, j;
+	int width = 1 << window;
+	volatile BN_ULONG *table = (volatile BN_ULONG *)buf;
 
 	if (bn_wexpand(b, top) == NULL)
 		return 0;
 
-	for (i=0, j=idx; i < top * sizeof b->d[0]; i++, j+=width)
-		{
-		((unsigned char*)b->d)[i] = buf[j];
-		}
+    if (window <= 3) {
+        for (i = 0; i < top; i++, table += width) {
+            BN_ULONG acc = 0;
+
+            for (j = 0; j < width; j++) {
+                acc |= table[j] &
+                       ((BN_ULONG)0 - (constant_time_eq_int(j,idx)&1));
+            }
+
+            b->d[i] = acc;
+        }
+    } else {
+        int xstride = 1 << (window - 2);
+        BN_ULONG y0, y1, y2, y3;
+
+        i = idx >> (window - 2);        /* equivalent of idx / xstride */
+        idx &= xstride - 1;             /* equivalent of idx % xstride */
+
+        y0 = (BN_ULONG)0 - (constant_time_eq_int(i,0)&1);
+        y1 = (BN_ULONG)0 - (constant_time_eq_int(i,1)&1);
+        y2 = (BN_ULONG)0 - (constant_time_eq_int(i,2)&1);
+        y3 = (BN_ULONG)0 - (constant_time_eq_int(i,3)&1);
+
+        for (i = 0; i < top; i++, table += width) {
+            BN_ULONG acc = 0;
+
+            for (j = 0; j < xstride; j++) {
+                acc |= ( (table[j + 0 * xstride] & y0) |
+                         (table[j + 1 * xstride] & y1) |
+                         (table[j + 2 * xstride] & y2) |
+                         (table[j + 3 * xstride] & y3) )
+                       & ((BN_ULONG)0 - (constant_time_eq_int(j,idx)&1));
+            }
+
+            b->d[i] = acc;
+        }
+     }
 
 	b->top = top;
 	bn_correct_top(b);
@@ -635,7 +672,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr
 	 * once each for a^0 and intermediate result.
 	 */
  	if (!BN_to_montgomery(r,BN_value_one(),mont,ctx)) goto err;
-	if (!MOD_EXP_CTIME_COPY_TO_PREBUF(r, top, powerbuf, 0, numPowers)) goto err;
+	if (!MOD_EXP_CTIME_COPY_TO_PREBUF(r, top, powerbuf, 0, window)) goto err;
 
 	/* Initialize computeTemp as a^1 with montgomery precalcs */
 	computeTemp = BN_CTX_get(ctx);
@@ -652,7 +689,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr
 		aa=a;
 	if (!BN_to_montgomery(am,aa,mont,ctx)) goto err;
 	if (!BN_copy(computeTemp, am)) goto err;
-	if (!MOD_EXP_CTIME_COPY_TO_PREBUF(am, top, powerbuf, 1, numPowers)) goto err;
+	if (!MOD_EXP_CTIME_COPY_TO_PREBUF(am, top, powerbuf, 1, window)) goto err;
 
 	/* If the window size is greater than 1, then calculate
 	 * val[i=2..2^winsize-1]. Powers are computed as a*a^(i-1)
@@ -666,7 +703,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr
 			/* Calculate a^i = a^(i-1) * a */
 			if (!BN_mod_mul_montgomery(computeTemp,am,computeTemp,mont,ctx))
 				goto err;
-			if (!MOD_EXP_CTIME_COPY_TO_PREBUF(computeTemp, top, powerbuf, i, numPowers)) goto err;
+			if (!MOD_EXP_CTIME_COPY_TO_PREBUF(computeTemp, top, powerbuf, i, window)) goto err;
 			}
 		}
 
@@ -699,7 +736,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr
   			}
  		
 		/* Fetch the appropriate pre-computed value from the pre-buf */
-		if (!MOD_EXP_CTIME_COPY_FROM_PREBUF(computeTemp, top, powerbuf, wvalue, numPowers)) goto err;
+		if (!MOD_EXP_CTIME_COPY_FROM_PREBUF(computeTemp, top, powerbuf, wvalue, window)) goto err;
 
  		/* Multiply the result into the intermediate result */
  		if (!BN_mod_mul_montgomery(r,r,computeTemp,mont,ctx)) goto err;
Index: openssl-0.9.8j/crypto/constant_time_locl.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ openssl-0.9.8j/crypto/constant_time_locl.h	2016-04-29 14:05:52.974325511 +0200
@@ -0,0 +1,211 @@
+/* crypto/constant_time_locl.h */
+/*-
+ * Utilities for constant-time cryptography.
+ *
+ * Author: Emilia Kasper (emilia@openssl.org)
+ * Based on previous work by Bodo Moeller, Emilia Kasper, Adam Langley
+ * (Google).
+ * ====================================================================
+ * Copyright (c) 2014 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     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
+ *    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
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_CONSTANT_TIME_LOCL_H
+# define HEADER_CONSTANT_TIME_LOCL_H
+
+# include "e_os.h"              /* For 'inline' */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-
+ * The boolean methods return a bitmask of all ones (0xff...f) for true
+ * and 0 for false. This is useful for choosing a value based on the result
+ * of a conditional in constant time. For example,
+ *
+ * if (a < b) {
+ *   c = a;
+ * } else {
+ *   c = b;
+ * }
+ *
+ * can be written as
+ *
+ * unsigned int lt = constant_time_lt(a, b);
+ * c = constant_time_select(lt, a, b);
+ */
+
+/*
+ * Returns the given value with the MSB copied to all the other
+ * bits. Uses the fact that arithmetic shift shifts-in the sign bit.
+ * However, this is not ensured by the C standard so you may need to
+ * replace this with something else on odd CPUs.
+ */
+static inline unsigned int constant_time_msb(unsigned int a);
+
+/*
+ * Returns 0xff..f if a < b and 0 otherwise.
+ */
+static inline unsigned int constant_time_lt(unsigned int a, unsigned int b);
+/* Convenience method for getting an 8-bit mask. */
+static inline unsigned char constant_time_lt_8(unsigned int a,
+                                               unsigned int b);
+
+/*
+ * Returns 0xff..f if a >= b and 0 otherwise.
+ */
+static inline unsigned int constant_time_ge(unsigned int a, unsigned int b);
+/* Convenience method for getting an 8-bit mask. */
+static inline unsigned char constant_time_ge_8(unsigned int a,
+                                               unsigned int b);
+
+/*
+ * Returns 0xff..f if a == 0 and 0 otherwise.
+ */
+static inline unsigned int constant_time_is_zero(unsigned int a);
+/* Convenience method for getting an 8-bit mask. */
+static inline unsigned char constant_time_is_zero_8(unsigned int a);
+
+/*
+ * Returns 0xff..f if a == b and 0 otherwise.
+ */
+static inline unsigned int constant_time_eq(unsigned int a, unsigned int b);
+/* Convenience method for getting an 8-bit mask. */
+static inline unsigned char constant_time_eq_8(unsigned int a,
+                                               unsigned int b);
+/* Signed integers. */
+static inline unsigned int constant_time_eq_int(int a, int b);
+/* Convenience method for getting an 8-bit mask. */
+static inline unsigned char constant_time_eq_int_8(int a, int b);
+
+/*-
+ * Returns (mask & a) | (~mask & b).
+ *
+ * When |mask| is all 1s or all 0s (as returned by the methods above),
+ * the select methods return either |a| (if |mask| is nonzero) or |b|
+ * (if |mask| is zero).
+ */
+static inline unsigned int constant_time_select(unsigned int mask,
+                                                unsigned int a,
+                                                unsigned int b);
+/* Convenience method for unsigned chars. */
+static inline unsigned char constant_time_select_8(unsigned char mask,
+                                                   unsigned char a,
+                                                   unsigned char b);
+/* Convenience method for signed integers. */
+static inline int constant_time_select_int(unsigned int mask, int a, int b);
+
+static inline unsigned int constant_time_msb(unsigned int a)
+{
+    return 0 - (a >> (sizeof(a) * 8 - 1));
+}
+
+static inline unsigned int constant_time_lt(unsigned int a, unsigned int b)
+{
+    return constant_time_msb(a ^ ((a ^ b) | ((a - b) ^ b)));
+}
+
+static inline unsigned char constant_time_lt_8(unsigned int a, unsigned int b)
+{
+    return (unsigned char)(constant_time_lt(a, b));
+}
+
+static inline unsigned int constant_time_ge(unsigned int a, unsigned int b)
+{
+    return ~constant_time_lt(a, b);
+}
+
+static inline unsigned char constant_time_ge_8(unsigned int a, unsigned int b)
+{
+    return (unsigned char)(constant_time_ge(a, b));
+}
+
+static inline unsigned int constant_time_is_zero(unsigned int a)
+{
+    return constant_time_msb(~a & (a - 1));
+}
+
+static inline unsigned char constant_time_is_zero_8(unsigned int a)
+{
+    return (unsigned char)(constant_time_is_zero(a));
+}
+
+static inline unsigned int constant_time_eq(unsigned int a, unsigned int b)
+{
+    return constant_time_is_zero(a ^ b);
+}
+
+static inline unsigned char constant_time_eq_8(unsigned int a, unsigned int b)
+{
+    return (unsigned char)(constant_time_eq(a, b));
+}
+
+static inline unsigned int constant_time_eq_int(int a, int b)
+{
+    return constant_time_eq((unsigned)(a), (unsigned)(b));
+}
+
+static inline unsigned char constant_time_eq_int_8(int a, int b)
+{
+    return constant_time_eq_8((unsigned)(a), (unsigned)(b));
+}
+
+static inline unsigned int constant_time_select(unsigned int mask,
+                                                unsigned int a,
+                                                unsigned int b)
+{
+    return (mask & a) | (~mask & b);
+}
+
+static inline unsigned char constant_time_select_8(unsigned char mask,
+                                                   unsigned char a,
+                                                   unsigned char b)
+{
+    return (unsigned char)(constant_time_select(mask, a, b));
+}
+
+static inline int constant_time_select_int(unsigned int mask, int a, int b)
+{
+    return (int)(constant_time_select(mask, (unsigned)(a), (unsigned)(b)));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif                          /* HEADER_CONSTANT_TIME_LOCL_H */
openSUSE Build Service is sponsored by