From 7a12edd163ff0e50b9c89ce0407577da500299af Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 8 Oct 2017 16:37:32 +0300 Subject: [PATCH] OWE: Support DH groups 20 (NIST P-384) and 21 (NIST P-521) in AP mode This extends OWE support in hostapd to allow DH groups 20 and 21 to be used in addition to the mandatory group 19 (NIST P-256). Signed-off-by: Jouni Malinen --- hostapd/Android.mk | 5 +++ hostapd/Makefile | 5 +++ src/ap/ieee802_11.c | 74 ++++++++++++++++++++++++++++++--------- src/ap/sta_info.c | 2 +- src/ap/sta_info.h | 2 ++ src/ap/wpa_auth.c | 25 ++++++------- src/ap/wpa_auth.h | 2 +- src/ap/wpa_auth_ft.c | 2 +- src/ap/wpa_auth_glue.c | 10 ++++-- wpa_supplicant/ibss_rsn.c | 6 +++- wpa_supplicant/mesh_rsn.c | 5 ++- 11 files changed, 103 insertions(+), 35 deletions(-) diff --git a/hostapd/Android.mk b/hostapd/Android.mk index 0e781a314..a1153b36f 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -274,6 +274,11 @@ ifdef CONFIG_OWE L_CFLAGS += -DCONFIG_OWE NEED_ECC=y NEED_HMAC_SHA256_KDF=y +NEED_HMAC_SHA384_KDF=y +NEED_HMAC_SHA512_KDF=y +NEED_SHA256=y +NEED_SHA384=y +NEED_SHA512=y endif ifdef CONFIG_FILS diff --git a/hostapd/Makefile b/hostapd/Makefile index c54de3917..a00e11c62 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -318,6 +318,11 @@ ifdef CONFIG_OWE CFLAGS += -DCONFIG_OWE NEED_ECC=y NEED_HMAC_SHA256_KDF=y +NEED_HMAC_SHA384_KDF=y +NEED_HMAC_SHA512_KDF=y +NEED_SHA256=y +NEED_SHA384=y +NEED_SHA512=y endif ifdef CONFIG_FILS diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index e4daec2e1..25d8e3b2d 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -14,6 +14,8 @@ #include "utils/eloop.h" #include "crypto/crypto.h" #include "crypto/sha256.h" +#include "crypto/sha384.h" +#include "crypto/sha512.h" #include "crypto/random.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" @@ -2131,21 +2133,32 @@ static u16 owe_process_assoc_req(struct sta_info *sta, const u8 *owe_dh, { struct wpabuf *secret, *pub, *hkey; int res; - u8 prk[SHA256_MAC_LEN], pmkid[SHA256_MAC_LEN]; + u8 prk[SHA512_MAC_LEN], pmkid[SHA512_MAC_LEN]; const char *info = "OWE Key Generation"; const u8 *addr[2]; size_t len[2]; + u16 group; + size_t hash_len, prime_len; - if (WPA_GET_LE16(owe_dh) != OWE_DH_GROUP) + group = WPA_GET_LE16(owe_dh); + if (group == 19) + prime_len = 32; + else if (group == 20) + prime_len = 48; + else if (group == 21) + prime_len = 66; + else return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; crypto_ecdh_deinit(sta->owe_ecdh); - sta->owe_ecdh = crypto_ecdh_init(OWE_DH_GROUP); + sta->owe_ecdh = crypto_ecdh_init(group); if (!sta->owe_ecdh) return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; + sta->owe_group = group; secret = crypto_ecdh_set_peerkey(sta->owe_ecdh, 0, owe_dh + 2, owe_dh_len - 2); + secret = wpabuf_zeropad(secret, prime_len); if (!secret) { wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key"); return WLAN_STATUS_UNSPECIFIED_FAILURE; @@ -2165,8 +2178,22 @@ static u16 owe_process_assoc_req(struct sta_info *sta, const u8 *owe_dh, len[0] = owe_dh_len - 2; addr[1] = wpabuf_head(pub); len[1] = wpabuf_len(pub); - res = sha256_vector(2, addr, len, pmkid); - if (res < 0) { + if (group == 19) { + res = sha256_vector(2, addr, len, pmkid); + hash_len = SHA256_MAC_LEN; + } else if (group == 20) { + res = sha384_vector(2, addr, len, pmkid); + hash_len = SHA384_MAC_LEN; + } else if (group == 21) { + res = sha512_vector(2, addr, len, pmkid); + hash_len = SHA512_MAC_LEN; + } else { + wpabuf_free(pub); + wpabuf_clear_free(secret); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + pub = wpabuf_zeropad(pub, prime_len); + if (res < 0 || !pub) { wpabuf_free(pub); wpabuf_clear_free(secret); return WLAN_STATUS_UNSPECIFIED_FAILURE; @@ -2182,35 +2209,50 @@ static u16 owe_process_assoc_req(struct sta_info *sta, const u8 *owe_dh, wpabuf_put_data(hkey, owe_dh + 2, owe_dh_len - 2); /* C */ wpabuf_put_buf(hkey, pub); /* A */ wpabuf_free(pub); - wpabuf_put_le16(hkey, OWE_DH_GROUP); /* group */ - res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey), - wpabuf_head(secret), wpabuf_len(secret), prk); + wpabuf_put_le16(hkey, group); /* group */ + if (group == 19) + res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey), + wpabuf_head(secret), wpabuf_len(secret), prk); + else if (group == 20) + res = hmac_sha384(wpabuf_head(hkey), wpabuf_len(hkey), + wpabuf_head(secret), wpabuf_len(secret), prk); + else if (group == 21) + res = hmac_sha512(wpabuf_head(hkey), wpabuf_len(hkey), + wpabuf_head(secret), wpabuf_len(secret), prk); wpabuf_clear_free(hkey); wpabuf_clear_free(secret); if (res < 0) return WLAN_STATUS_UNSPECIFIED_FAILURE; - wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, SHA256_MAC_LEN); + wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len); /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */ os_free(sta->owe_pmk); - sta->owe_pmk = os_malloc(PMK_LEN); + sta->owe_pmk = os_malloc(hash_len); if (!sta->owe_pmk) { - os_memset(prk, 0, SHA256_MAC_LEN); + os_memset(prk, 0, SHA512_MAC_LEN); return WLAN_STATUS_UNSPECIFIED_FAILURE; } - res = hmac_sha256_kdf(prk, SHA256_MAC_LEN, NULL, (const u8 *) info, - os_strlen(info), sta->owe_pmk, PMK_LEN); - os_memset(prk, 0, SHA256_MAC_LEN); + if (group == 19) + res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *) info, + os_strlen(info), sta->owe_pmk, hash_len); + else if (group == 20) + res = hmac_sha384_kdf(prk, hash_len, NULL, (const u8 *) info, + os_strlen(info), sta->owe_pmk, hash_len); + else if (group == 21) + res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info, + os_strlen(info), sta->owe_pmk, hash_len); + os_memset(prk, 0, SHA512_MAC_LEN); if (res < 0) { os_free(sta->owe_pmk); sta->owe_pmk = NULL; return WLAN_STATUS_UNSPECIFIED_FAILURE; } + sta->owe_pmk_len = hash_len; - wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, PMK_LEN); + wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len); wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN); /* TODO: Add PMKSA cache entry */ @@ -2822,7 +2864,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, *p++ = WLAN_EID_EXTENSION; /* Element ID */ *p++ = 1 + 2 + wpabuf_len(pub); /* Length */ *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */ - WPA_PUT_LE16(p, OWE_DH_GROUP); + WPA_PUT_LE16(p, sta->owe_group); p += 2; os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub)); p += wpabuf_len(pub); diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index 1e21282c9..b1fde3cf9 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -353,7 +353,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) #endif /* CONFIG_FILS */ #ifdef CONFIG_OWE - bin_clear_free(sta->owe_pmk, PMK_LEN); + bin_clear_free(sta->owe_pmk, sta->owe_pmk_len); crypto_ecdh_deinit(sta->owe_ecdh); #endif /* CONFIG_OWE */ diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index 271128b9e..efbbcebb3 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -246,7 +246,9 @@ struct sta_info { #ifdef CONFIG_OWE u8 *owe_pmk; + size_t owe_pmk_len; struct crypto_ecdh *owe_ecdh; + u16 owe_group; #endif /* CONFIG_OWE */ }; diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index aca687c70..5a37a09cc 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -110,12 +110,12 @@ static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth, static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth, const u8 *addr, const u8 *p2p_dev_addr, - const u8 *prev_psk) + const u8 *prev_psk, size_t *psk_len) { if (wpa_auth->cb->get_psk == NULL) return NULL; return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr, - prev_psk); + prev_psk, psk_len); } @@ -848,17 +848,16 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, struct wpa_ptk PTK; int ok = 0; const u8 *pmk = NULL; - unsigned int pmk_len; + size_t pmk_len; os_memset(&PTK, 0, sizeof(PTK)); for (;;) { if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) { pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, - sm->p2p_dev_addr, pmk); + sm->p2p_dev_addr, pmk, &pmk_len); if (pmk == NULL) break; - pmk_len = PMK_LEN; } else { pmk = sm->PMK; pmk_len = sm->pmk_len; @@ -2020,11 +2019,14 @@ SM_STATE(WPA_PTK, INITPMK) SM_STATE(WPA_PTK, INITPSK) { const u8 *psk; + size_t psk_len; + SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk); - psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL); + psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL, + &psk_len); if (psk) { - os_memcpy(sm->PMK, psk, PMK_LEN); - sm->pmk_len = PMK_LEN; + os_memcpy(sm->PMK, psk, psk_len); + sm->pmk_len = psk_len; #ifdef CONFIG_IEEE80211R_AP os_memcpy(sm->xxkey, psk, PMK_LEN); sm->xxkey_len = PMK_LEN; @@ -2619,7 +2621,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) struct wpa_ptk PTK; int ok = 0, psk_found = 0; const u8 *pmk = NULL; - unsigned int pmk_len; + size_t pmk_len; int ft; const u8 *eapol_key_ie, *key_data, *mic; u16 key_data_length; @@ -2642,11 +2644,10 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) { pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, - sm->p2p_dev_addr, pmk); + sm->p2p_dev_addr, pmk, &pmk_len); if (pmk == NULL) break; psk_found = 1; - pmk_len = PMK_LEN; } else { pmk = sm->PMK; pmk_len = sm->pmk_len; @@ -3169,7 +3170,7 @@ SM_STEP(WPA_PTK) break; case WPA_PTK_INITPSK: if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, - NULL)) { + NULL, NULL)) { SM_ENTER(WPA_PTK, PTKSTART); #ifdef CONFIG_SAE } else if (wpa_auth_uses_sae(sm) && sm->pmksa) { diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 9ef660af1..49aadee72 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -236,7 +236,7 @@ struct wpa_auth_callbacks { int value); int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var); const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *p2p_dev_addr, - const u8 *prev_psk); + const u8 *prev_psk, size_t *psk_len); int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len); int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg, const u8 *addr, int idx, u8 *key, size_t key_len); diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index dd99db70a..0ca27f8b9 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -443,7 +443,7 @@ static const u8 * wpa_ft_get_psk(struct wpa_authenticator *wpa_auth, if (wpa_auth->cb->get_psk == NULL) return NULL; return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr, - prev_psk); + prev_psk, NULL); } diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 5a09fb392..a44fd90fb 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -238,12 +238,15 @@ static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr, static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, const u8 *p2p_dev_addr, - const u8 *prev_psk) + const u8 *prev_psk, size_t *psk_len) { struct hostapd_data *hapd = ctx; struct sta_info *sta = ap_get_sta(hapd, addr); const u8 *psk; + if (psk_len) + *psk_len = PMK_LEN; + #ifdef CONFIG_SAE if (sta && sta->auth_alg == WLAN_AUTH_SAE) { if (!sta->sae || prev_psk) @@ -259,8 +262,11 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, #ifdef CONFIG_OWE if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && - sta && sta->owe_pmk) + sta && sta->owe_pmk) { + if (psk_len) + *psk_len = sta->owe_pmk_len; return sta->owe_pmk; + } #endif /* CONFIG_OWE */ psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk); diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c index 9b6c41698..00919d14a 100644 --- a/wpa_supplicant/ibss_rsn.c +++ b/wpa_supplicant/ibss_rsn.c @@ -259,9 +259,13 @@ static void auth_logger(void *ctx, const u8 *addr, logger_level level, static const u8 * auth_get_psk(void *ctx, const u8 *addr, - const u8 *p2p_dev_addr, const u8 *prev_psk) + const u8 *p2p_dev_addr, const u8 *prev_psk, + size_t *psk_len) { struct ibss_rsn *ibss_rsn = ctx; + + if (psk_len) + *psk_len = PMK_LEN; wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", __func__, MAC2STR(addr), prev_psk); if (prev_psk) diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c index 628382cbf..90137c444 100644 --- a/wpa_supplicant/mesh_rsn.c +++ b/wpa_supplicant/mesh_rsn.c @@ -75,12 +75,15 @@ static void auth_logger(void *ctx, const u8 *addr, logger_level level, static const u8 *auth_get_psk(void *ctx, const u8 *addr, - const u8 *p2p_dev_addr, const u8 *prev_psk) + const u8 *p2p_dev_addr, const u8 *prev_psk, + size_t *psk_len) { struct mesh_rsn *mesh_rsn = ctx; struct hostapd_data *hapd = mesh_rsn->wpa_s->ifmsh->bss[0]; struct sta_info *sta = ap_get_sta(hapd, addr); + if (psk_len) + *psk_len = PMK_LEN; wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", __func__, MAC2STR(addr), prev_psk);