From 5ce5cf643840cd6efd25d987bc5b6f12478c50a6 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 27 Jun 2020 13:02:24 -0700 Subject: [PATCH] Use getrandom syscall for nonces MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit * admin/merge-gnulib (GNULIB_MODULES): Add getrandom. * doc/lispref/text.texi (Format of GnuTLS Cryptography Inputs): Don’t say that iv-auto uses GNUTLS_RND_NONCE. Also, don’t say that it returns the IV’s actual value, as it never has done that. * src/fns.c, src/sysdep.c: Include sys/random.h, for getrandom. * src/fns.c (Fsecure_hash_algorithms): Use getrandom so that this function does not depend on HAVE_GNUTLS3. * src/sysdep.c: Do not include . (random_seed) [HAVE_LRAND48]: Can be long int now. (init_random) [!WINDOWSNT]: Use getrandom syscall instead of opening /dev/urandom, as this works even on GNU/Linux hosts that lack /dev/urandom. Don’t bother with gnutls_rnd as it’s not needed now that we have getrandom. --- admin/merge-gnulib | 2 +- doc/lispref/text.texi | 8 +++----- src/fns.c | 15 ++++++++++----- src/sysdep.c | 32 ++++++-------------------------- 4 files changed, 20 insertions(+), 37 deletions(-) diff --git a/admin/merge-gnulib b/admin/merge-gnulib index 99469e47aa7..5a78b052b24 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib @@ -35,7 +35,7 @@ GNULIB_MODULES=' environ execinfo explicit_bzero faccessat fchmodat fcntl fcntl-h fdopendir filemode filename filevercmp flexmember fpieee fstatat fsusage fsync futimens - getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog + getloadavg getopt-gnu getrandom gettime gettimeofday gitlog-to-changelog ieee754-h ignore-value intprops largefile lstat manywarnings memmem-simple mempcpy memrchr minmax mkostemp mktime nstrftime pathmax pipe2 pselect pthread_sigmask diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index 10e8246a5fa..0c3813ff1d0 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -4813,11 +4813,9 @@ When @var{noerror} is non-@code{nil}, this function silently uses @code{raw-text} coding instead. @item (@code{iv-auto} @var{length}) -This will generate an IV (Initialization Vector) of the specified -length using the GnuTLS @code{GNUTLS_RND_NONCE} generator and pass it -to the function. This ensures that the IV is unpredictable and -unlikely to be reused in the same session. The actual value of the IV -is returned by the function as described below. +This generates a random IV (Initialization Vector) of the specified +length and passes it to the function. This ensures that the IV is +unpredictable and unlikely to be reused in the same session. @end table diff --git a/src/fns.c b/src/fns.c index b2f84b202de..c1465f7fe3c 100644 --- a/src/fns.c +++ b/src/fns.c @@ -21,6 +21,7 @@ along with GNU Emacs. If not, see . */ #include #include +#include #include #include #include @@ -5267,7 +5268,6 @@ extract_data_from_object (Lisp_Object spec, } else if (EQ (object, Qiv_auto)) { -#ifdef HAVE_GNUTLS3 /* Format: (iv-auto REQUIRED-LENGTH). */ if (! FIXNATP (start)) @@ -5276,14 +5276,19 @@ extract_data_from_object (Lisp_Object spec, { EMACS_INT start_hold = XFIXNAT (start); object = make_uninit_string (start_hold); - gnutls_rnd (GNUTLS_RND_NONCE, SSDATA (object), start_hold); + char *lim = SSDATA (object) + start_hold; + for (char *p = SSDATA (object); p < lim; p++) + { + ssize_t gotten = getrandom (p, lim - p, 0); + if (0 <= gotten) + p += gotten; + else if (errno != EINTR) + report_file_error ("Getting random data", Qnil); + } *start_byte = 0; *end_byte = start_hold; } -#else - error ("GnuTLS is not available, so `iv-auto' can't be used"); -#endif } if (!STRINGP (object)) diff --git a/src/sysdep.c b/src/sysdep.c index cbd306a6b67..6b54ed3b6ec 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -27,6 +27,7 @@ along with GNU Emacs. If not, see . */ #endif /* HAVE_PWD_H */ #include #include +#include #include #include @@ -115,16 +116,6 @@ along with GNU Emacs. If not, see . */ #include "process.h" #include "cm.h" -#include "gnutls.h" -/* MS-Windows loads GnuTLS at run time, if available; we don't want to - do that during startup just to call gnutls_rnd. */ -#if defined HAVE_GNUTLS && !defined WINDOWSNT -# include -#else -# define emacs_gnutls_global_init() Qnil -# define gnutls_rnd(level, data, len) (-1) -#endif - #ifdef WINDOWSNT # include /* In process.h which conflicts with the local copy. */ @@ -2278,9 +2269,7 @@ init_signals (void) typedef unsigned int random_seed; static void set_random_seed (random_seed arg) { srandom (arg); } #elif defined HAVE_LRAND48 -/* Although srand48 uses a long seed, this is unsigned long to avoid - undefined behavior on signed integer overflow in init_random. */ -typedef unsigned long int random_seed; +typedef long int random_seed; static void set_random_seed (random_seed arg) { srand48 (arg); } #else typedef unsigned int random_seed; @@ -2307,23 +2296,14 @@ init_random (void) /* First, try seeding the PRNG from the operating system's entropy source. This approach is both fast and secure. */ #ifdef WINDOWSNT + /* FIXME: Perhaps getrandom can be used here too? */ success = w32_init_random (&v, sizeof v) == 0; #else - int fd = emacs_open ("/dev/urandom", O_RDONLY, 0); - if (0 <= fd) - { - success = emacs_read (fd, &v, sizeof v) == sizeof v; - close (fd); - } + verify (sizeof v <= 256); + success = getrandom (&v, sizeof v, 0) == sizeof v; #endif - /* If that didn't work, try using GnuTLS, which is secure, but on - some systems, can be somewhat slow. */ - if (!success) - success = EQ (emacs_gnutls_global_init (), Qt) - && gnutls_rnd (GNUTLS_RND_NONCE, &v, sizeof v) == 0; - - /* If _that_ didn't work, just use the current time value and PID. + /* If that didn't work, just use the current time value and PID. It's at least better than XKCD 221. */ if (!success) { -- 2.39.2