[PATCH] crypto: add option to use getrandom()
Lubomir Rintel
lkundrak at v3.sk
Mon Sep 18 05:58:07 PDT 2017
According to random(4) manual, /dev/random is essentially deprecated on Linux
for quite some time:
The /dev/random interface is considered a legacy interface, and
/dev/urandom is preferred and sufficient in all use cases, with the
exception of applications which require randomness during early boot time;
for these applications, getrandom(2) must be used instead, because it will
block until the entropy pool is initialized.
An attempt to use it would cause unnecessary blocking on machines
without a good hwrng even when it shouldn't be needed. Since Linux 3.17,
a getrandom(2) call is available that will block only until the
randomness pool has been seeded.
It is probably not a good default yet as it requires a fairly recent
kernel and glibc (3.17 and 2.25 respectively).
Signed-off-by: Lubomir Rintel <lkundrak at v3.sk>
---
hostapd/Makefile | 3 +++
hostapd/defconfig | 5 ++++
src/crypto/random.c | 67 ++++++++++++++++++++++++++++++++++--------------
wpa_supplicant/Makefile | 3 +++
wpa_supplicant/defconfig | 5 ++++
5 files changed, 64 insertions(+), 19 deletions(-)
diff --git a/hostapd/Makefile b/hostapd/Makefile
index c54de3917..842fe97b5 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -1026,6 +1026,9 @@ CFLAGS += -DCONFIG_ECC
endif
ifdef CONFIG_NO_RANDOM_POOL
+ifdef CONFIG_GETRANDOM
+CFLAGS += -DCONFIG_GETRANDOM
+endif
CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
OBJS += ../src/crypto/random.o
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 26be9f8d4..a2e2b998b 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -252,6 +252,11 @@ CONFIG_IPV6=y
# requirements described above.
#CONFIG_NO_RANDOM_POOL=y
+# Should we attempt to use the getrandom(2) call that provides more reliable
+# yet secure randomness source than /dev/random on Linux 3.17 and newer.
+# Requires glibc 2.25 to build, falls back to /dev/random if unavailable.
+#CONFIG_GETRANDOM=y
+
# Should we use poll instead of select? Select is used by default.
#CONFIG_ELOOP_POLL=y
diff --git a/src/crypto/random.c b/src/crypto/random.c
index fb9241762..5cb852853 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -25,6 +25,9 @@
#include "utils/includes.h"
#ifdef __linux__
#include <fcntl.h>
+#ifdef CONFIG_GETRANDOM
+#include <sys/random.h>
+#endif /* CONFIG_GETRANDOM */
#endif /* __linux__ */
#include "utils/common.h"
@@ -229,30 +232,49 @@ int random_pool_ready(void)
return 1; /* Already initialized - good to continue */
/*
- * Try to fetch some more data from the kernel high quality
- * /dev/random. There may not be enough data available at this point,
+ * Try to fetch some more data from the kernel high quality RNG
+ * There may not be enough data available at this point,
* so use non-blocking read to avoid blocking the application
* completely.
*/
- fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
- if (fd < 0) {
- wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
- strerror(errno));
- return -1;
- }
- res = read(fd, dummy_key + dummy_key_avail,
- sizeof(dummy_key) - dummy_key_avail);
+#ifdef CONFIG_GETRANDOM
+ res = getrandom(dummy_key + dummy_key_avail,
+ sizeof(dummy_key) - dummy_key_avail, GRND_NONBLOCK);
if (res < 0) {
- wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
- "%s", strerror(errno));
- res = 0;
+ if (errno == ENOSYS) {
+ wpa_printf(MSG_DEBUG, "random: getrandom() not supported, falling "
+ "back to /dev/random");
+ } else {
+ wpa_printf(MSG_ERROR, "random: no data from getrandom(): "
+ "%s", strerror(errno));
+ res = 0;
+ }
}
- wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from "
- "/dev/random", (unsigned) res,
+#else
+ res = -1;
+#endif /* CONFIG_GETRANDOM */
+ if (res < 0) {
+ fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ res = read(fd, dummy_key + dummy_key_avail,
+ sizeof(dummy_key) - dummy_key_avail);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
+ "%s", strerror(errno));
+ res = 0;
+ }
+ close(fd);
+ }
+
+ wpa_printf(MSG_DEBUG, "random: Got %u/%u random bytes", (unsigned) res,
(unsigned) (sizeof(dummy_key) - dummy_key_avail));
dummy_key_avail += res;
- close(fd);
if (dummy_key_avail == sizeof(dummy_key)) {
if (own_pool_ready < MIN_READY_MARK)
@@ -262,7 +284,7 @@ int random_pool_ready(void)
}
wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
- "random data available from /dev/random",
+ "random data available",
(unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key));
if (own_pool_ready >= MIN_READY_MARK ||
@@ -272,8 +294,8 @@ int random_pool_ready(void)
return 1;
}
- wpa_printf(MSG_INFO, "random: Not enough entropy pool available for "
- "secure operations");
+ wpa_printf(MSG_INFO, "random: Not enough entropy pool available "
+ "from for secure operations");
return 0;
#else /* __linux__ */
/* TODO: could do similar checks on non-Linux platforms */
@@ -415,6 +437,13 @@ void random_init(const char *entropy_file)
if (random_fd >= 0)
return;
+#ifdef CONFIG_GETRANDOM
+ if (getrandom(NULL, 0, GRND_NONBLOCK) == 0 || errno != ENOSYS) {
+ wpa_printf(MSG_INFO, "random: getrandom() support available");
+ return;
+ }
+#endif /* CONFIG_GETRANDOM */
+
random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
if (random_fd < 0) {
wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index b62b898d6..f629fc200 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1476,6 +1476,9 @@ endif
ifdef CONFIG_NO_RANDOM_POOL
CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
+ifdef CONFIG_GETRANDOM
+CFLAGS += -DCONFIG_GETRANDOM
+endif
OBJS += ../src/crypto/random.o
endif
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 1797ad359..c35272eb2 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -456,6 +456,11 @@ CONFIG_PEERKEY=y
# that meet the requirements described above.
#CONFIG_NO_RANDOM_POOL=y
+# Should we attempt to use the getrandom(2) call that provides more reliable
+# yet secure randomness source than /dev/random on Linux 3.17 and newer.
+# Requires glibc 2.25 to build, falls back to /dev/random if unavailable.
+#CONFIG_GETRANDOM=y
+
# IEEE 802.11n (High Throughput) support (mainly for AP mode)
#CONFIG_IEEE80211N=y
--
2.13.5
More information about the Hostap
mailing list