]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
FT: Derive PMK-R1 locally if requested PMKR0Name is found
authorJouni Malinen <jouni@codeaurora.org>
Sat, 24 Mar 2018 16:45:42 +0000 (18:45 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 24 Mar 2018 16:53:14 +0000 (18:53 +0200)
Derive PMK-R1 locally if the derived PMKR1Name is not found from the
local cache, but the request is for a key that was originally generated
locally (R0KH-ID matches) and the PMKR0Name is found in the local cache.
This was apparently not hit in the previously used FT sequences, but
this is useful to have available if a PMK-R1 entry is dropped from the
local cache before PMK-R0.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
src/ap/wpa_auth_ft.c

index 5191ae090651dfafa16329da2893639b38943fc3..1eb8bd50064e304d8f6f2ffb0ae2703ce2530b5d 100644 (file)
@@ -2055,6 +2055,43 @@ static int wpa_ft_set_key_mgmt(struct wpa_state_machine *sm,
 }
 
 
+static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth,
+                                     struct wpa_state_machine *sm,
+                                     const u8 *r0kh_id, size_t r0kh_id_len,
+                                     const u8 *req_pmk_r0_name,
+                                     const u8 *req_pmk_r1_name,
+                                     u8 *out_pmk_r1, int *out_pairwise)
+{
+       struct wpa_auth_config *conf = &wpa_auth->conf;
+       const struct wpa_ft_pmk_r0_sa *r0;
+       u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+
+       if (conf->r0_key_holder_len != r0kh_id_len ||
+           os_memcmp(conf->r0_key_holder, r0kh_id, conf->r0_key_holder_len) !=
+           0)
+               return -1; /* not our R0KH-ID */
+
+       wpa_printf(MSG_DEBUG, "FT: STA R0KH-ID matching local configuration");
+       if (wpa_ft_fetch_pmk_r0(sm->wpa_auth, sm->addr, req_pmk_r0_name, &r0) <
+           0)
+               return -1; /* no matching PMKR0Name in local cache */
+
+       wpa_printf(MSG_DEBUG, "FT: Requested PMKR0Name found in local cache");
+
+       if (wpa_derive_pmk_r1(r0->pmk_r0, r0->pmk_r0_name, conf->r1_key_holder,
+                             sm->addr, out_pmk_r1, pmk_r1_name) < 0)
+               return -1;
+       wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", out_pmk_r1, PMK_LEN);
+       wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
+
+       wpa_ft_store_pmk_r1(wpa_auth, sm->addr, out_pmk_r1, pmk_r1_name,
+                           sm->pairwise);
+
+       *out_pairwise = sm->pairwise;
+       return 0;
+}
+
+
 static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
                                   const u8 *ies, size_t ies_len,
                                   u8 **resp_ies, size_t *resp_ies_len)
@@ -2132,8 +2169,22 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
            wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
                if (wpa_ft_psk_pmk_r1(sm, pmk_r1_name, pmk_r1, &pairwise) < 0)
                        return WLAN_STATUS_INVALID_PMKID;
+               wpa_printf(MSG_DEBUG,
+                          "FT: Generated PMK-R1 for FT-PSK locally");
        } else if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name,
                                       pmk_r1, &pairwise) < 0) {
+               wpa_printf(MSG_DEBUG,
+                          "FT: No PMK-R1 available in local cache for the requested PMKR1Name");
+               if (wpa_ft_local_derive_pmk_r1(sm->wpa_auth, sm,
+                                              parse.r0kh_id, parse.r0kh_id_len,
+                                              parse.rsn_pmkid,
+                                              pmk_r1_name, pmk_r1, &pairwise)
+                   == 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "FT: Generated PMK-R1 based on local PMK-R0");
+                       goto pmk_r1_derived;
+               }
+
                if (wpa_ft_pull_pmk_r1(sm, ies, ies_len, parse.rsn_pmkid) < 0) {
                        wpa_printf(MSG_DEBUG,
                                   "FT: Did not have matching PMK-R1 and either unknown or blocked R0KH-ID or NAK from R0KH");
@@ -2141,8 +2192,11 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
                }
 
                return -1; /* Status pending */
+       } else {
+               wpa_printf(MSG_DEBUG, "FT: Found PMKR1Name from local cache");
        }
 
+pmk_r1_derived:
        wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN);
        sm->pmk_r1_name_valid = 1;
        os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);