aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ap/wpa_auth.c30
-rw-r--r--src/ap/wpa_auth_i.h1
-rw-r--r--src/crypto/random.c84
-rw-r--r--src/crypto/random.h4
4 files changed, 118 insertions, 1 deletions
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 851612e..397fa98 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -345,6 +345,12 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
+ if (random_pool_ready() != 1) {
+ wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
+ "for secure operations - update keys later when "
+ "the first station connects");
+ }
+
/*
* Set initial GMK/Counter value here. The actual values that will be
* used in negotiations will be set once the first station tries to
@@ -825,6 +831,25 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
return;
}
random_add_randomness(key->key_nonce, WPA_NONCE_LEN);
+ if (sm->group->reject_4way_hs_for_entropy) {
+ /*
+ * The system did not have enough entropy to generate
+ * strong random numbers. Reject the first 4-way
+ * handshake(s) and collect some entropy based on the
+ * information from it. Once enough entropy is
+ * available, the next atempt will trigger GMK/Key
+ * Counter update and the station will be allowed to
+ * continue.
+ */
+ wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to "
+ "collect more entropy for random number "
+ "generation");
+ sm->group->reject_4way_hs_for_entropy = FALSE;
+ random_mark_pool_ready();
+ sm->group->first_sta_seen = FALSE;
+ wpa_sta_disconnect(wpa_auth, sm->addr);
+ return;
+ }
if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length,
&kde) < 0) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -1465,6 +1490,11 @@ static void wpa_group_first_station(struct wpa_authenticator *wpa_auth,
*/
wpa_printf(MSG_DEBUG, "WPA: Re-initialize GMK/Counter on first "
"station");
+ if (random_pool_ready() != 1) {
+ wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
+ "to proceed - reject first 4-way handshake");
+ group->reject_4way_hs_for_entropy = TRUE;
+ }
wpa_group_init_gmk_and_counter(wpa_auth, group);
wpa_gtk_update(wpa_auth, group);
wpa_group_config_group_keys(wpa_auth, group);
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index bc6962f..3173144 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -146,6 +146,7 @@ struct wpa_group {
u8 GNonce[WPA_NONCE_LEN];
Boolean changed;
Boolean first_sta_seen;
+ Boolean reject_4way_hs_for_entropy;
#ifdef CONFIG_IEEE80211W
u8 IGTK[2][WPA_IGTK_LEN];
int GN_igtk, GM_igtk;
diff --git a/src/crypto/random.c b/src/crypto/random.c
index 33eae4d..9ea7ee6 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -29,6 +29,9 @@
*/
#include "utils/includes.h"
+#ifdef __linux__
+#include <fcntl.h>
+#endif /* __linux__ */
#include "utils/common.h"
#include "sha1.h"
@@ -42,14 +45,18 @@
#define POOL_TAP4 7
#define POOL_TAP5 1
#define EXTRACT_LEN 16
+#define MIN_READY_MARK 2
static u32 pool[POOL_WORDS];
static unsigned int input_rotate = 0;
static unsigned int pool_pos = 0;
-static const u8 dummy_key[20];
+static u8 dummy_key[20];
+static size_t dummy_key_avail = 0;
+static unsigned int own_pool_ready = 0;
#define MIN_COLLECT_ENTROPY 1000
static unsigned int entropy = 0;
+static unsigned int total_collected = 0;
static u32 __ROL32(u32 x, u32 y)
@@ -135,6 +142,7 @@ void random_add_randomness(const void *buf, size_t len)
wpa_hexdump_key(MSG_EXCESSIVE, "random pool",
(const u8 *) pool, sizeof(pool));
entropy++;
+ total_collected++;
}
@@ -174,3 +182,77 @@ int random_get_bytes(void *buf, size_t len)
return ret;
}
+
+
+int random_pool_ready(void)
+{
+#ifdef __linux__
+ int fd;
+ ssize_t res;
+
+ /*
+ * Make sure that there is reasonable entropy available before allowing
+ * some key derivation operations to proceed.
+ */
+
+ if (dummy_key_avail == sizeof(dummy_key))
+ 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,
+ * so use non-blocking read to avoid blocking the application
+ * completely.
+ */
+ fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ int error = errno;
+ perror("open(/dev/random)");
+ wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
+ strerror(error));
+ 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;
+ }
+ wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from "
+ "/dev/random", (unsigned) res,
+ (unsigned) (sizeof(dummy_key) - dummy_key_avail));
+ dummy_key_avail += res;
+ close(fd);
+
+ if (dummy_key_avail == sizeof(dummy_key))
+ return 1;
+
+ wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
+ "random data available from /dev/random",
+ (unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key));
+
+ if (own_pool_ready >= MIN_READY_MARK ||
+ total_collected + 10 * own_pool_ready > MIN_COLLECT_ENTROPY) {
+ wpa_printf(MSG_INFO, "random: Allow operation to proceed "
+ "based on internal entropy");
+ return 1;
+ }
+
+ wpa_printf(MSG_INFO, "random: Not enough entropy pool available for "
+ "secure operations");
+ return 0;
+#else /* __linux__ */
+ /* TODO: could do similar checks on non-Linux platforms */
+ return 1;
+#endif /* __linux__ */
+}
+
+
+void random_mark_pool_ready(void)
+{
+ own_pool_ready++;
+ wpa_printf(MSG_DEBUG, "random: Mark internal entropy pool to be "
+ "ready (count=%u/%u)", own_pool_ready, MIN_READY_MARK);
+}
diff --git a/src/crypto/random.h b/src/crypto/random.h
index 65a1900..7b62577 100644
--- a/src/crypto/random.h
+++ b/src/crypto/random.h
@@ -18,9 +18,13 @@
#ifdef CONFIG_NO_RANDOM_POOL
#define random_add_randomness(b, l) do { } while (0)
#define random_get_bytes(b, l) os_get_random((b), (l))
+#define random_pool_ready() 1
+#define random_mark_pool_ready() do { } while (0)
#else /* CONFIG_NO_RANDOM_POOL */
void random_add_randomness(const void *buf, size_t len);
int random_get_bytes(void *buf, size_t len);
+int random_pool_ready(void);
+void random_mark_pool_ready(void);
#endif /* CONFIG_NO_RANDOM_POOL */
#endif /* RANDOM_H */