From 0ebb23e340e625d59923039d0a4eb6379bdad992 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 3 Aug 2012 21:47:31 +0300 Subject: [PATCH] EXT PW: Add support for password parameter from external storage This allows the password parameter for EAP methods to be fetched from an external storage. Following example can be used for developer testing: ext_password_backend=test:pw1=password|pw2=testing network={ key_mgmt=WPA-EAP eap=TTLS identity="user" password=ext:pw1 ca_cert="ca.pem" phase2="auth=PAP" } Signed-hostap: Jouni Malinen --- src/eap_peer/eap.c | 49 ++++++++++++++++++++++++++++++ src/eap_peer/eap.h | 3 ++ src/eap_peer/eap_config.h | 3 ++ src/eap_peer/eap_i.h | 3 ++ src/eap_peer/eap_mschapv2.c | 4 ++- src/eapol_supp/eapol_supp_sm.c | 10 +++++- src/eapol_supp/eapol_supp_sm.h | 9 +++++- wpa_supplicant/config.c | 27 ++++++++++++++++ wpa_supplicant/wpa_supplicant.conf | 3 +- 9 files changed, 107 insertions(+), 4 deletions(-) diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index 8b43be438..b67249445 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -20,6 +20,7 @@ #include "common.h" #include "pcsc_funcs.h" #include "state_machine.h" +#include "ext_password.h" #include "crypto/crypto.h" #include "crypto/tls.h" #include "common/wpa_ctrl.h" @@ -93,6 +94,9 @@ static void eap_notify_status(struct eap_sm *sm, const char *status, static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt) { + ext_password_free(sm->ext_pw_buf); + sm->ext_pw_buf = NULL; + if (sm->m == NULL || sm->eap_method_priv == NULL) return; @@ -1915,6 +1919,27 @@ const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len) } +static int eap_get_ext_password(struct eap_sm *sm, + struct eap_peer_config *config) +{ + char *name; + + if (config->password == NULL) + return -1; + + name = os_zalloc(config->password_len + 1); + if (name == NULL) + return -1; + os_memcpy(name, config->password, config->password_len); + + ext_password_free(sm->ext_pw_buf); + sm->ext_pw_buf = ext_password_get(sm->ext_pw, name); + os_free(name); + + return sm->ext_pw_buf == NULL ? -1 : 0; +} + + /** * eap_get_config_password - Get password from the network configuration * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() @@ -1926,6 +1951,14 @@ const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len) struct eap_peer_config *config = eap_get_config(sm); if (config == NULL) return NULL; + + if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { + if (eap_get_ext_password(sm, config) < 0) + return NULL; + *len = wpabuf_len(sm->ext_pw_buf); + return wpabuf_head(sm->ext_pw_buf); + } + *len = config->password_len; return config->password; } @@ -1945,6 +1978,14 @@ const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash) struct eap_peer_config *config = eap_get_config(sm); if (config == NULL) return NULL; + + if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { + if (eap_get_ext_password(sm, config) < 0) + return NULL; + *len = wpabuf_len(sm->ext_pw_buf); + return wpabuf_head(sm->ext_pw_buf); + } + *len = config->password_len; if (hash) *hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH); @@ -2256,3 +2297,11 @@ int eap_is_wps_pin_enrollee(struct eap_peer_config *conf) return 1; } + + +void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext) +{ + ext_password_free(sm->ext_pw_buf); + sm->ext_pw_buf = NULL; + sm->ext_pw = ext; +} diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h index 6e87475d3..cf58608c7 100644 --- a/src/eap_peer/eap.h +++ b/src/eap_peer/eap.h @@ -306,6 +306,9 @@ void eap_invalidate_cached_session(struct eap_sm *sm); int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf); int eap_is_wps_pin_enrollee(struct eap_peer_config *conf); +struct ext_password_data; +void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext); + #endif /* IEEE8021X_EAPOL */ #endif /* EAP_H */ diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h index a6f6f4cfc..a08543e11 100644 --- a/src/eap_peer/eap_config.h +++ b/src/eap_peer/eap_config.h @@ -619,6 +619,7 @@ struct eap_peer_config { int fragment_size; #define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0) +#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1) /** * flags - Network configuration flags (bitfield) * @@ -626,6 +627,8 @@ struct eap_peer_config { * for the network parameters. * bit 0 = password is represented as a 16-byte NtPasswordHash value * instead of plaintext password + * bit 1 = password is stored in external storage; the value in the + * password field is the name of that external entry */ u32 flags; }; diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h index 3318b8115..dd943174e 100644 --- a/src/eap_peer/eap_i.h +++ b/src/eap_peer/eap_i.h @@ -330,6 +330,9 @@ struct eap_sm { struct wps_context *wps; int prev_failure; + + struct ext_password_data *ext_pw; + struct wpabuf *ext_pw_buf; }; const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len); diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c index 3b0a116bb..fb6c282a1 100644 --- a/src/eap_peer/eap_mschapv2.c +++ b/src/eap_peer/eap_mschapv2.c @@ -304,7 +304,9 @@ static void eap_mschapv2_password_changed(struct eap_sm *sm, "EAP-MSCHAPV2: Password changed successfully"); data->prev_error = 0; os_free(config->password); - if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) { + if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { + /* TODO: update external storage */ + } else if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) { config->password = os_malloc(16); config->password_len = 16; if (config->password) { diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c index f0cae700d..2a8ef1a68 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -1,6 +1,6 @@ /* * EAPOL supplicant state machines - * Copyright (c) 2004-2008, Jouni Malinen + * Copyright (c) 2004-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -1946,3 +1946,11 @@ void eapol_sm_deinit(struct eapol_sm *sm) os_free(sm->ctx); os_free(sm); } + + +void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm, + struct ext_password_data *ext) +{ + if (sm && sm->eap) + eap_sm_set_ext_pw_ctx(sm->eap, ext); +} diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h index 1a20e4b98..b69dd9790 100644 --- a/src/eapol_supp/eapol_supp_sm.h +++ b/src/eapol_supp/eapol_supp_sm.h @@ -1,6 +1,6 @@ /* * EAPOL supplicant state machines - * Copyright (c) 2004-2008, Jouni Malinen + * Copyright (c) 2004-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -243,6 +243,7 @@ struct eapol_ctx { struct eap_peer_config; +struct ext_password_data; #ifdef IEEE8021X_EAPOL struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx); @@ -275,6 +276,8 @@ void eapol_sm_request_reauth(struct eapol_sm *sm); void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm); void eapol_sm_invalidate_cached_session(struct eapol_sm *sm); const char * eapol_sm_get_method_name(struct eapol_sm *sm); +void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm, + struct ext_password_data *ext); #else /* IEEE8021X_EAPOL */ static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx) { @@ -366,6 +369,10 @@ static inline const char * eapol_sm_get_method_name(struct eapol_sm *sm) { return NULL; } +static inline void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm, + struct ext_password_data *ext) +{ +} #endif /* IEEE8021X_EAPOL */ #endif /* EAPOL_SUPP_SM_H */ diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 70c28fe85..6573ba82c 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -1192,6 +1192,20 @@ static int wpa_config_parse_password(const struct parse_data *data, return 0; } +#ifdef CONFIG_EXT_PASSWORD + if (os_strncmp(value, "ext:", 4) == 0) { + char *name = os_strdup(value + 4); + if (name == NULL) + return -1; + os_free(ssid->eap.password); + ssid->eap.password = (u8 *) name; + ssid->eap.password_len = os_strlen(name); + ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH; + ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD; + return 0; + } +#endif /* CONFIG_EXT_PASSWORD */ + if (os_strncmp(value, "hash:", 5) != 0) { char *tmp; size_t res_len; @@ -1209,6 +1223,7 @@ static int wpa_config_parse_password(const struct parse_data *data, ssid->eap.password = (u8 *) tmp; ssid->eap.password_len = res_len; ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH; + ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD; return 0; } @@ -1237,6 +1252,7 @@ static int wpa_config_parse_password(const struct parse_data *data, ssid->eap.password = hash; ssid->eap.password_len = 16; ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH; + ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD; return 0; } @@ -1250,6 +1266,17 @@ static char * wpa_config_write_password(const struct parse_data *data, if (ssid->eap.password == NULL) return NULL; +#ifdef CONFIG_EXT_PASSWORD + if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { + buf = os_zalloc(4 + ssid->eap.password_len + 1); + if (buf == NULL) + return NULL; + os_memcpy(buf, "ext:", 4); + os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len); + return buf; + } +#endif /* CONFIG_EXT_PASSWORD */ + if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) { return wpa_config_write_string( ssid->eap.password, ssid->eap.password_len); diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 9f1cd00fb..1154aba3a 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -578,7 +578,8 @@ fast_reauth=1 # MSCHAP (EAP-MSCHAPv2, EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP). # EAP-PSK (128-bit PSK), EAP-PAX (128-bit PSK), and EAP-SAKE (256-bit # PSK) is also configured using this field. For EAP-GPSK, this is a -# variable length PSK. +# variable length PSK. ext: format can +# be used to indicate that the password is stored in external storage. # ca_cert: File path to CA certificate file (PEM/DER). This file can have one # or more trusted CA certificates. If ca_cert and ca_path are not # included, server certificate will not be verified. This is insecure and