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.
This commit is contained in:
parent
ceb34f250a
commit
38e24575c1
8 changed files with 134 additions and 18 deletions
|
@ -193,9 +193,15 @@ CONFIG_IPV6=y
|
||||||
# it may help in cases where the system pool is not initialized properly.
|
# 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
|
# However, it is very strongly recommended that the system pool is initialized
|
||||||
# with enough entropy either by using hardware assisted random number
|
# 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
|
# 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.
|
# 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
|
# 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 */
|
#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);
|
hostapd_logger_register_cb(hostapd_logger_cb);
|
||||||
|
|
||||||
|
@ -383,7 +384,7 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
random_init();
|
random_init(entropy_file);
|
||||||
|
|
||||||
#ifndef CONFIG_NATIVE_WINDOWS
|
#ifndef CONFIG_NATIVE_WINDOWS
|
||||||
eloop_register_signal(SIGHUP, handle_reload, interfaces);
|
eloop_register_signal(SIGHUP, handle_reload, interfaces);
|
||||||
|
@ -468,13 +469,14 @@ static void usage(void)
|
||||||
show_version();
|
show_version();
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"\n"
|
"\n"
|
||||||
"usage: hostapd [-hdBKtv] [-P <PID file>] "
|
"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
|
||||||
"<configuration file(s)>\n"
|
"<configuration file(s)>\n"
|
||||||
"\n"
|
"\n"
|
||||||
"options:\n"
|
"options:\n"
|
||||||
" -h show this usage\n"
|
" -h show this usage\n"
|
||||||
" -d show more debug messages (-dd for even more)\n"
|
" -d show more debug messages (-dd for even more)\n"
|
||||||
" -B run daemon in the background\n"
|
" -B run daemon in the background\n"
|
||||||
|
" -e entropy file\n"
|
||||||
" -P PID file\n"
|
" -P PID file\n"
|
||||||
" -K include key data in debug messages\n"
|
" -K include key data in debug messages\n"
|
||||||
#ifdef CONFIG_DEBUG_FILE
|
#ifdef CONFIG_DEBUG_FILE
|
||||||
|
@ -504,12 +506,13 @@ int main(int argc, char *argv[])
|
||||||
int c, debug = 0, daemonize = 0;
|
int c, debug = 0, daemonize = 0;
|
||||||
char *pid_file = NULL;
|
char *pid_file = NULL;
|
||||||
const char *log_file = NULL;
|
const char *log_file = NULL;
|
||||||
|
const char *entropy_file = NULL;
|
||||||
|
|
||||||
if (os_program_init())
|
if (os_program_init())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
c = getopt(argc, argv, "Bdf:hKP:tv");
|
c = getopt(argc, argv, "Bde:f:hKP:tv");
|
||||||
if (c < 0)
|
if (c < 0)
|
||||||
break;
|
break;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
@ -524,6 +527,9 @@ int main(int argc, char *argv[])
|
||||||
case 'B':
|
case 'B':
|
||||||
daemonize++;
|
daemonize++;
|
||||||
break;
|
break;
|
||||||
|
case 'e':
|
||||||
|
entropy_file = optarg;
|
||||||
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
log_file = optarg;
|
log_file = optarg;
|
||||||
break;
|
break;
|
||||||
|
@ -564,7 +570,7 @@ int main(int argc, char *argv[])
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hostapd_global_init(&interfaces))
|
if (hostapd_global_init(&interfaces, entropy_file))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* Initialize interfaces */
|
/* Initialize interfaces */
|
||||||
|
|
|
@ -57,12 +57,18 @@ static size_t dummy_key_avail = 0;
|
||||||
static int random_fd = -1;
|
static int random_fd = -1;
|
||||||
#endif /* __linux__ */
|
#endif /* __linux__ */
|
||||||
static unsigned int own_pool_ready = 0;
|
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
|
#define MIN_COLLECT_ENTROPY 1000
|
||||||
static unsigned int entropy = 0;
|
static unsigned int entropy = 0;
|
||||||
static unsigned int total_collected = 0;
|
static unsigned int total_collected = 0;
|
||||||
|
|
||||||
|
|
||||||
|
static void random_write_entropy(void);
|
||||||
|
|
||||||
|
|
||||||
static u32 __ROL32(u32 x, u32 y)
|
static u32 __ROL32(u32 x, u32 y)
|
||||||
{
|
{
|
||||||
return (x << (y & 31)) | (x >> (32 - (y & 31)));
|
return (x << (y & 31)) | (x >> (32 - (y & 31)));
|
||||||
|
@ -232,8 +238,12 @@ int random_pool_ready(void)
|
||||||
dummy_key_avail += res;
|
dummy_key_avail += res;
|
||||||
close(fd);
|
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;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
|
wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
|
||||||
"random data available from /dev/random",
|
"random data available from /dev/random",
|
||||||
|
@ -261,6 +271,7 @@ void random_mark_pool_ready(void)
|
||||||
own_pool_ready++;
|
own_pool_ready++;
|
||||||
wpa_printf(MSG_DEBUG, "random: Mark internal entropy pool to be "
|
wpa_printf(MSG_DEBUG, "random: Mark internal entropy pool to be "
|
||||||
"ready (count=%u/%u)", own_pool_ready, MIN_READY_MARK);
|
"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));
|
(unsigned) (sizeof(dummy_key) - dummy_key_avail));
|
||||||
dummy_key_avail += res;
|
dummy_key_avail += res;
|
||||||
|
|
||||||
if (dummy_key_avail == sizeof(dummy_key))
|
if (dummy_key_avail == sizeof(dummy_key)) {
|
||||||
random_close_fd();
|
random_close_fd();
|
||||||
|
if (own_pool_ready < MIN_READY_MARK)
|
||||||
|
own_pool_ready = MIN_READY_MARK;
|
||||||
|
random_write_entropy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __linux__ */
|
#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__
|
#ifdef __linux__
|
||||||
if (random_fd >= 0)
|
if (random_fd >= 0)
|
||||||
return;
|
return;
|
||||||
|
@ -326,6 +406,8 @@ void random_init(void)
|
||||||
|
|
||||||
eloop_register_read_sock(random_fd, random_read_fd, NULL, NULL);
|
eloop_register_read_sock(random_fd, random_read_fd, NULL, NULL);
|
||||||
#endif /* __linux__ */
|
#endif /* __linux__ */
|
||||||
|
|
||||||
|
random_write_entropy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -334,4 +416,7 @@ void random_deinit(void)
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
random_close_fd();
|
random_close_fd();
|
||||||
#endif /* __linux__ */
|
#endif /* __linux__ */
|
||||||
|
random_write_entropy();
|
||||||
|
os_free(random_entropy_file);
|
||||||
|
random_entropy_file = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,14 @@
|
||||||
#define RANDOM_H
|
#define RANDOM_H
|
||||||
|
|
||||||
#ifdef CONFIG_NO_RANDOM_POOL
|
#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_deinit() do { } while (0)
|
||||||
#define random_add_randomness(b, l) 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_get_bytes(b, l) os_get_random((b), (l))
|
||||||
#define random_pool_ready() 1
|
#define random_pool_ready() 1
|
||||||
#define random_mark_pool_ready() do { } while (0)
|
#define random_mark_pool_ready() do { } while (0)
|
||||||
#else /* CONFIG_NO_RANDOM_POOL */
|
#else /* CONFIG_NO_RANDOM_POOL */
|
||||||
void random_init(void);
|
void random_init(const char *entropy_file);
|
||||||
void random_deinit(void);
|
void random_deinit(void);
|
||||||
void random_add_randomness(const void *buf, size_t len);
|
void random_add_randomness(const void *buf, size_t len);
|
||||||
int random_get_bytes(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
|
# 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
|
# 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
|
# 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.
|
# 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
|
# 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
|
# 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
|
# 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"
|
"[-g<global ctrl>] \\\n"
|
||||||
" -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
|
" -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
|
||||||
"[-p<driver_param>] \\\n"
|
"[-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"
|
" [-o<override driver>] [-O<override ctrl>] \\\n"
|
||||||
" [-N -i<ifname> -c<conf> [-C<ctrl>] "
|
" [-N -i<ifname> -c<conf> [-C<ctrl>] "
|
||||||
"[-D<driver>] \\\n"
|
"[-D<driver>] \\\n"
|
||||||
|
@ -56,7 +57,8 @@ static void usage(void)
|
||||||
" -C = ctrl_interface parameter (only used if -c is not)\n"
|
" -C = ctrl_interface parameter (only used if -c is not)\n"
|
||||||
" -i = interface name\n"
|
" -i = interface name\n"
|
||||||
" -d = increase debugging verbosity (-dd even more)\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
|
#ifdef CONFIG_DEBUG_FILE
|
||||||
printf(" -f = log output to debug file instead of stdout\n");
|
printf(" -f = log output to debug file instead of stdout\n");
|
||||||
#endif /* CONFIG_DEBUG_FILE */
|
#endif /* CONFIG_DEBUG_FILE */
|
||||||
|
@ -143,7 +145,7 @@ int main(int argc, char *argv[])
|
||||||
wpa_supplicant_fd_workaround();
|
wpa_supplicant_fd_workaround();
|
||||||
|
|
||||||
for (;;) {
|
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)
|
if (c < 0)
|
||||||
break;
|
break;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
@ -172,6 +174,9 @@ int main(int argc, char *argv[])
|
||||||
params.wpa_debug_level--;
|
params.wpa_debug_level--;
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
||||||
|
case 'e':
|
||||||
|
params.entropy_file = optarg;
|
||||||
|
break;
|
||||||
#ifdef CONFIG_DEBUG_FILE
|
#ifdef CONFIG_DEBUG_FILE
|
||||||
case 'f':
|
case 'f':
|
||||||
params.wpa_debug_file_path = optarg;
|
params.wpa_debug_file_path = optarg;
|
||||||
|
|
|
@ -2544,7 +2544,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
random_init();
|
random_init(params->entropy_file);
|
||||||
|
|
||||||
global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
|
global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
|
||||||
if (global->ctrl_iface == NULL) {
|
if (global->ctrl_iface == NULL) {
|
||||||
|
|
|
@ -181,6 +181,14 @@ struct wpa_params {
|
||||||
* created.
|
* created.
|
||||||
*/
|
*/
|
||||||
char *override_ctrl_interface;
|
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 {
|
struct p2p_srv_bonjour {
|
||||||
|
|
Loading…
Reference in a new issue