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:
Jouni Malinen 2017-10-08 16:37:32 +03:00 committed by Jouni Malinen
parent 6c4726189c
commit 7a12edd163
11 changed files with 103 additions and 35 deletions

View file

@ -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

View file

@ -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

View file

@ -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);
if (group == 19) {
res = sha256_vector(2, addr, len, pmkid);
if (res < 0) {
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 */
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);

View file

@ -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 */

View file

@ -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 */
};

View file

@ -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) {

View file

@ -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);

View file

@ -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);
}

View file

@ -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);

View file

@ -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)

View file

@ -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);