diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c b/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c index 300b14c42a9..3ce012b32a3 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c @@ -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; diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h index e1361ab5f2d..199c4c03754 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h @@ -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); diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c index 0e481718e96..990be107e08 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c @@ -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; diff --git a/components/wpa_supplicant/src/ap/ap_config.h b/components/wpa_supplicant/src/ap/ap_config.h index 49aa678c82c..65d5dc7c386 100644 --- a/components/wpa_supplicant/src/ap/ap_config.h +++ b/components/wpa_supplicant/src/ap/ap_config.h @@ -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 */ diff --git a/components/wpa_supplicant/src/ap/ieee802_11.c b/components/wpa_supplicant/src/ap/ieee802_11.c index 786987eb80f..9c8493faf4d 100644 --- a/components/wpa_supplicant/src/ap/ieee802_11.c +++ b/components/wpa_supplicant/src/ap/ieee802_11.c @@ -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 */ diff --git a/components/wpa_supplicant/src/ap/ieee802_11.h b/components/wpa_supplicant/src/ap/ieee802_11.h index 2136a1e2c32..7c59f84ceac 100644 --- a/components/wpa_supplicant/src/ap/ieee802_11.h +++ b/components/wpa_supplicant/src/ap/ieee802_11.h @@ -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 */ diff --git a/components/wpa_supplicant/src/ap/sta_info.c b/components/wpa_supplicant/src/ap/sta_info.c index 28daefb5479..dde4cbb94c8 100644 --- a/components/wpa_supplicant/src/ap/sta_info.c +++ b/components/wpa_supplicant/src/ap/sta_info.c @@ -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); } diff --git a/components/wpa_supplicant/src/ap/sta_info.h b/components/wpa_supplicant/src/ap/sta_info.h index 3c3769dd1af..38906c3112f 100644 --- a/components/wpa_supplicant/src/ap/sta_info.h +++ b/components/wpa_supplicant/src/ap/sta_info.h @@ -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 */ }; diff --git a/components/wpa_supplicant/src/ap/wpa_auth.c b/components/wpa_supplicant/src/ap/wpa_auth.c index da60b9d23e0..54fbeb1444e 100644 --- a/components/wpa_supplicant/src/ap/wpa_auth.c +++ b/components/wpa_supplicant/src/ap/wpa_auth.c @@ -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); }