diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index f8fbc176b..45495f3b8 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -1069,6 +1069,8 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src, if (hapd->dpp_pkex->failed) { wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange due to an earlier error"); + if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t) + hapd->dpp_pkex->own_bi->pkex_t = hapd->dpp_pkex->t; dpp_pkex_free(hapd->dpp_pkex); hapd->dpp_pkex = NULL; } @@ -1134,6 +1136,9 @@ hostapd_dpp_rx_pkex_commit_reveal_req(struct hostapd_data *hapd, const u8 *src, wpa_printf(MSG_DEBUG, "DPP: Failed to process the request"); if (hapd->dpp_pkex->failed) { wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange"); + if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t) + hapd->dpp_pkex->own_bi->pkex_t = + hapd->dpp_pkex->t; dpp_pkex_free(hapd->dpp_pkex); hapd->dpp_pkex = NULL; } @@ -1236,6 +1241,7 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src, u8 crypto_suite; enum dpp_public_action_frame_type type; const u8 *hdr; + unsigned int pkex_t; if (len < DPP_HDR_LEN) return; @@ -1302,6 +1308,17 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src, "DPP: Ignored unsupported frame subtype %d", type); break; } + + if (hapd->dpp_pkex) + pkex_t = hapd->dpp_pkex->t; + else if (hapd->dpp_pkex_bi) + pkex_t = hapd->dpp_pkex_bi->pkex_t; + else + pkex_t = 0; + if (pkex_t >= PKEX_COUNTER_T_LIMIT) { + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0"); + hostapd_dpp_pkex_remove(hapd, "*"); + } } @@ -1436,6 +1453,7 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd) return -1; } hapd->dpp_pkex_bi = own_bi; + own_bi->pkex_t = 0; /* clear pending errors on new code */ os_free(hapd->dpp_pkex_identifier); hapd->dpp_pkex_identifier = NULL; diff --git a/src/common/dpp.c b/src/common/dpp.c index 478ae53ff..566898b63 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -5769,6 +5769,12 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, const EC_POINT *Y_point; BIGNUM *Nx = NULL, *Ny = NULL; + if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) { + wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL + "PKEX counter t limit reached - ignore message"); + return NULL; + } + attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER, &attr_id_len); if (!attr_id && identifier) { @@ -5841,12 +5847,14 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, !EC_POINT_is_on_curve(group, X, bnctx)) { wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL "Invalid Encrypted Key value"); + bi->pkex_t++; goto fail; } pkex = os_zalloc(sizeof(*pkex)); if (!pkex) goto fail; + pkex->t = bi->pkex_t; pkex->msg_ctx = msg_ctx; pkex->own_bi = bi; os_memcpy(pkex->own_mac, own_mac, ETH_ALEN); @@ -6103,7 +6111,7 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, u8 u[DPP_MAX_HASH_LEN]; int res; - if (pkex->failed) + if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT) return NULL; attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS, @@ -6176,6 +6184,7 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, EC_POINT_is_at_infinity(group, Y) || !EC_POINT_is_on_curve(group, Y, bnctx)) { dpp_pkex_fail(pkex, "Invalid Encrypted Key value"); + pkex->t++; goto fail; } @@ -6396,7 +6405,8 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex, u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN]; int res; - if (!pkex->exchange_done || pkex->failed) + if (!pkex->exchange_done || pkex->failed || + pkex->t >= PKEX_COUNTER_T_LIMIT) goto fail; /* K = y * X' */ @@ -6455,6 +6465,7 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex, dpp_pkex_fail(pkex, "AES-SIV decryption failed - possible PKEX code mismatch"); pkex->failed = 1; + pkex->t++; goto fail; } wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", @@ -6523,6 +6534,7 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex, wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'", u, curve->hash_len); wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len); + pkex->t++; goto fail; } wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received"); @@ -6598,7 +6610,8 @@ int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr, EVP_PKEY_CTX *ctx = NULL; struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL; - if (!pkex->exchange_done || pkex->failed) + if (!pkex->exchange_done || pkex->failed || + pkex->t >= PKEX_COUNTER_T_LIMIT) goto fail; wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA, @@ -6629,6 +6642,7 @@ int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr, 2, addr, len, unwrapped) < 0) { dpp_pkex_fail(pkex, "AES-SIV decryption failed - possible PKEX code mismatch"); + pkex->t++; goto fail; } wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", @@ -6696,6 +6710,7 @@ int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr, wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'", v, curve->hash_len); wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len); + pkex->t++; goto fail; } wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received"); diff --git a/src/common/dpp.h b/src/common/dpp.h index d55c30e5d..c60d90f42 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -107,8 +107,12 @@ struct dpp_bootstrap_info { EVP_PKEY *pubkey; u8 pubkey_hash[SHA256_MAC_LEN]; const struct dpp_curve_params *curve; + unsigned int pkex_t; /* number of failures before dpp_pkex + * instantiation */ }; +#define PKEX_COUNTER_T_LIMIT 5 + struct dpp_pkex { void *msg_ctx; unsigned int initiator:1; @@ -127,6 +131,7 @@ struct dpp_pkex { EVP_PKEY *peer_bootstrap_key; struct wpabuf *exchange_req; struct wpabuf *exchange_resp; + unsigned int t; /* number of failures on code use */ }; struct dpp_configuration { diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 6e9dcf14a..b3fd287b8 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -171,6 +171,7 @@ extern "C" { #define DPP_EVENT_TX "DPP-TX " #define DPP_EVENT_TX_STATUS "DPP-TX-STATUS " #define DPP_EVENT_FAIL "DPP-FAIL " +#define DPP_EVENT_PKEX_T_LIMIT "DPP-PKEX-T-LIMIT " #define DPP_EVENT_INTRO "DPP-INTRO " /* MESH events */ diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index 87131f5fd..74dbb9311 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -1437,6 +1437,8 @@ wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s, if (wpa_s->dpp_pkex->failed) { wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange due to an earlier error"); + if (wpa_s->dpp_pkex->t > wpa_s->dpp_pkex->own_bi->pkex_t) + wpa_s->dpp_pkex->own_bi->pkex_t = wpa_s->dpp_pkex->t; dpp_pkex_free(wpa_s->dpp_pkex); wpa_s->dpp_pkex = NULL; } @@ -1558,6 +1560,8 @@ wpas_dpp_rx_pkex_commit_reveal_req(struct wpa_supplicant *wpa_s, const u8 *src, wpa_printf(MSG_DEBUG, "DPP: Failed to process the request"); if (pkex->failed) { wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange"); + if (pkex->t > pkex->own_bi->pkex_t) + pkex->own_bi->pkex_t = pkex->t; dpp_pkex_free(wpa_s->dpp_pkex); wpa_s->dpp_pkex = NULL; } @@ -1664,6 +1668,7 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, u8 crypto_suite; enum dpp_public_action_frame_type type; const u8 *hdr; + unsigned int pkex_t; if (len < DPP_HDR_LEN) return; @@ -1730,6 +1735,17 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, "DPP: Ignored unsupported frame subtype %d", type); break; } + + if (wpa_s->dpp_pkex) + pkex_t = wpa_s->dpp_pkex->t; + else if (wpa_s->dpp_pkex_bi) + pkex_t = wpa_s->dpp_pkex_bi->pkex_t; + else + pkex_t = 0; + if (pkex_t >= PKEX_COUNTER_T_LIMIT) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0"); + wpas_dpp_pkex_remove(wpa_s, "*"); + } } @@ -2009,6 +2025,7 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd) return -1; } wpa_s->dpp_pkex_bi = own_bi; + own_bi->pkex_t = 0; /* clear pending errors on new code */ os_free(wpa_s->dpp_pkex_identifier); wpa_s->dpp_pkex_identifier = NULL;