NFC: Update WPS ER to use the new connection handover design
authorJouni Malinen <jouni@qca.qualcomm.com>
Fri, 12 Apr 2013 04:37:41 +0000 (21:37 -0700)
committerJouni Malinen <j@w1.fi>
Mon, 27 Jan 2014 19:10:55 +0000 (21:10 +0200)
Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

src/wps/wps.h
src/wps/wps_attr_build.c
src/wps/wps_er.c
wpa_supplicant/ctrl_iface.c
wpa_supplicant/wps_supplicant.c
wpa_supplicant/wps_supplicant.h

index 1beef15..0a4ac55 100644 (file)
@@ -845,6 +845,9 @@ struct wpabuf * wps_er_config_token_from_cred(struct wps_context *wps,
                                              struct wps_credential *cred);
 struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid,
                                        const u8 *addr);
+struct wpabuf * wps_er_nfc_handover_sel(struct wps_er *er,
+                                       struct wps_context *wps, const u8 *uuid,
+                                       const u8 *addr, struct wpabuf *pubkey);
 
 int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]);
 char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
index 2f0c47c..8afbc7e 100644 (file)
@@ -40,7 +40,11 @@ int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
 #ifdef CONFIG_WPS_NFC
        } else if ((wps->dev_pw_id >= 0x10 ||
                    wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) &&
-                  wps->wps->ap &&
+                  (wps->wps->ap ||
+                   (wps->wps->ap_nfc_dh_pubkey &&
+                    wps->wps->ap_nfc_dev_pw_id ==
+                    DEV_PW_NFC_CONNECTION_HANDOVER &&
+                    wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER)) &&
                   (wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id ||
                    wps->wps->ap_nfc_dh_pubkey)) {
                wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys");
index 7ce3563..f03b0ac 100644 (file)
@@ -2070,4 +2070,29 @@ struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid,
        return wps_er_config_token_from_cred(er->wps, ap->ap_settings);
 }
 
+
+struct wpabuf * wps_er_nfc_handover_sel(struct wps_er *er,
+                                       struct wps_context *wps, const u8 *uuid,
+                                       const u8 *addr, struct wpabuf *pubkey)
+{
+       struct wps_er_ap *ap;
+
+       if (er == NULL)
+               return NULL;
+
+       ap = wps_er_ap_get(er, NULL, uuid, addr);
+       if (ap == NULL)
+               return NULL;
+       if (ap->ap_settings == NULL) {
+               wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
+                          "selected AP");
+               return NULL;
+       }
+
+       os_memcpy(wps->ssid, ap->ap_settings->ssid, ap->ap_settings->ssid_len);
+       wps->ssid_len = ap->ap_settings->ssid_len;
+
+       return wps_build_nfc_handover_sel(wps, pubkey);
+}
+
 #endif /* CONFIG_WPS_NFC */
index 2ec89a9..7ba17db 100644 (file)
@@ -1128,6 +1128,8 @@ static int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s,
        } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0)
        {
                ret = wpas_ap_wps_nfc_report_handover(wpa_s, req, sel);
+               if (ret < 0)
+                       ret = wpas_er_wps_nfc_report_handover(wpa_s, req, sel);
        } else {
                wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
                           "reported: role=%s type=%s", role, type);
index c2de53d..b485db9 100644 (file)
@@ -1444,6 +1444,20 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
 }
 
 
+#ifdef CONFIG_WPS_ER
+static void wpas_wps_nfc_clear(struct wps_context *wps)
+{
+       wps->ap_nfc_dev_pw_id = 0;
+       wpabuf_free(wps->ap_nfc_dh_pubkey);
+       wps->ap_nfc_dh_pubkey = NULL;
+       wpabuf_free(wps->ap_nfc_dh_privkey);
+       wps->ap_nfc_dh_privkey = NULL;
+       wpabuf_free(wps->ap_nfc_dev_pw);
+       wps->ap_nfc_dev_pw = NULL;
+}
+#endif /* CONFIG_WPS_ER */
+
+
 void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
 {
        eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
@@ -1457,6 +1471,7 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
 #ifdef CONFIG_WPS_ER
        wps_er_deinit(wpa_s->wps_er, NULL, NULL);
        wpa_s->wps_er = NULL;
+       wpas_wps_nfc_clear(wpa_s->wps);
 #endif /* CONFIG_WPS_ER */
 
        wps_registrar_deinit(wpa_s->wps->registrar);
@@ -2305,6 +2320,7 @@ struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s,
 
 
 #ifdef CONFIG_WPS_NFC
+
 static struct wpabuf *
 wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef,
                             const char *uuid)
@@ -2314,7 +2330,7 @@ wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef,
        u8 u[UUID_LEN], *use_uuid = NULL;
        u8 addr[ETH_ALEN], *use_addr = NULL;
 
-       if (!wpa_s->wps_er)
+       if (wpa_s->wps == NULL)
                return NULL;
 
        if (uuid == NULL)
@@ -2326,11 +2342,26 @@ wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef,
        else
                return NULL;
 
-       /*
-        * Handover Select carrier record for WPS uses the same format as
-        * configuration token.
-        */
-       ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr);
+       if (wpa_s->conf->wps_nfc_dh_pubkey == NULL) {
+               struct wps_context *wps = wpa_s->wps;
+               if (wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+                                  &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+                       return NULL;
+
+               wpas_wps_nfc_clear(wps);
+               wps->ap_nfc_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
+               wps->ap_nfc_dh_pubkey =
+                       wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
+               wps->ap_nfc_dh_privkey =
+                       wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
+               if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey) {
+                       wpas_wps_nfc_clear(wps);
+                       return NULL;
+               }
+       }
+
+       ret = wps_er_nfc_handover_sel(wpa_s->wps_er, wpa_s->wps, use_uuid,
+                                     use_addr, wpa_s->conf->wps_nfc_dh_pubkey);
        if (ndef && ret) {
                struct wpabuf *tmp;
                tmp = ndef_build_wifi(ret);
@@ -2467,6 +2498,100 @@ int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
        return wpas_wps_nfc_rx_handover_sel(wpa_s, sel);
 }
 
+
+int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+                                   const struct wpabuf *req,
+                                   const struct wpabuf *sel)
+{
+       struct wpabuf *wps;
+       int ret = -1;
+       u16 wsc_len;
+       const u8 *pos;
+       struct wpabuf msg;
+       struct wps_parse_attr attr;
+       u16 dev_pw_id;
+
+       /*
+        * Enrollee/station is always initiator of the NFC connection handover,
+        * so use the request message here to find Enrollee public key hash.
+        */
+       wps = ndef_parse_wifi(req);
+       if (wps == NULL)
+               return -1;
+       wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
+                  "payload from NFC connection handover");
+       wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
+       if (wpabuf_len(wps) < 2) {
+               wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Request "
+                          "Message");
+               goto out;
+       }
+       pos = wpabuf_head(wps);
+       wsc_len = WPA_GET_BE16(pos);
+       if (wsc_len > wpabuf_len(wps) - 2) {
+               wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
+                          "in rt Wi-Fi Handover Request Message", wsc_len);
+               goto out;
+       }
+       pos += 2;
+
+       wpa_hexdump(MSG_DEBUG,
+                   "WPS: WSC attributes in Wi-Fi Handover Request Message",
+                   pos, wsc_len);
+       if (wsc_len < wpabuf_len(wps) - 2) {
+               wpa_hexdump(MSG_DEBUG,
+                           "WPS: Ignore extra data after WSC attributes",
+                           pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
+       }
+
+       wpabuf_set(&msg, pos, wsc_len);
+       ret = wps_parse_msg(&msg, &attr);
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
+                          "Wi-Fi Handover Request Message");
+               goto out;
+       }
+
+       if (attr.oob_dev_password == NULL ||
+           attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+               wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
+                          "included in Wi-Fi Handover Request Message");
+               ret = -1;
+               goto out;
+       }
+
+       if (attr.uuid_e == NULL) {
+               wpa_printf(MSG_DEBUG, "WPS: No UUID-E included in Wi-Fi "
+                          "Handover Request Message");
+               ret = -1;
+               goto out;
+       }
+
+       wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", attr.uuid_e, WPS_UUID_LEN);
+
+       wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
+                   attr.oob_dev_password, attr.oob_dev_password_len);
+       dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
+                                WPS_OOB_PUBKEY_HASH_LEN);
+       if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
+               wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
+                          "%u in Wi-Fi Handover Request Message", dev_pw_id);
+               ret = -1;
+               goto out;
+       }
+       wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Public Key hash",
+                   attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
+
+       ret = wps_registrar_add_nfc_pw_token(wpa_s->wps->registrar,
+                                            attr.oob_dev_password,
+                                            DEV_PW_NFC_CONNECTION_HANDOVER,
+                                            NULL, 0, 1);
+
+out:
+       wpabuf_free(wps);
+       return ret;
+}
+
 #endif /* CONFIG_WPS_NFC */
 
 
index de8ae5c..f3c4f4d 100644 (file)
@@ -81,6 +81,9 @@ int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
 int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
                                 const struct wpabuf *req,
                                 const struct wpabuf *sel);
+int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+                                   const struct wpabuf *req,
+                                   const struct wpabuf *sel);
 void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
                             struct wpa_scan_results *scan_res);
 void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);