diff --git a/src/utils/ext_password.c b/src/utils/ext_password.c new file mode 100644 index 000000000..06131197a --- /dev/null +++ b/src/utils/ext_password.c @@ -0,0 +1,116 @@ +/* + * External password backend + * Copyright (c) 2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#ifdef __linux__ +#include +#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); +} diff --git a/src/utils/ext_password.h b/src/utils/ext_password.h new file mode 100644 index 000000000..e3e46ea08 --- /dev/null +++ b/src/utils/ext_password.h @@ -0,0 +1,33 @@ +/* + * External password backend + * Copyright (c) 2012, Jouni Malinen + * + * 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 */ diff --git a/src/utils/ext_password_i.h b/src/utils/ext_password_i.h new file mode 100644 index 000000000..043e7312c --- /dev/null +++ b/src/utils/ext_password_i.h @@ -0,0 +1,23 @@ +/* + * External password backend - internal definitions + * Copyright (c) 2012, Jouni Malinen + * + * 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 */ diff --git a/src/utils/ext_password_test.c b/src/utils/ext_password_test.c new file mode 100644 index 000000000..3801bb854 --- /dev/null +++ b/src/utils/ext_password_test.c @@ -0,0 +1,90 @@ +/* + * External password backend + * Copyright (c) 2012, Jouni Malinen + * + * 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, +}; diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index 0666f4d1e..27dda29d2 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -1321,6 +1321,17 @@ L_CFLAGS += -DCONFIG_AUTOSCAN OBJS += autoscan.c 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 OBJS += ../src/common/gas.c OBJS += gas_query.c diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index e8fe6f21f..a7683dd26 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -1346,6 +1346,17 @@ CFLAGS += -DCONFIG_AUTOSCAN OBJS += autoscan.o 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 OBJS += ../src/common/gas.o OBJS += gas_query.o diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 54a767e10..9d7f38ed1 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -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_privkey); wpabuf_free(config->wps_nfc_dev_pw); + os_free(config->ext_password_backend); 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 }, { BIN(wps_nfc_dh_pubkey), 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 diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 6f4f80182..c8c154251 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -206,6 +206,7 @@ struct wpa_cred { #define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11) #define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12) #define CFG_CHANGED_P2P_PREF_CHAN BIT(13) +#define CFG_CHANGED_EXT_PW_BACKEND BIT(14) /** * struct wpa_config - wpa_supplicant configuration data @@ -710,6 +711,13 @@ struct wpa_config { * wps_nfc_dh_pubkey - NFC Device Password for password token */ struct wpabuf *wps_nfc_dev_pw; + + /** + * ext_password_backend - External password backend or %NULL if none + * + * format: [:] + */ + char *ext_password_backend; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index a55a5c966..0520646b4 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -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_privkey", config->wps_nfc_dh_privkey); 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 */ diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index c35f7c3fe..f4d551df0 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -140,6 +140,14 @@ struct wpa_ssid { */ 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_* */ diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index 849f2448f..e2b6cbe42 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -512,3 +512,11 @@ CONFIG_PEERKEY=y #CONFIG_AUTOSCAN_EXPONENTIAL=y # For periodic module: #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 diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c index e53e15634..825e2b9db 100644 --- a/wpa_supplicant/eapol_test.c +++ b/wpa_supplicant/eapol_test.c @@ -13,6 +13,7 @@ #include #include "common.h" +#include "utils/ext_password.h" #include "config.h" #include "eapol_supp/eapol_supp_sm.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_s->ctrl_iface = NULL; } + + ext_password_deinit(wpa_s->ext_pw); + wpa_s->ext_pw = NULL; + wpa_config_free(wpa_s->conf); 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)) return -1; + if (wpas_init_ext_pw(&wpa_s) < 0) + return -1; + if (wait_for_monitor) wpa_supplicant_ctrl_iface_wait(wpa_s.ctrl_iface); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 502541014..924719547 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -21,6 +21,7 @@ #include "rsn_supp/wpa.h" #include "eloop.h" #include "config.h" +#include "utils/ext_password.h" #include "l2_packet/l2_packet.h" #include "wpa_supplicant_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; 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, struct wpa_interface *iface) { @@ -2725,6 +2761,9 @@ next_driver: if (pcsc_reader_init(wpa_s) < 0) return -1; + if (wpas_init_ext_pw(wpa_s) < 0) + return -1; + 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 wpas_wps_update_config(wpa_s); #endif /* CONFIG_WPS */ diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index af0da2065..05a2d0bc2 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -255,6 +255,10 @@ fast_reauth=1 # 1 = only include configured SSIDs in scan results/BSS table #filter_ssids=0 +# Password (and passphrase, etc.) backend for external storage +# format: [:] +#ext_password_backend=test:pw1=password|pw2=testing + # Interworking (IEEE 802.11u) diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index b608f2987..d6d941056 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1,6 +1,6 @@ /* * wpa_supplicant - Internal definitions - * Copyright (c) 2003-2010, Jouni Malinen + * Copyright (c) 2003-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -574,6 +574,8 @@ struct wpa_supplicant { /* WLAN_REASON_* reason codes. Negative if locally generated. */ 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_init_ext_pw(struct wpa_supplicant *wpa_s); + #endif /* WPA_SUPPLICANT_I_H */