Improve PRNG robustness.
This commit is contained in:
		
							
								
								
									
										13
									
								
								CHANGES
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								CHANGES
									
									
									
									
									
								
							| @@ -4,6 +4,19 @@ | |||||||
|  |  | ||||||
|  Changes between 0.9.5a and 0.9.6  [xx XXX 2000] |  Changes between 0.9.5a and 0.9.6  [xx XXX 2000] | ||||||
|  |  | ||||||
|  |   *) When generating bytes for the first time in md_rand.c, 'stir the pool' | ||||||
|  |      by seeding with STATE_SIZE dummy bytes (with zero entropy count). | ||||||
|  |      (The PRNG state consists of two parts, the large pool 'state' and 'md', | ||||||
|  |      where all of 'md' is used each time the PRNG is used, but 'state' | ||||||
|  |      is used only indexed by a cyclic counter. As entropy may not be | ||||||
|  |      well distributed from the beginning, 'md' is important as a | ||||||
|  |      chaining variable. However, the output function chains only half | ||||||
|  |      of 'md', i.e. 80 bits.  ssleay_rand_add, on the other hand, chains | ||||||
|  |      all of 'md', and seeding with STATE_SIZE dummy bytes will result | ||||||
|  |      in all of 'state' being rewritten, with the new values depending | ||||||
|  |      on virtually all of 'md'.  This overcomes the 80 bit limitation.) | ||||||
|  |      [Bodo Moeller] | ||||||
|  |  | ||||||
|   *) In ssl/s2_clnt.c and ssl/s3_clnt.c, call ERR_clear_error() when |   *) In ssl/s2_clnt.c and ssl/s3_clnt.c, call ERR_clear_error() when | ||||||
|      the handshake is continued after ssl_verify_cert_chain(); |      the handshake is continued after ssl_verify_cert_chain(); | ||||||
|      otherwise, if SSL_VERIFY_NONE is set, remaining error codes |      otherwise, if SSL_VERIFY_NONE is set, remaining error codes | ||||||
|   | |||||||
| @@ -109,7 +109,7 @@ | |||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #define ENTROPY_NEEDED 16  /* require 128 bits = 16 bytes of randomness */ | #define ENTROPY_NEEDED 20  /* require 160 bits = 20 bytes of randomness */ | ||||||
|  |  | ||||||
| #ifndef MD_RAND_DEBUG | #ifndef MD_RAND_DEBUG | ||||||
| # ifndef NDEBUG | # ifndef NDEBUG | ||||||
| @@ -411,6 +411,7 @@ static void ssleay_rand_initialize(void) | |||||||
|  |  | ||||||
| static int ssleay_rand_bytes(unsigned char *buf, int num) | static int ssleay_rand_bytes(unsigned char *buf, int num) | ||||||
| 	{ | 	{ | ||||||
|  | 	static volatile int stirred_pool = 0; | ||||||
| 	int i,j,k,st_num,st_idx; | 	int i,j,k,st_num,st_idx; | ||||||
| 	int ok; | 	int ok; | ||||||
| 	long md_c[2]; | 	long md_c[2]; | ||||||
| @@ -419,6 +420,7 @@ static int ssleay_rand_bytes(unsigned char *buf, int num) | |||||||
| #ifndef GETPID_IS_MEANINGLESS | #ifndef GETPID_IS_MEANINGLESS | ||||||
| 	pid_t curr_pid = getpid(); | 	pid_t curr_pid = getpid(); | ||||||
| #endif | #endif | ||||||
|  | 	int do_stir_pool = 0; | ||||||
|  |  | ||||||
| #ifdef PREDICT | #ifdef PREDICT | ||||||
| 	if (rand_predictable) | 	if (rand_predictable) | ||||||
| @@ -455,6 +457,9 @@ static int ssleay_rand_bytes(unsigned char *buf, int num) | |||||||
| 	if (!initialized) | 	if (!initialized) | ||||||
| 		ssleay_rand_initialize(); | 		ssleay_rand_initialize(); | ||||||
|  |  | ||||||
|  | 	if (!stirred_pool) | ||||||
|  | 		do_stir_pool = 1; | ||||||
|  | 	 | ||||||
| 	ok = (entropy >= ENTROPY_NEEDED); | 	ok = (entropy >= ENTROPY_NEEDED); | ||||||
| 	if (!ok) | 	if (!ok) | ||||||
| 		{ | 		{ | ||||||
| @@ -464,12 +469,42 @@ static int ssleay_rand_bytes(unsigned char *buf, int num) | |||||||
| 		 * Once we've had enough initial seeding we don't bother to | 		 * Once we've had enough initial seeding we don't bother to | ||||||
| 		 * adjust the entropy count, though, because we're not ambitious | 		 * adjust the entropy count, though, because we're not ambitious | ||||||
| 		 * to provide *information-theoretic* randomness. | 		 * to provide *information-theoretic* randomness. | ||||||
|  | 		 * | ||||||
|  | 		 * NOTE: This approach fails if the program forks before | ||||||
|  | 		 * we have enough entropy. Entropy should be collected | ||||||
|  | 		 * in a separate input pool and be transferred to the | ||||||
|  | 		 * output pool only when the entropy limit has been reached. | ||||||
| 		 */ | 		 */ | ||||||
| 		entropy -= num; | 		entropy -= num; | ||||||
| 		if (entropy < 0) | 		if (entropy < 0) | ||||||
| 			entropy = 0; | 			entropy = 0; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 	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. | ||||||
|  | 		 */ | ||||||
|  |  | ||||||
|  | 		int n = STATE_SIZE; /* so that the complete pool gets accessed */ | ||||||
|  | 		while (n > 0) | ||||||
|  | 			{ | ||||||
|  | #if MD_DIGEST_LENGTH > 20 | ||||||
|  | # error "Please adjust DUMMY_SEED." | ||||||
|  | #endif | ||||||
|  | #define DUMMY_SEED "...................." /* at least MD_DIGEST_LENGTH */ | ||||||
|  | 			/* Note that the seed does not matter, it's just that | ||||||
|  | 			 * ssleay_rand_add expects to have something to hash. */ | ||||||
|  | 			ssleay_rand_add(DUMMY_SEED, MD_DIGEST_LENGTH, 0.0); | ||||||
|  | 			n -= MD_DIGEST_LENGTH; | ||||||
|  | 			} | ||||||
|  | 		if (ok) | ||||||
|  | 			stirred_pool = 1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 	st_idx=state_index; | 	st_idx=state_index; | ||||||
| 	st_num=state_num; | 	st_num=state_num; | ||||||
| 	md_c[0] = md_count[0]; | 	md_c[0] = md_count[0]; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Bodo Möller
					Bodo Möller