random: Add support for maintaining internal entropy store over restarts

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.
master
Jouni Malinen 13 years ago committed by Jouni Malinen
parent ceb34f250a
commit 38e24575c1

@ -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

@ -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 */

@ -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;
}

@ -16,14 +16,14 @@
#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);

@ -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

@ -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;

@ -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) {

@ -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 {

Loading…
Cancel
Save