]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
FILS: Add Association Response frame elements and encrypt them (AP)
authorJouni Malinen <jouni@qca.qualcomm.com>
Wed, 9 Sep 2015 12:43:53 +0000 (15:43 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 25 Oct 2016 17:42:52 +0000 (20:42 +0300)
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
src/ap/ieee802_11.c
src/ap/wpa_auth.c
src/ap/wpa_auth.h

index 399b175003043168656bd33b02cbf064d5df7b1a..fe3dee30d0abd7a0710d6d655cf6ce93adf3f6e1 100644 (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));
index b348818332bb041b5d66df87791d0cd0fb0805a5..48d80de4cdbf4b74d3c954286dd6dd5eb64e6956 100644 (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 */
 
 
index 273e290890de2a3140fa811dc40d44022420908f..5a39aee9551259b9b74401753a81b89d3aa3307a 100644 (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 */