Module Name:    src
Committed By:   riz
Date:           Mon Apr  2 18:28:12 UTC 2012

Modified Files:
        src/crypto/external/bsd/openssh/dist [netbsd-6]: sshd.c
        src/crypto/external/bsd/openssl/dist/crypto/rand [netbsd-6]: md_rand.c
            rand_unix.c
Removed Files:
        src/crypto/external/bsd/openssh/dist [netbsd-6]: random.c

Log Message:
Pull up following revision(s) (requested by tls in ticket #146):
        crypto/external/bsd/openssl/dist/crypto/rand/md_rand.c: revision 1.2
        crypto/external/bsd/openssl/dist/crypto/rand/md_rand.c: revision 1.3
        crypto/external/bsd/openssh/dist/sshd.c: revision 1.9
        crypto/external/bsd/openssl/dist/crypto/rand/rand_unix.c: revision 1.3
        crypto/external/bsd/openssh/dist/random.c: file removal
Patch OpenSSL RNG to allow explicit initial seeding.  Patch OpenSSH to
explicitly seed the OpenSSL RNG in each new process rather than letting
it repeatedly open /dev/urandom to reseed, which depletes entropy severely.
Note that the OpenSSH part of this fix works better on NetBSD than it would
on many other platforms because on NetBSD, if you don't reopen /dev/urandom,
repeated reads don't deplete entropy.  On other platforms, some other
approach might be required.
Note also that this problem does not arise on OpenBSD because OpenBSD seems
to have patched OpenSSL to seed the RAND functions from arc4random()!  That
seems dangerous, so I am not taking that approach here.
Fix applications that call RAND_bytes() before any other RAND function.
Last change was...a bit too simple.


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r0 src/crypto/external/bsd/openssh/dist/random.c
cvs rdiff -u -r1.8 -r1.8.4.1 src/crypto/external/bsd/openssh/dist/sshd.c
cvs rdiff -u -r1.1.1.3 -r1.1.1.3.4.1 \
    src/crypto/external/bsd/openssl/dist/crypto/rand/md_rand.c
cvs rdiff -u -r1.2 -r1.2.8.1 \
    src/crypto/external/bsd/openssl/dist/crypto/rand/rand_unix.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/crypto/external/bsd/openssh/dist/sshd.c
diff -u src/crypto/external/bsd/openssh/dist/sshd.c:1.8 src/crypto/external/bsd/openssh/dist/sshd.c:1.8.4.1
--- src/crypto/external/bsd/openssh/dist/sshd.c:1.8	Fri Sep 16 15:36:18 2011
+++ src/crypto/external/bsd/openssh/dist/sshd.c	Mon Apr  2 18:28:12 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: sshd.c,v 1.8 2011/09/16 15:36:18 joerg Exp $	*/
+/*	$NetBSD: sshd.c,v 1.8.4.1 2012/04/02 18:28:12 riz Exp $	*/
 /* $OpenBSD: sshd.c,v 1.385 2011/06/23 09:34:13 djm Exp $ */
 /*
  * Author: Tatu Ylonen <y...@cs.hut.fi>
@@ -44,7 +44,7 @@
  */
 
 #include "includes.h"
-__RCSID("$NetBSD: sshd.c,v 1.8 2011/09/16 15:36:18 joerg Exp $");
+__RCSID("$NetBSD: sshd.c,v 1.8.4.1 2012/04/02 18:28:12 riz Exp $");
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/ioctl.h>
@@ -129,7 +129,10 @@ int deny_severity = LOG_WARNING;
 #define REEXEC_DEVCRYPTO_RESERVED_FD	(STDERR_FILENO + 1)
 #define REEXEC_STARTUP_PIPE_FD		(STDERR_FILENO + 2)
 #define REEXEC_CONFIG_PASS_FD		(STDERR_FILENO + 3)
-#define REEXEC_MIN_FREE_FD		(STDERR_FILENO + 4)
+#define REEXEC_DEVURANDOM_FD		(STDERR_FILENO + 4)
+#define REEXEC_MIN_FREE_FD		(STDERR_FILENO + 5)
+
+int urandom_fd = -1;
 
 int myflag = 0;
 
@@ -582,17 +585,20 @@ demote_sensitive_data(void)
 static void
 privsep_preauth_child(void)
 {
-	u_int32_t rnd[256];
+	u_int32_t rnd[32];
 	gid_t gidset[1];
 	struct passwd *pw;
 
 	/* Enable challenge-response authentication for privilege separation */
 	privsep_challenge_enable();
 
-	arc4random_stir();
-	arc4random_buf(rnd, sizeof(rnd));
+	if (read(urandom_fd, rnd, sizeof(rnd)) != sizeof(rnd)) {
+	    fatal("privsep_preauth_child: entropy read failed");
+	}
 	RAND_seed(rnd, sizeof(rnd));
 
+	arc4random_stir();
+
 	/* Demote the private keys to public keys. */
 	demote_sensitive_data();
 
@@ -689,7 +695,7 @@ privsep_preauth(Authctxt *authctxt)
 static void
 privsep_postauth(Authctxt *authctxt)
 {
-	u_int32_t rnd[256];
+	u_int32_t rnd[32];
 
 	if (authctxt->pw->pw_uid == 0 || options.use_login) {
 		/* File descriptor passing is broken or root login */
@@ -720,10 +726,13 @@ privsep_postauth(Authctxt *authctxt)
 	/* Demote the private keys to public keys. */
 	demote_sensitive_data();
 
-	arc4random_stir();
-	arc4random_buf(rnd, sizeof(rnd));
+	if (read(urandom_fd, rnd, sizeof(rnd)) != sizeof(rnd)) {
+	    fatal("privsep_postauth: entropy read failed");
+	}
 	RAND_seed(rnd, sizeof(rnd));
 
+	arc4random_stir();
+
 	/* Drop privileges */
 	do_setusercontext(authctxt->pw);
 
@@ -1091,6 +1100,7 @@ server_accept_loop(int *sock_in, int *so
 	struct sockaddr_storage from;
 	socklen_t fromlen;
 	pid_t pid;
+	uint8_t rnd[32];
 
 	/* setup fd set for accept */
 	fdset = NULL;
@@ -1283,6 +1293,12 @@ server_accept_loop(int *sock_in, int *so
 			 * Ensure that our random state differs
 			 * from that of the child
 			 */
+			if (read(urandom_fd, rnd, sizeof(rnd)) !=
+			    sizeof(rnd)) {
+				fatal("server_accept_loop: "
+				      "entropy read failed");
+			}
+			RAND_seed(rnd, sizeof(rnd));
 			arc4random_stir();
 		}
 
@@ -1312,6 +1328,7 @@ main(int ac, char **av)
 	mode_t new_umask;
 	Key *key;
 	Authctxt *authctxt;
+	uint8_t rnd[32];
 
 	/* Save argv. */
 	saved_argv = av;
@@ -1462,6 +1479,35 @@ main(int ac, char **av)
 	OpenSSL_add_all_algorithms();
 
 	/*
+	 * The OpenSSL PRNG is used by key-generation functions we
+	 * rely on for security.  Seed it ourselves, so that:
+	 *
+	 *	A) it does not seed itself from somewhere questionable,
+	 *	   such as the libc arc4random or, worse, getpid().
+	 *	B) it does not reopen /dev/urandom on systems where
+	 *	   this is expensive (generator keyed on open, etc).
+	 *
+	 * Note that /dev/urandom will never return the same data to
+	 * two callers, even if they have the same dup'd reference to it.
+	 */
+	if (rexeced_flag) {
+		urandom_fd = REEXEC_DEVURANDOM_FD;
+	} else {
+		urandom_fd = open("/dev/urandom", O_RDONLY);
+		if (urandom_fd == -1) {
+			fatal("sshd requires random device");
+		}
+		/* Might as well do this here; why do it later? */
+		dup2(urandom_fd, REEXEC_DEVURANDOM_FD);
+		close(urandom_fd);
+		urandom_fd = REEXEC_DEVURANDOM_FD;
+	}
+	if (read(urandom_fd, rnd, sizeof(rnd)) != sizeof(rnd)) {
+		fatal("entropy read failed");
+	}
+	RAND_seed(rnd, sizeof(rnd));
+
+	/*
 	 * Force logging to stderr until we have loaded the private host
 	 * key (unless started from inetd)
 	 */
@@ -1703,7 +1749,7 @@ main(int ac, char **av)
 	/* Reinitialize the log (because of the fork above). */
 	log_init(__progname, options.log_level, options.log_facility, log_stderr);
 
-	/* Initialize the random number generator. */
+	/* Initialize the fast random number generator. */
 	arc4random_stir();
 
 	/* Chdir to the root directory so that the current disk can be

Index: src/crypto/external/bsd/openssl/dist/crypto/rand/md_rand.c
diff -u src/crypto/external/bsd/openssl/dist/crypto/rand/md_rand.c:1.1.1.3 src/crypto/external/bsd/openssl/dist/crypto/rand/md_rand.c:1.1.1.3.4.1
--- src/crypto/external/bsd/openssl/dist/crypto/rand/md_rand.c:1.1.1.3	Sun Jun  5 14:59:27 2011
+++ src/crypto/external/bsd/openssl/dist/crypto/rand/md_rand.c	Mon Apr  2 18:28:12 2012
@@ -141,7 +141,6 @@ static unsigned char state[STATE_SIZE+MD
 static unsigned char md[MD_DIGEST_LENGTH];
 static long md_count[2]={0,0};
 static double entropy=0;
-static int initialized=0;
 
 static unsigned int crypto_lock_rand = 0; /* may be set only when a thread
                                            * holds CRYPTO_LOCK_RAND
@@ -187,7 +186,6 @@ 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)
@@ -389,18 +387,16 @@ static int ssleay_rand_bytes(unsigned ch
 	CRYPTO_w_unlock(CRYPTO_LOCK_RAND2);
 	crypto_lock_rand = 1;
 
-	if (!initialized)
-		{
-		RAND_poll();
-		initialized = 1;
-		}
-	
 	if (!stirred_pool)
 		do_stir_pool = 1;
 	
 	ok = (entropy >= ENTROPY_NEEDED);
 	if (!ok)
 		{
+
+		RAND_poll();
+		ok = (entropy >= ENTROPY_NEEDED);
+
 		/* If the PRNG state is not yet unpredictable, then seeing
 		 * the PRNG output may help attackers to determine the new
 		 * state; thus we have to decrease the entropy estimate.
@@ -571,11 +567,10 @@ static int ssleay_rand_status(void)
 		CRYPTO_w_unlock(CRYPTO_LOCK_RAND2);
 		crypto_lock_rand = 1;
 		}
-	
-	if (!initialized)
+
+	if (entropy < ENTROPY_NEEDED)
 		{
 		RAND_poll();
-		initialized = 1;
 		}
 
 	ret = entropy >= ENTROPY_NEEDED;

Index: src/crypto/external/bsd/openssl/dist/crypto/rand/rand_unix.c
diff -u src/crypto/external/bsd/openssl/dist/crypto/rand/rand_unix.c:1.2 src/crypto/external/bsd/openssl/dist/crypto/rand/rand_unix.c:1.2.8.1
--- src/crypto/external/bsd/openssl/dist/crypto/rand/rand_unix.c:1.2	Sun Jul 19 23:30:41 2009
+++ src/crypto/external/bsd/openssl/dist/crypto/rand/rand_unix.c	Mon Apr  2 18:28:12 2012
@@ -182,6 +182,16 @@ int RAND_poll(void)
 	u_int32_t rnd = 0, i;
 	unsigned char buf[ENTROPY_NEEDED];
 
+	/*
+	 * XXX is this really a good idea?  It has the seemingly
+	 * XXX very undesirable eventual result of keying the CTR_DRBG
+	 * XXX generator exclusively with key material produced by
+	 * XXX the libc arc4random().  It also guarantees that even
+	 * XXX if the generator tries to use RAND_poll() to rekey
+	 * XXX itself after a call to fork() etc, it will end up with
+	 * XXX the same state, since the libc arc4 state will be the same
+	 * XXX unless explicitly updated by the application.
+	 */
 	for (i = 0; i < sizeof(buf); i++) {
 		if (i % 4 == 0)
 			rnd = arc4random();

Reply via email to