From 5e287724ee32c036efa5376490de5b18057d7b43 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 27 Jan 2020 17:04:26 +0200 Subject: [PATCH] DPP: NFC negotiated connection handover Add new control interface commands "DPP_NFC_HANDOVER_REQ own= uri=" and "DPP_NFC_HANDOVER_SEL own= uri=" to support NFC negotiated connection handover. These commands are used to report a DPP URI received from a peer NFC Device in Handover Request and Handover Select messages. The commands return peer bootstrapping information ID or FAIL on failure. The returned ID is used similarly to any other bootstrapping information to initiate DPP authentication. Signed-off-by: Jouni Malinen --- hostapd/ctrl_iface.c | 18 ++++++++ src/ap/dpp_hostapd.c | 67 ++++++++++++++++++++++++++- src/ap/dpp_hostapd.h | 4 +- src/common/dpp.c | 82 +++++++++++++++++++++++++++++++++ src/common/dpp.h | 2 + wpa_supplicant/ctrl_iface.c | 22 +++++++++ wpa_supplicant/dpp_supplicant.c | 67 ++++++++++++++++++++++++++- wpa_supplicant/dpp_supplicant.h | 4 +- 8 files changed, 262 insertions(+), 4 deletions(-) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 5eef75bf7..090d4f0f6 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -3372,6 +3372,24 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, if (os_snprintf_error(reply_size, reply_len)) reply_len = -1; } + } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_REQ ", 21) == 0) { + res = hostapd_dpp_nfc_handover_req(hapd, buf + 20); + if (res < 0) { + reply_len = -1; + } else { + reply_len = os_snprintf(reply, reply_size, "%d", res); + if (os_snprintf_error(reply_size, reply_len)) + reply_len = -1; + } + } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_SEL ", 21) == 0) { + res = hostapd_dpp_nfc_handover_sel(hapd, buf + 20); + if (res < 0) { + reply_len = -1; + } else { + reply_len = os_snprintf(reply, reply_size, "%d", res); + if (os_snprintf_error(reply_size, reply_len)) + reply_len = -1; + } } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) { res = dpp_bootstrap_gen(hapd->iface->interfaces->dpp, buf + 18); if (res < 0) { diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index 1a3a815cb..48922516f 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -1,7 +1,7 @@ /* * hostapd / DPP integration * Copyright (c) 2017, Qualcomm Atheros, Inc. - * Copyright (c) 2018-2019, The Linux Foundation + * Copyright (c) 2018-2020, The Linux Foundation * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -81,6 +81,71 @@ int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd) } +int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd) +{ + const char *pos; + struct dpp_bootstrap_info *peer_bi, *own_bi; + + pos = os_strstr(cmd, " own="); + if (!pos) + return -1; + pos += 5; + own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos)); + if (!own_bi) + return -1; + + pos = os_strstr(cmd, " uri="); + if (!pos) + return -1; + pos += 5; + peer_bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, pos); + if (!peer_bi) { + wpa_printf(MSG_INFO, + "DPP: Failed to parse URI from NFC Handover Request"); + return -1; + } + + if (dpp_nfc_update_bi(own_bi, peer_bi) < 0) + return -1; + + return peer_bi->id; +} + + +int hostapd_dpp_nfc_handover_sel(struct hostapd_data *hapd, const char *cmd) +{ + const char *pos; + struct dpp_bootstrap_info *peer_bi, *own_bi; + + pos = os_strstr(cmd, " own="); + if (!pos) + return -1; + pos += 5; + own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos)); + if (!own_bi) + return -1; + + pos = os_strstr(cmd, " uri="); + if (!pos) + return -1; + pos += 5; + peer_bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, pos); + if (!peer_bi) { + wpa_printf(MSG_INFO, + "DPP: Failed to parse URI from NFC Handover Select"); + return -1; + } + + if (peer_bi->curve != own_bi->curve) { + wpa_printf(MSG_INFO, + "DPP: Peer (NFC Handover Selector) used different curve"); + return -1; + } + + return peer_bi->id; +} + + static void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx) { diff --git a/src/ap/dpp_hostapd.h b/src/ap/dpp_hostapd.h index e151c2fc6..b1fa99ed0 100644 --- a/src/ap/dpp_hostapd.h +++ b/src/ap/dpp_hostapd.h @@ -1,7 +1,7 @@ /* * hostapd / DPP integration * Copyright (c) 2017, Qualcomm Atheros, Inc. - * Copyright (c) 2018-2019, The Linux Foundation + * Copyright (c) 2018-2020, The Linux Foundation * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -12,6 +12,8 @@ int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd); int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd); +int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd); +int hostapd_dpp_nfc_handover_sel(struct hostapd_data *hapd, const char *cmd); int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd); int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd); void hostapd_dpp_listen_stop(struct hostapd_data *hapd); diff --git a/src/common/dpp.c b/src/common/dpp.c index 4b36c1efc..4a0bdf06e 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -9216,6 +9216,88 @@ void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap, } +static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi, + struct dpp_bootstrap_info *peer_bi) +{ + unsigned int i, freq = 0; + enum hostapd_hw_mode mode; + u8 op_class, channel; + char chan[20]; + + if (peer_bi->num_freq == 0) + return 0; /* no channel preference/constraint */ + + for (i = 0; i < peer_bi->num_freq; i++) { + if (own_bi->num_freq == 0 || + freq_included(own_bi->freq, own_bi->num_freq, + peer_bi->freq[i])) { + freq = peer_bi->freq[i]; + break; + } + } + if (!freq) { + wpa_printf(MSG_DEBUG, "DPP: No common channel found"); + return -1; + } + + mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel); + if (mode == NUM_HOSTAPD_MODES) { + wpa_printf(MSG_DEBUG, + "DPP: Could not determine operating class or channel number for %u MHz", + freq); + } + + wpa_printf(MSG_DEBUG, + "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover", + freq, op_class, channel); + os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel); + os_free(own_bi->chan); + own_bi->chan = os_strdup(chan); + own_bi->freq[0] = freq; + own_bi->num_freq = 1; + os_free(peer_bi->chan); + peer_bi->chan = os_strdup(chan); + peer_bi->freq[0] = freq; + peer_bi->num_freq = 1; + + return dpp_gen_uri(own_bi); +} + + +static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi, + struct dpp_bootstrap_info *peer_bi) +{ + if (peer_bi->curve == own_bi->curve) + return 0; + + wpa_printf(MSG_DEBUG, + "DPP: Update own bootstrapping key to match peer curve from NFC handover"); + + EVP_PKEY_free(own_bi->pubkey); + own_bi->pubkey = NULL; + + if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 || + dpp_gen_uri(own_bi) < 0) + goto fail; + + return 0; +fail: + dl_list_del(&own_bi->list); + dpp_bootstrap_info_free(own_bi); + return -1; +} + + +int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi, + struct dpp_bootstrap_info *peer_bi) +{ + if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 || + dpp_nfc_update_bi_key(own_bi, peer_bi) < 0) + return -1; + return 0; +} + + static unsigned int dpp_next_configurator_id(struct dpp_global *dpp) { struct dpp_configurator *conf; diff --git a/src/common/dpp.h b/src/common/dpp.h index 70d88b5dd..d59e5a426 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -418,6 +418,8 @@ int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi, const char *chan_list); int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac); int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info); +int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi, + struct dpp_bootstrap_info *peer_bi); struct hostapd_hw_modes; struct dpp_authentication * dpp_auth_init(void *msg_ctx, struct dpp_bootstrap_info *peer_bi, diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 65dcb90f1..8d75c80b2 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -10811,6 +10811,28 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (os_snprintf_error(reply_size, reply_len)) reply_len = -1; } + } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_REQ ", 21) == 0) { + int res; + + res = wpas_dpp_nfc_handover_req(wpa_s, buf + 20); + if (res < 0) { + reply_len = -1; + } else { + reply_len = os_snprintf(reply, reply_size, "%d", res); + if (os_snprintf_error(reply_size, reply_len)) + reply_len = -1; + } + } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_SEL ", 21) == 0) { + int res; + + res = wpas_dpp_nfc_handover_sel(wpa_s, buf + 20); + if (res < 0) { + reply_len = -1; + } else { + reply_len = os_snprintf(reply, reply_size, "%d", res); + if (os_snprintf_error(reply_size, reply_len)) + reply_len = -1; + } } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) { int res; diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index c01ff9498..f147afd9d 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -1,7 +1,7 @@ /* * wpa_supplicant - DPP * Copyright (c) 2017, Qualcomm Atheros, Inc. - * Copyright (c) 2018-2019, The Linux Foundation + * Copyright (c) 2018-2020, The Linux Foundation * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -106,6 +106,71 @@ int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd) } +int wpas_dpp_nfc_handover_req(struct wpa_supplicant *wpa_s, const char *cmd) +{ + const char *pos; + struct dpp_bootstrap_info *peer_bi, *own_bi; + + pos = os_strstr(cmd, " own="); + if (!pos) + return -1; + pos += 5; + own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos)); + if (!own_bi) + return -1; + + pos = os_strstr(cmd, " uri="); + if (!pos) + return -1; + pos += 5; + peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos); + if (!peer_bi) { + wpa_printf(MSG_INFO, + "DPP: Failed to parse URI from NFC Handover Request"); + return -1; + } + + if (dpp_nfc_update_bi(own_bi, peer_bi) < 0) + return -1; + + return peer_bi->id; +} + + +int wpas_dpp_nfc_handover_sel(struct wpa_supplicant *wpa_s, const char *cmd) +{ + const char *pos; + struct dpp_bootstrap_info *peer_bi, *own_bi; + + pos = os_strstr(cmd, " own="); + if (!pos) + return -1; + pos += 5; + own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos)); + if (!own_bi) + return -1; + + pos = os_strstr(cmd, " uri="); + if (!pos) + return -1; + pos += 5; + peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos); + if (!peer_bi) { + wpa_printf(MSG_INFO, + "DPP: Failed to parse URI from NFC Handover Select"); + return -1; + } + + if (peer_bi->curve != own_bi->curve) { + wpa_printf(MSG_INFO, + "DPP: Peer (NFC Handover Selector) used different curve"); + return -1; + } + + return peer_bi->id; +} + + static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h index 607036a38..5c3397a24 100644 --- a/wpa_supplicant/dpp_supplicant.h +++ b/wpa_supplicant/dpp_supplicant.h @@ -1,7 +1,7 @@ /* * wpa_supplicant - DPP * Copyright (c) 2017, Qualcomm Atheros, Inc. - * Copyright (c) 2018-2019, The Linux Foundation + * Copyright (c) 2018-2020, The Linux Foundation * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -14,6 +14,8 @@ enum dpp_status_error; int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd); int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd); +int wpas_dpp_nfc_handover_req(struct wpa_supplicant *wpa_s, const char *cmd); +int wpas_dpp_nfc_handover_sel(struct wpa_supplicant *wpa_s, const char *cmd); int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd); int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd); void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s);