mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-11-29 22:19:23 +01:00
ap: Handle PTK handshake frame 4/4
Handle the 4-Way Handshake last frame, install keys, enable data frames on the controlled port.
This commit is contained in:
parent
a3361c5077
commit
251edd2557
167
src/ap.c
167
src/ap.c
@ -65,6 +65,7 @@ struct ap_state {
|
|||||||
struct sta_state {
|
struct sta_state {
|
||||||
uint8_t addr[6];
|
uint8_t addr[6];
|
||||||
bool associated;
|
bool associated;
|
||||||
|
bool rsna;
|
||||||
uint16_t aid;
|
uint16_t aid;
|
||||||
struct mmpdu_field_capability capability;
|
struct mmpdu_field_capability capability;
|
||||||
uint16_t listen_interval;
|
uint16_t listen_interval;
|
||||||
@ -138,18 +139,143 @@ static bool ap_sta_match_addr(const void *a, const void *b)
|
|||||||
return !memcmp(sta->addr, b, 6);
|
return !memcmp(sta->addr, b, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ap_set_sta_cb(struct l_genl_msg *msg, void *user_data)
|
||||||
|
{
|
||||||
|
if (l_genl_msg_get_error(msg) < 0)
|
||||||
|
l_error("SET_STATION failed: %i", l_genl_msg_get_error(msg));
|
||||||
|
}
|
||||||
|
|
||||||
static void ap_del_sta_cb(struct l_genl_msg *msg, void *user_data)
|
static void ap_del_sta_cb(struct l_genl_msg *msg, void *user_data)
|
||||||
{
|
{
|
||||||
if (l_genl_msg_get_error(msg) < 0)
|
if (l_genl_msg_get_error(msg) < 0)
|
||||||
l_error("DEL_STATION failed: %i", l_genl_msg_get_error(msg));
|
l_error("DEL_STATION failed: %i", l_genl_msg_get_error(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ap_new_key_cb(struct l_genl_msg *msg, void *user_data)
|
||||||
|
{
|
||||||
|
if (l_genl_msg_get_error(msg) < 0)
|
||||||
|
l_error("NEW_KEY failed: %i", l_genl_msg_get_error(msg));
|
||||||
|
}
|
||||||
|
|
||||||
static void ap_del_key_cb(struct l_genl_msg *msg, void *user_data)
|
static void ap_del_key_cb(struct l_genl_msg *msg, void *user_data)
|
||||||
{
|
{
|
||||||
if (l_genl_msg_get_error(msg) < 0)
|
if (l_genl_msg_get_error(msg) < 0)
|
||||||
l_debug("DEL_KEY failed: %i", l_genl_msg_get_error(msg));
|
l_debug("DEL_KEY failed: %i", l_genl_msg_get_error(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ap_new_rsna(struct ap_state *ap, struct sta_state *sta)
|
||||||
|
{
|
||||||
|
struct l_genl_msg *msg;
|
||||||
|
uint32_t ifindex = device_get_ifindex(ap->device);
|
||||||
|
struct nl80211_sta_flag_update flags = {
|
||||||
|
.mask = (1 << NL80211_STA_FLAG_AUTHORIZED) |
|
||||||
|
(1 << NL80211_STA_FLAG_MFP),
|
||||||
|
.set = (1 << NL80211_STA_FLAG_AUTHORIZED),
|
||||||
|
};
|
||||||
|
uint8_t key_id = 0;
|
||||||
|
const struct crypto_ptk *ptk = (struct crypto_ptk *) sta->ptk;
|
||||||
|
uint32_t cipher = ie_rsn_cipher_suite_to_cipher(ap->ciphers);
|
||||||
|
uint32_t key_type = NL80211_KEYTYPE_PAIRWISE;
|
||||||
|
uint8_t tk_buf[32];
|
||||||
|
|
||||||
|
msg = l_genl_msg_new_sized(NL80211_CMD_SET_STATION, 128);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, 6, sta->addr);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_STA_FLAGS2, 8, &flags);
|
||||||
|
|
||||||
|
if (!l_genl_family_send(nl80211, msg, ap_set_sta_cb, NULL, NULL)) {
|
||||||
|
l_genl_msg_unref(msg);
|
||||||
|
l_error("Issuing SET_STATION failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sta->rsna = true;
|
||||||
|
|
||||||
|
switch (cipher) {
|
||||||
|
case CRYPTO_CIPHER_CCMP:
|
||||||
|
/*
|
||||||
|
* 802.11-2016 12.8.3 Mapping PTK to CCMP keys:
|
||||||
|
* "A STA shall use the temporal key as the CCMP key
|
||||||
|
* for MPDUs between the two communicating STAs."
|
||||||
|
*/
|
||||||
|
memcpy(tk_buf, ptk->tk, 16);
|
||||||
|
break;
|
||||||
|
case CRYPTO_CIPHER_TKIP:
|
||||||
|
/*
|
||||||
|
* 802.11-2016 12.8.1 Mapping PTK to TKIP keys:
|
||||||
|
* "A STA shall use bits 0-127 of the temporal key as its
|
||||||
|
* input to the TKIP Phase 1 and Phase 2 mixing functions.
|
||||||
|
*
|
||||||
|
* A STA shall use bits 128-191 of the temporal key as
|
||||||
|
* the michael key for MSDUs from the Authenticator's STA
|
||||||
|
* to the Supplicant's STA.
|
||||||
|
*
|
||||||
|
* A STA shall use bits 192-255 of the temporal key as
|
||||||
|
* the michael key for MSDUs from the Supplicant's STA
|
||||||
|
* to the Authenticator's STA."
|
||||||
|
*/
|
||||||
|
memcpy(tk_buf + NL80211_TKIP_DATA_OFFSET_ENCR_KEY, ptk->tk, 16);
|
||||||
|
memcpy(tk_buf + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY,
|
||||||
|
ptk->tk + 16, 8);
|
||||||
|
memcpy(tk_buf + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
|
||||||
|
ptk->tk + 24, 8);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
l_error("Unexpected cipher: %x", cipher);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = l_genl_msg_new_sized(NL80211_CMD_NEW_KEY, 128);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, 6, sta->addr);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_KEY_IDX, 1, &key_id);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_KEY_DATA,
|
||||||
|
crypto_cipher_key_len(cipher), tk_buf);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_KEY_TYPE, 4, &key_type);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_KEY_CIPHER, 4, &cipher);
|
||||||
|
|
||||||
|
if (!l_genl_family_send(nl80211, msg, ap_new_key_cb, NULL, NULL)) {
|
||||||
|
l_genl_msg_unref(msg);
|
||||||
|
l_error("Issuing NEW_KEY failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ap_drop_rsna(struct ap_state *ap, struct sta_state *sta)
|
||||||
|
{
|
||||||
|
struct l_genl_msg *msg;
|
||||||
|
uint32_t ifindex = device_get_ifindex(ap->device);
|
||||||
|
struct nl80211_sta_flag_update flags = {
|
||||||
|
.mask = (1 << NL80211_STA_FLAG_AUTHORIZED) |
|
||||||
|
(1 << NL80211_STA_FLAG_MFP),
|
||||||
|
.set = 0,
|
||||||
|
};
|
||||||
|
uint8_t key_id = 0;
|
||||||
|
|
||||||
|
sta->rsna = false;
|
||||||
|
|
||||||
|
msg = l_genl_msg_new_sized(NL80211_CMD_SET_STATION, 128);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, 6, sta->addr);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_STA_AID, 2, &sta->aid);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_STA_FLAGS2, 8, &flags);
|
||||||
|
|
||||||
|
if (!l_genl_family_send(nl80211, msg, ap_set_sta_cb, NULL, NULL)) {
|
||||||
|
l_genl_msg_unref(msg);
|
||||||
|
l_error("Issuing SET_STATION failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = l_genl_msg_new_sized(NL80211_CMD_DEL_KEY, 64);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_KEY_IDX, 1, &key_id);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, 6, sta->addr);
|
||||||
|
|
||||||
|
if (!l_genl_family_send(nl80211, msg, ap_del_key_cb, NULL, NULL)) {
|
||||||
|
l_genl_msg_unref(msg);
|
||||||
|
l_error("Issuing DEL_KEY failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define CIPHER_SUITE_GROUP_NOT_ALLOWED 0x000fac07
|
#define CIPHER_SUITE_GROUP_NOT_ALLOWED 0x000fac07
|
||||||
|
|
||||||
static void ap_set_rsn_info(struct ap_state *ap, struct ie_rsn_info *rsn)
|
static void ap_set_rsn_info(struct ap_state *ap, struct ie_rsn_info *rsn)
|
||||||
@ -308,6 +434,26 @@ static void ap_handle_ptk_2_of_4(struct sta_state *sta,
|
|||||||
ap_send_ptk_3_of_4(sta->ap, sta);
|
ap_send_ptk_3_of_4(sta->ap, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 802.11-2016 Section 12.7.6.5 */
|
||||||
|
static void ap_handle_ptk_4_of_4(struct sta_state *sta,
|
||||||
|
const struct eapol_key *ek)
|
||||||
|
{
|
||||||
|
const struct crypto_ptk *ptk = (struct crypto_ptk *) sta->ptk;
|
||||||
|
|
||||||
|
l_debug("");
|
||||||
|
|
||||||
|
if (!eapol_verify_ptk_4_of_4(ek, false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (L_BE64_TO_CPU(ek->key_replay_counter) != sta->key_replay_counter)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!eapol_verify_mic(ptk->kck, ek))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ap_new_rsna(sta->ap, sta);
|
||||||
|
}
|
||||||
|
|
||||||
static void ap_eapol_key_handle(struct sta_state *sta,
|
static void ap_eapol_key_handle(struct sta_state *sta,
|
||||||
const struct eapol_frame *frame)
|
const struct eapol_frame *frame)
|
||||||
{
|
{
|
||||||
@ -326,6 +472,8 @@ static void ap_eapol_key_handle(struct sta_state *sta,
|
|||||||
|
|
||||||
if (!sta->ptk_complete)
|
if (!sta->ptk_complete)
|
||||||
ap_handle_ptk_2_of_4(sta, ek);
|
ap_handle_ptk_2_of_4(sta, ek);
|
||||||
|
else if (!sta->rsna)
|
||||||
|
ap_handle_ptk_4_of_4(sta, ek);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ap_eapol_rx(uint16_t proto, const uint8_t *from,
|
static void ap_eapol_rx(uint16_t proto, const uint8_t *from,
|
||||||
@ -506,6 +654,7 @@ static void ap_associate_sta(struct ap_state *ap, struct sta_state *sta)
|
|||||||
uint16_t capability = l_get_le16(&sta->capability);
|
uint16_t capability = l_get_le16(&sta->capability);
|
||||||
|
|
||||||
sta->associated = true;
|
sta->associated = true;
|
||||||
|
sta->rsna = false;
|
||||||
sta->key_replay_counter = 0;
|
sta->key_replay_counter = 0;
|
||||||
|
|
||||||
minr = l_uintset_find_min(sta->rates);
|
minr = l_uintset_find_min(sta->rates);
|
||||||
@ -550,6 +699,7 @@ static void ap_disassociate_sta(struct ap_state *ap, struct sta_state *sta)
|
|||||||
uint8_t key_id = 0;
|
uint8_t key_id = 0;
|
||||||
|
|
||||||
sta->associated = false;
|
sta->associated = false;
|
||||||
|
sta->rsna = false;
|
||||||
|
|
||||||
msg = l_genl_msg_new_sized(NL80211_CMD_DEL_STATION, 64);
|
msg = l_genl_msg_new_sized(NL80211_CMD_DEL_STATION, 64);
|
||||||
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex);
|
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex);
|
||||||
@ -610,6 +760,10 @@ static void ap_success_assoc_resp_cb(struct l_genl_msg *msg, void *user_data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we were in State 4, go to back to State 3 */
|
||||||
|
if (sta->rsna)
|
||||||
|
ap_drop_rsna(ap, sta);
|
||||||
|
|
||||||
/* If we were in State 2 also go to State 3 */
|
/* If we were in State 2 also go to State 3 */
|
||||||
if (!sta->associated)
|
if (!sta->associated)
|
||||||
ap_associate_sta(ap, sta);
|
ap_associate_sta(ap, sta);
|
||||||
@ -801,6 +955,19 @@ static void ap_assoc_req_cb(struct netdev *netdev,
|
|||||||
|
|
||||||
unsupported:
|
unsupported:
|
||||||
bad_frame:
|
bad_frame:
|
||||||
|
/*
|
||||||
|
* TODO: MFP
|
||||||
|
*
|
||||||
|
* 802.11-2016 11.3.5.3 j)
|
||||||
|
* "if management frame protection is in use the state for the STA
|
||||||
|
* shall be left unchanged. and if management frame protection is
|
||||||
|
* not in use set to State 3 if it was in State 4."
|
||||||
|
*
|
||||||
|
* For now, we need to drop the RSNA.
|
||||||
|
*/
|
||||||
|
if (sta && sta->associated && sta->rsna)
|
||||||
|
ap_drop_rsna(ap, sta);
|
||||||
|
|
||||||
if (rates)
|
if (rates)
|
||||||
l_uintset_free(rates);
|
l_uintset_free(rates);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user