diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c index 8edb1cad5..27ce2e31c 100644 --- a/src/eap_peer/eap_wsc.c +++ b/src/eap_peer/eap_wsc.c @@ -144,12 +144,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) { @@ -220,6 +221,24 @@ static void * eap_wsc_init(struct eap_sm *sm) 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); diff --git a/src/wps/wps.c b/src/wps/wps.c index 22d7eeaa6..80343c8a3 100644 --- a/src/wps/wps.c +++ b/src/wps/wps.c @@ -133,6 +133,12 @@ struct wps_data * wps_init(const struct wps_config *cfg) data->use_psk_key = cfg->use_psk_key; data->pbc_in_m1 = cfg->pbc_in_m1; + if (cfg->peer_pubkey_hash) { + os_memcpy(data->peer_pubkey_hash, cfg->peer_pubkey_hash, + WPS_OOB_PUBKEY_HASH_LEN); + data->peer_pubkey_hash_set = 1; + } + return data; } diff --git a/src/wps/wps.h b/src/wps/wps.h index 15137a8a8..7e609c831 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -183,6 +183,11 @@ struct wps_config { * PBC with the AP. */ int pbc_in_m1; + + /** + * peer_pubkey_hash - Peer public key hash or %NULL if not known + */ + const u8 *peer_pubkey_hash; }; struct wps_data * wps_init(const struct wps_config *cfg); diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c index 7b86ff7ac..03005822c 100644 --- a/src/wps/wps_enrollee.c +++ b/src/wps/wps_enrollee.c @@ -514,6 +514,23 @@ static int wps_process_pubkey(struct wps_data *wps, const u8 *pk, return -1; } + if (wps->peer_pubkey_hash_set) { + u8 hash[WPS_HASH_LEN]; + sha256_vector(1, &pk, &pk_len, hash); + if (os_memcmp(hash, wps->peer_pubkey_hash, + WPS_OOB_PUBKEY_HASH_LEN) != 0) { + wpa_printf(MSG_ERROR, "WPS: Public Key hash mismatch"); + wpa_hexdump(MSG_DEBUG, "WPS: Received public key", + pk, pk_len); + wpa_hexdump(MSG_DEBUG, "WPS: Calculated public key " + "hash", hash, WPS_OOB_PUBKEY_HASH_LEN); + wpa_hexdump(MSG_DEBUG, "WPS: Expected public key hash", + wps->peer_pubkey_hash, + WPS_OOB_PUBKEY_HASH_LEN); + return -1; + } + } + wpabuf_free(wps->dh_pubkey_r); wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len); if (wps->dh_pubkey_r == NULL) diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h index aa8a6fadb..22070db9b 100644 --- a/src/wps/wps_i.h +++ b/src/wps/wps_i.h @@ -75,6 +75,9 @@ struct wps_data { size_t alt_dev_password_len; u16 alt_dev_pw_id; + u8 peer_pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN]; + int peer_pubkey_hash_set; + /** * request_type - Request Type attribute from (Re)AssocReq */ diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 68157d23c..277e32131 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -813,7 +813,7 @@ static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s, else if (hwaddr_aton(cmd, bssid)) return -1; - return wpas_wps_start_nfc(wpa_s, _bssid); + return wpas_wps_start_nfc(wpa_s, _bssid, NULL, 0, 0, NULL); } diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 038c7fae9..c32457b4d 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -1072,12 +1072,14 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, } -int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, - const char *pin, int p2p_group, u16 dev_pw_id) +static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *pin, int p2p_group, u16 dev_pw_id, + const u8 *peer_pubkey_hash) { struct wpa_ssid *ssid; - char val[128]; + char val[128 + 2 * WPS_OOB_PUBKEY_HASH_LEN]; unsigned int rpin = 0; + char hash[2 * WPS_OOB_PUBKEY_HASH_LEN + 10]; wpas_clear_wps(wpa_s); ssid = wpas_wps_add_network(wpa_s, 0, bssid); @@ -1085,6 +1087,14 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, return -1; ssid->temporary = 1; ssid->p2p_group = p2p_group; + if (peer_pubkey_hash) { + os_memcpy(hash, " pkhash=", 8); + wpa_snprintf_hex_uppercase(hash + 8, sizeof(hash) - 8, + peer_pubkey_hash, + WPS_OOB_PUBKEY_HASH_LEN); + } else { + hash[0] = '\0'; + } #ifdef CONFIG_P2P if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) { ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1); @@ -1098,12 +1108,12 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, } #endif /* CONFIG_P2P */ if (pin) - os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u\"", - pin, dev_pw_id); + os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u%s\"", + pin, dev_pw_id, hash); else { rpin = wps_generate_pin(); - os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u\"", - rpin, dev_pw_id); + os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u%s\"", + rpin, dev_pw_id, hash); } if (wpa_config_set(ssid, "phase1", val, 0) < 0) return -1; @@ -1117,6 +1127,14 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, } +int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *pin, int p2p_group, u16 dev_pw_id) +{ + return wpas_wps_start_dev_pw(wpa_s, bssid, pin, p2p_group, dev_pw_id, + NULL); +} + + /* Cancel the wps pbc/pin requests */ int wpas_wps_cancel(struct wpa_supplicant *wpa_s) { @@ -2070,14 +2088,21 @@ struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef) } -int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid) +int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid, + const struct wpabuf *dev_pw, u16 dev_pw_id, + int p2p_group, const u8 *peer_pubkey_hash) { struct wps_context *wps = wpa_s->wps; char pw[32 * 2 + 1]; + if (dev_pw == NULL) { + dev_pw = wpa_s->conf->wps_nfc_dev_pw; + dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id; + } + if (wpa_s->conf->wps_nfc_dh_pubkey == NULL || wpa_s->conf->wps_nfc_dh_privkey == NULL || - wpa_s->conf->wps_nfc_dev_pw == NULL) + dev_pw == NULL) return -1; dh5_free(wps->dh_ctx); @@ -2103,10 +2128,9 @@ int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid) } wpa_snprintf_hex_uppercase(pw, sizeof(pw), - wpabuf_head(wpa_s->conf->wps_nfc_dev_pw), - wpabuf_len(wpa_s->conf->wps_nfc_dev_pw)); - return wpas_wps_start_pin(wpa_s, bssid, pw, 0, - wpa_s->conf->wps_nfc_dev_pw_id); + wpabuf_head(dev_pw), wpabuf_len(dev_pw)); + return wpas_wps_start_dev_pw(wpa_s, bssid, pw, p2p_group, dev_pw_id, + peer_pubkey_hash); } diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h index 3fcfbbe19..93cadda63 100644 --- a/wpa_supplicant/wps_supplicant.h +++ b/wpa_supplicant/wps_supplicant.h @@ -64,7 +64,9 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s); struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s, int ndef, const char *id_str); struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef); -int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid); +int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid, + const struct wpabuf *dev_pw, u16 dev_pw_id, + int p2p_group, const u8 *peer_pubkey_hash); int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s, const struct wpabuf *data); struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s, int cr);