X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Frand%2Fmd_rand.c;h=6d7f37e15e648c659de7c3d88bf49d95f75bfbe5;hp=837947e8a622c90307c1f12336f987c424cddcaf;hb=daba492c3a461bbcc0df69d609124936a19205f6;hpb=d6ade7422ab60259c1d7b825ee0ff9a5361c7f42;ds=sidebyside diff --git a/crypto/rand/md_rand.c b/crypto/rand/md_rand.c index 837947e8a6..6d7f37e15e 100644 --- a/crypto/rand/md_rand.c +++ b/crypto/rand/md_rand.c @@ -119,7 +119,7 @@ #include #include -#include "openssl/e_os.h" +#include "e_os.h" #include #include "rand_lcl.h" @@ -141,10 +141,12 @@ static long md_count[2]={0,0}; static double entropy=0; static int initialized=0; -/* This should be set to 1 only when ssleay_rand_add() is called inside - an already locked state, so it doesn't try to lock and thereby cause - a hang. And it should always be reset back to 0 before unlocking. */ -static int add_do_not_lock=0; +static unsigned int crypto_lock_rand = 0; /* may be set only when a thread + * holds CRYPTO_LOCK_RAND + * (to prevent double locking) */ +/* access to lockin_thread is synchronized by CRYPTO_LOCK_RAND2 */ +static unsigned long locking_thread = 0; /* valid iff crypto_lock_rand is set */ + #ifdef PREDICT int rand_predictable=0; @@ -182,6 +184,7 @@ static void ssleay_rand_cleanup(void) md_count[0]=0; md_count[1]=0; entropy=0; + initialized=0; } static void ssleay_rand_add(const void *buf, int num, double add) @@ -190,6 +193,7 @@ static void ssleay_rand_add(const void *buf, int num, double add) long md_c[2]; unsigned char local_md[MD_DIGEST_LENGTH]; MD_CTX m; + int do_not_lock; /* * (Based on the rand(3) manpage) @@ -206,7 +210,17 @@ static void ssleay_rand_add(const void *buf, int num, double add) * hash function. */ - if (!add_do_not_lock) CRYPTO_w_lock(CRYPTO_LOCK_RAND); + /* check if we already have the lock */ + if (crypto_lock_rand) + { + CRYPTO_r_lock(CRYPTO_LOCK_RAND2); + do_not_lock = (locking_thread == CRYPTO_thread_id()); + CRYPTO_r_unlock(CRYPTO_LOCK_RAND2); + } + else + do_not_lock = 0; + + if (!do_not_lock) CRYPTO_w_lock(CRYPTO_LOCK_RAND); st_idx=state_index; /* use our own copies of the counters so that even @@ -238,7 +252,7 @@ static void ssleay_rand_add(const void *buf, int num, double add) md_count[1] += (num / MD_DIGEST_LENGTH) + (num % MD_DIGEST_LENGTH > 0); - if (!add_do_not_lock) CRYPTO_w_unlock(CRYPTO_LOCK_RAND); + if (!do_not_lock) CRYPTO_w_unlock(CRYPTO_LOCK_RAND); for (i=0; i state_num) state_index %= state_num; - /* state[st_idx], ..., state[(st_idx + num - 1) % st_num] + /* state[st_idx], ..., state[(st_idx + num_ceil - 1) % st_num] * are now ours (but other threads may use them too) */ md_count[0] += 1; - add_do_not_lock = 0; /* If this would ever be forgotten, we can - expect any evil god to eat our souls. */ + /* before unlocking, we must clear 'crypto_lock_rand' */ + crypto_lock_rand = 0; CRYPTO_w_unlock(CRYPTO_LOCK_RAND); while (num > 0) { + /* num_ceil -= MD_DIGEST_LENGTH/2 */ j=(num >= MD_DIGEST_LENGTH/2)?MD_DIGEST_LENGTH/2:num; num-=j; MD_Init(&m); @@ -433,27 +460,28 @@ static int ssleay_rand_bytes(unsigned char *buf, int num) curr_pid = 0; } #endif - MD_Update(&m,&(local_md[MD_DIGEST_LENGTH/2]),MD_DIGEST_LENGTH/2); + MD_Update(&m,local_md,MD_DIGEST_LENGTH); MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c)); #ifndef PURIFY MD_Update(&m,buf,j); /* purify complains */ #endif - k=(st_idx+j)-st_num; + k=(st_idx+MD_DIGEST_LENGTH/2)-st_num; if (k > 0) { - MD_Update(&m,&(state[st_idx]),j-k); + MD_Update(&m,&(state[st_idx]),MD_DIGEST_LENGTH/2-k); MD_Update(&m,&(state[0]),k); } else - MD_Update(&m,&(state[st_idx]),j); - MD_Final(local_md,&m); + MD_Update(&m,&(state[st_idx]),MD_DIGEST_LENGTH/2); + MD_Final(&m,local_md); - for (i=0; i= st_num) st_idx=0; + if (i < j) + *(buf++)=local_md[i+MD_DIGEST_LENGTH/2]; } } @@ -462,7 +490,7 @@ static int ssleay_rand_bytes(unsigned char *buf, int num) MD_Update(&m,local_md,MD_DIGEST_LENGTH); CRYPTO_w_lock(CRYPTO_LOCK_RAND); MD_Update(&m,md,MD_DIGEST_LENGTH); - MD_Final(md,&m); + MD_Final(&m,md); CRYPTO_w_unlock(CRYPTO_LOCK_RAND); memset(&m,0,sizeof(m)); @@ -481,7 +509,8 @@ static int ssleay_rand_bytes(unsigned char *buf, int num) unpredictable */ static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num) { - int ret, err; + int ret; + unsigned long err; ret = RAND_bytes(buf, num); if (ret == 0) @@ -497,14 +526,45 @@ static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num) static int ssleay_rand_status(void) { int ret; + int do_not_lock; + /* check if we already have the lock + * (could happen if a RAND_poll() implementation calls RAND_status()) */ + if (crypto_lock_rand) + { + CRYPTO_r_lock(CRYPTO_LOCK_RAND2); + do_not_lock = (locking_thread == CRYPTO_thread_id()); + CRYPTO_r_unlock(CRYPTO_LOCK_RAND2); + } + else + do_not_lock = 0; + + if (!do_not_lock) + { + CRYPTO_w_lock(CRYPTO_LOCK_RAND); + + /* prevent ssleay_rand_bytes() from trying to obtain the lock again */ + CRYPTO_w_lock(CRYPTO_LOCK_RAND2); + locking_thread = CRYPTO_thread_id(); + CRYPTO_w_unlock(CRYPTO_LOCK_RAND2); + crypto_lock_rand = 1; + } + if (!initialized) + { RAND_poll(); + initialized = 1; + } - CRYPTO_w_lock(CRYPTO_LOCK_RAND); - initialized = 1; ret = entropy >= ENTROPY_NEEDED; - CRYPTO_w_unlock(CRYPTO_LOCK_RAND); + if (!do_not_lock) + { + /* before unlocking, we must clear 'crypto_lock_rand' */ + crypto_lock_rand = 0; + + CRYPTO_w_unlock(CRYPTO_LOCK_RAND); + } + return ret; }