summaryrefslogtreecommitdiff
path: root/crypto
diff options
context:
space:
mode:
authorBodo Möller <bodo@openssl.org>2005-05-16 01:43:31 +0000
committerBodo Möller <bodo@openssl.org>2005-05-16 01:43:31 +0000
commit46a643763de6d8e39ecf6f76fa79b4d04885aa59 (patch)
treee1f3cfc98bddba797b5300977dbf3223f008fc4a /crypto
parent92c44685724c0d993ea8920577680f3c0a1d79c8 (diff)
downloadopenssl-new-46a643763de6d8e39ecf6f76fa79b4d04885aa59.tar.gz
Implement fixed-window exponentiation to mitigate hyper-threading
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
Diffstat (limited to 'crypto')
-rw-r--r--crypto/bn/bn.h44
-rw-r--r--crypto/bn/bn_err.c7
-rw-r--r--crypto/bn/bn_exp.c244
-rw-r--r--crypto/bn/bn_lcl.h39
-rw-r--r--crypto/bn/bntest.c56
-rw-r--r--crypto/bn/expspeed.c2
-rw-r--r--crypto/bn/exptest.c18
-rw-r--r--crypto/dh/dh.h9
-rw-r--r--crypto/dh/dh_key.c27
-rw-r--r--crypto/dh/dhtest.c4
-rw-r--r--crypto/dsa/dsa.h7
-rw-r--r--crypto/dsa/dsa_key.c15
-rw-r--r--crypto/dsa/dsa_ossl.c4
-rw-r--r--crypto/dsa/dsatest.c9
-rw-r--r--crypto/rsa/rsa.h33
-rw-r--r--crypto/rsa/rsa_eay.c127
-rw-r--r--crypto/rsa/rsa_test.c5
17 files changed, 600 insertions, 50 deletions
diff --git a/crypto/bn/bn.h b/crypto/bn/bn.h
index 99faf8f07e..6d52735207 100644
--- a/crypto/bn/bn.h
+++ b/crypto/bn/bn.h
@@ -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
diff --git a/crypto/bn/bn_err.c b/crypto/bn/bn_err.c
index 58a7d0617f..a253959a5c 100644
--- a/crypto/bn/bn_err.c
+++ b/crypto/bn/bn_err.c
@@ -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"},
diff --git a/crypto/bn/bn_exp.c b/crypto/bn/bn_exp.c
index d6bb2b4397..8f8c694481 100644
--- a/crypto/bn/bn_exp.c
+++ b/crypto/bn/bn_exp.c
@@ -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
@@ -113,6 +113,7 @@
#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)
diff --git a/crypto/bn/bn_lcl.h b/crypto/bn/bn_lcl.h
index 45e19221aa..1c680fc3ce 100644
--- a/crypto/bn/bn_lcl.h
+++ b/crypto/bn/bn_lcl.h
@@ -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 */
diff --git a/crypto/bn/bntest.c b/crypto/bn/bntest.c
index 9169cc8813..c885300a66 100644
--- a/crypto/bn/bntest.c
+++ b/crypto/bn/bntest.c
@@ -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;
diff --git a/crypto/bn/expspeed.c b/crypto/bn/expspeed.c
index 07a1bcf51c..4d5f221f33 100644
--- a/crypto/bn/expspeed.c
+++ b/crypto/bn/expspeed.c
@@ -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
diff --git a/crypto/bn/exptest.c b/crypto/bn/exptest.c
index 37aec55b89..f598a07cf5 100644
--- a/crypto/bn/exptest.c
+++ b/crypto/bn/exptest.c
@@ -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);
diff --git a/crypto/dh/dh.h b/crypto/dh/dh.h
index da44778b58..d1559fd4f8 100644
--- a/crypto/dh/dh.h
+++ b/crypto/dh/dh.h
@@ -73,7 +73,14 @@
#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" {
diff --git a/crypto/dh/dh_key.c b/crypto/dh/dh_key.c
index 9148f179f7..e384286c73 100644
--- a/crypto/dh/dh_key.c
+++ b/crypto/dh/dh_key.c
@@ -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);
diff --git a/crypto/dh/dhtest.c b/crypto/dh/dhtest.c
index 1b193649d3..882f5c310a 100644
--- a/crypto/dh/dhtest.c
+++ b/crypto/dh/dhtest.c
@@ -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);
diff --git a/crypto/dsa/dsa.h b/crypto/dsa/dsa.h
index c7ba059f25..b12db98b13 100644
--- a/crypto/dsa/dsa.h
+++ b/crypto/dsa/dsa.h
@@ -85,6 +85,13 @@
#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" {
diff --git a/crypto/dsa/dsa_key.c b/crypto/dsa/dsa_key.c
index 8427b77970..5ba885e1e2 100644
--- a/crypto/dsa/dsa_key.c
+++ b/crypto/dsa/dsa_key.c
@@ -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;
diff --git a/crypto/dsa/dsa_ossl.c b/crypto/dsa/dsa_ossl.c
index 25cd8484aa..2e5ede7826 100644
--- a/crypto/dsa/dsa_ossl.c
+++ b/crypto/dsa/dsa_ossl.c
@@ -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)
{
diff --git a/crypto/dsa/dsatest.c b/crypto/dsa/dsatest.c
index ccc456eab7..66ff417398 100644
--- a/crypto/dsa/dsatest.c
+++ b/crypto/dsa/dsatest.c
@@ -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);
diff --git a/crypto/rsa/rsa.h b/crypto/rsa/rsa.h
index f8bcbc3b8d..dcefebad21 100644
--- a/crypto/rsa/rsa.h
+++ b/crypto/rsa/rsa.h
@@ -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
diff --git a/crypto/rsa/rsa_eay.c b/crypto/rsa/rsa_eay.c
index 21755c0e2f..175ab8a789 100644
--- a/crypto/rsa/rsa_eay.c
+++ b/crypto/rsa/rsa_eay.c
@@ -55,6 +55,59 @@
* 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:
diff --git a/crypto/rsa/rsa_test.c b/crypto/rsa/rsa_test.c
index 6f0a28aa25..0f8059ccfd 100644
--- a/crypto/rsa/rsa_test.c
+++ b/crypto/rsa/rsa_test.c
@@ -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);