DPP: PKEX counter t
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>
This commit is contained in:
parent
84d53c775c
commit
29ab69e4b0
5 changed files with 59 additions and 3 deletions
|
@ -1069,6 +1069,8 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
|
||||||
if (hapd->dpp_pkex->failed) {
|
if (hapd->dpp_pkex->failed) {
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
"DPP: Terminate PKEX exchange due to an earlier error");
|
"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);
|
dpp_pkex_free(hapd->dpp_pkex);
|
||||||
hapd->dpp_pkex = NULL;
|
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");
|
wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
|
||||||
if (hapd->dpp_pkex->failed) {
|
if (hapd->dpp_pkex->failed) {
|
||||||
wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
|
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);
|
dpp_pkex_free(hapd->dpp_pkex);
|
||||||
hapd->dpp_pkex = NULL;
|
hapd->dpp_pkex = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1236,6 +1241,7 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
|
||||||
u8 crypto_suite;
|
u8 crypto_suite;
|
||||||
enum dpp_public_action_frame_type type;
|
enum dpp_public_action_frame_type type;
|
||||||
const u8 *hdr;
|
const u8 *hdr;
|
||||||
|
unsigned int pkex_t;
|
||||||
|
|
||||||
if (len < DPP_HDR_LEN)
|
if (len < DPP_HDR_LEN)
|
||||||
return;
|
return;
|
||||||
|
@ -1302,6 +1308,17 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
|
||||||
"DPP: Ignored unsupported frame subtype %d", type);
|
"DPP: Ignored unsupported frame subtype %d", type);
|
||||||
break;
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
hapd->dpp_pkex_bi = own_bi;
|
hapd->dpp_pkex_bi = own_bi;
|
||||||
|
own_bi->pkex_t = 0; /* clear pending errors on new code */
|
||||||
|
|
||||||
os_free(hapd->dpp_pkex_identifier);
|
os_free(hapd->dpp_pkex_identifier);
|
||||||
hapd->dpp_pkex_identifier = NULL;
|
hapd->dpp_pkex_identifier = NULL;
|
||||||
|
|
|
@ -5769,6 +5769,12 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
|
||||||
const EC_POINT *Y_point;
|
const EC_POINT *Y_point;
|
||||||
BIGNUM *Nx = NULL, *Ny = NULL;
|
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 = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
|
||||||
&attr_id_len);
|
&attr_id_len);
|
||||||
if (!attr_id && identifier) {
|
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)) {
|
!EC_POINT_is_on_curve(group, X, bnctx)) {
|
||||||
wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
|
wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
|
||||||
"Invalid Encrypted Key value");
|
"Invalid Encrypted Key value");
|
||||||
|
bi->pkex_t++;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
pkex = os_zalloc(sizeof(*pkex));
|
pkex = os_zalloc(sizeof(*pkex));
|
||||||
if (!pkex)
|
if (!pkex)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
pkex->t = bi->pkex_t;
|
||||||
pkex->msg_ctx = msg_ctx;
|
pkex->msg_ctx = msg_ctx;
|
||||||
pkex->own_bi = bi;
|
pkex->own_bi = bi;
|
||||||
os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
|
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];
|
u8 u[DPP_MAX_HASH_LEN];
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (pkex->failed)
|
if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
|
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_at_infinity(group, Y) ||
|
||||||
!EC_POINT_is_on_curve(group, Y, bnctx)) {
|
!EC_POINT_is_on_curve(group, Y, bnctx)) {
|
||||||
dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
|
dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
|
||||||
|
pkex->t++;
|
||||||
goto fail;
|
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];
|
u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (!pkex->exchange_done || pkex->failed)
|
if (!pkex->exchange_done || pkex->failed ||
|
||||||
|
pkex->t >= PKEX_COUNTER_T_LIMIT)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* K = y * X' */
|
/* K = y * X' */
|
||||||
|
@ -6455,6 +6465,7 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
|
||||||
dpp_pkex_fail(pkex,
|
dpp_pkex_fail(pkex,
|
||||||
"AES-SIV decryption failed - possible PKEX code mismatch");
|
"AES-SIV decryption failed - possible PKEX code mismatch");
|
||||||
pkex->failed = 1;
|
pkex->failed = 1;
|
||||||
|
pkex->t++;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
|
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'",
|
wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
|
||||||
u, curve->hash_len);
|
u, curve->hash_len);
|
||||||
wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
|
wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
|
||||||
|
pkex->t++;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
|
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;
|
EVP_PKEY_CTX *ctx = NULL;
|
||||||
struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = 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;
|
goto fail;
|
||||||
|
|
||||||
wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
|
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) {
|
2, addr, len, unwrapped) < 0) {
|
||||||
dpp_pkex_fail(pkex,
|
dpp_pkex_fail(pkex,
|
||||||
"AES-SIV decryption failed - possible PKEX code mismatch");
|
"AES-SIV decryption failed - possible PKEX code mismatch");
|
||||||
|
pkex->t++;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
|
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'",
|
wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
|
||||||
v, curve->hash_len);
|
v, curve->hash_len);
|
||||||
wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
|
wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
|
||||||
|
pkex->t++;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
|
wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
|
||||||
|
|
|
@ -107,8 +107,12 @@ struct dpp_bootstrap_info {
|
||||||
EVP_PKEY *pubkey;
|
EVP_PKEY *pubkey;
|
||||||
u8 pubkey_hash[SHA256_MAC_LEN];
|
u8 pubkey_hash[SHA256_MAC_LEN];
|
||||||
const struct dpp_curve_params *curve;
|
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 {
|
struct dpp_pkex {
|
||||||
void *msg_ctx;
|
void *msg_ctx;
|
||||||
unsigned int initiator:1;
|
unsigned int initiator:1;
|
||||||
|
@ -127,6 +131,7 @@ struct dpp_pkex {
|
||||||
EVP_PKEY *peer_bootstrap_key;
|
EVP_PKEY *peer_bootstrap_key;
|
||||||
struct wpabuf *exchange_req;
|
struct wpabuf *exchange_req;
|
||||||
struct wpabuf *exchange_resp;
|
struct wpabuf *exchange_resp;
|
||||||
|
unsigned int t; /* number of failures on code use */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dpp_configuration {
|
struct dpp_configuration {
|
||||||
|
|
|
@ -171,6 +171,7 @@ extern "C" {
|
||||||
#define DPP_EVENT_TX "DPP-TX "
|
#define DPP_EVENT_TX "DPP-TX "
|
||||||
#define DPP_EVENT_TX_STATUS "DPP-TX-STATUS "
|
#define DPP_EVENT_TX_STATUS "DPP-TX-STATUS "
|
||||||
#define DPP_EVENT_FAIL "DPP-FAIL "
|
#define DPP_EVENT_FAIL "DPP-FAIL "
|
||||||
|
#define DPP_EVENT_PKEX_T_LIMIT "DPP-PKEX-T-LIMIT "
|
||||||
#define DPP_EVENT_INTRO "DPP-INTRO "
|
#define DPP_EVENT_INTRO "DPP-INTRO "
|
||||||
|
|
||||||
/* MESH events */
|
/* MESH events */
|
||||||
|
|
|
@ -1437,6 +1437,8 @@ wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
|
||||||
if (wpa_s->dpp_pkex->failed) {
|
if (wpa_s->dpp_pkex->failed) {
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
"DPP: Terminate PKEX exchange due to an earlier error");
|
"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);
|
dpp_pkex_free(wpa_s->dpp_pkex);
|
||||||
wpa_s->dpp_pkex = NULL;
|
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");
|
wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
|
||||||
if (pkex->failed) {
|
if (pkex->failed) {
|
||||||
wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
|
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);
|
dpp_pkex_free(wpa_s->dpp_pkex);
|
||||||
wpa_s->dpp_pkex = NULL;
|
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;
|
u8 crypto_suite;
|
||||||
enum dpp_public_action_frame_type type;
|
enum dpp_public_action_frame_type type;
|
||||||
const u8 *hdr;
|
const u8 *hdr;
|
||||||
|
unsigned int pkex_t;
|
||||||
|
|
||||||
if (len < DPP_HDR_LEN)
|
if (len < DPP_HDR_LEN)
|
||||||
return;
|
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);
|
"DPP: Ignored unsupported frame subtype %d", type);
|
||||||
break;
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
wpa_s->dpp_pkex_bi = own_bi;
|
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);
|
os_free(wpa_s->dpp_pkex_identifier);
|
||||||
wpa_s->dpp_pkex_identifier = NULL;
|
wpa_s->dpp_pkex_identifier = NULL;
|
||||||
|
|
Loading…
Reference in a new issue