Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/crypto/external/bsd Patch OpenSSL RNG to allow explicit init...



details:   https://anonhg.NetBSD.org/src/rev/8697103c552a
branches:  trunk
changeset: 777840:8697103c552a
user:      tls <tls%NetBSD.org@localhost>
date:      Mon Mar 05 20:13:36 2012 +0000

description:
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.

diffstat:

 crypto/external/bsd/openssh/dist/random.c                |  128 ---------------
 crypto/external/bsd/openssh/dist/sshd.c                  |   66 ++++++-
 crypto/external/bsd/openssl/dist/crypto/rand/md_rand.c   |   16 +-
 crypto/external/bsd/openssl/dist/crypto/rand/rand_unix.c |   10 +
 4 files changed, 71 insertions(+), 149 deletions(-)

diffs (truncated from 358 to 300 lines):

diff -r 15908116aa7d -r 8697103c552a crypto/external/bsd/openssh/dist/random.c
--- a/crypto/external/bsd/openssh/dist/random.c Mon Mar 05 19:40:08 2012 +0000
+++ /dev/null   Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-/*     $NetBSD: random.c,v 1.2 2010/12/07 22:50:37 joerg Exp $ */
-
-/*-
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Jason R. Thorpe.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-#ifndef lint
-__RCSID("$NetBSD: random.c,v 1.2 2010/12/07 22:50:37 joerg Exp $");
-#endif
-
-/*
- * Functions for stirring in additional noise into the
- * cryptographically strong PRNG.
- * the functions are not using "arc4" in any ways, they are placed here
- * to make porting easy.
- */
-
-#include <sys/types.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <stdlib.h>
-
-#include "pathnames.h"
-#include "random.h"
-#include "log.h"
-
-int
-arc4random_check(void)
-{
-       int fd;
-
-       fd = open(_PATH_URANDOM, O_RDONLY, 0666);
-       if (fd < 0) {
-               fatal("random number device is mandatory.  see rnd(4).");
-               /*NOTREACHED*/
-       }
-       close(fd);
-       return 0;
-}
-
-void
-arc4random_buf(void *_buf, size_t n)
-{
-       size_t i;
-       u_int32_t r = 0;
-       char *buf = (char *)_buf;
-
-       for (i = 0; i < n; i++) {
-               if (i % 4 == 0)
-                       r = arc4random();
-               buf[i] = r & 0xff;
-               r >>= 8;
-       }
-       i = r = 0;
-}
-
-/*
- * Calculate a uniformly distributed random number less than upper_bound
- * avoiding "modulo bias".
- *
- * Uniformity is achieved by generating new random numbers until the one
- * returned is outside the range [0, 2**32 % upper_bound).  This
- * guarantees the selected random number will be inside
- * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
- * after reduction modulo upper_bound.
- */
-u_int32_t
-arc4random_uniform(u_int32_t upper_bound)
-{
-       u_int32_t r, min;
-
-       if (upper_bound < 2)
-               return 0;
-
-#if (ULONG_MAX > 0xffffffffUL)
-       min = 0x100000000UL % upper_bound;
-#else
-       /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
-       if (upper_bound > 0x80000000)
-               min = 1 + ~upper_bound;         /* 2**32 - upper_bound */
-       else {
-               /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
-               min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
-       }
-#endif
-
-       /*
-        * This could theoretically loop forever but each retry has
-        * p > 0.5 (worst case, usually far better) of selecting a
-        * number inside the range we need, so it should rarely need
-        * to re-roll.
-        */
-       for (;;) {
-               r = arc4random();
-               if (r >= min)
-                       break;
-       }
-
-       return r % upper_bound;
-}
diff -r 15908116aa7d -r 8697103c552a crypto/external/bsd/openssh/dist/sshd.c
--- a/crypto/external/bsd/openssh/dist/sshd.c   Mon Mar 05 19:40:08 2012 +0000
+++ b/crypto/external/bsd/openssh/dist/sshd.c   Mon Mar 05 20:13:36 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sshd.c,v 1.8 2011/09/16 15:36:18 joerg Exp $   */
+/*     $NetBSD: sshd.c,v 1.9 2012/03/05 20:13:36 tls Exp $     */
 /* $OpenBSD: sshd.c,v 1.385 2011/06/23 09:34:13 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo%cs.hut.fi@localhost>
@@ -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.9 2012/03/05 20:13:36 tls Exp $");
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/ioctl.h>
@@ -129,7 +129,10 @@
 #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,16 +585,19 @@
 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();
 
+       if (read(urandom_fd, rnd, sizeof(rnd)) != sizeof(rnd)) {
+           fatal("privsep_preauth_child: entropy read failed");
+       }
+       RAND_seed(rnd, sizeof(rnd));
+
        arc4random_stir();
-       arc4random_buf(rnd, sizeof(rnd));
-       RAND_seed(rnd, sizeof(rnd));
 
        /* Demote the private keys to public keys. */
        demote_sensitive_data();
@@ -689,7 +695,7 @@
 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,9 +726,12 @@
        /* Demote the private keys to public keys. */
        demote_sensitive_data();
 
+       if (read(urandom_fd, rnd, sizeof(rnd)) != sizeof(rnd)) {
+           fatal("privsep_postauth: entropy read failed");
+       }
+       RAND_seed(rnd, sizeof(rnd));
+
        arc4random_stir();
-       arc4random_buf(rnd, sizeof(rnd));
-       RAND_seed(rnd, sizeof(rnd));
 
        /* Drop privileges */
        do_setusercontext(authctxt->pw);
@@ -1091,6 +1100,7 @@
        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 @@
                         * 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 @@
        mode_t new_umask;
        Key *key;
        Authctxt *authctxt;
+       uint8_t rnd[32];
 
        /* Save argv. */
        saved_argv = av;
@@ -1462,6 +1479,35 @@
        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 @@
        /* 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
diff -r 15908116aa7d -r 8697103c552a crypto/external/bsd/openssl/dist/crypto/rand/md_rand.c
--- a/crypto/external/bsd/openssl/dist/crypto/rand/md_rand.c    Mon Mar 05 19:40:08 2012 +0000
+++ b/crypto/external/bsd/openssl/dist/crypto/rand/md_rand.c    Mon Mar 05 20:13:36 2012 +0000
@@ -141,7 +141,6 @@
 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 @@
        md_count[0]=0;
        md_count[1]=0;
        entropy=0;
-       initialized=0;
        }



Home | Main Index | Thread Index | Old Index