OWE: PTK derivation workaround in AP mode
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>
This commit is contained in:
parent
bd50805e40
commit
65a44e849a
6 changed files with 42 additions and 5 deletions
|
@ -4412,6 +4412,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||||
line, pos);
|
line, pos);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
} else if (os_strcmp(buf, "owe_ptk_workaround") == 0) {
|
||||||
|
bss->owe_ptk_workaround = atoi(pos);
|
||||||
#endif /* CONFIG_OWE */
|
#endif /* CONFIG_OWE */
|
||||||
} else if (os_strcmp(buf, "coloc_intf_reporting") == 0) {
|
} else if (os_strcmp(buf, "coloc_intf_reporting") == 0) {
|
||||||
bss->coloc_intf_reporting = atoi(pos);
|
bss->coloc_intf_reporting = atoi(pos);
|
||||||
|
|
|
@ -1817,6 +1817,19 @@ own_ip_addr=127.0.0.1
|
||||||
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
|
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
|
||||||
#owe_groups=19 20 21
|
#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
|
# OWE transition mode configuration
|
||||||
# Pointer to the matching open/OWE BSS
|
# Pointer to the matching open/OWE BSS
|
||||||
#owe_transition_bssid=<bssid>
|
#owe_transition_bssid=<bssid>
|
||||||
|
|
|
@ -733,6 +733,7 @@ struct hostapd_bss_config {
|
||||||
size_t owe_transition_ssid_len;
|
size_t owe_transition_ssid_len;
|
||||||
char owe_transition_ifname[IFNAMSIZ + 1];
|
char owe_transition_ifname[IFNAMSIZ + 1];
|
||||||
int *owe_groups;
|
int *owe_groups;
|
||||||
|
int owe_ptk_workaround;
|
||||||
#endif /* CONFIG_OWE */
|
#endif /* CONFIG_OWE */
|
||||||
|
|
||||||
int coloc_intf_reporting;
|
int coloc_intf_reporting;
|
||||||
|
|
|
@ -56,7 +56,7 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
|
||||||
struct wpa_group *group);
|
struct wpa_group *group);
|
||||||
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
||||||
const u8 *pmk, unsigned int pmk_len,
|
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,
|
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
|
||||||
struct wpa_group *group);
|
struct wpa_group *group);
|
||||||
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
|
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;
|
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;
|
break;
|
||||||
|
|
||||||
if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
|
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,
|
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
||||||
const u8 *pmk, unsigned int pmk_len,
|
const u8 *pmk, unsigned int pmk_len,
|
||||||
struct wpa_ptk *ptk)
|
struct wpa_ptk *ptk, int force_sha256)
|
||||||
{
|
{
|
||||||
const u8 *z = NULL;
|
const u8 *z = NULL;
|
||||||
size_t z_len = 0;
|
size_t z_len = 0;
|
||||||
|
int akmp;
|
||||||
|
|
||||||
#ifdef CONFIG_IEEE80211R_AP
|
#ifdef CONFIG_IEEE80211R_AP
|
||||||
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
|
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 */
|
#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",
|
return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
|
||||||
sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
|
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_key *key;
|
||||||
struct wpa_eapol_ie_parse kde;
|
struct wpa_eapol_ie_parse kde;
|
||||||
int vlan_id = 0;
|
int vlan_id = 0;
|
||||||
|
int owe_ptk_workaround = !!wpa_auth->conf.owe_ptk_workaround;
|
||||||
|
|
||||||
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
|
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
|
||||||
sm->EAPOLKeyReceived = FALSE;
|
sm->EAPOLKeyReceived = FALSE;
|
||||||
|
@ -2881,7 +2887,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||||
pmk_len = sm->pmksa->pmk_len;
|
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;
|
break;
|
||||||
|
|
||||||
if (mic_len &&
|
if (mic_len &&
|
||||||
|
@ -2905,6 +2912,16 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_FILS */
|
#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) ||
|
if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
|
||||||
wpa_key_mgmt_sae(sm->wpa_key_mgmt))
|
wpa_key_mgmt_sae(sm->wpa_key_mgmt))
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -237,6 +237,7 @@ struct wpa_auth_config {
|
||||||
u8 fils_cache_id[FILS_CACHE_ID_LEN];
|
u8 fils_cache_id[FILS_CACHE_ID_LEN];
|
||||||
#endif /* CONFIG_FILS */
|
#endif /* CONFIG_FILS */
|
||||||
int sae_pwe;
|
int sae_pwe;
|
||||||
|
int owe_ptk_workaround;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
|
@ -162,6 +162,9 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||||
wconf->sae_pwe = 1;
|
wconf->sae_pwe = 1;
|
||||||
else if (sae_pw_id == 1 && wconf->sae_pwe == 0)
|
else if (sae_pw_id == 1 && wconf->sae_pwe == 0)
|
||||||
wconf->sae_pwe = 2;
|
wconf->sae_pwe = 2;
|
||||||
|
#ifdef CONFIG_OWE
|
||||||
|
wconf->owe_ptk_workaround = conf->owe_ptk_workaround;
|
||||||
|
#endif /* CONFIG_OWE */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue