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>
This commit is contained in:
parent
6c4726189c
commit
7a12edd163
11 changed files with 103 additions and 35 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue