Added preliminary Wi-Fi Protected Setup (WPS) implementation

This adds WPS support for both hostapd and wpa_supplicant. Both programs
can be configured to act as WPS Enrollee and Registrar. Both PBC and PIN
methods are supported.

Currently, hostapd has more complete configuration option for WPS
parameters and wpa_supplicant configuration style will likely change in
the future. External Registrars are not yet supported in hostapd or
wpa_supplicant. While wpa_supplicant has initial support for acting as
an Registrar to configure an AP, this is still using number of hardcoded
parameters which will need to be made configurable for proper operation.
This commit is contained in:
Jouni Malinen 2008-11-23 19:34:26 +02:00
parent 6e89cc438e
commit ad08c3633c
71 changed files with 8602 additions and 47 deletions

View file

@ -493,6 +493,26 @@ endif
NEED_SHA256=y
endif
ifdef CONFIG_WPS
# EAP-WSC
ifeq ($(CONFIG_EAP_WSC), dyn)
CFLAGS += -DCONFIG_WPS -DEAP_WSC_DYNAMIC
EAPDYN += ../src/eap_peer/eap_wsc.so
else
CFLAGS += -DCONFIG_WPS -DEAP_WSC
OBJS += ../src/utils/uuid.o
OBJS += ../src/eap_peer/eap_wsc.o ../src/eap_common/eap_wsc_common.o
OBJS += ../src/wps/wps.o
OBJS += ../src/wps/wps_common.o
OBJS += ../src/wps/wps_dev_attr.o
OBJS += ../src/wps/wps_enrollee.o
OBJS += ../src/wps/wps_registrar.o
OBJS_h += ../src/eap_server/eap_wsc.o
endif
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
endif
ifdef CONFIG_EAP_IKEV2
# EAP-IKEv2
ifeq ($(CONFIG_EAP_IKEV2), dyn)
@ -1080,6 +1100,10 @@ eap_sake.so: ../src/eap_peer/eap_sake.c ../src/eap_common/eap_sake_common.c
$(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
-Deap_peer_sake_register=eap_peer_method_dynamic_init
eap_wsc.so: ../src/eap_peer/eap_wsc.c ../src/eap_common/eap_wsc_common.c ../src/wps/wps.c
$(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
-Deap_peer_wsc_register=eap_peer_method_dynamic_init
eap_ikev2.so: ../src/eap_peer/eap_ikev2.c ../src/eap_peer/ikev2.c ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.c
$(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
-Deap_peer_ikev2_register=eap_peer_method_dynamic_init

View file

@ -515,6 +515,10 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
else if (os_strcmp(start, "WPS") == 0)
val |= WPA_KEY_MGMT_WPS;
#endif /* CONFIG_WPS */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);

View file

@ -871,6 +871,8 @@ int wpa_config_write(const char *name, struct wpa_config *config)
wpa_config_write_global(f, config);
for (ssid = config->ssid; ssid; ssid = ssid->next) {
if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
continue; /* do not save temporary WPS networks */
fprintf(f, "\nnetwork={\n");
wpa_config_write_network(f, ssid);
fprintf(f, "}\n");

View file

@ -874,6 +874,8 @@ int wpa_config_write(const char *name, struct wpa_config *config)
wpa_config_delete_subkeys(hk, TEXT("networks"));
for (ssid = config->ssid, id = 0; ssid; ssid = ssid->next, id++) {
if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
continue; /* do not save temporary WPS networks */
if (wpa_config_write_network(hk, ssid, id))
errors++;
}

View file

@ -420,6 +420,14 @@ DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
goto error;
}
ie = wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE);
if (ie) {
if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
(const char *) ie,
ie[1] + 2))
goto error;
}
if (res->freq) {
if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency",
res->freq))

View file

@ -170,6 +170,9 @@ CONFIG_EAP_LEAP=y
# EAP-TNC and related Trusted Network Connect support (experimental)
#CONFIG_EAP_TNC=y
# Wi-Fi Protected Setup (WPS)
#CONFIG_WPS=y
# EAP-IKEv2
#CONFIG_EAP_IKEV2=y

View file

@ -336,6 +336,7 @@ static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
#endif /* EAP_TLS_OPENSSL */
ctx->mac_addr = wpa_s->own_addr;
wpa_s->eapol = eapol_sm_init(ctx);
if (wpa_s->eapol == NULL) {

View file

@ -31,6 +31,7 @@
#include "ieee802_11_defs.h"
#include "blacklist.h"
#include "wpas_glue.h"
#include "wps/wps.h"
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
@ -276,6 +277,53 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_ssid *ssid,
int proto_match = 0;
const u8 *rsn_ie, *wpa_ie;
#ifdef CONFIG_WPS
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
const u8 *wps_ie;
wps_ie = wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
if (!wps_ie) {
wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
return 0;
}
if (!wps_is_selected_pbc_registrar(wps_ie + 6,
wps_ie[1] - 4)) {
wpa_printf(MSG_DEBUG, " skip - WPS AP "
"without active PBC Registrar");
return 0;
}
/* TODO: overlap detection */
wpa_printf(MSG_DEBUG, " selected based on WPS IE "
"(Active PBC)");
return 1;
}
if (eap_is_wps_pin_enrollee(&ssid->eap)) {
if (!wps_ie) {
wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
return 0;
}
if (!wps_is_selected_pin_registrar(wps_ie + 6,
wps_ie[1] - 4)) {
wpa_printf(MSG_DEBUG, " skip - WPS AP "
"without active PIN Registrar");
return 0;
}
wpa_printf(MSG_DEBUG, " selected based on WPS IE "
"(Active PIN)");
return 1;
}
if (wps_ie) {
wpa_printf(MSG_DEBUG, " selected based on WPS IE");
return 1;
}
}
#endif /* CONFIG_WPS */
rsn_ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
proto_match++;
@ -364,6 +412,34 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_ssid *ssid,
}
#ifdef CONFIG_WPS
static int wps_ssid_wildcard_ok(struct wpa_ssid *ssid,
struct wpa_scan_res *bss)
{
const u8 *wps_ie;
if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
wps_ie = wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
if (wps_ie &&
wps_is_selected_pbc_registrar(wps_ie + 6, wps_ie[1] - 4)) {
/* allow wildcard SSID for WPS PBC */
return 1;
}
}
if (eap_is_wps_pin_enrollee(&ssid->eap)) {
wps_ie = wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
if (wps_ie &&
wps_is_selected_pin_registrar(wps_ie + 6, wps_ie[1] - 4)) {
/* allow wildcard SSID for WPS PIN */
return 1;
}
}
return 0;
}
#endif /* CONFIG_WPS */
static struct wpa_scan_res *
wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s,
struct wpa_ssid *group,
@ -409,13 +485,22 @@ wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s,
}
for (ssid = group; ssid; ssid = ssid->pnext) {
int check_ssid = 1;
if (ssid->disabled) {
wpa_printf(MSG_DEBUG, " skip - disabled");
continue;
}
if (ssid_len != ssid->ssid_len ||
os_memcmp(ssid_, ssid->ssid, ssid_len) != 0) {
#ifdef CONFIG_WPS
if (ssid->ssid_len == 0 &&
wps_ssid_wildcard_ok(ssid, bss))
check_ssid = 0;
#endif /* CONFIG_WPS */
if (check_ssid &&
(ssid_len != ssid->ssid_len ||
os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
wpa_printf(MSG_DEBUG, " skip - "
"SSID mismatch");
continue;
@ -485,12 +570,26 @@ wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s,
}
for (ssid = group; ssid; ssid = ssid->pnext) {
int check_ssid = ssid->ssid_len != 0;
if (ssid->disabled) {
wpa_printf(MSG_DEBUG, " skip - disabled");
continue;
}
if (ssid->ssid_len != 0 &&
#ifdef CONFIG_WPS
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
/* Only allow wildcard SSID match if an AP
* advertises active WPS operation that matches
* with our mode. */
check_ssid = 1;
if (ssid->ssid_len == 0 &&
wps_ssid_wildcard_ok(ssid, bss))
check_ssid = 0;
}
#endif /* CONFIG_WPS */
if (check_ssid &&
(ssid_len != ssid->ssid_len ||
os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
wpa_printf(MSG_DEBUG, " skip - "
@ -507,6 +606,7 @@ wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s,
}
if (!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
!(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
!(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA))
{
wpa_printf(MSG_DEBUG, " skip - "
@ -570,6 +670,65 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
}
#ifdef CONFIG_WPS
static int wpa_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *selected,
struct wpa_ssid *ssid)
{
const u8 *sel_uuid, *uuid;
size_t i;
const u8 *wps_ie;
if (!eap_is_wps_pbc_enrollee(&ssid->eap))
return 0;
/* Make sure that only one AP is in active PBC mode */
wps_ie = wpa_scan_get_vendor_ie(selected, WPS_IE_VENDOR_TYPE);
if (wps_ie)
sel_uuid = wps_get_uuid_e(wps_ie + 6, wps_ie[1] - 4);
else
sel_uuid = NULL;
if (!sel_uuid) {
wpa_printf(MSG_DEBUG, "WPS: UUID-E not "
"available for PBC overlap "
"detection");
return 1;
}
for (i = 0; i < wpa_s->scan_res->num; i++) {
struct wpa_scan_res *bss = wpa_s->scan_res->res[i];
if (bss == selected)
continue;
wps_ie = wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
if (!wps_ie)
continue;
if (!wps_is_selected_pbc_registrar(wps_ie + 6,
wps_ie[1] - 4))
continue;
uuid = wps_get_uuid_e(wps_ie + 6, wps_ie[1] - 4);
if (uuid == NULL) {
wpa_printf(MSG_DEBUG, "WPS: UUID-E not "
"available for PBC overlap "
"detection (other BSS)");
return 1;
}
if (os_memcmp(sel_uuid, uuid, 16) != 0)
return 1; /* PBC overlap */
/* TODO: verify that this is reasonable dual-band situation */
}
return 0;
}
#else /* CONFIG_WPS */
#define wpa_scan_pbc_overlap(w, s, i) 0
#endif /* CONFIG_WPS */
static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s)
{
int prio, timeout;
@ -619,6 +778,13 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s)
}
if (selected) {
if (wpa_scan_pbc_overlap(wpa_s, selected, ssid)) {
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP
"PBC session overlap");
timeout = 10;
goto req_scan;
}
/* Do not trigger new association unless the BSSID has changed
* or if reassociation is requested. If we are in process of
* associating with the selected BSSID, do not trigger new

View file

@ -20,6 +20,7 @@
#include "wpa_supplicant_i.h"
#include "mlme.h"
#include "uuid.h"
#include "wps/wps.h"
static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
@ -41,13 +42,45 @@ static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
}
#ifdef CONFIG_WPS
static int wpas_wps_in_use(struct wpa_config *conf, u8 *uuid)
{
struct wpa_ssid *ssid;
int wps = 0;
const char *pos;
for (ssid = conf->ssid; ssid; ssid = ssid->next) {
if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
continue;
wps = 1;
if (!ssid->eap.phase1)
continue;
pos = os_strstr(ssid->eap.phase1, "uuid=");
if (pos)
uuid_str2bin(pos + 5, uuid);
if (os_strstr(ssid->eap.phase1, "pbc=1"))
return 2;
}
return wps;
}
#endif /* CONFIG_WPS */
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct wpa_ssid *ssid;
int enabled, scan_req = 0, ret;
struct wpabuf *wps_ie = NULL;
const u8 *extra_ie = NULL;
size_t extra_ie_len = 0;
int wps = 0;
#ifdef CONFIG_WPS
u8 uuid[UUID_LEN];
#endif /* CONFIG_WPS */
if (wpa_s->disconnected && !wpa_s->scan_req)
return;
@ -134,8 +167,12 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
} else
wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN;
#ifdef CONFIG_WPS
wps = wpas_wps_in_use(wpa_s->conf, uuid);
#endif /* CONFIG_WPS */
if (wpa_s->scan_res_tried == 0 && wpa_s->conf->ap_scan == 1 &&
!wpa_s->use_client_mlme) {
!wpa_s->use_client_mlme && wps != 2) {
wpa_s->scan_res_tried++;
wpa_s->scan_req = scan_req;
wpa_printf(MSG_DEBUG, "Trying to get current scan results "
@ -145,6 +182,16 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
return;
}
#ifdef CONFIG_WPS
if (wps) {
wps_ie = wps_enrollee_build_probe_req_ie(wps == 2, uuid);
if (wps_ie) {
extra_ie = wpabuf_head(wps_ie);
extra_ie_len = wpabuf_len(wps_ie);
}
}
#endif /* CONFIG_WPS */
if (wpa_s->use_client_mlme) {
ieee80211_sta_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len);
ret = ieee80211_sta_req_scan(wpa_s, ssid ? ssid->ssid : NULL,
@ -155,6 +202,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
ssid ? ssid->ssid_len : 0);
}
wpabuf_free(wps_ie);
if (ret) {
wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
wpa_supplicant_req_scan(wpa_s, 10, 0);

View file

@ -38,6 +38,7 @@
#include "ieee802_11_defs.h"
#include "blacklist.h"
#include "wpas_glue.h"
#include "wps/wps.h"
const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
@ -282,7 +283,8 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
eapol_conf.workaround = ssid->eap_workaround;
eapol_conf.eap_disabled =
!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA;
wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
#endif /* IEEE8021X_EAPOL */
}
@ -302,7 +304,9 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
{
int i;
if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
else if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
else
wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
@ -635,6 +639,8 @@ static wpa_key_mgmt key_mgmt2driver(int key_mgmt)
return KEY_MGMT_802_1X_SHA256;
case WPA_KEY_MGMT_PSK_SHA256:
return KEY_MGMT_PSK_SHA256;
case WPA_KEY_MGMT_WPS:
return KEY_MGMT_WPS;
case WPA_KEY_MGMT_PSK:
default:
return KEY_MGMT_PSK;
@ -1001,6 +1007,16 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
"results)");
return;
}
#ifdef CONFIG_WPS
} else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
struct wpabuf *wps_ie = wps_enrollee_build_assoc_req_ie();
if (wps_ie && wpabuf_len(wps_ie) <= sizeof(wpa_ie)) {
wpa_ie_len = wpabuf_len(wps_ie);
os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len);
}
wpabuf_free(wps_ie);
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
#endif /* CONFIG_WPS */
} else {
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
wpa_ie_len = 0;
@ -1019,6 +1035,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
wep_keys_set = 1;
}
}
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
use_crypt = 0;
#ifdef IEEE8021X_EAPOL
if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {

View file

@ -397,6 +397,8 @@ fast_reauth=1
# * 0 = do not use cryptobinding (default)
# * 1 = use cryptobinding if server supports it
# * 2 = require cryptobinding
# EAP-WSC (WPS) uses following options: pin=<Device Password> and
# uuid=<Device UUID>.
# phase2: Phase2 (inner authentication with TLS tunnel) parameters
# (string with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
# "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS)

View file

@ -25,6 +25,8 @@
#include "pmksa_cache.h"
#include "mlme.h"
#include "ieee802_11_defs.h"
#include "wps/wps.h"
#include "wps/wps_defs.h"
#include "wpa_ctrl.h"
#include "wpas_glue.h"
@ -228,6 +230,19 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully",
success ? "" : "un");
#ifdef CONFIG_WPS
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid &&
!(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
"try to associate with the received credential");
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
return;
}
#endif /* CONFIG_WPS */
if (!success) {
/*
* Make sure we do not get stuck here waiting for long EAPOL
@ -491,6 +506,139 @@ static int wpa_supplicant_send_ft_action(void *ctx, u8 action,
#endif /* CONFIG_NO_WPA */
#ifdef CONFIG_WPS
static int wpa_supplicant_wps_cred(void *ctx, struct wps_credential *cred)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *ssid = wpa_s->current_ssid;
wpa_msg(wpa_s, MSG_INFO, "WPS: New credential received");
if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
"on the received credential");
os_free(ssid->eap.identity);
ssid->eap.identity = NULL;
ssid->eap.identity_len = 0;
os_free(ssid->eap.phase1);
ssid->eap.phase1 = NULL;
os_free(ssid->eap.eap_methods);
ssid->eap.eap_methods = NULL;
} else {
wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
"received credential");
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL)
return -1;
}
wpa_config_set_network_defaults(ssid);
os_free(ssid->ssid);
ssid->ssid = os_malloc(cred->ssid_len);
if (ssid->ssid) {
os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len);
ssid->ssid_len = cred->ssid_len;
}
switch (cred->encr_type) {
case WPS_ENCR_NONE:
ssid->pairwise_cipher = ssid->group_cipher = WPA_CIPHER_NONE;
break;
case WPS_ENCR_WEP:
ssid->pairwise_cipher = ssid->group_cipher =
WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104;
if (cred->key_len > 0 && cred->key_len <= MAX_WEP_KEY_LEN &&
cred->key_idx < NUM_WEP_KEYS) {
os_memcpy(ssid->wep_key[cred->key_idx], cred->key,
cred->key_len);
ssid->wep_key_len[cred->key_idx] = cred->key_len;
ssid->wep_tx_keyidx = cred->key_idx;
}
break;
case WPS_ENCR_TKIP:
ssid->pairwise_cipher = WPA_CIPHER_TKIP;
ssid->group_cipher = WPA_CIPHER_TKIP;
break;
case WPS_ENCR_AES:
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
break;
}
switch (cred->auth_type) {
case WPS_AUTH_OPEN:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_NONE;
ssid->proto = 0;
break;
case WPS_AUTH_SHARED:
ssid->auth_alg = WPA_AUTH_ALG_SHARED;
ssid->key_mgmt = WPA_KEY_MGMT_NONE;
ssid->proto = 0;
break;
case WPS_AUTH_WPAPSK:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->proto = WPA_PROTO_WPA;
break;
case WPS_AUTH_WPA:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
ssid->proto = WPA_PROTO_WPA;
break;
case WPS_AUTH_WPA2:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
ssid->proto = WPA_PROTO_RSN;
break;
case WPS_AUTH_WPA2PSK:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->proto = WPA_PROTO_RSN;
break;
}
if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) {
if (cred->key_len == 2 * PMK_LEN) {
if (hexstr2bin((const char *) cred->key, ssid->psk,
PMK_LEN)) {
wpa_printf(MSG_ERROR, "WPS: Invalid Network "
"Key");
return -1;
}
ssid->psk_set = 1;
} else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) {
os_free(ssid->passphrase);
ssid->passphrase = os_malloc(cred->key_len + 1);
if (ssid->passphrase == NULL)
return -1;
os_memcpy(ssid->passphrase, cred->key, cred->key_len);
ssid->passphrase[cred->key_len] = '\0';
wpa_config_update_psk(ssid);
} else {
wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
"length %lu",
(unsigned long) cred->key_len);
return -1;
}
}
#ifndef CONFIG_NO_CONFIG_WRITE
if (wpa_s->conf->update_config &&
wpa_config_write(wpa_s->confname, wpa_s->conf)) {
wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration");
return -1;
}
#endif /* CONFIG_NO_CONFIG_WRITE */
return 0;
}
#else /* CONFIG_WPS */
#define wpa_supplicant_wps_cred NULL
#endif /* CONFIG_WPS */
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
static void wpa_supplicant_eap_param_needed(void *ctx, const char *field,
const char *txt)
@ -554,6 +702,8 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
#endif /* EAP_TLS_OPENSSL */
ctx->mac_addr = wpa_s->own_addr;
ctx->wps_cred = wpa_supplicant_wps_cred;
ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
ctx->cb = wpa_supplicant_eapol_cb;
ctx->cb_ctx = wpa_s;