From 694a1c68739954f40d6d3f95ecc96557a33f27c9 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Tue, 6 Dec 2022 11:46:05 +0200 Subject: [PATCH] SAE: Make sme_sae_auth() return IE offset Authentication frames include several fixed body parts (see Table 9-68 (Authentication frame body) and Table 9-69 (Presence of fields and elements in Authentication frames) in IEEE P802.11-REVme/D2.0). To be able to parse the IE part, these fields need to be skipped. Since SAE logic already implements this parsing, change SAE authentication handling functions to return the offset to the IE part. This preparation is needed for future MLD patches that need to parse out the ML related elements in the Authentication frames. Signed-off-by: Andrei Otcheretianski --- src/ap/ieee802_11.c | 6 ++++-- src/common/common_module_tests.c | 2 +- src/common/sae.c | 12 ++++++++++-- src/common/sae.h | 5 +++-- src/pasn/pasn_initiator.c | 4 ++-- src/pasn/pasn_responder.c | 4 ++-- tests/fuzzing/sae/sae.c | 6 ++++-- wpa_supplicant/sme.c | 17 ++++++++++++----- 8 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 490dbcbe9..e53f0dcbe 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -1373,7 +1373,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, mgmt->u.auth.variable, &token, &token_len, groups, status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT || - status_code == WLAN_STATUS_SAE_PK); + status_code == WLAN_STATUS_SAE_PK, + NULL); if (resp == SAE_SILENTLY_DISCARD) { wpa_printf(MSG_DEBUG, "SAE: Drop commit message from " MACSTR " due to reflection attack", @@ -1473,7 +1474,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, return; } - if (sae_check_confirm(sta->sae, var, var_len) < 0) { + if (sae_check_confirm(sta->sae, var, var_len, + NULL) < 0) { resp = WLAN_STATUS_CHALLENGE_FAIL; goto reply; } diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c index 8aba713f9..a95ae36dc 100644 --- a/src/common/common_module_tests.c +++ b/src/common/common_module_tests.c @@ -428,7 +428,7 @@ static int sae_tests(void) } if (sae_parse_commit(&sae, peer_commit, sizeof(peer_commit), NULL, NULL, - NULL, 0) != 0 || + NULL, 0, NULL) != 0 || sae_process_commit(&sae) < 0) goto fail; diff --git a/src/common/sae.c b/src/common/sae.c index 8e78c96f3..d4a196f15 100644 --- a/src/common/sae.c +++ b/src/common/sae.c @@ -2157,7 +2157,7 @@ static int sae_parse_akm_suite_selector(struct sae_data *sae, u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, const u8 **token, size_t *token_len, int *allowed_groups, - int h2e) + int h2e, int *ie_offset) { const u8 *pos = data, *end = data + len; u16 res; @@ -2183,6 +2183,9 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, if (res != WLAN_STATUS_SUCCESS) return res; + if (ie_offset) + *ie_offset = pos - data; + /* Optional Password Identifier element */ res = sae_parse_password_identifier(sae, &pos, end); if (res != WLAN_STATUS_SUCCESS) @@ -2376,7 +2379,8 @@ int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf) } -int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len) +int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len, + int *ie_offset) { u8 verifier[SAE_MAX_HASH_LEN]; size_t hash_len; @@ -2432,6 +2436,10 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len) return -1; #endif /* CONFIG_SAE_PK */ + /* 2 bytes are for send-confirm, then the hash, followed by IEs */ + if (ie_offset) + *ie_offset = 2 + hash_len; + return 0; } diff --git a/src/common/sae.h b/src/common/sae.h index 6a6b0c824..c446da396 100644 --- a/src/common/sae.h +++ b/src/common/sae.h @@ -136,9 +136,10 @@ int sae_write_commit(struct sae_data *sae, struct wpabuf *buf, const struct wpabuf *token, const char *identifier); u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, const u8 **token, size_t *token_len, int *allowed_groups, - int h2e); + int h2e, int *ie_offset); int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf); -int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len); +int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len, + int *ie_offset); u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group); const char * sae_state_txt(enum sae_state state); size_t sae_ecc_prime_len_2_hash_len(size_t prime_len); diff --git a/src/pasn/pasn_initiator.c b/src/pasn/pasn_initiator.c index a98eba20c..1f9a50830 100644 --- a/src/pasn/pasn_initiator.c +++ b/src/pasn/pasn_initiator.c @@ -108,7 +108,7 @@ static int wpas_pasn_wd_sae_rx(struct pasn_data *pasn, struct wpabuf *wd) } res = sae_parse_commit(&pasn->sae, data + 6, len - 6, NULL, 0, groups, - 1); + 1, NULL); if (res != WLAN_STATUS_SUCCESS) { wpa_printf(MSG_DEBUG, "PASN: SAE failed parsing commit"); return -1; @@ -151,7 +151,7 @@ static int wpas_pasn_wd_sae_rx(struct pasn_data *pasn, struct wpabuf *wd) return -1; } - res = sae_check_confirm(&pasn->sae, data + 6, len - 6); + res = sae_check_confirm(&pasn->sae, data + 6, len - 6, NULL); if (res != WLAN_STATUS_SUCCESS) { wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm"); return -1; diff --git a/src/pasn/pasn_responder.c b/src/pasn/pasn_responder.c index e36aa39b8..3b1912df3 100644 --- a/src/pasn/pasn_responder.c +++ b/src/pasn/pasn_responder.c @@ -85,7 +85,7 @@ static int pasn_wd_handle_sae_commit(struct pasn_data *pasn, } res = sae_parse_commit(&pasn->sae, data + 6, buf_len - 6, NULL, 0, - groups, 0); + groups, 0, NULL); if (res != WLAN_STATUS_SUCCESS) { wpa_printf(MSG_DEBUG, "PASN: Failed parsing SAE commit"); return -1; @@ -135,7 +135,7 @@ static int pasn_wd_handle_sae_confirm(struct pasn_data *pasn, return -1; } - res = sae_check_confirm(&pasn->sae, data + 6, buf_len - 6); + res = sae_check_confirm(&pasn->sae, data + 6, buf_len - 6, NULL); if (res != WLAN_STATUS_SUCCESS) { wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm"); return -1; diff --git a/tests/fuzzing/sae/sae.c b/tests/fuzzing/sae/sae.c index 8819a4abb..738a8f615 100644 --- a/tests/fuzzing/sae/sae.c +++ b/tests/fuzzing/sae/sae.c @@ -27,10 +27,12 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) return 0; os_memset(&sae, 0, sizeof(sae)); - res = sae_parse_commit(&sae, data, size, &token, &token_len, groups, 0); + res = sae_parse_commit(&sae, data, size, &token, &token_len, groups, 0, + NULL); wpa_printf(MSG_DEBUG, "sae_parse_commit(0): %u", res); sae_clear_data(&sae); - res = sae_parse_commit(&sae, data, size, &token, &token_len, groups, 1); + res = sae_parse_commit(&sae, data, size, &token, &token_len, groups, 1, + NULL); wpa_printf(MSG_DEBUG, "sae_parse_commit(1): %u", res); sae_clear_data(&sae); os_program_deinit(); diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 7095edbe5..dce8a5563 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -1344,7 +1344,7 @@ static int sme_check_sae_rejected_groups(struct wpa_supplicant *wpa_s, static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, u16 status_code, const u8 *data, size_t len, - int external, const u8 *sa) + int external, const u8 *sa, int *ie_offset) { int *groups; @@ -1408,6 +1408,10 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, } token_len = elen - 1; } + + if (ie_offset) + *ie_offset = token_pos + token_len - data; + wpa_s->sme.sae_token = wpabuf_alloc_copy(token_pos, token_len); if (!wpa_s->sme.sae_token) { wpa_dbg(wpa_s, MSG_ERROR, @@ -1509,7 +1513,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL, groups, status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT || - status_code == WLAN_STATUS_SAE_PK); + status_code == WLAN_STATUS_SAE_PK, + ie_offset); if (res == SAE_SILENTLY_DISCARD) { wpa_printf(MSG_DEBUG, "SAE: Drop commit message due to reflection attack"); @@ -1544,7 +1549,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm"); if (wpa_s->sme.sae.state != SAE_CONFIRMED) return -1; - if (sae_check_confirm(&wpa_s->sme.sae, data, len) < 0) + if (sae_check_confirm(&wpa_s->sme.sae, data, len, + ie_offset) < 0) return -1; wpa_s->sme.sae.state = SAE_ACCEPTED; sae_clear_temp_data(&wpa_s->sme.sae); @@ -1616,7 +1622,7 @@ void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s, wpa_s, le_to_host16(header->u.auth.auth_transaction), le_to_host16(header->u.auth.status_code), header->u.auth.variable, - len - auth_length, 1, header->sa); + len - auth_length, 1, header->sa, NULL); if (res < 0) { /* Notify failure to the driver */ sme_send_external_auth_status( @@ -1674,7 +1680,8 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) int res; res = sme_sae_auth(wpa_s, data->auth.auth_transaction, data->auth.status_code, data->auth.ies, - data->auth.ies_len, 0, data->auth.peer); + data->auth.ies_len, 0, data->auth.peer, + NULL); if (res < 0) { wpas_connection_failed(wpa_s, wpa_s->pending_bssid); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);