Implement fixed-window exponentiation to mitigate hyper-threading
authorBodo Möller <bodo@openssl.org>
Mon, 16 May 2005 01:43:31 +0000 (01:43 +0000)
committerBodo Möller <bodo@openssl.org>
Mon, 16 May 2005 01:43:31 +0000 (01:43 +0000)
timing attacks.

BN_FLG_EXP_CONSTTIME requests this algorithm, and this done by default for
RSA/DSA/DH private key computations unless
RSA_FLAG_NO_EXP_CONSTTIME/DSA_FLAG_NO_EXP_CONSTTIME/
DH_FLAG_NO_EXP_CONSTTIME is set.

Submitted by: Matthew D Wood
Reviewed by: Bodo Moeller

19 files changed:
CHANGES
apps/speed.c
crypto/bn/bn.h
crypto/bn/bn_err.c
crypto/bn/bn_exp.c
crypto/bn/bn_lcl.h
crypto/bn/bntest.c
crypto/bn/expspeed.c
crypto/bn/exptest.c
crypto/dh/dh.h
crypto/dh/dh_key.c
crypto/dh/dhtest.c
crypto/dsa/dsa.h
crypto/dsa/dsa_key.c
crypto/dsa/dsa_ossl.c
crypto/dsa/dsatest.c
crypto/rsa/rsa.h
crypto/rsa/rsa_eay.c
crypto/rsa/rsa_test.c

diff --git a/CHANGES b/CHANGES
index cd3dba1..54df558 100644 (file)
--- a/CHANGES
+++ b/CHANGES
 
  Changes between 0.9.7g and 0.9.7h  [XX xxx XXXX]
 
+  *) Make a new fixed-window mod_exp implementation the default for
+     RSA, DSA, and DH private-key operations to mitigate the
+     hyper-threading timing attacks pointed out by Colin Percival
+     (http://www.daemonology.net/hyperthreading-considered-harmful/),
+     and potential related attacks.
+
+     BN_mod_exp_mont_consttime() is the new exponentiation implementation,
+     and this is automatically used by BN_mod_exp_mont() if the new flag
+     BN_FLG_EXP_CONSTTIME is set for the exponent.  RSA, DSA, and DH
+     will use this BN flag for private exponents unless the flag
+     RSA_FLAG_NO_EXP_CONSTTIME, DSA_FLAG_NO_EXP_CONSTTIME, or
+     DH_FLAG_NO_EXP_CONSTTIME, respectively, is set.
+
+     [Matthew D Wood (Intel Corp), with some changes by Bodo Moeller]
+
   *) Change the client implementation for SSLv23_method() and
      SSLv23_client_method() so that is uses the SSL 3.0/TLS 1.0
      Client Hello message format if the SSL_OP_NO_SSLv2 option is set.
index bd5b217..2ecbb1e 100644 (file)
@@ -2365,7 +2365,7 @@ show_res:
                                k,rsa_bits[k],rsa_results[k][0],
                                rsa_results[k][1]);
                else
-                       fprintf(stdout,"rsa %4u bits %8.4fs %8.4fs %8.1f %8.1f\n",
+                       fprintf(stdout,"rsa %4u bits %8.6fs %8.6fs %8.1f %8.1f\n",
                                rsa_bits[k],rsa_results[k][0],rsa_results[k][1],
                                1.0/rsa_results[k][0],1.0/rsa_results[k][1]);
                }
@@ -2384,7 +2384,7 @@ show_res:
                        fprintf(stdout,"+F3:%u:%u:%f:%f\n",
                                k,dsa_bits[k],dsa_results[k][0],dsa_results[k][1]);
                else
-                       fprintf(stdout,"dsa %4u bits %8.4fs %8.4fs %8.1f %8.1f\n",
+                       fprintf(stdout,"dsa %4u bits %8.6fs %8.6fs %8.1f %8.1f\n",
                                dsa_bits[k],dsa_results[k][0],dsa_results[k][1],
                                1.0/dsa_results[k][0],1.0/dsa_results[k][1]);
                }
index 99faf8f..6d52735 100644 (file)
@@ -245,12 +245,23 @@ extern "C" {
 
 #define BN_FLG_MALLOCED                0x01
 #define BN_FLG_STATIC_DATA     0x02
+#define BN_FLG_EXP_CONSTTIME   0x04 /* avoid leaking exponent information through timings
+                                     * (BN_mod_exp_mont() will call BN_mod_exp_mont_consttime) */
 #ifndef OPENSSL_NO_DEPRECATED
 #define BN_FLG_FREE            0x8000  /* used for debuging */
 #endif
 #define BN_set_flags(b,n)      ((b)->flags|=(n))
 #define BN_get_flags(b,n)      ((b)->flags&(n))
 
+#define BN_with_flags(dest,b,n)  ((dest)->d=(b)->d, \
+                                  (dest)->top=(b)->top, \
+                                  (dest)->dmax=(b)->dmax, \
+                                  (dest)->neg=(b)->neg, \
+                                  (dest)->flags=(((dest)->flags & BN_FLG_MALLOCED) \
+                                                 |  ((b)->flags & ~BN_FLG_MALLOCED) \
+                                                 |  BN_FLG_STATIC_DATA \
+                                                 |  (n)))
+
 /* Already declared in ossl_typ.h */
 #if 0
 typedef struct bignum_st BIGNUM;
@@ -439,6 +450,8 @@ int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
        const BIGNUM *m,BN_CTX *ctx);
 int    BN_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
        const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
+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    BN_mod_exp_mont_word(BIGNUM *r, BN_ULONG a, const BIGNUM *p,
        const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
 int    BN_mod_exp2_mont(BIGNUM *r, const BIGNUM *a1, const BIGNUM *p1,
@@ -728,9 +741,9 @@ void ERR_load_BN_strings(void);
 /* Error codes for the BN functions. */
 
 /* Function codes. */
-#define BN_F_BNRAND                                     114
+#define BN_F_BNRAND                                     127
 #define BN_F_BN_BLINDING_CONVERT_EX                     100
-#define BN_F_BN_BLINDING_CREATE_PARAM                   133
+#define BN_F_BN_BLINDING_CREATE_PARAM                   128
 #define BN_F_BN_BLINDING_INVERT_EX                      101
 #define BN_F_BN_BLINDING_NEW                            102
 #define BN_F_BN_BLINDING_UPDATE                                 103
@@ -738,28 +751,32 @@ void ERR_load_BN_strings(void);
 #define BN_F_BN_BN2HEX                                  105
 #define BN_F_BN_CTX_GET                                         116
 #define BN_F_BN_CTX_NEW                                         106
-#define BN_F_BN_CTX_START                               130
+#define BN_F_BN_CTX_START                               129
 #define BN_F_BN_DIV                                     107
-#define BN_F_BN_DIV_RECP                                131
+#define BN_F_BN_DIV_RECP                                130
+#define BN_F_BN_EXP                                     123
 #define BN_F_BN_EXPAND2                                         108
 #define BN_F_BN_EXPAND_INTERNAL                                 120
-#define BN_F_BN_GF2M_MOD                                126
-#define BN_F_BN_GF2M_MOD_DIV                            123
-#define BN_F_BN_GF2M_MOD_EXP                            127
-#define BN_F_BN_GF2M_MOD_MUL                            124
-#define BN_F_BN_GF2M_MOD_SOLVE_QUAD                     128
-#define BN_F_BN_GF2M_MOD_SOLVE_QUAD_ARR                         129
-#define BN_F_BN_GF2M_MOD_SQR                            125
-#define BN_F_BN_GF2M_MOD_SQRT                           132
+#define BN_F_BN_GF2M_MOD                                131
+#define BN_F_BN_GF2M_MOD_EXP                            132
+#define BN_F_BN_GF2M_MOD_MUL                            133
+#define BN_F_BN_GF2M_MOD_SOLVE_QUAD                     134
+#define BN_F_BN_GF2M_MOD_SOLVE_QUAD_ARR                         135
+#define BN_F_BN_GF2M_MOD_SQR                            136
+#define BN_F_BN_GF2M_MOD_SQRT                           137
 #define BN_F_BN_MOD_EXP2_MONT                           118
 #define BN_F_BN_MOD_EXP_MONT                            109
+#define BN_F_BN_MOD_EXP_MONT_CONSTTIME                  124
 #define BN_F_BN_MOD_EXP_MONT_WORD                       117
+#define BN_F_BN_MOD_EXP_RECP                            125
+#define BN_F_BN_MOD_EXP_SIMPLE                          126
 #define BN_F_BN_MOD_INVERSE                             110
 #define BN_F_BN_MOD_LSHIFT_QUICK                        119
 #define BN_F_BN_MOD_MUL_RECIPROCAL                      111
 #define BN_F_BN_MOD_SQRT                                121
 #define BN_F_BN_MPI2BN                                  112
 #define BN_F_BN_NEW                                     113
+#define BN_F_BN_RAND                                    114
 #define BN_F_BN_RAND_RANGE                              122
 #define BN_F_BN_USUB                                    115
 
@@ -775,10 +792,9 @@ void ERR_load_BN_strings(void);
 #define BN_R_INVALID_LENGTH                             106
 #define BN_R_INVALID_RANGE                              115
 #define BN_R_NOT_A_SQUARE                               111
-#define BN_R_NOT_IMPLEMENTED                            116
 #define BN_R_NOT_INITIALIZED                            107
 #define BN_R_NO_INVERSE                                         108
-#define BN_R_NO_SOLUTION                                117
+#define BN_R_NO_SOLUTION                                116
 #define BN_R_P_IS_NOT_PRIME                             112
 #define BN_R_TOO_MANY_ITERATIONS                        113
 #define BN_R_TOO_MANY_TEMPORARY_VARIABLES               109
index 58a7d06..a253959 100644 (file)
@@ -83,10 +83,10 @@ static ERR_STRING_DATA BN_str_functs[]=
 {ERR_FUNC(BN_F_BN_CTX_START),  "BN_CTX_start"},
 {ERR_FUNC(BN_F_BN_DIV),        "BN_div"},
 {ERR_FUNC(BN_F_BN_DIV_RECP),   "BN_div_recp"},
+{ERR_FUNC(BN_F_BN_EXP),        "BN_exp"},
 {ERR_FUNC(BN_F_BN_EXPAND2),    "bn_expand2"},
 {ERR_FUNC(BN_F_BN_EXPAND_INTERNAL),    "BN_EXPAND_INTERNAL"},
 {ERR_FUNC(BN_F_BN_GF2M_MOD),   "BN_GF2m_mod"},
-{ERR_FUNC(BN_F_BN_GF2M_MOD_DIV),       "BN_GF2m_mod_div"},
 {ERR_FUNC(BN_F_BN_GF2M_MOD_EXP),       "BN_GF2m_mod_exp"},
 {ERR_FUNC(BN_F_BN_GF2M_MOD_MUL),       "BN_GF2m_mod_mul"},
 {ERR_FUNC(BN_F_BN_GF2M_MOD_SOLVE_QUAD),        "BN_GF2m_mod_solve_quad"},
@@ -95,13 +95,17 @@ static ERR_STRING_DATA BN_str_functs[]=
 {ERR_FUNC(BN_F_BN_GF2M_MOD_SQRT),      "BN_GF2m_mod_sqrt"},
 {ERR_FUNC(BN_F_BN_MOD_EXP2_MONT),      "BN_mod_exp2_mont"},
 {ERR_FUNC(BN_F_BN_MOD_EXP_MONT),       "BN_mod_exp_mont"},
+{ERR_FUNC(BN_F_BN_MOD_EXP_MONT_CONSTTIME),     "BN_mod_exp_mont_consttime"},
 {ERR_FUNC(BN_F_BN_MOD_EXP_MONT_WORD),  "BN_mod_exp_mont_word"},
+{ERR_FUNC(BN_F_BN_MOD_EXP_RECP),       "BN_mod_exp_recp"},
+{ERR_FUNC(BN_F_BN_MOD_EXP_SIMPLE),     "BN_mod_exp_simple"},
 {ERR_FUNC(BN_F_BN_MOD_INVERSE),        "BN_mod_inverse"},
 {ERR_FUNC(BN_F_BN_MOD_LSHIFT_QUICK),   "BN_mod_lshift_quick"},
 {ERR_FUNC(BN_F_BN_MOD_MUL_RECIPROCAL), "BN_mod_mul_reciprocal"},
 {ERR_FUNC(BN_F_BN_MOD_SQRT),   "BN_mod_sqrt"},
 {ERR_FUNC(BN_F_BN_MPI2BN),     "BN_mpi2bn"},
 {ERR_FUNC(BN_F_BN_NEW),        "BN_new"},
+{ERR_FUNC(BN_F_BN_RAND),       "BN_rand"},
 {ERR_FUNC(BN_F_BN_RAND_RANGE), "BN_rand_range"},
 {ERR_FUNC(BN_F_BN_USUB),       "BN_usub"},
 {0,NULL}
@@ -120,7 +124,6 @@ static ERR_STRING_DATA BN_str_reasons[]=
 {ERR_REASON(BN_R_INVALID_LENGTH)         ,"invalid length"},
 {ERR_REASON(BN_R_INVALID_RANGE)          ,"invalid range"},
 {ERR_REASON(BN_R_NOT_A_SQUARE)           ,"not a square"},
-{ERR_REASON(BN_R_NOT_IMPLEMENTED)        ,"not implemented"},
 {ERR_REASON(BN_R_NOT_INITIALIZED)        ,"not initialized"},
 {ERR_REASON(BN_R_NO_INVERSE)             ,"no inverse"},
 {ERR_REASON(BN_R_NO_SOLUTION)            ,"no solution"},
index d6bb2b4..8f8c694 100644 (file)
@@ -56,7 +56,7 @@
  * [including the GNU Public Licence.]
  */
 /* ====================================================================
- * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1998-2005 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
 #include "cryptlib.h"
 #include "bn_lcl.h"
 
+/* maximum precomputation table size for *variable* sliding windows */
 #define TABLE_SIZE     32
 
 /* this one works - simple but works */
@@ -121,6 +122,13 @@ int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx)
        int i,bits,ret=0;
        BIGNUM *v,*rr;
 
+       if (BN_get_flags(p, BN_FLG_EXP_CONSTTIME) != 0)
+               {
+               /* BN_FLG_EXP_CONSTTIME only supported by BN_mod_exp_mont() */
+               BNerr(BN_F_BN_EXP,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+               return -1;
+               }
+
        BN_CTX_start(ctx);
        if ((r == a) || (r == p))
                rr = BN_CTX_get(ctx);
@@ -205,7 +213,7 @@ int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
        if (BN_is_odd(m))
                {
 #  ifdef MONT_EXP_WORD
-               if (a->top == 1 && !a->neg)
+               if (a->top == 1 && !a->neg && (BN_get_flags(p, BN_FLG_EXP_CONSTTIME) == 0))
                        {
                        BN_ULONG A = a->d[0];
                        ret=BN_mod_exp_mont_word(r,A,p,m,ctx,NULL);
@@ -237,6 +245,13 @@ int BN_mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
        BIGNUM *val[TABLE_SIZE];
        BN_RECP_CTX recp;
 
+       if (BN_get_flags(p, BN_FLG_EXP_CONSTTIME) != 0)
+               {
+               /* BN_FLG_EXP_CONSTTIME only supported by BN_mod_exp_mont() */
+               BNerr(BN_F_BN_MOD_EXP_RECP,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+               return -1;
+               }
+
        bits=BN_num_bits(p);
 
        if (bits == 0)
@@ -364,6 +379,11 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
        BIGNUM *val[TABLE_SIZE];
        BN_MONT_CTX *mont=NULL;
 
+       if (BN_get_flags(p, BN_FLG_EXP_CONSTTIME) != 0)
+               {
+               return BN_mod_exp_mont_consttime(rr, a, p, m, ctx, in_mont);
+               }
+
        bn_check_top(a);
        bn_check_top(p);
        bn_check_top(m);
@@ -495,6 +515,212 @@ err:
        return(ret);
        }
 
+
+/* BN_mod_exp_mont_consttime() stores the precomputed powers in a specific layout
+ * so that accessing any of these table values shows the same access pattern as far
+ * 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)
+       {
+       size_t i, j;
+
+       if (bn_wexpand(b, top) == NULL)
+               return 0;
+       while (b->top < top)
+               {
+               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];
+               }
+
+       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)
+       {
+       size_t i, j;
+
+       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];
+               }
+
+       b->top = top;
+       bn_correct_top(b);
+       return 1;
+       }       
+
+/* 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))))
+
+/* This variant of BN_mod_exp_mont() uses fixed windows and the special
+ * precomputation memory layout to limit data-dependency to a minimum
+ * to protect secret exponents (cf. the hyper-threading timing attacks
+ * pointed out by Colin Percival,
+ * http://www.daemonology.net/hyperthreading-considered-harmful/)
+ */
+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 top;
+       BIGNUM *r;
+       const BIGNUM *aa;
+       BN_MONT_CTX *mont=NULL;
+
+       int numPowers;
+       unsigned char *powerbufFree=NULL;
+       int powerbufLen = 0;
+       unsigned char *powerbuf=NULL;
+       BIGNUM *computeTemp=NULL, *am=NULL;
+
+       bn_check_top(a);
+       bn_check_top(p);
+       bn_check_top(m);
+
+       top = m->top;
+
+       if (!(m->d[0] & 1))
+               {
+               BNerr(BN_F_BN_MOD_EXP_MONT_CONSTTIME,BN_R_CALLED_WITH_EVEN_MODULUS);
+               return(0);
+               }
+       bits=BN_num_bits(p);
+       if (bits == 0)
+               {
+               ret = BN_one(rr);
+               return ret;
+               }
+
+       /* Initialize BIGNUM context and allocate intermediate result */
+       BN_CTX_start(ctx);
+       r = BN_CTX_get(ctx);
+       if (r == NULL) goto err;
+
+       /* Allocate a montgomery context if it was not supplied by the caller.
+        * If this is not done, things will break in the montgomery part.
+        */
+       if (in_mont != NULL)
+               mont=in_mont;
+       else
+               {
+               if ((mont=BN_MONT_CTX_new()) == NULL) goto err;
+               if (!BN_MONT_CTX_set(mont,m,ctx)) goto err;
+               }
+
+       /* Get the window size to use with size of p. */
+       window = BN_window_bits_for_ctime_exponent_size(bits);
+
+       /* Allocate a buffer large enough to hold all of the pre-computed
+        * powers of a.
+        */
+       numPowers = 1 << window;
+       powerbufLen = sizeof(m->d[0])*top*numPowers;
+       if ((powerbufFree=(unsigned char*)OPENSSL_malloc(powerbufLen+MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH)) == NULL)
+               goto err;
+               
+       powerbuf = MOD_EXP_CTIME_ALIGN(powerbufFree);
+       memset(powerbuf, 0, powerbufLen);
+
+       /* Initialize the intermediate result. Do this early to save double conversion,
+        * 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;
+
+       /* Initialize computeTemp as a^1 with montgomery precalcs */
+       computeTemp = BN_CTX_get(ctx);
+       am = BN_CTX_get(ctx);
+       if (computeTemp==NULL || am==NULL) goto err;
+
+       if (a->neg || BN_ucmp(a,m) >= 0)
+               {
+               if (!BN_mod(am,a,m,ctx))
+                       goto err;
+               aa= am;
+               }
+       else
+               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 the window size is greater than 1, then calculate
+        * val[i=2..2^winsize-1]. Powers are computed as a*a^(i-1)
+        * (even powers could instead be computed as (a^(i/2))^2
+        * to use the slight performance advantage of sqr over mul).
+        */
+       if (window > 1)
+               {
+               for (i=2; i<numPowers; i++)
+                       {
+                       /* 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;
+                       }
+               }
+
+       /* Adjust the number of bits up to a multiple of the window size.
+        * If the exponent length is not a multiple of the window size, then
+        * this pads the most significant bits with zeros to normalize the
+        * scanning loop to there's no special cases.
+        *
+        * * NOTE: Making the window size a power of two less than the native
+        * * word size ensures that the padded bits won't go past the last
+        * * word in the internal BIGNUM structure. Going past the end will
+        * * still produce the correct result, but causes a different branch
+        * * 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 */
+
+       /* Scan the exponent one window at a time starting from the most
+        * significant bits.
+        */
+       while (idx >= 0)
+               {
+               wvalue=0; /* The 'value' of the window */
+               
+               /* Scan the window, squaring the result as we go */
+               for (i=0; i<window; i++,idx--)
+                       {
+                       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, numPowers)) goto err;
+
+               /* Multiply the result into the intermediate result */
+               if (!BN_mod_mul_montgomery(r,r,computeTemp,mont,ctx)) goto err;
+               }
+
+       /* Convert the final result from montgomery to standard format */
+       if (!BN_from_montgomery(rr,r,mont,ctx)) goto err;
+       ret=1;
+err:
+       if ((in_mont == NULL) && (mont != NULL)) BN_MONT_CTX_free(mont);
+       if (powerbuf!=NULL)
+               {
+               OPENSSL_cleanse(powerbuf,powerbufLen);
+               OPENSSL_free(powerbufFree);
+               }
+       if (am!=NULL) BN_clear(am);
+       if (computeTemp!=NULL) BN_clear(computeTemp);
+       BN_CTX_end(ctx);
+       return(ret);
+       }
+
 int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p,
                          const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont)
        {
@@ -519,6 +745,13 @@ int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p,
 #define BN_TO_MONTGOMERY_WORD(r, w, mont) \
                (BN_set_word(r, (w)) && BN_to_montgomery(r, r, (mont), ctx))
 
+       if (BN_get_flags(p, BN_FLG_EXP_CONSTTIME) != 0)
+               {
+               /* BN_FLG_EXP_CONSTTIME only supported by BN_mod_exp_mont() */
+               BNerr(BN_F_BN_MOD_EXP_MONT_WORD,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+               return -1;
+               }
+
        bn_check_top(p);
        bn_check_top(m);
 
@@ -648,6 +881,13 @@ int BN_mod_exp_simple(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
        /* Table of variables obtained from 'ctx' */
        BIGNUM *val[TABLE_SIZE];
 
+       if (BN_get_flags(p, BN_FLG_EXP_CONSTTIME) != 0)
+               {
+               /* BN_FLG_EXP_CONSTTIME only supported by BN_mod_exp_mont() */
+               BNerr(BN_F_BN_MOD_EXP_SIMPLE,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+               return -1;
+               }
+
        bits=BN_num_bits(p);
 
        if (bits == 0)
index 45e1922..1c680fc 100644 (file)
@@ -163,6 +163,45 @@ extern "C" {
 
 
 
+/* BN_mod_exp_mont_conttime is based on the assumption that the
+ * L1 data cache line width of the target processor is at least
+ * the following value.
+ */
+#define MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH     ( 64 )
+#define MOD_EXP_CTIME_MIN_CACHE_LINE_MASK      (MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH - 1)
+
+/* Window sizes optimized for fixed window size modular exponentiation
+ * algorithm (BN_mod_exp_mont_consttime).
+ *
+ * To achieve the security goals of BN_mode_exp_mont_consttime, the
+ * maximum size of the window must not exceed
+ * log_2(MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH). 
+ *
+ * Window size thresholds are defined for cache line sizes of 32 and 64,
+ * cache line sizes where log_2(32)=5 and log_2(64)=6 respectively. A
+ * window size of 7 should only be used on processors that have a 128
+ * byte or greater cache line size.
+ */
+#if MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH == 64
+
+#  define BN_window_bits_for_ctime_exponent_size(b) \
+               ((b) > 937 ? 6 : \
+                (b) > 306 ? 5 : \
+                (b) >  89 ? 4 : \
+                (b) >  22 ? 3 : 1)
+#  define BN_MAX_WINDOW_BITS_FOR_CTIME_EXPONENT_SIZE   (6)
+
+#elif MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH == 32
+
+#  define BN_window_bits_for_ctime_exponent_size(b) \
+               ((b) > 306 ? 5 : \
+                (b) >  89 ? 4 : \
+                (b) >  22 ? 3 : 1)
+#  define BN_MAX_WINDOW_BITS_FOR_CTIME_EXPONENT_SIZE   (5)
+
+#endif
+
+
 /* Pentium pro 16,16,16,32,64 */
 /* Alpha       16,16,16,16.64 */
 #define BN_MULL_SIZE_NORMAL                    (16) /* 32 */
index 9169cc8..c885300 100644 (file)
@@ -106,6 +106,7 @@ int test_mont(BIO *bp,BN_CTX *ctx);
 int test_mod(BIO *bp,BN_CTX *ctx);
 int test_mod_mul(BIO *bp,BN_CTX *ctx);
 int test_mod_exp(BIO *bp,BN_CTX *ctx);
+int test_mod_exp_mont_consttime(BIO *bp,BN_CTX *ctx);
 int test_exp(BIO *bp,BN_CTX *ctx);
 int test_gf2m_add(BIO *bp);
 int test_gf2m_mod(BIO *bp);
@@ -246,6 +247,10 @@ int main(int argc, char *argv[])
        if (!test_mod_exp(out,ctx)) goto err;
        BIO_flush(out);
 
+       message(out,"BN_mod_exp_mont_consttime");
+       if (!test_mod_exp_mont_consttime(out,ctx)) goto err;
+       BIO_flush(out);
+
        message(out,"BN_exp");
        if (!test_exp(out,ctx)) goto err;
        BIO_flush(out);
@@ -954,6 +959,57 @@ int test_mod_exp(BIO *bp, BN_CTX *ctx)
        return(1);
        }
 
+int test_mod_exp_mont_consttime(BIO *bp, BN_CTX *ctx)
+       {
+       BIGNUM *a,*b,*c,*d,*e;
+       int i;
+
+       a=BN_new();
+       b=BN_new();
+       c=BN_new();
+       d=BN_new();
+       e=BN_new();
+
+       BN_bntest_rand(c,30,0,1); /* must be odd for montgomery */
+       for (i=0; i<num2; i++)
+               {
+               BN_bntest_rand(a,20+i*5,0,0); /**/
+               BN_bntest_rand(b,2+i,0,0); /**/
+
+               if (!BN_mod_exp_mont_consttime(d,a,b,c,ctx,NULL))
+                       return(00);
+
+               if (bp != NULL)
+                       {
+                       if (!results)
+                               {
+                               BN_print(bp,a);
+                               BIO_puts(bp," ^ ");
+                               BN_print(bp,b);
+                               BIO_puts(bp," % ");
+                               BN_print(bp,c);
+                               BIO_puts(bp," - ");
+                               }
+                       BN_print(bp,d);
+                       BIO_puts(bp,"\n");
+                       }
+               BN_exp(e,a,b,ctx);
+               BN_sub(e,e,d);
+               BN_div(a,b,e,c,ctx);
+               if(!BN_is_zero(b))
+                   {
+                   fprintf(stderr,"Modulo exponentiation test failed!\n");
+                   return 0;
+                   }
+               }
+       BN_free(a);
+       BN_free(b);
+       BN_free(c);
+       BN_free(d);
+       BN_free(e);
+       return(1);
+       }
+
 int test_exp(BIO *bp, BN_CTX *ctx)
        {
        BIGNUM *a,*b,*d,*e,*one;
index 07a1bcf..4d5f221 100644 (file)
@@ -321,7 +321,7 @@ void do_mul_exp(BIGNUM *r, BIGNUM *a, BIGNUM *b, BIGNUM *c, BN_CTX *ctx)
 #else /* TEST_SQRT */
                        "2*sqrt [prime == %d (mod 64)] %4d %4d mod %4d"
 #endif
-                       " -> %8.3fms %5.1f (%ld)\n",
+                       " -> %8.6fms %5.1f (%ld)\n",
 #ifdef TEST_SQRT
                        P_MOD_64,
 #endif
index 37aec55..f598a07 100644 (file)
@@ -77,7 +77,7 @@ int main(int argc, char *argv[])
        BIO *out=NULL;
        int i,ret;
        unsigned char c;
-       BIGNUM *r_mont,*r_recp,*r_simple,*a,*b,*m;
+       BIGNUM *r_mont,*r_mont_const,*r_recp,*r_simple,*a,*b,*m;
 
        RAND_seed(rnd_seed, sizeof rnd_seed); /* or BN_rand may fail, and we don't
                                               * even check its return value
@@ -88,6 +88,7 @@ int main(int argc, char *argv[])
        ctx=BN_CTX_new();
        if (ctx == NULL) EXIT(1);
        r_mont=BN_new();
+       r_mont_const=BN_new();
        r_recp=BN_new();
        r_simple=BN_new();
        a=BN_new();
@@ -143,8 +144,17 @@ int main(int argc, char *argv[])
                        EXIT(1);
                        }
 
+               ret=BN_mod_exp_mont_consttime(r_mont_const,a,b,m,ctx,NULL);
+               if (ret <= 0)
+                       {
+                       printf("BN_mod_exp_mont_consttime() problems\n");
+                       ERR_print_errors(out);
+                       EXIT(1);
+                       }
+
                if (BN_cmp(r_simple, r_mont) == 0
-                   && BN_cmp(r_simple,r_recp) == 0)
+                   && BN_cmp(r_simple,r_recp) == 0
+                       && BN_cmp(r_simple,r_mont_const) == 0)
                        {
                        printf(".");
                        fflush(stdout);
@@ -153,6 +163,8 @@ int main(int argc, char *argv[])
                        {
                        if (BN_cmp(r_simple,r_mont) != 0)
                                printf("\nsimple and mont results differ\n");
+                       if (BN_cmp(r_simple,r_mont) != 0)
+                               printf("\nsimple and mont const time results differ\n");
                        if (BN_cmp(r_simple,r_recp) != 0)
                                printf("\nsimple and recp results differ\n");
 
@@ -162,11 +174,13 @@ int main(int argc, char *argv[])
                        printf("\nsimple   ="); BN_print(out,r_simple);
                        printf("\nrecp     ="); BN_print(out,r_recp);
                        printf("\nmont     ="); BN_print(out,r_mont);
+                       printf("\nmont_ct  ="); BN_print(out,r_mont_const);
                        printf("\n");
                        EXIT(1);
                        }
                }
        BN_free(r_mont);
+       BN_free(r_mont_const);
        BN_free(r_recp);
        BN_free(r_simple);
        BN_free(a);
index da44778..d1559fd 100644 (file)
 #include <openssl/bn.h>
 #endif
        
-#define DH_FLAG_CACHE_MONT_P   0x01
+#define DH_FLAG_CACHE_MONT_P     0x01
+#define DH_FLAG_NO_EXP_CONSTTIME 0x02 /* new with 0.9.7h; the built-in DH
+                                       * implementation now uses constant time
+                                       * modular exponentiation for secret exponents
+                                       * by default. This flag causes the
+                                       * faster variable sliding window method to
+                                       * be used for all exponents.
+                                       */
 
 #ifdef  __cplusplus
 extern "C" {
index 9148f17..e384286 100644 (file)
@@ -141,8 +141,21 @@ static int generate_key(DH *dh)
                l = dh->length ? dh->length : BN_num_bits(dh->p)-1; /* secret exponent length */
                if (!BN_rand(priv_key, l, 0, 0)) goto err;
                }
-       if (!dh->meth->bn_mod_exp(dh, pub_key, dh->g, priv_key,dh->p,ctx,mont))
-               goto err;
+
+       {
+               BIGNUM local_prk;
+               BIGNUM *prk;
+
+               if ((dh->flags & DH_FLAG_NO_EXP_CONSTTIME) == 0)
+                       {
+                       prk = &local_prk;
+                       BN_with_flags(prk, priv_key, BN_FLG_EXP_CONSTTIME);
+                       }
+               else
+                       prk = priv_key;
+
+               if (!dh->meth->bn_mod_exp(dh, pub_key, dh->g, prk, dh->p, ctx, mont)) goto err;
+       }
                
        dh->pub_key=pub_key;
        dh->priv_key=priv_key;
@@ -179,6 +192,11 @@ static int compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
                {
                mont = BN_MONT_CTX_set_locked(&dh->method_mont_p,
                                CRYPTO_LOCK_DH, dh->p, ctx);
+               if ((dh->flags & DH_FLAG_NO_EXP_CONSTTIME) == 0)
+                       {
+                       /* XXX */
+                       BN_set_flags(dh->priv_key, BN_FLG_EXP_CONSTTIME);
+                       }
                if (!mont)
                        goto err;
                }
@@ -201,7 +219,10 @@ static int dh_bn_mod_exp(const DH *dh, BIGNUM *r,
                        const BIGNUM *m, BN_CTX *ctx,
                        BN_MONT_CTX *m_ctx)
        {
-       if (a->top == 1)
+       /* If a is only one word long and constant time is false, use the faster
+        * exponenentiation function.
+        */
+       if (a->top == 1 && ((dh->flags & DH_FLAG_NO_EXP_CONSTTIME) != 0))
                {
                BN_ULONG A = a->d[0];
                return BN_mod_exp_mont_word(r,A,p,m,ctx,m_ctx);
index 1b19364..882f5c3 100644 (file)
@@ -145,6 +145,10 @@ int main(int argc, char *argv[])
        b->g=BN_dup(a->g);
        if ((b->p == NULL) || (b->g == NULL)) goto err;
 
+       /* Set a to run with normal modexp and b to use constant time */
+       a->flags &= ~DH_FLAG_NO_EXP_CONSTTIME;
+       b->flags |= DH_FLAG_NO_EXP_CONSTTIME;
+
        if (!DH_generate_key(a)) goto err;
        BIO_puts(out,"pri 1=");
        BN_print(out,a->priv_key);
index c7ba059..b12db98 100644 (file)
 #endif
 
 #define DSA_FLAG_CACHE_MONT_P  0x01
+#define DSA_FLAG_NO_EXP_CONSTTIME       0x02 /* new with 0.9.7h; the built-in DSA
+                                              * implementation now uses constant time
+                                              * modular exponentiation for secret exponents
+                                              * by default. This flag causes the
+                                              * faster variable sliding window method to
+                                              * be used for all exponents.
+                                              */
 
 #ifdef  __cplusplus
 extern "C" {
index 8427b77..5ba885e 100644 (file)
@@ -98,8 +98,21 @@ static int dsa_builtin_keygen(DSA *dsa)
                }
        else
                pub_key=dsa->pub_key;
+       
+       {
+               BIGNUM local_prk;
+               BIGNUM *prk;
+
+               if ((dsa->flags & DSA_FLAG_NO_EXP_CONSTTIME) == 0)
+                       {
+                       prk = &local_prk;
+                       BN_with_flags(prk, priv_key, BN_FLG_EXP_CONSTTIME);
+                       }
+               else
+                       prk = priv_key;
 
-       if (!BN_mod_exp(pub_key,dsa->g,priv_key,dsa->p,ctx)) goto err;
+               if (!BN_mod_exp(pub_key,dsa->g,prk,dsa->p,ctx)) goto err;
+       }
 
        dsa->priv_key=priv_key;
        dsa->pub_key=pub_key;
index 25cd848..2e5ede7 100644 (file)
@@ -227,6 +227,10 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp)
        do
                if (!BN_rand_range(&k, dsa->q)) goto err;
        while (BN_is_zero(&k));
+       if ((dsa->flags & DSA_FLAG_NO_EXP_CONSTTIME) == 0)
+               {
+               BN_set_flags(&k, BN_FLG_EXP_CONSTTIME);
+               }
 
        if (dsa->flags & DSA_FLAG_CACHE_MONT_P)
                {
index ccc456e..66ff417 100644 (file)
@@ -204,10 +204,19 @@ int main(int argc, char **argv)
                BIO_printf(bio_err,"g value is wrong\n");
                goto end;
                }
+
+       dsa->flags |= DSA_FLAG_NO_EXP_CONSTTIME;
        DSA_generate_key(dsa);
        DSA_sign(0, str1, 20, sig, &siglen, dsa);
        if (DSA_verify(0, str1, 20, sig, siglen, dsa) == 1)
                ret=1;
+
+       dsa->flags &= ~DSA_FLAG_NO_EXP_CONSTTIME;
+       DSA_generate_key(dsa);
+       DSA_sign(0, str1, 20, sig, &siglen, dsa);
+       if (DSA_verify(0, str1, 20, sig, siglen, dsa) == 1)
+               ret=1;
+
 end:
        if (!ret)
                ERR_print_errors(bio_err);
index f8bcbc3..dcefeba 100644 (file)
@@ -162,28 +162,35 @@ struct rsa_st
 #define RSA_3  0x3L
 #define RSA_F4 0x10001L
 
-#define RSA_METHOD_FLAG_NO_CHECK       0x01 /* don't check pub/private match */
+#define RSA_METHOD_FLAG_NO_CHECK       0x0001 /* don't check pub/private match */
 
-#define RSA_FLAG_CACHE_PUBLIC          0x02
-#define RSA_FLAG_CACHE_PRIVATE         0x04
-#define RSA_FLAG_BLINDING              0x08
-#define RSA_FLAG_THREAD_SAFE           0x10
+#define RSA_FLAG_CACHE_PUBLIC          0x0002
+#define RSA_FLAG_CACHE_PRIVATE         0x0004
+#define RSA_FLAG_BLINDING              0x0008
+#define RSA_FLAG_THREAD_SAFE           0x0010
 /* This flag means the private key operations will be handled by rsa_mod_exp
  * and that they do not depend on the private key components being present:
  * for example a key stored in external hardware. Without this flag bn_mod_exp
  * gets called when private key components are absent.
  */
-#define RSA_FLAG_EXT_PKEY              0x20
+#define RSA_FLAG_EXT_PKEY              0x0020
 
 /* This flag in the RSA_METHOD enables the new rsa_sign, rsa_verify functions.
  */
-#define RSA_FLAG_SIGN_VER              0x40
-
-#define RSA_FLAG_NO_BLINDING           0x80 /* new with 0.9.6j and 0.9.7b; the built-in
-                                              * RSA implementation now uses blinding by
-                                              * default (ignoring RSA_FLAG_BLINDING),
-                                              * but other engines might not need it
-                                              */
+#define RSA_FLAG_SIGN_VER              0x0040
+
+#define RSA_FLAG_NO_BLINDING           0x0080 /* new with 0.9.6j and 0.9.7b; the built-in
+                                                * RSA implementation now uses blinding by
+                                                * default (ignoring RSA_FLAG_BLINDING),
+                                                * but other engines might not need it
+                                                */
+#define RSA_FLAG_NO_EXP_CONSTTIME      0x0100 /* new with 0.9.7h; the built-in RSA
+                                                * implementation now uses constant time
+                                                * modular exponentiation for secret exponents
+                                                * by default. This flag causes the
+                                                * faster variable sliding window method to
+                                                * be used for all exponents.
+                                                */
 
 #define RSA_PKCS1_PADDING      1
 #define RSA_SSLV23_PADDING     2
index 21755c0..175ab8a 100644 (file)
  * copied and put under another distribution licence
  * [including the GNU Public Licence.]
  */
+/* ====================================================================
+ * Copyright (c) 1998-2005 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 above 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 acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
 
 #include <stdio.h>
 #include "cryptlib.h"
@@ -320,11 +373,25 @@ static int RSA_eay_private_encrypt(int flen, const unsigned char *from,
                (rsa->dmp1 != NULL) &&
                (rsa->dmq1 != NULL) &&
                (rsa->iqmp != NULL)) )
-               { if (!rsa->meth->rsa_mod_exp(ret,f,rsa,ctx)) goto err; }
+               { 
+               if (!rsa->meth->rsa_mod_exp(ret, f, rsa, ctx)) goto err;
+               }
        else
                {
+               BIGNUM local_d;
+               BIGNUM *d = NULL;
+               
+               if (!(rsa->flags & RSA_FLAG_NO_EXP_CONSTTIME))
+                       {
+                       d = &local_d;
+                       BN_with_flags(d, rsa->d, BN_FLG_EXP_CONSTTIME);
+                       }
+               else
+                       d = rsa->d;
+
                MONT_HELPER(rsa, ctx, n, rsa->flags & RSA_FLAG_CACHE_PUBLIC, goto err);
-               if (!rsa->meth->bn_mod_exp(ret,f,rsa->d,rsa->n,ctx,
+
+               if (!rsa->meth->bn_mod_exp(ret,f,d,rsa->n,ctx,
                                rsa->_method_mod_n)) goto err;
                }
 
@@ -416,13 +483,26 @@ static int RSA_eay_private_decrypt(int flen, const unsigned char *from,
                (rsa->dmp1 != NULL) &&
                (rsa->dmq1 != NULL) &&
                (rsa->iqmp != NULL)) )
-               { if (!rsa->meth->rsa_mod_exp(ret,f,rsa,ctx)) goto err; }
+               {
+               if (!rsa->meth->rsa_mod_exp(ret, f, rsa, ctx)) goto err;
+               }
        else
                {
+               BIGNUM local_d;
+               BIGNUM *d = NULL;
+               
+               if (!(rsa->flags & RSA_FLAG_NO_EXP_CONSTTIME))
+                       {
+                       d = &local_d;
+                       BN_with_flags(d, rsa->d, BN_FLG_EXP_CONSTTIME);
+                       }
+               else
+                       d = rsa->d;
+
                MONT_HELPER(rsa, ctx, n, rsa->flags & RSA_FLAG_CACHE_PUBLIC, goto err);
-               if (!rsa->meth->bn_mod_exp(ret,f,rsa->d,rsa->n,ctx,
+               if (!rsa->meth->bn_mod_exp(ret,f,d,rsa->n,ctx,
                                rsa->_method_mod_n))
-                       goto err;
+                 goto err;
                }
 
        if (blinding)
@@ -547,6 +627,8 @@ err:
 static int RSA_eay_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
        {
        BIGNUM *r1,*m1,*vrfy;
+       BIGNUM local_dmp1, local_dmq1;
+       BIGNUM *dmp1, *dmq1;
        int ret=0;
 
        BN_CTX_start(ctx);
@@ -559,11 +641,25 @@ static int RSA_eay_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
        MONT_HELPER(rsa, ctx, n, rsa->flags & RSA_FLAG_CACHE_PUBLIC, goto err);
 
        if (!BN_mod(r1,I,rsa->q,ctx)) goto err;
-       if (!rsa->meth->bn_mod_exp(m1,r1,rsa->dmq1,rsa->q,ctx,
+       if (!(rsa->flags & RSA_FLAG_NO_EXP_CONSTTIME))
+               {
+               dmq1 = &local_dmq1;
+               BN_with_flags(dmq1, rsa->dmq1, BN_FLG_EXP_CONSTTIME);
+               }
+       else
+               dmq1 = rsa->dmq1;
+       if (!rsa->meth->bn_mod_exp(m1,r1,dmq1,rsa->q,ctx,
                rsa->_method_mod_q)) goto err;
 
        if (!BN_mod(r1,I,rsa->p,ctx)) goto err;
-       if (!rsa->meth->bn_mod_exp(r0,r1,rsa->dmp1,rsa->p,ctx,
+       if (!(rsa->flags & RSA_FLAG_NO_EXP_CONSTTIME))
+               {
+               dmp1 = &local_dmp1;
+               BN_with_flags(dmp1, rsa->dmp1, BN_FLG_EXP_CONSTTIME);
+               }
+       else
+               dmp1 = rsa->dmp1;
+       if (!rsa->meth->bn_mod_exp(r0,r1,dmp1,rsa->p,ctx,
                rsa->_method_mod_p)) goto err;
 
        if (!BN_sub(r0,r0,m1)) goto err;
@@ -598,11 +694,24 @@ static int RSA_eay_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
                if (BN_is_negative(vrfy))
                        if (!BN_add(vrfy, vrfy, rsa->n)) goto err;
                if (!BN_is_zero(vrfy))
+                       {
                        /* 'I' and 'vrfy' aren't congruent mod n. Don't leak
                         * miscalculated CRT output, just do a raw (slower)
                         * mod_exp and return that instead. */
-                       if (!rsa->meth->bn_mod_exp(r0,I,rsa->d,rsa->n,ctx,
-                                       rsa->_method_mod_n)) goto err;
+
+                       BIGNUM local_d;
+                       BIGNUM *d = NULL;
+               
+                       if (!(rsa->flags & RSA_FLAG_NO_EXP_CONSTTIME))
+                               {
+                               d = &local_d;
+                               BN_with_flags(d, rsa->d, BN_FLG_EXP_CONSTTIME);
+                               }
+                       else
+                               d = rsa->d;
+                       if (!rsa->meth->bn_mod_exp(r0,I,d,rsa->n,ctx,
+                                                  rsa->_method_mod_n)) goto err;
+                       }
                }
        ret=1;
 err:
index 6f0a28a..0f8059c 100644 (file)
@@ -228,10 +228,10 @@ int main(int argc, char *argv[])
 
     plen = sizeof(ptext_ex) - 1;
 
-    for (v = 0; v < 3; v++)
+    for (v = 0; v < 6; v++)
        {
        key = RSA_new();
-       switch (v) {
+       switch (v%3) {
     case 0:
        clen = key1(key, ctext_ex);
        break;
@@ -242,6 +242,7 @@ int main(int argc, char *argv[])
        clen = key3(key, ctext_ex);
        break;
        }
+       if (v/3 > 1) key->flags |= RSA_FLAG_NO_EXP_CONSTTIME;
 
        num = RSA_public_encrypt(plen, ptext_ex, ctext, key,
                                 RSA_PKCS1_PADDING);