From ecb1445ce2df51e5310bb58c67c57f7f83ed6a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bodo=20M=C3=B6ller?= Date: Mon, 16 May 2005 01:26:08 +0000 Subject: [PATCH] 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 --- CHANGES | 15 +++ apps/speed.c | 4 +- crypto/bn/bn.h | 17 +++ crypto/bn/bn_err.c | 4 + crypto/bn/bn_exp.c | 244 +++++++++++++++++++++++++++++++++++++++++- crypto/bn/bn_lcl.h | 39 +++++++ crypto/bn/bntest.c | 56 ++++++++++ crypto/bn/expspeed.c | 2 +- crypto/bn/exptest.c | 18 +++- crypto/dh/dh.h | 9 +- crypto/dh/dh_key.c | 27 ++++- crypto/dh/dhtest.c | 4 + crypto/dsa/dsa.h | 7 ++ crypto/dsa/dsa_key.c | 15 ++- crypto/dsa/dsa_ossl.c | 4 + crypto/dsa/dsatest.c | 9 ++ crypto/rsa/rsa.h | 31 +++--- crypto/rsa/rsa_eay.c | 120 +++++++++++++++++++-- crypto/rsa/rsa_test.c | 5 +- util/libeay.num | 1 + 20 files changed, 598 insertions(+), 33 deletions(-) diff --git a/CHANGES b/CHANGES index 82b24f052..b87152a8e 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,21 @@ 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. diff --git a/apps/speed.c b/apps/speed.c index 5ed510ced..2fc327c37 100644 --- a/apps/speed.c +++ b/apps/speed.c @@ -1706,7 +1706,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]); } @@ -1725,7 +1725,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]); } diff --git a/crypto/bn/bn.h b/crypto/bn/bn.h index ad42f2df7..91674afd3 100644 --- a/crypto/bn/bn.h +++ b/crypto/bn/bn.h @@ -225,10 +225,21 @@ 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) */ #define BN_FLG_FREE 0x8000 /* used for debuging */ #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))) + typedef struct bignum_st { BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks. */ @@ -378,6 +389,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, @@ -512,11 +525,15 @@ void ERR_load_BN_strings(void); #define BN_F_BN_CTX_GET 116 #define BN_F_BN_CTX_NEW 106 #define BN_F_BN_DIV 107 +#define BN_F_BN_EXP 123 #define BN_F_BN_EXPAND2 108 #define BN_F_BN_EXPAND_INTERNAL 120 #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 diff --git a/crypto/bn/bn_err.c b/crypto/bn/bn_err.c index 45c523ae2..5dfac00c8 100644 --- a/crypto/bn/bn_err.c +++ b/crypto/bn/bn_err.c @@ -79,11 +79,15 @@ static ERR_STRING_DATA BN_str_functs[]= {ERR_FUNC(BN_F_BN_CTX_GET), "BN_CTX_get"}, {ERR_FUNC(BN_F_BN_CTX_NEW), "BN_CTX_new"}, {ERR_FUNC(BN_F_BN_DIV), "BN_div"}, +{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_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"}, diff --git a/crypto/bn/bn_exp.c b/crypto/bn/bn_exp.c index afdfd580f..9e1e88abe 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); @@ -204,7 +212,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); @@ -234,6 +242,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) @@ -361,6 +376,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); @@ -493,6 +513,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_fix_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_fix_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= 0) + { + wvalue=0; /* The 'value' of the window */ + + /* Scan the window, squaring the result as we go */ + for (i=0; i 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 28cd3339d..685007d33 100644 --- a/crypto/bn/bntest.c +++ b/crypto/bn/bntest.c @@ -86,6 +86,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_kron(BIO *bp,BN_CTX *ctx); int test_sqrt(BIO *bp,BN_CTX *ctx); @@ -213,6 +214,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); @@ -813,6 +818,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 %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 b09cf8870..28aaac2ac 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 05851f842..92c7481e1 100644 --- a/crypto/dh/dh.h +++ b/crypto/dh/dh.h @@ -70,7 +70,14 @@ #include #include -#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 d54a3b111..f7ed790f3 100644 --- a/crypto/dh/dh_key.c +++ b/crypto/dh/dh_key.c @@ -143,8 +143,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; @@ -182,6 +195,11 @@ static int compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) mont = BN_MONT_CTX_set_locked( (BN_MONT_CTX **)&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; } @@ -204,7 +222,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 d75077f9f..b76dede77 100644 --- a/crypto/dh/dhtest.c +++ b/crypto/dh/dhtest.c @@ -136,6 +136,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 225ff391f..925f11cd5 100644 --- a/crypto/dsa/dsa.h +++ b/crypto/dsa/dsa.h @@ -80,6 +80,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. + */ #if defined(OPENSSL_FIPS) #define FIPS_DSA_SIZE_T int diff --git a/crypto/dsa/dsa_key.c b/crypto/dsa/dsa_key.c index 30607ca57..63bd8bff2 100644 --- a/crypto/dsa/dsa_key.c +++ b/crypto/dsa/dsa_key.c @@ -90,8 +90,21 @@ int DSA_generate_key(DSA *dsa) } else pub_key=dsa->pub_key; + + { + BIGNUM local_prk; + BIGNUM *prk; - if (!BN_mod_exp(pub_key,dsa->g,priv_key,dsa->p,ctx)) goto err; + 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,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 a25a29450..e668b079e 100644 --- a/crypto/dsa/dsa_ossl.c +++ b/crypto/dsa/dsa_ossl.c @@ -197,6 +197,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 4734ce4af..55a3756af 100644 --- a/crypto/dsa/dsatest.c +++ b/crypto/dsa/dsatest.c @@ -194,10 +194,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 fc3bb5f86..d18c17ff8 100644 --- a/crypto/rsa/rsa.h +++ b/crypto/rsa/rsa.h @@ -157,28 +157,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_SIGN_VER 0x0040 -#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_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 368ac84f1..4aefd5419 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 #include "cryptlib.h" @@ -314,10 +367,22 @@ 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)) goto err; } + { + if (!rsa->meth->rsa_mod_exp(&ret,&f,rsa)) goto err; + } else { - if (!rsa->meth->bn_mod_exp(&ret,&f,rsa->d,rsa->n,ctx,NULL)) 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(&ret,&f,d,rsa->n,ctx,NULL)) goto err; } if (blinding) @@ -427,10 +492,22 @@ 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)) goto err; } + { + if (!rsa->meth->rsa_mod_exp(&ret,&f,rsa)) goto err; + } else { - if (!rsa->meth->bn_mod_exp(&ret,&f,rsa->d,rsa->n,ctx,NULL)) + 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(&ret,&f,d,rsa->n,ctx,NULL)) goto err; } @@ -561,6 +638,8 @@ err: static int RSA_eay_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa) { BIGNUM r1,m1,vrfy; + BIGNUM local_dmp1, local_dmq1; + BIGNUM *dmp1, *dmq1; int ret=0; BN_CTX *ctx; @@ -580,11 +659,25 @@ static int RSA_eay_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa) } 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; @@ -619,10 +712,23 @@ static int RSA_eay_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa) if (vrfy.neg) 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,NULL)) 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,NULL)) goto err; + } } ret=1; err: diff --git a/crypto/rsa/rsa_test.c b/crypto/rsa/rsa_test.c index 924e9ad1f..218bb2a39 100644 --- a/crypto/rsa/rsa_test.c +++ b/crypto/rsa/rsa_test.c @@ -227,10 +227,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; @@ -241,6 +241,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); diff --git a/util/libeay.num b/util/libeay.num index 96060bd8b..fb25c0c5c 100755 --- a/util/libeay.num +++ b/util/libeay.num @@ -2875,3 +2875,4 @@ EVP_sha224 3314 EXIST::FUNCTION:SHA EVP_sha256 3315 EXIST::FUNCTION:SHA FIPS_selftest_hmac 3316 EXIST:OPENSSL_FIPS:FUNCTION: FIPS_corrupt_rng 3317 EXIST:OPENSSL_FIPS:FUNCTION: +BN_mod_exp_mont_consttime 3318 EXIST::FUNCTION: