WPS: Allow Device Password to be changed from M1 to M2
authorJouni Malinen <jouni@qca.qualcomm.com>
Thu, 14 Feb 2013 18:41:14 +0000 (20:41 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 14 Feb 2013 18:41:14 +0000 (20:41 +0200)
Registrar is allowed to propose another Device Password ID in M2. Make
Enrollee validate Device Password ID in M2 to check if this happened.
This commit adds support for changing from NFC password token to default
PIN for the case where the AP is the Enrollee and has both the NFC
password token and AP PIN enabled at the same time.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

src/wps/wps.c
src/wps/wps_enrollee.c
src/wps/wps_i.h
src/wps/wps_registrar.c

index 2575705..ff4b20d 100644 (file)
@@ -53,12 +53,18 @@ struct wps_data * wps_init(const struct wps_config *cfg)
                }
                os_memcpy(data->dev_password, cfg->pin, cfg->pin_len);
                data->dev_password_len = cfg->pin_len;
+               wpa_hexdump_key(MSG_DEBUG, "WPS: AP PIN dev_password",
+                               data->dev_password, data->dev_password_len);
        }
 
 #ifdef CONFIG_WPS_NFC
        if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) {
+               /* Keep AP PIN as alternative Device Password */
+               data->alt_dev_pw_id = data->dev_pw_id;
+               data->alt_dev_password = data->dev_password;
+               data->alt_dev_password_len = data->dev_password_len;
+
                data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id;
-               os_free(data->dev_password);
                data->dev_password =
                        os_malloc(wpabuf_len(cfg->wps->ap_nfc_dev_pw));
                if (data->dev_password == NULL) {
@@ -69,6 +75,8 @@ struct wps_data * wps_init(const struct wps_config *cfg)
                          wpabuf_head(cfg->wps->ap_nfc_dev_pw),
                          wpabuf_len(cfg->wps->ap_nfc_dev_pw));
                data->dev_password_len = wpabuf_len(cfg->wps->ap_nfc_dev_pw);
+               wpa_hexdump_key(MSG_DEBUG, "WPS: NFC dev_password",
+                           data->dev_password, data->dev_password_len);
        }
 #endif /* CONFIG_WPS_NFC */
 
@@ -155,6 +163,7 @@ void wps_deinit(struct wps_data *data)
        wpabuf_free(data->dh_pubkey_r);
        wpabuf_free(data->last_msg);
        os_free(data->dev_password);
+       os_free(data->alt_dev_password);
        os_free(data->new_psk);
        wps_device_data_free(&data->peer_dev);
        os_free(data->new_ap_settings);
index 837b941..9c0cebb 100644 (file)
@@ -837,6 +837,39 @@ static int wps_process_ap_settings_e(struct wps_data *wps,
 }
 
 
+static int wps_process_dev_pw_id(struct wps_data *wps, const u8 *dev_pw_id)
+{
+       u16 id;
+
+       if (dev_pw_id == NULL) {
+               wpa_printf(MSG_DEBUG, "WPS: Device Password ID");
+               return -1;
+       }
+
+       id = WPA_GET_BE16(dev_pw_id);
+       if (wps->dev_pw_id == id) {
+               wpa_printf(MSG_DEBUG, "WPS: Device Password ID %u", id);
+               return 0;
+       }
+
+       wpa_printf(MSG_DEBUG, "WPS: Registrar trying to change Device Password "
+                  "ID from %u to %u", wps->dev_pw_id, id);
+
+       if (wps->alt_dev_password && wps->alt_dev_pw_id == id) {
+               wpa_printf(MSG_DEBUG, "WPS: Found a matching Device Password");
+               os_free(wps->dev_password);
+               wps->dev_pw_id = wps->alt_dev_pw_id;
+               wps->dev_password = wps->alt_dev_password;
+               wps->dev_password_len = wps->alt_dev_password_len;
+               wps->alt_dev_password = NULL;
+               wps->alt_dev_password_len = 0;
+               return 0;
+       }
+
+       return -1;
+}
+
+
 static enum wps_process_res wps_process_m2(struct wps_data *wps,
                                           const struct wpabuf *msg,
                                           struct wps_parse_attr *attr)
@@ -852,7 +885,8 @@ static enum wps_process_res wps_process_m2(struct wps_data *wps,
 
        if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
            wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
-           wps_process_uuid_r(wps, attr->uuid_r)) {
+           wps_process_uuid_r(wps, attr->uuid_r) ||
+           wps_process_dev_pw_id(wps, attr->dev_password_id)) {
                wps->state = SEND_WSC_NACK;
                return WPS_CONTINUE;
        }
index 8110894..6efc3bf 100644 (file)
@@ -71,6 +71,9 @@ struct wps_data {
        size_t dev_password_len;
        u16 dev_pw_id;
        int pbc;
+       u8 *alt_dev_password;
+       size_t alt_dev_password_len;
+       u16 alt_dev_pw_id;
 
        /**
         * request_type - Request Type attribute from (Re)AssocReq
index b650a3c..57344c5 100644 (file)
@@ -1358,6 +1358,14 @@ static int wps_get_dev_password(struct wps_data *wps)
        } else {
                pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e,
                                            &pin_len);
+               if (pin && wps->dev_pw_id >= 0x10) {
+                       wpa_printf(MSG_DEBUG, "WPS: No match for OOB Device "
+                                  "Password ID, but PIN found");
+                       /*
+                        * See whether Enrollee is willing to use PIN instead.
+                        */
+                       wps->dev_pw_id = DEV_PW_DEFAULT;
+               }
        }
        if (pin == NULL) {
                wpa_printf(MSG_DEBUG, "WPS: No Device Password available for "