Add support to use a push button -based bootstrap mechanism with DPP.
The new DPP_PUSH_BUTTON control interface command enables this mode on
the AP/hostapd and station/wpa_supplicant. This goes through the
following sequence of events: a suitable peer in active push button mode
is discovered with session overlap detection, PKEX is executed with
bootstrap key hash validation, DPP authentication and configuration
exchanges are performed.
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
} else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
hostapd_dpp_chirp_stop(hapd);
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ } else if (os_strcmp(buf, "DPP_PUSH_BUTTON") == 0) {
+ if (hostapd_dpp_push_button(hapd) < 0)
+ reply_len = -1;
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
#ifdef RADIUS_SERVER
} else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) {
#ifdef CONFIG_DPP
dpp_global_clear(interfaces->dpp);
+#ifdef CONFIG_DPP3
+ {
+ int i;
+
+ for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
+ struct dpp_pb_info *info;
+
+ info = &interfaces->dpp_pb[i];
+ info->rx_time.sec = 0;
+ info->rx_time.usec = 0;
+ }
+ }
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
}
}
#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_DPP3
+static int hostapd_cli_cmd_dpp_push_button(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_PUSH_BUTTON");
+}
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
{ "dpp_stop_chirp", hostapd_cli_cmd_dpp_stop_chirp, NULL,
"= stop DPP chirp" },
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ { "dpp_push_button", hostapd_cli_cmd_dpp_push_button, NULL,
+ "= press DPP push button" },
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
{ "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
"=Add/Delete/Show/Clear accept MAC ACL" },
#include "common/dpp.h"
#include "common/gas.h"
#include "common/wpa_ctrl.h"
+#include "crypto/random.h"
#include "hostapd.h"
#include "ap_drv_ops.h"
#include "gas_query_ap.h"
hapd->dpp_pkex = NULL;
pkex = dpp_pkex_init(hapd->msg_ctx, hapd->dpp_pkex_bi, hapd->own_addr,
hapd->dpp_pkex_identifier,
- hapd->dpp_pkex_code, v2);
+ hapd->dpp_pkex_code, hapd->dpp_pkex_code_len, v2);
if (!pkex)
return -1;
pkex->forced_ver = ver != PKEX_VER_AUTO;
}
+#ifdef CONFIG_DPP3
+
+static bool hostapd_dpp_pb_active(struct hostapd_data *hapd)
+{
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+
+ return ifaces && (ifaces->dpp_pb_time.sec ||
+ ifaces->dpp_pb_time.usec);
+}
+
+
+static void hostapd_dpp_remove_pb_hash(struct hostapd_data *hapd)
+{
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+ int i;
+
+ if (!ifaces->dpp_pb_bi)
+ return;
+ for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
+ struct dpp_pb_info *info = &ifaces->dpp_pb[i];
+
+ if (info->rx_time.sec == 0 && info->rx_time.usec == 0)
+ continue;
+ if (os_memcmp(info->hash, ifaces->dpp_pb_resp_hash,
+ SHA256_MAC_LEN) == 0) {
+ /* Allow a new push button session to be established
+ * immediately without the successfully completed
+ * session triggering session overlap. */
+ info->rx_time.sec = 0;
+ info->rx_time.usec = 0;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Removed PB hash from session overlap detection due to successfully completed provisioning");
+ }
+ }
+}
+
+#endif /* CONFIG_DPP3 */
+
+
static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len)
{
struct dpp_authentication *auth = hapd->dpp_auth;
enum dpp_status_error status;
+#ifdef CONFIG_DPP3
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+#endif /* CONFIG_DPP3 */
wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
MAC2STR(src));
hapd->dpp_auth = NULL;
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
NULL);
+#ifdef CONFIG_DPP3
+ if (!ifaces->dpp_pb_result_indicated && hostapd_dpp_pb_active(hapd)) {
+ if (status == DPP_STATUS_OK)
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PB_RESULT
+ "success");
+ else
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PB_RESULT
+ "no-configuration-available");
+ ifaces->dpp_pb_result_indicated = true;
+ if (status == DPP_STATUS_OK)
+ hostapd_dpp_remove_pb_hash(hapd);
+ hostapd_dpp_push_button_stop(hapd);
+ }
+#endif /* CONFIG_DPP3 */
}
hapd->own_addr, src,
hapd->dpp_pkex_identifier,
hapd->dpp_pkex_code,
+ hapd->dpp_pkex_code_len,
buf, len, v2);
if (!hapd->dpp_pkex) {
wpa_printf(MSG_DEBUG,
const u8 *hdr, const u8 *buf, size_t len,
unsigned int freq)
{
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
int res;
struct dpp_bootstrap_info *bi;
struct dpp_pkex *pkex = hapd->dpp_pkex;
return;
}
- bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
+ bi = dpp_pkex_finish(ifaces->dpp, pkex, src, freq);
if (!bi)
return;
hapd->dpp_pkex = NULL;
+#ifdef CONFIG_DPP3
+ if (ifaces->dpp_pb_bi &&
+ os_memcmp(bi->pubkey_hash_chirp, ifaces->dpp_pb_resp_hash,
+ SHA256_MAC_LEN) != 0) {
+ char id[20];
+
+ wpa_printf(MSG_INFO,
+ "DPP: Peer bootstrap key from PKEX does not match PB announcement hash");
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Peer provided bootstrap key hash(chirp) from PB PKEX",
+ bi->pubkey_hash_chirp, SHA256_MAC_LEN);
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Peer provided bootstrap key hash(chirp) from PB announcement",
+ ifaces->dpp_pb_resp_hash, SHA256_MAC_LEN);
+
+ os_snprintf(id, sizeof(id), "%u", bi->id);
+ dpp_bootstrap_remove(ifaces->dpp, id);
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+#endif /* CONFIG_DPP3 */
+
os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
bi->id,
hapd->dpp_pkex_auth_cmd ? hapd->dpp_pkex_auth_cmd : "");
}
+#ifdef CONFIG_DPP3
+
+static void hostapd_dpp_pb_pkex_init(struct hostapd_data *hapd,
+ unsigned int freq, const u8 *src,
+ const u8 *r_hash)
+{
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+ struct dpp_pkex *pkex;
+ struct wpabuf *msg;
+ char ssid_hex[2 * SSID_MAX_LEN + 1], *pass_hex = NULL;
+ char cmd[300];
+ const char *password = NULL;
+ struct sae_password_entry *e;
+ int conf_id = -1;
+ bool sae = false, psk = false;
+
+ if (hapd->dpp_pkex) {
+ wpa_printf(MSG_DEBUG,
+ "PDP: Sending previously generated PKEX Exchange Request to "
+ MACSTR, MAC2STR(src));
+ msg = hapd->dpp_pkex->exchange_req;
+ hostapd_drv_send_action(hapd, freq, 0, src,
+ wpabuf_head(msg), wpabuf_len(msg));
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Initiate PKEX for push button with "
+ MACSTR, MAC2STR(src));
+
+ hapd->dpp_pkex_bi = ifaces->dpp_pb_bi;
+ os_memcpy(ifaces->dpp_pb_resp_hash, r_hash, SHA256_MAC_LEN);
+
+ pkex = dpp_pkex_init(hapd->msg_ctx, hapd->dpp_pkex_bi, hapd->own_addr,
+ "PBPKEX", (const char *) ifaces->dpp_pb_c_nonce,
+ ifaces->dpp_pb_bi->curve->nonce_len,
+ true);
+ if (!pkex) {
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+ pkex->freq = freq;
+
+ hapd->dpp_pkex = pkex;
+ msg = hapd->dpp_pkex->exchange_req;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), freq,
+ DPP_PA_PKEX_EXCHANGE_REQ);
+ hostapd_drv_send_action(hapd, pkex->freq, 0, src,
+ wpabuf_head(msg), wpabuf_len(msg));
+ pkex->exch_req_wait_time = 2000;
+ pkex->exch_req_tries = 1;
+
+ wpa_snprintf_hex(ssid_hex, sizeof(ssid_hex),
+ (const u8 *) hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len);
+
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) {
+ /* TODO: If a local Configurator has been enabled, allow a
+ * DPP AKM credential to be provisioned by setting conf_id. */
+ }
+
+ if (hapd->conf->wpa & WPA_PROTO_RSN) {
+ psk = hapd->conf->wpa_key_mgmt & (WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256);
+#ifdef CONFIG_SAE
+ sae = hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE;
+#endif /* CONFIG_SAE */
+ }
+
+#ifdef CONFIG_SAE
+ for (e = hapd->conf->sae_passwords; sae && e && !password;
+ e = e->next) {
+ if (e->identifier || !is_broadcast_ether_addr(e->peer_addr))
+ continue;
+ password = e->password;
+ }
+#endif /* CONFIG_SAE */
+ if (!password && hapd->conf->ssid.wpa_passphrase_set &&
+ hapd->conf->ssid.wpa_passphrase)
+ password = hapd->conf->ssid.wpa_passphrase;
+ if (password) {
+ size_t len = 2 * os_strlen(password) + 1;
+
+ pass_hex = os_malloc(len);
+ if (!pass_hex) {
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+ wpa_snprintf_hex(pass_hex, len, (const u8 *) password,
+ os_strlen(password));
+ }
+
+ if (conf_id > 0 && sae && psk && pass_hex) {
+ os_snprintf(cmd, sizeof(cmd),
+ "conf=sta-dpp+psk+sae configurator=%d ssid=%s pass=%s",
+ conf_id, ssid_hex, pass_hex);
+ } else if (conf_id > 0 && sae && pass_hex) {
+ os_snprintf(cmd, sizeof(cmd),
+ "conf=sta-dpp+sae configurator=%d ssid=%s pass=%s",
+ conf_id, ssid_hex, pass_hex);
+ } else if (conf_id > 0) {
+ os_snprintf(cmd, sizeof(cmd),
+ "conf=sta-dpp configurator=%d ssid=%s",
+ conf_id, ssid_hex);
+ } if (sae && psk && pass_hex) {
+ os_snprintf(cmd, sizeof(cmd),
+ "conf=sta-psk+sae ssid=%s pass=%s",
+ ssid_hex, pass_hex);
+ } else if (sae && pass_hex) {
+ os_snprintf(cmd, sizeof(cmd),
+ "conf=sta-sae ssid=%s pass=%s",
+ ssid_hex, pass_hex);
+ } else if (psk && pass_hex) {
+ os_snprintf(cmd, sizeof(cmd),
+ "conf=sta-psk ssid=%s pass=%s",
+ ssid_hex, pass_hex);
+ } else {
+ wpa_printf(MSG_INFO,
+ "DPP: Unsupported AP configuration for push button");
+ str_clear_free(pass_hex);
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+ str_clear_free(pass_hex);
+
+ os_free(hapd->dpp_pkex_auth_cmd);
+ hapd->dpp_pkex_auth_cmd = os_strdup(cmd);
+ forced_memzero(cmd, sizeof(cmd));
+ if (!hapd->dpp_pkex_auth_cmd) {
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+}
+
+
+static void
+hostapd_dpp_rx_pb_presence_announcement(struct hostapd_data *hapd,
+ const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+ const u8 *r_hash;
+ u16 r_hash_len;
+ unsigned int i;
+ bool found = false;
+ struct dpp_pb_info *info, *tmp;
+ struct os_reltime now, age;
+ struct wpabuf *msg;
+
+ if (!ifaces)
+ return;
+
+ os_get_reltime(&now);
+ wpa_printf(MSG_DEBUG, "DPP: Push Button Presence Announcement from "
+ MACSTR, MAC2STR(src));
+
+ r_hash = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_hash_len);
+ if (!r_hash || r_hash_len != SHA256_MAC_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_hash, r_hash_len);
+
+ for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
+ info = &ifaces->dpp_pb[i];
+ if ((info->rx_time.sec == 0 && info->rx_time.usec == 0) ||
+ os_memcmp(r_hash, info->hash, SHA256_MAC_LEN) != 0)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Active push button Enrollee already known");
+ found = true;
+ info->rx_time = now;
+ }
+
+ if (!found) {
+ for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
+ tmp = &ifaces->dpp_pb[i];
+ if (tmp->rx_time.sec == 0 && tmp->rx_time.usec == 0)
+ continue;
+
+ if (os_reltime_expired(&now, &tmp->rx_time, 120)) {
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Push button Enrollee hash expired",
+ tmp->hash, SHA256_MAC_LEN);
+ tmp->rx_time.sec = 0;
+ tmp->rx_time.usec = 0;
+ continue;
+ }
+
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Push button session overlap with hash",
+ tmp->hash, SHA256_MAC_LEN);
+ if (!ifaces->dpp_pb_result_indicated &&
+ hostapd_dpp_pb_active(hapd)) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_PB_RESULT "session-overlap");
+ ifaces->dpp_pb_result_indicated = true;
+ }
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+
+ /* Replace the oldest entry */
+ info = &ifaces->dpp_pb[0];
+ for (i = 1; i < DPP_PB_INFO_COUNT; i++) {
+ tmp = &ifaces->dpp_pb[i];
+ if (os_reltime_before(&tmp->rx_time, &info->rx_time))
+ info = tmp;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: New active push button Enrollee");
+ os_memcpy(info->hash, r_hash, SHA256_MAC_LEN);
+ info->rx_time = now;
+ }
+
+ if (!hostapd_dpp_pb_active(hapd)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Discard message since own push button has not been pressed");
+ return;
+ }
+
+ if (ifaces->dpp_pb_announce_time.sec == 0 &&
+ ifaces->dpp_pb_announce_time.usec == 0) {
+ /* Start a wait before allowing PKEX to be initiated */
+ ifaces->dpp_pb_announce_time = now;
+ }
+
+ if (!ifaces->dpp_pb_bi) {
+ int res;
+
+ res = dpp_bootstrap_gen(ifaces->dpp, "type=pkex");
+ if (res < 0)
+ return;
+ ifaces->dpp_pb_bi = dpp_bootstrap_get_id(ifaces->dpp, res);
+ if (!ifaces->dpp_pb_bi)
+ return;
+
+ if (random_get_bytes(ifaces->dpp_pb_c_nonce,
+ ifaces->dpp_pb_bi->curve->nonce_len)) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to generate C-nonce");
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+ }
+
+ /* Skip the response if one was sent within last 50 ms since the
+ * Enrollee is going to send out at least three announcement messages.
+ */
+ os_reltime_sub(&now, &ifaces->dpp_pb_last_resp, &age);
+ if (age.sec == 0 && age.usec < 50000) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Skip Push Button Presence Announcement Response frame immediately after having sent one");
+ return;
+ }
+
+ msg = dpp_build_pb_announcement_resp(
+ ifaces->dpp_pb_bi, r_hash, ifaces->dpp_pb_c_nonce,
+ ifaces->dpp_pb_bi->curve->nonce_len);
+ if (!msg) {
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Send Push Button Presence Announcement Response to "
+ MACSTR, MAC2STR(src));
+ ifaces->dpp_pb_last_resp = now;
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), freq,
+ DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP);
+ hostapd_drv_send_action(hapd, freq, 0, src,
+ wpabuf_head(msg), wpabuf_len(msg));
+ wpabuf_free(msg);
+
+ if (os_reltime_expired(&now, &ifaces->dpp_pb_announce_time, 15))
+ hostapd_dpp_pb_pkex_init(hapd, freq, src, r_hash);
+}
+
+#endif /* CONFIG_DPP3 */
+
+
void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
const u8 *buf, size_t len, unsigned int freq)
{
freq);
break;
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ case DPP_PA_PB_PRESENCE_ANNOUNCEMENT:
+ hostapd_dpp_rx_pb_presence_announcement(hapd, src, hdr,
+ buf, len, freq);
+ break;
+#endif /* CONFIG_DPP3 */
default:
wpa_printf(MSG_DEBUG,
"DPP: Ignored unsupported frame subtype %d", type);
void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
{
struct dpp_authentication *auth = hapd->dpp_auth;
+#ifdef CONFIG_DPP3
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+#endif /* CONFIG_DPP3 */
if (!auth)
return;
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
+#ifdef CONFIG_DPP3
+ if (!ifaces->dpp_pb_result_indicated && hostapd_dpp_pb_active(hapd)) {
+ if (ok)
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PB_RESULT
+ "success");
+ else
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PB_RESULT
+ "could-not-connect");
+ ifaces->dpp_pb_result_indicated = true;
+ if (ok)
+ hostapd_dpp_remove_pb_hash(hapd);
+ hostapd_dpp_push_button_stop(hapd);
+ }
+#endif /* CONFIG_DPP3 */
}
hapd->dpp_pkex_code = os_strdup(pos + 6);
if (!hapd->dpp_pkex_code)
return -1;
+ hapd->dpp_pkex_code_len = os_strlen(hapd->dpp_pkex_code);
pos = os_strstr(cmd, " ver=");
if (pos) {
hapd->dpp_auth = NULL;
dpp_pkex_free(hapd->dpp_pkex);
hapd->dpp_pkex = NULL;
+#ifdef CONFIG_DPP3
+ hostapd_dpp_push_button_stop(hapd);
+#endif /* CONFIG_DPP3 */
}
#endif /* CONFIG_DPP2 */
#ifdef CONFIG_DPP3
eloop_cancel_timeout(hostapd_dpp_build_new_key, hapd, NULL);
+ hostapd_dpp_push_button_stop(hapd);
#endif /* CONFIG_DPP3 */
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
hapd->dpp_pkex = NULL;
os_free(hapd->dpp_configurator_params);
hapd->dpp_configurator_params = NULL;
+ os_free(hapd->dpp_pkex_auth_cmd);
+ hapd->dpp_pkex_auth_cmd = NULL;
}
}
#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_DPP3
+
+static void hostapd_dpp_push_button_expire(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "DPP: Active push button mode expired");
+ hostapd_dpp_push_button_stop(hapd);
+}
+
+
+int hostapd_dpp_push_button(struct hostapd_data *hapd)
+{
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+
+ if (!ifaces || !ifaces->dpp)
+ return -1;
+ os_get_reltime(&ifaces->dpp_pb_time);
+ ifaces->dpp_pb_announce_time.sec = 0;
+ ifaces->dpp_pb_announce_time.usec = 0;
+ eloop_register_timeout(100, 0, hostapd_dpp_push_button_expire,
+ hapd, NULL);
+
+ return 0;
+}
+
+
+void hostapd_dpp_push_button_stop(struct hostapd_data *hapd)
+{
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+
+ if (!ifaces || !ifaces->dpp)
+ return;
+ eloop_cancel_timeout(hostapd_dpp_push_button_expire, hapd, NULL);
+ if (hostapd_dpp_pb_active(hapd)) {
+ wpa_printf(MSG_DEBUG, "DPP: Stop active push button mode");
+ if (!ifaces->dpp_pb_result_indicated)
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_PB_RESULT "failed");
+ }
+ ifaces->dpp_pb_time.sec = 0;
+ ifaces->dpp_pb_time.usec = 0;
+ dpp_pkex_free(hapd->dpp_pkex);
+ hapd->dpp_pkex = NULL;
+ os_free(hapd->dpp_pkex_auth_cmd);
+ hapd->dpp_pkex_auth_cmd = NULL;
+
+ if (ifaces->dpp_pb_bi) {
+ char id[20];
+
+ os_snprintf(id, sizeof(id), "%u", ifaces->dpp_pb_bi->id);
+ dpp_bootstrap_remove(ifaces->dpp, id);
+ ifaces->dpp_pb_bi = NULL;
+ }
+
+ ifaces->dpp_pb_result_indicated = false;
+}
+
+#endif /* CONFIG_DPP3 */
int hostapd_dpp_chirp(struct hostapd_data *hapd, const char *cmd);
void hostapd_dpp_chirp_stop(struct hostapd_data *hapd);
void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi);
+int hostapd_dpp_push_button(struct hostapd_data *hapd);
+void hostapd_dpp_push_button_stop(struct hostapd_data *hapd);
#endif /* DPP_HOSTAPD_H */
#define CTRL_IFACE_COOKIE_LEN 8
#endif /* CONFIG_CTRL_IFACE_UDP */
+#define DPP_PB_INFO_COUNT 2
+
+struct dpp_pb_info {
+ u8 hash[SHA256_MAC_LEN];
+ struct os_reltime rx_time;
+};
+
struct hostapd_iface;
struct hapd_interfaces {
#ifdef CONFIG_DPP
struct dpp_global *dpp;
+#ifdef CONFIG_DPP3
+ struct os_reltime dpp_pb_time;
+ struct os_reltime dpp_pb_announce_time;
+ struct dpp_pb_info dpp_pb[DPP_PB_INFO_COUNT];
+ struct dpp_bootstrap_info *dpp_pb_bi;
+ u8 dpp_pb_c_nonce[DPP_MAX_NONCE_LEN];
+ u8 dpp_pb_resp_hash[SHA256_MAC_LEN];
+ struct os_reltime dpp_pb_last_resp;
+ bool dpp_pb_result_indicated;
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
#ifdef CONFIG_CTRL_IFACE_UDP
struct dpp_pkex *dpp_pkex;
struct dpp_bootstrap_info *dpp_pkex_bi;
char *dpp_pkex_code;
+ size_t dpp_pkex_code_len;
char *dpp_pkex_identifier;
enum dpp_pkex_ver dpp_pkex_ver;
char *dpp_pkex_auth_cmd;
}
#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_DPP3
+
+struct wpabuf * dpp_build_pb_announcement(struct dpp_bootstrap_info *bi)
+{
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Build Push Button Presence Announcement frame");
+
+ msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT,
+ 4 + SHA256_MAC_LEN);
+ if (!msg)
+ return NULL;
+
+ /* Responder Bootstrapping Key Hash */
+ dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Push Button Presence Announcement frame attributes",
+ msg);
+ return msg;
+}
+
+
+struct wpabuf * dpp_build_pb_announcement_resp(struct dpp_bootstrap_info *bi,
+ const u8 *e_hash,
+ const u8 *c_nonce,
+ size_t c_nonce_len)
+{
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Build Push Button Presence Announcement Response frame");
+
+ msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP,
+ 2 * (4 + SHA256_MAC_LEN) + 4 + c_nonce_len);
+ if (!msg)
+ return NULL;
+
+ /* Initiator Bootstrapping Key Hash */
+ wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
+ wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
+ wpabuf_put_le16(msg, SHA256_MAC_LEN);
+ wpabuf_put_data(msg, bi->pubkey_hash_chirp, SHA256_MAC_LEN);
+
+ /* Responder Bootstrapping Key Hash */
+ dpp_build_attr_r_bootstrap_key_hash(msg, e_hash);
+
+ /* Configurator Nonce */
+ wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE);
+ wpabuf_put_le16(msg, c_nonce_len);
+ wpabuf_put_data(msg, c_nonce, c_nonce_len);
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Push Button Presence Announcement Response frame attributes",
+ msg);
+ return msg;
+}
+
+#endif /* CONFIG_DPP3 */
DPP_PA_RECONFIG_AUTH_RESP = 16,
DPP_PA_RECONFIG_AUTH_CONF = 17,
DPP_PA_PKEX_EXCHANGE_REQ = 18,
+ DPP_PA_PB_PRESENCE_ANNOUNCEMENT = 19,
+ DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP = 20,
};
enum dpp_attribute_id {
u8 peer_mac[ETH_ALEN];
char *identifier;
char *code;
+ size_t code_len;
struct crypto_ec_key *x;
struct crypto_ec_key *y;
u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
const u8 *own_mac,
const char *identifier, const char *code,
- bool v2);
+ size_t code_len, bool v2);
struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
struct dpp_bootstrap_info *bi,
const u8 *own_mac,
const u8 *peer_mac,
const char *identifier,
- const char *code,
+ const char *code, size_t code_len,
const u8 *buf, size_t len, bool v2);
struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
const u8 *peer_mac,
void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
unsigned int freq, const u8 *hash);
+struct wpabuf * dpp_build_pb_announcement(struct dpp_bootstrap_info *bi);
+struct wpabuf * dpp_build_pb_announcement_resp(struct dpp_bootstrap_info *bi,
+ const u8 *e_hash,
+ const u8 *c_nonce,
+ size_t c_nonce_len);
+
struct dpp_global_config {
void *cb_ctx;
void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
struct crypto_ec_point *
dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
- const char *code, const char *identifier,
+ const char *code, size_t code_len, const char *identifier,
struct crypto_ec **ret_ec)
{
u8 hash[DPP_MAX_HASH_LEN];
len[num_elem] = os_strlen(identifier);
num_elem++;
}
- wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
+ wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, code_len);
addr[num_elem] = (const u8 *) code;
- len[num_elem] = os_strlen(code);
+ len[num_elem] = code_len;
num_elem++;
if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
goto fail;
struct crypto_ec_point *
dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
- const char *code, const char *identifier,
+ const char *code, size_t code_len, const char *identifier,
struct crypto_ec **ret_ec)
{
u8 hash[DPP_MAX_HASH_LEN];
len[num_elem] = os_strlen(identifier);
num_elem++;
}
- wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
+ wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, code_len);
addr[num_elem] = (const u8 *) code;
- len[num_elem] = os_strlen(code);
+ len[num_elem] = code_len;
num_elem++;
if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
goto fail;
u8 ver_init, u8 ver_resp,
const u8 *Mx, size_t Mx_len,
const u8 *Nx, size_t Nx_len,
- const char *code,
+ const char *code, size_t code_len,
const u8 *Kx, size_t Kx_len,
u8 *z, unsigned int hash_len)
{
info_len = 2 * ETH_ALEN;
else
info_len = 2;
- info_len += Mx_len + Nx_len + os_strlen(code);
+ info_len += Mx_len + Nx_len + code_len;
info = os_malloc(info_len);
if (!info)
return -1;
pos += Mx_len;
os_memcpy(pos, Nx, Nx_len);
pos += Nx_len;
- os_memcpy(pos, code, os_strlen(code));
+ os_memcpy(pos, code, code_len);
/* HKDF-Expand(PRK, info, L) */
if (hash_len == 32)
struct crypto_ec_key *peer_key, u8 *pmkid);
struct crypto_ec_point *
dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
- const char *code, const char *identifier,
+ const char *code, size_t code_len, const char *identifier,
struct crypto_ec **ret_ec);
struct crypto_ec_point *
dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
- const char *code, const char *identifier,
+ const char *code, size_t code_len, const char *identifier,
struct crypto_ec **ret_ec);
int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
u8 ver_init, u8 ver_resp,
const u8 *Mx, size_t Mx_len,
const u8 *Nx, size_t Nx_len,
- const char *code,
+ const char *code, size_t code_len,
const u8 *Kx, size_t Kx_len,
u8 *z, unsigned int hash_len);
int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
/* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : pkex->own_mac, pkex->code,
- pkex->identifier, &ec);
+ pkex->code_len, pkex->identifier, &ec);
if (!Qi)
goto fail;
struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
const u8 *own_mac,
const char *identifier, const char *code,
- bool v2)
+ size_t code_len, bool v2)
{
struct dpp_pkex *pkex;
if (!pkex->identifier)
goto fail;
}
- pkex->code = os_strdup(code);
+ pkex->code = os_memdup(code, code_len);
if (!pkex->code)
goto fail;
+ pkex->code_len = code_len;
pkex->exchange_req = dpp_pkex_build_exchange_req(pkex, v2);
if (!pkex->exchange_req)
goto fail;
const u8 *own_mac,
const u8 *peer_mac,
const char *identifier,
- const char *code,
+ const char *code, size_t code_len,
const u8 *buf, size_t len, bool v2)
{
const u8 *attr_group, *attr_id, *attr_key;
}
/* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
- Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, identifier,
- &ec);
+ Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, code_len,
+ identifier, &ec);
if (!Qi)
goto fail;
if (!pkex->identifier)
goto fail;
}
- pkex->code = os_strdup(code);
+ pkex->code = os_memdup(code, code_len);
if (!pkex->code)
goto fail;
+ pkex->code_len = code_len;
os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
goto fail;
/* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
- Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, identifier,
- NULL);
+ Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, code_len,
+ identifier, NULL);
if (!Qr)
goto fail;
pkex->peer_version, DPP_VERSION,
pkex->Mx, curve->prime_len,
pkex->Nx, curve->prime_len, pkex->code,
- Kx, Kx_len, pkex->z, curve->hash_len);
+ pkex->code_len, Kx, Kx_len, pkex->z,
+ curve->hash_len);
os_memset(Kx, 0, Kx_len);
if (res < 0)
goto fail;
/* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
Qr = dpp_pkex_derive_Qr(curve, pkex->v2 ? NULL : pkex->peer_mac,
- pkex->code, pkex->identifier, &ec);
+ pkex->code, pkex->code_len, pkex->identifier,
+ &ec);
if (!Qr)
goto fail;
DPP_VERSION, pkex->peer_version,
pkex->Mx, curve->prime_len,
attr_key /* N.x */, attr_key_len / 2,
- pkex->code, Kx, Kx_len,
+ pkex->code, pkex->code_len, Kx, Kx_len,
pkex->z, curve->hash_len);
os_memset(Kx, 0, Kx_len);
if (res < 0)
NULL, NULL,
ctrl->pkex_identifier,
ctrl->pkex_code,
+ os_strlen(ctrl->pkex_code),
buf, len, true);
if (!conn->pkex) {
wpa_printf(MSG_DEBUG,
#define DPP_EVENT_CSR "DPP-CSR "
#define DPP_EVENT_CHIRP_RX "DPP-CHIRP-RX "
#define DPP_EVENT_CONF_NEEDED "DPP-CONF-NEEDED "
+#define DPP_EVENT_PB_STATUS "DPP-PB-STATUS "
+#define DPP_EVENT_PB_RESULT "DPP-PB-RESULT "
/* MESH events */
#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
if (wpas_dpp_ca_set(wpa_s, buf + 10) < 0)
reply_len = -1;
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ } else if (os_strcmp(buf, "DPP_PUSH_BUTTON") == 0) {
+ if (wpas_dpp_push_button(wpa_s) < 0)
+ reply_len = -1;
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
} else if (os_strncmp(buf, "MSCS ", 5) == 0) {
if (wpas_ctrl_iface_configure_mscs(wpa_s, buf + 5))
conf->server_name);
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ if (!wpa_s->dpp_pb_result_indicated) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT "success");
+ wpa_s->dpp_pb_result_indicated = true;
+ }
+
+#endif /* CONFIG_DPP3 */
+
return wpas_dpp_process_config(wpa_s, auth, conf);
}
wpa_s->dpp_pkex = NULL;
pkex = dpp_pkex_init(wpa_s, wpa_s->dpp_pkex_bi, wpa_s->own_addr,
wpa_s->dpp_pkex_identifier,
- wpa_s->dpp_pkex_code, v2);
+ wpa_s->dpp_pkex_code, wpa_s->dpp_pkex_code_len,
+ v2);
if (!pkex)
return -1;
pkex->forced_ver = ver != PKEX_VER_AUTO;
wpa_s->own_addr, src,
wpa_s->dpp_pkex_identifier,
wpa_s->dpp_pkex_code,
+ wpa_s->dpp_pkex_code_len,
buf, len, v2);
if (!wpa_s->dpp_pkex) {
wpa_printf(MSG_DEBUG,
return;
}
+#ifdef CONFIG_DPP3
+ if (wpa_s->dpp_pb_bi && wpa_s->dpp_pb_announcement) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Started PB PKEX (no more PB announcements)");
+ wpabuf_free(wpa_s->dpp_pb_announcement);
+ wpa_s->dpp_pb_announcement = NULL;
+ }
+#endif /* CONFIG_DPP3 */
wpa_s->dpp_pkex_wait_auth_req = false;
msg = wpa_s->dpp_pkex->exchange_resp;
wait_time = wpa_s->max_remain_on_chan;
bi = dpp_pkex_finish(wpa_s->dpp, wpa_s->dpp_pkex, peer, freq);
if (!bi)
return NULL;
+
wpa_s->dpp_pkex = NULL;
+
+#ifdef CONFIG_DPP3
+ if (wpa_s->dpp_pb_bi &&
+ os_memcmp(bi->pubkey_hash_chirp, wpa_s->dpp_pb_init_hash,
+ SHA256_MAC_LEN) != 0) {
+ char id[20];
+
+ wpa_printf(MSG_INFO,
+ "DPP: Peer bootstrap key from PKEX does not match PB announcement response hash");
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Peer provided bootstrap key hash(chirp) from PB PKEX",
+ bi->pubkey_hash_chirp, SHA256_MAC_LEN);
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Peer provided bootstrap key hash(chirp) from PB announcement response",
+ wpa_s->dpp_pb_init_hash, SHA256_MAC_LEN);
+
+ os_snprintf(id, sizeof(id), "%u", bi->id);
+ dpp_bootstrap_remove(wpa_s->dpp, id);
+ wpas_dpp_push_button_stop(wpa_s);
+ return NULL;
+ }
+#endif /* CONFIG_DPP3 */
+
return bi;
}
}
+#ifdef CONFIG_DPP3
+
+static void
+wpas_dpp_rx_pb_presence_announcement_resp(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *i_hash, *r_hash, *c_nonce;
+ u16 i_hash_len, r_hash_len, c_nonce_len;
+ bool overlap = false;
+
+ if (!wpa_s->dpp_pb_announcement || !wpa_s->dpp_pb_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Not in active push button mode - discard Push Button Presence Announcement Response from "
+ MACSTR, MAC2STR(src));
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Push Button Presence Announcement Response from "
+ MACSTR, MAC2STR(src));
+
+ i_hash = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
+ &i_hash_len);
+ r_hash = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_hash_len);
+ c_nonce = dpp_get_attr(buf, len, DPP_ATTR_CONFIGURATOR_NONCE,
+ &c_nonce_len);
+ if (!i_hash || i_hash_len != SHA256_MAC_LEN ||
+ !r_hash || r_hash_len != SHA256_MAC_LEN ||
+ !c_nonce || c_nonce_len > DPP_MAX_NONCE_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Missing or invalid required attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
+ i_hash, i_hash_len);
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_hash, r_hash_len);
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Configurator Nonce",
+ c_nonce, c_nonce_len);
+
+ if (os_memcmp(r_hash, wpa_s->dpp_pb_bi->pubkey_hash_chirp,
+ SHA256_MAC_LEN) != 0) {
+ wpa_printf(MSG_INFO,
+ "DPP: Unexpected push button Responder hash - abort");
+ overlap = true;
+ }
+
+ if (wpa_s->dpp_pb_resp_freq &&
+ os_memcmp(i_hash, wpa_s->dpp_pb_init_hash, SHA256_MAC_LEN) != 0) {
+ wpa_printf(MSG_INFO,
+ "DPP: Push button session overlap detected - abort");
+ overlap = true;
+ }
+
+ if (overlap) {
+ if (!wpa_s->dpp_pb_result_indicated) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT
+ "session-overlap");
+ wpa_s->dpp_pb_result_indicated = true;
+ }
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+
+ if (!wpa_s->dpp_pb_resp_freq) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS
+ "discovered push button AP/Configurator " MACSTR,
+ MAC2STR(src));
+ wpa_s->dpp_pb_resp_freq = freq;
+ os_memcpy(wpa_s->dpp_pb_init_hash, i_hash, SHA256_MAC_LEN);
+ os_memcpy(wpa_s->dpp_pb_c_nonce, c_nonce, c_nonce_len);
+ wpa_s->dpp_pb_c_nonce_len = c_nonce_len;
+ /* Stop announcement iterations after at least one more full
+ * round and one extra round for postponed session overlap
+ * detection. */
+ wpa_s->dpp_pb_stop_iter = 3;
+ }
+}
+
+#endif /* CONFIG_DPP3 */
+
+
void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *buf, size_t len, unsigned int freq)
{
wpas_dpp_rx_reconfig_auth_conf(wpa_s, src, hdr, buf, len, freq);
break;
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ case DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP:
+ wpas_dpp_rx_pb_presence_announcement_resp(wpa_s, src, hdr,
+ buf, len, freq);
+ break;
+#endif /* CONFIG_DPP3 */
default:
wpa_printf(MSG_DEBUG,
"DPP: Ignored unsupported frame subtype %d", type);
wpa_s->dpp_pkex_code = os_strdup(pos + 6);
if (!wpa_s->dpp_pkex_code)
return -1;
+ wpa_s->dpp_pkex_code_len = os_strlen(wpa_s->dpp_pkex_code);
pos = os_strstr(cmd, " ver=");
if (pos) {
wpa_s->dpp_pkex_wait_auth_req = false;
if (wpa_s->dpp_gas_client && wpa_s->dpp_gas_dialog_token >= 0)
gas_query_stop(wpa_s->gas, wpa_s->dpp_gas_dialog_token);
+#ifdef CONFIG_DPP3
+ wpas_dpp_push_button_stop(wpa_s);
+#endif /* CONFIG_DPP3 */
}
}
#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_DPP3
+
+#define DPP_PB_ANNOUNCE_PER_CHAN 3
+
+static int wpas_dpp_pb_announce(struct wpa_supplicant *wpa_s, int freq);
+static void wpas_dpp_pb_next(void *eloop_ctx, void *timeout_ctx);
+
+
+static bool wpas_dpp_pb_chan_ok(int flags)
+{
+ return !(flags & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_NO_IR |
+ HOSTAPD_CHAN_RADAR));
+}
+
+
+static int wpas_dpp_pb_channels(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_hw_modes *mode;
+ int m, c;
+
+ for (m = 0; m < wpa_s->hw.num_modes; m++) {
+ mode = &wpa_s->hw.modes[m];
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if (!wpas_dpp_pb_chan_ok(chan->flag))
+ continue;
+ int_array_add_unique(&wpa_s->dpp_pb_freqs, chan->freq);
+ }
+ }
+
+ return wpa_s->dpp_pb_freqs ? 0 : -1;
+}
+
+
+static void wpas_dpp_pb_tx_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result)
+{
+ if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to send push button announcement on %d MHz",
+ freq);
+ if (eloop_register_timeout(0, 0, wpas_dpp_pb_next,
+ wpa_s, NULL) < 0)
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Push button announcement on %d MHz sent",
+ freq);
+ if (wpa_s->dpp_pb_discovery_done) {
+ wpa_s->dpp_pb_announce_count = 0;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Wait for push button announcement response and PKEX on %d MHz",
+ freq);
+ if (eloop_register_timeout(0, 500000, wpas_dpp_pb_next,
+ wpa_s, NULL) < 0)
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ } else if (wpa_s->dpp_pb_announce_count >= DPP_PB_ANNOUNCE_PER_CHAN) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Wait for push button announcement response on %d MHz",
+ freq);
+ if (eloop_register_timeout(0, 50000, wpas_dpp_pb_next,
+ wpa_s, NULL) < 0)
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+
+ if (wpas_dpp_pb_announce(wpa_s, freq) < 0)
+ wpas_dpp_push_button_stop(wpa_s);
+}
+
+
+static int wpas_dpp_pb_announce(struct wpa_supplicant *wpa_s, int freq)
+{
+ struct wpabuf *msg;
+ int type;
+
+ msg = wpa_s->dpp_pb_announcement;
+ if (!msg)
+ return -1;
+
+ wpa_s->dpp_pb_announce_count++;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Send push button announcement %d/%d (%d MHz)",
+ wpa_s->dpp_pb_announce_count, DPP_PB_ANNOUNCE_PER_CHAN,
+ freq);
+
+ type = DPP_PA_PB_PRESENCE_ANNOUNCEMENT;
+ if (wpa_s->dpp_pb_announce_count == 1)
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(broadcast), freq, type);
+ if (offchannel_send_action(
+ wpa_s, freq, broadcast, wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ 1000, wpas_dpp_pb_tx_status, 0) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static void wpas_dpp_pb_next(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct os_reltime now;
+ int freq;
+
+ if (!wpa_s->dpp_pb_freqs)
+ return;
+
+ os_get_reltime(&now);
+ offchannel_send_action_done(wpa_s);
+
+ if (os_reltime_expired(&now, &wpa_s->dpp_pb_time, 100)) {
+ wpa_printf(MSG_DEBUG, "DPP: Push button wait time expired");
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+
+ if (wpa_s->dpp_pb_freq_idx >= int_array_len(wpa_s->dpp_pb_freqs)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Completed push button announcement round");
+ wpa_s->dpp_pb_freq_idx = 0;
+ if (wpa_s->dpp_pb_stop_iter > 0) {
+ wpa_s->dpp_pb_stop_iter--;
+
+ if (wpa_s->dpp_pb_stop_iter == 1) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS
+ "wait for AP/Configurator to allow PKEX to be initiated");
+ if (eloop_register_timeout(10, 0,
+ wpas_dpp_pb_next,
+ wpa_s, NULL) < 0) {
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+ return;
+ }
+
+ if (wpa_s->dpp_pb_stop_iter == 0) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS
+ "start push button PKEX responder on the discovered channel (%d MHz)",
+ wpa_s->dpp_pb_resp_freq);
+ wpa_s->dpp_pb_discovery_done = true;
+
+ wpa_s->dpp_pkex_bi = wpa_s->dpp_pb_bi;
+
+ os_free(wpa_s->dpp_pkex_code);
+ wpa_s->dpp_pkex_code = os_memdup(
+ wpa_s->dpp_pb_c_nonce,
+ wpa_s->dpp_pb_c_nonce_len);
+ wpa_s->dpp_pkex_code_len =
+ wpa_s->dpp_pb_c_nonce_len;
+
+ os_free(wpa_s->dpp_pkex_identifier);
+ wpa_s->dpp_pkex_identifier =
+ os_strdup("PBPKEX");
+
+ if (!wpa_s->dpp_pkex_code ||
+ !wpa_s->dpp_pkex_identifier) {
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+
+ wpa_s->dpp_pkex_ver = PKEX_VER_ONLY_2;
+
+ os_free(wpa_s->dpp_pkex_auth_cmd);
+ wpa_s->dpp_pkex_auth_cmd = NULL;
+ }
+ }
+ }
+
+ if (wpa_s->dpp_pb_discovery_done)
+ freq = wpa_s->dpp_pb_resp_freq;
+ else
+ freq = wpa_s->dpp_pb_freqs[wpa_s->dpp_pb_freq_idx++];
+ wpa_s->dpp_pb_announce_count = 0;
+ if (!wpa_s->dpp_pb_announcement) {
+ wpa_printf(MSG_DEBUG, "DPP: Push button announcements stopped");
+ return;
+ }
+ if (wpas_dpp_pb_announce(wpa_s, freq) < 0) {
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+}
+
+
+int wpas_dpp_push_button(struct wpa_supplicant *wpa_s)
+{
+ int res;
+
+ if (!wpa_s->dpp)
+ return -1;
+ wpas_dpp_push_button_stop(wpa_s);
+ wpas_dpp_stop(wpa_s);
+ wpas_dpp_chirp_stop(wpa_s);
+
+ os_get_reltime(&wpa_s->dpp_pb_time);
+
+ if (wpas_dpp_pb_channels(wpa_s) < 0)
+ return -1;
+ wpa_s->dpp_pb_freq_idx = 0;
+
+ res = dpp_bootstrap_gen(wpa_s->dpp, "type=pkex");
+ if (res < 0)
+ return -1;
+ wpa_s->dpp_pb_bi = dpp_bootstrap_get_id(wpa_s->dpp, res);
+ if (!wpa_s->dpp_pb_bi)
+ return -1;
+
+ wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+ wpa_s->dpp_netrole = DPP_NETROLE_STA;
+ wpa_s->dpp_qr_mutual = 0;
+ wpa_s->dpp_pb_announcement =
+ dpp_build_pb_announcement(wpa_s->dpp_pb_bi);
+ if (!wpa_s->dpp_pb_announcement)
+ return -1;
+
+ return eloop_register_timeout(0, 0, wpas_dpp_pb_next, wpa_s, NULL);
+}
+
+
+void wpas_dpp_push_button_stop(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->dpp)
+ return;
+ os_free(wpa_s->dpp_pb_freqs);
+ wpa_s->dpp_pb_freqs = NULL;
+ wpabuf_free(wpa_s->dpp_pb_announcement);
+ wpa_s->dpp_pb_announcement = NULL;
+ if (wpa_s->dpp_pb_bi) {
+ char id[20];
+
+ os_snprintf(id, sizeof(id), "%u", wpa_s->dpp_pb_bi->id);
+ dpp_bootstrap_remove(wpa_s->dpp, id);
+ wpa_s->dpp_pb_bi = NULL;
+ if (!wpa_s->dpp_pb_result_indicated)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT "failed");
+ }
+
+ wpa_s->dpp_pb_resp_freq = 0;
+ wpa_s->dpp_pb_stop_iter = 0;
+ wpa_s->dpp_pb_discovery_done = false;
+ wpa_s->dpp_pb_result_indicated = false;
+
+ eloop_cancel_timeout(wpas_dpp_pb_next, wpa_s, NULL);
+}
+
+#endif /* CONFIG_DPP3 */
int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_conf_set(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_push_button(struct wpa_supplicant *wpa_s);
+void wpas_dpp_push_button_stop(struct wpa_supplicant *wpa_s);
#endif /* DPP_SUPPLICANT_H */
}
#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_DPP3
+static int wpa_cli_cmd_dpp_push_button(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_PUSH_BUTTON");
+}
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
cli_cmd_flag_none,
"= stop DPP chirp" },
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ { "dpp_push_button", wpa_cli_cmd_dpp_push_button, NULL,
+ cli_cmd_flag_none,
+ "= press DPP push button" },
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
{ "all_bss", wpa_cli_cmd_all_bss, NULL, cli_cmd_flag_none,
"= list all BSS entries (scan results)" },
struct dpp_pkex *dpp_pkex;
struct dpp_bootstrap_info *dpp_pkex_bi;
char *dpp_pkex_code;
+ size_t dpp_pkex_code_len;
char *dpp_pkex_identifier;
enum dpp_pkex_ver dpp_pkex_ver;
char *dpp_pkex_auth_cmd;
int dpp_reconfig_ssid_id;
struct dpp_reconfig_id *dpp_reconfig_id;
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ struct os_reltime dpp_pb_time;
+ int *dpp_pb_freqs;
+ unsigned int dpp_pb_freq_idx;
+ unsigned int dpp_pb_announce_count;
+ struct wpabuf *dpp_pb_announcement;
+ struct dpp_bootstrap_info *dpp_pb_bi;
+ unsigned int dpp_pb_resp_freq;
+ u8 dpp_pb_init_hash[SHA256_MAC_LEN];
+ int dpp_pb_stop_iter;
+ bool dpp_pb_discovery_done;
+ u8 dpp_pb_c_nonce[DPP_MAX_NONCE_LEN];
+ size_t dpp_pb_c_nonce_len;
+ bool dpp_pb_result_indicated;
+#endif /* CONFIG_DPP3 */
#ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override;
char *dpp_discovery_override;