diff --git a/src/wps/wps.h b/src/wps/wps.h index 1beef159a..0a4ac55b3 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -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, diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c index 2f0c47c3d..8afbc7e52 100644 --- a/src/wps/wps_attr_build.c +++ b/src/wps/wps_attr_build.c @@ -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"); diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c index 7ce356302..f03b0ac88 100644 --- a/src/wps/wps_er.c +++ b/src/wps/wps_er.c @@ -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 */ diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 2ec89a9b5..7ba17db1d 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -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); diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index c2de53d2f..b485db9c8 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -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 */ diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h index de8ae5ca7..f3c4f4dab 100644 --- a/wpa_supplicant/wps_supplicant.h +++ b/wpa_supplicant/wps_supplicant.h @@ -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);