From 46a643763de6d8e39ecf6f76fa79b4d04885aa59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bodo=20M=C3=B6ller?= Date: Mon, 16 May 2005 01:43:31 +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 | 44 +++++--- crypto/bn/bn_err.c | 7 +- 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 | 33 +++--- crypto/rsa/rsa_eay.c | 127 ++++++++++++++++++++-- crypto/rsa/rsa_test.c | 5 +- 19 files changed, 617 insertions(+), 52 deletions(-) diff --git a/CHANGES b/CHANGES index cd3dba144e..54df558352 100644 --- a/CHANGES +++ b/CHANGES @@ -799,6 +799,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 bd5b217b57..2ecbb1e9c6 100644 --- a/apps/speed.c +++ b/apps/speed.c @@ -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]); } 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= 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 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 %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 #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 #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); -- GitLab