FILS: Add Association Response frame elements and encrypt them (AP)

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2015-09-09 15:43:53 +03:00 committed by Jouni Malinen
parent 78815f3dde
commit e73ffa0925
3 changed files with 155 additions and 0 deletions

View file

@ -2347,6 +2347,31 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
send_len += p - reply->u.assoc_resp.variable;
#ifdef CONFIG_FILS
if ((sta->auth_alg == WLAN_AUTH_FILS_SK ||
sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
sta->auth_alg == WLAN_AUTH_FILS_PK) &&
status_code == WLAN_STATUS_SUCCESS) {
struct ieee802_11_elems elems;
if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
ParseFailed || !elems.fils_session)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
/* FILS Session */
*p++ = WLAN_EID_EXTENSION; /* Element ID */
*p++ = 1 + FILS_SESSION_LEN; /* Length */
*p++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
os_memcpy(p, elems.fils_session, FILS_SESSION_LEN);
send_len += 2 + 1 + FILS_SESSION_LEN;
send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len,
sizeof(buf));
if (send_len < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
#endif /* CONFIG_FILS */
if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
strerror(errno));

View file

@ -58,6 +58,7 @@ static void wpa_group_get(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_put(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
static const u32 dot11RSNAConfigGroupUpdateCount = 4;
static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
@ -2255,6 +2256,133 @@ int fils_decrypt_assoc(struct wpa_state_machine *sm, const u8 *fils_session,
return left - AES_BLOCK_SIZE;
}
int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
size_t current_len, size_t max_len)
{
u8 *end = buf + max_len;
u8 *pos = buf + current_len;
struct ieee80211_mgmt *mgmt;
struct wpabuf *plain;
u8 *len, *tmp, *tmp2;
u8 hdr[2];
u8 *gtk, dummy_gtk[32];
size_t gtk_len;
struct wpa_group *gsm;
const u8 *aad[5];
size_t aad_len[5];
if (!sm || !sm->PTK_valid)
return -1;
wpa_hexdump(MSG_DEBUG,
"FILS: Association Response frame before FILS processing",
buf, current_len);
mgmt = (struct ieee80211_mgmt *) buf;
/* AES-SIV AAD vectors */
/* The AP's BSSID */
aad[0] = mgmt->sa;
aad_len[0] = ETH_ALEN;
/* The STA's MAC address */
aad[1] = mgmt->da;
aad_len[1] = ETH_ALEN;
/* The AP's nonce */
aad[2] = sm->ANonce;
aad_len[2] = FILS_NONCE_LEN;
/* The STA's nonce */
aad[3] = sm->SNonce;
aad_len[3] = FILS_NONCE_LEN;
/*
* The (Re)Association Response frame from the Capability Information
* field (the same offset in both Association and Reassociation
* Response frames) to the FILS Session element (both inclusive).
*/
aad[4] = (const u8 *) &mgmt->u.assoc_resp.capab_info;
aad_len[4] = pos - aad[4];
/* The following elements will be encrypted with AES-SIV */
plain = wpabuf_alloc(1000);
if (!plain)
return -1;
/* TODO: FILS Public Key */
/* FILS Key Confirmation */
wpabuf_put_u8(plain, WLAN_EID_EXTENSION); /* Element ID */
wpabuf_put_u8(plain, 1 + sm->fils_key_auth_len); /* Length */
/* Element ID Extension */
wpabuf_put_u8(plain, WLAN_EID_EXT_FILS_KEY_CONFIRM);
wpabuf_put_data(plain, sm->fils_key_auth_ap, sm->fils_key_auth_len);
/* TODO: FILS HLP Container */
/* TODO: FILS IP Address Assignment */
/* Key Delivery */
gsm = sm->group;
wpabuf_put_u8(plain, WLAN_EID_EXTENSION); /* Element ID */
len = wpabuf_put(plain, 1);
wpabuf_put_u8(plain, WLAN_EID_EXT_KEY_DELIVERY);
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN,
wpabuf_put(plain, WPA_KEY_RSC_LEN));
/* GTK KDE */
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
if (sm->wpa_auth->conf.disable_gtk) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
*/
if (random_get_bytes(dummy_gtk, gtk_len) < 0) {
wpabuf_free(plain);
return -1;
}
gtk = dummy_gtk;
}
hdr[0] = gsm->GN & 0x03;
hdr[1] = 0;
tmp = wpabuf_put(plain, 0);
tmp2 = wpa_add_kde(tmp, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gtk_len);
wpabuf_put(plain, tmp2 - tmp);
/* IGTK KDE */
tmp = wpabuf_put(plain, 0);
tmp2 = ieee80211w_kde_add(sm, tmp);
wpabuf_put(plain, tmp2 - tmp);
*len = (u8 *) wpabuf_put(plain, 0) - len - 1;
if (pos + wpabuf_len(plain) + AES_BLOCK_SIZE > end) {
wpa_printf(MSG_DEBUG,
"FILS: Not enough room for FILS elements");
wpabuf_free(plain);
return -1;
}
wpa_hexdump_buf_key(MSG_DEBUG, "FILS: Association Response plaintext",
plain);
if (aes_siv_encrypt(sm->PTK.kek, sm->PTK.kek_len,
wpabuf_head(plain), wpabuf_len(plain),
5, aad, aad_len, pos) < 0) {
wpabuf_free(plain);
return -1;
}
wpa_hexdump(MSG_DEBUG,
"FILS: Encrypted Association Response elements",
pos, AES_BLOCK_SIZE + wpabuf_len(plain));
current_len += wpabuf_len(plain) + AES_BLOCK_SIZE;
wpabuf_free(plain);
return current_len;
}
#endif /* CONFIG_FILS */

View file

@ -353,5 +353,7 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
int fils_decrypt_assoc(struct wpa_state_machine *sm, const u8 *fils_session,
const struct ieee80211_mgmt *mgmt, size_t frame_len,
u8 *pos, size_t left);
int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
size_t current_len, size_t max_len);
#endif /* WPA_AUTH_H */