OWE: Process Diffie-Hellman Parameter element in AP mode

This adds AP side processing for OWE Diffie-Hellman Parameter element in
(Re)Association Request frame and adding it in (Re)Association Response
frame.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen
2026-05-05 21:40:29 +05:30
committed by tarun.kumar
parent 5df4063496
commit acfebf2a75
9 changed files with 174 additions and 7 deletions
@@ -28,6 +28,11 @@
#include "ap/ieee802_11.h"
#define WIFI_PASSWORD_LEN_MAX 65
#ifdef CONFIG_OWE_SOFTAP
#include "crypto/crypto.h"
#include "ap/ieee802_11.h"
#endif
struct hostapd_data *global_hapd;
#ifdef CONFIG_SAE
@@ -379,8 +384,46 @@ u16 esp_send_assoc_resp(struct hostapd_data *hapd, const u8 *addr,
if (!omit_rsnxe) {
send_len = esp_wifi_build_rsnxe(hapd, buf, ASSOC_RESP_LENGTH);
}
#ifdef CONFIG_OWE_SOFTAP
#define OWE_DH_GROUP 19
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) {
struct wpabuf *pub;
struct sta_info *sta = ap_get_sta(hapd, addr);
if (!sta) {
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
if (!pub) {
res = WLAN_STATUS_UNSPECIFIED_FAILURE;
return res;
}
struct wpabuf *owe_buf = wpabuf_alloc(37);
if (!owe_buf) {
wpa_printf(MSG_ERROR, "Memory allocation failed for OWE IE");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
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);
wpa_hexdump_buf(MSG_DEBUG, "OWE: Buffer", owe_buf);
int owe_ie_len = wpabuf_len(owe_buf);
esp_wifi_set_appie_internal(WIFI_APPIE_ASSOC_RESP, (uint8_t *)wpabuf_head(owe_buf), owe_ie_len, 0);
}
#else
esp_wifi_set_appie_internal(WIFI_APPIE_ASSOC_RESP, buf, send_len, 0);
#endif /* CONFIG_OWE_SOFTAP */
reply = os_zalloc(sizeof(wifi_mgmt_frm_req_t) + sizeof(uint16_t));
if (!reply) {
@@ -426,7 +469,7 @@ uint8_t wpa_status_to_reason_code(int status)
bool hostap_new_assoc_sta(struct sta_info *sta, uint8_t *bssid, u8 *wpa_ie,
u8 wpa_ie_len, u8 *rsnxe, uint16_t rsnxe_len,
bool *pmf_enable, int subtype, uint8_t *pairwise_cipher, uint8_t *reason, uint8_t *rsn_selection_ie)
bool *pmf_enable, int subtype, uint8_t *pairwise_cipher, uint8_t *reason, uint8_t *rsn_selection_ie, uint8_t *owe_dh, uint8_t owe_ie_len)
{
struct hostapd_data *hapd = (struct hostapd_data*)esp_wifi_get_hostap_private_internal();
enum wpa_validate_result res = WPA_IE_OK;
@@ -476,6 +519,16 @@ bool hostap_new_assoc_sta(struct sta_info *sta, uint8_t *bssid, u8 *wpa_ie,
status = wpa_res_to_status_code(res);
#ifdef CONFIG_OWE_SOFTAP
if (hapd->conf->wpa_key_mgmt == WPA_KEY_MGMT_OWE) {
status = owe_process_assoc_req(sta, owe_dh, owe_ie_len);
if (status != WLAN_STATUS_SUCCESS) {
return status;
}
}
#endif /* CONFIG_OWE_SOFTAP */
send_resp:
if (!rsnxe) {
omit_rsnxe = true;
@@ -130,7 +130,7 @@ struct wpa_funcs {
bool (*wpa_sta_in_4way_handshake)(void);
void *(*wpa_ap_init)(void);
bool (*wpa_ap_deinit)(void *data);
bool (*wpa_ap_join)(void **sm, u8 *bssid, u8 *wpa_ie, u8 wpa_ie_len, u8* rsnxe, u16 rsnxe_len, bool *pmf_enable, int subtype, uint8_t *pairwise_cipher, uint8_t *rsn_selection_ie);
bool (*wpa_ap_join)(void **sm, u8 *bssid, u8 *wpa_ie, u8 wpa_ie_len, u8* rsnxe, u16 rsnxe_len, bool *pmf_enable, int subtype, uint8_t *pairwise_cipher, uint8_t *rsn_selection_ie, uint8_t *owe_dh, uint8_t owe_ie_len);
bool (*wpa_ap_remove)(u8 *bssid);
uint8_t *(*wpa_ap_get_wpa_ie)(size_t *len);
bool (*wpa_ap_rx_eapol)(void *hapd_data, void *sm, u8 *data, size_t data_len);
@@ -389,7 +389,7 @@ static int check_n_add_wps_sta(struct hostapd_data *hapd, struct sta_info *sta_i
}
#endif
static bool hostap_sta_join(void **sta, u8 *bssid, u8 *wpa_ie, u8 wpa_ie_len, u8 *rsnxe, u16 rsnxe_len, bool *pmf_enable, int subtype, uint8_t *pairwise_cipher, uint8_t *rsn_selection_ie)
static bool hostap_sta_join(void **sta, u8 *bssid, u8 *wpa_ie, u8 wpa_ie_len, u8 *rsnxe, u16 rsnxe_len, bool *pmf_enable, int subtype, uint8_t *pairwise_cipher, uint8_t *rsn_selection_ie, uint8_t *owe_dh, uint8_t owe_ie_len)
{
struct sta_info *sta_info = NULL;
struct hostapd_data *hapd = hostapd_get_hapd_data();
@@ -451,7 +451,8 @@ process_old_sta:
goto fail;
}
#endif
if (hostap_new_assoc_sta(sta_info, bssid, wpa_ie, wpa_ie_len, rsnxe, rsnxe_len, pmf_enable, subtype, pairwise_cipher, &reason, rsn_selection_ie)) {
if (hostap_new_assoc_sta(sta_info, bssid, wpa_ie, wpa_ie_len, rsnxe, rsnxe_len, pmf_enable, subtype, pairwise_cipher, &reason, rsn_selection_ie, owe_dh, owe_ie_len)) {
goto done;
} else {
goto fail;
+2 -2
View File
@@ -395,9 +395,9 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
const u8 *addr, const u8 *prev_psk);
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
struct sta_info;
bool hostap_new_assoc_sta(struct sta_info *sta, uint8_t *bssid, u8 *wpa_ie,
bool hostap_new_assoc_sta(struct sta_info *sta, uint8_t *bssid, uint8_t *wpa_ie,
u8 wpa_ie_len, u8 *rsnxe, uint16_t rsnxe_len,
bool *pmf_enable, int subtype, uint8_t *pairwise_cipher, uint8_t *reason, uint8_t *rsn_selection_ie);
bool *pmf_enable, int subtype, uint8_t *pairwise_cipher, uint8_t *reason, uint8_t *rsn_selection_ie, uint8_t *owe_dh, uint8_t owe_ie_len);
bool wpa_ap_remove(u8* bssid);
#endif /* HOSTAPD_CONFIG_H */
@@ -773,3 +773,98 @@ u16 wpa_res_to_status_code(enum wpa_validate_result res)
}
return WLAN_STATUS_INVALID_IE;
}
#ifdef CONFIG_OWE_SOFTAP
#include "crypto/crypto.h"
#define OWE_DH_GROUP 19
uint16_t owe_process_assoc_req(struct sta_info *sta, const uint8_t *owe_dh,
uint8_t owe_dh_len)
{
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 (WPA_GET_LE16(owe_dh + 3) != OWE_DH_GROUP)
return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
crypto_ecdh_deinit(sta->owe_ecdh);
sta->owe_ecdh = crypto_ecdh_init(OWE_DH_GROUP);
if (!sta->owe_ecdh)
return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
secret = crypto_ecdh_set_peerkey(sta->owe_ecdh, 0, owe_dh + 5,
owe_dh_len - 3);
if (!secret) {
wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", secret);
/* prk = HKDF-extract(C | A | group, z) */
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
if (!pub) {
wpabuf_clear_free(secret);
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
/* PMKID = Truncate-128(Hash(C | A)) */
addr[0] = owe_dh + 5;
len[0] = owe_dh_len - 3;
addr[1] = wpabuf_head(pub);
len[1] = wpabuf_len(pub);
res = sha256_vector(2, addr, len, pmkid);
if (res < 0) {
wpabuf_free(pub);
wpabuf_clear_free(secret);
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
hkey = wpabuf_alloc(owe_dh_len - 3 + wpabuf_len(pub) + 2);
if (!hkey) {
wpabuf_free(pub);
wpabuf_clear_free(secret);
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
wpabuf_put_data(hkey, owe_dh + 5, owe_dh_len - 3); /* 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_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);
/* PMK = HKDF-expand(prk, "OWE Key Generation", n) */
os_free(sta->owe_pmk);
sta->owe_pmk = os_malloc(PMK_LEN);
if (!sta->owe_pmk) {
os_memset(prk, 0, SHA256_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 (res < 0) {
os_free(sta->owe_pmk);
sta->owe_pmk = NULL;
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, PMK_LEN);
wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
/* TODO: Add PMKSA cache entry */
return WLAN_STATUS_SUCCESS;
}
#endif /* CONFIG_OWE_SOFTAP */
@@ -16,5 +16,8 @@ int handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
u8 *buf, size_t len, u8 *bssid,
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 uint8_t *owe_dh,
uint8_t owe_dh_len);
#endif
#endif /* IEEE802_11_H */
@@ -127,6 +127,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
wpabuf_free(sta->wps_ie);
#endif
#ifdef CONFIG_OWE_SOFTAP
bin_clear_free(sta->owe_pmk, PMK_LEN);
crypto_ecdh_deinit(sta->owe_ecdh);
#endif /* CONFIG_OWE_SOFTAP */
os_free(sta);
}
@@ -69,6 +69,10 @@ struct sta_info {
struct wpabuf *sae_data;
#endif /* CONFIG_SAE */
#endif /* ESP_SUPPLICANT */
#ifdef CONFIG_OWE_SOFTAP
u8 *owe_pmk;
struct crypto_ecdh *owe_ecdh;
#endif /* CONFIG_OWE_SOFTAP */
};
@@ -150,6 +150,13 @@ 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;
}
#endif /* CONFIG_OWE_SOFTAP */
return (u8*)hostapd_get_psk(hapd->conf, addr, prev_psk);
}