SAE: Support external authentication offload for driver-SME cases
Extend the SME functionality to support the external authentication. External authentication may be used by the drivers that do not define separate commands for authentication and association (~WPA_DRIVER_FLAGS_SME) but rely on wpa_supplicant's SME for the authentication. Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
parent
3382224082
commit
5ff39c1380
6 changed files with 276 additions and 20 deletions
|
@ -1036,4 +1036,14 @@ static inline int wpa_drv_update_connect_params(
|
|||
mask);
|
||||
}
|
||||
|
||||
static inline int
|
||||
wpa_drv_send_external_auth_status(struct wpa_supplicant *wpa_s,
|
||||
struct external_auth *params)
|
||||
{
|
||||
if (!wpa_s->driver->send_external_auth_status)
|
||||
return -1;
|
||||
return wpa_s->driver->send_external_auth_status(wpa_s->drv_priv,
|
||||
params);
|
||||
}
|
||||
|
||||
#endif /* DRIVER_I_H */
|
||||
|
|
|
@ -4267,6 +4267,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
|||
break;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
if (stype == WLAN_FC_STYPE_AUTH &&
|
||||
!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
|
||||
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
|
||||
sme_external_auth_mgmt_rx(
|
||||
wpa_s, data->rx_mgmt.frame,
|
||||
data->rx_mgmt.frame_len);
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received "
|
||||
"management frame in non-AP mode");
|
||||
break;
|
||||
|
@ -4579,6 +4589,15 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
|||
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_BEACON_LOSS);
|
||||
bgscan_notify_beacon_loss(wpa_s);
|
||||
break;
|
||||
case EVENT_EXTERNAL_AUTH:
|
||||
#ifdef CONFIG_SAE
|
||||
if (!wpa_s->current_ssid) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: current_ssid is NULL");
|
||||
break;
|
||||
}
|
||||
sme_external_auth_trigger(wpa_s, data);
|
||||
#endif /* CONFIG_SAE */
|
||||
break;
|
||||
default:
|
||||
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
|
||||
break;
|
||||
|
|
|
@ -83,7 +83,7 @@ static int sme_set_sae_group(struct wpa_supplicant *wpa_s)
|
|||
|
||||
static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_ssid *ssid,
|
||||
const u8 *bssid)
|
||||
const u8 *bssid, int external)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
size_t len;
|
||||
|
@ -126,16 +126,18 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
|
|||
buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_put_le16(buf, 1); /* Transaction seq# */
|
||||
wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
|
||||
if (!external) {
|
||||
wpabuf_put_le16(buf, 1); /* Transaction seq# */
|
||||
wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
|
||||
}
|
||||
sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s)
|
||||
static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s,
|
||||
int external)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
|
||||
|
@ -143,8 +145,10 @@ static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s)
|
|||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_put_le16(buf, 2); /* Transaction seq# */
|
||||
wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
|
||||
if (!external) {
|
||||
wpabuf_put_le16(buf, 2); /* Transaction seq# */
|
||||
wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
|
||||
}
|
||||
sae_write_confirm(&wpa_s->sme.sae, buf);
|
||||
|
||||
return buf;
|
||||
|
@ -554,9 +558,9 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
|
|||
if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE) {
|
||||
if (start)
|
||||
resp = sme_auth_build_sae_commit(wpa_s, ssid,
|
||||
bss->bssid);
|
||||
bss->bssid, 0);
|
||||
else
|
||||
resp = sme_auth_build_sae_confirm(wpa_s);
|
||||
resp = sme_auth_build_sae_confirm(wpa_s, 0);
|
||||
if (resp == NULL) {
|
||||
wpas_connection_failed(wpa_s, bss->bssid);
|
||||
return;
|
||||
|
@ -789,8 +793,150 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
|
|||
|
||||
#ifdef CONFIG_SAE
|
||||
|
||||
static int sme_external_auth_build_buf(struct wpabuf *buf,
|
||||
struct wpabuf *params,
|
||||
const u8 *sa, const u8 *da,
|
||||
u16 auth_transaction, u16 seq_num)
|
||||
{
|
||||
struct ieee80211_mgmt *resp;
|
||||
|
||||
resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
|
||||
u.auth.variable));
|
||||
|
||||
resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
|
||||
(WLAN_FC_STYPE_AUTH << 4));
|
||||
os_memcpy(resp->da, da, ETH_ALEN);
|
||||
os_memcpy(resp->sa, sa, ETH_ALEN);
|
||||
os_memcpy(resp->bssid, da, ETH_ALEN);
|
||||
resp->u.auth.auth_alg = WLAN_AUTH_SAE;
|
||||
resp->seq_ctrl = seq_num << 4;
|
||||
resp->u.auth.auth_transaction = auth_transaction;
|
||||
resp->u.auth.status_code = WLAN_STATUS_SUCCESS;
|
||||
if (params)
|
||||
wpabuf_put_buf(buf, params);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
|
||||
const u8 *bssid,
|
||||
struct wpa_ssid *ssid)
|
||||
{
|
||||
struct wpabuf *resp, *buf;
|
||||
|
||||
resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1);
|
||||
if (!resp)
|
||||
return;
|
||||
|
||||
wpa_s->sme.sae.state = SAE_COMMITTED;
|
||||
buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + wpabuf_len(resp));
|
||||
if (!buf) {
|
||||
wpabuf_free(resp);
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_s->sme.seq_num++;
|
||||
sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
|
||||
bssid, 1, wpa_s->sme.seq_num);
|
||||
wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
|
||||
wpabuf_free(resp);
|
||||
wpabuf_free(buf);
|
||||
}
|
||||
|
||||
|
||||
static void sme_send_external_auth_status(struct wpa_supplicant *wpa_s,
|
||||
u16 status)
|
||||
{
|
||||
struct external_auth params;
|
||||
|
||||
os_memset(¶ms, 0, sizeof(params));
|
||||
params.status = status;
|
||||
os_memcpy(params.ssid, wpa_s->sme.ext_auth.ssid,
|
||||
wpa_s->sme.ext_auth.ssid_len);
|
||||
params.ssid_len = wpa_s->sme.ext_auth.ssid_len;
|
||||
os_memcpy(params.bssid, wpa_s->sme.ext_auth.bssid, ETH_ALEN);
|
||||
wpa_drv_send_external_auth_status(wpa_s, ¶ms);
|
||||
}
|
||||
|
||||
|
||||
static void sme_handle_external_auth_start(struct wpa_supplicant *wpa_s,
|
||||
union wpa_event_data *data)
|
||||
{
|
||||
struct wpa_ssid *ssid;
|
||||
size_t ssid_str_len = data->external_auth.ssid_len;
|
||||
u8 *ssid_str = data->external_auth.ssid;
|
||||
|
||||
/* Get the SSID conf from the ssid string obtained */
|
||||
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
|
||||
if (!wpas_network_disabled(wpa_s, ssid) &&
|
||||
ssid_str_len == ssid->ssid_len &&
|
||||
os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0)
|
||||
break;
|
||||
}
|
||||
if (ssid)
|
||||
sme_external_auth_send_sae_commit(wpa_s,
|
||||
data->external_auth.bssid,
|
||||
ssid);
|
||||
else
|
||||
sme_send_external_auth_status(wpa_s,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s,
|
||||
const u8 *da)
|
||||
{
|
||||
struct wpabuf *resp, *buf;
|
||||
|
||||
resp = sme_auth_build_sae_confirm(wpa_s, 1);
|
||||
if (!resp) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Confirm message buf alloc failure");
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_s->sme.sae.state = SAE_CONFIRMED;
|
||||
buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN + wpabuf_len(resp));
|
||||
if (!buf) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Auth Confirm buf alloc failure");
|
||||
wpabuf_free(resp);
|
||||
return;
|
||||
}
|
||||
wpa_s->sme.seq_num++;
|
||||
sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
|
||||
da, 2, wpa_s->sme.seq_num);
|
||||
wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
|
||||
wpabuf_free(resp);
|
||||
wpabuf_free(buf);
|
||||
}
|
||||
|
||||
|
||||
void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
|
||||
union wpa_event_data *data)
|
||||
{
|
||||
if (RSN_SELECTOR_GET(&data->external_auth.key_mgmt_suite) !=
|
||||
RSN_AUTH_KEY_MGMT_SAE)
|
||||
return;
|
||||
|
||||
if (data->external_auth.action == EXT_AUTH_START) {
|
||||
os_memcpy(&wpa_s->sme.ext_auth, data,
|
||||
sizeof(struct external_auth));
|
||||
wpa_s->sme.seq_num = 0;
|
||||
wpa_s->sme.sae.state = SAE_NOTHING;
|
||||
wpa_s->sme.sae.send_confirm = 0;
|
||||
wpa_s->sme.sae_group_index = 0;
|
||||
sme_handle_external_auth_start(wpa_s, data);
|
||||
} else if (data->external_auth.action == EXT_AUTH_ABORT) {
|
||||
/* Report failure to driver for the wrong trigger */
|
||||
sme_send_external_auth_status(wpa_s,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
|
||||
u16 status_code, const u8 *data, size_t len)
|
||||
u16 status_code, const u8 *data, size_t len,
|
||||
int external, const u8 *sa)
|
||||
{
|
||||
int *groups;
|
||||
|
||||
|
@ -800,7 +946,7 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
|
|||
if (auth_transaction == 1 &&
|
||||
status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
|
||||
wpa_s->sme.sae.state == SAE_COMMITTED &&
|
||||
wpa_s->current_bss && wpa_s->current_ssid) {
|
||||
(external || wpa_s->current_bss) && wpa_s->current_ssid) {
|
||||
int default_groups[] = { 19, 20, 21, 25, 26, 0 };
|
||||
u16 group;
|
||||
|
||||
|
@ -827,22 +973,32 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
|
|||
wpabuf_free(wpa_s->sme.sae_token);
|
||||
wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16),
|
||||
len - sizeof(le16));
|
||||
sme_send_authentication(wpa_s, wpa_s->current_bss,
|
||||
wpa_s->current_ssid, 1);
|
||||
if (!external)
|
||||
sme_send_authentication(wpa_s, wpa_s->current_bss,
|
||||
wpa_s->current_ssid, 1);
|
||||
else
|
||||
sme_external_auth_send_sae_commit(
|
||||
wpa_s, wpa_s->sme.ext_auth.bssid,
|
||||
wpa_s->current_ssid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (auth_transaction == 1 &&
|
||||
status_code == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
|
||||
wpa_s->sme.sae.state == SAE_COMMITTED &&
|
||||
wpa_s->current_bss && wpa_s->current_ssid) {
|
||||
(external || wpa_s->current_bss) && wpa_s->current_ssid) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
|
||||
wpa_s->sme.sae_group_index++;
|
||||
if (sme_set_sae_group(wpa_s) < 0)
|
||||
return -1; /* no other groups enabled */
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Try next enabled SAE group");
|
||||
sme_send_authentication(wpa_s, wpa_s->current_bss,
|
||||
wpa_s->current_ssid, 1);
|
||||
if (!external)
|
||||
sme_send_authentication(wpa_s, wpa_s->current_bss,
|
||||
wpa_s->current_ssid, 1);
|
||||
else
|
||||
sme_external_auth_send_sae_commit(
|
||||
wpa_s, wpa_s->sme.ext_auth.bssid,
|
||||
wpa_s->current_ssid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -855,7 +1011,7 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
|
|||
groups = wpa_s->conf->sae_groups;
|
||||
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
|
||||
if (wpa_s->current_bss == NULL ||
|
||||
if ((!external && wpa_s->current_bss == NULL) ||
|
||||
wpa_s->current_ssid == NULL)
|
||||
return -1;
|
||||
if (wpa_s->sme.sae.state != SAE_COMMITTED)
|
||||
|
@ -880,8 +1036,11 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
|
|||
|
||||
wpabuf_free(wpa_s->sme.sae_token);
|
||||
wpa_s->sme.sae_token = NULL;
|
||||
sme_send_authentication(wpa_s, wpa_s->current_bss,
|
||||
wpa_s->current_ssid, 0);
|
||||
if (!external)
|
||||
sme_send_authentication(wpa_s, wpa_s->current_bss,
|
||||
wpa_s->current_ssid, 0);
|
||||
else
|
||||
sme_external_auth_send_sae_confirm(wpa_s, sa);
|
||||
return 0;
|
||||
} else if (auth_transaction == 2) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
|
||||
|
@ -891,11 +1050,59 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
|
|||
return -1;
|
||||
wpa_s->sme.sae.state = SAE_ACCEPTED;
|
||||
sae_clear_temp_data(&wpa_s->sme.sae);
|
||||
|
||||
if (external) {
|
||||
/* Report success to driver */
|
||||
sme_send_external_auth_status(wpa_s,
|
||||
WLAN_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
|
||||
const u8 *auth_frame, size_t len)
|
||||
{
|
||||
const struct ieee80211_mgmt *header;
|
||||
size_t auth_length;
|
||||
|
||||
header = (const struct ieee80211_mgmt *) auth_frame;
|
||||
auth_length = IEEE80211_HDRLEN + sizeof(header->u.auth);
|
||||
|
||||
if (len < auth_length) {
|
||||
/* Notify failure to the driver */
|
||||
sme_send_external_auth_status(wpa_s,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (header->u.auth.auth_alg == WLAN_AUTH_SAE) {
|
||||
int res;
|
||||
|
||||
res = sme_sae_auth(wpa_s, header->u.auth.auth_transaction,
|
||||
header->u.auth.status_code,
|
||||
header->u.auth.variable,
|
||||
len - auth_length, 1, header->sa);
|
||||
if (res < 0) {
|
||||
/* Notify failure to the driver */
|
||||
sme_send_external_auth_status(
|
||||
wpa_s, WLAN_STATUS_UNSPECIFIED_FAILURE);
|
||||
return;
|
||||
}
|
||||
if (res != 1)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"SME: SAE completed - setting PMK for 4-way handshake");
|
||||
wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
|
||||
wpa_s->sme.sae.pmkid, wpa_s->pending_bssid);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
|
||||
|
@ -936,7 +1143,7 @@ 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);
|
||||
data->auth.ies_len, 0, NULL);
|
||||
if (res < 0) {
|
||||
wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
|
||||
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
|
||||
|
|
|
@ -38,6 +38,10 @@ void sme_deinit(struct wpa_supplicant *wpa_s);
|
|||
|
||||
int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
|
||||
void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable);
|
||||
void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
|
||||
union wpa_event_data *data);
|
||||
void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
|
||||
const u8 *auth_frame, size_t len);
|
||||
|
||||
#else /* CONFIG_SME */
|
||||
|
||||
|
@ -113,6 +117,16 @@ static inline void sme_sched_obss_scan(struct wpa_supplicant *wpa_s,
|
|||
{
|
||||
}
|
||||
|
||||
static inline void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
|
||||
union wpa_event_data *data)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
|
||||
const u8 *auth_frame, size_t len)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SME */
|
||||
|
||||
#endif /* SME_H */
|
||||
|
|
|
@ -2473,6 +2473,10 @@ static u8 * wpas_populate_assoc_ies(
|
|||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
#endif /* IEEE8021X_EAPOL */
|
||||
#ifdef CONFIG_SAE
|
||||
if (wpa_s->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE))
|
||||
algs = WPA_AUTH_ALG_SAE;
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
|
||||
if (ssid->auth_alg) {
|
||||
|
|
|
@ -789,6 +789,8 @@ struct wpa_supplicant {
|
|||
struct wpabuf *sae_token;
|
||||
int sae_group_index;
|
||||
unsigned int sae_pmksa_caching:1;
|
||||
u16 seq_num;
|
||||
struct external_auth ext_auth;
|
||||
#endif /* CONFIG_SAE */
|
||||
} sme;
|
||||
#endif /* CONFIG_SME */
|
||||
|
|
Loading…
Reference in a new issue