Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / src / eap_peer / eap_wsc.c
index 09d8a1c..7ac99c7 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * EAP-WSC peer for Wi-Fi Protected Setup
- * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2009, 2012, Jouni Malinen <j@w1.fi>
  *
- * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -83,35 +77,47 @@ static int eap_wsc_new_ap_settings(struct wps_credential *cred,
        else
                len = end - pos;
        if ((len & 1) || len > 2 * sizeof(cred->ssid) ||
-           hexstr2bin(pos, cred->ssid, len / 2))
+           hexstr2bin(pos, cred->ssid, len / 2)) {
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_ssid");
                return -1;
+       }
        cred->ssid_len = len / 2;
 
        pos = os_strstr(params, "new_auth=");
-       if (pos == NULL)
+       if (pos == NULL) {
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_auth");
                return -1;
+       }
        if (os_strncmp(pos + 9, "OPEN", 4) == 0)
                cred->auth_type = WPS_AUTH_OPEN;
        else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0)
                cred->auth_type = WPS_AUTH_WPAPSK;
        else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0)
                cred->auth_type = WPS_AUTH_WPA2PSK;
-       else
+       else {
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_auth");
                return -1;
+       }
 
        pos = os_strstr(params, "new_encr=");
-       if (pos == NULL)
+       if (pos == NULL) {
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_encr");
                return -1;
+       }
        if (os_strncmp(pos + 9, "NONE", 4) == 0)
                cred->encr_type = WPS_ENCR_NONE;
+#ifdef CONFIG_TESTING_OPTIONS
        else if (os_strncmp(pos + 9, "WEP", 3) == 0)
                cred->encr_type = WPS_ENCR_WEP;
+#endif /* CONFIG_TESTING_OPTIONS */
        else if (os_strncmp(pos + 9, "TKIP", 4) == 0)
                cred->encr_type = WPS_ENCR_TKIP;
        else if (os_strncmp(pos + 9, "CCMP", 4) == 0)
                cred->encr_type = WPS_ENCR_AES;
-       else
+       else {
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_encr");
                return -1;
+       }
 
        pos = os_strstr(params, "new_key=");
        if (pos == NULL)
@@ -123,8 +129,10 @@ static int eap_wsc_new_ap_settings(struct wps_credential *cred,
        else
                len = end - pos;
        if ((len & 1) || len > 2 * sizeof(cred->key) ||
-           hexstr2bin(pos, cred->key, len / 2))
+           hexstr2bin(pos, cred->key, len / 2)) {
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_key");
                return -1;
+       }
        cred->key_len = len / 2;
 
        return 1;
@@ -138,11 +146,13 @@ static void * eap_wsc_init(struct eap_sm *sm)
        size_t identity_len;
        int registrar;
        struct wps_config cfg;
-       const char *pos;
+       const char *pos, *end;
        const char *phase1;
        struct wps_context *wps;
        struct wps_credential new_ap_settings;
        int res;
+       int nfc = 0;
+       u8 pkhash[WPS_OOB_PUBKEY_HASH_LEN];
 
        wps = sm->wps;
        if (wps == NULL) {
@@ -190,26 +200,57 @@ static void * eap_wsc_init(struct eap_sm *sm)
                while (*pos != '\0' && *pos != ' ')
                        pos++;
                cfg.pin_len = pos - (const char *) cfg.pin;
+               if (cfg.pin_len == 6 &&
+                   os_strncmp((const char *) cfg.pin, "nfc-pw", 6) == 0) {
+                       cfg.pin = NULL;
+                       cfg.pin_len = 0;
+                       nfc = 1;
+               }
        } else {
                pos = os_strstr(phase1, "pbc=1");
                if (pos)
                        cfg.pbc = 1;
        }
 
-       if (cfg.pin == NULL && !cfg.pbc) {
+       pos = os_strstr(phase1, "dev_pw_id=");
+       if (pos) {
+               u16 id = atoi(pos + 10);
+               if (id == DEV_PW_NFC_CONNECTION_HANDOVER)
+                       nfc = 1;
+               if (cfg.pin || id == DEV_PW_NFC_CONNECTION_HANDOVER)
+                       cfg.dev_pw_id = id;
+       }
+
+       if (cfg.pin == NULL && !cfg.pbc && !nfc) {
                wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 "
                           "configuration data");
                os_free(data);
                return NULL;
        }
 
-       pos = os_strstr(phase1, "dev_pw_id=");
-       if (pos && cfg.pin)
-               cfg.dev_pw_id = atoi(pos + 10);
+       pos = os_strstr(phase1, " pkhash=");
+       if (pos) {
+               size_t len;
+               pos += 8;
+               end = os_strchr(pos, ' ');
+               if (end)
+                       len = end - pos;
+               else
+                       len = os_strlen(pos);
+               if (len != 2 * WPS_OOB_PUBKEY_HASH_LEN ||
+                   hexstr2bin(pos, pkhash, WPS_OOB_PUBKEY_HASH_LEN)) {
+                       wpa_printf(MSG_INFO, "EAP-WSC: Invalid pkhash");
+                       os_free(data);
+                       return NULL;
+               }
+               cfg.peer_pubkey_hash = pkhash;
+       }
 
        res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
        if (res < 0) {
                os_free(data);
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to parse new AP "
+                          "settings");
                return NULL;
        }
        if (res == 1) {
@@ -221,6 +262,7 @@ static void * eap_wsc_init(struct eap_sm *sm)
        data->wps = wps_init(&cfg);
        if (data->wps == NULL) {
                os_free(data);
+               wpa_printf(MSG_DEBUG, "EAP-WSC: wps_init failed");
                return NULL;
        }
        res = eap_get_config_fragment_size(sm);
@@ -420,7 +462,7 @@ static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv,
                message_length = WPA_GET_BE16(pos);
                pos += 2;
 
-               if (message_length < end - pos) {
+               if (message_length < end - pos || message_length > 50000) {
                        wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
                                   "Length");
                        ret->ignore = TRUE;
@@ -515,6 +557,9 @@ send_msg:
                if (data->out_buf == NULL) {
                        wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to receive "
                                   "message from WPS");
+                       eap_wsc_state(data, FAIL);
+                       ret->methodState = METHOD_DONE;
+                       ret->decision = DECISION_FAIL;
                        return NULL;
                }
                data->out_used = 0;