diff --git a/src/common/defs.h b/src/common/defs.h index 9adc2ac..097e5fc 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -72,6 +72,7 @@ static inline int wpa_key_mgmt_sha256(int akm) #define WPA_PROTO_WPA BIT(0) #define WPA_PROTO_RSN BIT(1) +#define WPA_PROTO_WPS BIT(2) #define WPA_AUTH_ALG_OPEN BIT(0) #define WPA_AUTH_ALG_SHARED BIT(1) diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 05d7a4e..247de59 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -49,6 +49,10 @@ extern "C" { /** New scan results available */ #define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS " +#define WPA_EVENT_WPS_ERROR "CTRL-EVENT-WPS-ERROR " +#define WPA_EVENT_WPS_OVERLAP "CTRL-EVENT-WPS-OVERLAP " +#define WPA_EVENT_WPS_SUCCESS "CTRL-EVENT-WPS-SUCCESS " + /* wpa_supplicant/hostapd control interface access */ diff --git a/src/crypto/crypto_internal.c b/src/crypto/crypto_internal.c index 9324c6e..073d2d8 100644 --- a/src/crypto/crypto_internal.c +++ b/src/crypto/crypto_internal.c @@ -790,7 +790,7 @@ void crypto_global_deinit(void) } -#ifdef EAP_FAST +#if defined(EAP_FAST) || defined(EAP_WPS) int crypto_mod_exp(const u8 *base, size_t base_len, const u8 *power, size_t power_len, diff --git a/src/crypto/crypto_libtomcrypt.c b/src/crypto/crypto_libtomcrypt.c index e82097f..d0f645d 100644 --- a/src/crypto/crypto_libtomcrypt.c +++ b/src/crypto/crypto_libtomcrypt.c @@ -697,7 +697,7 @@ void crypto_global_deinit(void) } -#ifdef EAP_FAST +#if defined(EAP_FAST) || defined(EAP_WPS) int crypto_mod_exp(const u8 *base, size_t base_len, const u8 *power, size_t power_len, diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 77a2ceb..fbdb594 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -31,6 +31,7 @@ #define IEEE80211_CAP_PRIVACY 0x0010 #define SSID_MAX_WPA_IE_LEN 40 +#define SSID_MAX_WPS_IE_LEN 256 /** * struct wpa_scan_result - Scan results (old structure) * @bssid: BSSID @@ -204,6 +205,15 @@ struct wpa_driver_associate_params { int wep_tx_keyidx; /** + * wps_ie - WPS information element for Association/Probe Request + */ + const u8 *wps_ie; + /** + * wps_ie_len - length of wps_ie + */ + size_t wps_ie_len; + + /** * mgmt_frame_protection - IEEE 802.11w management frame protection */ enum { @@ -1232,6 +1242,7 @@ void wpa_supplicant_sta_free_hw_features(struct wpa_hw_modes *hw_features, const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie); #define WPA_IE_VENDOR_TYPE 0x0050f201 +#define WPS_IE_VENDOR_TYPE 0x0050f204 const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, u32 vendor_type); int wpa_scan_get_max_rate(const struct wpa_scan_res *res); diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index a618a74..5d3215d 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -2209,7 +2209,10 @@ int wpa_driver_wext_associate(void *priv, /* TODO: should consider getting wpa version and cipher/key_mgmt suites * from configuration, not from here, where only the selected suite is * available */ - if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len) + if (0 != params->wps_ie_len) { + if (wpa_driver_wext_set_gen_ie(drv, params->wps_ie, params->wps_ie_len) < 0) + ret = -1; + } else if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0) ret = -1; if (params->wpa_ie == NULL || params->wpa_ie_len == 0) @@ -2760,6 +2763,11 @@ static int wpa_driver_wext_set_param(void *priv, const char *param) return 0; } +int wpa_driver_wext_set_ie(void *priv, const u8 *ie, size_t ie_len) +{ + return wpa_driver_wext_set_gen_ie(priv, ie, ie_len); +} + int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv) { @@ -2800,4 +2808,5 @@ const struct wpa_driver_ops wpa_driver_wext_ops = { .mlme_add_sta = wpa_driver_wext_mlme_add_sta, .mlme_remove_sta = wpa_driver_wext_mlme_remove_sta, #endif /* CONFIG_CLIENT_MLME */ + .set_probe_req_ie = wpa_driver_wext_set_ie, }; diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h index 2cb2bb7..e3aba39 100644 --- a/src/eap_common/eap_defs.h +++ b/src/eap_common/eap_defs.h @@ -45,6 +45,7 @@ enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3, typedef enum { EAP_TYPE_NONE = 0, EAP_TYPE_IDENTITY = 1 /* RFC 3748 */, + EAP_TYPE_SIMPLE_CONFIG = 1, EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */, EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */, EAP_TYPE_MD5 = 4, /* RFC 3748 */ @@ -79,6 +80,8 @@ enum { EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */ }; +#define WPS_EAP_IDENTITY "WFA-SimpleConfig-Enrollee-1-0" + #define EAP_MSK_LEN 64 #define EAP_EMSK_LEN 64 diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index 71bb07f..ef61a7e 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -674,7 +674,11 @@ static void eap_peer_sm_step_local(struct eap_sm *sm) SM_ENTER(EAP, SEND_RESPONSE); break; case EAP_SEND_RESPONSE: - SM_ENTER(EAP, IDLE); + if (sm->decision == DECISION_FAIL && sm->methodState == + METHOD_DONE) + SM_ENTER(EAP, FAILURE); + else + SM_ENTER(EAP, IDLE); break; case EAP_DISCARD: SM_ENTER(EAP, IDLE); diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h index 3fd3783..8313a64 100644 --- a/src/eap_peer/eap_config.h +++ b/src/eap_peer/eap_config.h @@ -561,6 +561,14 @@ struct eap_peer_config { size_t new_password_len; /** + * assoc_state - The WPS association state + * + * Set by the EAP method and used by the supplicant to determine + * if an association attempt failed + */ + u16 assoc_state; + + /** * fragment_size - Maximum EAP fragment size in bytes (default 1398) * * This value limits the fragment size for EAP methods that support diff --git a/src/eap_peer/eap_methods.c b/src/eap_peer/eap_methods.c index 0973b2f..704b1ee 100644 --- a/src/eap_peer/eap_methods.c +++ b/src/eap_peer/eap_methods.c @@ -476,6 +476,13 @@ int eap_peer_register_methods(void) } #endif /* EAP_TNC */ +#ifdef EAP_WPS + if (ret == 0) { + int eap_peer_wps_register(void); + ret = eap_peer_wps_register(); + } +#endif + return ret; } diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c index ea65d27..e5ff901 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -400,6 +400,11 @@ SM_STEP(SUPP_PAE) if (sm->ctx->eapol_done_cb) sm->ctx->eapol_done_cb(sm->ctx->ctx); } + if (sm->eapFail && sm->conf.expect_fail) { + if (sm->ctx->eapol_done_cb) + sm->ctx->eapol_done_cb(sm->ctx->ctx); + SM_ENTER(SUPP_PAE, HELD); + } if (sm->eapSuccess && sm->portValid) SM_ENTER(SUPP_PAE, AUTHENTICATED); else if (sm->eapFail || (sm->keyDone && !sm->portValid)) @@ -1349,6 +1354,7 @@ void eapol_sm_notify_config(struct eapol_sm *sm, sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys; sm->conf.required_keys = conf->required_keys; sm->conf.fast_reauth = conf->fast_reauth; + sm->conf.expect_fail = conf->expect_fail; if (sm->eap) { eap_set_fast_reauth(sm->eap, conf->fast_reauth); eap_set_workaround(sm->eap, conf->workaround); diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h index 719fbd3..21d49da 100644 --- a/src/eapol_supp/eapol_supp_sm.h +++ b/src/eapol_supp/eapol_supp_sm.h @@ -59,6 +59,13 @@ struct eapol_config { * eap_disabled - Whether EAP is disabled */ int eap_disabled; + + /** + * expect_fail - Whether EAP-Failure is actually an indication of success + * + * This is only used for WPS + */ + int expect_fail; }; struct eapol_sm; diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 1bdac6c..8fbce24 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -525,6 +525,18 @@ OBJS += ../src/eap_peer/tncc.o NEED_BASE64=y endif +ifdef CONFIG_EAP_WPS +# EAP-WPS +CFLAGS += -DEAP_WPS +OBJS += ../src/utils/tlv.o +OBJS += ../src/eap_common/eap_wps_common.o +OBJS += ../src/eap_peer/eap_wps.o +TLS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +NEED_DH_GROUPS=y +NEED_SHA256=y +endif + ifdef CONFIG_IEEE8021X_EAPOL # IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication) CFLAGS += -DIEEE8021X_EAPOL @@ -874,11 +886,13 @@ endif ifndef CONFIG_NO_WPA OBJS += ../src/rsn_supp/wpa.o +OBJS += ../src/rsn_supp/wps.o OBJS += ../src/rsn_supp/preauth.o OBJS += ../src/rsn_supp/pmksa_cache.o OBJS += ../src/rsn_supp/peerkey.o OBJS += ../src/rsn_supp/wpa_ie.o OBJS += ../src/common/wpa_common.o +OBJS += ../src/utils/uuid.o NEED_AES=y else CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2 diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index fc64be1..61d7d5c 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -414,6 +414,8 @@ static int wpa_config_parse_proto(const struct parse_data *data, else if (os_strcmp(start, "RSN") == 0 || os_strcmp(start, "WPA2") == 0) val |= WPA_PROTO_RSN; + else if (os_strcmp(start, "WPS") == 0) + val |= WPA_PROTO_WPS; else { wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'", line, start); @@ -466,6 +468,14 @@ static char * wpa_config_write_proto(const struct parse_data *data, first = 0; } + if (ssid->proto & WPA_PROTO_WPS) { + ret = os_snprintf(pos, end - pos, "%sWPS", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return buf; + pos += ret; + first = 0; + } + return buf; } #endif /* NO_CONFIG_WRITE */ diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 1eae050..4b38f70 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -244,6 +244,11 @@ struct wpa_config { int update_config; /** + * uuid_e - Universally Unique ID + */ + char *uuid_e; + + /** * blobs - Configuration blobs */ struct wpa_config_blob *blobs; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 60650ae..66309ba 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -106,7 +106,12 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line) if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_PSK_SHA256)) && - !ssid->psk_set) { + !ssid->psk_set +#ifdef EAP_WPS + /* PSK not set with WPS */ + && !(ssid->proto & WPA_PROTO_WPS) +#endif + ) { wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key " "management, but no PSK configured.", line); errors++; @@ -427,6 +432,15 @@ static int wpa_config_process_load_dynamic_eap(int line, char *so) } +static int wpa_config_process_uuid_e(struct wpa_config *config, char *pos) +{ + os_free(config->uuid_e); + config->uuid_e = os_strdup(pos); + wpa_printf(MSG_DEBUG, "uuid_e=%s", config->uuid_e); + return 0; +} + + static int wpa_config_process_global(struct wpa_config *config, char *pos, int line) { @@ -481,6 +495,9 @@ static int wpa_config_process_global(struct wpa_config *config, char *pos, if (os_strncmp(pos, "load_dynamic_eap=", 17) == 0) return wpa_config_process_load_dynamic_eap(line, pos + 17); + if (os_strncmp(pos, "uuid=", 5) == 0) + return wpa_config_process_uuid_e(config, pos + 5); + return -1; } @@ -842,6 +859,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) config->dot11RSNAConfigSATimeout); if (config->update_config) fprintf(f, "update_config=%d\n", config->update_config); + if (config->uuid_e) + fprintf(f, "uuid=%s\n", config->uuid_e); } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 036365d..174faf5 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -17,9 +17,11 @@ #include "common.h" #include "eloop.h" #include "wpa.h" +#include "wps.h" #include "config.h" #include "eapol_supp/eapol_supp_sm.h" #include "wpa_supplicant_i.h" +#include "wps_i.h" #include "ctrl_iface.h" #include "l2_packet/l2_packet.h" #include "preauth.h" @@ -528,6 +530,30 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto, return pos; } +static char * wps_ie_txt(char *pos, char *end, const char *proto, + const u8 *ie, size_t ie_len) +{ + struct wps_ie_data data; + int first, ret; + + ret = os_snprintf(pos, end - pos, "[%s-", proto); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + + if (wpa_parse_wps_ie(ie, ie_len, &data) < 0) { + ret = os_snprintf(pos, end - pos, "?]"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + return pos; + } + + first = 1; + + return pos; +} + /* Format one result on one text line into a buffer. */ static int wpa_supplicant_ctrl_iface_scan_result( @@ -535,7 +561,7 @@ static int wpa_supplicant_ctrl_iface_scan_result( { char *pos, *end; int ret; - const u8 *ie, *ie2; + const u8 *ie, *ie2, *ie3; pos = buf; end = buf + buflen; @@ -551,6 +577,9 @@ static int wpa_supplicant_ctrl_iface_scan_result( ie2 = wpa_scan_get_ie(res, WLAN_EID_RSN); if (ie2) pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]); + ie3 = wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE); + if (ie3) + pos = wps_ie_txt(pos, end, "WPS", ie, 2 + ie[1]); if (!ie && !ie2 && res->caps & IEEE80211_CAP_PRIVACY) { ret = os_snprintf(pos, end - pos, "[WEP]"); if (ret < 0 || ret >= end - pos) @@ -1494,6 +1523,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "BSS ", 4) == 0) { reply_len = wpa_supplicant_ctrl_iface_bss( wpa_s, buf + 4, reply, reply_size); + } else if (os_strcmp(buf, "PBC") == 0) { + wps_config_pbc(wpa_s->wps); + } else if (os_strcmp(buf, "PIN_GET") == 0) { + reply_len = wps_get_pin(wpa_s->wps, reply, reply_size); + } else if (os_strcmp(buf, "PIN_ENTERED") == 0) { + wps_config_pin(wpa_s->wps); } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index 2ad2bb8..298bc05 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -167,6 +167,13 @@ CONFIG_EAP_LEAP=y # EAP-IKEv2 #CONFIG_EAP_IKEV2=y +# EAP-WPS (enable Wifi Protected Setup, sometimes refered to as Simple Config) +# This EAP method requires CONFIG_IEEE8021X_EAPOL as well as +# CONFIG_TLS=internal +CONFIG_EAP_WPS=y +CONFIG_TLS=internal +CONFIG_INTERNAL_LIBTOMMATH=y + # PKCS#12 (PFX) support (used to read private key and certificate file from # a file that usually has extension .p12 or .pfx) CONFIG_PKCS12=y diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 45b5ac3..fa36df6 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -17,11 +17,13 @@ #include "common.h" #include "eapol_supp/eapol_supp_sm.h" #include "wpa.h" +#include "wps.h" #include "eloop.h" #include "drivers/driver.h" #include "config.h" #include "l2_packet/l2_packet.h" #include "wpa_supplicant_i.h" +#include "wps_i.h" #include "pcsc_funcs.h" #include "preauth.h" #include "pmksa_cache.h" @@ -364,6 +366,215 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_ssid *ssid, } +static struct wpa_ssid * +wpa_supplicant_wps_match(struct wpa_supplicant *wpa_s, + struct wpa_ssid *group, struct wpa_scan_res *bss) +{ + const u8 *ie, *ssid_; + u8 wps_ie_len, ssid_len; + struct wpa_ssid *ssid, *selected_ssid = NULL; + + ie = wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE); + wps_ie_len = ie ? ie[1] + 2 : 0; + + for (ssid = group; ssid; ssid = ssid->pnext) { + if (ssid->disabled) { + wpa_printf(MSG_DEBUG, " skip - disabled"); + continue; + } + + ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); + ssid_ = ie ? ie + 2 : (u8 *) ""; + ssid_len = ie ? ie[1] : 0; + + if ((ssid->proto & WPA_PROTO_WPS) && wps_ie_len > 0) { + selected_ssid = ssid; + if (ssid->ssid) { + os_free(ssid->ssid); + } + if (NULL == (ssid->ssid = os_malloc(ssid_len))) { + wpa_printf(MSG_ERROR, "EAP-WPS: Cannot allocate SSID"); + break; + } + os_memcpy(ssid->ssid, ssid_, ssid_len); + ssid->ssid_len = ssid_len; + wpa_printf(MSG_DEBUG, " selected WPS AP " + MACSTR " ssid='%s'", + MAC2STR(bss->bssid), + wpa_ssid_txt(ssid_, ssid_len)); + + if (NULL != ssid->eap.identity) + os_free(ssid->eap.identity); + ssid->eap.identity = (u8 *)os_strdup(WPS_EAP_IDENTITY); + ssid->eap.identity_len = os_strlen(WPS_EAP_IDENTITY); + } + } + + return selected_ssid; +} + + +static struct wpa_scan_res * +wpa_supplicant_select_bss_wps(struct wpa_supplicant *wpa_s, + struct wpa_ssid *group, + struct wpa_ssid **selected_ssid) +{ + struct wpa_scan_res *bss = NULL; + struct wps_ie_data *wps_res = NULL; + struct wps_ie_data *pbc_bss = NULL; + struct wps_ie_data *pin_bss = NULL; + size_t wps_res_count = 0; + size_t pbc_count = 0; + size_t i; + struct wpa_blacklist *e; + const u8 *ie; + const u8 *ssid_ = NULL; + u16 config_meth; + u8 wps_ie_len = 0, ssid_len = 0; + + *selected_ssid = NULL; + config_meth = wps_sm_get_param(wpa_s->wps, WPS_PARAM_CONFIG_METHOD); + + if (WPS_CONFIG_METHOD_NONE == config_meth) + return NULL; + + wps_res = os_zalloc(wpa_s->scan_res->num * sizeof(struct wps_ie_data)); + + wpa_printf(MSG_DEBUG, "Try to find WPS-selected AP"); + for (i = 0; i < wpa_s->scan_res->num; i++) { + struct wpa_scan_res *bss_ = wpa_s->scan_res->res[i]; + + ie = wpa_scan_get_ie(bss_, WLAN_EID_SSID); + ssid_ = ie ? ie + 2 : (u8 *) ""; + ssid_len = ie ? ie[1] : 0; + + ie = wpa_scan_get_vendor_ie(bss_, WPS_IE_VENDOR_TYPE); + wps_ie_len = ie ? ie[1] + 2 : 0; + + wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' " + "wps_ie_len=%u caps=0x%x", + i, MAC2STR(bss_->bssid), + wpa_ssid_txt(ssid_, ssid_len), + wps_ie_len, bss_->caps); + + if (0 == wps_ie_len) { + wpa_printf(MSG_DEBUG, " skip - no WPS IE"); + continue; + } + + if (wpa_parse_wps_ie(ie, wps_ie_len, &wps_res[wps_res_count])) { + wpa_printf(MSG_DEBUG, " skip - bad WPS IE"); + continue; + } + + e = wpa_blacklist_get(wpa_s, bss_->bssid); + if (e && e->count > 1) { + wpa_printf(MSG_DEBUG, " skip - blacklisted"); + continue; + } + + /* + * Cache BSS' advertising a WPS IE. This speeds up the search + * for unselected external registrars. + */ + wps_res[wps_res_count].bss = bss_; + + /* + * Selected Registrar is an optional element which if TRUE + * indicates Device Password ID is present and valid. + * + * Note that some external registrars like ********* (removed + * to protect the bone-headed) won't cause the AP to set + * Selected Registrar to TRUE until after an enrollee has + * attempted to start the WPS protocol (i.e. sent M1). See + * below for a work around. + */ + if (wps_res[wps_res_count].selected_registrar) { + u16 dev_pass_id = wps_res[wps_res_count].device_password_id; + + if (WPS_DEVICE_PASSWORD_ID_PBC == dev_pass_id) { + pbc_count++; + if (NULL == pbc_bss) { + pbc_bss = &wps_res[wps_res_count]; + wpa_printf(MSG_DEBUG, " pending PBC"); + } else if (0 == os_memcmp(pbc_bss->uuid, + wps_res[wps_res_count].uuid, WPS_UUID_LEN)) { + pbc_count--; + wpa_printf(MSG_DEBUG, " skip - matching UUID_E PBC"); + } else { + wpa_printf(MSG_DEBUG, " skip - overlapping PBC"); + } + } else if (WPS_DEVICE_PASSWORD_ID_PIN == dev_pass_id) { + if (NULL == pin_bss) { + pin_bss = &wps_res[wps_res_count]; + wpa_printf(MSG_DEBUG, " pending PIN"); + } + } else { + wpa_printf(MSG_DEBUG, " only PBC / PIN supported"); + } + } else { + wpa_printf(MSG_DEBUG, " skip - registrar not selected"); + } + + wps_res_count++; + } + + switch (config_meth) { + case WPS_CONFIG_METHOD_PBC: + if (1 == pbc_count) { + bss = pbc_bss->bss; + } else if (pbc_count > 1) { + /* only one registrar can use PBC at a time */ + wps_cancel_walktime_timeout(wpa_s->wps); + wpa_msg(wpa_s, MSG_ERROR, WPA_EVENT_WPS_OVERLAP); + } + break; + case WPS_CONFIG_METHOD_DISPLAY: + case WPS_CONFIG_METHOD_LABEL: + /* + * Look for a selected registrar using PIN. + * Otherwise, choose the first non-black listed BSS + * supporting PIN. + */ + if (pin_bss) { + bss = pin_bss->bss; + } else { + wpa_printf(MSG_DEBUG, "Try to find WPS-capable AP"); + for (i = 0; i < wps_res_count; i++) { + struct wpa_scan_res *bss_ = wps_res[i].bss; + + ie = wpa_scan_get_ie(bss_, WLAN_EID_SSID); + ssid_ = ie ? ie + 2 : (u8 *) ""; + ssid_len = ie ? ie[1] : 0; + + wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' ", + i, + MAC2STR(bss_->bssid), + wpa_ssid_txt(ssid_, ssid_len)); + + if (wps_res[i].config_method & + (WPS_CONFIG_METHOD_LABEL | + WPS_CONFIG_METHOD_DISPLAY) + ) { + wpa_printf(MSG_DEBUG, " pending PIN"); + bss = bss_; + } else { + wpa_printf(MSG_DEBUG, " skip - not using PIN"); + } + } + } + break; + } + + if (bss) + *selected_ssid = wpa_supplicant_wps_match(wpa_s, group, bss); + + os_free(wps_res); + + return bss; +} + + static struct wpa_scan_res * wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s, struct wpa_ssid *group, @@ -559,7 +770,16 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group, wpa_printf(MSG_DEBUG, "Selecting BSS from priority group %d", group->priority); - /* First, try to find WPA-enabled AP */ +#ifdef EAP_WPS + /* First, try to find WPS-enabled AP */ + selected = wpa_supplicant_select_bss_wps(wpa_s, group, selected_ssid); + if (selected) { + wpa_supplicant_wps_supp_set_config(wpa_s, *selected_ssid); + return selected; + } +#endif + + /* Next, try to find WPA-enabled AP */ selected = wpa_supplicant_select_bss_wpa(wpa_s, group, selected_ssid); if (selected) return selected; diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 8767109..d430994 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -18,6 +18,8 @@ #include "eloop.h" #include "config.h" #include "wpa_supplicant_i.h" +#include "wps.h" +#include "wps_i.h" #include "mlme.h" #include "uuid.h" @@ -46,7 +48,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) struct wpa_supplicant *wpa_s = eloop_ctx; struct wpa_ssid *ssid; int enabled, scan_req = 0, ret; - const u8 *extra_ie = NULL; + u8 *extra_ie = NULL; size_t extra_ie_len = 0; if (wpa_s->disconnected && !wpa_s->scan_req) @@ -145,6 +147,23 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) return; } + if (WPS_CONFIG_METHOD_NONE != wps_sm_get_param(wpa_s->wps, + WPS_PARAM_CONFIG_METHOD)) { + u8 wps_ie[SSID_MAX_WPS_IE_LEN]; + size_t wps_ie_len; + + if (wpa_gen_wps_ie(wpa_s->wps, wpa_s->conf->uuid_e, wps_ie, + &wps_ie_len)) { + wpa_printf(MSG_WARNING, "WPA: Failed to create WPS IE"); + return; + } + extra_ie = os_realloc(extra_ie, extra_ie_len + wps_ie_len); + if (extra_ie) { + os_memcpy(extra_ie + extra_ie_len, wps_ie, wps_ie_len); + extra_ie_len += wps_ie_len; + } + } + if (wpa_s->use_client_mlme) { ieee80211_sta_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len); ret = ieee80211_sta_req_scan(wpa_s, ssid ? ssid->ssid : NULL, diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 46ec736..44f3871 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -133,6 +133,11 @@ static const char *commands_help = " stkstart = request STK negotiation with \n" " ft_ds = request over-the-DS FT with \n" " terminate = terminate wpa_supplicant\n" +#ifdef EAP_WPS +" pbc = start Push Button Configuration\n" +" pin_get = get the PIN for this device\n" +" pin_entered = PIN has been entered into registrar\n" +#endif " quit = exit wpa_cli\n"; static struct wpa_ctrl *ctrl_conn; @@ -438,6 +443,24 @@ static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +static int wpa_cli_cmd_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "PBC"); +} + + +static int wpa_cli_cmd_pin_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "PIN_GET"); +} + + +static int wpa_cli_cmd_pin_entered(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "PIN_ENTERED"); +} + + static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256]; @@ -1091,6 +1114,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { { "ap_scan", wpa_cli_cmd_ap_scan }, { "stkstart", wpa_cli_cmd_stkstart }, { "ft_ds", wpa_cli_cmd_ft_ds }, + { "pbc", wpa_cli_cmd_pbc }, + { "pin_get", wpa_cli_cmd_pin_get }, + { "pin_entered", wpa_cli_cmd_pin_entered }, { NULL, NULL } }; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 59024d8..989bfae 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -22,11 +22,13 @@ #include "eapol_supp/eapol_supp_sm.h" #include "eap_peer/eap.h" #include "wpa.h" +#include "wps.h" #include "eloop.h" #include "drivers/driver.h" #include "config.h" #include "l2_packet/l2_packet.h" #include "wpa_supplicant_i.h" +#include "wps_i.h" #include "ctrl_iface.h" #include "ctrl_iface_dbus.h" #include "pcsc_funcs.h" @@ -278,6 +280,10 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s) eapol_conf.required_keys = 0; } } + if (WPS_CONFIG_METHOD_NONE != wps_sm_get_param(wpa_s->wps, + WPS_PARAM_CONFIG_METHOD)) { + eapol_conf.expect_fail = 1; + } if (wpa_s->conf) eapol_conf.fast_reauth = wpa_s->conf->fast_reauth; eapol_conf.workaround = ssid->eap_workaround; @@ -898,7 +904,9 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, struct wpa_scan_res *bss, struct wpa_ssid *ssid) { u8 wpa_ie[80]; + u8 wps_ie[SSID_MAX_WPS_IE_LEN]; size_t wpa_ie_len; + size_t wps_ie_len; int use_crypt, ret, i; int algs = AUTH_ALG_OPEN_SYSTEM; wpa_cipher cipher_pairwise, cipher_group; @@ -968,7 +976,16 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, } wpa_drv_set_auth_alg(wpa_s, algs); - if (bss && (wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) || + if ((ssid->proto & WPA_PROTO_WPS) && bss && + wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE)) { + cipher_pairwise = WPA_CIPHER_NONE; + cipher_group = WPA_CIPHER_NONE; + + wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X; + + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, WPA_PROTO_WPS); + } else if (bss && (wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) || wpa_scan_get_ie(bss, WLAN_EID_RSN)) && (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_IEEE8021X | @@ -1093,6 +1110,14 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_IEEE80211W */ + if (wpa_gen_wps_ie(wpa_s->wps, wpa_s->conf->uuid_e, wps_ie, &wps_ie_len)) { + wpa_printf(MSG_WARNING, "WPA: Failed to create WPS IE"); + return; + } + + params.wps_ie = wps_ie; + params.wps_ie_len = wps_ie_len; + if (wpa_s->use_client_mlme) ret = ieee80211_sta_associate(wpa_s, ¶ms); else diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index b639d39..12a68ec 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -142,6 +142,11 @@ fast_reauth=1 # Timeout for security association negotiation in seconds; default 60 #dot11RSNAConfigSATimeout=60 +# Universally Unique Identifier (UUID) for WPS +# Use a UUID from the system (if available) or generate one using an app +# such as uuidgen +#uuid=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + # network block # # Each network (usually AP's sharing the same SSID) is configured as a separate @@ -761,6 +766,11 @@ blob-base64-exampleblob={ SGVsbG8gV29ybGQhCg== } +# Example of EAP-WPS (aka Wifi Protected Setup) +network={ + proto=WPS + eap=WPS +} # Wildcard match for SSID (plaintext APs only). This example select any # open AP regardless of its SSID. diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 9afae2a..5e74514 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -305,6 +305,7 @@ struct wpa_supplicant { int interface_removed; /* whether the network interface has been * removed */ struct wpa_sm *wpa; + struct wps_sm *wps; struct eapol_sm *eapol; struct ctrl_iface_priv *ctrl_iface; diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index f0c1cda..4363d1d 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -15,13 +15,17 @@ #include "includes.h" #include "common.h" +#include "tlv.h" #include "eapol_supp/eapol_supp_sm.h" #include "wpa.h" +#include "wps.h" #include "eloop.h" #include "config.h" +#include "uuid.h" #include "l2_packet/l2_packet.h" #include "wpa_common.h" #include "wpa_supplicant_i.h" +#include "wps_i.h" #include "pmksa_cache.h" #include "mlme.h" #include "ieee802_11_defs.h" @@ -279,7 +283,24 @@ static void wpa_supplicant_notify_eapol_done(void *ctx) { struct wpa_supplicant *wpa_s = ctx; wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete"); - if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { + if (wps_sm_get_param(wpa_s->wps, WPS_PARAM_CONFIG_METHOD)) { + if (wpa_s->current_ssid && (wpa_s->current_ssid->eap.assoc_state == + WPS_ASSOCIATION_STATE_CONNECTION_SUCCESS)) { + wps_sm_set_param(wpa_s->wps, WPS_PARAM_CONFIG_METHOD, + WPS_CONFIG_METHOD_NONE); + wpa_supplicant_wps_supp_get_config(wpa_s); + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_WPS_SUCCESS); + } else { + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_WPS_ERROR); + } + wps_cancel_walktime_timeout(wpa_s->wps); + wpa_supplicant_cancel_auth_timeout(wpa_s); + + wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED); + wpa_s->reassociate = 1; + + wpa_supplicant_req_scan(wpa_s, 0, 0); + } else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE); } else { wpa_supplicant_cancel_auth_timeout(wpa_s); @@ -605,6 +626,13 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) "machine"); return -1; } + + wpa_s->wps = wps_sm_init(ctx); + if (wpa_s->wps == NULL) { + wpa_printf(MSG_ERROR, "Failed to initialize WPS state " + "machine"); + return -1; + } #endif /* CONFIG_NO_WPA */ return 0; @@ -629,3 +657,254 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, } wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL); } + +int wpa_supplicant_wps_supp_set_config(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + struct wpa_config_blob *blob; + u8 *pos = NULL; + u16 auth = 0, encr = 0; + u8 uuid_e[WPS_UUID_LEN]; + + if (NULL == ssid) { + return -1; + } + + wpa_config_remove_blob(wpa_s->conf, WPS_BLOB_NAME_REQUIRE); + + blob = os_zalloc(sizeof(struct wpa_config_blob)); + if (NULL == blob) { + return -1; + } + blob->name = os_strdup(WPS_BLOB_NAME_REQUIRE); + + blob->len = TLV_BYTES(WPS_ELEM_LEN_NETWORK_INDEX) + + TLV_BYTES(WPS_ELEM_LEN_MAC_ADDRESS) + + TLV_BYTES(WPS_ELEM_LEN_AUTHENTICATION_TYPE_FLAG) + + TLV_BYTES(WPS_ELEM_LEN_ENCRYPTION_TYPE_FLAG) + + TLV_BYTES(WPS_ELEM_LEN_NETWORK_KEY); + + if (NULL == (blob->data = os_malloc(blob->len))) { + os_free(blob); + return -1; + } + + pos = blob->data; + pos = tlv_write_u8(pos, WPS_ELEM_NETWORK_INDEX, ssid->id & 0xff); + pos = tlv_write(pos, WPS_ELEM_MAC_ADDRESS, ETH_ALEN, + wpa_s->own_addr); + + if (wpa_s->conf->uuid_e) { + if (uuid_str2bin(wpa_s->conf->uuid_e, uuid_e)) { + wpa_printf(MSG_ERROR, "EAP-WPS: bad UUID format %s", + wpa_s->conf->uuid_e); + wpa_hexdump(MSG_DEBUG, "EAP-WPS:", uuid_e, WPS_UUID_LEN); + return -1; + } + } + pos = tlv_write(pos, WPS_ELEM_UUID_E, WPS_ELEM_LEN_UUID_E, uuid_e); + /* + * Borrow the vendor extension element to pass down the PIN. + * Note that this doesn't follow the WPS format + */ + pos = tlv_write(pos, WPS_ELEM_VENDOR_EXTENSION, WPS_PIN_LEN, + (u8 *)wps_sm_get_pin(wpa_s->wps)); + + if (WPA_KEY_MGMT_NONE & ssid->key_mgmt) + auth |= WPS_AUTHENTICATION_TYPE_OPEN; + if (WPA_KEY_MGMT_PSK & ssid->key_mgmt) { + if (WPA_PROTO_WPA & ssid->proto) + auth |= WPS_AUTHENTICATION_TYPE_WPAPSK; + if (WPA_PROTO_RSN & ssid->proto) + auth |= WPS_AUTHENTICATION_TYPE_WPA2PSK; + } + if (WPA_KEY_MGMT_IEEE8021X & ssid->key_mgmt) { + if (WPA_PROTO_WPA & ssid->proto) + auth |= WPS_AUTHENTICATION_TYPE_WPA; + if (WPA_PROTO_RSN & ssid->proto) + auth |= WPS_AUTHENTICATION_TYPE_WPA2; + } + pos = tlv_write_u16(pos, WPS_ELEM_AUTHENTICATION_TYPE_FLAG, auth); + + if ((WPA_CIPHER_NONE & ssid->pairwise_cipher) || + (WPA_CIPHER_NONE & ssid->group_cipher)) + encr |= WPS_ENCRYPTION_TYPE_NONE; + if (((WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104) & ssid->pairwise_cipher) || + ((WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104) & ssid->group_cipher)) + encr |= WPS_ENCRYPTION_TYPE_WEP; + if ((WPA_CIPHER_TKIP & ssid->pairwise_cipher) || + (WPA_CIPHER_TKIP & ssid->group_cipher)) + encr |= WPS_ENCRYPTION_TYPE_TKIP; + if ((WPA_CIPHER_CCMP & ssid->pairwise_cipher) || + (WPA_CIPHER_CCMP & ssid->group_cipher)) + encr |= WPS_ENCRYPTION_TYPE_AES; + pos = tlv_write_u16(pos, WPS_ELEM_ENCRYPTION_TYPE_FLAG, encr); + + pos = tlv_write(pos, WPS_ELEM_NETWORK_KEY, sizeof(ssid->psk), ssid->psk); + + wpa_config_set_blob(wpa_s->conf, blob); + + return 0; +} + + +/** + * wpa_supplicant_wps_supp_get_config - convert a WPS blob into wpa_ssid('s) + */ +int wpa_supplicant_wps_supp_get_config(struct wpa_supplicant *wpa_s) +{ + const struct wpa_config_blob *blob; + const u8 *pos; + const u8 *end; + u16 tlv_type, tlv_len; + u16 auth_type = 0; + u16 encryption_type = 0; + u8 *network_key = NULL; + size_t network_key_len = 0; + struct wpa_ssid *ssid = NULL; + + blob = wpa_config_get_blob(wpa_s->conf, WPS_BLOB_NAME_RESULT); + if (NULL == blob) + return -1; + + pos = blob->data; + end = pos + blob->len; + + do { + tlv_type = TLV_GET_TYPE(pos); + tlv_len = TLV_GET_LEN(pos); + pos = TLV_GET_VAL(pos); + + switch (tlv_type) { + case WPS_ELEM_NETWORK_INDEX: + ssid = wpa_config_add_network(wpa_s->conf); + if (NULL == ssid) { + return -1; + } + wpa_config_set_network_defaults(ssid); + + ssid->disabled = 1; + ssid->proto = 0; + ssid->key_mgmt = 0; + ssid->pairwise_cipher = 0; + ssid->group_cipher = 0; + break; + case WPS_ELEM_SSID: + ssid->ssid = os_realloc(ssid->ssid, tlv_len); + if (NULL != ssid->ssid) { + os_memcpy(ssid->ssid, pos, tlv_len); + ssid->ssid_len = tlv_len; + } else { + ssid->ssid_len = 0; + } + break; + case WPS_ELEM_AUTHENTICATION_TYPE_FLAG: + auth_type = WPA_GET_BE16(pos); + + if (auth_type & WPS_AUTHENTICATION_TYPE_Shared) { + ssid->auth_alg = WPA_AUTH_ALG_SHARED; + wpa_printf(MSG_DEBUG, "EAP-WPS: shared key authentication"); + } else { + ssid->auth_alg = WPA_AUTH_ALG_OPEN; + wpa_printf(MSG_DEBUG, "EAP-WPS: open system authentication"); + } + + if (auth_type & WPS_AUTHENTICATION_TYPE_OPEN) { + ssid->key_mgmt = WPA_KEY_MGMT_NONE; + } else { + if (auth_type & + (WPS_AUTHENTICATION_TYPE_WPAPSK | + WPS_AUTHENTICATION_TYPE_WPA)) { + ssid->proto |= WPA_PROTO_WPA; + wpa_printf(MSG_DEBUG, "EAP-WPS: protocol WPA"); + if (auth_type & WPS_AUTHENTICATION_TYPE_WPAPSK) { + ssid->key_mgmt |= WPA_KEY_MGMT_PSK; + wpa_printf(MSG_DEBUG, "EAP-WPS: key management PSK"); + } + } + + if (auth_type & + (WPS_AUTHENTICATION_TYPE_WPA2PSK | + WPS_AUTHENTICATION_TYPE_WPA2)) { + ssid->proto |= WPA_PROTO_RSN; + wpa_printf(MSG_DEBUG, "EAP-WPS: protocol RSN"); + if (auth_type & WPS_AUTHENTICATION_TYPE_WPA2PSK) { + ssid->key_mgmt |= WPA_KEY_MGMT_PSK; + wpa_printf(MSG_DEBUG, "EAP-WPS: key management PSK"); + } + } + } + break; + case WPS_ELEM_ENCRYPTION_TYPE_FLAG: + encryption_type = WPA_GET_BE16(pos); + + if (encryption_type & WPS_ENCRYPTION_TYPE_NONE) { + ssid->pairwise_cipher |= WPA_CIPHER_NONE; + ssid->group_cipher |= WPA_CIPHER_NONE; + wpa_printf(MSG_DEBUG, "EAP-WPS: cipher NONE"); + } + + if (encryption_type & WPS_ENCRYPTION_TYPE_WEP) { + ssid->pairwise_cipher |= WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104; + ssid->group_cipher |= WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104; + wpa_printf(MSG_DEBUG, "EAP-WPS: cipher WEP"); + } + + /* + * WPS has a protocol problem in that a Credential contains a + * single encryption type, but this doesn't account for AP that + * use different ciphers for group and pairwise keys. The safest + * approach is to enable both TKIP and CCMP, and let the upper + * layer sort things out based on the advertised WPA/RSN IE. + */ + if (encryption_type & WPS_ENCRYPTION_TYPE_TKIP || + encryption_type & WPS_ENCRYPTION_TYPE_AES) { + ssid->pairwise_cipher |= WPA_CIPHER_TKIP | WPA_CIPHER_CCMP; + ssid->group_cipher |= WPA_CIPHER_TKIP | WPA_CIPHER_CCMP; + wpa_printf(MSG_DEBUG, "EAP-WPS: cipher TKIP/CCMP"); + } + break; + case WPS_ELEM_NETWORK_KEY: + network_key = (u8 *)pos; + network_key_len = tlv_len; + + if (network_key) { + wpa_hexdump_key(MSG_DEBUG, "EAP-WPS: Network key", + network_key, network_key_len); + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { + if (network_key_len < WPS_WPAPSK_PASSPHRASE_LEN) { + size_t len = network_key_len; + + ssid->psk_set = 0; + os_free(ssid->passphrase); + ssid->passphrase = os_malloc(len +1); + if (NULL == ssid->passphrase) { + wpa_printf(MSG_DEBUG, "EAP-WPS: alloc failed for passphrase"); + } else { + os_memcpy(ssid->passphrase, network_key, len); + ssid->passphrase[len] = '\0'; + } + wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-WPS: passphrase", + (u8 *) ssid->passphrase, + os_strlen(ssid->passphrase)); + wpa_config_update_psk(ssid); + } else { + ssid->psk_set = 1; + hexstr2bin((const char *)network_key, ssid->psk, + PMK_LEN); + } + wpa_hexdump_key(MSG_DEBUG, "EAP-WPS: psk", ssid->psk, + PMK_LEN); + } else { + wpa_printf(MSG_ERROR, "EAP-WPS: key management not PSK"); + } + ssid->disabled = 0; + } + break; + } + + pos += tlv_len; + } while (pos < end); + + return 0; +} diff --git a/wpa_supplicant/wpas_glue.h b/wpa_supplicant/wpas_glue.h index b571e4d..f5ea4a4 100644 --- a/wpa_supplicant/wpas_glue.h +++ b/wpa_supplicant/wpas_glue.h @@ -19,5 +19,8 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s); int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s); void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); +int wpa_supplicant_wps_supp_set_config(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); +int wpa_supplicant_wps_supp_get_config(struct wpa_supplicant *wpa_s); #endif /* WPAS_GLUE_H */