const u8 *pos;
int left, i;
struct sta_info *sta;
+ u8 *tmp = NULL;
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
sizeof(mgmt->u.assoc_req))) {
*/
sta->capability = capab_info;
+#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) {
+ /* The end of the payload is encrypted. Need to decrypt it
+ * before parsing. */
+
+ tmp = os_malloc(left);
+ if (!tmp) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ os_memcpy(tmp, pos, left);
+
+ left = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
+ len, tmp, left);
+ if (left < 0) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ pos = tmp;
+ }
+#endif /* CONFIG_FILS */
+
/* followed by SSID and Supported rates; and HT capabilities if 802.11n
* is used */
resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
reply_res = send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
+ os_free(tmp);
/*
* Remove the station in case tranmission of a success response fails
if (sm->mgmt_frame_prot && event == WPA_AUTH)
remove_ptk = 0;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_FILS
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) && event == WPA_AUTH)
+ remove_ptk = 0;
+#endif /* CONFIG_FILS */
if (remove_ptk) {
sm->PTK_valid = FALSE;
sm->fils_key_auth_ap,
&sm->fils_key_auth_len);
os_memset(ick, 0, sizeof(ick));
+
+ /* Store nonces for (Re)Association Request/Response frame processing */
+ os_memcpy(sm->SNonce, snonce, FILS_NONCE_LEN);
+ os_memcpy(sm->ANonce, anonce, FILS_NONCE_LEN);
+
return res;
}
*_key_data_len = key_data_len;
return 0;
}
+
+
+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)
+{
+ u16 fc, stype;
+ const u8 *end, *ie_start, *ie, *session, *crypt;
+ struct ieee802_11_elems elems;
+ const u8 *aad[5];
+ size_t aad_len[5];
+
+ if (!sm || !sm->PTK_valid) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No KEK to decrypt Assocication Request frame");
+ return -1;
+ }
+
+ if (!wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Not a FILS AKM - reject association");
+ return -1;
+ }
+
+ end = ((const u8 *) mgmt) + frame_len;
+ fc = le_to_host16(mgmt->frame_control);
+ stype = WLAN_FC_GET_STYPE(fc);
+ if (stype == WLAN_FC_STYPE_REASSOC_REQ)
+ ie_start = mgmt->u.reassoc_req.variable;
+ else
+ ie_start = mgmt->u.assoc_req.variable;
+ ie = ie_start;
+
+ /*
+ * Find FILS Session element which is the last unencrypted element in
+ * the frame.
+ */
+ session = NULL;
+ while (ie + 1 < end) {
+ if (ie + 2 + ie[1] > end)
+ break;
+ if (ie[0] == WLAN_EID_EXTENSION &&
+ ie[1] >= 1 + FILS_SESSION_LEN &&
+ ie[2] == WLAN_EID_EXT_FILS_SESSION) {
+ session = ie;
+ break;
+ }
+ ie += 2 + ie[1];
+ }
+
+ if (!session) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Could not find FILS Session element in Association Request frame - reject");
+ return -1;
+ }
+ if (os_memcmp(fils_session, session + 3, FILS_SESSION_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Session mismatch");
+ wpa_hexdump(MSG_DEBUG, "FILS: Expected FILS Session",
+ fils_session, FILS_SESSION_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: Received FILS Session",
+ session + 3, FILS_SESSION_LEN);
+ return -1;
+ }
+ crypt = session + 2 + session[1];
+
+ if (end - crypt < AES_BLOCK_SIZE) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Too short frame to include AES-SIV data");
+ return -1;
+ }
+
+ /* AES-SIV AAD vectors */
+
+ /* The STA's MAC address */
+ aad[0] = mgmt->sa;
+ aad_len[0] = ETH_ALEN;
+ /* The AP's BSSID */
+ aad[1] = mgmt->da;
+ aad_len[1] = ETH_ALEN;
+ /* The STA's nonce */
+ aad[2] = sm->SNonce;
+ aad_len[2] = FILS_NONCE_LEN;
+ /* The AP's nonce */
+ aad[3] = sm->ANonce;
+ aad_len[3] = FILS_NONCE_LEN;
+ /*
+ * The (Re)Association Request frame from the Capability Information
+ * field to the FILS Session element (both inclusive).
+ */
+ aad[4] = (const u8 *) &mgmt->u.assoc_req.capab_info;
+ aad_len[4] = crypt - aad[0];
+
+ if (aes_siv_decrypt(sm->PTK.kek, sm->PTK.kek_len, crypt, end - crypt,
+ 1, aad, aad_len, pos + (crypt - ie_start)) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Invalid AES-SIV data in the frame");
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "FILS: Decrypted Association Request elements",
+ pos, left - AES_BLOCK_SIZE);
+
+ if (ieee802_11_parse_elems(pos, left - AES_BLOCK_SIZE, &elems, 1) ==
+ ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Failed to parse decrypted elements");
+ return -1;
+ }
+ if (!elems.fils_key_confirm) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Key Confirm element");
+ return -1;
+ }
+ if (elems.fils_key_confirm_len != sm->fils_key_auth_len) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Unexpected Key-Auth length %d (expected %d)",
+ elems.fils_key_confirm_len,
+ (int) sm->fils_key_auth_len);
+ return -1;
+ }
+ if (os_memcmp(elems.fils_key_confirm, sm->fils_key_auth_sta,
+ sm->fils_key_auth_len) != 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Key-Auth mismatch");
+ wpa_hexdump(MSG_DEBUG, "FILS: Received Key-Auth",
+ elems.fils_key_confirm,
+ elems.fils_key_confirm_len);
+ wpa_hexdump(MSG_DEBUG, "FILS: Expected Key-Auth",
+ sm->fils_key_auth_sta, sm->fils_key_auth_len);
+ return -1;
+ }
+
+ return left - AES_BLOCK_SIZE;
+}
+
#endif /* CONFIG_FILS */