File openssl-One_and_Done.patch of Package compat-openssl098.14113

Based on:

commit 848113a30b431c2fe21ae8de2a366b9b6146fb92
Author: User <milosprv@gmail.com>
Date:   Wed May 16 13:59:36 2018 -0400

    bn/bn_exp.c: mitigation of the One-and-Done side-channel attack.
    
    The One&Done attack, which is described in a paper to appear in the 
    USENIX Security'18 conference, uses EM emanations to recover the values
    of the bits that are obtained using BN_is_bit_set while constructing
    the value of the window in BN_mod_exp_consttime. The EM signal changes
    slightly depending on the value of the bit, and since the lookup of a
    bit is surrounded by highly regular execution (constant-time Montgomery
    multiplications) the attack is able to isolate the (very brief) part of
    the signal that changes depending on the bit. Although the change is
    slight, the attack recovers it successfully >90% of the time on several
    phones and IoT devices (all with ARM processors with clock rates around
    1GHz), so after only one RSA decryption more than 90% of the bits in
    d_p and d_q are recovered correctly, which enables rapid recovery of
    the full RSA key using an algorithm (also described in the paper) that
    modifies the branch-and-prune approach for a situation in which the 
    exponents' bits are recovered with errors, i.e. where we do not know
    a priori which bits are correctly recovered.
    
    The mitigation for the attack is relatively simple - all the bits of
    the window are obtained at once, along with other bits so that an
    entire integer's worth of bits are obtained together using masking and 
    shifts, without unnecessarily considering each bit in isolation. This
    improves performance somewhat (one call to bn_get_bits is faster than
    several calls to BN_is_bit_set), so the attacker now gets one signal
    snippet per window (rather than one per bit) in which the signal is
    affected by all bits in the integer (rather than just the one bit).
    
    Reviewed-by: Andy Polyakov <appro@openssl.org>
    Reviewed-by: Rich Salz <rsalz@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/6276)

Index: openssl-0.9.8j/crypto/bn/bn_exp.c
===================================================================
--- openssl-0.9.8j.orig/crypto/bn/bn_exp.c	2018-11-26 16:03:05.329750971 +0100
+++ openssl-0.9.8j/crypto/bn/bn_exp.c	2018-11-26 16:50:19.102450105 +0100
@@ -595,6 +595,25 @@ static int MOD_EXP_CTIME_COPY_FROM_PREBU
 	return 1;
 	}	
 
+static BN_ULONG bn_get_bits(const BIGNUM *a, int bitpos)
+{
+    BN_ULONG ret = 0;
+    int wordpos;
+
+    wordpos = bitpos / BN_BITS2;
+    bitpos %= BN_BITS2;
+    if (wordpos >= 0 && wordpos < a->top) {
+        ret = a->d[wordpos] & BN_MASK2;
+        if (bitpos) {
+            ret >>= bitpos;
+            if (++wordpos < a->top)
+                ret |= a->d[wordpos] << (BN_BITS2 - bitpos);
+        }
+    }
+
+    return ret & BN_MASK2;
+}
+
 /* Given a pointer value, compute the next address that is a cache line multiple. */
 #define MOD_EXP_CTIME_ALIGN(x_) \
 	((unsigned char*)(x_) + (MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH - (((BN_ULONG)(x_)) & (MOD_EXP_CTIME_MIN_CACHE_LINE_MASK))))
@@ -608,7 +627,7 @@ static int MOD_EXP_CTIME_COPY_FROM_PREBU
 int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
 		    const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont)
 	{
-	int i,bits,ret=0,idx,window,wvalue;
+	int i,bits,ret=0,window,wvalue,wmask;
 	int top;
  	BIGNUM *r;
 	const BIGNUM *aa;
@@ -719,24 +738,36 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr
  	 * * to be taken in the BN_is_bit_set function.
  	 */
  	bits = ((bits+window-1)/window)*window;
- 	idx=bits-1;	/* The top bit of the window */
+ 	bits--;	/* The top bit of the window */
+        wmask=(1<<window)-1;
 
  	/* Scan the exponent one window at a time starting from the most
  	 * significant bits.
  	 */
- 	while (idx >= 0)
+ 	while (bits >= 0)
   		{
- 		wvalue=0; /* The 'value' of the window */
- 		
- 		/* Scan the window, squaring the result as we go */
- 		for (i=0; i<window; i++,idx--)
- 			{
+            /* Get window-aligned word's worth of bits from the exponent
+             *  This avoids calling BN_is_bit_set for each bit, which
+             *  is not only slower but also makes each bit vulnerable to
+             *  EM (and likely other) side-channel attacks like One&Done
+             *  (for details see "One&Done: A Single-Decryption EM-Based
+             *   Attack on OpenSSL’s Constant-Time Blinded RSA" by M. Alam,
+             *   H. Khan, M. Dey, N. Sinha, R. Callan, A. Zajic, and
+             *   M. Prvulovic, in USENIX Security'18)
+             */
+            bits-=window;
+            wvalue=bn_get_bits(p,bits+1);
+            /* Square the result window-size times */
+            for (i = 0; i < window; i++)
 			if (!BN_mod_mul_montgomery(r,r,r,mont,ctx))	goto err;
-			wvalue = (wvalue<<1)+BN_is_bit_set(p,idx);
-  			}
- 		
-		/* Fetch the appropriate pre-computed value from the pre-buf */
-		if (!MOD_EXP_CTIME_COPY_FROM_PREBUF(computeTemp, top, powerbuf, wvalue, window)) goto err;
+
+		/* Fetch the appropriate pre-computed value from the pre-buf
+             * (the index is masked now so that only the actual window
+             *  bits are used, not the entire word returned by bn_get_bits,
+             *  and this masking should not be done earlier because that
+             *  would facilitate One&Done-like side-channel attacks)
+             */
+		if (!MOD_EXP_CTIME_COPY_FROM_PREBUF(computeTemp, top, powerbuf, wvalue&wmask, window)) goto err;
 
  		/* Multiply the result into the intermediate result */
  		if (!BN_mod_mul_montgomery(r,r,computeTemp,mont,ctx)) goto err;
openSUSE Build Service is sponsored by