Add limit on number of failed attempts that could have used PKEX code.
If the limit (5) is reached, drop the PKEX state (including the code)
and report this on the control interface to indicate that a new code
needs to be entered due to possible attack.
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
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;
}
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;
}
u8 crypto_suite;
enum dpp_public_action_frame_type type;
const u8 *hdr;
+ unsigned int pkex_t;
if (len < DPP_HDR_LEN)
return;
"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, "*");
+ }
}
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;
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) {
!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);
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,
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;
}
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' */
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",
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");
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,
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",
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");
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;
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 {
#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 */
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;
}
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;
}
u8 crypto_suite;
enum dpp_public_action_frame_type type;
const u8 *hdr;
+ unsigned int pkex_t;
if (len < DPP_HDR_LEN)
return;
"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, "*");
+ }
}
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;