Browse Source

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 <jouni@qca.qualcomm.com>
Jouni Malinen 7 years ago
parent
commit
7a12edd163

+ 5 - 0
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

+ 5 - 0
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

+ 59 - 17
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];
-
-	if (WPA_GET_LE16(owe_dh) != OWE_DH_GROUP)
+	u16 group;
+	size_t hash_len, prime_len;
+
+	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);

+ 1 - 1
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 */
 

+ 2 - 0
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 */
 };
 

+ 13 - 12
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) {

+ 1 - 1
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);

+ 1 - 1
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);
 }
 
 

+ 8 - 2
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);

+ 5 - 1
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)

+ 4 - 1
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);