mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-28 01:04:48 +03:00
OWE: PMKSA caching in AP mode
This extends OWE support in hostapd to allow PMKSA caching to be used. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
committed by
tarun.kumar
parent
01380bd7d9
commit
376fb23ff7
@@ -20,6 +20,13 @@
|
||||
#include "esp_wpa3_i.h"
|
||||
#include "esp_hostap.h"
|
||||
|
||||
#ifdef CONFIG_OWE_SOFTAP
|
||||
#include "crypto/crypto.h"
|
||||
#include "ap/wpa_auth_i.h"
|
||||
#define OWE_DH_GRP19 19
|
||||
#define OWE_DHIE_LEN 37
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
|
||||
static void sae_set_state(struct sta_info *sta, enum sae_state state,
|
||||
@@ -775,14 +782,29 @@ u16 wpa_res_to_status_code(enum wpa_validate_result res)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OWE_SOFTAP
|
||||
#include "ap/wpa_auth_i.h"
|
||||
#include "crypto/crypto.h"
|
||||
#define OWE_DH_GRP19 19
|
||||
#define OWE_DHIE_LEN 37
|
||||
uint16_t owe_process_assoc_req(struct sta_info *sta, const uint8_t *owe_dh,
|
||||
uint8_t owe_dh_len)
|
||||
{
|
||||
|
||||
int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
|
||||
int session_timeout, int akmp, const u8 *dpp_pkhash)
|
||||
{
|
||||
if (!wpa_auth || wpa_auth->conf.disable_pmksa_caching)
|
||||
return -1;
|
||||
|
||||
struct rsn_pmksa_cache_entry *entry;
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (3)", pmk, PMK_LEN);
|
||||
entry = pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
|
||||
NULL, 0, wpa_auth->addr, addr, session_timeout,
|
||||
NULL, akmp);
|
||||
if (!entry)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t owe_process_assoc_req(struct hostapd_data *hapd, struct sta_info *sta, const u8 *owe_dh,
|
||||
u8 owe_dh_len)
|
||||
{
|
||||
const u8 *addr[2];
|
||||
size_t len[2];
|
||||
struct wpabuf *hkey, *pub, *secret;
|
||||
@@ -791,6 +813,11 @@ uint16_t owe_process_assoc_req(struct sta_info *sta, const uint8_t *owe_dh,
|
||||
u8 pmkid[SHA256_MAC_LEN];
|
||||
int res;
|
||||
|
||||
if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
|
||||
wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!owe_dh) {
|
||||
wpa_printf(MSG_ERROR, "OWE: Invalid DH data received");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
@@ -801,11 +828,25 @@ uint16_t owe_process_assoc_req(struct sta_info *sta, const uint8_t *owe_dh,
|
||||
if (sta->owe_group != OWE_DH_GRP19)
|
||||
return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
|
||||
|
||||
crypto_ecdh_deinit(sta->owe_ecdh);
|
||||
sta->owe_ecdh = crypto_ecdh_init(OWE_DH_GRP19);
|
||||
if (!sta->owe_ecdh) {
|
||||
wpa_printf(MSG_ERROR, "OWE: Error initializing ECDH for STA");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
if (sta->owe_ecdh) {
|
||||
/* This is a workaround for mac80211 behavior of retransmitting
|
||||
* the Association Request frames multiple times if the link
|
||||
* layer retries (i.e., seq# remains same) fail. The mac80211
|
||||
* initiated retransmission will use a different seq# and as
|
||||
* such, will go through duplicate detection. If we were to
|
||||
* change our DH key for that attempt, there would be two
|
||||
* different DH shared secrets and the STA would likely select
|
||||
* the wrong one. */
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: Try to reuse own previous DH key since the STA tried to go through OWE association again");
|
||||
} else {
|
||||
|
||||
crypto_ecdh_deinit(sta->owe_ecdh);
|
||||
sta->owe_ecdh = crypto_ecdh_init(OWE_DH_GRP19);
|
||||
if (!sta->owe_ecdh) {
|
||||
wpa_printf(MSG_ERROR, "OWE: Error initializing ECDH for STA");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the DH shared secret
|
||||
@@ -888,13 +929,27 @@ uint16_t owe_process_assoc_req(struct sta_info *sta, const uint8_t *owe_dh,
|
||||
wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, PMK_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
|
||||
|
||||
sta->owe_pmk_len = SHA256_MAC_LEN;
|
||||
|
||||
// Add the PMK to the PMKSA cache
|
||||
wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk, sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE, NULL);
|
||||
|
||||
// Update the PMKID in the STA's WPA state machine
|
||||
os_memcpy(sta->wpa_sm->pmkid, pmkid, PMKID_LEN);
|
||||
sta->wpa_sm->pmkid_set = 1;
|
||||
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint8_t *owe_build_assoc_resp_dhie(struct hostapd_data *hapd, const u8 *bssid, int *owe_ie_len)
|
||||
{
|
||||
|
||||
|
||||
if (!hapd || !hapd->wpa_auth || !hapd->wpa_auth->wpa_ie) {
|
||||
wpa_printf(MSG_ERROR, "Invalid hapd or WPA auth data");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wpabuf *pub;
|
||||
struct sta_info *sta = ap_get_sta(hapd, bssid);
|
||||
if (!sta) {
|
||||
@@ -907,34 +962,39 @@ uint8_t *owe_build_assoc_resp_dhie(struct hostapd_data *hapd, const u8 *bssid, i
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u8 *pos, buf[128];
|
||||
// If PMKSA caching is used, write and return only RSN IE with PMKID
|
||||
if (sta->wpa_sm && sta->wpa_sm->pmksa) {
|
||||
u8 *pos, buf[128];
|
||||
pos = buf;
|
||||
|
||||
pos = buf;
|
||||
|
||||
pos = wpa_auth_write_assoc_resp_owe(hapd, sta->wpa_sm, pos,
|
||||
wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching for Assoc Resp");
|
||||
pos = wpa_auth_write_assoc_resp_owe(hapd, sta->wpa_sm, pos,
|
||||
buf + sizeof(buf) - pos);
|
||||
|
||||
wpabuf_resize(&owe_buf, pos - buf);
|
||||
wpabuf_put_data(owe_buf, buf, pos - buf);
|
||||
*owe_ie_len = pos - buf;
|
||||
|
||||
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
|
||||
if (!pub) {
|
||||
return NULL;
|
||||
wpabuf_resize(&owe_buf, pos - buf);
|
||||
wpabuf_put_data(owe_buf, buf, pos - buf);
|
||||
*owe_ie_len = pos - buf;
|
||||
return (uint8_t *)wpabuf_head(owe_buf);
|
||||
}
|
||||
|
||||
if (sta->owe_ecdh) {
|
||||
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
|
||||
if (!pub) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wpa_hexdump_buf(MSG_DEBUG, "Own public key", pub);
|
||||
wpa_hexdump_buf(MSG_DEBUG, "Own public key", pub);
|
||||
|
||||
wpabuf_resize(&owe_buf, OWE_DHIE_LEN);
|
||||
wpabuf_put_u8(owe_buf, WLAN_EID_EXTENSION);
|
||||
wpabuf_put_u8(owe_buf, 1 + 2 + wpabuf_len(pub));
|
||||
wpabuf_put_u8(owe_buf, WLAN_EID_EXT_OWE_DH_PARAM);
|
||||
wpabuf_put_le16(owe_buf, IANA_SECP256R1);
|
||||
wpabuf_put_buf(owe_buf, pub);
|
||||
wpabuf_free(pub);
|
||||
wpabuf_resize(&owe_buf, OWE_DHIE_LEN);
|
||||
wpabuf_put_u8(owe_buf, WLAN_EID_EXTENSION);
|
||||
wpabuf_put_u8(owe_buf, 1 + 2 + wpabuf_len(pub));
|
||||
wpabuf_put_u8(owe_buf, WLAN_EID_EXT_OWE_DH_PARAM);
|
||||
wpabuf_put_le16(owe_buf, IANA_SECP256R1);
|
||||
wpabuf_put_buf(owe_buf, pub);
|
||||
wpabuf_free(pub);
|
||||
|
||||
wpa_hexdump_buf(MSG_DEBUG, "OWE: Buffer", owe_buf);
|
||||
wpa_hexdump_buf(MSG_DEBUG, "OWE: Buffer", owe_buf);
|
||||
}
|
||||
*owe_ie_len = wpabuf_len(owe_buf);
|
||||
|
||||
return (uint8_t *)wpabuf_head(owe_buf);
|
||||
|
||||
@@ -17,7 +17,7 @@ int handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u16 auth_transaction, u16 status);
|
||||
u16 wpa_res_to_status_code(enum wpa_validate_result res);
|
||||
#ifdef CONFIG_OWE_SOFTAP
|
||||
uint16_t owe_process_assoc_req(struct sta_info *sta, const u8 *owe_dh,
|
||||
uint16_t owe_process_assoc_req(struct hostapd_data *hapd, struct sta_info *sta, const u8 *owe_dh,
|
||||
u8 owe_dh_len);
|
||||
uint8_t *owe_build_assoc_resp_dhie(struct hostapd_data *hapd, const u8 *bssid, int *owe_ie_len);
|
||||
#endif /* CONFIG_OWE_SOFTAP */
|
||||
|
||||
@@ -72,6 +72,7 @@ struct sta_info {
|
||||
#ifdef CONFIG_OWE_SOFTAP
|
||||
u16 owe_group;
|
||||
u8 *owe_pmk;
|
||||
size_t owe_pmk_len;
|
||||
struct crypto_ecdh *owe_ecdh;
|
||||
#endif /* CONFIG_OWE_SOFTAP */
|
||||
|
||||
|
||||
@@ -152,9 +152,20 @@ static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
|
||||
#endif /*CONFIG_SAE*/
|
||||
|
||||
#ifdef CONFIG_OWE_SOFTAP
|
||||
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && sta && sta->owe_pmk) {
|
||||
return sta->owe_pmk;
|
||||
}
|
||||
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
|
||||
sta && sta->owe_pmk) {
|
||||
return sta->owe_pmk;
|
||||
}
|
||||
|
||||
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && sta) {
|
||||
struct rsn_pmksa_cache_entry *sa;
|
||||
|
||||
sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
|
||||
if (sa && sa->akmp == WPA_KEY_MGMT_OWE) {
|
||||
return sa->pmk;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_OWE_SOFTAP */
|
||||
#endif /* defined(CONFIG_SAE) || defined(CONFIG_OWE_SOFTAP) */
|
||||
|
||||
@@ -1038,6 +1049,12 @@ void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid)
|
||||
sm->pmkid_set = 1;
|
||||
}
|
||||
|
||||
struct rsn_pmksa_cache_entry *
|
||||
wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm)
|
||||
{
|
||||
return sm ? sm->pmksa : NULL;
|
||||
}
|
||||
|
||||
static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
|
||||
const u8 *gnonce, u8 *gtk, size_t gtk_len)
|
||||
{
|
||||
@@ -1633,6 +1650,9 @@ SM_STATE(WPA_PTK, INITPSK)
|
||||
psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL);
|
||||
if (psk) {
|
||||
memcpy(sm->PMK, psk, PMK_LEN);
|
||||
#ifdef CONFIG_OWE_SOFTAP
|
||||
sm->pmk_len = PMK_LEN;
|
||||
#endif
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
memcpy(sm->xxkey, psk, PMK_LEN);
|
||||
sm->xxkey_len = PMK_LEN;
|
||||
@@ -1671,6 +1691,7 @@ SM_STATE(WPA_PTK, PTKSTART)
|
||||
*/
|
||||
if (sm->wpa == WPA_VERSION_WPA2 &&
|
||||
(wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) ||
|
||||
(sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && sm->pmksa) ||
|
||||
wpa_key_mgmt_sae(sm->wpa_key_mgmt))) {
|
||||
pmkid = buf;
|
||||
pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
|
||||
|
||||
@@ -876,7 +876,8 @@ uint8_t *wpa_auth_write_assoc_resp_owe(struct hostapd_data *hapd, struct wpa_sta
|
||||
{
|
||||
int res;
|
||||
|
||||
res = wpa_write_rsn_ie(&hapd->wpa_auth->conf, pos, max_len, NULL);
|
||||
res = wpa_write_rsn_ie(&hapd->wpa_auth->conf, pos, max_len,
|
||||
sm->pmksa ? sm->pmksa->pmkid : NULL, hapd->wpa_auth->conf.group_mgmt_cipher);
|
||||
if (res < 0)
|
||||
return pos;
|
||||
return pos + res;
|
||||
|
||||
Reference in New Issue
Block a user