X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Frand%2Fmd_rand.c;h=2d6a55f6edfa7739d332933a52f131b7cf6261d1;hp=1c87f2117110e29335a7123af06d20b181730f36;hb=c051e521a7a390a9d61cdb3ae89b3fd69a96e724;hpb=323f289c480b0a8eb15ed3be2befbcc0f86e8904 diff --git a/crypto/rand/md_rand.c b/crypto/rand/md_rand.c index 1c87f21171..2d6a55f6ed 100644 --- a/crypto/rand/md_rand.c +++ b/crypto/rand/md_rand.c @@ -56,7 +56,7 @@ * [including the GNU Public Licence.] */ /* ==================================================================== - * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. + * Copyright (c) 1998-2001 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 @@ -109,6 +109,8 @@ * */ +#define OPENSSL_FIPSAPI + #ifdef MD_RAND_DEBUG # ifndef NDEBUG # define NDEBUG @@ -121,12 +123,23 @@ #include "e_os.h" +#if !(defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYSNAME_DSPBIOS)) +# include +#endif +#if defined(OPENSSL_SYS_VXWORKS) +# include +#endif + +#include #include #include "rand_lcl.h" -#include #include +#ifdef OPENSSL_FIPS +#include +#endif + #ifdef BN_DEBUG # define PREDICT #endif @@ -144,25 +157,27 @@ static int initialized=0; static unsigned int crypto_lock_rand = 0; /* may be set only when a thread * holds CRYPTO_LOCK_RAND * (to prevent double locking) */ -static unsigned long locking_thread = 0; /* valid iff crypto_lock_rand is set */ +/* access to lockin_thread is synchronized by CRYPTO_LOCK_RAND2 */ +static CRYPTO_THREADID locking_threadid; /* valid iff crypto_lock_rand is set */ #ifdef PREDICT int rand_predictable=0; #endif -const char *RAND_version="RAND" OPENSSL_VERSION_PTEXT; +const char RAND_version[]="RAND" OPENSSL_VERSION_PTEXT; static void ssleay_rand_cleanup(void); -static void ssleay_rand_seed(const void *buf, int num); -static void ssleay_rand_add(const void *buf, int num, double add_entropy); -static int ssleay_rand_bytes(unsigned char *buf, int num); +static int ssleay_rand_seed(const void *buf, int num); +static int ssleay_rand_add(const void *buf, int num, double add_entropy); +static int ssleay_rand_bytes(unsigned char *buf, int num, int pseudo); +static int ssleay_rand_nopseudo_bytes(unsigned char *buf, int num); static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num); static int ssleay_rand_status(void); -RAND_METHOD rand_ssleay_meth={ +static RAND_METHOD rand_ssleay_meth={ ssleay_rand_seed, - ssleay_rand_bytes, + ssleay_rand_nopseudo_bytes, ssleay_rand_cleanup, ssleay_rand_add, ssleay_rand_pseudo_bytes, @@ -176,23 +191,24 @@ RAND_METHOD *RAND_SSLeay(void) static void ssleay_rand_cleanup(void) { - memset(state,0,sizeof(state)); + OPENSSL_cleanse(state,sizeof(state)); state_num=0; state_index=0; - memset(md,0,MD_DIGEST_LENGTH); + OPENSSL_cleanse(md,MD_DIGEST_LENGTH); md_count[0]=0; md_count[1]=0; entropy=0; initialized=0; } -static void ssleay_rand_add(const void *buf, int num, double add) +static int ssleay_rand_add(const void *buf, int num, double add) { int i,j,k,st_idx; long md_c[2]; unsigned char local_md[MD_DIGEST_LENGTH]; - MD_CTX m; + EVP_MD_CTX m; int do_not_lock; + int rv = 0; /* * (Based on the rand(3) manpage) @@ -209,8 +225,18 @@ static void ssleay_rand_add(const void *buf, int num, double add) * hash function. */ + EVP_MD_CTX_init(&m); /* check if we already have the lock */ - do_not_lock = crypto_lock_rand && (locking_thread == CRYPTO_thread_id()); + if (crypto_lock_rand) + { + CRYPTO_THREADID cur; + CRYPTO_THREADID_current(&cur); + CRYPTO_r_lock(CRYPTO_LOCK_RAND2); + do_not_lock = !CRYPTO_THREADID_cmp(&locking_threadid, &cur); + 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; @@ -251,20 +277,36 @@ static void ssleay_rand_add(const void *buf, int num, double add) j=(num-i); j=(j > MD_DIGEST_LENGTH)?MD_DIGEST_LENGTH:j; - MD_Init(&m); - MD_Update(&m,local_md,MD_DIGEST_LENGTH); + if (!MD_Init(&m)) + goto err; + if (!MD_Update(&m,local_md,MD_DIGEST_LENGTH)) + goto err; k=(st_idx+j)-STATE_SIZE; if (k > 0) { - MD_Update(&m,&(state[st_idx]),j-k); - MD_Update(&m,&(state[0]),k); + if (!MD_Update(&m,&(state[st_idx]),j-k)) + goto err; + if (!MD_Update(&m,&(state[0]),k)) + goto err; } else - MD_Update(&m,&(state[st_idx]),j); - - MD_Update(&m,buf,j); - MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c)); - MD_Final(&m,local_md); + if (!MD_Update(&m,&(state[st_idx]),j)) + goto err; + + /* DO NOT REMOVE THE FOLLOWING CALL TO MD_Update()! */ + if (!MD_Update(&m,buf,j)) + goto err; + /* We know that line may cause programs such as + purify and valgrind to complain about use of + uninitialized data. The problem is not, it's + with the caller. Removing that line will make + sure you get really bad randomness and thereby + other problems such as very insecure keys. */ + + if (!MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c))) + goto err; + if (!MD_Final(&m,local_md)) + goto err; md_c[1]++; buf=(const char *)buf + j; @@ -284,14 +326,13 @@ static void ssleay_rand_add(const void *buf, int num, double add) st_idx=0; } } - memset((char *)&m,0,sizeof(m)); if (!do_not_lock) CRYPTO_w_lock(CRYPTO_LOCK_RAND); /* Don't just copy back local_md into md -- this could mean that * other thread's seeding remains without effect (except for * the incremented counter). By XORing it we keep at least as * much entropy as fits into md. */ - for (k = 0; k < sizeof md; k++) + for (k = 0; k < (int)sizeof(md); k++) { md[k] ^= local_md[k]; } @@ -302,25 +343,51 @@ static void ssleay_rand_add(const void *buf, int num, double add) #if !defined(OPENSSL_THREADS) && !defined(OPENSSL_SYS_WIN32) assert(md_c[1] == md_count[1]); #endif + rv = 1; + err: + EVP_MD_CTX_cleanup(&m); + return rv; } -static void ssleay_rand_seed(const void *buf, int num) +static int ssleay_rand_seed(const void *buf, int num) { - ssleay_rand_add(buf, num, num); + return ssleay_rand_add(buf, num, (double)num); } -static int ssleay_rand_bytes(unsigned char *buf, int num) +static int ssleay_rand_bytes(unsigned char *buf, int num, int pseudo) { static volatile int stirred_pool = 0; int i,j,k,st_num,st_idx; + int num_ceil; int ok; long md_c[2]; unsigned char local_md[MD_DIGEST_LENGTH]; - MD_CTX m; + EVP_MD_CTX m; #ifndef GETPID_IS_MEANINGLESS pid_t curr_pid = getpid(); #endif + time_t curr_time = time(NULL); int do_stir_pool = 0; +/* time value for various platforms */ +#ifdef OPENSSL_SYS_WIN32 + FILETIME tv; +# ifdef _WIN32_WCE + SYSTEMTIME t; + GetSystemTime(&t); + SystemTimeToFileTime(&t, &tv); +# else + GetSystemTimeAsFileTime(&tv); +# endif +#elif defined(OPENSSL_SYS_VXWORKS) + struct timespec tv; + clock_gettime(CLOCK_REALTIME, &ts); +#elif defined(OPENSSL_SYSNAME_DSPBIOS) + unsigned long long tv, OPENSSL_rdtsc(); + tv = OPENSSL_rdtsc(); +#else + struct timeval tv; + gettimeofday(&tv, NULL); +#endif #ifdef PREDICT if (rand_predictable) @@ -333,19 +400,25 @@ static int ssleay_rand_bytes(unsigned char *buf, int num) } #endif + if (num <= 0) + return 1; + + EVP_MD_CTX_init(&m); + /* round upwards to multiple of MD_DIGEST_LENGTH/2 */ + num_ceil = (1 + (num-1)/(MD_DIGEST_LENGTH/2)) * (MD_DIGEST_LENGTH/2); + /* * (Based on the rand(3) manpage:) * * For each group of 10 bytes (or less), we do the following: * - * Input into the hash function the top 10 bytes from the - * local 'md' (which is initialized from the global 'md' - * before any bytes are generated), the bytes that are - * to be overwritten by the random bytes, and bytes from the - * 'state' (incrementing looping index). From this digest output - * (which is kept in 'md'), the top (up to) 10 bytes are - * returned to the caller and the bottom (up to) 10 bytes are xored - * into the 'state'. + * Input into the hash function the local 'md' (which is initialized from + * the global 'md' before any bytes are generated), the bytes that are to + * be overwritten by the random bytes, and bytes from the 'state' + * (incrementing looping index). From this digest output (which is kept + * in 'md'), the top (up to) 10 bytes are returned to the caller and the + * bottom 10 bytes are xored into the 'state'. + * * Finally, after we have finished 'num' random bytes for the * caller, 'count' (which is incremented) and the local and global 'md' * are fed into the hash function and the results are kept in the @@ -355,8 +428,10 @@ static int ssleay_rand_bytes(unsigned char *buf, int num) CRYPTO_w_lock(CRYPTO_LOCK_RAND); /* prevent ssleay_rand_bytes() from trying to obtain the lock again */ + CRYPTO_w_lock(CRYPTO_LOCK_RAND2); + CRYPTO_THREADID_current(&locking_threadid); + CRYPTO_w_unlock(CRYPTO_LOCK_RAND2); crypto_lock_rand = 1; - locking_thread = CRYPTO_thread_id(); if (!initialized) { @@ -389,11 +464,11 @@ static int ssleay_rand_bytes(unsigned char *buf, int num) if (do_stir_pool) { - /* Our output function chains only half of 'md', so we better - * make sure that the required entropy gets 'evenly distributed' - * through 'state', our randomness pool. The input function - * (ssleay_rand_add) chains all of 'md', which makes it more - * suitable for this purpose. + /* In the output function only half of 'md' remains secret, + * so we better make sure that the required entropy gets + * 'evenly distributed' through 'state', our randomness pool. + * The input function (ssleay_rand_add) chains all of 'md', + * which makes it more suitable for this purpose. */ int n = STATE_SIZE; /* so that the complete pool gets accessed */ @@ -418,110 +493,156 @@ static int ssleay_rand_bytes(unsigned char *buf, int num) md_c[1] = md_count[1]; memcpy(local_md, md, sizeof md); - state_index+=num; + state_index+=num_ceil; if (state_index > 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; /* before unlocking, we must clear 'crypto_lock_rand' */ crypto_lock_rand = 0; - locking_thread = 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); + if (!MD_Init(&m)) + goto err; #ifndef GETPID_IS_MEANINGLESS if (curr_pid) /* just in the first iteration to save time */ { - MD_Update(&m,(unsigned char*)&curr_pid,sizeof curr_pid); + if (!MD_Update(&m,(unsigned char*)&curr_pid, + sizeof curr_pid)) + goto err; curr_pid = 0; } #endif - MD_Update(&m,&(local_md[MD_DIGEST_LENGTH/2]),MD_DIGEST_LENGTH/2); - MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c)); -#ifndef PURIFY - MD_Update(&m,buf,j); /* purify complains */ + if (curr_time) /* just in the first iteration to save time */ + { + if (!MD_Update(&m,(unsigned char*)&curr_time, + sizeof curr_time)) + goto err; + if (!MD_Update(&m,(unsigned char*)&tv, + sizeof tv)) + goto err; + curr_time = 0; + } + if (!MD_Update(&m,local_md,MD_DIGEST_LENGTH)) + goto err; + if (!MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c))) + goto err; + +#ifndef PURIFY /* purify complains */ + /* The following line uses the supplied buffer as a small + * source of entropy: since this buffer is often uninitialised + * it may cause programs such as purify or valgrind to + * complain. So for those builds it is not used: the removal + * of such a small source of entropy has negligible impact on + * security. + */ + if (!MD_Update(&m,buf,j)) + goto err; #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[0]),k); + if (!MD_Update(&m,&(state[st_idx]),MD_DIGEST_LENGTH/2-k)) + goto err; + if (!MD_Update(&m,&(state[0]),k)) + goto err; } else - MD_Update(&m,&(state[st_idx]),j); - MD_Final(&m,local_md); + if (!MD_Update(&m,&(state[st_idx]),MD_DIGEST_LENGTH/2)) + goto err; + if (!MD_Final(&m,local_md)) + goto err; - for (i=0; i= st_num) st_idx=0; + if (i < j) + *(buf++)=local_md[i+MD_DIGEST_LENGTH/2]; } } - MD_Init(&m); - MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c)); - MD_Update(&m,local_md,MD_DIGEST_LENGTH); + if (!MD_Init(&m) + || !MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c)) + || !MD_Update(&m,local_md,MD_DIGEST_LENGTH)) + goto err; CRYPTO_w_lock(CRYPTO_LOCK_RAND); - MD_Update(&m,md,MD_DIGEST_LENGTH); - MD_Final(&m,md); + if (!MD_Update(&m,md,MD_DIGEST_LENGTH) || !MD_Final(&m,md)) + { + CRYPTO_w_unlock(CRYPTO_LOCK_RAND); + goto err; + } CRYPTO_w_unlock(CRYPTO_LOCK_RAND); - memset(&m,0,sizeof(m)); + EVP_MD_CTX_cleanup(&m); if (ok) return(1); - else + else if (pseudo) + return 0; + else { RANDerr(RAND_F_SSLEAY_RAND_BYTES,RAND_R_PRNG_NOT_SEEDED); ERR_add_error_data(1, "You need to read the OpenSSL FAQ, " "http://www.openssl.org/support/faq.html"); return(0); } + err: + EVP_MD_CTX_cleanup(&m); + RANDerr(RAND_F_SSLEAY_RAND_BYTES,ERR_R_EVP_LIB); + return 0; + + } + +static int ssleay_rand_nopseudo_bytes(unsigned char *buf, int num) + { + return ssleay_rand_bytes(buf, num, 0); } /* pseudo-random bytes that are guaranteed to be unique but not unpredictable */ static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num) { - int ret; - unsigned long err; - - ret = RAND_bytes(buf, num); - if (ret == 0) - { - err = ERR_peek_error(); - if (ERR_GET_LIB(err) == ERR_LIB_RAND && - ERR_GET_REASON(err) == RAND_R_PRNG_NOT_SEEDED) - (void)ERR_get_error(); - } - return (ret); + return ssleay_rand_bytes(buf, num, 1); } static int ssleay_rand_status(void) { + CRYPTO_THREADID cur; int ret; int do_not_lock; + CRYPTO_THREADID_current(&cur); /* check if we already have the lock * (could happen if a RAND_poll() implementation calls RAND_status()) */ - do_not_lock = crypto_lock_rand && (locking_thread == CRYPTO_thread_id()); + if (crypto_lock_rand) + { + CRYPTO_r_lock(CRYPTO_LOCK_RAND2); + do_not_lock = !CRYPTO_THREADID_cmp(&locking_threadid, &cur); + 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); + CRYPTO_THREADID_cpy(&locking_threadid, &cur); + CRYPTO_w_unlock(CRYPTO_LOCK_RAND2); crypto_lock_rand = 1; - locking_thread = CRYPTO_thread_id(); } if (!initialized) @@ -536,7 +657,6 @@ static int ssleay_rand_status(void) { /* before unlocking, we must clear 'crypto_lock_rand' */ crypto_lock_rand = 0; - locking_thread = 0; CRYPTO_w_unlock(CRYPTO_LOCK_RAND); }