From d2709206920b2e38f53077d01f5ef8d5d2e443af Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 29 Oct 2017 16:08:02 +0200 Subject: [PATCH] DPP: Negotiation channel change request from Initiator Allow the Initiator to request a different channel to be used for DPP Authentication and DPP Configuration exchanges. This commit adds support for this in wpa_supplicant with the optional neg_freq= parameter in DPP_AUTH_INIT. Signed-off-by: Jouni Malinen --- src/ap/dpp_hostapd.c | 2 +- src/common/dpp.c | 62 ++++++++++++++++++++++++++++++--- src/common/dpp.h | 6 +++- wpa_supplicant/dpp_supplicant.c | 56 +++++++++++++++++++++++++---- 4 files changed, 112 insertions(+), 14 deletions(-) diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index 943e20648..6c45ee382 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -503,7 +503,7 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd) if (hapd->dpp_auth) dpp_auth_deinit(hapd->dpp_auth); - hapd->dpp_auth = dpp_auth_init(hapd, peer_bi, own_bi, configurator); + hapd->dpp_auth = dpp_auth_init(hapd, peer_bi, own_bi, configurator, 0); if (!hapd->dpp_auth) goto fail; hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth); diff --git a/src/common/dpp.c b/src/common/dpp.c index f969cb35f..00e7b4793 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -1349,7 +1349,8 @@ static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth, const struct wpabuf *pi, size_t nonce_len, const u8 *r_pubkey_hash, - const u8 *i_pubkey_hash) + const u8 *i_pubkey_hash, + unsigned int neg_freq) { struct wpabuf *msg; u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1]; @@ -1362,6 +1363,8 @@ static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth, /* Build DPP Authentication Request frame attributes */ attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) + 4 + sizeof(wrapped_data); + if (neg_freq > 0) + attr_len += 4 + 2; #ifdef CONFIG_TESTING_OPTIONS if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) attr_len += 4; @@ -1393,6 +1396,25 @@ static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth, wpabuf_put_buf(msg, pi); } + /* Channel */ + if (neg_freq > 0) { + u8 op_class, channel; + + if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class, + &channel) == + NUM_HOSTAPD_MODES) { + wpa_printf(MSG_INFO, + "DPP: Unsupported negotiation frequency request: %d", + neg_freq); + wpabuf_free(msg); + return NULL; + } + wpabuf_put_le16(msg, DPP_ATTR_CHANNEL); + wpabuf_put_le16(msg, 2); + wpabuf_put_u8(msg, op_class); + wpabuf_put_u8(msg, channel); + } + #ifdef CONFIG_TESTING_OPTIONS if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) { wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data"); @@ -1668,7 +1690,8 @@ skip_wrapped_data: struct dpp_authentication * dpp_auth_init(void *msg_ctx, struct dpp_bootstrap_info *peer_bi, struct dpp_bootstrap_info *own_bi, - int configurator) + int configurator, + unsigned int neg_freq) { struct dpp_authentication *auth; size_t nonce_len; @@ -1751,7 +1774,7 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx, #endif /* CONFIG_TESTING_OPTIONS */ auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash, - i_pubkey_hash); + i_pubkey_hash, neg_freq); if (!auth->req_msg) goto fail; @@ -2349,9 +2372,10 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, size_t len[2]; u8 *unwrapped = NULL; size_t unwrapped_len = 0; - const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap; + const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap, + *channel; u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len, - i_bootstrap_len; + i_bootstrap_len, channel_len; struct dpp_authentication *auth = NULL; wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, @@ -2374,6 +2398,34 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, auth->curve = own_bi->curve; auth->curr_freq = freq; + channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL, + &channel_len); + if (channel) { + int neg_freq; + + if (channel_len < 2) { + dpp_auth_fail(auth, "Too short Channel attribute"); + goto fail; + } + + neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]); + wpa_printf(MSG_DEBUG, + "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d", + channel[0], channel[1], neg_freq); + if (neg_freq < 0) { + dpp_auth_fail(auth, + "Unsupported Channel attribute value"); + goto fail; + } + + if (auth->curr_freq != (unsigned int) neg_freq) { + wpa_printf(MSG_DEBUG, + "DPP: Changing negotiation channel from %u MHz to %u MHz", + freq, neg_freq); + auth->curr_freq = neg_freq; + } + } + i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY, &i_proto_len); if (!i_proto) { diff --git a/src/common/dpp.h b/src/common/dpp.h index 905d1f138..a86b5787b 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -52,6 +52,8 @@ enum dpp_attribute_id { DPP_ATTR_ENROLLEE_NONCE = 0x1014, DPP_ATTR_CODE_IDENTIFIER = 0x1015, DPP_ATTR_TRANSACTION_ID = 0x1016, + DPP_ATTR_BOOTSTRAP_INFO = 0x1017, + DPP_ATTR_CHANNEL = 0x1018, DPP_ATTR_TESTING = 0x10ff, /* not defined in the DPP tech spec */ }; @@ -159,6 +161,7 @@ struct dpp_authentication { struct wpabuf *req_msg; struct wpabuf *resp_msg; unsigned int curr_freq; + unsigned int neg_freq; size_t secret_len; u8 Mx[DPP_MAX_SHARED_SECRET_LEN]; u8 Nx[DPP_MAX_SHARED_SECRET_LEN]; @@ -260,7 +263,8 @@ char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve, struct dpp_authentication * dpp_auth_init(void *msg_ctx, struct dpp_bootstrap_info *peer_bi, struct dpp_bootstrap_info *own_bi, - int configurator); + int configurator, + unsigned int neg_freq); struct dpp_authentication * dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, struct dpp_bootstrap_info *peer_bi, diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index 874b90992..1d920b487 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -340,18 +340,32 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s, /* TODO: In case of DPP Authentication Request frame, move to * the next channel immediately */ } + + if (!wpa_s->dpp_auth_ok_on_ack && wpa_s->dpp_auth->neg_freq > 0 && + wpa_s->dpp_auth->curr_freq != wpa_s->dpp_auth->neg_freq) { + wpa_printf(MSG_DEBUG, + "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response", + wpa_s->dpp_auth->curr_freq, + wpa_s->dpp_auth->neg_freq); + offchannel_send_action_done(wpa_s); + wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->neg_freq); + } } static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; + unsigned int freq; if (!wpa_s->dpp_auth) return; + freq = wpa_s->dpp_auth->curr_freq; + if (wpa_s->dpp_auth->neg_freq > 0) + freq = wpa_s->dpp_auth->neg_freq; wpa_printf(MSG_DEBUG, "DPP: Continue reply wait on channel %u MHz", - wpa_s->dpp_auth->curr_freq); - wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->curr_freq); + freq); + wpas_dpp_listen_start(wpa_s, freq); } @@ -510,6 +524,7 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd) int res; int configurator = 1; unsigned int wait_time; + unsigned int neg_freq = 0; wpa_s->dpp_gas_client = 0; @@ -559,12 +574,17 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd) wpa_s->dpp_netrole_ap = os_strncmp(pos, "ap", 2) == 0; } + pos = os_strstr(cmd, " neg_freq="); + if (pos) + neg_freq = atoi(pos + 10); + if (wpa_s->dpp_auth) { eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); offchannel_send_action_done(wpa_s); dpp_auth_deinit(wpa_s->dpp_auth); } - wpa_s->dpp_auth = dpp_auth_init(wpa_s, peer_bi, own_bi, configurator); + wpa_s->dpp_auth = dpp_auth_init(wpa_s, peer_bi, own_bi, configurator, + neg_freq); if (!wpa_s->dpp_auth) goto fail; wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth); @@ -577,6 +597,7 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd) wpa_s->dpp_auth->curr_freq = peer_bi->freq[0]; else wpa_s->dpp_auth->curr_freq = 2412; + wpa_s->dpp_auth->neg_freq = neg_freq; if (is_zero_ether_addr(peer_bi->mac_addr)) { dst = broadcast; @@ -593,6 +614,12 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd) eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000, wpas_dpp_reply_wait_timeout, wpa_s, NULL); + if (neg_freq > 0 && wpa_s->dpp_auth->curr_freq != neg_freq) { + wpa_printf(MSG_DEBUG, + "DPP: Initiate on curr_freq %u MHz and move to neg_freq %u MHz for response", + wpa_s->dpp_auth->curr_freq, + wpa_s->dpp_auth->neg_freq); + } wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", MAC2STR(dst), wpa_s->dpp_auth->curr_freq, DPP_PA_AUTHENTICATION_REQ); @@ -864,6 +891,14 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src, wpa_s->dpp_configurator_params); os_memcpy(wpa_s->dpp_auth->peer_mac_addr, src, ETH_ALEN); + if (wpa_s->dpp_listen_freq && + wpa_s->dpp_listen_freq != wpa_s->dpp_auth->curr_freq) { + wpa_printf(MSG_DEBUG, + "DPP: Stop listen on %u MHz to allow response on the request %u MHz", + wpa_s->dpp_listen_freq, wpa_s->dpp_auth->curr_freq); + wpas_dpp_listen_stop(wpa_s); + } + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", MAC2STR(src), wpa_s->dpp_auth->curr_freq, DPP_PA_AUTHENTICATION_RESP); @@ -1161,13 +1196,14 @@ static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator) static void wpas_dpp_rx_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src, - const u8 *hdr, const u8 *buf, size_t len) + const u8 *hdr, const u8 *buf, size_t len, + unsigned int freq) { struct dpp_authentication *auth = wpa_s->dpp_auth; struct wpabuf *msg; - wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR, - MAC2STR(src)); + wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR + " (freq %u MHz)", MAC2STR(src), freq); if (!auth) { wpa_printf(MSG_DEBUG, @@ -1184,6 +1220,12 @@ static void wpas_dpp_rx_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src, eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); + if (auth->curr_freq != freq && auth->neg_freq == freq) { + wpa_printf(MSG_DEBUG, + "DPP: Responder accepted request for different negotiation channel"); + auth->curr_freq = freq; + } + msg = dpp_auth_resp_rx(auth, hdr, buf, len); if (!msg) { if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) { @@ -1641,7 +1683,7 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, wpas_dpp_rx_auth_req(wpa_s, src, hdr, buf, len, freq); break; case DPP_PA_AUTHENTICATION_RESP: - wpas_dpp_rx_auth_resp(wpa_s, src, hdr, buf, len); + wpas_dpp_rx_auth_resp(wpa_s, src, hdr, buf, len, freq); break; case DPP_PA_AUTHENTICATION_CONF: wpas_dpp_rx_auth_conf(wpa_s, src, hdr, buf, len);