]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
random: Add support for maintaining internal entropy store over restarts
authorJouni Malinen <jouni.malinen@atheros.com>
Tue, 31 May 2011 17:07:11 +0000 (20:07 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 31 May 2011 17:07:11 +0000 (20:07 +0300)
This can be used to avoid rejection of first two 4-way handshakes every
time hostapd (or wpa_supplicant in AP/IBSS mode) is restarted. A new
command line parameter, -e, can now be used to specify an entropy file
that will be used to maintain the needed state.

hostapd/defconfig
hostapd/main.c
src/crypto/random.c
src/crypto/random.h
wpa_supplicant/defconfig
wpa_supplicant/main.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index 38d328419edc3b0a77fc81c88443e64c9c183b07..26be2a83b6e5c33accd77be2f82ddc1f0d096ffb 100644 (file)
@@ -193,9 +193,15 @@ CONFIG_IPV6=y
 # it may help in cases where the system pool is not initialized properly.
 # However, it is very strongly recommended that the system pool is initialized
 # with enough entropy either by using hardware assisted random number
-# generatior or by storing state over device reboots.
+# generator or by storing state over device reboots.
 #
-# If the os_get_random() is known to provide strong ramdom data (e.g., on
+# hostapd can be configured to maintain its own entropy store over restarts to
+# enhance random number generation. This is not perfect, but it is much more
+# secure than using the same sequence of random numbers after every reboot.
+# This can be enabled with -e<entropy file> command line option. The specified
+# file needs to be readable and writable by hostapd.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
 # Linux/BSD, the board in question is known to have reliable source of random
 # data from /dev/urandom), the internal hostapd random pool can be disabled.
 # This will save some in binary size and CPU use. However, this should only be
index 7a4cfb0041b02f90776cb978fa11edf3dafce1dc..01ad826db341e06b4bd52f3f7910dd807d29aed8 100644 (file)
@@ -369,7 +369,8 @@ static void handle_dump_state(int sig, void *signal_ctx)
 #endif /* CONFIG_NATIVE_WINDOWS */
 
 
-static int hostapd_global_init(struct hapd_interfaces *interfaces)
+static int hostapd_global_init(struct hapd_interfaces *interfaces,
+                              const char *entropy_file)
 {
        hostapd_logger_register_cb(hostapd_logger_cb);
 
@@ -383,7 +384,7 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces)
                return -1;
        }
 
-       random_init();
+       random_init(entropy_file);
 
 #ifndef CONFIG_NATIVE_WINDOWS
        eloop_register_signal(SIGHUP, handle_reload, interfaces);
@@ -468,13 +469,14 @@ static void usage(void)
        show_version();
        fprintf(stderr,
                "\n"
-               "usage: hostapd [-hdBKtv] [-P <PID file>] "
+               "usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
                "<configuration file(s)>\n"
                "\n"
                "options:\n"
                "   -h   show this usage\n"
                "   -d   show more debug messages (-dd for even more)\n"
                "   -B   run daemon in the background\n"
+               "   -e   entropy file\n"
                "   -P   PID file\n"
                "   -K   include key data in debug messages\n"
 #ifdef CONFIG_DEBUG_FILE
@@ -504,12 +506,13 @@ int main(int argc, char *argv[])
        int c, debug = 0, daemonize = 0;
        char *pid_file = NULL;
        const char *log_file = NULL;
+       const char *entropy_file = NULL;
 
        if (os_program_init())
                return -1;
 
        for (;;) {
-               c = getopt(argc, argv, "Bdf:hKP:tv");
+               c = getopt(argc, argv, "Bde:f:hKP:tv");
                if (c < 0)
                        break;
                switch (c) {
@@ -524,6 +527,9 @@ int main(int argc, char *argv[])
                case 'B':
                        daemonize++;
                        break;
+               case 'e':
+                       entropy_file = optarg;
+                       break;
                case 'f':
                        log_file = optarg;
                        break;
@@ -564,7 +570,7 @@ int main(int argc, char *argv[])
                return -1;
        }
 
-       if (hostapd_global_init(&interfaces))
+       if (hostapd_global_init(&interfaces, entropy_file))
                return -1;
 
        /* Initialize interfaces */
index a30afde1156e584e6adf8675371313d224f3e028..f545917a73396204246f2b1dbe0d4d1651e35678 100644 (file)
@@ -57,12 +57,18 @@ static size_t dummy_key_avail = 0;
 static int random_fd = -1;
 #endif /* __linux__ */
 static unsigned int own_pool_ready = 0;
+#define RANDOM_ENTROPY_SIZE 20
+static char *random_entropy_file = NULL;
+static int random_entropy_file_read = 0;
 
 #define MIN_COLLECT_ENTROPY 1000
 static unsigned int entropy = 0;
 static unsigned int total_collected = 0;
 
 
+static void random_write_entropy(void);
+
+
 static u32 __ROL32(u32 x, u32 y)
 {
        return (x << (y & 31)) | (x >> (32 - (y & 31)));
@@ -232,8 +238,12 @@ int random_pool_ready(void)
        dummy_key_avail += res;
        close(fd);
 
-       if (dummy_key_avail == sizeof(dummy_key))
+       if (dummy_key_avail == sizeof(dummy_key)) {
+               if (own_pool_ready < MIN_READY_MARK)
+                       own_pool_ready = MIN_READY_MARK;
+               random_write_entropy();
                return 1;
+       }
 
        wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
                   "random data available from /dev/random",
@@ -261,6 +271,7 @@ 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);
+       random_write_entropy();
 }
 
 
@@ -298,15 +309,84 @@ static void random_read_fd(int sock, void *eloop_ctx, void *sock_ctx)
                   (unsigned) (sizeof(dummy_key) - dummy_key_avail));
        dummy_key_avail += res;
 
-       if (dummy_key_avail == sizeof(dummy_key))
+       if (dummy_key_avail == sizeof(dummy_key)) {
                random_close_fd();
+               if (own_pool_ready < MIN_READY_MARK)
+                       own_pool_ready = MIN_READY_MARK;
+               random_write_entropy();
+       }
 }
 
 #endif /* __linux__ */
 
 
-void random_init(void)
+static void random_read_entropy(void)
+{
+       char *buf;
+       size_t len;
+
+       if (!random_entropy_file)
+               return;
+
+       buf = os_readfile(random_entropy_file, &len);
+       if (buf == NULL)
+               return; /* entropy file not yet available */
+
+       if (len != 1 + RANDOM_ENTROPY_SIZE) {
+               wpa_printf(MSG_DEBUG, "random: Invalid entropy file %s",
+                          random_entropy_file);
+               os_free(buf);
+               return;
+       }
+
+       own_pool_ready = (u8) buf[0];
+       random_add_randomness(buf + 1, RANDOM_ENTROPY_SIZE);
+       random_entropy_file_read = 1;
+       os_free(buf);
+       wpa_printf(MSG_DEBUG, "random: Added entropy from %s "
+                  "(own_pool_ready=%u)",
+                  random_entropy_file, own_pool_ready);
+}
+
+
+static void random_write_entropy(void)
 {
+       char buf[RANDOM_ENTROPY_SIZE];
+       FILE *f;
+       u8 opr;
+
+       if (!random_entropy_file)
+               return;
+
+       random_get_bytes(buf, RANDOM_ENTROPY_SIZE);
+
+       f = fopen(random_entropy_file, "wb");
+       if (f == NULL) {
+               wpa_printf(MSG_ERROR, "random: Could not write %s",
+                          random_entropy_file);
+               return;
+       }
+
+       opr = own_pool_ready > 0xff ? 0xff : own_pool_ready;
+       fwrite(&opr, 1, 1, f);
+       fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f);
+       fclose(f);
+
+       wpa_printf(MSG_DEBUG, "random: Updated entropy file %s "
+                  "(own_pool_ready=%u)",
+                  random_entropy_file, own_pool_ready);
+}
+
+
+void random_init(const char *entropy_file)
+{
+       os_free(random_entropy_file);
+       if (entropy_file)
+               random_entropy_file = os_strdup(entropy_file);
+       else
+               random_entropy_file = NULL;
+       random_read_entropy();
+
 #ifdef __linux__
        if (random_fd >= 0)
                return;
@@ -326,6 +406,8 @@ void random_init(void)
 
        eloop_register_read_sock(random_fd, random_read_fd, NULL, NULL);
 #endif /* __linux__ */
+
+       random_write_entropy();
 }
 
 
@@ -334,4 +416,7 @@ void random_deinit(void)
 #ifdef __linux__
        random_close_fd();
 #endif /* __linux__ */
+       random_write_entropy();
+       os_free(random_entropy_file);
+       random_entropy_file = NULL;
 }
index 5dabd2b02f50274bfa290e864c87f11d61341891..1048bb484a0936d3ecfd55067885f18769bafe31 100644 (file)
 #define RANDOM_H
 
 #ifdef CONFIG_NO_RANDOM_POOL
-#define random_init() do { } while (0)
+#define random_init(e) do { } while (0)
 #define random_deinit() do { } while (0)
 #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_init(void);
+void random_init(const char *entropy_file);
 void random_deinit(void);
 void random_add_randomness(const void *buf, size_t len);
 int random_get_bytes(void *buf, size_t len);
index 0c8e5f21b4022ce56d342f29cd918b91bd7990f9..ea925c435c45e6aac2bc05258e0b5241f572e000 100644 (file)
@@ -437,10 +437,16 @@ CONFIG_PEERKEY=y
 # from the OS. This by itself is not considered to be very strong, but it may
 # help in cases where the system pool is not initialized properly. However, it
 # is very strongly recommended that the system pool is initialized with enough
-# entropy either by using hardware assisted random number generatior or by
+# entropy either by using hardware assisted random number generator or by
 # storing state over device reboots.
 #
-# If the os_get_random() is known to provide strong ramdom data (e.g., on
+# wpa_supplicant can be configured to maintain its own entropy store over
+# restarts to enhance random number generation. This is not perfect, but it is
+# much more secure than using the same sequence of random numbers after every
+# reboot. This can be enabled with -e<entropy file> command line option. The
+# specified file needs to be readable and writable by wpa_supplicant.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
 # Linux/BSD, the board in question is known to have reliable source of random
 # data from /dev/urandom), the internal wpa_supplicant random pool can be
 # disabled. This will save some in binary size and CPU use. However, this
index c0aa59c4ee0a5486a18efcd4e2aba299d2787228..e196f3c4a42833f903ae4e388fed21e0dd072014 100644 (file)
@@ -33,7 +33,8 @@ static void usage(void)
               "[-g<global ctrl>] \\\n"
               "        -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
               "[-p<driver_param>] \\\n"
-              "        [-b<br_ifname>] [-f<debug file>] \\\n"
+              "        [-b<br_ifname>] [-f<debug file>] [-e<entropy file>] "
+              "\\\n"
               "        [-o<override driver>] [-O<override ctrl>] \\\n"
               "        [-N -i<ifname> -c<conf> [-C<ctrl>] "
               "[-D<driver>] \\\n"
@@ -56,7 +57,8 @@ static void usage(void)
               "  -C = ctrl_interface parameter (only used if -c is not)\n"
               "  -i = interface name\n"
               "  -d = increase debugging verbosity (-dd even more)\n"
-              "  -D = driver name (can be multiple drivers: nl80211,wext)\n");
+              "  -D = driver name (can be multiple drivers: nl80211,wext)\n"
+              "  -e = entropy file\n");
 #ifdef CONFIG_DEBUG_FILE
        printf("  -f = log output to debug file instead of stdout\n");
 #endif /* CONFIG_DEBUG_FILE */
@@ -143,7 +145,7 @@ int main(int argc, char *argv[])
        wpa_supplicant_fd_workaround();
 
        for (;;) {
-               c = getopt(argc, argv, "b:Bc:C:D:df:g:hi:KLNo:O:p:P:qstuvW");
+               c = getopt(argc, argv, "b:Bc:C:D:de:f:g:hi:KLNo:O:p:P:qstuvW");
                if (c < 0)
                        break;
                switch (c) {
@@ -172,6 +174,9 @@ int main(int argc, char *argv[])
                        params.wpa_debug_level--;
                        break;
 #endif /* CONFIG_NO_STDOUT_DEBUG */
+               case 'e':
+                       params.entropy_file = optarg;
+                       break;
 #ifdef CONFIG_DEBUG_FILE
                case 'f':
                        params.wpa_debug_file_path = optarg;
index 9295651ce395624a51a3d3444141b0b7a2cab5f8..0352c13e728830750847565f1cd343d383224d9e 100644 (file)
@@ -2544,7 +2544,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
                return NULL;
        }
 
-       random_init();
+       random_init(params->entropy_file);
 
        global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
        if (global->ctrl_iface == NULL) {
index 8498666fc594b8c5868d8a7bbb899ce85b62652a..b18d6d9a3e60df563ec0d5649cd0d4c099bdd541 100644 (file)
@@ -181,6 +181,14 @@ struct wpa_params {
         * created.
         */
        char *override_ctrl_interface;
+
+       /**
+        * entropy_file - Optional entropy file
+        *
+        * This parameter can be used to configure wpa_supplicant to maintain
+        * its internal entropy store over restarts.
+        */
+       char *entropy_file;
 };
 
 struct p2p_srv_bonjour {