]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/ap/wpa_auth_ft.c
Introduce and add key_flag
[thirdparty/hostap.git] / src / ap / wpa_auth_ft.c
index 25a0cc1d7ae00d8f559b984f091a85ad7631e830..462876195a0879a5ad93c0a67df546b300fde7dc 100644 (file)
@@ -25,6 +25,7 @@
 #include "wmm.h"
 #include "wpa_auth.h"
 #include "wpa_auth_i.h"
+#include "pmksa_cache_auth.h"
 
 
 #ifdef CONFIG_IEEE80211R_AP
@@ -66,7 +67,7 @@ struct tlv_list {
  * Returns: 0 on success, -1 on error
  */
 static int wpa_ft_rrb_decrypt(const u8 *key, const size_t key_len,
-                             const u8 *enc, const size_t enc_len,
+                             const u8 *enc, size_t enc_len,
                              const u8 *auth, const size_t auth_len,
                              const u8 *src_addr, u8 type,
                              u8 **plain, size_t *plain_size)
@@ -101,8 +102,18 @@ static int wpa_ft_rrb_decrypt(const u8 *key, const size_t key_len,
                goto err;
 
        if (aes_siv_decrypt(key, key_len, enc, enc_len, 3, ad, ad_len,
-                           *plain) < 0)
-               goto err;
+                           *plain) < 0) {
+               if (enc_len < AES_BLOCK_SIZE + 2)
+                       goto err;
+
+               /* Try to work around Ethernet devices that add extra
+                * two octet padding even if the frame is longer than
+                * the minimum Ethernet frame. */
+               enc_len -= 2;
+               if (aes_siv_decrypt(key, key_len, enc, enc_len, 3, ad, ad_len,
+                                   *plain) < 0)
+                       goto err;
+       }
 
        *plain_size = enc_len - AES_BLOCK_SIZE;
        wpa_hexdump_key(MSG_DEBUG, "FT(RRB): decrypted TLVs",
@@ -512,9 +523,10 @@ static int wpa_ft_rrb_build(const u8 *key, const size_t key_len,
                            const u8 *src_addr, u8 type,
                            u8 **packet, size_t *packet_len)
 {
-       u8 *plain = NULL, *auth = NULL, *pos;
+       u8 *plain = NULL, *auth = NULL, *pos, *tmp;
        size_t plain_len = 0, auth_len = 0;
        int ret = -1;
+       size_t pad_len = 0;
 
        *packet = NULL;
        if (wpa_ft_rrb_lin(tlvs_enc0, tlvs_enc1, vlan, &plain, &plain_len) < 0)
@@ -526,6 +538,28 @@ static int wpa_ft_rrb_build(const u8 *key, const size_t key_len,
        *packet_len = sizeof(u16) + auth_len + plain_len;
        if (key)
                *packet_len += AES_BLOCK_SIZE;
+#define RRB_MIN_MSG_LEN 64
+       if (*packet_len < RRB_MIN_MSG_LEN) {
+               pad_len = RRB_MIN_MSG_LEN - *packet_len;
+               if (pad_len < sizeof(struct ft_rrb_tlv))
+                       pad_len = sizeof(struct ft_rrb_tlv);
+               wpa_printf(MSG_DEBUG,
+                          "FT: Pad message to minimum Ethernet frame length (%d --> %d)",
+                          (int) *packet_len, (int) (*packet_len + pad_len));
+               *packet_len += pad_len;
+               tmp = os_realloc(auth, auth_len + pad_len);
+               if (!tmp)
+                       goto out;
+               auth = tmp;
+               pos = auth + auth_len;
+               WPA_PUT_LE16(pos, FT_RRB_LAST_EMPTY);
+               pos += 2;
+               WPA_PUT_LE16(pos, pad_len - sizeof(struct ft_rrb_tlv));
+               pos += 2;
+               os_memset(pos, 0, pad_len - sizeof(struct ft_rrb_tlv));
+               auth_len += pad_len;
+
+       }
        *packet = os_zalloc(*packet_len);
        if (!*packet)
                goto out;
@@ -917,8 +951,9 @@ wpa_ft_rrb_seq_req(struct wpa_authenticator *wpa_auth,
                goto err;
        }
 
-       wpa_printf(MSG_DEBUG, "FT: Send out sequence number request to " MACSTR,
-                  MAC2STR(src_addr));
+       wpa_printf(MSG_DEBUG, "FT: Send sequence number request from " MACSTR
+                  " to " MACSTR,
+                  MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
        item = os_zalloc(sizeof(*item));
        if (!item)
                goto err;
@@ -1963,9 +1998,6 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
        key = r0kh->key;
        key_len = sizeof(r0kh->key);
 
-       wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
-                  "address " MACSTR, MAC2STR(r0kh->addr));
-
        if (r0kh->seq->rx.num_last == 0) {
                /* A sequence request will be sent out anyway when pull
                 * response is received. Send it out now to avoid one RTT. */
@@ -1974,6 +2006,10 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
                                   key_len, NULL, 0, NULL, 0, NULL);
        }
 
+       wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request from " MACSTR
+                  " to remote R0KH address " MACSTR,
+                  MAC2STR(sm->wpa_auth->addr), MAC2STR(r0kh->addr));
+
        if (first &&
            random_get_bytes(sm->ft_pending_pull_nonce, FT_RRB_NONCE_LEN) < 0) {
                wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
@@ -2041,8 +2077,7 @@ int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm,
 }
 
 
-int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
-                          struct wpa_ptk *ptk)
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
 {
        u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
        size_t pmk_r0_len = wpa_key_mgmt_sha384(sm->wpa_key_mgmt) ?
@@ -2062,8 +2097,16 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
        const u8 *identity, *radius_cui;
        size_t identity_len, radius_cui_len;
        int session_timeout;
-
-       if (sm->xxkey_len == 0) {
+       const u8 *mpmk;
+       size_t mpmk_len;
+
+       if (sm->xxkey_len > 0) {
+               mpmk = sm->xxkey;
+               mpmk_len = sm->xxkey_len;
+       } else if (sm->pmksa) {
+               mpmk = sm->pmksa->pmk;
+               mpmk_len = sm->pmksa->pmk_len;
+       } else {
                wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
                           "derivation");
                return -1;
@@ -2080,7 +2123,7 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
                                               &radius_cui);
        session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr);
 
-       if (wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
+       if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid,
                              r0kh, r0kh_len, sm->addr,
                              pmk_r0, pmk_r0_name,
                              wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0)
@@ -2185,12 +2228,12 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
                return NULL;
        }
 
+       forced_memzero(keybuf, sizeof(keybuf));
        *len = subelem_len;
        return subelem;
 }
 
 
-#ifdef CONFIG_IEEE80211W
 static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
 {
        u8 *subelem, *pos;
@@ -2237,7 +2280,6 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
        *len = subelem_len;
        return subelem;
 }
-#endif /* CONFIG_IEEE80211W */
 
 
 static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
@@ -2378,6 +2420,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
        u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
        u8 *fte_mic, *elem_count;
        size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0;
+       u8 rsnxe[10];
+       size_t rsnxe_len;
        int res;
        struct wpa_auth_config *conf;
        struct wpa_ft_ies parse;
@@ -2445,7 +2489,6 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
                r0kh_id_len = sm->r0kh_id_len;
                anonce = sm->ANonce;
                snonce = sm->SNonce;
-#ifdef CONFIG_IEEE80211W
                if (sm->mgmt_frame_prot) {
                        u8 *igtk;
                        size_t igtk_len;
@@ -2468,7 +2511,6 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
                        subelem_len += igtk_len;
                        os_free(igtk);
                }
-#endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_OCV
                if (wpa_auth_uses_ocv(sm)) {
                        struct wpa_channel_info ci;
@@ -2542,6 +2584,13 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
        if (ric_start == pos)
                ric_start = NULL;
 
+       res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe, sizeof(rsnxe));
+       if (res < 0)
+               return NULL;
+       rsnxe_len = res;
+       if (auth_alg == WLAN_AUTH_FT && rsnxe_len)
+               *elem_count += 1;
+
        if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
                kck = sm->PTK.kck2;
                kck_len = sm->PTK.kck2_len;
@@ -2554,6 +2603,7 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
                       mdie, mdie_len, ftie, ftie_len,
                       rsnie, rsnie_len,
                       ric_start, ric_start ? pos - ric_start : 0,
+                      rsnxe_len ? rsnxe : NULL, rsnxe_len,
                       fte_mic) < 0) {
                wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
                return NULL;
@@ -2572,12 +2622,13 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
                                   int vlan_id,
                                   enum wpa_alg alg, const u8 *addr, int idx,
-                                  u8 *key, size_t key_len)
+                                  u8 *key, size_t key_len,
+                                  enum key_flag key_flag)
 {
        if (wpa_auth->cb->set_key == NULL)
                return -1;
        return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
-                                    key, key_len);
+                                    key, key_len, key_flag);
 }
 
 
@@ -2610,7 +2661,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
         * optimized by adding the STA entry earlier.
         */
        if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-                            sm->PTK.tk, klen))
+                            sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX))
                return;
 
        /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
@@ -2951,6 +3002,8 @@ pmk_r1_derived:
        wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, pmk_r1_len);
        sm->pmk_r1_name_valid = 1;
        os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
+       os_memcpy(sm->pmk_r1, pmk_r1, pmk_r1_len);
+       sm->pmk_r1_len = pmk_r1_len;
 
        if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
                wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
@@ -3056,8 +3109,9 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
        status = res;
 
        wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
-                  " auth_transaction=%d status=%d",
-                  MAC2STR(sm->addr), auth_transaction + 1, status);
+                  " auth_transaction=%d status=%u (%s)",
+                  MAC2STR(sm->addr), auth_transaction + 1, status,
+                  status2str(status));
        wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
        cb(ctx, sm->addr, bssid, auth_transaction + 1, status,
           resp_ies, resp_ies_len);
@@ -3208,6 +3262,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
        count = 3;
        if (parse.ric)
                count += ieee802_11_ie_count(parse.ric, parse.ric_len);
+       if (parse.rsnxe)
+               count++;
        if (fte_elem_count != count) {
                wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
                           "Control: received %u expected %u",
@@ -3227,6 +3283,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
                       parse.ftie - 2, parse.ftie_len + 2,
                       parse.rsn - 2, parse.rsn_len + 2,
                       parse.ric, parse.ric_len,
+                      parse.rsnxe ? parse.rsnxe - 2 : NULL,
+                      parse.rsnxe ? parse.rsnxe_len + 2 : 0,
                       mic) < 0) {
                wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -3245,6 +3303,9 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
                            parse.ftie - 2, parse.ftie_len + 2);
                wpa_hexdump(MSG_MSGDUMP, "FT: RSN",
                            parse.rsn - 2, parse.rsn_len + 2);
+               wpa_hexdump(MSG_MSGDUMP, "FT: RSNXE",
+                           parse.rsnxe ? parse.rsnxe - 2 : NULL,
+                           parse.rsnxe ? parse.rsnxe_len + 2 : 0);
                return WLAN_STATUS_INVALID_FTIE;
        }
 
@@ -3415,8 +3476,9 @@ static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
        u8 *pos;
 
        wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
-                  " CurrentAP=" MACSTR " status=%d",
-                  MAC2STR(sm->addr), MAC2STR(current_ap), status);
+                  " CurrentAP=" MACSTR " status=%u (%s)",
+                  MAC2STR(sm->addr), MAC2STR(current_ap), status,
+                  status2str(status));
        wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
 
        /* RRB - Forward action frame response to the Current AP */
@@ -3522,7 +3584,7 @@ static int wpa_ft_rrb_build_r0(const u8 *key, const size_t key_len,
                               pmk_r0->vlan, src_addr, type,
                               packet, packet_len);
 
-       os_memset(pmk_r1, 0, sizeof(pmk_r1));
+       forced_memzero(pmk_r1, sizeof(pmk_r1));
 
        return ret;
 }
@@ -3628,6 +3690,10 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
                goto out;
        }
 
+       wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull response from " MACSTR
+                  " to " MACSTR,
+                  MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
+
        resp[0].type = FT_RRB_S1KH_ID;
        resp[0].len = f_s1kh_id_len;
        resp[0].data = f_s1kh_id;
@@ -3848,10 +3914,7 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth,
 
        ret = 0;
 out:
-       if (plain) {
-               os_memset(plain, 0, plain_len);
-               os_free(plain);
-       }
+       bin_clear_free(plain, plain_len);
 
        return ret;
 
@@ -4137,6 +4200,10 @@ static int wpa_ft_rrb_rx_seq_req(struct wpa_authenticator *wpa_auth,
                goto out;
        }
 
+       wpa_printf(MSG_DEBUG, "FT: Send sequence number response from " MACSTR
+                  " to " MACSTR,
+                  MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
+
        seq_resp_auth[0].type = FT_RRB_NONCE;
        seq_resp_auth[0].len = f_nonce_len;
        seq_resp_auth[0].data = f_nonce;
@@ -4396,9 +4463,11 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
        size_t alen, elen;
        int no_defer = 0;
 
-       wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP "
-                  MACSTR, MAC2STR(src_addr));
-       wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame - oui_suffix=%d", oui_suffix);
+       wpa_printf(MSG_DEBUG, "FT: RRB-OUI(" MACSTR
+                  ") received frame from remote AP "
+                  MACSTR " oui_suffix=%u dst=" MACSTR,
+                  MAC2STR(wpa_auth->addr), MAC2STR(src_addr), oui_suffix,
+                  MAC2STR(dst_addr));
        wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", data, data_len);
 
        if (is_multicast_ether_addr(src_addr)) {
@@ -4408,13 +4477,8 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
                return;
        }
 
-       if (is_multicast_ether_addr(dst_addr)) {
-               wpa_printf(MSG_DEBUG,
-                          "FT: RRB-OUI received frame from remote AP " MACSTR
-                          " to multicast address " MACSTR,
-                          MAC2STR(src_addr), MAC2STR(dst_addr));
+       if (is_multicast_ether_addr(dst_addr))
                no_defer = 1;
-       }
 
        if (data_len < sizeof(u16)) {
                wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame too short");
@@ -4489,6 +4553,10 @@ static int wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
                return -1;
        }
 
+       wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 push from " MACSTR
+                  " to remote R0KH address " MACSTR,
+                  MAC2STR(wpa_auth->addr), MAC2STR(r1kh->addr));
+
        if (wpa_ft_rrb_build_r0(r1kh->key, sizeof(r1kh->key), push, pmk_r0,
                                r1kh->id, s1kh_id, push_auth, wpa_auth->addr,
                                FT_PACKET_R0KH_R1KH_PUSH,