]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
OWE: PTK derivation workaround in AP mode
authorJouni Malinen <jouni@codeaurora.org>
Thu, 23 Jan 2020 18:56:51 +0000 (20:56 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 23 Jan 2020 22:47:41 +0000 (00:47 +0200)
Initial OWE implementation used SHA256 when deriving the PTK for all OWE
groups. This was supposed to change to SHA384 for group 20 and SHA512
for group 21. The new owe_ptk_workaround parameter can be used to enable
workaround for interoperability with stations that use SHA256 with
groups 20 and 21. By default, only the appropriate hash function is
accepted. When workaround is enabled (owe_ptk_workaround=1), the
appropriate hash function is tried first and if that fails, SHA256-based
PTK derivation is attempted. This workaround can result in reduced
security for groups 20 and 21, but is required for interoperability with
older implementations. There is no impact to group 19 behavior.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
hostapd/config_file.c
hostapd/hostapd.conf
src/ap/ap_config.h
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_glue.c

index c40983c98b98af0150ca03231cad43c8c4e0e4f2..0169b989d7978acfd4996305a6344d897ff614a4 100644 (file)
@@ -4412,6 +4412,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                                   line, pos);
                        return 1;
                }
+       } else if (os_strcmp(buf, "owe_ptk_workaround") == 0) {
+               bss->owe_ptk_workaround = atoi(pos);
 #endif /* CONFIG_OWE */
        } else if (os_strcmp(buf, "coloc_intf_reporting") == 0) {
                bss->coloc_intf_reporting = atoi(pos);
index fbaa42b098e5ba183131d589049011401ab97ad4..f55925afd755c7a683b9bfcdb44ba9cd25cc795e 100644 (file)
@@ -1817,6 +1817,19 @@ own_ip_addr=127.0.0.1
 # http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
 #owe_groups=19 20 21
 
+# OWE PTK derivation workaround
+# Initial OWE implementation used SHA256 when deriving the PTK for all OWE
+# groups. This was supposed to change to SHA384 for group 20 and SHA512 for
+# group 21. This parameter can be used to enable workaround for interoperability
+# with stations that use SHA256 with groups 20 and 21. By default (0) only the
+# appropriate hash function is accepted. When workaround is enabled (1), the
+# appropriate hash function is tried first and if that fails, SHA256-based PTK
+# derivation is attempted. This workaround can result in reduced security for
+# groups 20 and 21, but is required for interoperability with older
+# implementations. There is no impact to group 19 behavior. The workaround is
+# disabled by default and can be enabled by uncommenting the following line.
+#owe_ptk_workaround=1
+
 # OWE transition mode configuration
 # Pointer to the matching open/OWE BSS
 #owe_transition_bssid=<bssid>
index 1efdc2b4320b7332b7f15feb20e5bb7f5fe3c05b..017e60aa425b13bc7f613cd5b4d02b0b564966ce 100644 (file)
@@ -733,6 +733,7 @@ struct hostapd_bss_config {
        size_t owe_transition_ssid_len;
        char owe_transition_ifname[IFNAMSIZ + 1];
        int *owe_groups;
+       int owe_ptk_workaround;
 #endif /* CONFIG_OWE */
 
        int coloc_intf_reporting;
index 423528d128e338e511a3b0a7917a4336e409f02e..0a807a3c65f7d77745d56972ac89df6eddea845e 100644 (file)
@@ -56,7 +56,7 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
                                       struct wpa_group *group);
 static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
                          const u8 *pmk, unsigned int pmk_len,
-                         struct wpa_ptk *ptk);
+                         struct wpa_ptk *ptk, int force_sha256);
 static void wpa_group_free(struct wpa_authenticator *wpa_auth,
                           struct wpa_group *group);
 static void wpa_group_get(struct wpa_authenticator *wpa_auth,
@@ -926,7 +926,8 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
                        pmk_len = sm->pmk_len;
                }
 
-               if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK) < 0)
+               if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0) <
+                   0)
                        break;
 
                if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
@@ -2233,10 +2234,11 @@ SM_STATE(WPA_PTK, PTKSTART)
 
 static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
                          const u8 *pmk, unsigned int pmk_len,
-                         struct wpa_ptk *ptk)
+                         struct wpa_ptk *ptk, int force_sha256)
 {
        const u8 *z = NULL;
        size_t z_len = 0;
+       int akmp;
 
 #ifdef CONFIG_IEEE80211R_AP
        if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -2262,9 +2264,12 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
        }
 #endif /* CONFIG_DPP2 */
 
+       akmp = sm->wpa_key_mgmt;
+       if (force_sha256)
+               akmp = WPA_KEY_MGMT_PSK_SHA256;
        return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
                              sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
-                             ptk, sm->wpa_key_mgmt, sm->pairwise, z, z_len);
+                             ptk, akmp, sm->pairwise, z, z_len);
 }
 
 
@@ -2844,6 +2849,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
        struct wpa_eapol_key *key;
        struct wpa_eapol_ie_parse kde;
        int vlan_id = 0;
+       int owe_ptk_workaround = !!wpa_auth->conf.owe_ptk_workaround;
 
        SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
        sm->EAPOLKeyReceived = FALSE;
@@ -2881,7 +2887,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                        pmk_len = sm->pmksa->pmk_len;
                }
 
-               if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0)
+               if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK,
+                                  owe_ptk_workaround == 2) < 0)
                        break;
 
                if (mic_len &&
@@ -2905,6 +2912,16 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                }
 #endif /* CONFIG_FILS */
 
+#ifdef CONFIG_OWE
+               if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && pmk_len > 32 &&
+                   owe_ptk_workaround == 1) {
+                       wpa_printf(MSG_DEBUG,
+                                  "OWE: Try PTK derivation workaround with SHA256");
+                       owe_ptk_workaround = 2;
+                       continue;
+               }
+#endif /* CONFIG_OWE */
+
                if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
                    wpa_key_mgmt_sae(sm->wpa_key_mgmt))
                        break;
index 0b4b7297c18ee301cb147d67a9e8df4e7788883a..437719b17ccefe2d115fe73875ea69d566ce56ea 100644 (file)
@@ -237,6 +237,7 @@ struct wpa_auth_config {
        u8 fils_cache_id[FILS_CACHE_ID_LEN];
 #endif /* CONFIG_FILS */
        int sae_pwe;
+       int owe_ptk_workaround;
 };
 
 typedef enum {
index 4927744ef39608688e735f33e8a6ba3ba47754e6..066d7c5fe813948960bf0219fa62c8d8442d4fde 100644 (file)
@@ -162,6 +162,9 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
                wconf->sae_pwe = 1;
        else if (sae_pw_id == 1 && wconf->sae_pwe == 0)
                wconf->sae_pwe = 2;
+#ifdef CONFIG_OWE
+       wconf->owe_ptk_workaround = conf->owe_ptk_workaround;
+#endif /* CONFIG_OWE */
 }