PASN: Add support for comeback flow to wpa_supplicant
Process the received comeback cookie and retry automatically if the AP allows this. Otherwise, provide the cookie to upper layers to allow a later attempt with the cookie. Signed-off-by: Ilan Peer <ilan.peer@intel.com>
This commit is contained in:
parent
ab623ac750
commit
67014b3f74
3 changed files with 124 additions and 16 deletions
|
@ -10598,15 +10598,18 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
|
||||||
u8 bssid[ETH_ALEN];
|
u8 bssid[ETH_ALEN];
|
||||||
int akmp = -1, cipher = -1, got_bssid = 0;
|
int akmp = -1, cipher = -1, got_bssid = 0;
|
||||||
u16 group = 0xFFFF;
|
u16 group = 0xFFFF;
|
||||||
int id = 0;
|
u8 *comeback = NULL;
|
||||||
|
size_t comeback_len = 0;
|
||||||
|
int id = 0, ret = -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Entry format: bssid=<BSSID> akmp=<AKMP> cipher=<CIPHER> group=<group>
|
* Entry format: bssid=<BSSID> akmp=<AKMP> cipher=<CIPHER> group=<group>
|
||||||
|
* [comeback=<hexdump>]
|
||||||
*/
|
*/
|
||||||
while ((token = str_token(cmd, " ", &context))) {
|
while ((token = str_token(cmd, " ", &context))) {
|
||||||
if (os_strncmp(token, "bssid=", 6) == 0) {
|
if (os_strncmp(token, "bssid=", 6) == 0) {
|
||||||
if (hwaddr_aton(token + 6, bssid))
|
if (hwaddr_aton(token + 6, bssid))
|
||||||
return -1;
|
goto out;
|
||||||
got_bssid = 1;
|
got_bssid = 1;
|
||||||
} else if (os_strcmp(token, "akmp=PASN") == 0) {
|
} else if (os_strcmp(token, "akmp=PASN") == 0) {
|
||||||
akmp = WPA_KEY_MGMT_PASN;
|
akmp = WPA_KEY_MGMT_PASN;
|
||||||
|
@ -10640,20 +10643,34 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
|
||||||
group = atoi(token + 6);
|
group = atoi(token + 6);
|
||||||
} else if (os_strncmp(token, "nid=", 4) == 0) {
|
} else if (os_strncmp(token, "nid=", 4) == 0) {
|
||||||
id = atoi(token + 4);
|
id = atoi(token + 4);
|
||||||
|
} else if (os_strncmp(token, "comeback=", 9) == 0) {
|
||||||
|
comeback_len = os_strlen(token + 9);
|
||||||
|
if (comeback || !comeback_len || comeback_len % 2)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
comeback_len /= 2;
|
||||||
|
comeback = os_malloc(comeback_len);
|
||||||
|
if (!comeback ||
|
||||||
|
hexstr2bin(token + 9, comeback, comeback_len))
|
||||||
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
"CTRL: PASN Invalid parameter: '%s'",
|
"CTRL: PASN Invalid parameter: '%s'",
|
||||||
token);
|
token);
|
||||||
return -1;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!got_bssid || akmp == -1 || cipher == -1 || group == 0xFFFF) {
|
if (!got_bssid || akmp == -1 || cipher == -1 || group == 0xFFFF) {
|
||||||
wpa_printf(MSG_DEBUG,"CTRL: PASN missing parameter");
|
wpa_printf(MSG_DEBUG,"CTRL: PASN missing parameter");
|
||||||
return -1;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
return wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id);
|
ret = wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id,
|
||||||
|
comeback, comeback_len);
|
||||||
|
out:
|
||||||
|
os_free(comeback);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ struct wpa_pasn_auth_work {
|
||||||
int cipher;
|
int cipher;
|
||||||
u16 group;
|
u16 group;
|
||||||
int network_id;
|
int network_id;
|
||||||
|
struct wpabuf *comeback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,8 +57,30 @@ static void wpas_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s)
|
||||||
|
|
||||||
|
|
||||||
static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||||
int akmp, int cipher, u8 status)
|
int akmp, int cipher, u8 status,
|
||||||
|
struct wpabuf *comeback,
|
||||||
|
u16 comeback_after)
|
||||||
{
|
{
|
||||||
|
if (comeback) {
|
||||||
|
size_t comeback_len = wpabuf_len(comeback);
|
||||||
|
size_t buflen = comeback_len * 2 + 1;
|
||||||
|
char *comeback_txt = os_malloc(buflen);
|
||||||
|
|
||||||
|
if (comeback_txt) {
|
||||||
|
wpa_snprintf_hex(comeback_txt, buflen,
|
||||||
|
wpabuf_head(comeback), comeback_len);
|
||||||
|
|
||||||
|
wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR
|
||||||
|
" akmp=%s, status=%u comeback_after=%u comeback=%s",
|
||||||
|
MAC2STR(bssid),
|
||||||
|
wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
|
||||||
|
status, comeback_after, comeback_txt);
|
||||||
|
|
||||||
|
os_free(comeback_txt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wpa_msg(wpa_s, MSG_INFO,
|
wpa_msg(wpa_s, MSG_INFO,
|
||||||
PASN_AUTH_STATUS MACSTR " akmp=%s, status=%u",
|
PASN_AUTH_STATUS MACSTR " akmp=%s, status=%u",
|
||||||
MAC2STR(bssid), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
|
MAC2STR(bssid), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
|
||||||
|
@ -612,7 +635,8 @@ static u8 wpas_pasn_get_wrapped_data_format(struct wpas_pasn *pasn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s)
|
static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s,
|
||||||
|
struct wpabuf *comeback)
|
||||||
{
|
{
|
||||||
struct wpas_pasn *pasn = &wpa_s->pasn;
|
struct wpas_pasn *pasn = &wpa_s->pasn;
|
||||||
struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
|
struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
|
||||||
|
@ -680,7 +704,7 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s)
|
||||||
wrapped_data = WPA_PASN_WRAPPED_DATA_NO;
|
wrapped_data = WPA_PASN_WRAPPED_DATA_NO;
|
||||||
|
|
||||||
wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
|
wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
|
||||||
pubkey, true, NULL, -1);
|
pubkey, true, comeback, -1);
|
||||||
|
|
||||||
if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
|
if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -828,6 +852,10 @@ static void wpas_pasn_reset(struct wpa_supplicant *wpa_s)
|
||||||
wpabuf_free(pasn->beacon_rsne_rsnxe);
|
wpabuf_free(pasn->beacon_rsne_rsnxe);
|
||||||
pasn->beacon_rsne_rsnxe = NULL;
|
pasn->beacon_rsne_rsnxe = NULL;
|
||||||
|
|
||||||
|
wpabuf_free(pasn->comeback);
|
||||||
|
pasn->comeback = NULL;
|
||||||
|
pasn->comeback_after = 0;
|
||||||
|
|
||||||
#ifdef CONFIG_SAE
|
#ifdef CONFIG_SAE
|
||||||
sae_clear_data(&pasn->sae);
|
sae_clear_data(&pasn->sae);
|
||||||
#endif /* CONFIG_SAE */
|
#endif /* CONFIG_SAE */
|
||||||
|
@ -946,7 +974,7 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||||
int akmp, int cipher, u16 group, int freq,
|
int akmp, int cipher, u16 group, int freq,
|
||||||
const u8 *beacon_rsne, u8 beacon_rsne_len,
|
const u8 *beacon_rsne, u8 beacon_rsne_len,
|
||||||
const u8 *beacon_rsnxe, u8 beacon_rsnxe_len,
|
const u8 *beacon_rsnxe, u8 beacon_rsnxe_len,
|
||||||
int network_id)
|
int network_id, struct wpabuf *comeback)
|
||||||
{
|
{
|
||||||
struct wpas_pasn *pasn = &wpa_s->pasn;
|
struct wpas_pasn *pasn = &wpa_s->pasn;
|
||||||
struct wpa_ssid *ssid = NULL;
|
struct wpa_ssid *ssid = NULL;
|
||||||
|
@ -1023,7 +1051,7 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||||
MAC2STR(pasn->bssid), pasn->akmp, pasn->cipher,
|
MAC2STR(pasn->bssid), pasn->akmp, pasn->cipher,
|
||||||
pasn->group);
|
pasn->group);
|
||||||
|
|
||||||
frame = wpas_pasn_build_auth_1(wpa_s);
|
frame = wpas_pasn_build_auth_1(wpa_s, comeback);
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame");
|
wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -1105,6 +1133,8 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
|
||||||
wpa_s, NULL);
|
wpa_s, NULL);
|
||||||
wpa_s->pasn_auth_work = NULL;
|
wpa_s->pasn_auth_work = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wpabuf_free(awork->comeback);
|
||||||
os_free(awork);
|
os_free(awork);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1132,16 +1162,22 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
|
||||||
ret = wpas_pasn_start(wpa_s, awork->bssid, awork->akmp, awork->cipher,
|
ret = wpas_pasn_start(wpa_s, awork->bssid, awork->akmp, awork->cipher,
|
||||||
awork->group, bss->freq, rsne, *(rsne + 1) + 2,
|
awork->group, bss->freq, rsne, *(rsne + 1) + 2,
|
||||||
rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0,
|
rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0,
|
||||||
awork->network_id);
|
awork->network_id, awork->comeback);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
"PASN: Failed to start PASN authentication");
|
"PASN: Failed to start PASN authentication");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* comeback token is no longer needed at this stage */
|
||||||
|
wpabuf_free(awork->comeback);
|
||||||
|
awork->comeback = NULL;
|
||||||
|
|
||||||
wpa_s->pasn_auth_work = work;
|
wpa_s->pasn_auth_work = work;
|
||||||
return;
|
return;
|
||||||
fail:
|
fail:
|
||||||
|
wpabuf_free(awork->comeback);
|
||||||
|
awork->comeback = NULL;
|
||||||
os_free(awork);
|
os_free(awork);
|
||||||
work->ctx = NULL;
|
work->ctx = NULL;
|
||||||
radio_work_done(work);
|
radio_work_done(work);
|
||||||
|
@ -1149,7 +1185,8 @@ fail:
|
||||||
|
|
||||||
|
|
||||||
int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||||
int akmp, int cipher, u16 group, int network_id)
|
int akmp, int cipher, u16 group, int network_id,
|
||||||
|
const u8 *comeback, size_t comeback_len)
|
||||||
{
|
{
|
||||||
struct wpa_pasn_auth_work *awork;
|
struct wpa_pasn_auth_work *awork;
|
||||||
struct wpa_bss *bss;
|
struct wpa_bss *bss;
|
||||||
|
@ -1195,8 +1232,17 @@ int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||||
awork->group = group;
|
awork->group = group;
|
||||||
awork->network_id = network_id;
|
awork->network_id = network_id;
|
||||||
|
|
||||||
|
if (comeback && comeback_len) {
|
||||||
|
awork->comeback = wpabuf_alloc_copy(comeback, comeback_len);
|
||||||
|
if (!awork->comeback) {
|
||||||
|
os_free(awork);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (radio_add_work(wpa_s, bss->freq, "pasn-start-auth", 1,
|
if (radio_add_work(wpa_s, bss->freq, "pasn-start-auth", 1,
|
||||||
wpas_pasn_auth_start_cb, awork) < 0) {
|
wpas_pasn_auth_start_cb, awork) < 0) {
|
||||||
|
wpabuf_free(awork->comeback);
|
||||||
os_free(awork);
|
os_free(awork);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1216,12 +1262,33 @@ void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s)
|
||||||
wpa_printf(MSG_DEBUG, "PASN: Stopping authentication");
|
wpa_printf(MSG_DEBUG, "PASN: Stopping authentication");
|
||||||
|
|
||||||
wpas_pasn_auth_status(wpa_s, pasn->bssid, pasn->akmp, pasn->cipher,
|
wpas_pasn_auth_status(wpa_s, pasn->bssid, pasn->akmp, pasn->cipher,
|
||||||
pasn->status);
|
pasn->status, pasn->comeback,
|
||||||
|
pasn->comeback_after);
|
||||||
|
|
||||||
wpas_pasn_reset(wpa_s);
|
wpas_pasn_reset(wpa_s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wpas_pasn_immediate_retry(struct wpa_supplicant *wpa_s,
|
||||||
|
struct wpas_pasn *pasn,
|
||||||
|
struct wpa_pasn_params_data *params)
|
||||||
|
{
|
||||||
|
int akmp = pasn->akmp;
|
||||||
|
int cipher = pasn->cipher;
|
||||||
|
u16 group = pasn->group;
|
||||||
|
u8 bssid[ETH_ALEN];
|
||||||
|
int network_id = pasn->ssid ? pasn->ssid->id : 0;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "PASN: Immediate retry");
|
||||||
|
os_memcpy(bssid, pasn->bssid, ETH_ALEN);
|
||||||
|
wpas_pasn_reset(wpa_s);
|
||||||
|
|
||||||
|
return wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group,
|
||||||
|
network_id,
|
||||||
|
params->comeback, params->comeback_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
|
int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
|
||||||
const struct ieee80211_mgmt *mgmt, size_t len)
|
const struct ieee80211_mgmt *mgmt, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -1315,10 +1382,26 @@ int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: handle comeback flow */
|
|
||||||
if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
|
if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
"PASN: Authentication temporarily rejected");
|
"PASN: Authentication temporarily rejected");
|
||||||
|
|
||||||
|
if (pasn_params.comeback && pasn_params.comeback_len) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"PASN: Comeback token available. After=%u",
|
||||||
|
pasn_params.after);
|
||||||
|
|
||||||
|
if (!pasn_params.after)
|
||||||
|
return wpas_pasn_immediate_retry(wpa_s, pasn,
|
||||||
|
&pasn_params);
|
||||||
|
|
||||||
|
pasn->comeback = wpabuf_alloc_copy(
|
||||||
|
pasn_params.comeback, pasn_params.comeback_len);
|
||||||
|
if (pasn->comeback)
|
||||||
|
pasn->comeback_after = pasn_params.after;
|
||||||
|
}
|
||||||
|
|
||||||
|
pasn->status = status;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1456,7 +1539,11 @@ fail:
|
||||||
* the frame and terminate the authentication exchange. However, better
|
* the frame and terminate the authentication exchange. However, better
|
||||||
* reply to the AP with an error status.
|
* reply to the AP with an error status.
|
||||||
*/
|
*/
|
||||||
pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
if (status == WLAN_STATUS_SUCCESS)
|
||||||
|
pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||||
|
else
|
||||||
|
pasn->status = status;
|
||||||
|
|
||||||
wpas_pasn_auth_stop(wpa_s);
|
wpas_pasn_auth_stop(wpa_s);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -554,6 +554,9 @@ struct wpas_pasn {
|
||||||
struct wpa_ptk ptk;
|
struct wpa_ptk ptk;
|
||||||
struct crypto_ecdh *ecdh;
|
struct crypto_ecdh *ecdh;
|
||||||
|
|
||||||
|
struct wpabuf *comeback;
|
||||||
|
u16 comeback_after;
|
||||||
|
|
||||||
#ifdef CONFIG_SAE
|
#ifdef CONFIG_SAE
|
||||||
struct sae_data sae;
|
struct sae_data sae;
|
||||||
#endif /* CONFIG_SAE */
|
#endif /* CONFIG_SAE */
|
||||||
|
@ -1730,7 +1733,8 @@ void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||||
|
|
||||||
int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
|
int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
|
||||||
const u8 *bssid, int akmp, int cipher,
|
const u8 *bssid, int akmp, int cipher,
|
||||||
u16 group, int network_id);
|
u16 group, int network_id,
|
||||||
|
const u8 *comeback, size_t comeback_len);
|
||||||
void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s);
|
void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s);
|
||||||
int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s,
|
int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s,
|
||||||
const u8 *data, size_t data_len, u8 acked);
|
const u8 *data, size_t data_len, u8 acked);
|
||||||
|
|
Loading…
Reference in a new issue