EXT PW: Add framework for supporting external password storage

This new mechanism can be used to make wpa_supplicant using external
storage (e.g., key store in the operating system) for passwords,
passphrases, and PSKs. This commit is only adding the framework part
needed to support this, i.e., no actual configuration parameter can
yet use this new mechanism. In addition, only a simple test backend
is added to allow developer testing of the functionality.

Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2012-08-03 21:28:42 +03:00
parent 2518aad3e8
commit 306ae22556
15 changed files with 374 additions and 2 deletions

116
src/utils/ext_password.c Normal file
View file

@ -0,0 +1,116 @@
/*
* External password backend
* Copyright (c) 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#ifdef __linux__
#include <sys/mman.h>
#endif /* __linux__ */
#include "common.h"
#include "ext_password_i.h"
#ifdef CONFIG_EXT_PASSWORD_TEST
extern struct ext_password_backend ext_password_test;
#endif /* CONFIG_EXT_PASSWORD_TEST */
static const struct ext_password_backend *backends[] = {
#ifdef CONFIG_EXT_PASSWORD_TEST
&ext_password_test,
#endif /* CONFIG_EXT_PASSWORD_TEST */
NULL
};
struct ext_password_data {
const struct ext_password_backend *backend;
void *priv;
};
struct ext_password_data * ext_password_init(const char *backend,
const char *params)
{
struct ext_password_data *data;
int i;
data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
for (i = 0; backends[i]; i++) {
if (os_strcmp(backends[i]->name, backend) == 0) {
data->backend = backends[i];
break;
}
}
if (!data->backend) {
os_free(data);
return NULL;
}
data->priv = data->backend->init(params);
if (data->priv == NULL) {
os_free(data);
return NULL;
}
return data;
}
void ext_password_deinit(struct ext_password_data *data)
{
if (data && data->backend && data->priv)
data->backend->deinit(data->priv);
os_free(data);
}
struct wpabuf * ext_password_get(struct ext_password_data *data,
const char *name)
{
if (data == NULL)
return NULL;
return data->backend->get(data->priv, name);
}
struct wpabuf * ext_password_alloc(size_t len)
{
struct wpabuf *buf;
buf = wpabuf_alloc(len);
if (buf == NULL)
return NULL;
#ifdef __linux__
if (mlock(wpabuf_head(buf), wpabuf_len(buf)) < 0) {
wpa_printf(MSG_ERROR, "EXT PW: mlock failed: %s",
strerror(errno));
}
#endif /* __linux__ */
return buf;
}
void ext_password_free(struct wpabuf *pw)
{
if (pw == NULL)
return;
os_memset(wpabuf_mhead(pw), 0, wpabuf_len(pw));
#ifdef __linux__
if (munlock(wpabuf_head(pw), wpabuf_len(pw)) < 0) {
wpa_printf(MSG_ERROR, "EXT PW: munlock failed: %s",
strerror(errno));
}
#endif /* __linux__ */
wpabuf_free(pw);
}

33
src/utils/ext_password.h Normal file
View file

@ -0,0 +1,33 @@
/*
* External password backend
* Copyright (c) 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef EXT_PASSWORD_H
#define EXT_PASSWORD_H
struct ext_password_data;
#ifdef CONFIG_EXT_PASSWORD
struct ext_password_data * ext_password_init(const char *backend,
const char *params);
void ext_password_deinit(struct ext_password_data *data);
struct wpabuf * ext_password_get(struct ext_password_data *data,
const char *name);
void ext_password_free(struct wpabuf *pw);
#else /* CONFIG_EXT_PASSWORD */
#define ext_password_init(b, p) ((void *) 1)
#define ext_password_deinit(d) do { } while (0)
#define ext_password_get(d, n) (NULL)
#define ext_password_free(p) do { } while (0)
#endif /* CONFIG_EXT_PASSWORD */
#endif /* EXT_PASSWORD_H */

View file

@ -0,0 +1,23 @@
/*
* External password backend - internal definitions
* Copyright (c) 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef EXT_PASSWORD_I_H
#define EXT_PASSWORD_I_H
#include "ext_password.h"
struct ext_password_backend {
const char *name;
void * (*init)(const char *params);
void (*deinit)(void *ctx);
struct wpabuf * (*get)(void *ctx, const char *name);
};
struct wpabuf * ext_password_alloc(size_t len);
#endif /* EXT_PASSWORD_I_H */

View file

@ -0,0 +1,90 @@
/*
* External password backend
* Copyright (c) 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#include "common.h"
#include "ext_password_i.h"
struct ext_password_test_data {
char *params;
};
static void * ext_password_test_init(const char *params)
{
struct ext_password_test_data *data;
data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
if (params)
data->params = os_strdup(params);
return data;
}
static void ext_password_test_deinit(void *ctx)
{
struct ext_password_test_data *data = ctx;
os_free(data->params);
os_free(data);
}
static struct wpabuf * ext_password_test_get(void *ctx, const char *name)
{
struct ext_password_test_data *data = ctx;
char *pos, *pos2;
size_t nlen;
wpa_printf(MSG_DEBUG, "EXT PW TEST: get(%s)", name);
pos = data->params;
if (pos == NULL)
return NULL;
nlen = os_strlen(name);
while (pos && *pos) {
if (os_strncmp(pos, name, nlen) == 0 && pos[nlen] == '=') {
struct wpabuf *buf;
pos += nlen + 1;
pos2 = pos;
while (*pos2 != '|' && *pos2 != '\0')
pos2++;
buf = ext_password_alloc(pos2 - pos);
if (buf == NULL)
return NULL;
wpabuf_put_data(buf, pos, pos2 - pos);
wpa_hexdump_ascii_key(MSG_DEBUG, "EXT PW TEST: value",
wpabuf_head(buf),
wpabuf_len(buf));
return buf;
}
pos = os_strchr(pos + 1, '|');
if (pos)
pos++;
}
wpa_printf(MSG_DEBUG, "EXT PW TEST: get(%s) - not found", name);
return NULL;
}
const struct ext_password_backend ext_password_test = {
.name = "test",
.init = ext_password_test_init,
.deinit = ext_password_test_deinit,
.get = ext_password_test_get,
};

View file

@ -1321,6 +1321,17 @@ L_CFLAGS += -DCONFIG_AUTOSCAN
OBJS += autoscan.c OBJS += autoscan.c
endif endif
ifdef CONFIG_EXT_PASSWORD_TEST
OBJS += ../src/utils/ext_password_test.c
L_CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
NEED_EXT_PASSWORD=y
endif
ifdef NEED_EXT_PASSWORD
OBJS += ../src/utils/ext_password.c
L_CFLAGS += -DCONFIG_EXT_PASSWORD
endif
ifdef NEED_GAS ifdef NEED_GAS
OBJS += ../src/common/gas.c OBJS += ../src/common/gas.c
OBJS += gas_query.c OBJS += gas_query.c

View file

@ -1346,6 +1346,17 @@ CFLAGS += -DCONFIG_AUTOSCAN
OBJS += autoscan.o OBJS += autoscan.o
endif endif
ifdef CONFIG_EXT_PASSWORD_TEST
OBJS += ../src/utils/ext_password_test.o
CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
NEED_EXT_PASSWORD=y
endif
ifdef NEED_EXT_PASSWORD
OBJS += ../src/utils/ext_password.o
CFLAGS += -DCONFIG_EXT_PASSWORD
endif
ifdef NEED_GAS ifdef NEED_GAS
OBJS += ../src/common/gas.o OBJS += ../src/common/gas.o
OBJS += gas_query.o OBJS += gas_query.o

View file

@ -1866,6 +1866,7 @@ void wpa_config_free(struct wpa_config *config)
wpabuf_free(config->wps_nfc_dh_pubkey); wpabuf_free(config->wps_nfc_dh_pubkey);
wpabuf_free(config->wps_nfc_dh_privkey); wpabuf_free(config->wps_nfc_dh_privkey);
wpabuf_free(config->wps_nfc_dev_pw); wpabuf_free(config->wps_nfc_dev_pw);
os_free(config->ext_password_backend);
os_free(config); os_free(config);
} }
@ -2968,7 +2969,8 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 }, { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 },
{ BIN(wps_nfc_dh_pubkey), 0 }, { BIN(wps_nfc_dh_pubkey), 0 },
{ BIN(wps_nfc_dh_privkey), 0 }, { BIN(wps_nfc_dh_privkey), 0 },
{ BIN(wps_nfc_dev_pw), 0 } { BIN(wps_nfc_dev_pw), 0 },
{ STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND }
}; };
#undef FUNC #undef FUNC

View file

@ -206,6 +206,7 @@ struct wpa_cred {
#define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11) #define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11)
#define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12) #define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12)
#define CFG_CHANGED_P2P_PREF_CHAN BIT(13) #define CFG_CHANGED_P2P_PREF_CHAN BIT(13)
#define CFG_CHANGED_EXT_PW_BACKEND BIT(14)
/** /**
* struct wpa_config - wpa_supplicant configuration data * struct wpa_config - wpa_supplicant configuration data
@ -710,6 +711,13 @@ struct wpa_config {
* wps_nfc_dh_pubkey - NFC Device Password for password token * wps_nfc_dh_pubkey - NFC Device Password for password token
*/ */
struct wpabuf *wps_nfc_dev_pw; struct wpabuf *wps_nfc_dev_pw;
/**
* ext_password_backend - External password backend or %NULL if none
*
* format: <backend name>[:<optional backend parameters>]
*/
char *ext_password_backend;
}; };

View file

@ -869,6 +869,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
write_global_bin(f, "wps_nfc_dh_pubkey", config->wps_nfc_dh_pubkey); write_global_bin(f, "wps_nfc_dh_pubkey", config->wps_nfc_dh_pubkey);
write_global_bin(f, "wps_nfc_dh_privkey", config->wps_nfc_dh_privkey); write_global_bin(f, "wps_nfc_dh_privkey", config->wps_nfc_dh_privkey);
write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw); write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw);
if (config->ext_password_backend)
fprintf(f, "ext_password_backend=%s\n",
config->ext_password_backend);
} }
#endif /* CONFIG_NO_CONFIG_WRITE */ #endif /* CONFIG_NO_CONFIG_WRITE */

View file

@ -140,6 +140,14 @@ struct wpa_ssid {
*/ */
char *passphrase; char *passphrase;
/**
* ext_psk - PSK/passphrase name in external storage
*
* If this is set, PSK/passphrase will be fetched from external storage
* when requesting association with the network.
*/
char *ext_psk;
/** /**
* pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_* * pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_*
*/ */

View file

@ -512,3 +512,11 @@ CONFIG_PEERKEY=y
#CONFIG_AUTOSCAN_EXPONENTIAL=y #CONFIG_AUTOSCAN_EXPONENTIAL=y
# For periodic module: # For periodic module:
#CONFIG_AUTOSCAN_PERIODIC=y #CONFIG_AUTOSCAN_PERIODIC=y
# Password (and passphrase, etc.) backend for external storage
# These optional mechanisms can be used to add support for storing passwords
# and other secrets in external (to wpa_supplicant) location. This allows, for
# example, operating system specific key storage to be used
#
# External password backend for testing purposes (developer use)
#CONFIG_EXT_PASSWORD_TEST=y

View file

@ -13,6 +13,7 @@
#include <assert.h> #include <assert.h>
#include "common.h" #include "common.h"
#include "utils/ext_password.h"
#include "config.h" #include "config.h"
#include "eapol_supp/eapol_supp_sm.h" #include "eapol_supp/eapol_supp_sm.h"
#include "eap_peer/eap.h" #include "eap_peer/eap.h"
@ -506,6 +507,10 @@ static void test_eapol_clean(struct eapol_test_data *e,
wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface); wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
wpa_s->ctrl_iface = NULL; wpa_s->ctrl_iface = NULL;
} }
ext_password_deinit(wpa_s->ext_pw);
wpa_s->ext_pw = NULL;
wpa_config_free(wpa_s->conf); wpa_config_free(wpa_s->conf);
p = e->extra_attrs; p = e->extra_attrs;
@ -1228,6 +1233,9 @@ int main(int argc, char *argv[])
if (test_eapol(&eapol_test, &wpa_s, wpa_s.conf->ssid)) if (test_eapol(&eapol_test, &wpa_s, wpa_s.conf->ssid))
return -1; return -1;
if (wpas_init_ext_pw(&wpa_s) < 0)
return -1;
if (wait_for_monitor) if (wait_for_monitor)
wpa_supplicant_ctrl_iface_wait(wpa_s.ctrl_iface); wpa_supplicant_ctrl_iface_wait(wpa_s.ctrl_iface);

View file

@ -21,6 +21,7 @@
#include "rsn_supp/wpa.h" #include "rsn_supp/wpa.h"
#include "eloop.h" #include "eloop.h"
#include "config.h" #include "config.h"
#include "utils/ext_password.h"
#include "l2_packet/l2_packet.h" #include "l2_packet/l2_packet.h"
#include "wpa_supplicant_i.h" #include "wpa_supplicant_i.h"
#include "driver_i.h" #include "driver_i.h"
@ -453,6 +454,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_s->bssid_filter = NULL; wpa_s->bssid_filter = NULL;
wnm_bss_keep_alive_deinit(wpa_s); wnm_bss_keep_alive_deinit(wpa_s);
ext_password_deinit(wpa_s->ext_pw);
wpa_s->ext_pw = NULL;
} }
@ -2500,6 +2504,38 @@ static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
} }
int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
{
char *val, *pos;
ext_password_deinit(wpa_s->ext_pw);
wpa_s->ext_pw = NULL;
eapol_sm_set_ext_pw_ctx(wpa_s->eapol, NULL);
if (!wpa_s->conf->ext_password_backend)
return 0;
val = os_strdup(wpa_s->conf->ext_password_backend);
if (val == NULL)
return -1;
pos = os_strchr(val, ':');
if (pos)
*pos++ = '\0';
wpa_printf(MSG_DEBUG, "EXT PW: Initialize backend '%s'", val);
wpa_s->ext_pw = ext_password_init(val, pos);
os_free(val);
if (wpa_s->ext_pw == NULL) {
wpa_printf(MSG_DEBUG, "EXT PW: Failed to initialize backend");
return -1;
}
eapol_sm_set_ext_pw_ctx(wpa_s->eapol, wpa_s->ext_pw);
return 0;
}
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
struct wpa_interface *iface) struct wpa_interface *iface)
{ {
@ -2725,6 +2761,9 @@ next_driver:
if (pcsc_reader_init(wpa_s) < 0) if (pcsc_reader_init(wpa_s) < 0)
return -1; return -1;
if (wpas_init_ext_pw(wpa_s) < 0)
return -1;
return 0; return 0;
} }
@ -3153,6 +3192,9 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
} }
} }
if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
wpas_init_ext_pw(wpa_s);
#ifdef CONFIG_WPS #ifdef CONFIG_WPS
wpas_wps_update_config(wpa_s); wpas_wps_update_config(wpa_s);
#endif /* CONFIG_WPS */ #endif /* CONFIG_WPS */

View file

@ -255,6 +255,10 @@ fast_reauth=1
# 1 = only include configured SSIDs in scan results/BSS table # 1 = only include configured SSIDs in scan results/BSS table
#filter_ssids=0 #filter_ssids=0
# Password (and passphrase, etc.) backend for external storage
# format: <backend name>[:<optional backend parameters>]
#ext_password_backend=test:pw1=password|pw2=testing
# Interworking (IEEE 802.11u) # Interworking (IEEE 802.11u)

View file

@ -1,6 +1,6 @@
/* /*
* wpa_supplicant - Internal definitions * wpa_supplicant - Internal definitions
* Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi> * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
* *
* This software may be distributed under the terms of the BSD license. * This software may be distributed under the terms of the BSD license.
* See README for more details. * See README for more details.
@ -574,6 +574,8 @@ struct wpa_supplicant {
/* WLAN_REASON_* reason codes. Negative if locally generated. */ /* WLAN_REASON_* reason codes. Negative if locally generated. */
int disconnect_reason; int disconnect_reason;
struct ext_password_data *ext_pw;
}; };
@ -697,4 +699,6 @@ static inline int network_is_persistent_group(struct wpa_ssid *ssid)
int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
#endif /* WPA_SUPPLICANT_I_H */ #endif /* WPA_SUPPLICANT_I_H */