AP: MLO: Handle Multi-Link element during authentication
In case the AP is an AP MLD, parse the Multi-Link element from the Authentication frame, store the relevant information, and prepare the response Multi-Link element. If the AP is not an AP MLD or the parsing of the element fails, continue the authentication flow without MLD support. For SAE, it is needed to skip various fixed fields in the Authentication frame. Implement it for SAE with H2E. TODO: This should be extended to other authentication algorithms which are allowed for MLD connections and have fixed fields in the Authentication frames, according to IEEE P802.11-REVme/D3.0, Table 9-69 (Presence of fields and elements in Authentications frames). This commit doesn't support FILS, FT, etc. Signed-off-by: Ilan Peer <ilan.peer@intel.com> Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
This commit is contained in:
parent
f540d078c9
commit
bcbe80a66a
3 changed files with 319 additions and 14 deletions
|
@ -396,17 +396,38 @@ static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
u8 *buf;
|
u8 *buf;
|
||||||
size_t rlen;
|
size_t rlen;
|
||||||
int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||||
|
const u8 *sa = hapd->own_addr;
|
||||||
|
struct wpabuf *ml_resp = NULL;
|
||||||
|
|
||||||
|
#ifdef CONFIG_IEEE80211BE
|
||||||
|
/*
|
||||||
|
* Once a non-AP MLD is added to the driver, the addressing should use
|
||||||
|
* the MLD MAC address. Thus, use the MLD address instead of translating
|
||||||
|
* the addresses.
|
||||||
|
*/
|
||||||
|
if (hapd->conf->mld_ap && sta && sta->mld_info.mld_sta) {
|
||||||
|
sa = hapd->mld_addr;
|
||||||
|
|
||||||
|
ml_resp = hostapd_ml_auth_resp(hapd);
|
||||||
|
if (!ml_resp)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IEEE80211BE */
|
||||||
|
|
||||||
rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
|
rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
|
||||||
|
if (ml_resp)
|
||||||
|
rlen += wpabuf_len(ml_resp);
|
||||||
buf = os_zalloc(rlen);
|
buf = os_zalloc(rlen);
|
||||||
if (buf == NULL)
|
if (!buf) {
|
||||||
|
wpabuf_free(ml_resp);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
reply = (struct ieee80211_mgmt *) buf;
|
reply = (struct ieee80211_mgmt *) buf;
|
||||||
reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||||
WLAN_FC_STYPE_AUTH);
|
WLAN_FC_STYPE_AUTH);
|
||||||
os_memcpy(reply->da, dst, ETH_ALEN);
|
os_memcpy(reply->da, dst, ETH_ALEN);
|
||||||
os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
|
os_memcpy(reply->sa, sa, ETH_ALEN);
|
||||||
os_memcpy(reply->bssid, bssid, ETH_ALEN);
|
os_memcpy(reply->bssid, bssid, ETH_ALEN);
|
||||||
|
|
||||||
reply->u.auth.auth_alg = host_to_le16(auth_alg);
|
reply->u.auth.auth_alg = host_to_le16(auth_alg);
|
||||||
|
@ -416,6 +437,14 @@ static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
if (ies && ies_len)
|
if (ies && ies_len)
|
||||||
os_memcpy(reply->u.auth.variable, ies, ies_len);
|
os_memcpy(reply->u.auth.variable, ies, ies_len);
|
||||||
|
|
||||||
|
#ifdef CONFIG_IEEE80211BE
|
||||||
|
if (ml_resp)
|
||||||
|
os_memcpy(reply->u.auth.variable + ies_len,
|
||||||
|
wpabuf_head(ml_resp), wpabuf_len(ml_resp));
|
||||||
|
|
||||||
|
wpabuf_free(ml_resp);
|
||||||
|
#endif /* CONFIG_IEEE80211BE */
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
|
wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
|
||||||
" auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
|
" auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
|
||||||
MAC2STR(dst), auth_alg, auth_transaction,
|
MAC2STR(dst), auth_alg, auth_transaction,
|
||||||
|
@ -2748,6 +2777,8 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
size_t resp_ies_len = 0;
|
size_t resp_ies_len = 0;
|
||||||
u16 seq_ctrl;
|
u16 seq_ctrl;
|
||||||
struct radius_sta rad_info;
|
struct radius_sta rad_info;
|
||||||
|
const u8 *dst, *sa, *bssid;
|
||||||
|
bool mld_sta = false;
|
||||||
|
|
||||||
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
|
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
|
||||||
wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
|
wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
|
||||||
|
@ -2765,6 +2796,20 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_TESTING_OPTIONS */
|
#endif /* CONFIG_TESTING_OPTIONS */
|
||||||
|
|
||||||
|
sa = mgmt->sa;
|
||||||
|
#ifdef CONFIG_IEEE80211BE
|
||||||
|
/*
|
||||||
|
* Handle MLO authentication before the station is added to hostapd and
|
||||||
|
* the driver so that the station MLD MAC address would be used in both
|
||||||
|
* hostapd and the driver.
|
||||||
|
*/
|
||||||
|
sa = hostapd_process_ml_auth(hapd, mgmt, len);
|
||||||
|
if (sa)
|
||||||
|
mld_sta = true;
|
||||||
|
else
|
||||||
|
sa = mgmt->sa;
|
||||||
|
#endif /* CONFIG_IEEE80211BE */
|
||||||
|
|
||||||
auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
|
auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
|
||||||
auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
|
auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
|
||||||
status_code = le_to_host16(mgmt->u.auth.status_code);
|
status_code = le_to_host16(mgmt->u.auth.status_code);
|
||||||
|
@ -2780,7 +2825,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
|
wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
|
||||||
"auth_transaction=%d status_code=%d wep=%d%s "
|
"auth_transaction=%d status_code=%d wep=%d%s "
|
||||||
"seq_ctrl=0x%x%s%s",
|
"seq_ctrl=0x%x%s%s",
|
||||||
MAC2STR(mgmt->sa), auth_alg, auth_transaction,
|
MAC2STR(sa), auth_alg, auth_transaction,
|
||||||
status_code, !!(fc & WLAN_FC_ISWEP),
|
status_code, !!(fc & WLAN_FC_ISWEP),
|
||||||
challenge ? " challenge" : "",
|
challenge ? " challenge" : "",
|
||||||
seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
|
seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
|
||||||
|
@ -2846,7 +2891,17 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
|
|
||||||
if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
|
if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
|
||||||
wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
|
wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
|
||||||
MAC2STR(mgmt->sa));
|
MAC2STR(sa));
|
||||||
|
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mld_sta &&
|
||||||
|
(os_memcmp(sa, hapd->own_addr, ETH_ALEN) == 0 ||
|
||||||
|
os_memcmp(sa, hapd->mld_addr, ETH_ALEN) == 0)) {
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"Station " MACSTR " not allowed to authenticate",
|
||||||
|
MAC2STR(sa));
|
||||||
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -2854,7 +2909,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
if (hapd->conf->no_auth_if_seen_on) {
|
if (hapd->conf->no_auth_if_seen_on) {
|
||||||
struct hostapd_data *other;
|
struct hostapd_data *other;
|
||||||
|
|
||||||
other = sta_track_seen_on(hapd->iface, mgmt->sa,
|
other = sta_track_seen_on(hapd->iface, sa,
|
||||||
hapd->conf->no_auth_if_seen_on);
|
hapd->conf->no_auth_if_seen_on);
|
||||||
if (other) {
|
if (other) {
|
||||||
u8 *pos;
|
u8 *pos;
|
||||||
|
@ -2863,7 +2918,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: Reject authentication from "
|
wpa_printf(MSG_DEBUG, "%s: Reject authentication from "
|
||||||
MACSTR " since STA has been seen on %s",
|
MACSTR " since STA has been seen on %s",
|
||||||
hapd->conf->iface, MAC2STR(mgmt->sa),
|
hapd->conf->iface, MAC2STR(sa),
|
||||||
hapd->conf->no_auth_if_seen_on);
|
hapd->conf->no_auth_if_seen_on);
|
||||||
|
|
||||||
resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION;
|
resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION;
|
||||||
|
@ -2906,12 +2961,12 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
|
res = ieee802_11_allowed_address(hapd, sa, (const u8 *) mgmt, len,
|
||||||
&rad_info);
|
&rad_info);
|
||||||
if (res == HOSTAPD_ACL_REJECT) {
|
if (res == HOSTAPD_ACL_REJECT) {
|
||||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
||||||
"Ignore Authentication frame from " MACSTR
|
"Ignore Authentication frame from " MACSTR
|
||||||
" due to ACL reject", MAC2STR(mgmt->sa));
|
" due to ACL reject", MAC2STR(sa));
|
||||||
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -2921,7 +2976,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
#ifdef CONFIG_SAE
|
#ifdef CONFIG_SAE
|
||||||
if (auth_alg == WLAN_AUTH_SAE && !from_queue &&
|
if (auth_alg == WLAN_AUTH_SAE && !from_queue &&
|
||||||
(auth_transaction == 1 ||
|
(auth_transaction == 1 ||
|
||||||
(auth_transaction == 2 && auth_sae_queued_addr(hapd, mgmt->sa)))) {
|
(auth_transaction == 2 && auth_sae_queued_addr(hapd, sa)))) {
|
||||||
/* Handle SAE Authentication commit message through a queue to
|
/* Handle SAE Authentication commit message through a queue to
|
||||||
* provide more control for postponing the needed heavy
|
* provide more control for postponing the needed heavy
|
||||||
* processing under a possible DoS attack scenario. In addition,
|
* processing under a possible DoS attack scenario. In addition,
|
||||||
|
@ -2934,7 +2989,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SAE */
|
#endif /* CONFIG_SAE */
|
||||||
|
|
||||||
sta = ap_get_sta(hapd, mgmt->sa);
|
sta = ap_get_sta(hapd, sa);
|
||||||
if (sta) {
|
if (sta) {
|
||||||
sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
|
sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
|
||||||
sta->ft_over_ds = 0;
|
sta->ft_over_ds = 0;
|
||||||
|
@ -2954,7 +3009,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
sta->plink_state == PLINK_BLOCKED) {
|
sta->plink_state == PLINK_BLOCKED) {
|
||||||
wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
|
wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
|
||||||
" is blocked - drop Authentication frame",
|
" is blocked - drop Authentication frame",
|
||||||
MAC2STR(mgmt->sa));
|
MAC2STR(sa));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_MESH */
|
#endif /* CONFIG_MESH */
|
||||||
|
@ -2974,7 +3029,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
*/
|
*/
|
||||||
wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
|
wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
|
||||||
" not yet known - drop Authentication frame",
|
" not yet known - drop Authentication frame",
|
||||||
MAC2STR(mgmt->sa));
|
MAC2STR(sa));
|
||||||
/*
|
/*
|
||||||
* Save a copy of the frame so that it can be processed
|
* Save a copy of the frame so that it can be processed
|
||||||
* if a new peer entry is added shortly after this.
|
* if a new peer entry is added shortly after this.
|
||||||
|
@ -2986,13 +3041,38 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_MESH */
|
#endif /* CONFIG_MESH */
|
||||||
|
|
||||||
sta = ap_sta_add(hapd, mgmt->sa);
|
sta = ap_sta_add(hapd, sa);
|
||||||
if (!sta) {
|
if (!sta) {
|
||||||
wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
|
wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
|
||||||
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
|
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_IEEE80211BE
|
||||||
|
if (auth_transaction == 1) {
|
||||||
|
os_memset(&sta->mld_info, 0, sizeof(sta->mld_info));
|
||||||
|
|
||||||
|
if (mld_sta) {
|
||||||
|
u8 link_id = hapd->mld_link_id;
|
||||||
|
|
||||||
|
sta->mld_info.mld_sta = true;
|
||||||
|
sta->mld_assoc_link_id = link_id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the MLD address as the station address and the
|
||||||
|
* station addresses.
|
||||||
|
*/
|
||||||
|
os_memcpy(sta->mld_info.common_info.mld_addr, sa,
|
||||||
|
ETH_ALEN);
|
||||||
|
os_memcpy(sta->mld_info.links[link_id].peer_addr,
|
||||||
|
mgmt->sa, ETH_ALEN);
|
||||||
|
os_memcpy(sta->mld_info.links[link_id].local_addr,
|
||||||
|
hapd->own_addr, ETH_ALEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IEEE80211BE */
|
||||||
|
|
||||||
sta->last_seq_ctrl = seq_ctrl;
|
sta->last_seq_ctrl = seq_ctrl;
|
||||||
sta->last_subtype = WLAN_FC_STYPE_AUTH;
|
sta->last_subtype = WLAN_FC_STYPE_AUTH;
|
||||||
#ifdef CONFIG_MBO
|
#ifdef CONFIG_MBO
|
||||||
|
@ -3130,7 +3210,22 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
}
|
}
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
reply_res = send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, auth_alg,
|
dst = mgmt->sa;
|
||||||
|
bssid = mgmt->bssid;
|
||||||
|
|
||||||
|
#ifdef CONFIG_IEEE80211BE
|
||||||
|
/*
|
||||||
|
* Once a non-AP MLD is added to the driver, the addressing should use
|
||||||
|
* the MLD MAC address. It is the responsibility of the driver to
|
||||||
|
* handle the translations.
|
||||||
|
*/
|
||||||
|
if (hapd->conf->mld_ap && sta && sta->mld_info.mld_sta) {
|
||||||
|
dst = sta->addr;
|
||||||
|
bssid = hapd->mld_addr;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IEEE80211BE */
|
||||||
|
|
||||||
|
reply_res = send_auth_reply(hapd, sta, dst, bssid, auth_alg,
|
||||||
auth_alg == WLAN_AUTH_SAE ?
|
auth_alg == WLAN_AUTH_SAE ?
|
||||||
auth_transaction : auth_transaction + 1,
|
auth_transaction : auth_transaction + 1,
|
||||||
resp, resp_ies, resp_ies_len,
|
resp, resp_ies, resp_ies_len,
|
||||||
|
|
|
@ -86,6 +86,10 @@ void hostapd_get_eht_capab(struct hostapd_data *hapd,
|
||||||
size_t len);
|
size_t len);
|
||||||
u8 * hostapd_eid_eht_basic_ml(struct hostapd_data *hapd, u8 *eid,
|
u8 * hostapd_eid_eht_basic_ml(struct hostapd_data *hapd, u8 *eid,
|
||||||
struct sta_info *info, bool include_mld_id);
|
struct sta_info *info, bool include_mld_id);
|
||||||
|
struct wpabuf * hostapd_ml_auth_resp(struct hostapd_data *hapd);
|
||||||
|
const u8 * hostapd_process_ml_auth(struct hostapd_data *hapd,
|
||||||
|
const struct ieee80211_mgmt *mgmt,
|
||||||
|
size_t len);
|
||||||
int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
|
int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
const u8 *ht_capab);
|
const u8 *ht_capab);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "utils/includes.h"
|
#include "utils/includes.h"
|
||||||
#include "utils/common.h"
|
#include "utils/common.h"
|
||||||
|
#include "crypto/dh_groups.h"
|
||||||
#include "hostapd.h"
|
#include "hostapd.h"
|
||||||
#include "sta_info.h"
|
#include "sta_info.h"
|
||||||
#include "ieee802_11.h"
|
#include "ieee802_11.h"
|
||||||
|
@ -621,3 +622,208 @@ out:
|
||||||
wpabuf_free(buf);
|
wpabuf_free(buf);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct wpabuf * hostapd_ml_auth_resp(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
struct wpabuf *buf = wpabuf_alloc(12);
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
|
||||||
|
wpabuf_put_u8(buf, 10);
|
||||||
|
wpabuf_put_u8(buf, WLAN_EID_EXT_MULTI_LINK);
|
||||||
|
wpabuf_put_le16(buf, MULTI_LINK_CONTROL_TYPE_BASIC);
|
||||||
|
wpabuf_put_u8(buf, ETH_ALEN + 1);
|
||||||
|
wpabuf_put_data(buf, hapd->mld_addr, ETH_ALEN);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const u8 *
|
||||||
|
sae_commit_skip_fixed_fields(const struct ieee80211_mgmt *mgmt, size_t len,
|
||||||
|
const u8 *pos, u16 status_code)
|
||||||
|
{
|
||||||
|
u16 group;
|
||||||
|
size_t prime_len;
|
||||||
|
struct crypto_ec *ec;
|
||||||
|
|
||||||
|
if (status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT)
|
||||||
|
return pos;
|
||||||
|
|
||||||
|
/* SAE H2E commit message (group, scalar, FFE) */
|
||||||
|
if (len < 2) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"EHT: SAE Group is not present");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
group = WPA_GET_LE16(pos);
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
/* TODO: How to parse when the group is unknown? */
|
||||||
|
ec = crypto_ec_init(group);
|
||||||
|
if (!ec) {
|
||||||
|
const struct dh_group *dh = dh_groups_get(group);
|
||||||
|
|
||||||
|
if (!dh) {
|
||||||
|
wpa_printf(MSG_DEBUG, "EHT: Unknown SAE group %u",
|
||||||
|
group);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
prime_len = dh->prime_len;
|
||||||
|
} else {
|
||||||
|
prime_len = crypto_ec_prime_len(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "EHT: SAE scalar length is %zu", prime_len);
|
||||||
|
|
||||||
|
/* scalar */
|
||||||
|
pos += prime_len;
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
pos += prime_len * 2;
|
||||||
|
crypto_ec_deinit(ec);
|
||||||
|
} else {
|
||||||
|
pos += prime_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos - mgmt->u.auth.variable > (int) len) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"EHT: Too short SAE commit Authentication frame");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_hexdump(MSG_DEBUG, "EHT: SAE: Authentication frame elements",
|
||||||
|
pos, (int) len - (pos - mgmt->u.auth.variable));
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const u8 *
|
||||||
|
sae_confirm_skip_fixed_fields(struct hostapd_data *hapd,
|
||||||
|
const struct ieee80211_mgmt *mgmt, size_t len,
|
||||||
|
const u8 *pos, u16 status_code)
|
||||||
|
{
|
||||||
|
struct sta_info *sta;
|
||||||
|
|
||||||
|
if (status_code == WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION)
|
||||||
|
return pos;
|
||||||
|
|
||||||
|
/* send confirm integer */
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At this stage we should already have an MLD station and actually SA
|
||||||
|
* will be replaced with the MLD MAC address by the driver.
|
||||||
|
*/
|
||||||
|
sta = ap_get_sta(hapd, mgmt->sa);
|
||||||
|
if (!sta) {
|
||||||
|
wpa_printf(MSG_DEBUG, "SAE: No MLD STA for SAE confirm");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sta->sae || sta->sae->state < SAE_COMMITTED || !sta->sae->tmp) {
|
||||||
|
if (sta->sae)
|
||||||
|
wpa_printf(MSG_DEBUG, "SAE: Invalid state=%u",
|
||||||
|
sta->sae->state);
|
||||||
|
else
|
||||||
|
wpa_printf(MSG_DEBUG, "SAE: No SAE context");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "SAE: confirm: kck_len=%zu",
|
||||||
|
sta->sae->tmp->kck_len);
|
||||||
|
|
||||||
|
pos += sta->sae->tmp->kck_len;
|
||||||
|
|
||||||
|
if (pos - mgmt->u.auth.variable > (int) len) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"EHT: Too short SAE confirm Authentication frame");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const u8 * auth_skip_fixed_fields(struct hostapd_data *hapd,
|
||||||
|
const struct ieee80211_mgmt *mgmt,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
|
||||||
|
u16 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
|
||||||
|
u16 status_code = le_to_host16(mgmt->u.auth.status_code);
|
||||||
|
const u8 *pos = mgmt->u.auth.variable;
|
||||||
|
|
||||||
|
/* Skip fixed fields as based on IEE P802.11-REVme/D3.0, Table 9-69
|
||||||
|
* (Presence of fields and elements in Authentications frames) */
|
||||||
|
switch (auth_alg) {
|
||||||
|
case WLAN_AUTH_OPEN:
|
||||||
|
return pos;
|
||||||
|
case WLAN_AUTH_SAE:
|
||||||
|
if (auth_transaction == 1) {
|
||||||
|
if (status_code == WLAN_STATUS_SUCCESS) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"EHT: SAE H2E is mandatory for MLD");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sae_commit_skip_fixed_fields(mgmt, len, pos,
|
||||||
|
status_code);
|
||||||
|
} else if (auth_transaction == 2) {
|
||||||
|
return sae_confirm_skip_fixed_fields(hapd, mgmt, len,
|
||||||
|
pos, status_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
/* TODO: Support additional algorithms that can be used for MLO */
|
||||||
|
case WLAN_AUTH_FT:
|
||||||
|
case WLAN_AUTH_FILS_SK:
|
||||||
|
case WLAN_AUTH_FILS_SK_PFS:
|
||||||
|
case WLAN_AUTH_FILS_PK:
|
||||||
|
case WLAN_AUTH_PASN:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"TODO: Authentication algorithm %u not supported with MLD",
|
||||||
|
auth_alg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const u8 * hostapd_process_ml_auth(struct hostapd_data *hapd,
|
||||||
|
const struct ieee80211_mgmt *mgmt,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
struct ieee802_11_elems elems;
|
||||||
|
const u8 *pos;
|
||||||
|
|
||||||
|
if (!hapd->conf->mld_ap)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
len -= offsetof(struct ieee80211_mgmt, u.auth.variable);
|
||||||
|
|
||||||
|
pos = auth_skip_fixed_fields(hapd, mgmt, len);
|
||||||
|
if (!pos)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (ieee802_11_parse_elems(pos,
|
||||||
|
(int)len - (pos - mgmt->u.auth.variable),
|
||||||
|
&elems, 0) == ParseFailed) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"MLD: Failed parsing Authentication frame");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!elems.basic_mle || !elems.basic_mle_len)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return get_basic_mle_mld_addr(elems.basic_mle, elems.basic_mle_len);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue