]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP3: Push button bootstrap mechanism
authorJouni Malinen <quic_jouni@quicinc.com>
Wed, 6 Jul 2022 14:11:12 +0000 (17:11 +0300)
committerJouni Malinen <j@w1.fi>
Wed, 6 Jul 2022 21:31:30 +0000 (00:31 +0300)
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>
17 files changed:
hostapd/ctrl_iface.c
hostapd/hostapd_cli.c
src/ap/dpp_hostapd.c
src/ap/dpp_hostapd.h
src/ap/hostapd.h
src/common/dpp.c
src/common/dpp.h
src/common/dpp_crypto.c
src/common/dpp_i.h
src/common/dpp_pkex.c
src/common/dpp_tcp.c
src/common/wpa_ctrl.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/dpp_supplicant.c
wpa_supplicant/dpp_supplicant.h
wpa_supplicant/wpa_cli.c
wpa_supplicant/wpa_supplicant_i.h

index 4e464da73870215822fa65114769528d83153ad2..e0b582030cdb9def48bc8032d846109b64b6d00b 100644 (file)
@@ -3674,6 +3674,11 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
        } 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) {
@@ -4182,6 +4187,19 @@ static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
 
 #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 */
 }
 
index 60396f3dad48ee2085049f658ca2799690be820d..7ab97817977993b092088b0ffbd617341bd6ebf8 100644 (file)
@@ -1503,6 +1503,15 @@ static int hostapd_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc,
 }
 
 #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 */
 
 
@@ -1729,6 +1738,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
        { "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" },
index 2613c0cbbc86fede18a567fd1f3932faaefbd3d9..1c4be2430350145ce7e295faeeab5fed04115f19 100644 (file)
@@ -15,6 +15,7 @@
 #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"
@@ -362,7 +363,7 @@ static int hostapd_dpp_pkex_init(struct hostapd_data *hapd,
        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;
@@ -1450,11 +1451,53 @@ static void hostapd_dpp_conn_status_result_wait_timeout(void *eloop_ctx,
 }
 
 
+#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));
@@ -1498,6 +1541,20 @@ static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *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 */
 }
 
 
@@ -2048,6 +2105,7 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
                                                  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,
@@ -2177,6 +2235,7 @@ hostapd_dpp_rx_pkex_commit_reveal_resp(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;
        int res;
        struct dpp_bootstrap_info *bi;
        struct dpp_pkex *pkex = hapd->dpp_pkex;
@@ -2196,11 +2255,33 @@ hostapd_dpp_rx_pkex_commit_reveal_resp(struct hostapd_data *hapd, const u8 *src,
                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 : "");
@@ -2215,6 +2296,292 @@ hostapd_dpp_rx_pkex_commit_reveal_resp(struct hostapd_data *hapd, const u8 *src,
 }
 
 
+#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)
 {
@@ -2320,6 +2687,12 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
                                                  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);
@@ -2388,6 +2761,9 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
 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;
@@ -2427,6 +2803,20 @@ void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
                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 */
 }
 
 
@@ -2528,6 +2918,7 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
        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) {
@@ -2600,6 +2991,9 @@ void hostapd_dpp_stop(struct hostapd_data *hapd)
        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 */
 }
 
 
@@ -2698,6 +3092,7 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
 #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;
@@ -2705,6 +3100,8 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
        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;
 }
 
 
@@ -3077,3 +3474,64 @@ void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi)
 }
 
 #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 */
index 264d3e4c0166fb62b15cba2328c01a41b5f5a7a1..6b7716428cfdbc7fbdd568b48be69fbd478fc05d 100644 (file)
@@ -45,5 +45,7 @@ int hostapd_dpp_controller_start(struct hostapd_data *hapd, const char *cmd);
 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 */
index cbe03a06064a8b9e08a024c4e857bd6b7455ddfd..2e9a898906010d780f10885767ce049a2290f1b3 100644 (file)
@@ -43,6 +43,13 @@ struct mesh_conf;
 #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 {
@@ -76,6 +83,16 @@ 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
@@ -401,6 +418,7 @@ struct hostapd_data {
        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;
index e878f72567865b0bdde8175a9616126b559e2e47..9bbe71868c051fca1ba93e36301e9ae90ad23c4c 100644 (file)
@@ -4950,3 +4950,64 @@ void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
 }
 
 #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 */
index 812298f60adcac768fdcdfde3138c56bc9dc5c96..c2cf0c2ef7af25b01cedc913ffeee4125140beb6 100644 (file)
@@ -56,6 +56,8 @@ enum dpp_public_action_frame_type {
        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 {
@@ -203,6 +205,7 @@ struct dpp_pkex {
        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];
@@ -644,13 +647,13 @@ int dpp_get_connector_version(const char *connector);
 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,
@@ -759,6 +762,12 @@ struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi);
 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);
index fb239f7729cde70bb295af3dd62f5934a073a1c9..9c0dd35a8b2e82048f19c60f5cb46f79a47f3b11 100644 (file)
@@ -1437,7 +1437,7 @@ dpp_pkex_get_role_elem(const struct dpp_curve_params *curve, int init)
 
 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];
@@ -1465,9 +1465,9 @@ dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
                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;
@@ -1512,7 +1512,7 @@ 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];
@@ -1540,9 +1540,9 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
                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;
@@ -1590,7 +1590,7 @@ 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)
 {
@@ -1615,7 +1615,7 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
                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;
@@ -1633,7 +1633,7 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
        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)
index 10db4e818491aec55ffc5341d185733b01980360..f7184121c965c1187d743eda3221b7789afcd9c5 100644 (file)
@@ -113,17 +113,17 @@ int dpp_derive_pmkid(const struct dpp_curve_params *curve,
                     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,
index cf4fb6b5ccd21875fa8a7514d34bb0e6ce8cd155..c4713a4fec74339c25d4550d0f0bde0f57544dff 100644 (file)
@@ -41,7 +41,7 @@ static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex,
 
        /* 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;
 
@@ -171,7 +171,7 @@ static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
 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;
 
@@ -196,9 +196,10 @@ struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
                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;
@@ -340,7 +341,7 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
                                           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;
@@ -437,8 +438,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
        }
 
        /* 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;
 
@@ -477,9 +478,10 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
                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);
 
@@ -495,8 +497,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
                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;
 
@@ -550,7 +552,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
                                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;
@@ -791,7 +794,8 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
 
        /* 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;
 
@@ -869,7 +873,7 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
                                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)
index c83fb2da48cf75aa5c7cf72b5f38d6963faed67c..5b1eeb449f1cc2367e504e71339285c7d23e1244 100644 (file)
@@ -1017,6 +1017,7 @@ static int dpp_controller_rx_pkex_exchange_req(struct dpp_connection *conn,
                                              NULL, NULL,
                                              ctrl->pkex_identifier,
                                              ctrl->pkex_code,
+                                             os_strlen(ctrl->pkex_code),
                                              buf, len, true);
        if (!conn->pkex) {
                wpa_printf(MSG_DEBUG,
index 055bf7309c627b0ca2bf48a94ff9bfe1a310fe88..51dd3e836c6226a907db15a7d460f20ad44b5565 100644 (file)
@@ -213,6 +213,8 @@ extern "C" {
 #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 "
index 7adb7687beb093f256f2cd3b4687065b14af5802..1c89e7d123509483ec9520aad4dd314d1135b1b0 100644 (file)
@@ -12453,6 +12453,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                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))
index caf3af800db888dc40fe10e91a6cc3aa03c2c67f..88986af6c7bf8eda98b06cee17f6af01317ebdd1 100644 (file)
@@ -1610,6 +1610,14 @@ static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
                        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);
 }
 
@@ -2777,7 +2785,8 @@ static int wpas_dpp_pkex_init(struct wpa_supplicant *wpa_s,
        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;
@@ -2947,6 +2956,7 @@ wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src,
                                                   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,
@@ -2954,6 +2964,14 @@ wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src,
                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;
@@ -3021,7 +3039,31 @@ wpas_dpp_pkex_finish(struct wpa_supplicant *wpa_s, const u8 *peer,
        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;
 }
 
@@ -3118,6 +3160,91 @@ wpas_dpp_rx_pkex_commit_reveal_resp(struct wpa_supplicant *wpa_s, const u8 *src,
 }
 
 
+#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)
 {
@@ -3227,6 +3354,12 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
                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);
@@ -3717,6 +3850,7 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
        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) {
@@ -3794,6 +3928,9 @@ void wpas_dpp_stop(struct wpa_supplicant *wpa_s)
        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 */
 }
 
 
@@ -4452,3 +4589,261 @@ int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd)
 }
 
 #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 */
index 2b03a54624edb598329dac94e64074a26ac8d515..f9ccc602887aee2f8bf9cd73a80f1109e47ca46e 100644 (file)
@@ -44,5 +44,7 @@ void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s);
 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 */
index 0e2315d253b7898ec46674b77441fe910678026d..ff39b5d12f5b5b5ef85acb193f845dbbe6d7a889 100644 (file)
@@ -3159,6 +3159,15 @@ static int wpa_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc,
 }
 
 #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 */
 
 
@@ -3994,6 +4003,11 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
          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)" },
index 301d5d56a857eb6f783b11a7c154118e365f3f34..a349d6551d68f9c17b1402d8473dde89fa71325e 100644 (file)
@@ -1462,6 +1462,7 @@ struct wpa_supplicant {
        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;
@@ -1492,6 +1493,21 @@ struct wpa_supplicant {
        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;