diff options
| author | Eli Zaretskii | 2016-01-15 11:47:55 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2016-01-15 11:47:55 +0200 |
| commit | 3ffe81e245d854a694ae1734f1b6a995bdc5e724 (patch) | |
| tree | 2d8fccecc5b404f8fb71e15fe0ea6477a09a1857 | |
| parent | fee0526a189f43e8470d78e8374bd425890fbe6f (diff) | |
| download | emacs-3ffe81e245d854a694ae1734f1b6a995bdc5e724.tar.gz emacs-3ffe81e245d854a694ae1734f1b6a995bdc5e724.zip | |
Make 'random' seeds cryptographically secure if possible
* configure.ac: Check for "/dev/urandom".
* src/sysdep.c (init_random) [HAVE_DEV_URANDOM]: Read the stream
for the seed from "/dev/urandom".
[WINDOWSNT]: Obtain the stream for the seed from w32 APIs.
* src/fns.c (Frandom): Update the doc string to indicate that
system entropy is used when available.
* src/w32.c: Include wincrypt.h.
(w32_init_crypt_random, w32_init_random): New functions, use the
CryptGenRandom API.
(globals_of_w32): Initialize w32_crypto_hprov handle to zero.
* src/w32.h (w32_init_random): Add prototype.
* doc/lispref/numbers.texi (Random Numbers): Document more details
about 't' as the argument to 'random'.
* etc/NEWS: Mention that '(random t)' now uses a cryptographically
strong seed if possible.
(Bug#22202)
| -rw-r--r-- | configure.ac | 16 | ||||
| -rw-r--r-- | doc/lispref/numbers.texi | 4 | ||||
| -rw-r--r-- | etc/NEWS | 8 | ||||
| -rw-r--r-- | src/fns.c | 3 | ||||
| -rw-r--r-- | src/sysdep.c | 31 | ||||
| -rw-r--r-- | src/w32.c | 32 | ||||
| -rw-r--r-- | src/w32.h | 3 |
7 files changed, 93 insertions, 4 deletions
diff --git a/configure.ac b/configure.ac index 8c01abac9c6..6c9b621dd82 100644 --- a/configure.ac +++ b/configure.ac | |||
| @@ -4153,6 +4153,22 @@ fi | |||
| 4153 | 4153 | ||
| 4154 | AC_TYPE_MBSTATE_T | 4154 | AC_TYPE_MBSTATE_T |
| 4155 | 4155 | ||
| 4156 | AC_MSG_CHECKING([whether "/dev/urandom" is available]) | ||
| 4157 | dev_urandom=no | ||
| 4158 | dnl MSYS, being a Cygwin fork, thinks "/dev/urandom" does exist, so | ||
| 4159 | dnl don't check this for the MinGW builds. | ||
| 4160 | if test "${opsys}" != "mingw32"; then | ||
| 4161 | if test -r "/dev/urandom"; then | ||
| 4162 | AC_DEFINE(HAVE_DEV_URANDOM, 1, [Define if the system supports the "/dev/urandom" device.]) | ||
| 4163 | dev_urandom=yes | ||
| 4164 | fi | ||
| 4165 | fi | ||
| 4166 | if test $dev_urandom = yes; then | ||
| 4167 | AC_MSG_RESULT(yes) | ||
| 4168 | else | ||
| 4169 | AC_MSG_RESULT(no) | ||
| 4170 | fi | ||
| 4171 | |||
| 4156 | dnl Fixme: AC_SYS_POSIX_TERMIOS should probably be used, but it's not clear | 4172 | dnl Fixme: AC_SYS_POSIX_TERMIOS should probably be used, but it's not clear |
| 4157 | dnl how the tty code is related to POSIX and/or other versions of termios. | 4173 | dnl how the tty code is related to POSIX and/or other versions of termios. |
| 4158 | dnl The following looks like a useful start. | 4174 | dnl The following looks like a useful start. |
diff --git a/doc/lispref/numbers.texi b/doc/lispref/numbers.texi index 20d3c4290f3..3a9483af967 100644 --- a/doc/lispref/numbers.texi +++ b/doc/lispref/numbers.texi | |||
| @@ -1252,7 +1252,9 @@ any integer representable in Lisp, i.e., an integer between | |||
| 1252 | (@pxref{Integer Basics}). | 1252 | (@pxref{Integer Basics}). |
| 1253 | 1253 | ||
| 1254 | If @var{limit} is @code{t}, it means to choose a new seed as if Emacs | 1254 | If @var{limit} is @code{t}, it means to choose a new seed as if Emacs |
| 1255 | were restarting. | 1255 | were restarting. The new seed will be set from the system entropy, if |
| 1256 | that is available, or from the current time and Emacs process's PID | ||
| 1257 | (@pxref{System Environment, emacs-pid}) if not. | ||
| 1256 | 1258 | ||
| 1257 | If @var{limit} is a string, it means to choose a new seed based on the | 1259 | If @var{limit} is a string, it means to choose a new seed based on the |
| 1258 | string's contents. | 1260 | string's contents. |
| @@ -214,6 +214,14 @@ for use in Emacs bug reports. | |||
| 214 | hiding character but the default `.' can be used by let-binding the | 214 | hiding character but the default `.' can be used by let-binding the |
| 215 | variable `read-hide-char'. | 215 | variable `read-hide-char'. |
| 216 | 216 | ||
| 217 | +++ | ||
| 218 | ** The Emacs pseudo-random number generator can be securely seeded. | ||
| 219 | On system where Emacs can access the system entropy or some other | ||
| 220 | cryptographically secure random stream, it now uses that when `random' | ||
| 221 | is called with its argument `t'. This allows cryptographically strong | ||
| 222 | random values; in particular, the Emacs server now uses this facility | ||
| 223 | to produce its authentication key. | ||
| 224 | |||
| 217 | --- | 225 | --- |
| 218 | ** New input methods: `tamil-dvorak' and `programmer-dvorak'. | 226 | ** New input methods: `tamil-dvorak' and `programmer-dvorak'. |
| 219 | 227 | ||
| @@ -50,7 +50,8 @@ All integers representable in Lisp, i.e. between `most-negative-fixnum' | |||
| 50 | and `most-positive-fixnum', inclusive, are equally likely. | 50 | and `most-positive-fixnum', inclusive, are equally likely. |
| 51 | 51 | ||
| 52 | With positive integer LIMIT, return random number in interval [0,LIMIT). | 52 | With positive integer LIMIT, return random number in interval [0,LIMIT). |
| 53 | With argument t, set the random number seed from the current time and pid. | 53 | With argument t, set the random number seed from the system's entropy |
| 54 | pool, or from the current time and pid if entropy is unavailable. | ||
| 54 | With a string argument, set the seed based on the string's contents. | 55 | With a string argument, set the seed based on the string's contents. |
| 55 | Other values of LIMIT are ignored. | 56 | Other values of LIMIT are ignored. |
| 56 | 57 | ||
diff --git a/src/sysdep.c b/src/sysdep.c index a78c4c64c81..1fa422947ed 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -2095,8 +2095,35 @@ seed_random (void *seed, ptrdiff_t seed_size) | |||
| 2095 | void | 2095 | void |
| 2096 | init_random (void) | 2096 | init_random (void) |
| 2097 | { | 2097 | { |
| 2098 | struct timespec t = current_timespec (); | 2098 | uintmax_t v; |
| 2099 | uintmax_t v = getpid () ^ t.tv_sec ^ t.tv_nsec; | 2099 | struct timespec t; |
| 2100 | bool success = false; | ||
| 2101 | |||
| 2102 | #if HAVE_DEV_URANDOM | ||
| 2103 | FILE *fp = fopen ("/dev/urandom", "rb"); | ||
| 2104 | |||
| 2105 | if (fp) | ||
| 2106 | { | ||
| 2107 | int i; | ||
| 2108 | |||
| 2109 | for (i = 0, v = 0; i < sizeof (uintmax_t); i++) | ||
| 2110 | { | ||
| 2111 | v <<= 8; | ||
| 2112 | v |= fgetc (fp); | ||
| 2113 | } | ||
| 2114 | fclose (fp); | ||
| 2115 | success = true; | ||
| 2116 | } | ||
| 2117 | #elif defined WINDOWSNT | ||
| 2118 | if (w32_init_random (&v, sizeof v) == 0) | ||
| 2119 | success = true; | ||
| 2120 | #endif /* HAVE_DEV_URANDOM || WINDOWSNT */ | ||
| 2121 | if (!success) | ||
| 2122 | { | ||
| 2123 | /* Fall back to current time value + PID. */ | ||
| 2124 | t = current_timespec (); | ||
| 2125 | v = getpid () ^ t.tv_sec ^ t.tv_nsec; | ||
| 2126 | } | ||
| 2100 | seed_random (&v, sizeof v); | 2127 | seed_random (&v, sizeof v); |
| 2101 | } | 2128 | } |
| 2102 | 2129 | ||
| @@ -224,6 +224,8 @@ typedef struct _REPARSE_DATA_BUFFER { | |||
| 224 | 224 | ||
| 225 | #include <iphlpapi.h> /* should be after winsock2.h */ | 225 | #include <iphlpapi.h> /* should be after winsock2.h */ |
| 226 | 226 | ||
| 227 | #include <wincrypt.h> | ||
| 228 | |||
| 227 | #include <c-strcase.h> | 229 | #include <c-strcase.h> |
| 228 | 230 | ||
| 229 | #include "w32.h" | 231 | #include "w32.h" |
| @@ -2093,6 +2095,34 @@ init_user_info (void) | |||
| 2093 | CloseHandle (token); | 2095 | CloseHandle (token); |
| 2094 | } | 2096 | } |
| 2095 | 2097 | ||
| 2098 | static HCRYPTPROV w32_crypto_hprov; | ||
| 2099 | static int | ||
| 2100 | w32_init_crypt_random (void) | ||
| 2101 | { | ||
| 2102 | if (!CryptAcquireContext (&w32_crypto_hprov, NULL, NULL, PROV_RSA_FULL, | ||
| 2103 | CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) | ||
| 2104 | { | ||
| 2105 | DebPrint (("CryptAcquireContext failed with error %x\n", | ||
| 2106 | GetLastError ())); | ||
| 2107 | w32_crypto_hprov = 0; | ||
| 2108 | return -1; | ||
| 2109 | } | ||
| 2110 | return 0; | ||
| 2111 | } | ||
| 2112 | |||
| 2113 | int | ||
| 2114 | w32_init_random (void *buf, ptrdiff_t buflen) | ||
| 2115 | { | ||
| 2116 | if (!w32_crypto_hprov) | ||
| 2117 | w32_init_crypt_random (); | ||
| 2118 | if (w32_crypto_hprov) | ||
| 2119 | { | ||
| 2120 | if (CryptGenRandom (w32_crypto_hprov, buflen, (BYTE *)buf)) | ||
| 2121 | return 0; | ||
| 2122 | } | ||
| 2123 | return -1; | ||
| 2124 | } | ||
| 2125 | |||
| 2096 | int | 2126 | int |
| 2097 | random (void) | 2127 | random (void) |
| 2098 | { | 2128 | { |
| @@ -9410,6 +9440,8 @@ globals_of_w32 (void) | |||
| 9410 | extern void dynlib_reset_last_error (void); | 9440 | extern void dynlib_reset_last_error (void); |
| 9411 | dynlib_reset_last_error (); | 9441 | dynlib_reset_last_error (); |
| 9412 | #endif | 9442 | #endif |
| 9443 | |||
| 9444 | w32_crypto_hprov = (HCRYPTPROV)0; | ||
| 9413 | } | 9445 | } |
| 9414 | 9446 | ||
| 9415 | /* For make-serial-process */ | 9447 | /* For make-serial-process */ |
| @@ -222,6 +222,9 @@ extern int w32_memory_info (unsigned long long *, unsigned long long *, | |||
| 222 | /* Compare 2 UTF-8 strings in locale-dependent fashion. */ | 222 | /* Compare 2 UTF-8 strings in locale-dependent fashion. */ |
| 223 | extern int w32_compare_strings (const char *, const char *, char *, int); | 223 | extern int w32_compare_strings (const char *, const char *, char *, int); |
| 224 | 224 | ||
| 225 | /* Return a cryptographically secure seed for PRNG. */ | ||
| 226 | extern int w32_init_random (void *, ptrdiff_t); | ||
| 227 | |||
| 225 | #ifdef HAVE_GNUTLS | 228 | #ifdef HAVE_GNUTLS |
| 226 | #include <gnutls/gnutls.h> | 229 | #include <gnutls/gnutls.h> |
| 227 | 230 | ||