OWE: Process Diffie-Hellman Parameter element in STA mode
This adds STA side addition of OWE Diffie-Hellman Parameter element into (Re)Association Request frame and processing it in (Re)Association Response frame. Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
09368515d1
commit
0a6147991e
5 changed files with 185 additions and 2 deletions
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* WPA Supplicant - WPA state machine and EAPOL-Key processing
|
||||
* Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
|
||||
* Copyright(c) 2015 Intel Deutschland GmbH
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
|
@ -15,6 +15,7 @@
|
|||
#include "crypto/crypto.h"
|
||||
#include "crypto/random.h"
|
||||
#include "crypto/aes_siv.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "eap_common/eap_defs.h"
|
||||
|
@ -2447,6 +2448,9 @@ void wpa_sm_deinit(struct wpa_sm *sm)
|
|||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
wpabuf_free(sm->test_assoc_ie);
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#ifdef CONFIG_OWE
|
||||
crypto_ecdh_deinit(sm->owe_ecdh);
|
||||
#endif /* CONFIG_OWE */
|
||||
os_free(sm);
|
||||
}
|
||||
|
||||
|
@ -3814,3 +3818,139 @@ int wpa_fils_is_completed(struct wpa_sm *sm)
|
|||
return 0;
|
||||
#endif /* CONFIG_FILS */
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
|
||||
struct wpabuf * owe_build_assoc_req(struct wpa_sm *sm)
|
||||
{
|
||||
struct wpabuf *ie = NULL, *pub = NULL;
|
||||
|
||||
crypto_ecdh_deinit(sm->owe_ecdh);
|
||||
sm->owe_ecdh = crypto_ecdh_init(OWE_DH_GROUP);
|
||||
if (!sm->owe_ecdh)
|
||||
goto fail;
|
||||
pub = crypto_ecdh_get_pubkey(sm->owe_ecdh, 0);
|
||||
if (!pub)
|
||||
goto fail;
|
||||
|
||||
ie = wpabuf_alloc(5 + wpabuf_len(pub));
|
||||
if (!ie)
|
||||
goto fail;
|
||||
wpabuf_put_u8(ie, WLAN_EID_EXTENSION);
|
||||
wpabuf_put_u8(ie, 1 + 2 + wpabuf_len(pub));
|
||||
wpabuf_put_u8(ie, WLAN_EID_EXT_OWE_DH_PARAM);
|
||||
wpabuf_put_le16(ie, OWE_DH_GROUP);
|
||||
wpabuf_put_buf(ie, pub);
|
||||
wpabuf_free(pub);
|
||||
wpa_hexdump_buf(MSG_DEBUG, "OWE: Diffie-Hellman Parameter element",
|
||||
ie);
|
||||
|
||||
return ie;
|
||||
fail:
|
||||
wpabuf_free(pub);
|
||||
crypto_ecdh_deinit(sm->owe_ecdh);
|
||||
sm->owe_ecdh = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int owe_process_assoc_resp(struct wpa_sm *sm, const u8 *resp_ies,
|
||||
size_t resp_ies_len)
|
||||
{
|
||||
struct ieee802_11_elems elems;
|
||||
u16 group;
|
||||
struct wpabuf *secret, *pub, *hkey;
|
||||
int res;
|
||||
u8 prk[SHA256_MAC_LEN], pmkid[SHA256_MAC_LEN];
|
||||
const char *info = "OWE Key Generation";
|
||||
const u8 *addr[2];
|
||||
size_t len[2];
|
||||
|
||||
if (!resp_ies ||
|
||||
ieee802_11_parse_elems(resp_ies, resp_ies_len, &elems, 1) ==
|
||||
ParseFailed ||
|
||||
!elems.owe_dh) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"OWE: No Diffie-Hellman Parameter element found in Association Response frame");
|
||||
return -1;
|
||||
}
|
||||
|
||||
group = WPA_GET_LE16(elems.owe_dh);
|
||||
if (group != OWE_DH_GROUP) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"OWE: Unexpected Diffie-Hellman group in response: %u",
|
||||
group);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!sm->owe_ecdh) {
|
||||
wpa_printf(MSG_INFO, "OWE: No ECDH state available");
|
||||
return -1;
|
||||
}
|
||||
|
||||
secret = crypto_ecdh_set_peerkey(sm->owe_ecdh, 0,
|
||||
elems.owe_dh + 2,
|
||||
elems.owe_dh_len - 2);
|
||||
if (!secret) {
|
||||
wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key");
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", secret);
|
||||
|
||||
/* prk = HKDF-extract(C | A | group, z) */
|
||||
|
||||
pub = crypto_ecdh_get_pubkey(sm->owe_ecdh, 0);
|
||||
if (!pub) {
|
||||
wpabuf_clear_free(secret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* PMKID = Truncate-128(Hash(C | A)) */
|
||||
addr[0] = wpabuf_head(pub);
|
||||
len[0] = wpabuf_len(pub);
|
||||
addr[1] = elems.owe_dh + 2;
|
||||
len[1] = elems.owe_dh_len - 2;
|
||||
res = sha256_vector(2, addr, len, pmkid);
|
||||
if (res < 0) {
|
||||
wpabuf_free(pub);
|
||||
wpabuf_clear_free(secret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hkey = wpabuf_alloc(wpabuf_len(pub) + elems.owe_dh_len - 2 + 2);
|
||||
if (!hkey) {
|
||||
wpabuf_free(pub);
|
||||
wpabuf_clear_free(secret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpabuf_put_buf(hkey, pub); /* C */
|
||||
wpabuf_free(pub);
|
||||
wpabuf_put_data(hkey, elems.owe_dh + 2, elems.owe_dh_len - 2); /* A */
|
||||
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_clear_free(hkey);
|
||||
wpabuf_clear_free(secret);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, SHA256_MAC_LEN);
|
||||
|
||||
/* PMK = HKDF-expand(prk, "OWE Key Generation", n) */
|
||||
|
||||
res = hmac_sha256_kdf(prk, SHA256_MAC_LEN, NULL, (const u8 *) info,
|
||||
os_strlen(info), sm->pmk, PMK_LEN);
|
||||
os_memset(prk, 0, SHA256_MAC_LEN);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sm->pmk, PMK_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
|
||||
/* TODO: Add PMKSA cache entry */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_OWE */
|
||||
|
|
|
@ -446,4 +446,8 @@ struct wpabuf * fils_build_assoc_req(struct wpa_sm *sm, const u8 **kek,
|
|||
int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len);
|
||||
int wpa_fils_is_completed(struct wpa_sm *sm);
|
||||
|
||||
struct wpabuf * owe_build_assoc_req(struct wpa_sm *sm);
|
||||
int owe_process_assoc_resp(struct wpa_sm *sm, const u8 *resp_ies,
|
||||
size_t resp_ies_len);
|
||||
|
||||
#endif /* WPA_H */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Internal WPA/RSN supplicant state machine definitions
|
||||
* Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
|
@ -152,6 +152,10 @@ struct wpa_sm {
|
|||
u8 fils_erp_pmkid[PMKID_LEN];
|
||||
u8 fils_cache_id[FILS_CACHE_ID_LEN];
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
struct crypto_ecdh *owe_ecdh;
|
||||
#endif /* CONFIG_OWE */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -2225,6 +2225,16 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
|
|||
#endif /* CONFIG_SME */
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
|
||||
owe_process_assoc_resp(wpa_s->wpa,
|
||||
data->assoc_info.resp_ies,
|
||||
data->assoc_info.resp_ies_len) < 0) {
|
||||
wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED);
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_SME
|
||||
if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
|
||||
|
|
|
@ -1064,6 +1064,31 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
|
|||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
if (auth_type == WLAN_AUTH_OPEN &&
|
||||
wpa_s->key_mgmt == WPA_KEY_MGMT_OWE) {
|
||||
struct wpabuf *owe_ie;
|
||||
|
||||
owe_ie = owe_build_assoc_req(wpa_s->wpa);
|
||||
if (!owe_ie) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"OWE: Failed to build IE for Association Request frame");
|
||||
return;
|
||||
}
|
||||
if (wpa_s->sme.assoc_req_ie_len + wpabuf_len(owe_ie) >
|
||||
sizeof(wpa_s->sme.assoc_req_ie)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"OWE: Not enough buffer room for own Association Request frame elements");
|
||||
wpabuf_free(owe_ie);
|
||||
return;
|
||||
}
|
||||
os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
|
||||
wpabuf_head(owe_ie), wpabuf_len(owe_ie));
|
||||
wpa_s->sme.assoc_req_ie_len += wpabuf_len(owe_ie);
|
||||
wpabuf_free(owe_ie);
|
||||
}
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
params.bssid = bssid;
|
||||
params.ssid = wpa_s->sme.ssid;
|
||||
params.ssid_len = wpa_s->sme.ssid_len;
|
||||
|
|
Loading…
Reference in a new issue