diff -urN wpa_supplicant-0.5.10.orig/config.c wpa_supplicant-0.5.10/config.c --- wpa_supplicant-0.5.10.orig/config.c 2008-02-17 16:27:56.000000000 -0800 +++ wpa_supplicant-0.5.10/config.c 2008-08-13 11:00:41.880743000 -0700 @@ -378,6 +378,8 @@ 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); @@ -429,6 +431,14 @@ 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; } @@ -1139,6 +1149,9 @@ { STR(key_id) }, { INT(engine) }, { INT(eapol_flags) }, +#ifdef EAP_WPS + { STR(uuid_e) }, +#endif #endif /* IEEE8021X_EAPOL */ { FUNC_KEY(wep_key0) }, { FUNC_KEY(wep_key1) }, @@ -1305,6 +1318,10 @@ os_free(ssid->pin); os_free(ssid->engine_id); os_free(ssid->key_id); +#ifdef EAP_WPS + os_free(ssid->uuid_e); + os_free(ssid->wps_pin); +#endif os_free(ssid->otp); os_free(ssid->pending_req_otp); os_free(ssid->pac_file); diff -urN wpa_supplicant-0.5.10.orig/config_file.c wpa_supplicant-0.5.10/config_file.c --- wpa_supplicant-0.5.10.orig/config_file.c 2007-03-24 19:09:49.000000000 -0700 +++ wpa_supplicant-0.5.10/config_file.c 2008-07-16 15:27:06.067472000 -0700 @@ -104,7 +104,13 @@ wpa_config_update_psk(ssid); } - if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) { + if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && + !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++; diff -urN wpa_supplicant-0.5.10.orig/config_ssid.h wpa_supplicant-0.5.10/config_ssid.h --- wpa_supplicant-0.5.10.orig/config_ssid.h 2007-12-27 15:59:35.000000000 -0800 +++ wpa_supplicant-0.5.10/config_ssid.h 2008-09-03 09:45:20.767315000 -0700 @@ -36,6 +36,7 @@ #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) @@ -46,7 +47,6 @@ #define EAP_PSK_LEN_MIN 16 #define EAP_PSK_LEN_MAX 32 - #define DEFAULT_EAP_WORKAROUND ((unsigned int) -1) #define DEFAULT_EAPOL_FLAGS (EAPOL_FLAG_REQUIRE_KEY_UNICAST | \ EAPOL_FLAG_REQUIRE_KEY_BROADCAST) @@ -590,6 +590,38 @@ */ int eapol_flags; + /** + * uuid_e - The Universally Unique ID for the enrollee + * + * This is supplied by the user. The format should be + * 16 hex digits in ASCII format. + * + */ + char *uuid_e; + + /** + * wps_pin - The WPS PIN number + * + * This is created by the supplicant + */ + char *wps_pin; + + /** + * own_addr - The MAC address of this device + * + * This field should not be set in the configuration step. It is only + * used internally in the construction of WPS messages. + */ + u8 own_addr[ETH_ALEN]; + + /** + * assoc_state - The WPS association state + * + * This field should not be set in the configuration step. It is only + * used internally. + */ + u16 assoc_state; + #endif /* IEEE8021X_EAPOL */ #define NUM_WEP_KEYS 4 diff -urN wpa_supplicant-0.5.10.orig/crypto_internal.c wpa_supplicant-0.5.10/crypto_internal.c --- wpa_supplicant-0.5.10.orig/crypto_internal.c 2007-03-24 19:09:49.000000000 -0700 +++ wpa_supplicant-0.5.10/crypto_internal.c 2008-07-31 15:13:16.148445000 -0700 @@ -625,7 +625,7 @@ } -#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 -urN wpa_supplicant-0.5.10.orig/ctrl_iface.c wpa_supplicant-0.5.10/ctrl_iface.c --- wpa_supplicant-0.5.10.orig/ctrl_iface.c 2007-11-27 20:55:36.000000000 -0800 +++ wpa_supplicant-0.5.10/ctrl_iface.c 2008-07-24 10:17:50.678496000 -0700 @@ -17,10 +17,12 @@ #include "common.h" #include "eloop.h" #include "wpa.h" +#include "wps.h" #include "wpa_supplicant.h" #include "config.h" #include "eapol_sm.h" #include "wpa_supplicant_i.h" +#include "wps_i.h" #include "ctrl_iface.h" #include "l2_packet.h" #include "preauth.h" @@ -470,6 +472,32 @@ return pos; } +#ifdef EAP_WPS +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; +} +#endif + static int wpa_supplicant_ctrl_iface_scan_results( struct wpa_supplicant *wpa_s, char *buf, size_t buflen) @@ -509,7 +537,14 @@ res->rsn_ie, res->rsn_ie_len); } - if (!res->wpa_ie_len && !res->rsn_ie_len && +#ifdef EAP_WPS + if (res->wps_ie_len) { + pos = wps_ie_txt(pos, end, "WPS", + res->wps_ie, + res->wps_ie_len); + } +#endif + if (!res->wpa_ie_len && !res->rsn_ie_len && !res->wps_ie_len && res->caps & IEEE80211_CAP_PRIVACY) { ret = os_snprintf(pos, end - pos, "[WEP]"); if (ret < 0 || ret >= end - pos) @@ -1195,6 +1230,14 @@ } else if (os_strcmp(buf, "INTERFACES") == 0) { reply_len = wpa_supplicant_global_iface_interfaces( wpa_s->global, reply, reply_size); +#ifdef EAP_WPS + } else if (os_strcmp(buf, "PBC") == 0) { + wps_config_pbc(wpa_s); + } else if (os_strcmp(buf, "PIN_GET") == 0) { + reply_len = wps_get_pin(wpa_s, reply, reply_size); + } else if (os_strcmp(buf, "PIN_ENTERED") == 0) { + wps_config_pin(wpa_s); +#endif } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; diff -urN wpa_supplicant-0.5.10.orig/defconfig wpa_supplicant-0.5.10/defconfig --- wpa_supplicant-0.5.10.orig/defconfig 2007-12-08 20:20:43.000000000 -0800 +++ wpa_supplicant-0.5.10/defconfig 2008-09-03 10:24:13.487315000 -0700 @@ -158,6 +158,13 @@ # Include support for optional SHA256 cipher suite in EAP-GPSK #CONFIG_EAP_GPSK_SHA256=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 -urN wpa_supplicant-0.5.10.orig/driver_bsd.c wpa_supplicant-0.5.10/driver_bsd.c --- wpa_supplicant-0.5.10.orig/driver_bsd.c 2006-09-11 19:33:20.000000000 -0700 +++ wpa_supplicant-0.5.10/driver_bsd.c 2008-07-29 14:25:40.062405000 -0700 @@ -608,6 +608,12 @@ return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); } +static int __inline +iswpsoui(const u_int8_t *frm) +{ + return frm[1] > 3 && LE_READ_4(frm+2) == ((WPS_OUI_TYPE<<24)|WPA_OUI); +} + static int wpa_driver_bsd_get_scan_results(void *priv, struct wpa_scan_result *results, @@ -646,12 +652,17 @@ while (ielen > 0) { switch (vp[0]) { case IEEE80211_ELEMID_VENDOR: - if (!iswpaoui(vp)) - break; - wsr->wpa_ie_len = - min(2+vp[1], SSID_MAX_WPA_IE_LEN); - os_memcpy(wsr->wpa_ie, vp, - wsr->wpa_ie_len); + if (iswpaoui(vp)) { + wsr->wpa_ie_len = + min(2+vp[1], SSID_MAX_WPA_IE_LEN); + os_memcpy(wsr->wpa_ie, vp, + wsr->wpa_ie_len); + } else if (iswpsoui(vp)) { + wsr->wps_ie_len = + min(2+vp[1], SSID_MAX_WPS_IE_LEN); + os_memcpy(wsr->wps_ie, vp, + wsr->wps_ie_len); + } break; case IEEE80211_ELEMID_RSN: wsr->rsn_ie_len = diff -urN wpa_supplicant-0.5.10.orig/driver.h wpa_supplicant-0.5.10/driver.h --- wpa_supplicant-0.5.10.orig/driver.h 2007-03-24 19:09:49.000000000 -0700 +++ wpa_supplicant-0.5.10/driver.h 2008-08-15 11:50:28.541490000 -0700 @@ -31,6 +31,7 @@ #define IEEE80211_CAP_PRIVACY 0x0010 #define SSID_MAX_WPA_IE_LEN 40 +#define SSID_MAX_WPS_IE_LEN 257 /** * struct wpa_scan_result - Scan results * @bssid: BSSID @@ -40,6 +41,8 @@ * @wpa_ie_len: length of the wpa_ie * @rsn_ie: RSN IE * @rsn_ie_len: length of the RSN IE + * @wps_ie: WPS IE + * @wps_ie_len: length of the WPS IE * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1) * @caps: capability information field in host byte order * @qual: signal quality @@ -59,6 +62,8 @@ size_t wpa_ie_len; u8 rsn_ie[SSID_MAX_WPA_IE_LEN]; size_t rsn_ie_len; + u8 wps_ie[SSID_MAX_WPS_IE_LEN]; + size_t wps_ie_len; int freq; u16 caps; int qual; @@ -145,6 +150,15 @@ 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 { @@ -752,6 +766,15 @@ * (management frame processing) to wpa_supplicant. */ int (*mlme_remove_sta)(void *priv, const u8 *addr); + + /** + * * set_probe_req_ie - Set information element(s) for Probe Request + * @priv: private driver interface data + * @ies: Information elements to append or %NULL to remove extra IEs + * @ies_len: Length of the IE buffer in octets + * Returns: 0 on success, -1 on failure + */ + int (*set_probe_req_ie)(void *priv, u8 *ies, size_t ies_len); }; #endif /* DRIVER_H */ diff -urN wpa_supplicant-0.5.10.orig/driver_wext.c wpa_supplicant-0.5.10/driver_wext.c --- wpa_supplicant-0.5.10.orig/driver_wext.c 2008-02-17 10:38:29.000000000 -0800 +++ wpa_supplicant-0.5.10/driver_wext.c 2008-08-18 15:42:58.482858000 -0700 @@ -1302,20 +1302,33 @@ while (gpos + 1 < gend && gpos + 2 + (u8) gpos[1] <= gend) { u8 ie = gpos[0], ielen = gpos[1] + 2; + /* XXX cft - removed check because WPS IE length (7-257) can be + * much bigger than the WPA IE length (40) + */ +#if 0 if (ielen > SSID_MAX_WPA_IE_LEN) { gpos += ielen; continue; } +#endif switch (ie) { case GENERIC_INFO_ELEM: - if (ielen < 2 + 4 || - os_memcmp(&gpos[2], - "\x00\x50\xf2\x01", 4) != - 0) + if (ielen < 2 + 4) break; - os_memcpy(results[ap_num].wpa_ie, gpos, - ielen); - results[ap_num].wpa_ie_len = ielen; + else if (os_memcmp(&gpos[2], + "\x00\x50\xf2\x01", 4) == 0) { + os_memcpy(results[ap_num].wpa_ie, gpos, + ielen); + results[ap_num].wpa_ie_len = ielen; + } +#ifdef EAP_WPS + else if (os_memcmp(&gpos[2], + "\x00\x50\xf2\x04", 4) == 0) { + os_memcpy(results[ap_num].wps_ie, gpos, + ielen); + results[ap_num].wps_ie_len = ielen; + } +#endif break; case RSN_INFO_ELEM: os_memcpy(results[ap_num].rsn_ie, gpos, @@ -1830,9 +1843,15 @@ /* 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) - < 0) - ret = -1; + 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) value = IW_AUTH_WPA_VERSION_DISABLED; else if (params->wpa_ie[0] == RSN_INFO_ELEM) @@ -2327,6 +2346,11 @@ return 0; } +int wpa_driver_wext_set_ie(void *priv, 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) { @@ -2366,4 +2390,5 @@ .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 -urN wpa_supplicant-0.5.10.orig/eap.c wpa_supplicant-0.5.10/eap.c --- wpa_supplicant-0.5.10.orig/eap.c 2007-03-24 19:09:50.000000000 -0700 +++ wpa_supplicant-0.5.10/eap.c 2008-09-03 07:53:11.097315000 -0700 @@ -665,7 +665,11 @@ 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); @@ -969,6 +973,11 @@ identity_len = config->identity_len; wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from " "IMSI", identity, identity_len); +#ifdef EAP_WPS + } else if (config->proto & WPA_PROTO_WPS) { + identity = (u8 *)WPS_EAP_IDENTITY; + identity_len = os_strlen(WPS_EAP_IDENTITY); +#endif } else { eap_sm_request_identity(sm); return NULL; diff -urN wpa_supplicant-0.5.10.orig/eap_defs.h wpa_supplicant-0.5.10/eap_defs.h --- wpa_supplicant-0.5.10.orig/eap_defs.h 2007-03-24 19:09:50.000000000 -0700 +++ wpa_supplicant-0.5.10/eap_defs.h 2008-06-21 13:42:20.579960000 -0700 @@ -41,6 +41,7 @@ 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 */ @@ -66,9 +67,12 @@ /* SMI Network Management Private Enterprise Code for vendor specific types */ enum { - EAP_VENDOR_IETF = 0 + EAP_VENDOR_IETF = 0, + EAP_VENDOR_WFA = 14122 }; +#define WPS_EAP_IDENTITY "WFA-SimpleConfig-Enrollee-1-0" + #define EAP_MSK_LEN 64 #define EAP_EMSK_LEN 64 diff -urN wpa_supplicant-0.5.10.orig/eap_methods.c wpa_supplicant-0.5.10/eap_methods.c --- wpa_supplicant-0.5.10.orig/eap_methods.c 2007-03-24 19:09:50.000000000 -0700 +++ wpa_supplicant-0.5.10/eap_methods.c 2008-06-20 15:18:08.325521000 -0700 @@ -462,6 +462,13 @@ } #endif /* EAP_VENDOR_TEST */ +#ifdef EAP_WPS + if (ret == 0) { + int eap_peer_wps_register(void); + ret = eap_peer_wps_register(); + } +#endif + return ret; } diff -urN wpa_supplicant-0.5.10.orig/eapol_sm.c wpa_supplicant-0.5.10/eapol_sm.c --- wpa_supplicant-0.5.10.orig/eapol_sm.c 2007-12-27 16:33:26.000000000 -0800 +++ wpa_supplicant-0.5.10/eapol_sm.c 2008-09-03 08:53:05.467315000 -0700 @@ -381,6 +381,11 @@ 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)) @@ -1331,6 +1336,7 @@ 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 -urN wpa_supplicant-0.5.10.orig/eapol_sm.h wpa_supplicant-0.5.10/eapol_sm.h --- wpa_supplicant-0.5.10.orig/eapol_sm.h 2007-03-24 19:09:50.000000000 -0700 +++ wpa_supplicant-0.5.10/eapol_sm.h 2008-08-08 15:10:58.043032000 -0700 @@ -59,6 +59,13 @@ * 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 -urN wpa_supplicant-0.5.10.orig/eap_wps.c wpa_supplicant-0.5.10/eap_wps.c --- wpa_supplicant-0.5.10.orig/eap_wps.c 1969-12-31 16:00:00.000000000 -0800 +++ wpa_supplicant-0.5.10/eap_wps.c 2008-09-03 08:21:30.077315000 -0700 @@ -0,0 +1,1807 @@ +/* + * EAP peer method: EAP-WPS + * Copyright (c) 2008, Chuck Tuffli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "eap_i.h" +#include "config.h" +#include "config_ssid.h" +#include "sha256.h" +#include "aes_wrap.h" +#include "crypto.h" +#include "wps.h" +#include "wpa_ctrl.h" + +/** + * WPS_PARSE_ERR - Incoming message did not parse correctly + */ +#define WPS_PARSE_ERR -1 + +/** + * WPS_AUTHENTICATOR_ERR - Incoming message's authenticator invalid + */ +#define WPS_AUTHENTICATOR_ERR -2 + +/** + * WPS_M2D_ERR - Received a M2D message instead of M2 + */ +#define WPS_M2D_ERR -3 + +/** + * WPS_NONCE_LEN - Byte length of 128-bit random number (nonce) + */ +#define WPS_NONCE_LEN (128/8) + +/** + * EAP_WPS_KDK_LEN - Byte length of 256-bit HMAC-SHA-256 Key Derivation Key + */ +#define EAP_WPS_KDK_LEN (256/8) + +/** + * WPS_AUTHKEY_LEN - AuthKey byte length (256-bits) + */ +#define WPS_AUTHKEY_LEN (256/8) + +/** + * WPS_KEYWRAPKEY_LEN - KeyWrapKey byte length (128-bits) + */ +#define WPS_KEYWRAPKEY_LEN (128/8) + +/** + * WPS_EMSK_LEN - EMSK byte length (256-bits) + */ +#define WPS_EMSK_LEN (256/8) + +/** + * WPS_S_NONCE_LEN - Secret nonces (ie E-S1, E-S2, R-S1, R-S2) byte length (128-bits) + */ +#define WPS_S_NONCE_LEN (128/8) + +/** + * WPS_AUTHENTICATOR_LEN - Authenticator element byte length (64-bits) + */ +#define WPS_AUTHENTICATOR_LEN (64/8) + +/** + * WPS_IV_LEN - Initialization Vector Length (128-bits) + */ +#define WPS_IV_LEN (128/8) + +/** + * WPS_KWA_LEN - Key Wrap Authenticator Length (64-bits) + */ +#define WPS_KWA_LEN (64/8) + +/** + * WPS_ENCRYPTED_SETTINGS_LEN - Encrypted Settings Length + */ +#define WPS_ENCRYPTED_SETTINGS_LEN 64 + +/** + * WPS_PK_LEN - Enrollee/Registrar's Public Key length (1536-bits) + */ +#define WPS_PK_LEN (1536/8) + +/** + * WPS_MSG_BUF_LEN - Default allocation size of the message buffer + */ +#define WPS_MSG_BUF_LEN 512 + +#define WPS_WPAPSK_PASSPHRASE_LEN 64 + +#define WPS_TLV_LEN 4 +#define WPS_TLV_GET_TYPE(p) WPA_GET_BE16(p) +#define WPS_TLV_GET_LEN(p) WPA_GET_BE16(((u8 *)(p)) + 2) +#define WPS_TLV_GET_VAL(p) (((u8 *)(p)) + WPS_TLV_LEN) + + +/** + * MODP - The 1536 bit MODP group used by WPS (see RFC 3526) + */ +static const u8 wps_dh_modp[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, + 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, + 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, + 0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, + 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, + 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, + 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37, + 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, + 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, + 0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, + 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, + 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, + 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6, + 0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, + 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05, + 0x98, 0xda, 0x48, 0x36, 0x1c, 0x55, 0xd3, 0x9a, + 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f, + 0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, + 0x1c, 0x62, 0xf3, 0x56, 0x20, 0x85, 0x52, 0xbb, + 0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, + 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04, + 0xf1, 0x74, 0x6c, 0x08, 0xca, 0x23, 0x73, 0x27, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + + +static const char *config_err_str[] = { + "No Error", + "OOB Interface Read Error", + "Decryption CRC Failure", + "2.4 channel not supported", + "5.0 channel not supported", + "Signal too weak", + "Network auth failure", + "Network association failure", + "No DHCP response", + "Failed DHCP config", + "IP address conflict", + "Couldn’t connect to Registrar", + "Multiple PBC sessions detected", + "Rogue activity suspected", + "Device busy", + "Setup locked", + "Message Timeout", + "Registration Session Timeout", + "Device Password Auth Failure" +}; + +static const size_t config_err_str_len = sizeof(config_err_str)/sizeof(char *); + +static const size_t wps_dh_modp_size = sizeof(wps_dh_modp); + + +static const u8 wps_dh_generator = 2; + + +struct eap_wps_data { + enum { WPS_START, WPS_M2, WPS_M4, WPS_M6, WPS_M8 } state; + + /* Enrollee's nonce */ + u8 N1[WPS_NONCE_LEN]; + + /* Enrollee's Diffie-Hellman private (secret) key */ + u8 SKE[WPS_PK_LEN]; + + /* Enrollee's Diffie-Hellman public key */ + u8 PKE[WPS_PK_LEN]; + + /* Enrollee's PSK values derived from Device Password */ + u8 PSK1[SHA256_MAC_LEN]; + u8 PSK2[SHA256_MAC_LEN]; + + /* Enrollee's secret nonces */ + u8 ES1[WPS_S_NONCE_LEN]; + u8 ES2[WPS_S_NONCE_LEN]; + + /* Registrar's nonce */ + u8 N2[WPS_NONCE_LEN]; + + /* Registrar's Diffie-Hellman public key */ + u8 PKR[WPS_PK_LEN]; + + /* Registrar's Hashes */ + u8 RHASH1[SHA256_MAC_LEN]; + u8 RHASH2[SHA256_MAC_LEN]; + + u8 authKey[WPS_AUTHKEY_LEN]; + u8 keyWrapKey[WPS_KEYWRAPKEY_LEN]; + u8 emsk[WPS_EMSK_LEN]; + + u8 *prv_msg; + size_t prv_msg_len; + + u8 *ssid; + size_t ssid_len; + u8 *network_key; + size_t network_key_len; + u16 auth_type; + u16 encryption_type; +}; + + +static int wps_dh_key(struct eap_wps_data *data); +static int eap_wps_kdk(struct eap_wps_data *data, u8 *enrolleeMac, u8 *kdk); +static int eap_wps_kdf(struct eap_wps_data *data, const u8 *kdk); +static int eap_wps_hash(u8 *authKey, u8 *PSK, u8 *PKE, u8 *PKR, u8 *ES, + char *dev_passwd, size_t dev_passwd_len, u8 *hash); +static int eap_wps_authenticator(u8 *authKey, const u8 *d1, size_t d1_len, + u8 *d2, size_t d2_len, u8 *auth); +static int eap_wps_authenticator_check(u8 *authKey, + const u8 *prv, size_t prv_len, + const u8 *cur, size_t cur_len, + const u8 *auth); +static int eap_wps_encrypted_settings(u8 *authKey, u8 *keyWrapKey, + u16 type, u8 *data, size_t data_len, + u8 *encrypted); +static int eap_wps_decrypt_settings(struct eap_wps_data *data, u8 *iv, + u8 *encrypted, size_t encrypted_len, + u8 *decrypted, size_t *decrypted_len); + + +static u8 * eap_wps_write_tlv(u8 *buf, u16 type, u16 len, u8 *val) +{ + u8 *start; + + WPA_PUT_BE16(buf, type); + WPA_PUT_BE16(buf + 2, len); + + start = WPS_TLV_GET_VAL(buf); + os_memcpy(start, val, len); + start += len; + + return start; +} + + +static inline u8 * eap_wps_write_tlv_u8(u8 *buf, u16 type, u8 val) +{ + return eap_wps_write_tlv(buf, type, 1, &val); +} + + +static inline u8 * eap_wps_write_tlv_u16(u8 *buf, u16 type, u16 val) +{ + u16 be_val = host_to_be16(val); + + return eap_wps_write_tlv(buf, type, 2, (u8 *) &be_val); +} + + +/** + * eap_wps_msg_M1 - Create the payload for a M1 message + */ +static u8 *eap_wps_msg_M1(struct eap_wps_data *data, struct wpa_ssid *ssid, + size_t *len) +{ + u8 *payload = NULL, *p; + u16 val16; + u8 uuid_e[WPS_UUID_LEN]; + + *len = 0; + + if (ssid->uuid_e) { + if (hexstr2bin(ssid->uuid_e, uuid_e, WPS_UUID_LEN)) { + wpa_printf(MSG_ERROR, "EAP-WPS: bad UUID format %s", ssid->uuid_e); + return NULL; + } + } + + wpa_hexdump(MSG_DEBUG, "EAP-WPS: UUID", uuid_e, WPS_UUID_LEN); + + if (NULL != (p = payload = os_malloc(WPS_MSG_BUF_LEN))) { + *p++ = WPS_OPCODE_WSC_MSG; + *p++ = 0; /* Flags */ + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_VERSION, WPS_VERSION_1_0); + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_MESSAGE_TYPE, WPS_MESSAGE_TYPE_M1); + + p = eap_wps_write_tlv(p, WPS_ELEM_UUID_E, WPS_UUID_LEN, uuid_e); + + p = eap_wps_write_tlv(p, WPS_ELEM_MAC_ADDRESS, ETH_ALEN, + ssid->own_addr); + + p = eap_wps_write_tlv(p, WPS_ELEM_ENROLLEE_NONCE, WPS_NONCE_LEN, + data->N1); + + if (wps_dh_key(data)) { + os_free(payload); + return NULL; + } + p = eap_wps_write_tlv(p, WPS_ELEM_PUBLIC_KEY, WPS_PK_LEN, data->PKE); + + val16 = 0; + if (WPA_AUTH_ALG_SHARED == ssid->auth_alg) { + val16 |= WPS_AUTHENTICATION_TYPE_Shared; + } else { + val16 |= WPS_AUTHENTICATION_TYPE_OPEN; + } + /* Only support PSK although other values are defined */ + val16 |= + WPS_AUTHENTICATION_TYPE_WPAPSK | + WPS_AUTHENTICATION_TYPE_WPA2PSK; + p = eap_wps_write_tlv_u16(p, WPS_ELEM_AUTHENTICATION_TYPE_FLAG, + val16); + + val16 = 0; + if ((ssid->pairwise_cipher & WPA_CIPHER_TKIP) || + (ssid->group_cipher & WPA_CIPHER_TKIP)) { + val16 |= WPS_ENCRYPTION_TYPE_TKIP; + } + if ((ssid->pairwise_cipher & WPA_CIPHER_CCMP) || + (ssid->group_cipher & WPA_CIPHER_CCMP)) { + val16 |= WPS_ENCRYPTION_TYPE_AES; + } + p = eap_wps_write_tlv_u16(p, WPS_ELEM_ENCRYPTION_TYPE_FLAG, + val16); + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_CONNECTION_TYPE_FLAG, + WPS_CONNECTION_TYPE_ESS); + + p = eap_wps_write_tlv_u16(p, WPS_ELEM_CONFIG_METHODS, + WPS_CONFIG_METHOD_LABEL | + WPS_CONFIG_METHOD_DISPLAY | + WPS_CONFIG_METHOD_PBC); + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_WPS_STATE, + WPS_SETUP_STATE_NOT_CONFIGURED); + + /* TODO get these somehow instead of using "None" and PC type */ + p = eap_wps_write_tlv(p, WPS_ELEM_MANUFACTURER, 4, (u8 *)"None"); + + p = eap_wps_write_tlv(p, WPS_ELEM_MODEL_NAME, 4, (u8 *)"None"); + + p = eap_wps_write_tlv(p, WPS_ELEM_MODEL_NUMBER, 4, (u8 *)"None"); + + p = eap_wps_write_tlv(p, WPS_ELEM_SERIAL_NUMBER, 4, (u8 *)"None"); + + p = eap_wps_write_tlv(p, WPS_ELEM_PRIMARY_DEVICE_TYPE, 8, + (u8 *)"\x00\x01\x00\x50\xf2\x04\x00\x01"); + + p = eap_wps_write_tlv(p, WPS_ELEM_DEVICE_NAME, 4, (u8 *)"None"); + + /* TODO get this somehow instead of assuming a dual-mode device */ + p = eap_wps_write_tlv_u8(p, WPS_ELEM_RF_BANDS, + WPS_RF_BAND_2_4GHZ | WPS_RF_BAND_5_0GHZ); + + p = eap_wps_write_tlv_u16(p, WPS_ELEM_ASSOCIATION_STATE, + WPS_ASSOCIATION_STATE_NOT_ASSOCIATED); + + p = eap_wps_write_tlv_u16(p, WPS_ELEM_DEVICE_PASSWORD_ID, + 0 == os_strncmp(ssid->wps_pin, WPS_PIN_PBC, sizeof(WPS_PIN_PBC)) ? + WPS_DEVICE_PASSWORD_ID_PBC : WPS_DEVICE_PASSWORD_ID_PIN); + + p = eap_wps_write_tlv_u16(p, WPS_ELEM_CONFIGURATION_ERROR, + WPS_CONFIGURATION_ERROR_NO_ERROR); + + p = eap_wps_write_tlv(p, WPS_ELEM_OS_VERSION, 4, (u8 *)"\x00\x00\x00\x01"); + } + + *len = (size_t)p - (size_t)payload; + + return payload; +} + + +/** + * eap_wps_parse_M2 - Parse the payload for a M2 message + */ +static int eap_wps_parse_M2(struct eap_sm *sm, struct eap_wps_data *data, + const u8 *payload, size_t len, u8 **auth) +{ + const u8 *pos = payload; + const u8 *end = pos + len; + u16 tlv_type, tlv_len, tlv_val; + int ret = -1; + + *auth = NULL; + + if (WPS_OPCODE_WSC_MSG != *pos) { + wpa_printf(MSG_WARNING, "EAP-WPS: Message is not WSC_MSG (%#02x)", + *pos); + wpa_hexdump(MSG_WARNING, "message:", pos, len); + return -1; + } + + pos++; /* Opcode */ + pos++; /* Flags */ + + do { + tlv_type = WPS_TLV_GET_TYPE(pos); + tlv_len = WPS_TLV_GET_LEN(pos); + pos = WPS_TLV_GET_VAL(pos); + + switch (tlv_type) { + case WPS_ELEM_MESSAGE_TYPE: + switch (pos[0]) { + case WPS_MESSAGE_TYPE_M2: + ret = 0; + break; + case WPS_MESSAGE_TYPE_M2D: + wpa_printf(MSG_DEBUG, "EAP-WPS: received M2D"); + ret = WPS_M2D_ERR; + break; + default: + wpa_printf(MSG_WARNING, "EAP-WPS: Expecting message M2 but got %#x", + pos[0]); + return WPS_PARSE_ERR; + } + break; + case WPS_ELEM_REGISTRAR_NONCE: + os_memcpy(data->N2, pos, WPS_NONCE_LEN); + break; + case WPS_ELEM_PUBLIC_KEY: + os_memcpy(data->PKR, pos, WPS_PK_LEN); + break; + case WPS_ELEM_CONFIGURATION_ERROR: + tlv_val = WPA_GET_BE16(pos); + if (tlv_val > config_err_str_len) { + wpa_printf(MSG_ERROR, "EAP-WPS: Bad M2 Configuration error value %#x", + tlv_val); + return -1; + } else if (WPS_CONFIGURATION_ERROR_MULTI_PBC == tlv_val) { + wpa_msg(sm->msg_ctx, MSG_ERROR, WPA_EVENT_WPS_OVERLAP); + return -1; + } else if (WPS_CONFIGURATION_ERROR_NO_ERROR != tlv_val) { + wpa_msg(sm->msg_ctx, MSG_ERROR, WPA_EVENT_WPS_ERROR); + wpa_printf(MSG_WARNING, "EAP-WPS: M2 Configuration error %s", + config_err_str[tlv_val]); + return -1; + } + break; + case WPS_ELEM_AUTHENTICATOR: + *auth = (u8 *)pos; + break; + } + + pos += tlv_len; + } while (pos < end); + + return ret; +} + +/** + * eap_wps_msg_M3 - Create the payload for a M3 message + */ +static u8 *eap_wps_msg_M3(struct eap_wps_data *data, const u8 *M2, + size_t M2_len, u8 *addr, char *pin, size_t *len) +{ + size_t half_pin_len; + u8 *payload = NULL, *p; + u8 kdk[EAP_WPS_KDK_LEN]; + u8 hash[SHA256_MAC_LEN]; + u8 authenticator[WPS_AUTHENTICATOR_LEN]; + + *len = 0; + + if (NULL == pin) { + wpa_printf(MSG_ERROR, "EAP-WPS: PIN is NULL?!?"); + return NULL; + } + + wpa_printf(MSG_DEBUG, "EAP-WPS: pin %s", pin); + + half_pin_len = os_strlen(pin) / 2; + + if (NULL != (p = payload = os_malloc(WPS_MSG_BUF_LEN))) { + *p++ = WPS_OPCODE_WSC_MSG; + *p++ = 0; /* Flags */ + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_VERSION, WPS_VERSION_1_0); + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_MESSAGE_TYPE, WPS_MESSAGE_TYPE_M3); + + p = eap_wps_write_tlv(p, WPS_ELEM_REGISTRAR_NONCE, WPS_NONCE_LEN, + data->N2); + + /* Generate a KDK used to create the AuthKey, KeyWrapKey, and EMSK */ + if (eap_wps_kdk(data, addr, kdk)) { + return NULL; + } + + eap_wps_kdf(data, kdk); + + eap_wps_hash(data->authKey, data->PSK1, data->PKE, data->PKR, data->ES1, + pin, half_pin_len, + hash); + p = eap_wps_write_tlv(p, WPS_ELEM_E_HASH1, sizeof(hash), hash); + + eap_wps_hash(data->authKey, data->PSK2, data->PKE, data->PKR, data->ES2, + pin + half_pin_len, half_pin_len, + hash); + p = eap_wps_write_tlv(p, WPS_ELEM_E_HASH2, sizeof(hash), hash); + + *len = (size_t)p - (size_t)payload; + + /* + * Message Authenticator is a keyed hash (HMAC-SHA_256) of (M2 | M3*) + * using the AuthKey. + * Note that M2 and M3 do not include the Opcode or Flags (thus +/- 2) + */ + eap_wps_authenticator(data->authKey, M2 + 2, M2_len - 2, payload + 2, + *len - 2, authenticator); + p = eap_wps_write_tlv(p, WPS_ELEM_AUTHENTICATOR, WPS_AUTHENTICATOR_LEN, + authenticator); + + *len = (size_t)p - (size_t)payload; + } + + return payload; +} + + +/** + * eap_wps_parse_encrypted_settings_snonce - Parse the encrypted settings + * + * TODO fail if any required element is missing (?) + */ +static int eap_wps_parse_encrypted_settings_snonce(struct eap_wps_data *data, + const u8 *settings, size_t len) +{ + const u8 *pos = settings; + const u8 *end; + u16 tlv_type, tlv_len; + const u8 *addr[4]; + size_t vlen[4]; + u8 hash[SHA256_MAC_LEN]; + u8 *expect = NULL; + char *nonce_str = NULL; + + end = settings + len; + + do { + tlv_type = WPS_TLV_GET_TYPE(pos); + tlv_len = WPS_TLV_GET_LEN(pos); + pos = WPS_TLV_GET_VAL(pos); + + switch (tlv_type) { + case WPS_ELEM_R_SNONCE1: + addr[0] = pos; + addr[1] = data->PSK1; + expect = data->RHASH1; + nonce_str = "R-SNonce1"; + break; + case WPS_ELEM_R_SNONCE2: + addr[0] = pos; + addr[1] = data->PSK2; + expect = data->RHASH2; + nonce_str = "R-SNonce2"; + break; + case WPS_ELEM_KEY_WRAP_AUTHENTICATOR: + if (eap_wps_authenticator_check(data->authKey, + settings, len - WPS_TLV_LEN - WPS_AUTHENTICATOR_LEN, + NULL, 0, pos)) + { + wpa_printf(MSG_ERROR, + "EAP-WPS: Key wrap authenticator check fail " + "Encrypted Settings %s", nonce_str); + return -1; + } + break; + default: + wpa_printf(MSG_DEBUG, "EAP-WPS: unknown type (%#x)", tlv_type); + } + + pos += tlv_len; + } while (pos < end); + + vlen[0] = WPS_S_NONCE_LEN; + vlen[1] = SHA256_MAC_LEN/2; /* only use the first 128-bits */ + addr[2] = data->PKE; + vlen[2] = WPS_PK_LEN; + addr[3] = data->PKR; + vlen[3] = WPS_PK_LEN; + + hmac_sha256_vector(data->authKey, WPS_AUTHKEY_LEN, 4, addr, vlen, hash); + + return os_memcmp(expect, hash, SHA256_MAC_LEN); +} + + +/** + * eap_wps_parse_M4 - Parse the payload for a M4 message + * @data: Pointer to WPS data + * @payload: Message buffer to parse + * @len: Length of message buffer + * Returns: 0 if payload is a valid M4 message, -1 if not a valid M4 + * message, or -2 if the Authenticator check fails + */ +static int eap_wps_parse_M4(struct eap_wps_data *data, const u8 *payload, + size_t len) +{ + const u8 *pos = payload; + const u8 *end = pos + len; + u16 tlv_type, tlv_len; + u8 *settings = NULL; + size_t settings_len; + int ret = -1; + + if (WPS_OPCODE_WSC_MSG != *pos) { + wpa_printf(MSG_WARNING, "EAP-WPS: Message is not WSC_MSG (%#02x)", + *pos); + wpa_hexdump(MSG_WARNING, "message:", pos, len); + return WPS_PARSE_ERR; + } + + pos++; /* Opcode */ + pos++; /* Flags */ + + do { + tlv_type = WPS_TLV_GET_TYPE(pos); + tlv_len = WPS_TLV_GET_LEN(pos); + pos = WPS_TLV_GET_VAL(pos); + + switch (tlv_type) { + case WPS_ELEM_MESSAGE_TYPE: + if (WPS_MESSAGE_TYPE_M4 != pos[0]) { + wpa_printf(MSG_WARNING, "EAP-WPS: Expecting message M4 but got %#x", + pos[0]); + return WPS_PARSE_ERR; + } else { + ret = 0; + } + break; + case WPS_ELEM_R_HASH1: + os_memcpy(data->RHASH1, pos, SHA256_MAC_LEN); + break; + case WPS_ELEM_R_HASH2: + os_memcpy(data->RHASH2, pos, SHA256_MAC_LEN); + break; + case WPS_ELEM_ENCRYPTED_SETTINGS: + if (NULL != (settings = os_malloc(tlv_len))) { + /* first 128 bits are IV. remaining bits are the encrypted data */ + eap_wps_decrypt_settings(data, (u8 *)pos, + (u8 *)pos + WPS_IV_LEN, tlv_len - WPS_IV_LEN, + settings, &settings_len); + + if (eap_wps_parse_encrypted_settings_snonce(data, settings, + settings_len)) { + wpa_printf(MSG_ERROR, "EAP-WPS: Incorrect encrypted settings M4"); + return WPS_PARSE_ERR; + } + } + break; + case WPS_ELEM_AUTHENTICATOR: + if (eap_wps_authenticator_check(data->authKey, + data->prv_msg + 2, data->prv_msg_len - 2, + payload + 2, len - 2, pos)) + { + wpa_printf(MSG_ERROR, "EAP-WPS: M4 authenticator check fail"); + return WPS_AUTHENTICATOR_ERR; + } + break; + } + + pos += tlv_len; + } while (pos < end); + + return ret; +} + +/** + * eap_wps_msg_M5 - Create the payload for a M5 message + */ +static u8 *eap_wps_msg_M5(struct eap_wps_data *data, const u8 *M4, size_t M4_len, size_t *len) +{ + u8 *payload = NULL, *p; + u8 encSetting[WPS_ENCRYPTED_SETTINGS_LEN]; + u8 authenticator[WPS_AUTHENTICATOR_LEN]; + + *len = 0; + + if (NULL != (p = payload = os_malloc(WPS_MSG_BUF_LEN))) { + *p++ = WPS_OPCODE_WSC_MSG; + *p++ = 0; /* Flags */ + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_VERSION, WPS_VERSION_1_0); + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_MESSAGE_TYPE, WPS_MESSAGE_TYPE_M5); + + p = eap_wps_write_tlv(p, WPS_ELEM_REGISTRAR_NONCE, WPS_NONCE_LEN, + data->N2); + + eap_wps_encrypted_settings(data->authKey, data->keyWrapKey, WPS_ELEM_E_SNONCE1, + data->ES1, WPS_S_NONCE_LEN, encSetting); + p = eap_wps_write_tlv(p, WPS_ELEM_ENCRYPTED_SETTINGS, sizeof(encSetting), + encSetting); + + *len = (size_t)p - (size_t)payload; + + /* + * Message Authenticator is a keyed hash (HMAC-SHA_256) of (M4 | M5*) + * using the AuthKey. + * Note that M4 and M5 do not include the Opcode or Flags (thus +/- 2) + */ + eap_wps_authenticator(data->authKey, M4 + 2, M4_len - 2, payload + 2, *len - 2, + authenticator); + p = eap_wps_write_tlv(p, WPS_ELEM_AUTHENTICATOR, WPS_AUTHENTICATOR_LEN, + authenticator); + + *len = (size_t)p - (size_t)payload; + } + + return payload; +} + +/** + * eap_wps_parse_M6 - Parse the payload for a M6 message + * @data: Pointer to WPS data + * @payload: Message buffer to parse + * @len: Length of message buffer + * Returns: 0 if payload is a valid M6 message, -1 if not a valid M6 + * message, or -2 if the Authenticator check fails + */ +static int eap_wps_parse_M6(struct eap_wps_data *data, const u8 *payload, + size_t len) +{ + const u8 *pos = payload; + const u8 *end = pos + len; + u16 tlv_type, tlv_len; + u8 *settings = NULL; + size_t settings_len; + int ret = -1; + + if (WPS_OPCODE_WSC_MSG != *pos) { + wpa_printf(MSG_WARNING, "EAP-WPS: Message is not WSC_MSG (%#02x)", + *pos); + wpa_hexdump(MSG_WARNING, "message:", pos, len); + return WPS_PARSE_ERR; + } + + pos++; /* Opcode */ + pos++; /* Flags */ + + do { + tlv_type = WPS_TLV_GET_TYPE(pos); + tlv_len = WPS_TLV_GET_LEN(pos); + pos = WPS_TLV_GET_VAL(pos); + + switch (tlv_type) { + case WPS_ELEM_MESSAGE_TYPE: + if (WPS_MESSAGE_TYPE_M6 != pos[0]) { + wpa_printf(MSG_WARNING, "EAP-WPS: Expecting message M6 but got %#x", + pos[0]); + return WPS_PARSE_ERR; + } else { + ret = 0; + } + break; + case WPS_ELEM_ENCRYPTED_SETTINGS: + if (NULL != (settings = os_malloc(tlv_len))) { + /* first 128 bits are IV. remaining bits are the encrypted data */ + eap_wps_decrypt_settings(data, (u8 *)pos, + (u8 *)pos + WPS_IV_LEN, tlv_len - WPS_IV_LEN, + settings, &settings_len); + + if (eap_wps_parse_encrypted_settings_snonce(data, settings, + settings_len)) { + wpa_printf(MSG_ERROR, "EAP-WPS: Incorrect encrypted settings M6"); + return WPS_PARSE_ERR; + } + } + break; + case WPS_ELEM_AUTHENTICATOR: + if (eap_wps_authenticator_check(data->authKey, + data->prv_msg + 2, data->prv_msg_len - 2, + payload + 2, len - 2, pos)) + { + wpa_printf(MSG_ERROR, "EAP-WPS: M6 authenticator check fail"); + return WPS_AUTHENTICATOR_ERR; + } + break; + } + + pos += tlv_len; + } while (pos < end); + + return ret; +} + +/** + * eap_wps_msg_M7 - Create the payload for a M7 message + */ +static u8 *eap_wps_msg_M7(struct eap_wps_data *data, const u8 *M6, size_t M6_len, size_t *len) +{ + u8 *payload = NULL, *p; + u8 encSetting[WPS_ENCRYPTED_SETTINGS_LEN]; + u8 authenticator[WPS_AUTHENTICATOR_LEN]; + + *len = 0; + + if (NULL != (p = payload = os_malloc(WPS_MSG_BUF_LEN))) { + *p++ = WPS_OPCODE_WSC_MSG; + *p++ = 0; /* Flags */ + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_VERSION, WPS_VERSION_1_0); + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_MESSAGE_TYPE, WPS_MESSAGE_TYPE_M7); + + p = eap_wps_write_tlv(p, WPS_ELEM_REGISTRAR_NONCE, WPS_NONCE_LEN, + data->N2); + + eap_wps_encrypted_settings(data->authKey, data->keyWrapKey, WPS_ELEM_E_SNONCE2, + data->ES2, WPS_S_NONCE_LEN, encSetting); + p = eap_wps_write_tlv(p, WPS_ELEM_ENCRYPTED_SETTINGS, sizeof(encSetting), + encSetting); + + *len = (size_t)p - (size_t)payload; + + /* + * Message Authenticator is a keyed hash (HMAC-SHA_256) of (M6 | M7*) + * using the AuthKey. + * Note that M6 and M7 do not include the Opcode or Flags (thus +/- 2) + */ + eap_wps_authenticator(data->authKey, M6 + 2, M6_len - 2, payload + 2, *len - 2, + authenticator); + p = eap_wps_write_tlv(p, WPS_ELEM_AUTHENTICATOR, WPS_AUTHENTICATOR_LEN, + authenticator); + + *len = (size_t)p - (size_t)payload; + } + + return payload; +} + + +/** + * eap_wps_parse_credential - Parse the Credentials element + */ +static int eap_wps_parse_credential(struct eap_wps_data *data, + const u8 *credential, size_t len) +{ + const u8 *pos = credential; + const u8 *end; + u16 tlv_type, tlv_len; + end = credential + len; + + do { + tlv_type = WPS_TLV_GET_TYPE(pos); + tlv_len = WPS_TLV_GET_LEN(pos); + pos = WPS_TLV_GET_VAL(pos); + + switch (tlv_type) { + case WPS_ELEM_NETWORK_INDEX: + break; + case WPS_ELEM_SSID: + if ((tlv_len != data->ssid_len) || + os_memcmp(data->ssid, pos, tlv_len)) { + wpa_printf(MSG_WARNING, "EAP-WPS: Credential SSID mis-match %s", + wpa_ssid_txt((u8 *)pos, tlv_len)); + return -1; + } else { + wpa_printf(MSG_WARNING, "EAP-WPS: Credential SSID OK %s", + wpa_ssid_txt((u8 *)pos, tlv_len)); + } + break; + case WPS_ELEM_AUTHENTICATION_TYPE: + data->auth_type = WPA_GET_BE16(pos); + wpa_printf(MSG_DEBUG, "EAP-WPS: auth_type=0x%04x", data->auth_type); + break; + case WPS_ELEM_ENCRYPTION_TYPE: + data->encryption_type = WPA_GET_BE16(pos); + wpa_printf(MSG_DEBUG, "EAP-WPS: encryption_type=0x%04x", data->encryption_type); + break; + case WPS_ELEM_NETWORK_KEY: + if (data->network_key) { + os_free(data->network_key); + } + if (NULL == (data->network_key = os_malloc(tlv_len))) { + wpa_printf(MSG_ERROR, "EAP-WPS: Cannot allocate network key"); + return -1; + } + os_memcpy(data->network_key, pos, tlv_len); + data->network_key_len = tlv_len; + break; + case WPS_ELEM_MAC_ADDRESS: + break; + default: + wpa_printf(MSG_DEBUG, "EAP-WPS: unknown type %#x (credential)", + tlv_type); + } + + pos += tlv_len; + } while (pos < end); + + return 0; +} + +/** + * eap_wps_parse_encrypted_settings_sta - Parse the encrypted settings + * + * TODO fail if any required element is missing (?) + */ +static int eap_wps_parse_encrypted_settings_sta(struct eap_wps_data *data, + const u8 *settings, size_t len) +{ + const u8 *pos = settings; + const u8 *end; + u16 tlv_type, tlv_len; + + end = settings + len; + + do { + tlv_type = WPS_TLV_GET_TYPE(pos); + tlv_len = WPS_TLV_GET_LEN(pos); + pos = WPS_TLV_GET_VAL(pos); + + switch (tlv_type) { + case WPS_ELEM_CREDENTIAL: + eap_wps_parse_credential(data, pos, tlv_len); + break; + case WPS_ELEM_KEY_WRAP_AUTHENTICATOR: + if (eap_wps_authenticator_check(data->authKey, + settings, len - WPS_TLV_LEN - WPS_AUTHENTICATOR_LEN, + NULL, 0, pos)) + { + wpa_printf(MSG_ERROR, + "EAP-WPS: Key wrap authenticator check fail " + "Encrypted Settings STA"); + return -1; + } + + /* Setting pos exits while loop to avoid PKCS#5 v2.0 padding */ + pos = end; + break; + default: + wpa_printf(MSG_DEBUG, "EAP-WPS: unknown type (%#x) STA", tlv_type); + } + + pos += tlv_len; + } while (pos < end); + + return 0; +} + +/** + * eap_wps_parse_M8 - Parse the payload for a M8 message + * @data: Pointer to WPS data + * @payload: Message buffer to parse + * @len: Length of message buffer + * Returns: 0 if payload is a valid M8 message, -1 if not a valid M8 + * message, or -2 if the Authenticator check fails + */ +static int eap_wps_parse_M8(struct eap_wps_data *data, const u8 *payload, + size_t len) +{ + const u8 *pos = payload; + const u8 *end = pos + len; + u16 tlv_type, tlv_len; + u8 *settings = NULL; + size_t settings_len; + int ret = -1; + + if (WPS_OPCODE_WSC_MSG != *pos) { + wpa_printf(MSG_WARNING, "EAP-WPS: Message is not WSC_MSG (%#02x)", + *pos); + wpa_hexdump(MSG_WARNING, "message:", pos, len); + return WPS_PARSE_ERR; + } + + pos++; /* Opcode */ + pos++; /* Flags */ + + do { + tlv_type = WPS_TLV_GET_TYPE(pos); + tlv_len = WPS_TLV_GET_LEN(pos); + pos = WPS_TLV_GET_VAL(pos); + + switch (tlv_type) { + case WPS_ELEM_MESSAGE_TYPE: + if (WPS_MESSAGE_TYPE_M8 != pos[0]) { + wpa_printf(MSG_WARNING, "EAP-WPS: Expecting message M8 but got %#x", + pos[0]); + return WPS_PARSE_ERR; + } else { + ret = 0; + } + break; + case WPS_ELEM_ENCRYPTED_SETTINGS: + if (NULL != (settings = os_malloc(tlv_len))) { + /* first 128 bits are IV. remaining bits are the encrypted data */ + eap_wps_decrypt_settings(data, (u8 *)pos, + (u8 *)pos + WPS_IV_LEN, tlv_len - WPS_IV_LEN, + settings, &settings_len); + + if (eap_wps_parse_encrypted_settings_sta(data, settings, + settings_len)) { + wpa_printf(MSG_ERROR, "EAP-WPS: Incorrect encrypted settings M8"); + ret = WPS_PARSE_ERR; + goto done_eap_wps_parse_M8; + } + } + break; + case WPS_ELEM_AUTHENTICATOR: + if (eap_wps_authenticator_check(data->authKey, + data->prv_msg + 2, data->prv_msg_len - 2, + payload + 2, len - 2, pos)) + { + wpa_printf(MSG_ERROR, "EAP-WPS: M8 authenticator check fail"); + return WPS_AUTHENTICATOR_ERR; + } + break; + } + + pos += tlv_len; + } while (pos < end); + +done_eap_wps_parse_M8: + if (settings) { + os_free(settings); + } + + return ret; +} + +/** + * eap_wps_msg_Done - Create the payload for a WSC_Done message + */ +static u8 *eap_wps_msg_Done(struct eap_wps_data *data, size_t *len) +{ + u8 *payload = NULL, *p; + + *len = 0; + + if (NULL != (p = payload = os_malloc(WPS_MSG_BUF_LEN))) { + *p++ = WPS_OPCODE_WSC_Done; + *p++ = 0; /* Flags */ + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_VERSION, WPS_VERSION_1_0); + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_MESSAGE_TYPE, WPS_MESSAGE_TYPE_WSC_Done); + + p = eap_wps_write_tlv(p, WPS_ELEM_ENROLLEE_NONCE, WPS_NONCE_LEN, + data->N1); + + p = eap_wps_write_tlv(p, WPS_ELEM_REGISTRAR_NONCE, WPS_NONCE_LEN, + data->N2); + + *len = (size_t)p - (size_t)payload; + } + + return payload; +} + + +static u8 *eap_wps_ack(struct eap_wps_data *data, size_t *len) +{ + u8 *payload = NULL, *p; + + *len = 0; + + if (NULL != (p = payload = os_malloc(WPS_MSG_BUF_LEN))) { + *p++ = WPS_OPCODE_WSC_ACK; + *p++ = 0; /* Flags */ + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_VERSION, WPS_VERSION_1_0); + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_MESSAGE_TYPE, + WPS_MESSAGE_TYPE_WSC_ACK); + + p = eap_wps_write_tlv(p, WPS_ELEM_ENROLLEE_NONCE, WPS_NONCE_LEN, + data->N1); + + p = eap_wps_write_tlv(p, WPS_ELEM_REGISTRAR_NONCE, WPS_NONCE_LEN, + data->N2); + + *len = (size_t)p - (size_t)payload; + } + + return payload; +} + +static u8 *eap_wps_nack(struct eap_wps_data *data, size_t *len, u16 error) +{ + u8 *payload = NULL, *p; + + *len = 0; + + if (NULL != (p = payload = os_malloc(WPS_MSG_BUF_LEN))) { + *p++ = WPS_OPCODE_WSC_NACK; + *p++ = 0; /* Flags */ + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_VERSION, WPS_VERSION_1_0); + + p = eap_wps_write_tlv_u8(p, WPS_ELEM_MESSAGE_TYPE, + WPS_MESSAGE_TYPE_WSC_NACK); + + p = eap_wps_write_tlv(p, WPS_ELEM_ENROLLEE_NONCE, WPS_NONCE_LEN, + data->N1); + + p = eap_wps_write_tlv(p, WPS_ELEM_REGISTRAR_NONCE, WPS_NONCE_LEN, + data->N2); + + p = eap_wps_write_tlv_u16(p, WPS_ELEM_CONFIGURATION_ERROR, error); + + *len = (size_t)p - (size_t)payload; + } + + return payload; +} + + +static void * eap_wps_init(struct eap_sm *sm) +{ + struct eap_wps_data *data; + + data = os_zalloc(sizeof(*data)); + if (data == NULL) + return NULL; + + data->state = WPS_START; + + return data; +} + + +static void eap_wps_deinit(struct eap_sm *sm, void *priv) +{ + struct eap_wps_data *data = priv; + + if (data == NULL) + return; + os_free(data->prv_msg); + os_free(data->ssid); + os_free(data->network_key); + os_free(data); +} + + +static u8 * eap_wps_process(struct eap_sm *sm, void *priv, + struct eap_method_ret *ret, + const u8 *reqData, size_t reqDataLen, + size_t *respDataLen) +{ + struct eap_wps_data *data = priv; + struct wpa_ssid *ssid = NULL; + const u8 *pos; + size_t len; + u8 *rpos, *msg = NULL; + size_t msg_len; + const struct eap_hdr *req; + struct eap_hdr *resp = NULL; + u8 *auth = NULL; + int err = 0; + + pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_TYPE_SIMPLE_CONFIG, + reqData, reqDataLen, &len); + + if (!sm->rxFailure && ((NULL == pos) || (0 == len))) { + wpa_printf(MSG_WARNING, "EAP-WPS: Invalid frame (pos=%p len=%lu)", + pos, (unsigned long) len); + ret->ignore = TRUE; + return NULL; + } + + if (NULL == (ssid = eap_get_config(sm))) { + wpa_printf(MSG_WARNING, "EAP-WPS: Cannot get configuration"); + ret->ignore = TRUE; + return NULL; + } + + req = (const struct eap_hdr *) reqData; + + if (WPS_OPCODE_WSC_NACK == *pos) { + ret->ignore = FALSE; + ret->decision = DECISION_FAIL; + ret->methodState = METHOD_DONE; + + if (NULL == (msg = eap_wps_nack(data, &msg_len, + WPS_CONFIGURATION_ERROR_NO_ERROR))) { + wpa_printf(MSG_WARNING, "EAP-WPS: Cannot create WSC_NACK"); + ret->ignore = TRUE; + } + + data->state = WPS_START; + } else switch (data->state) { + case WPS_START: + /* Clear all state including keys and nonces */ + ssid->assoc_state = WPS_ASSOCIATION_STATE_CONNECTION_FAILURE; + os_free(data->prv_msg); + os_free(data->ssid); + os_free(data->network_key); + os_memset(data, 0, sizeof(struct eap_wps_data)); + + if (WPS_OPCODE_WSC_Start != *pos) { + wpa_printf(MSG_WARNING, "EAP-WPS: Message is not WSC_Start (%#02x)", + *pos); + ret->ignore = TRUE; + break; + } + + wpa_printf(MSG_DEBUG, "EAP-WPS: Received WSC_Start"); + + if (NULL != (data->ssid = os_malloc(ssid->ssid_len))) { + os_memcpy(data->ssid, ssid->ssid, ssid->ssid_len); + data->ssid_len = ssid->ssid_len; + } + + ret->ignore = FALSE; + ret->methodState = METHOD_MAY_CONT; + + if (os_get_random(data->N1, WPS_NONCE_LEN)) { + wpa_printf(MSG_ERROR, "EAP-WPS: Failed to get random data for N1"); + break; + } + wpa_hexdump(MSG_DEBUG, "EAP-WPS: N1 (Enrollee nonce)", + data->N1, WPS_NONCE_LEN); + + if (NULL == (msg = eap_wps_msg_M1(data, ssid, &msg_len))) { + wpa_printf(MSG_WARNING, "EAP-WPS: Cannot create message M1"); + ret->ignore = TRUE; + break; + } + + data->state = WPS_M2; + break; + case WPS_M2: + /* Validate that this is a M2 message */ + err = eap_wps_parse_M2(sm, data, pos, len, &auth); + if (WPS_PARSE_ERR == err) { + wpa_printf(MSG_WARNING, "EAP-WPS: Message is not M2"); + if (0 /* EAP-Failure */) { + ret->ignore = FALSE; + ret->decision = DECISION_FAIL; + ret->methodState = METHOD_DONE; + } else { + ret->ignore = TRUE; + } + + break; + } else if (WPS_M2D_ERR == err) { + if (NULL == (msg = eap_wps_ack(data, &msg_len))) { + wpa_printf(MSG_WARNING, "EAP-WPS: Cannot create WSC_ACK"); + } + ret->ignore = FALSE; + ret->decision = DECISION_FAIL; + ret->methodState = METHOD_DONE; + break; + } + + wpa_printf(MSG_DEBUG, "EAP-WPS: Received M2"); + + ret->ignore = FALSE; + ret->methodState = METHOD_MAY_CONT; + + /* build message M3 */ + if (NULL == (msg = eap_wps_msg_M3(data, pos, len, ssid->own_addr, + ssid->wps_pin, &msg_len))) { + wpa_printf(MSG_WARNING, "EAP-WPS: Cannot create message M3"); + ret->ignore = TRUE; + break; + } + + /* + * Normally you would want to verify the authenticator in the + * parse routine above, but the AuthKey can't be calculated + * until after parsing the incoming message for N2 + */ + if (eap_wps_authenticator_check(data->authKey, + data->prv_msg + 2, data->prv_msg_len - 2, + pos + 2, len - 2, auth)) + { + wpa_printf(MSG_ERROR, "EAP-WPS: M2 authenticator check fail"); + break; + } + + data->state = WPS_M4; + break; + case WPS_M4: + err = eap_wps_parse_M4(data, pos, len); + if (WPS_PARSE_ERR == err) { + wpa_printf(MSG_WARNING, "EAP-WPS: Message is not M4"); + ret->ignore = FALSE; + ret->decision = DECISION_FAIL; + ret->methodState = METHOD_DONE; + + if (NULL == (msg = eap_wps_nack(data, &msg_len, + WPS_CONFIGURATION_ERROR_NO_ERROR))) { + wpa_printf(MSG_WARNING, "EAP-WPS: Cannot create WSC_NACK"); + ret->ignore = TRUE; + } + + data->state = WPS_START; + break; + } else if (WPS_AUTHENTICATOR_ERR == err) { + wpa_printf(MSG_WARNING, "EAP-WPS: M4 authenticator invalid"); + ret->ignore = TRUE; + ret->methodState = METHOD_MAY_CONT; + break; + } + + wpa_printf(MSG_DEBUG, "EAP-WPS: Received M4"); + + ret->ignore = FALSE; + ret->methodState = METHOD_MAY_CONT; + + /* build message M5 */ + if (NULL == (msg = eap_wps_msg_M5(data, pos, len, &msg_len))) { + wpa_printf(MSG_WARNING, "EAP-WPS: Cannot create message M5"); + ret->ignore = TRUE; + break; + } + + data->state = WPS_M6; + break; + case WPS_M6: + err = eap_wps_parse_M6(data, pos, len); + if (WPS_PARSE_ERR == err) { + wpa_printf(MSG_WARNING, "EAP-WPS: Message is not M6"); + ret->ignore = FALSE; + ret->decision = DECISION_FAIL; + ret->methodState = METHOD_DONE; + + if (NULL == (msg = eap_wps_nack(data, &msg_len, + WPS_CONFIGURATION_ERROR_NO_ERROR))) { + wpa_printf(MSG_WARNING, "EAP-WPS: Cannot create WSC_NACK"); + ret->ignore = TRUE; + } + + data->state = WPS_START; + break; + } else if (WPS_AUTHENTICATOR_ERR == err) { + wpa_printf(MSG_WARNING, "EAP-WPS: M6 authenticator invalid"); + ret->ignore = TRUE; + ret->methodState = METHOD_MAY_CONT; + break; + } + + wpa_printf(MSG_DEBUG, "EAP-WPS: Received M6"); + + ret->ignore = FALSE; + ret->methodState = METHOD_MAY_CONT; + + /* build message M7 */ + if (NULL == (msg = eap_wps_msg_M7(data, pos, len, &msg_len))) { + wpa_printf(MSG_WARNING, "EAP-WPS: Cannot create message M7"); + ret->ignore = TRUE; + break; + } + + data->state = WPS_M8; + break; + case WPS_M8: + err = eap_wps_parse_M8(data, pos, len); + if (WPS_PARSE_ERR == err) { + wpa_printf(MSG_WARNING, "EAP-WPS: Message is not M8"); + ret->ignore = FALSE; + ret->decision = DECISION_FAIL; + ret->methodState = METHOD_DONE; + + /* TODO can we do better than NO_ERROR */ + if (NULL == (msg = eap_wps_nack(data, &msg_len, + WPS_CONFIGURATION_ERROR_NO_ERROR))) { + wpa_printf(MSG_WARNING, "EAP-WPS: Cannot create WSC_NACK"); + ret->ignore = TRUE; + } + + data->state = WPS_START; + break; + } else if (WPS_AUTHENTICATOR_ERR == err) { + wpa_printf(MSG_WARNING, "EAP-WPS: M8 authenticator invalid"); + ret->ignore = TRUE; + ret->methodState = METHOD_MAY_CONT; + break; + } + + wpa_printf(MSG_DEBUG, "EAP-WPS: Received M8"); + + ret->ignore = FALSE; + ret->decision = DECISION_FAIL; + ret->methodState = METHOD_DONE; + + /* build message WSC_Done */ + if (NULL == (msg = eap_wps_msg_Done(data, &msg_len))) { + wpa_printf(MSG_WARNING, "EAP-WPS: Cannot create message WSC_Done"); + ret->ignore = TRUE; + break; + } + + if (data->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"); + } + + ssid->key_mgmt = 0; + ssid->proto = 0; + ssid->pairwise_cipher = 0; + ssid->group_cipher = 0; + + if (data->auth_type & WPS_AUTHENTICATION_TYPE_OPEN) { + ssid->key_mgmt = WPA_KEY_MGMT_NONE; + } else { + if (data->auth_type & + (WPS_AUTHENTICATION_TYPE_WPAPSK | + WPS_AUTHENTICATION_TYPE_WPA)) { + ssid->proto |= WPA_PROTO_WPA; + wpa_printf(MSG_DEBUG, "EAP-WPS: protocol WPA"); + if (data->auth_type & WPS_AUTHENTICATION_TYPE_WPAPSK) { + ssid->key_mgmt |= WPA_KEY_MGMT_PSK; + wpa_printf(MSG_DEBUG, "EAP-WPS: key management PSK"); + } + } + + if (data->auth_type & + (WPS_AUTHENTICATION_TYPE_WPA2PSK | + WPS_AUTHENTICATION_TYPE_WPA2)) { + ssid->proto |= WPA_PROTO_RSN; + wpa_printf(MSG_DEBUG, "EAP-WPS: protocol RSN"); + if (data->auth_type & WPS_AUTHENTICATION_TYPE_WPA2PSK) { + ssid->key_mgmt |= WPA_KEY_MGMT_PSK; + wpa_printf(MSG_DEBUG, "EAP-WPS: key management PSK"); + } + } + } + + if (data->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 (data->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 (data->encryption_type & WPS_ENCRYPTION_TYPE_TKIP || + data->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"); + } + + if (data->network_key) { + wpa_hexdump_key(MSG_DEBUG, "EAP-WPS: Network key", + data->network_key, data->network_key_len); + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { + if (data->network_key_len < WPS_WPAPSK_PASSPHRASE_LEN) { + size_t len = data->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, data->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 *)data->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->assoc_state = WPS_ASSOCIATION_STATE_CONNECTION_SUCCESS; + + data->state = WPS_START; + break; + default: + wpa_printf(MSG_WARNING, "EAP-WPS: Unhandled state %d", data->state); + ret->ignore = TRUE; + } + + if (msg) { + resp = eap_msg_alloc(EAP_VENDOR_WFA, EAP_TYPE_SIMPLE_CONFIG, + respDataLen, msg_len, EAP_CODE_RESPONSE, + req->identifier, &rpos); + + if (resp) { + os_memcpy(rpos, msg, msg_len); + } + /* + * Save a copy of our current message to use in the validation + * of the next received message. + */ + if (NULL != (data->prv_msg = os_realloc(data->prv_msg, msg_len))) { + os_memcpy(data->prv_msg, msg, msg_len); + data->prv_msg_len = msg_len; + } + os_free(msg); + } + + return (u8 *) resp; +} + + +int eap_peer_wps_register(void) +{ + struct eap_method *eap; + int ret; + + eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, + EAP_VENDOR_WFA, EAP_TYPE_SIMPLE_CONFIG, "WPS"); + if (eap == NULL) + return -1; + + eap->init = eap_wps_init; + eap->deinit = eap_wps_deinit; + eap->process = eap_wps_process; + + ret = eap_peer_method_register(eap); + if (ret) + eap_peer_method_free(eap); + + return ret; +} + + +/* + * private key is random # a + * public key is g^a mod p + * where g = base (generator) + * where p = prime number (modp) + */ +static int wps_dh_key(struct eap_wps_data *data) +{ + int ret = 0; + size_t pke_len = WPS_PK_LEN; + + if (os_get_random(data->SKE, sizeof(data->SKE))) { + wpa_printf(MSG_ERROR, "EAP-WPS: Failed to get random data for SKE"); + return -1; + } + + /* + * Calculate the public key A = g^a mod p + */ + ret = crypto_mod_exp(&wps_dh_generator, 1, /* g */ + data->SKE, sizeof(data->SKE), /* a */ + wps_dh_modp, wps_dh_modp_size, /* p */ + data->PKE, &pke_len); + + return ret; +} + +static int eap_wps_kdk(struct eap_wps_data *data, u8 *enrolleeMac, u8 *kdk) +{ + u8 dh_key[WPS_PK_LEN]; + size_t dh_key_len = WPS_PK_LEN; + const u8 *addr[3]; + size_t len[3]; + int ret = 0; + + /* KDK = HMAC-SHA-256 dh_key (N1 || EnrolleeMAC || N2) */ + + ret = crypto_mod_exp(data->PKR, WPS_PK_LEN, /* (g^b mod p) */ + data->SKE, sizeof(data->SKE), /* a */ + wps_dh_modp, wps_dh_modp_size, /* p */ + dh_key, &dh_key_len); + wpa_hexdump_key(MSG_DEBUG, "EAP-WPS: dh_key", dh_key, dh_key_len); + + addr[0] = data->N1; + len[0] = WPS_NONCE_LEN; + addr[1] = enrolleeMac; + len[1] = ETH_ALEN; + addr[2] = data->N2; + len[2] = WPS_NONCE_LEN; + + hmac_sha256_vector(dh_key, dh_key_len, 3, addr, len, kdk); + + return ret; +} + +#define WPS_TOTAL_KEY_BITS 640 +static int eap_wps_kdf(struct eap_wps_data *data, const u8 *kdk) +{ + const char personalization[] = "Wi-Fi Easy and Secure Key Derivation"; + /* #define for the PRF digest size (ie HMAC-SHA-256) is in bytes */ + const u32 iterations = + (WPS_TOTAL_KEY_BITS + (SHA256_MAC_LEN * 8) - 1)/(SHA256_MAC_LEN * 8); + size_t i; + u8 *keys = NULL, *k; + const u8 *addr[3]; + size_t len[3]; + u32 iterations_be; + u32 total_key_bits_be; + + if (NULL == (keys = os_zalloc(iterations * SHA256_MAC_LEN))) { + wpa_printf(MSG_ERROR, "EAP-WPS: Couldn't allocate KDF buffer"); + return -1; + } + + addr[0] = (u8 *)&iterations_be; + len[0] = sizeof(u32); + addr[1] = (u8 *)personalization; + len[1] = os_strlen(personalization); + addr[2] = (u8 *)&total_key_bits_be; + len[2] = sizeof(u32); + + k = keys; + total_key_bits_be = host_to_be32(WPS_TOTAL_KEY_BITS); + for (i=1; i<=iterations; i++) { + iterations_be = host_to_be32(i); + hmac_sha256_vector(kdk, SHA256_MAC_LEN, 3, addr, len, k); + k += SHA256_MAC_LEN; + } + + if (keys) { + k = keys; + + os_memcpy(data->authKey, k, WPS_AUTHKEY_LEN); + k += WPS_AUTHKEY_LEN; + + os_memcpy(data->keyWrapKey, k, WPS_KEYWRAPKEY_LEN); + k += WPS_KEYWRAPKEY_LEN; + + os_memcpy(data->emsk, k, WPS_EMSK_LEN); + + os_free(keys); + } + + return 0; +} + +static int eap_wps_hash(u8 *authKey, u8 *PSK, u8 *PKE, u8 *PKR, + u8 *ES, + char *dev_passwd, size_t dev_passwd_len, + u8 *hash) +{ + const u8 *addr[4]; + size_t len[4]; + + if (os_get_random(ES, WPS_S_NONCE_LEN)) { + wpa_printf(MSG_ERROR, "EAP-WPS: Failed to get random data for E-Sn"); + return -1; + } + + hmac_sha256(authKey, WPS_AUTHKEY_LEN, (u8 *)dev_passwd, + dev_passwd_len, PSK); + + addr[0] = ES; + len[0] = WPS_S_NONCE_LEN; + addr[1] = PSK; + len[1] = SHA256_MAC_LEN/2; /* only use the first 128-bits */ + addr[2] = PKE; + len[2] = WPS_PK_LEN; + addr[3] = PKR; + len[3] = WPS_PK_LEN; + + hmac_sha256_vector(authKey, WPS_AUTHKEY_LEN, 4, addr, len, hash); + + return 0; +} + +static int eap_wps_authenticator(u8 *authKey, + const u8 *d1, size_t d1_len, + u8 *d2, size_t d2_len, + u8 *auth) +{ + const u8 *addr[2]; + size_t len[2]; + u8 hmac[SHA256_MAC_LEN]; + size_t n_vector = 2; + + addr[0] = d1; + len[0] = d1_len; + addr[1] = d2; + len[1] = d2_len; + + if (NULL == d2) { + n_vector = 1; + } + hmac_sha256_vector(authKey, WPS_AUTHKEY_LEN, n_vector, addr, len, hmac); + + os_memcpy(auth, hmac, WPS_AUTHENTICATOR_LEN); + + return 0; +} + +/** + * eap_wps_authenticator_check - validate authenticator value + * @authKey: Pointer to AuthKey + * @prv: Pointer to the previous frame (Opcode and Flags not included) + * @prv_len: Length of previous frame + * @cur: Pointer to the current frame (Opcode and Flags not included) + * @cur_len: Length of current frame + * @auth: Pointer to the expected authenticator value + * Returns: 0 if authenticator value matches, non-zero otherwise + * + * Calculate the authenticator value for the previous and current + * frames and compare it to the expected value. + */ +static int eap_wps_authenticator_check(u8 *authKey, + const u8 *prv, size_t prv_len, + const u8 *cur, size_t cur_len, + const u8 *auth) +{ + u8 hmac[SHA256_MAC_LEN]; + + /* + * Message Authenticator is a keyed hash (HMAC-SHA_256) of (M(n-1) | Mn*) + * using the AuthKey. + * Note that M* should not include the Opcode or Flags + * Also note that the calculation does not include the authenticator + * TLV from the current frame. + */ + cur_len -= WPS_TLV_LEN + WPS_AUTHENTICATOR_LEN; + eap_wps_authenticator(authKey, prv, prv_len, (u8 *)cur, cur_len, + hmac); + + return os_memcmp(hmac, auth, WPS_AUTHENTICATOR_LEN); +} + + +static int eap_wps_encrypted_settings(u8 *authKey, u8 *keyWrapKey, + u16 type, u8 *data, size_t data_len, + u8 *encrypted) +{ + u8 *e = encrypted; + u8 authenticator[WPS_KWA_LEN]; + size_t i; + size_t len = 0; + + if (os_get_random(e, WPS_IV_LEN)) { + wpa_printf(MSG_ERROR, "EAP-WPS: Failed to get random data for IV"); + return -1; + } + + e = eap_wps_write_tlv(e + WPS_IV_LEN, type, data_len, data); + + /* + * Key Wrap Authenticator + */ + eap_wps_authenticator(authKey, encrypted + WPS_IV_LEN, data_len + WPS_TLV_LEN, + NULL, 0, authenticator); + e = eap_wps_write_tlv(e, WPS_ELEM_KEY_WRAP_AUTHENTICATOR, WPS_KWA_LEN, + authenticator); + + /* Pad out the data re. PKCS #5 V2.0 */ + for (i=0; i<16; i++) { + *e++ = 0x10; + } + + len = (size_t)e - (size_t)encrypted - WPS_IV_LEN; + + /* encrypted starts with the IV */ + aes_128_cbc_encrypt(keyWrapKey, encrypted, encrypted + WPS_IV_LEN, len); + + return 0; +} + + +static int eap_wps_decrypt_settings(struct eap_wps_data *data, u8 *iv, + u8 *encrypted, size_t encrypted_len, + u8 *decrypted, size_t *decrypted_len) +{ + int ret; + u8 pad_len = 0; + + os_memcpy(decrypted, encrypted, encrypted_len); + aes_128_cbc_decrypt(data->keyWrapKey, iv, decrypted, encrypted_len); + + /* + * Last byte value in the decrypted data is length of padding at + * end of buffer. The value should be between 1 and 16. Return + * -1 if pad value is out of range. Otherwise adjust the value + * of decrytped length + */ + pad_len = *(decrypted + encrypted_len - 1); + if (pad_len > 16) { + *decrypted_len = 0; + ret = -1; + } else { + *decrypted_len = encrypted_len - pad_len; + ret = 0; + } + + wpa_hexdump(MSG_DEBUG, "EAP-WPS: decrypted settings", decrypted, *decrypted_len); + + return 0; +} diff -urN wpa_supplicant-0.5.10.orig/events.c wpa_supplicant-0.5.10/events.c --- wpa_supplicant-0.5.10.orig/events.c 2007-11-28 18:49:08.000000000 -0800 +++ wpa_supplicant-0.5.10/events.c 2008-09-03 10:32:59.997315000 -0700 @@ -17,11 +17,13 @@ #include "common.h" #include "eapol_sm.h" #include "wpa.h" +#include "wps.h" #include "eloop.h" #include "wpa_supplicant.h" #include "config.h" #include "l2_packet.h" #include "wpa_supplicant_i.h" +#include "wps_i.h" #include "pcsc_funcs.h" #include "preauth.h" #include "pmksa_cache.h" @@ -350,6 +352,41 @@ } +static struct wpa_ssid * +wpa_supplicant_wps_select_wpa_ssid(struct wpa_supplicant *wpa_s, + struct wpa_ssid *group, struct wpa_scan_result *bss) +{ + struct wpa_ssid *ssid, *selected_ssid = NULL; + + for (ssid = group; ssid; ssid = ssid->pnext) { + if (ssid->disabled) { + wpa_printf(MSG_DEBUG, " skip - disabled"); + continue; + } + + if ((ssid->proto & WPA_PROTO_WPS) && bss->wps_ie_len > 0) { + selected_ssid = ssid; + os_memcpy(ssid->own_addr, wpa_s->own_addr, ETH_ALEN); + if (ssid->ssid) { + os_free(ssid->ssid); + } + if (NULL == (ssid->ssid = os_malloc(bss->ssid_len))) { + wpa_printf(MSG_ERROR, "EAP-WPS: Cannot allocate SSID"); + break; + } + os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len); + ssid->ssid_len = bss->ssid_len; + wpa_printf(MSG_DEBUG, " selected WPS AP " + MACSTR " ssid='%s'", + MAC2STR(bss->bssid), + wpa_ssid_txt(bss->ssid, + bss->ssid_len)); + } + } + + return selected_ssid; +} + static struct wpa_scan_result * wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group, struct wpa_scan_result *results, int num, @@ -358,6 +395,11 @@ struct wpa_ssid *ssid; struct wpa_scan_result *bss, *selected = NULL; int i; +#ifdef EAP_WPS + struct wps_ie_data wps_data; + struct wpa_scan_result **wps_results = NULL; + size_t wps_results_len = 0; +#endif struct wpa_blacklist *e; wpa_printf(MSG_DEBUG, "Selecting BSS from priority group %d", @@ -365,7 +407,151 @@ bss = NULL; ssid = NULL; - /* First, try to find WPA-enabled AP */ +#ifdef EAP_WPS + if (WPS_CONFIG_METHOD_NONE != wpa_s->wps_config_method) { + int pbc_count = 0; /* Number of devices using PBC */ + u8 selected_uuid[WPS_UUID_LEN]; + + /* First, try to find WPS-enabled AP */ + wpa_printf(MSG_DEBUG, "Try to find WPS-selected AP"); + for (i = 0; i < num; i++) { + bss = &results[i]; + wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' " + "wps_ie_len=%lu caps=0x%x", + i, MAC2STR(bss->bssid), + wpa_ssid_txt(bss->ssid, bss->ssid_len), + (unsigned long) bss->wps_ie_len, + bss->caps); + + if (0 == bss->wps_ie_len) { + wpa_printf(MSG_DEBUG, " skip - no WPS IE"); + continue; + } + + wps_results_len++; + wps_results = os_realloc(wps_results, + wps_results_len * sizeof(struct wpa_scan_result *)); + wps_results[wps_results_len - 1] = bss; + + os_memset(&wps_data, 0, sizeof(struct wps_ie_data)); + + if (wpa_parse_wps_ie(bss->wps_ie, bss->wps_ie_len, &wps_data)) { + wpa_printf(MSG_DEBUG, " skip - bad WPS IE"); + continue; + } + + /* + * 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 (See below for a + * work around) + */ + if (FALSE == wps_data.selected_registrar) { + wpa_printf(MSG_DEBUG, " skip - registrar not selected"); + continue; + } + + switch (wpa_s->wps_config_method) { + case WPS_CONFIG_METHOD_PBC: + if (wps_data.device_password_id == WPS_DEVICE_PASSWORD_ID_PBC) { + pbc_count++; + if (1 == pbc_count) { + wpa_printf(MSG_DEBUG, " pending PBC"); + os_memcpy(selected_uuid, wps_data.uuid, WPS_UUID_LEN); + } else if (0 == os_memcmp(selected_uuid, wps_data.uuid, WPS_UUID_LEN)) { + pbc_count--; + wpa_printf(MSG_DEBUG, " skip - matching UUID_E PBC"); + continue; + } else { + wpa_printf(MSG_DEBUG, " skip - overlapping PBC"); + continue; + } + } else { + wpa_printf(MSG_DEBUG, " skip - PBC not activated"); + continue; + } + break; + case WPS_CONFIG_METHOD_DISPLAY: + case WPS_CONFIG_METHOD_LABEL: + if (wps_data.device_password_id != WPS_DEVICE_PASSWORD_ID_PIN) { + wpa_printf(MSG_DEBUG, " skip - PIN not activated"); + continue; + } + break; + default: + wpa_printf(MSG_DEBUG, " skip - WPS not configured"); + continue; + } + + e = wpa_blacklist_get(wpa_s, bss->bssid); + if (e && e->count > 1) { + wpa_printf(MSG_DEBUG, " skip - blacklisted"); + continue; + } + + *selected_ssid = wpa_supplicant_wps_select_wpa_ssid(wpa_s, + group, bss); + if (NULL != *selected_ssid) { + selected = bss; + + if (WPS_CONFIG_METHOD_PBC != wpa_s->wps_config_method) { + break; + } + } + } + + /* + * If no AP was selected but one or more AP advertised a WPS IE, + * run the WPS protocol against each AP in case one has an + * "ill behaved" external registrar + */ + if (!selected) { + pbc_count = 0; + wpa_printf(MSG_DEBUG, "Try to find WPS-capable AP"); + for (i = 0; i < wps_results_len; i++) { + bss = wps_results[i]; + wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' ", + i, MAC2STR(bss->bssid), + wpa_ssid_txt(bss->ssid, bss->ssid_len)); + + e = wpa_blacklist_get(wpa_s, bss->bssid); + if (e && e->count > 1) { + wpa_printf(MSG_DEBUG, " skip - blacklisted"); + continue; + } + + *selected_ssid = wpa_supplicant_wps_select_wpa_ssid(wpa_s, + group, bss); + if (NULL != *selected_ssid) { + selected = bss; + + if (WPS_CONFIG_METHOD_PBC != wpa_s->wps_config_method) { + break; + } + } + } + } + + if ((WPS_CONFIG_METHOD_PBC == wpa_s->wps_config_method) && + (pbc_count > 1)) { + selected = NULL; + *selected_ssid = NULL; + ssid = NULL; + bss = NULL; + + wps_cancel_walktime_timeout(wpa_s); + wpa_msg(wpa_s, MSG_ERROR, WPA_EVENT_WPS_OVERLAP); + } + + os_free(wps_results); + } +#endif + + /* Next, try to find WPA-enabled AP */ wpa_printf(MSG_DEBUG, "Try to find WPA-enabled AP"); for (i = 0; i < num && !selected; i++) { bss = &results[i]; diff -urN wpa_supplicant-0.5.10.orig/Makefile wpa_supplicant-0.5.10/Makefile --- wpa_supplicant-0.5.10.orig/Makefile 2008-02-19 16:08:52.000000000 -0800 +++ wpa_supplicant-0.5.10/Makefile 2008-09-03 10:03:58.907315000 -0700 @@ -602,6 +602,26 @@ CONFIG_INTERNAL_MD5=y endif +ifdef CONFIG_EAP_WPS +# EAP-WPS +ifeq ($(CONFIG_EAP_WPS), dyn) +EAPDYN += eap_wps.so +else +OBJS += eap_wps.o +endif +CFLAGS += -DEAP_WPS +NEED_SHA256=y +CONFIG_INTERNAL_SHA256=y +CONFIG_IEEE8021X_EAPOL=y +CONFIG_INTERNAL_DES=y + +ifneq ($(TLS_FUNCS), y) +CFLAGS += -DCONFIG_CRYPTO_INTERNAL -DCONFIG_INTERNAL_LIBTOMMATH -DEAP_TLS_FUNCS -DCONFIG_TLS_INTERNAL +OBJS += asn1.o crypto_internal.o rsa.o bignum.o +endif + +endif + ifdef CONFIG_INTERNAL_AES CFLAGS += -DINTERNAL_AES endif @@ -712,7 +732,7 @@ endif ifndef CONFIG_NO_WPA -OBJS += wpa.o preauth.o pmksa_cache.o +OBJS += wpa.o preauth.o pmksa_cache.o wps.o NEED_AES=y else CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2 diff -urN wpa_supplicant-0.5.10.orig/wpa_cli.c wpa_supplicant-0.5.10/wpa_cli.c --- wpa_supplicant-0.5.10.orig/wpa_cli.c 2008-02-17 10:26:11.000000000 -0800 +++ wpa_supplicant-0.5.10/wpa_cli.c 2008-09-03 10:04:48.537315000 -0700 @@ -131,6 +131,9 @@ " ap_scan = set ap_scan parameter\n" " stkstart = request STK negotiation with \n" " terminate = terminate wpa_supplicant\n" +" pbc = start Push Button Configuration\n" +" pin_get = get the PIN for this device\n" +" pin_entered = PIN has been entered into registrar\n" " quit = exit wpa_cli\n"; static struct wpa_ctrl *ctrl_conn; @@ -412,6 +415,27 @@ } +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]; @@ -1021,6 +1045,9 @@ { "interface_remove", wpa_cli_cmd_interface_remove }, { "ap_scan", wpa_cli_cmd_ap_scan }, { "stkstart", wpa_cli_cmd_stkstart }, + { "pbc", wpa_cli_cmd_pbc }, + { "pin_get", wpa_cli_cmd_pin_get }, + { "pin_entered", wpa_cli_cmd_pin_entered }, { NULL, NULL } }; diff -urN wpa_supplicant-0.5.10.orig/wpa_ctrl.h wpa_supplicant-0.5.10/wpa_ctrl.h --- wpa_supplicant-0.5.10.orig/wpa_ctrl.h 2007-03-24 19:09:50.000000000 -0700 +++ wpa_supplicant-0.5.10/wpa_ctrl.h 2008-07-21 15:39:03.121505000 -0700 @@ -47,6 +47,10 @@ /** EAP authentication failed (EAP-Failure received) */ #define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE " +#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 -urN wpa_supplicant-0.5.10.orig/wpa_supplicant.c wpa_supplicant-0.5.10/wpa_supplicant.c --- wpa_supplicant-0.5.10.orig/wpa_supplicant.c 2008-02-17 10:42:02.000000000 -0800 +++ wpa_supplicant-0.5.10/wpa_supplicant.c 2008-09-03 09:48:40.107315000 -0700 @@ -22,11 +22,13 @@ #include "eapol_sm.h" #include "eap.h" #include "wpa.h" +#include "wps.h" #include "eloop.h" #include "wpa_supplicant.h" #include "config.h" #include "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" @@ -359,7 +361,21 @@ { struct wpa_supplicant *wpa_s = ctx; wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete"); - if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X) { + if (wpa_s->wps_config_method) { + if (wpa_s->current_ssid && (wpa_s->current_ssid->assoc_state == + WPS_ASSOCIATION_STATE_CONNECTION_SUCCESS)) { + wps_cancel_walktime_timeout(wpa_s); + wpa_supplicant_cancel_auth_timeout(wpa_s); + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_WPS_SUCCESS); + } else { + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_WPS_ERROR); + } + + wpa_supplicant_deauthenticate(wpa_s, REASON_UNSPECIFIED); + wpa_s->reassociate = 1; + + wpa_supplicant_req_scan(wpa_s, 0, 0); + } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X) { wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE); } else { eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); @@ -606,6 +622,9 @@ eapol_conf.required_keys = 0; } } + if (wpa_s->wps_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; @@ -710,6 +729,8 @@ wpa_supplicant_cancel_auth_timeout(wpa_s); ieee80211_sta_deinit(wpa_s); + + os_free(wpa_s->wps_pin); } @@ -961,6 +982,9 @@ struct wpa_supplicant *wpa_s = eloop_ctx; struct wpa_ssid *ssid; int enabled, scan_req = 0, ret; + u8 wps_ie[SSID_MAX_WPS_IE_LEN]; + size_t wps_ie_len; + const char *uuid_str = NULL; if (wpa_s->disconnected && !wpa_s->scan_req) return; @@ -970,6 +994,7 @@ while (ssid) { if (!ssid->disabled) { enabled++; + uuid_str = ssid->uuid_e; break; } ssid = ssid->next; @@ -1056,10 +1081,21 @@ return; } + if (WPS_CONFIG_METHOD_NONE != wpa_s->wps_config_method) { + if (wpa_create_wps_ie(uuid_str, wpa_s->wps_config_method, wps_ie, + &wps_ie_len)) { + wpa_printf(MSG_WARNING, "WPA: Failed to create WPS IE"); + return; + } + } else { + wps_ie_len = 0; + } + if (wpa_s->use_client_mlme) { ret = ieee80211_sta_req_scan(wpa_s, ssid ? ssid->ssid : NULL, ssid ? ssid->ssid_len : 0); } else { + wpa_drv_set_probe_req_ie(wpa_s, wps_ie, wps_ie_len); ret = wpa_drv_scan(wpa_s, ssid ? ssid->ssid : NULL, ssid ? ssid->ssid_len : 0); } @@ -1339,6 +1375,8 @@ int wep_keys_set = 0; struct wpa_driver_capa capa; int assoc_failed = 0; + u8 wps_ie[SSID_MAX_WPS_IE_LEN]; + size_t wps_ie_len; wpa_s->reassociate = 0; if (bss) { @@ -1382,7 +1420,19 @@ } wpa_drv_set_auth_alg(wpa_s, algs); - if (bss && (bss->wpa_ie_len || bss->rsn_ie_len) && + if ((ssid->proto & WPA_PROTO_WPS) && bss && bss->wps_ie_len) { + 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); + + if (wpa_s->wps_pin) { + ssid->wps_pin = os_strdup(wpa_s->wps_pin); + } + } else if (bss && (bss->wpa_ie_len || bss->rsn_ie_len) && (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK))) { int try_opportunistic; try_opportunistic = ssid->proactive_key_caching && @@ -1497,6 +1547,18 @@ } #endif /* CONFIG_IEEE80211W */ + if (WPS_CONFIG_METHOD_NONE != wpa_s->wps_config_method) { + if (wpa_create_wps_ie(ssid->uuid_e, wpa_s->wps_config_method, + wps_ie, &wps_ie_len)) { + wpa_printf(MSG_WARNING, "WPA: Failed to create WPS IE"); + return; + } + } else { + wps_ie_len = 0; + } + 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 -urN wpa_supplicant-0.5.10.orig/wpa_supplicant.conf wpa_supplicant-0.5.10/wpa_supplicant.conf --- wpa_supplicant-0.5.10.orig/wpa_supplicant.conf 2007-12-27 15:59:35.000000000 -0800 +++ wpa_supplicant-0.5.10/wpa_supplicant.conf 2008-08-01 14:19:10.235926000 -0700 @@ -740,6 +740,11 @@ 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 -urN wpa_supplicant-0.5.10.orig/wpa_supplicant_i.h wpa_supplicant-0.5.10/wpa_supplicant_i.h --- wpa_supplicant-0.5.10.orig/wpa_supplicant_i.h 2007-12-27 16:50:15.000000000 -0800 +++ wpa_supplicant-0.5.10/wpa_supplicant_i.h 2008-09-03 09:46:41.827315000 -0700 @@ -342,6 +342,9 @@ struct wpa_client_mlme mlme; int use_client_mlme; + + int wps_config_method; + char *wps_pin; }; @@ -693,4 +696,14 @@ return -1; } +static inline int wpa_drv_set_probe_req_ie(struct wpa_supplicant *wpa_s, + u8 *ie, size_t ie_len) +{ + if (wpa_s->driver->set_probe_req_ie) { + return wpa_s->driver->set_probe_req_ie(wpa_s->drv_priv, ie, + ie_len); + } + return -1; +} + #endif /* WPA_SUPPLICANT_I_H */ diff -urN wpa_supplicant-0.5.10.orig/wps.c wpa_supplicant-0.5.10/wps.c --- wpa_supplicant-0.5.10.orig/wps.c 1969-12-31 16:00:00.000000000 -0800 +++ wpa_supplicant-0.5.10/wps.c 2008-08-29 17:15:31.940899000 -0700 @@ -0,0 +1,291 @@ +/* + * WiFi Protected Setup - WPS specific processing + * Copyright (c) 2008, Chuck Tuffli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "wpa.h" +#include "eloop.h" +#include "config.h" +#include "wpa_supplicant_i.h" +#include "wps.h" + +static const int WPS_SELECTOR_LEN = 4; +static const u8 WPS_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 0x4 }; +static const u16 WPS_VERSION = 0x10; + +/* WPS IE version 1.0 + * + * Required fields for all IE + * 00-50-f2:04 (OUI:OUI type) + * 0x10 (version) + * 0x01 0x02 (wiFi Protected Setup State; unconfigured, configured) + * (following fields are optional:) + * (AP Setup Locked; BOOL ) + * (Selected Registrar; BOOL) + * (Device Password ID; ) + * (Selected Registrar Config Methods; ) + * (following fields are optional in some management packets) + * (Response Type; required=Probe Resp) + * (UUID-R; optional=Beacon, required=Probe Resp) + * (Manufacturer; required=Probe Resp) + * (Model Name; required=Probe Resp) + * (Model Number; required=Probe Resp) + * (Serial Number; required=Probe Resp) + * (Primary Device Type; required=Probe Resp) + * (Device Name; required=Probe Resp) + * (Config Methodes; required=Probe Resp) + * (RF Bands; optional=Beacon and Probe Resp) + */ + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct wps_ie_hdr { + u8 elem_id; + u8 len; + u8 oui[3]; + u8 oui_type; + u16 type_version; + u16 len_version; + u8 version; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + +int wpa_parse_wps_ie(const u8 *wps_ie, size_t wps_ie_len, + struct wps_ie_data *data) +{ + const struct wps_ie_hdr *hdr; + const u8 *pos; + int left; + u16 elem, len; + + data->proto = WPA_PROTO_WPS; + + if (0 == wps_ie_len) { + /* No WPS IE - fail silently */ + return -1; + } + + if (wps_ie_len < sizeof(struct wps_ie_hdr)) { + wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", + __func__, (unsigned long) wps_ie_len); + return -1; + } + + hdr = (const struct wps_ie_hdr *) wps_ie; + + if (hdr->elem_id != GENERIC_INFO_ELEM || + hdr->len != wps_ie_len - 2 || + os_memcmp(hdr->oui, WPS_OUI_TYPE, WPS_SELECTOR_LEN) != 0 || + hdr->version != WPS_VERSION) { + wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", + __func__); + return -1; + } + + pos = (const u8 *) (hdr + 1); + left = wps_ie_len - sizeof(*hdr); + + while (left >= 2) { + elem = WPA_GET_BE16(pos); + len = WPA_GET_BE16(pos+2); + pos += 4; + left -= 4; + + if ((0 == len) || (len > left)) { + wpa_printf(MSG_DEBUG, "%s: bad length %d (left %d)\n", + __func__, len, left); + return -1; + } + switch (elem) { + case WPS_ELEM_DEVICE_PASSWORD_ID: + if (data->selected_registrar) + data->device_password_id = WPA_GET_BE16(pos); + break; + case WPS_ELEM_CONFIG_METHODS: + data->config_method = WPA_GET_BE16(pos); + break; + case WPS_ELEM_SELECTED_REGISTRAR: + data->selected_registrar = *pos; + break; + case WPS_ELEM_UUID_E: + os_memcpy(data->uuid, pos, sizeof(data->uuid)); + break; + } + pos += len; + left -= len; + } + return 0; +} + +static u8 * wps_write_tlv(u8 *buf, u16 type, u16 len, u8 *val) +{ + WPA_PUT_BE16(buf, type); + WPA_PUT_BE16(buf + 2, len); + os_memcpy(buf + 4, val, len); + + return (buf + 4 + len); +} + +static inline u8 * wps_write_tlv_u8(u8 *buf, u16 type, u8 val) +{ + return wps_write_tlv(buf, type, 1, &val); +} + +static inline u8 * wps_write_tlv_u16(u8 *buf, u16 type, u16 val) +{ + u16 be_val = host_to_be16(val); + + return wps_write_tlv(buf, type, 2, (u8 *)&be_val); +} + +int wpa_create_wps_ie(const char *uuid_str, u16 method, u8 *wps_ie, + size_t *wps_ie_len) +{ + u8 *pos = wps_ie; + u8 uuid_e[WPS_UUID_LEN]; + + *wps_ie_len = 0; + + if (hexstr2bin(uuid_str, uuid_e, WPS_UUID_LEN)) { + wpa_printf(MSG_ERROR, "EAP-WPS: bad UUID format %s", uuid_str); + return -1; + } + + *pos++ = GENERIC_INFO_ELEM; + pos++; /* skip length initially */ + os_memcpy(pos, WPS_OUI_TYPE, WPS_SELECTOR_LEN); + pos += WPS_SELECTOR_LEN; + pos = wps_write_tlv_u8(pos, WPS_ELEM_VERSION, WPS_VERSION); + pos = wps_write_tlv_u8(pos, WPS_ELEM_REQUEST_TYPE, + WPS_REQUEST_TYPE_ENROLLEE_OPEN); + pos = wps_write_tlv_u16(pos, WPS_ELEM_CONFIG_METHODS, + WPS_CONFIG_METHOD_LABEL | + WPS_CONFIG_METHOD_DISPLAY | + WPS_CONFIG_METHOD_PBC); + pos = wps_write_tlv(pos, WPS_ELEM_UUID_E, WPS_UUID_LEN, uuid_e); + pos = wps_write_tlv(pos, WPS_ELEM_PRIMARY_DEVICE_TYPE, 8, + (u8 *)"\x00\x01\x00\x50\xf2\x04\x00\x01"); + pos = wps_write_tlv_u8(pos, WPS_ELEM_RF_BANDS, + WPS_RF_BAND_2_4GHZ | WPS_RF_BAND_5_0GHZ); + pos = wps_write_tlv_u16(pos, WPS_ELEM_ASSOCIATION_STATE, + WPS_ASSOCIATION_STATE_NOT_ASSOCIATED); + pos = wps_write_tlv_u16(pos, WPS_ELEM_CONFIGURATION_ERROR, + WPS_CONFIGURATION_ERROR_NO_ERROR); + pos = wps_write_tlv_u16(pos, WPS_ELEM_DEVICE_PASSWORD_ID, + WPS_CONFIG_METHOD_PBC == method ? + WPS_DEVICE_PASSWORD_ID_PBC : WPS_DEVICE_PASSWORD_ID_PIN); + + *wps_ie_len = (size_t)pos - (size_t)wps_ie; + + wps_ie[1] = (u8)(*wps_ie_len) - 2; + + return 0; +} + +static void wps_walktime_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + + wpa_msg(wpa_s, MSG_DEBUG, "WPS PBC method timed out"); + wpa_s->wps_config_method = 0; +} + +int wps_config_pbc(struct wpa_supplicant *wpa_s) +{ + wpa_s->wps_config_method = WPS_CONFIG_METHOD_PBC; + + os_free(wpa_s->wps_pin); + wpa_s->wps_pin = os_strdup(WPS_PIN_PBC); + + eloop_cancel_timeout(wps_walktime_timeout, wpa_s, NULL); + eloop_register_timeout(WPS_WALK_TIME, 0, wps_walktime_timeout, wpa_s, NULL); + + return 0; +} + +int wps_cancel_walktime_timeout(struct wpa_supplicant *wpa_s) +{ + eloop_cancel_timeout(wps_walktime_timeout, wpa_s, NULL); + wpa_s->wps_config_method = 0; + + return 0; +} + +/** + * wps_generate_pin - Generate a Device Password (aka PIN) + * + * Creates an 8 digit pin by generating a 7 digit random number + * and appending a checksum digit to the end of the random number + * (WPS Section 6.4.1) + */ +static u32 wps_generate_pin() +{ + u32 rand; + u32 pin; + u32 accum = 0; + +#define PIN_MIN 1 +#define PIN_MAX 9999999 + + os_get_random((unsigned char *)&rand, sizeof(rand)); + pin = PIN_MIN + (rand / ((u32)(-1) / PIN_MAX + 1)); + + pin *= 10; + accum += 3 * ((pin / 10000000) % 10); + accum += 1 * ((pin / 1000000) % 10); + accum += 3 * ((pin / 100000) % 10); + accum += 1 * ((pin / 10000) % 10); + accum += 3 * ((pin / 1000) % 10); + accum += 1 * ((pin / 100) % 10); + accum += 3 * ((pin / 10) % 10); + + pin += (10 - (accum % 10)) % 10; + + return pin; +} + +int wps_get_pin(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) +{ + u32 pin; + + os_free(wpa_s->wps_pin); + if (NULL == (wpa_s->wps_pin = os_malloc(sizeof(WPS_PIN_PBC)))) { + wpa_msg(wpa_s, MSG_ERROR, "WPS PIN method no memory"); + return -1; + } + + pin = wps_generate_pin(); + os_snprintf(wpa_s->wps_pin, sizeof(WPS_PIN_PBC), "%08d", pin); + + os_snprintf(buf, buflen, "%08d", pin); + buf[buflen - 1] = '\0'; + + return os_strlen(buf); +} + +int wps_config_pin(struct wpa_supplicant *wpa_s) +{ + wpa_s->wps_config_method = WPS_CONFIG_METHOD_DISPLAY; + + eloop_cancel_timeout(wps_walktime_timeout, wpa_s, NULL); + eloop_register_timeout(WPS_WALK_TIME, 0, wps_walktime_timeout, wpa_s, NULL); + + return 0; +} diff -urN wpa_supplicant-0.5.10.orig/wps.h wpa_supplicant-0.5.10/wps.h --- wpa_supplicant-0.5.10.orig/wps.h 1969-12-31 16:00:00.000000000 -0800 +++ wpa_supplicant-0.5.10/wps.h 2008-08-14 11:51:44.287650000 -0700 @@ -0,0 +1,269 @@ +/* + * WiFi Protected Setup - WPS definitions + * Copyright (c) 2008, Chuck Tuffli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPS_H +#define WPS_H + +#include "defs.h" + +#ifndef BIT +#define BIT(n) (1 << (n)) +#endif + +#define WPS_UUID_LEN 16 + +struct wps_ie_data { + int proto; + int device_password_id; + int config_method; + Boolean selected_registrar; + u8 uuid[WPS_UUID_LEN]; +}; + +/** + * WPS Op-Codes + */ +#define WPS_OPCODE_WSC_Start 0x01 +#define WPS_OPCODE_WSC_ACK 0x02 +#define WPS_OPCODE_WSC_NACK 0x03 +#define WPS_OPCODE_WSC_MSG 0x04 +#define WPS_OPCODE_WSC_Done 0x05 +#define WPS_OPCODE_WSC_FRAG_ACK 0x06 + +/** + * WPS EAP Flags + * MF = more fragments + * LF = length field + */ +#define WPS_EAP_FLAG_MF 0x01 +#define WPS_EAP_FLAG_LF 0x02 + +#define WPS_ELEM_AP_CHANNEL 0x1001 +#define WPS_ELEM_ASSOCIATION_STATE 0x1002 +#define WPS_ELEM_AUTHENTICATION_TYPE 0x1003 +#define WPS_ELEM_AUTHENTICATION_TYPE_FLAG 0x1004 +#define WPS_ELEM_AUTHENTICATOR 0x1005 +#define WPS_ELEM_CONFIG_METHODS 0x1008 +#define WPS_ELEM_CONFIGURATION_ERROR 0x1009 +#define WPS_ELEM_CONFIRMATION_URL4 0x100a +#define WPS_ELEM_CONFIRMATION_URL6 0x100b +#define WPS_ELEM_CONNECTION_TYPE 0x100c +#define WPS_ELEM_CONNECTION_TYPE_FLAG 0x100d +#define WPS_ELEM_CREDENTIAL 0x100e +#define WPS_ELEM_DEVICE_NAME 0x1011 +#define WPS_ELEM_DEVICE_PASSWORD_ID 0x1012 +#define WPS_ELEM_E_HASH1 0x1014 +#define WPS_ELEM_E_HASH2 0x1015 +#define WPS_ELEM_E_SNONCE1 0x1016 +#define WPS_ELEM_E_SNONCE2 0x1017 +#define WPS_ELEM_ENCRYPTED_SETTINGS 0x1018 +#define WPS_ELEM_ENCRYPTION_TYPE 0x100f +#define WPS_ELEM_ENCRYPTION_TYPE_FLAG 0x1010 +#define WPS_ELEM_ENROLLEE_NONCE 0x101a +#define WPS_ELEM_FEATURE_ID 0x101b +#define WPS_ELEM_IDENTITY 0x101c +#define WPS_ELEM_IDENTITY_PROOF 0x101d +#define WPS_ELEM_KEY_WRAP_AUTHENTICATOR 0x101e +#define WPS_ELEM_KEY_IDENTIFIER 0x101f +#define WPS_ELEM_MAC_ADDRESS 0x1020 +#define WPS_ELEM_MANUFACTURER 0x1021 +#define WPS_ELEM_MESSAGE_TYPE 0x1022 +#define WPS_ELEM_MODEL_NAME 0x1023 +#define WPS_ELEM_MODEL_NUMBER 0x1024 +#define WPS_ELEM_NETWORK_INDEX 0x1026 +#define WPS_ELEM_NETWORK_KEY 0x1027 +#define WPS_ELEM_NETWORK_KEY_INDEX 0x1028 +#define WPS_ELEM_NEW_DEVICE_NAME 0x1029 +#define WPS_ELEM_NEW_PASSWORD 0x102a +#define WPS_ELEM_OOB_DEVICE_PASSWORD 0x102c +#define WPS_ELEM_OS_VERSION 0x102d +#define WPS_ELEM_POWER_LEVEL 0x102f +#define WPS_ELEM_PSK_CURRENT 0x1030 +#define WPS_ELEM_PSK_MAX 0x1031 +#define WPS_ELEM_PUBLIC_KEY 0x1032 +#define WPS_ELEM_RADIO_ENABLED 0x1033 +#define WPS_ELEM_REBOOT 0x1034 +#define WPS_ELEM_REGISTRAR_CURRENT 0x1035 +#define WPS_ELEM_REGISTRAR_ESTABLISHED 0x1036 +#define WPS_ELEM_REGISTRAR_LIST 0x1037 +#define WPS_ELEM_REGISTRAR_MAX 0x1038 +#define WPS_ELEM_REGISTRAR_NONCE 0x1039 +#define WPS_ELEM_REQUEST_TYPE 0x103a +#define WPS_ELEM_RESPONSE_TYPE 0x103b +#define WPS_ELEM_RF_BANDS 0x103c +#define WPS_ELEM_R_HASH1 0x103d +#define WPS_ELEM_R_HASH2 0x103e +#define WPS_ELEM_R_SNONCE1 0x103f +#define WPS_ELEM_R_SNONCE2 0x1040 +#define WPS_ELEM_SELECTED_REGISTRAR 0x1041 +#define WPS_ELEM_SERIAL_NUMBER 0x1042 +#define WPS_ELEM_WPS_STATE 0x1044 +#define WPS_ELEM_SSID 0x1045 +#define WPS_ELEM_TOTAL_NETWORKS 0x1046 +#define WPS_ELEM_UUID_E 0x1047 +#define WPS_ELEM_UUID_R 0x1048 +#define WPS_ELEM_VENDOR_EXTENSION 0x1049 +#define WPS_ELEM_VERSION 0x104a +#define WPS_ELEM_X509_CERT_REQUEST 0x104b +#define WPS_ELEM_X509_CERTIFICATE 0x104c +#define WPS_ELEM_EAP_IDENTITY 0x104d +#define WPS_ELEM_MESSAGE_COUNTER 0x104e +#define WPS_ELEM_PUBLIC_KEY_HASH 0x104f +#define WPS_ELEM_REKEY_KEY 0x1050 +#define WPS_ELEM_KEY_LIFETIME 0x1051 +#define WPS_ELEM_PERMITTED_CONFIG_METHODS 0x1052 +#define WPS_ELEM_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053 +#define WPS_ELEM_PRIMARY_DEVICE_TYPE 0x1054 +#define WPS_ELEM_SECONDARY_DEVICE_TYPE_LIST 0x1055 +#define WPS_ELEM_PORTABLE_DEVICE 0x1056 +#define WPS_ELEM_AP_SETUP_LOCKED 0x1057 +#define WPS_ELEM_APPLICATION_EXTENSION 0x1058 +#define WPS_ELEM_EAP_TYPE 0x1059 +#define WPS_ELEM_INITIALIZATION_VECTOR 0x1060 +#define WPS_ELEM_KEY_PROVIDED_AUTOMATICALLY 0x1061 +#define WPS_ELEM_8021X_ENABLED 0x1062 +#define WPS_ELEM_APPSESSIONKEY 0x1063 +#define WPS_ELEM_WEPTRANSMITKEY 0x1064 + + +#define WPS_ASSOCIATION_STATE_NOT_ASSOCIATED 0x0000 +#define WPS_ASSOCIATION_STATE_CONNECTION_SUCCESS 0x0001 +#define WPS_ASSOCIATION_STATE_CONNECTION_FAILURE 0x0002 +#define WPS_ASSOCIATION_STATE_ASSOCIATION_FAILURE 0x0003 +#define WPS_ASSOCIATION_STATE_IP_FAILURE 0x0004 + +#define WPS_AUTHENTICATION_TYPE_OPEN 0x0001 +#define WPS_AUTHENTICATION_TYPE_WPAPSK 0x0002 +#define WPS_AUTHENTICATION_TYPE_Shared 0x0004 +#define WPS_AUTHENTICATION_TYPE_WPA 0x0008 +#define WPS_AUTHENTICATION_TYPE_WPA2 0x0010 +#define WPS_AUTHENTICATION_TYPE_WPA2PSK 0x0020 + +#define WPS_CONFIG_METHOD_NONE 0x0000 /* NB not defined by spec */ +#define WPS_CONFIG_METHOD_USBA 0x0001 +#define WPS_CONFIG_METHOD_ETHERNET 0x0002 +#define WPS_CONFIG_METHOD_LABEL 0x0004 +#define WPS_CONFIG_METHOD_DISPLAY 0x0008 +#define WPS_CONFIG_METHOD_EXTERN_NFC 0x0010 +#define WPS_CONFIG_METHOD_INTERN_NFC 0x0020 +#define WPS_CONFIG_METHOD_NFC_IFACE 0x0040 +#define WPS_CONFIG_METHOD_PBC 0x0080 +#define WPS_CONFIG_METHOD_KEYPAD 0x0100 + +#define WPS_CONFIGURATION_ERROR_NO_ERROR 0 +#define WPS_CONFIGURATION_ERROR_OOB_IF_READ 1 +#define WPS_CONFIGURATION_ERROR_DECRYPT_CRC 2 +#define WPS_CONFIGURATION_ERROR_24_NOT_SUP 3 +#define WPS_CONFIGURATION_ERROR_50_NOT_SUP 4 +#define WPS_CONFIGURATION_ERROR_SIG_WEAK 5 +#define WPS_CONFIGURATION_ERROR_NET_AUTH 6 +#define WPS_CONFIGURATION_ERROR_NET_ASSOC 7 +#define WPS_CONFIGURATION_ERROR_NO_DHCP 8 +#define WPS_CONFIGURATION_ERROR_DHCP_CONF 9 +#define WPS_CONFIGURATION_ERROR_IP_CONFLICT 10 +#define WPS_CONFIGURATION_ERROR_CONN_REG 11 +#define WPS_CONFIGURATION_ERROR_MULTI_PBC 12 +#define WPS_CONFIGURATION_ERROR_ROUGE_ACT 13 +#define WPS_CONFIGURATION_ERROR_DEV_BUSY 14 +#define WPS_CONFIGURATION_ERROR_SETUP_LOCK 15 +#define WPS_CONFIGURATION_ERROR_MSG_TIMEOUT 16 +#define WPS_CONFIGURATION_ERROR_REG_TIMEOUT 17 +#define WPS_CONFIGURATION_ERROR_DEV_PASSWD 18 + +#define WPS_CONNECTION_TYPE_ESS 0x01 +#define WPS_CONNECTION_TYPE_IBSS 0x02 + +#define WPS_DEVICE_PASSWORD_ID_PIN 0x0000 +#define WPS_DEVICE_PASSWORD_ID_USER 0x0001 +#define WPS_DEVICE_PASSWORD_ID_MACHINE 0x0002 +#define WPS_DEVICE_PASSWORD_ID_REKEY 0x0003 +#define WPS_DEVICE_PASSWORD_ID_PBC 0x0004 +#define WPS_DEVICE_PASSWORD_ID_REGISTRAR 0x0005 + +#define WPS_ENCRYPTION_TYPE_NONE 0x0001 +#define WPS_ENCRYPTION_TYPE_WEP 0x0002 +#define WPS_ENCRYPTION_TYPE_TKIP 0x0004 +#define WPS_ENCRYPTION_TYPE_AES 0x0008 + +#define WPS_MESSAGE_TYPE_M1 0x04 +#define WPS_MESSAGE_TYPE_M2 0x05 +#define WPS_MESSAGE_TYPE_M2D 0x06 +#define WPS_MESSAGE_TYPE_M3 0x07 +#define WPS_MESSAGE_TYPE_M4 0x08 +#define WPS_MESSAGE_TYPE_M5 0x09 +#define WPS_MESSAGE_TYPE_M6 0x0a +#define WPS_MESSAGE_TYPE_M7 0x0b +#define WPS_MESSAGE_TYPE_M8 0x0c +#define WPS_MESSAGE_TYPE_WSC_ACK 0x0d +#define WPS_MESSAGE_TYPE_WSC_NACK 0x0e +#define WPS_MESSAGE_TYPE_WSC_Done 0x0f + +#define WPS_CATEGORY_COMPUTER 1 +#define WPS_CATEGORY_IO_DEVICE 2 +#define WPS_CATEGORY_PRINTER_SCANNER 3 +#define WPS_CATEGORY_CAMERA 4 +#define WPS_CATEGORY_STORAGE 5 +#define WPS_CATEGORY_NETWORK 6 +#define WPS_CATEGORY_DISPLAYS 7 +#define WPS_CATEGORY_MULTIMEDIA 8 +#define WPS_CATEGORY_GAMING 9 +#define WPS_CATEGORY_TELEPHONE 10 + +#define WPS_REQUEST_TYPE_ENROLLEE_INFO 0x00 +#define WPS_REQUEST_TYPE_ENROLLEE_OPEN 0x01 +#define WPS_REQUEST_TYPE_REGISTRAR 0x02 +#define WPS_REQUEST_TYPE_WLAN_MANAGER 0x03 + +#define WPS_RF_BAND_2_4GHZ 0x01 +#define WPS_RF_BAND_5_0GHZ 0x02 + +#define WPS_SUBCATEGORY_PC 1 +#define WPS_SUBCATEGORY_SERVER 2 +#define WPS_SUBCATEGORY_MEDIA_CENTER 3 +#define WPS_SUBCATEGORY_PRINTER 1 +#define WPS_SUBCATEGORY_SCANNER 2 +#define WPS_SUBCATEGORY_STILL_CAMERA 1 +#define WPS_SUBCATEGORY_NAS 1 +#define WPS_SUBCATEGORY_AP 1 +#define WPS_SUBCATEGORY_ROUTER 2 +#define WPS_SUBCATEGORY_SWITCH 3 +#define WPS_SUBCATEGORY_TELEVISION 1 +#define WPS_SUBCATEGORY_PICTURE_FRAME 2 +#define WPS_SUBCATEGORY_PROJECTOR 3 +#define WPS_SUBCATEGORY_DAR 1 +#define WPS_SUBCATEGORY_PVR 2 +#define WPS_SUBCATEGORY_MCX 3 +#define WPS_SUBCATEGORY_XBOX 1 +#define WPS_SUBCATEGORY_XBOX360 2 +#define WPS_SUBCATEGORY_PLAYSTATION 3 +#define WPS_SUBCATEGORY_WINDOWS_MOBILE 1 + +#define WPS_SETUP_STATE_NOT_CONFIGURED 0x01 +#define WPS_SETUP_STATE_CONFIGURED 0x02 + +#define WPS_VERSION_1_0 0x10 + +/** + * WPS_WALK_TIME - Amount of time allowed to start PBC configuration + * Time in seconds + */ +#define WPS_WALK_TIME 120 + + +/** + * WPS_PIN_PBC - PIN value for PBC + */ +#define WPS_PIN_PBC "00000000" + +#endif /* WPS_H */ diff -urN wpa_supplicant-0.5.10.orig/wps_i.h wpa_supplicant-0.5.10/wps_i.h --- wpa_supplicant-0.5.10.orig/wps_i.h 1969-12-31 16:00:00.000000000 -0800 +++ wpa_supplicant-0.5.10/wps_i.h 2008-08-20 14:38:10.316131000 -0700 @@ -0,0 +1,27 @@ +/* + * WiFi Protected Setup - WPS interface definitions + * Copyright (c) 2008, Chuck Tuffli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPS_I_H +#define WPS_I_H + +int wpa_parse_wps_ie(const u8 *wps_ie, size_t wps_ie_len, + struct wps_ie_data *data); +int wpa_create_wps_ie(const char *uuid_str, u16 method, u8 *wps_ie, + size_t *wps_ie_len); +int wps_config_pbc(struct wpa_supplicant *wpa_s); +int wps_cancel_walktime_timeout(struct wpa_supplicant *wpa_s); +int wps_get_pin(struct wpa_supplicant *wpa_s, char *buf, size_t buflen); +int wps_config_pin(struct wpa_supplicant *wpa_s); + +#endif /* WPS_I_H */