From f591732af79f925671b793b130bca58b015f1d67 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 16 Jan 2024 16:03:34 +0200 Subject: [PATCH] Supplicant side testing functionality for EAPOL-Key Key Data field Allow additional elements and KDEs to be added to EAPOL-Key msg 2/4 and 4/4. This is for testing purposes to enable a convenient mechanism for testing Authenticator behavior with either potential future extensions or incorrect Supplicant behavior. Signed-off-by: Jouni Malinen --- src/rsn_supp/wpa.c | 56 +++++++++++++++++++++++++++++++++---- src/rsn_supp/wpa.h | 2 ++ src/rsn_supp/wpa_i.h | 2 ++ wpa_supplicant/ctrl_iface.c | 53 +++++++++++++++++++++++++++++++---- 4 files changed, 102 insertions(+), 11 deletions(-) diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 950d91bfd..e2e05eb45 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -521,7 +521,7 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, const u8 *wpa_ie, size_t wpa_ie_len, struct wpa_ptk *ptk) { - size_t mic_len, hdrlen, rlen; + size_t mic_len, hdrlen, rlen, extra_len = 0; struct wpa_eapol_key *reply; u8 *rbuf, *key_mic; u8 *rsn_ie_buf = NULL; @@ -573,10 +573,15 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len); +#ifdef CONFIG_TESTING_OPTIONS + if (sm->test_eapol_m2_elems) + extra_len = wpabuf_len(sm->test_eapol_m2_elems); +#endif /* CONFIG_TESTING_OPTIONS */ + mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len); hdrlen = sizeof(*reply) + mic_len + 2; rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, - NULL, hdrlen + wpa_ie_len, + NULL, hdrlen + wpa_ie_len + extra_len, &rlen, (void *) &reply); if (rbuf == NULL) { os_free(rsn_ie_buf); @@ -604,9 +609,17 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, WPA_REPLAY_COUNTER_LEN); key_mic = (u8 *) (reply + 1); - WPA_PUT_BE16(key_mic + mic_len, wpa_ie_len); /* Key Data Length */ + /* Key Data Length */ + WPA_PUT_BE16(key_mic + mic_len, wpa_ie_len + extra_len); os_memcpy(key_mic + mic_len + 2, wpa_ie, wpa_ie_len); /* Key Data */ os_free(rsn_ie_buf); +#ifdef CONFIG_TESTING_OPTIONS + if (sm->test_eapol_m2_elems) { + os_memcpy(key_mic + mic_len + 2 + wpa_ie_len, + wpabuf_head(sm->test_eapol_m2_elems), + wpabuf_len(sm->test_eapol_m2_elems)); + } +#endif /* CONFIG_TESTING_OPTIONS */ os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN); @@ -2154,7 +2167,7 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, struct wpa_eapol_key *reply; u8 *rbuf, *key_mic; u8 *kde = NULL; - size_t kde_len = 0; + size_t kde_len = 0, extra_len = 0; if (sm->mlo.valid_links) { u8 *pos; @@ -2171,10 +2184,16 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, kde_len = pos - kde; } +#ifdef CONFIG_TESTING_OPTIONS + if (sm->test_eapol_m4_elems) + extra_len = wpabuf_len(sm->test_eapol_m4_elems); +#endif /* CONFIG_TESTING_OPTIONS */ + mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len); hdrlen = sizeof(*reply) + mic_len + 2; rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, - hdrlen + kde_len, &rlen, (void *) &reply); + hdrlen + kde_len + extra_len, &rlen, + (void *) &reply); if (!rbuf) { os_free(kde); return -1; @@ -2198,12 +2217,21 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, WPA_REPLAY_COUNTER_LEN); key_mic = (u8 *) (reply + 1); - WPA_PUT_BE16(key_mic + mic_len, kde_len); /* Key Data length */ + /* Key Data length */ + WPA_PUT_BE16(key_mic + mic_len, kde_len + extra_len); if (kde) { os_memcpy(key_mic + mic_len + 2, kde, kde_len); /* Key Data */ os_free(kde); } +#ifdef CONFIG_TESTING_OPTIONS + if (sm->test_eapol_m4_elems) { + os_memcpy(key_mic + mic_len + 2 + kde_len, + wpabuf_head(sm->test_eapol_m4_elems), + wpabuf_len(sm->test_eapol_m4_elems)); + } +#endif /* CONFIG_TESTING_OPTIONS */ + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4"); return wpa_eapol_key_send(sm, ptk, ver, dst, ETH_P_EAPOL, rbuf, rlen, key_mic); @@ -4039,6 +4067,8 @@ void wpa_sm_deinit(struct wpa_sm *sm) #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_TESTING_OPTIONS wpabuf_free(sm->test_assoc_ie); + wpabuf_free(sm->test_eapol_m2_elems); + wpabuf_free(sm->test_eapol_m4_elems); #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_FILS_SK_PFS crypto_ecdh_deinit(sm->fils_ecdh); @@ -5204,6 +5234,20 @@ void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf) } +void wpa_sm_set_test_eapol_m2_elems(struct wpa_sm *sm, struct wpabuf *buf) +{ + wpabuf_free(sm->test_eapol_m2_elems); + sm->test_eapol_m2_elems = buf; +} + + +void wpa_sm_set_test_eapol_m4_elems(struct wpa_sm *sm, struct wpabuf *buf) +{ + wpabuf_free(sm->test_eapol_m4_elems); + sm->test_eapol_m4_elems = buf; +} + + const u8 * wpa_sm_get_anonce(struct wpa_sm *sm) { return sm->anonce; diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 47a86b04b..d99e5f676 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -585,6 +585,8 @@ extern unsigned int tdls_testing; int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf); void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf); +void wpa_sm_set_test_eapol_m2_elems(struct wpa_sm *sm, struct wpabuf *buf); +void wpa_sm_set_test_eapol_m4_elems(struct wpa_sm *sm, struct wpabuf *buf); const u8 * wpa_sm_get_anonce(struct wpa_sm *sm); unsigned int wpa_sm_get_key_mgmt(struct wpa_sm *sm); diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index 5fe6182ff..aa1d739c5 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -182,6 +182,8 @@ struct wpa_sm { #ifdef CONFIG_TESTING_OPTIONS struct wpabuf *test_assoc_ie; + struct wpabuf *test_eapol_m2_elems; + struct wpabuf *test_eapol_m4_elems; int ft_rsnxe_used; unsigned int oci_freq_override_eapol; unsigned int oci_freq_override_eapol_g2; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 0708fbdff..8317b1a7a 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -8852,6 +8852,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->ft_rsnxe_used = 0; wpa_s->reject_btm_req_reason = 0; wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL); + wpa_sm_set_test_eapol_m2_elems(wpa_s->wpa, NULL); + wpa_sm_set_test_eapol_m4_elems(wpa_s->wpa, NULL); os_free(wpa_s->get_pref_freq_list_override); wpa_s->get_pref_freq_list_override = NULL; wpabuf_free(wpa_s->sae_commit_override); @@ -10152,13 +10154,12 @@ static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd) } -static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s, - const char *cmd) +static int wpas_get_hex_buf(const char *val, struct wpabuf **ret) { struct wpabuf *buf; size_t len; - len = os_strlen(cmd); + len = os_strlen(val); if (len & 1) return -1; len /= 2; @@ -10167,20 +10168,56 @@ static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s, buf = NULL; } else { buf = wpabuf_alloc(len); - if (buf == NULL) + if (!buf) return -1; - if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) { + if (hexstr2bin(val, wpabuf_put(buf, len), len) < 0) { wpabuf_free(buf); return -1; } } + *ret = buf; + return 0; +} + + +static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + struct wpabuf *buf; + + if (wpas_get_hex_buf(cmd, &buf) < 0) + return -1; wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf); return 0; } +static int wpas_ctrl_test_eapol_m2_elems(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + struct wpabuf *buf; + + if (wpas_get_hex_buf(cmd, &buf) < 0) + return -1; + wpa_sm_set_test_eapol_m2_elems(wpa_s->wpa, buf); + return 0; +} + + +static int wpas_ctrl_test_eapol_m4_elems(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + struct wpabuf *buf; + + if (wpas_get_hex_buf(cmd, &buf) < 0) + return -1; + wpa_sm_set_test_eapol_m4_elems(wpa_s->wpa, buf); + return 0; +} + + static int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s) { u8 zero[WPA_TK_MAX_LEN]; @@ -12880,6 +12917,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) { if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0) reply_len = -1; + } else if (os_strncmp(buf, "TEST_EAPOL_M2_ELEMS ", 20) == 0) { + if (wpas_ctrl_test_eapol_m2_elems(wpa_s, buf + 20) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "TEST_EAPOL_M4_ELEMS ", 20) == 0) { + if (wpas_ctrl_test_eapol_m4_elems(wpa_s, buf + 20) < 0) + reply_len = -1; } else if (os_strcmp(buf, "RESET_PN") == 0) { if (wpas_ctrl_reset_pn(wpa_s) < 0) reply_len = -1;