make RSA blinding thread-safe

This commit is contained in:
Bodo Möller 2003-04-02 09:50:17 +00:00
parent 60511b8bb8
commit 223c80ea7d
7 changed files with 128 additions and 14 deletions

View File

@ -14,12 +14,17 @@
to avoid a timing attack. Applications that don't want it can call to avoid a timing attack. Applications that don't want it can call
RSA_blinding_off() or use the new flag RSA_FLAG_NO_BLINDING. RSA_blinding_off() or use the new flag RSA_FLAG_NO_BLINDING.
They would be ill-advised to do so in most cases. They would be ill-advised to do so in most cases.
[Ben Laurie, Steve Henson, Geoff Thorpe] [Ben Laurie, Steve Henson, Geoff Thorpe, Bodo Moeller]
*) Change RSA blinding code so that it works when the PRNG is not *) Change RSA blinding code so that it works when the PRNG is not
seeded (in this case, the secret RSA exponent is abused as seeded (in this case, the secret RSA exponent is abused as
an unpredictable seed -- if it is not unpredictable, there an unpredictable seed -- if it is not unpredictable, there
is no point in blinding anyway). is no point in blinding anyway). Make RSA blinding thread-safe
by remembering the creator's thread ID in rsa->blinding and
having all other threads use local one-time blinding factors
(this requires more computation than sharing rsa->blinding, but
avoids excessive locking; and if an RSA object is not shared
between threads, blinding will still be very fast).
[Bodo Moeller] [Bodo Moeller]
Changes between 0.9.6h and 0.9.6i [19 Feb 2003] Changes between 0.9.6h and 0.9.6i [19 Feb 2003]

View File

@ -259,6 +259,8 @@ typedef struct bn_blinding_st
BIGNUM *A; BIGNUM *A;
BIGNUM *Ai; BIGNUM *Ai;
BIGNUM *mod; /* just a reference */ BIGNUM *mod; /* just a reference */
unsigned long thread_id; /* added in OpenSSL 0.9.6j and 0.9.7b;
* used only by crypto/rsa/rsa_eay.c, rsa_lib.c */
} BN_BLINDING; } BN_BLINDING;
/* Used for montgomery multiplication */ /* Used for montgomery multiplication */

View File

@ -336,6 +336,7 @@ void ERR_load_RSA_strings(void);
#define RSA_R_DMP1_NOT_CONGRUENT_TO_D 124 #define RSA_R_DMP1_NOT_CONGRUENT_TO_D 124
#define RSA_R_DMQ1_NOT_CONGRUENT_TO_D 125 #define RSA_R_DMQ1_NOT_CONGRUENT_TO_D 125
#define RSA_R_D_E_NOT_CONGRUENT_TO_1 123 #define RSA_R_D_E_NOT_CONGRUENT_TO_1 123
#define RSA_R_INTERNAL_ERROR 133
#define RSA_R_INVALID_MESSAGE_LENGTH 131 #define RSA_R_INVALID_MESSAGE_LENGTH 131
#define RSA_R_IQMP_NOT_INVERSE_OF_Q 126 #define RSA_R_IQMP_NOT_INVERSE_OF_Q 126
#define RSA_R_KEY_SIZE_TOO_SMALL 120 #define RSA_R_KEY_SIZE_TOO_SMALL 120

View File

@ -209,6 +209,40 @@ static int rsa_eay_blinding(RSA *rsa, BN_CTX *ctx)
err_instr \ err_instr \
} while(0) } while(0)
static BN_BLINDING *setup_blinding(RSA *rsa, BN_CTX *ctx)
{
BIGNUM *A, *Ai;
BN_BLINDING *ret = NULL;
/* added in OpenSSL 0.9.6j and 0.9.7b */
/* NB: similar code appears in RSA_blinding_on (rsa_lib.c);
* this should be placed in a new function of its own, but for reasons
* of binary compatibility can't */
BN_CTX_start(ctx);
A = BN_CTX_get(ctx);
if ((RAND_status() == 0) && rsa->d != NULL && rsa->d->d != NULL)
{
/* if PRNG is not properly seeded, resort to secret exponent as unpredictable seed */
RAND_add(rsa->d->d, rsa->d->dmax * sizeof rsa->d->d[0], 0);
if (!BN_pseudo_rand_range(A,rsa->n)) goto err;
}
else
{
if (!BN_rand_range(A,rsa->n)) goto err;
}
if ((Ai=BN_mod_inverse(NULL,A,rsa->n,ctx)) == NULL) goto err;
if (!rsa->meth->bn_mod_exp(A,A,rsa->e,rsa->n,ctx,rsa->_method_mod_n))
goto err;
ret = BN_BLINDING_new(A,Ai,rsa->n);
BN_free(Ai);
err:
BN_CTX_end(ctx);
return ret;
}
/* signing */ /* signing */
static int RSA_eay_private_encrypt(int flen, unsigned char *from, static int RSA_eay_private_encrypt(int flen, unsigned char *from,
unsigned char *to, RSA *rsa, int padding) unsigned char *to, RSA *rsa, int padding)
@ -217,6 +251,8 @@ static int RSA_eay_private_encrypt(int flen, unsigned char *from,
int i,j,k,num=0,r= -1; int i,j,k,num=0,r= -1;
unsigned char *buf=NULL; unsigned char *buf=NULL;
BN_CTX *ctx=NULL; BN_CTX *ctx=NULL;
int local_blinding = 0;
BN_BLINDING *blinding = NULL;
BN_init(&f); BN_init(&f);
BN_init(&ret); BN_init(&ret);
@ -254,9 +290,38 @@ static int RSA_eay_private_encrypt(int flen, unsigned char *from,
} }
BLINDING_HELPER(rsa, ctx, goto err;); BLINDING_HELPER(rsa, ctx, goto err;);
blinding = rsa->blinding;
/* Now unless blinding is disabled, 'blinding' is non-NULL.
* But the BN_BLINDING object may be owned by some other thread
* (we don't want to keep it constant and we don't want to use
* lots of locking to avoid race conditions, so only a single
* thread can use it; other threads have to use local blinding
* factors) */
if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) if (!(rsa->flags & RSA_FLAG_NO_BLINDING))
if (!BN_BLINDING_convert(&f,rsa->blinding,ctx)) goto err; {
if (blinding == NULL)
{
RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_INTERNAL_ERROR);
goto err;
}
}
if (blinding != NULL)
{
if (blinding->thread_id != CRYPTO_thread_id())
{
/* we need a local one-time blinding factor */
blinding = setup_blinding(rsa, ctx);
if (blinding == NULL)
goto err;
local_blinding = 1;
}
}
if (blinding)
if (!BN_BLINDING_convert(&f, blinding, ctx)) goto err;
if ( (rsa->flags & RSA_FLAG_EXT_PKEY) || if ( (rsa->flags & RSA_FLAG_EXT_PKEY) ||
((rsa->p != NULL) && ((rsa->p != NULL) &&
@ -270,8 +335,8 @@ static int RSA_eay_private_encrypt(int flen, unsigned char *from,
if (!rsa->meth->bn_mod_exp(&ret,&f,rsa->d,rsa->n,ctx,NULL)) goto err; if (!rsa->meth->bn_mod_exp(&ret,&f,rsa->d,rsa->n,ctx,NULL)) goto err;
} }
if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) if (blinding)
if (!BN_BLINDING_invert(&ret,rsa->blinding,ctx)) goto err; if (!BN_BLINDING_invert(&ret, blinding, ctx)) goto err;
/* put in leading 0 bytes if the number is less than the /* put in leading 0 bytes if the number is less than the
* length of the modulus */ * length of the modulus */
@ -285,6 +350,8 @@ err:
if (ctx != NULL) BN_CTX_free(ctx); if (ctx != NULL) BN_CTX_free(ctx);
BN_clear_free(&ret); BN_clear_free(&ret);
BN_clear_free(&f); BN_clear_free(&f);
if (local_blinding)
BN_BLINDING_free(blinding);
if (buf != NULL) if (buf != NULL)
{ {
OPENSSL_cleanse(buf,num); OPENSSL_cleanse(buf,num);
@ -301,6 +368,8 @@ static int RSA_eay_private_decrypt(int flen, unsigned char *from,
unsigned char *p; unsigned char *p;
unsigned char *buf=NULL; unsigned char *buf=NULL;
BN_CTX *ctx=NULL; BN_CTX *ctx=NULL;
int local_blinding = 0;
BN_BLINDING *blinding = NULL;
BN_init(&f); BN_init(&f);
BN_init(&ret); BN_init(&ret);
@ -333,9 +402,38 @@ static int RSA_eay_private_decrypt(int flen, unsigned char *from,
} }
BLINDING_HELPER(rsa, ctx, goto err;); BLINDING_HELPER(rsa, ctx, goto err;);
blinding = rsa->blinding;
/* Now unless blinding is disabled, 'blinding' is non-NULL.
* But the BN_BLINDING object may be owned by some other thread
* (we don't want to keep it constant and we don't want to use
* lots of locking to avoid race conditions, so only a single
* thread can use it; other threads have to use local blinding
* factors) */
if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) if (!(rsa->flags & RSA_FLAG_NO_BLINDING))
if (!BN_BLINDING_convert(&f,rsa->blinding,ctx)) goto err; {
if (blinding == NULL)
{
RSAerr(RSA_F_RSA_EAY_PRIVATE_DECRYPT, RSA_R_INTERNAL_ERROR);
goto err;
}
}
if (blinding != NULL)
{
if (blinding->thread_id != CRYPTO_thread_id())
{
/* we need a local one-time blinding factor */
blinding = setup_blinding(rsa, ctx);
if (blinding == NULL)
goto err;
local_blinding = 1;
}
}
if (blinding)
if (!BN_BLINDING_convert(&f, blinding, ctx)) goto err;
/* do the decrypt */ /* do the decrypt */
if ( (rsa->flags & RSA_FLAG_EXT_PKEY) || if ( (rsa->flags & RSA_FLAG_EXT_PKEY) ||
@ -351,8 +449,8 @@ static int RSA_eay_private_decrypt(int flen, unsigned char *from,
goto err; goto err;
} }
if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) if (blinding)
if (!BN_BLINDING_invert(&ret,rsa->blinding,ctx)) goto err; if (!BN_BLINDING_invert(&ret, blinding, ctx)) goto err;
p=buf; p=buf;
j=BN_bn2bin(&ret,p); /* j is only used with no-padding mode */ j=BN_bn2bin(&ret,p); /* j is only used with no-padding mode */

View File

@ -1,6 +1,6 @@
/* crypto/rsa/rsa_err.c */ /* crypto/rsa/rsa_err.c */
/* ==================================================================== /* ====================================================================
* Copyright (c) 1999 The OpenSSL Project. All rights reserved. * Copyright (c) 1999-2003 The OpenSSL Project. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -113,6 +113,7 @@ static ERR_STRING_DATA RSA_str_reasons[]=
{RSA_R_DMP1_NOT_CONGRUENT_TO_D ,"dmp1 not congruent to d"}, {RSA_R_DMP1_NOT_CONGRUENT_TO_D ,"dmp1 not congruent to d"},
{RSA_R_DMQ1_NOT_CONGRUENT_TO_D ,"dmq1 not congruent to d"}, {RSA_R_DMQ1_NOT_CONGRUENT_TO_D ,"dmq1 not congruent to d"},
{RSA_R_D_E_NOT_CONGRUENT_TO_1 ,"d e not congruent to 1"}, {RSA_R_D_E_NOT_CONGRUENT_TO_1 ,"d e not congruent to 1"},
{RSA_R_INTERNAL_ERROR ,"internal error"},
{RSA_R_INVALID_MESSAGE_LENGTH ,"invalid message length"}, {RSA_R_INVALID_MESSAGE_LENGTH ,"invalid message length"},
{RSA_R_IQMP_NOT_INVERSE_OF_Q ,"iqmp not inverse of q"}, {RSA_R_IQMP_NOT_INVERSE_OF_Q ,"iqmp not inverse of q"},
{RSA_R_KEY_SIZE_TOO_SMALL ,"key size too small"}, {RSA_R_KEY_SIZE_TOO_SMALL ,"key size too small"},

View File

@ -273,6 +273,10 @@ int RSA_blinding_on(RSA *rsa, BN_CTX *p_ctx)
if (rsa->blinding != NULL) if (rsa->blinding != NULL)
BN_BLINDING_free(rsa->blinding); BN_BLINDING_free(rsa->blinding);
/* NB: similar code appears in setup_blinding (rsa_eay.c);
* this should be placed in a new function of its own, but for reasons
* of binary compatibility can't */
BN_CTX_start(ctx); BN_CTX_start(ctx);
A = BN_CTX_get(ctx); A = BN_CTX_get(ctx);
if ((RAND_status() == 0) && rsa->d != NULL && rsa->d->d != NULL) if ((RAND_status() == 0) && rsa->d != NULL && rsa->d->d != NULL)
@ -289,7 +293,10 @@ int RSA_blinding_on(RSA *rsa, BN_CTX *p_ctx)
if (!rsa->meth->bn_mod_exp(A,A,rsa->e,rsa->n,ctx,rsa->_method_mod_n)) if (!rsa->meth->bn_mod_exp(A,A,rsa->e,rsa->n,ctx,rsa->_method_mod_n))
goto err; goto err;
rsa->blinding=BN_BLINDING_new(A,Ai,rsa->n); if ((rsa->blinding=BN_BLINDING_new(A,Ai,rsa->n)) == NULL) goto err;
/* to make things thread-safe without excessive locking,
* rsa->blinding will be used just by the current thread: */
rsa->blinding->thread_id = CRYPTO_thread_id();
rsa->flags |= RSA_FLAG_BLINDING; rsa->flags |= RSA_FLAG_BLINDING;
rsa->flags &= ~RSA_FLAG_NO_BLINDING; rsa->flags &= ~RSA_FLAG_NO_BLINDING;
BN_free(Ai); BN_free(Ai);

View File

@ -320,7 +320,7 @@ EOF
print OUT <<"EOF"; print OUT <<"EOF";
/* $cfile */ /* $cfile */
/* ==================================================================== /* ====================================================================
* Copyright (c) 1999-2002 The OpenSSL Project. All rights reserved. * Copyright (c) 1999-2003 The OpenSSL Project. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions