diff --git a/components/esp_common/src/esp_err_to_name.c b/components/esp_common/src/esp_err_to_name.c index 45e5d11f6e..a6ac17ddbd 100644 --- a/components/esp_common/src/esp_err_to_name.c +++ b/components/esp_common/src/esp_err_to_name.c @@ -62,6 +62,9 @@ #if __has_include("ulp_common.h") #include "ulp_common.h" #endif +#if __has_include("esp_supplicant/esp_dpp.h") +#include "esp_supplicant/esp_dpp.h" +#endif #ifdef CONFIG_ESP_ERR_TO_NAME_LOOKUP #define ERR_TBL_IT(err) {err, #err} @@ -407,6 +410,25 @@ static const esp_err_msg_t esp_err_msg_table[] = { # endif # ifdef ESP_ERR_ESPNOW_IF ERR_TBL_IT(ESP_ERR_ESPNOW_IF), /* 12396 0x306c Interface error */ +# endif + // components/wpa_supplicant/include/esp_supplicant/esp_dpp.h +# ifdef ESP_ERR_DPP_FAILURE + ERR_TBL_IT(ESP_ERR_DPP_FAILURE), /* 12439 0x3097 Generic failure during DPP Operation */ +# endif +# ifdef ESP_ERR_DPP_NO_MEM + ERR_TBL_IT(ESP_ERR_DPP_NO_MEM), /* 12440 0x3098 Failure to allocate memory in DPP Operation */ +# endif +# ifdef ESP_ERR_DPP_TIMEOUT + ERR_TBL_IT(ESP_ERR_DPP_TIMEOUT), /* 12441 0x3099 DPP Operation timed out */ +# endif +# ifdef ESP_ERR_DPP_TX_FAILURE + ERR_TBL_IT(ESP_ERR_DPP_TX_FAILURE), /* 12442 0x309a DPP Frame Tx failed OR not Acked */ +# endif +# ifdef ESP_ERR_DPP_INVALID_ATTR + ERR_TBL_IT(ESP_ERR_DPP_INVALID_ATTR), /* 12443 0x309b Encountered invalid DPP Attribute */ +# endif +# ifdef ESP_ERR_DPP_NOT_SUPPORTED + ERR_TBL_IT(ESP_ERR_DPP_NOT_SUPPORTED), /* 12444 0x309c DPP Configuration not supported */ # endif // components/esp_common/include/esp_err.h # ifdef ESP_ERR_MESH_BASE diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index e72afb2e09..131cf35884 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -331,6 +331,12 @@ menu "Wi-Fi" If neither of them are enabled, the other 7.4KB IRAM memory would be taken by this option. Wi-Fi power-save mode average current would be reduced if this option is enabled. + config ESP32_WIFI_OFFCHANNEL_OPS + bool "Enable Offchannel operations" + default n + help + Select this option to enable Offchannel Tx and Remain on Channel features. + endmenu # Wi-Fi menu "PHY" diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index 377b8a8e5a..799e3e7153 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -18,7 +18,7 @@ set(srcs "port/os_xtensa.c" "src/crypto/aes-omac1.c" "src/crypto/aes-unwrap.c" "src/crypto/aes-wrap.c" - "src/crypto/aes-omac1.c" + "src/crypto/sha256-tlsprf.c" "src/crypto/bignum.c" "src/crypto/ccmp.c" "src/crypto/crypto_mbedtls.c" @@ -63,6 +63,7 @@ set(srcs "port/os_xtensa.c" "src/esp_supplicant/esp_wpas_glue.c" "src/esp_supplicant/esp_wps.c" "src/esp_supplicant/esp_wpa3.c" + "src/esp_supplicant/esp_dpp.c" "src/rsn_supp/pmksa_cache.c" "src/rsn_supp/wpa.c" "src/rsn_supp/wpa_ie.c" diff --git a/components/wpa_supplicant/include/esp_supplicant/esp_dpp.h b/components/wpa_supplicant/include/esp_supplicant/esp_dpp.h new file mode 100644 index 0000000000..0e5bccbf55 --- /dev/null +++ b/components/wpa_supplicant/include/esp_supplicant/esp_dpp.h @@ -0,0 +1,59 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ESP_DPP_H +#define ESP_DPP_H + +#include + +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_ERR_DPP_FAILURE (ESP_ERR_WIFI_BASE + 151) /*!< Generic failure during DPP Operation */ +#define ESP_ERR_DPP_NO_MEM (ESP_ERR_WIFI_BASE + 152) /*!< Failure to allocate memory in DPP Operation */ +#define ESP_ERR_DPP_TIMEOUT (ESP_ERR_WIFI_BASE + 153) /*!< DPP Operation timed out */ +#define ESP_ERR_DPP_TX_FAILURE (ESP_ERR_WIFI_BASE + 154) /*!< DPP Frame Tx failed OR not Acked */ +#define ESP_ERR_DPP_INVALID_ATTR (ESP_ERR_WIFI_BASE + 155) /*!< Encountered invalid DPP Attribute */ +#define ESP_ERR_DPP_NOT_SUPPORTED (ESP_ERR_WIFI_BASE + 156) /*!< Encountered invalid DPP Attribute */ + +enum dpp_bootstrap_type { + DPP_BOOTSTRAP_QR_CODE, + DPP_BOOTSTRAP_PKEX, + DPP_BOOTSTRAP_NFC_URI, +}; + +typedef enum { + WIFI_DPP_URI_READY, + WIFI_DPP_CFG_RECVD, + WIFI_DPP_FAIL, +} wifi_dpp_event_t; + +typedef void (*wifi_dpp_event_cb_t)(wifi_dpp_event_t evt, void *data); + +esp_err_t esp_supp_dpp_init(wifi_dpp_event_cb_t evt_cb); +void esp_supp_dpp_deinit(void); + +esp_err_t esp_dpp_bootstrap_gen(uint8_t channel, enum dpp_bootstrap_type type, + const char *key, const char *info); + +void esp_dpp_start_listen(uint8_t channel); +void esp_dpp_stop_listen(void); + +#ifdef __cplusplus +} +#endif +#endif /* ESP_DPP_H */ diff --git a/components/wpa_supplicant/src/common/dpp.c b/components/wpa_supplicant/src/common/dpp.c index 44003add05..462a228d9a 100644 --- a/components/wpa_supplicant/src/common/dpp.c +++ b/components/wpa_supplicant/src/common/dpp.c @@ -2397,7 +2397,7 @@ struct dpp_authentication * dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, struct dpp_bootstrap_info *peer_bi, struct dpp_bootstrap_info *own_bi, - unsigned int freq, const u8 *hdr, const u8 *attr_start, + unsigned int curr_chan, const u8 *hdr, const u8 *attr_start, size_t attr_len) { struct crypto_key *pi = NULL; @@ -2406,10 +2406,8 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, size_t len[2]; u8 *unwrapped = NULL; size_t unwrapped_len = 0; - const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap, - *channel; - u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len, - i_bootstrap_len, channel_len; + const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap; + u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len, i_bootstrap_len; struct dpp_authentication *auth = NULL; #ifdef CONFIG_WPA_TESTING_OPTIONS @@ -2438,10 +2436,11 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, auth->peer_bi = peer_bi; auth->own_bi = own_bi; auth->curve = own_bi->curve; - auth->curr_freq = freq; + auth->curr_chan = curr_chan; auth->peer_version = 1; /* default to the first version */ +#if 0 channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL, &channel_len); if (channel) { @@ -2452,7 +2451,6 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, goto fail; } -#ifndef ESP_SUPPLICANT neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]); wpa_printf(MSG_DEBUG, "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d", @@ -2469,10 +2467,10 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, freq, neg_freq); auth->curr_freq = neg_freq; } -#endif /* rename it to chan */ - auth->curr_freq = *channel; + auth->curr_chan = *channel; } +#endif i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY, &i_proto_len); @@ -4630,7 +4628,7 @@ static int dpp_parse_cred_legacy(struct dpp_config_obj *conf, (u8 *)pass->string, len); if (len < 8 || len > 63) return -1; - os_strlcpy(conf->passphrase, pass->string, + os_strncpy(conf->passphrase, pass->string, sizeof(conf->passphrase)); } else if (psk_hex && psk_hex->type == JSON_STRING) { if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) { @@ -5386,7 +5384,7 @@ fail: int dpp_conf_resp_rx(struct dpp_authentication *auth, - const struct wpabuf *resp) + const uint8_t *resp, uint32_t resp_len) { const u8 *wrapped_data, *e_nonce, *status, *conf_obj; u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len; @@ -5398,12 +5396,12 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth, auth->conf_resp_status = 255; - if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) { + if (dpp_check_attrs(resp, resp_len) < 0) { dpp_auth_fail(auth, "Invalid attribute in config response"); return -1; } - wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp), + wrapped_data = dpp_get_attr(resp, resp_len, DPP_ATTR_WRAPPED_DATA, &wrapped_data_len); if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { @@ -5419,8 +5417,8 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth, if (!unwrapped) return -1; - addr[0] = wpabuf_head(resp); - len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp); + addr[0] = resp; + len[0] = wrapped_data - 4 - resp; wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]); if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, @@ -5451,7 +5449,7 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth, goto fail; } - status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp), + status = dpp_get_attr(resp, resp_len, DPP_ATTR_STATUS, &status_len); if (!status || status_len < 1) { dpp_auth_fail(auth, @@ -6083,9 +6081,6 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) int ret = -1; struct dpp_bootstrap_info *bi; - if (!dpp) - return -1; - bi = os_zalloc(sizeof(*bi)); if (!bi) goto fail; @@ -6143,8 +6138,9 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) mac ? "M:" : "", mac ? mac : "", mac ? ";" : "", info ? "I:" : "", info ? info : "", info ? ";" : "", pk); - bi->id = dpp_next_id(dpp); - dl_list_add(&dpp->bootstrap, &bi->list); + + bi->id = dpp_next_id(dpp); + dl_list_add(&dpp->bootstrap, &bi->list); ret = bi->id; bi = NULL; fail: diff --git a/components/wpa_supplicant/src/common/dpp.h b/components/wpa_supplicant/src/common/dpp.h index 4d595ceebb..e56bc642a4 100644 --- a/components/wpa_supplicant/src/common/dpp.h +++ b/components/wpa_supplicant/src/common/dpp.h @@ -13,8 +13,11 @@ #ifdef CONFIG_DPP #include "utils/list.h" -#include "common/wpa_common.h" #include "crypto/sha256.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "esp_err.h" +#include "esp_dpp.h" struct crypto_ecdh; struct hostapd_ip_addr; @@ -147,12 +150,6 @@ struct dpp_curve_params { const char *jws_alg; }; -enum dpp_bootstrap_type { - DPP_BOOTSTRAP_QR_CODE, - DPP_BOOTSTRAP_PKEX, - DPP_BOOTSTRAP_NFC_URI, -}; - struct dpp_bootstrap_info { struct dl_list list; unsigned int id; @@ -258,6 +255,7 @@ struct dpp_authentication { * Authentication exchange */ unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ]; unsigned int num_freq, freq_idx; + unsigned int curr_chan; unsigned int curr_freq; unsigned int neg_freq; unsigned int num_freq_iters; @@ -488,8 +486,8 @@ void dpp_auth_deinit(struct dpp_authentication *auth); struct wpabuf * dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, size_t attr_len); -int dpp_conf_resp_rx(struct dpp_authentication *auth, - const struct wpabuf *resp); +int dpp_conf_resp_rx(struct dpp_authentication *auth, const u8 *resp, + u32 resp_len); enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth, const u8 *hdr, const u8 *attr_start, size_t attr_len); diff --git a/components/wpa_supplicant/src/common/ieee802_11_defs.h b/components/wpa_supplicant/src/common/ieee802_11_defs.h index 742ad2be64..e0fef0b684 100644 --- a/components/wpa_supplicant/src/common/ieee802_11_defs.h +++ b/components/wpa_supplicant/src/common/ieee802_11_defs.h @@ -263,6 +263,13 @@ #define WLAN_ACTION_UNPROTECTED_WNM 11 #define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */ +/* Public action codes (IEEE Std 802.11-2016, 9.6.8.1, Table 9-307) */ +#define WLAN_PA_VENDOR_SPECIFIC 9 +#define WLAN_PA_GAS_INITIAL_REQ 10 +#define WLAN_PA_GAS_INITIAL_RESP 11 +#define WLAN_PA_GAS_COMEBACK_REQ 12 +#define WLAN_PA_GAS_COMEBACK_RESP 13 + /* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */ #define WLAN_SA_QUERY_REQUEST 0 #define WLAN_SA_QUERY_RESPONSE 1 @@ -274,6 +281,8 @@ #define WLAN_TIMEOUT_KEY_LIFETIME 2 #define WLAN_TIMEOUT_ASSOC_COMEBACK 3 +#define OUI_WFA 0x506f9a +#define DPP_OUI_TYPE 0x1A #ifdef _MSC_VER #pragma pack(push, 1) @@ -343,110 +352,37 @@ enum lci_req_subelem { LCI_REQ_SUBELEM_MAX_AGE = 4, }; -struct ieee80211_mgmt { - le16 frame_control; - le16 duration; - u8 da[6]; - u8 sa[6]; - u8 bssid[6]; - le16 seq_ctrl; - union { - struct { - le16 auth_alg; - le16 auth_transaction; - le16 status_code; - /* possibly followed by Challenge text */ - u8 variable[0]; - } STRUCT_PACKED auth; - struct { - le16 reason_code; - } STRUCT_PACKED deauth; - struct { - le16 capab_info; - le16 listen_interval; - /* followed by SSID and Supported rates */ - u8 variable[0]; - } STRUCT_PACKED assoc_req; - struct { - le16 capab_info; - le16 status_code; - le16 aid; - /* followed by Supported rates */ - u8 variable[0]; - } STRUCT_PACKED assoc_resp, reassoc_resp; - struct { - le16 capab_info; - le16 listen_interval; - u8 current_ap[6]; - /* followed by SSID and Supported rates */ - u8 variable[0]; - } STRUCT_PACKED reassoc_req; - struct { - le16 reason_code; - } STRUCT_PACKED disassoc; - struct { - u8 timestamp[8]; - le16 beacon_int; - le16 capab_info; - /* followed by some of SSID, Supported rates, - * FH Params, DS Params, CF Params, IBSS Params, TIM */ - u8 variable[0]; - } STRUCT_PACKED beacon; - struct { - /* only variable items: SSID, Supported rates */ - u8 variable[0]; - } STRUCT_PACKED probe_req; - struct { - u8 timestamp[8]; - le16 beacon_int; - le16 capab_info; - /* followed by some of SSID, Supported rates, - * FH Params, DS Params, CF Params, IBSS Params */ - u8 variable[0]; - } STRUCT_PACKED probe_resp; - struct { - u8 category; - union { - struct { - u8 action_code; - u8 dialog_token; - u8 status_code; - u8 variable[0]; - } STRUCT_PACKED wmm_action; - struct{ - u8 action_code; - u8 element_id; - u8 length; - u8 switch_mode; - u8 new_chan; - u8 switch_count; - } STRUCT_PACKED chan_switch; - struct { - u8 action; - u8 sta_addr[ETH_ALEN]; - u8 target_ap_addr[ETH_ALEN]; - u8 variable[0]; /* FT Request */ - } STRUCT_PACKED ft_action_req; - struct { - u8 action; - u8 sta_addr[ETH_ALEN]; - u8 target_ap_addr[ETH_ALEN]; - le16 status_code; - u8 variable[0]; /* FT Request */ - } STRUCT_PACKED ft_action_resp; - struct { - u8 action; - u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; - } STRUCT_PACKED sa_query_req; - struct { - u8 action; /* */ - u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; - } STRUCT_PACKED sa_query_resp; - } u; - } STRUCT_PACKED action; - } u; +#ifdef ESP_SUPPLICANT +struct ieee80211_pa_vendor { + u8 oui[3]; + u8 wfa_stype; + u8 vendor_data[]; } STRUCT_PACKED; +struct ieee80211_gas_resp { + u8 diag_token; + u16 status_code; + u16 comeback_delay; + u8 type; + u8 length; + u8 data[]; +} STRUCT_PACKED; + +struct ieee80211_public_action { + u8 action; + union { + struct ieee80211_pa_vendor pa_vendor_spec; + struct ieee80211_gas_resp pa_gas_resp; + } v; +} STRUCT_PACKED; + +struct ieee80211_action { + u8 category; + union { + struct ieee80211_public_action public_action; + } u; +} STRUCT_PACKED; +#endif /* ESP_SUPPLICANT */ #define IEEE80211_MAX_MMPDU_SIZE 2304 struct ieee80211_ht_capabilities { diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_dpp.c b/components/wpa_supplicant/src/esp_supplicant/esp_dpp.c new file mode 100644 index 0000000000..5c59d9c2f7 --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_dpp.c @@ -0,0 +1,562 @@ +/* + * wpa_supplicant - DPP + * Copyright (c) 2017, Qualcomm Atheros, Inc. + * Copyright (c) 2018-2019, The Linux Foundation + * + * This software may be distributed under the terms of the BSD license. + */ + +#include "esp_dpp_i.h" +#include "esp_dpp.h" +#include "esp_wpa.h" +#include "esp_timer.h" +#include "esp_event.h" +#include "common/ieee802_11_defs.h" + +static void *s_dpp_task_hdl = NULL; +static void *s_dpp_evt_queue = NULL; +static void *s_dpp_api_lock = NULL; + +static bool s_dpp_auth_start; +static int s_dpp_auth_retries; +struct esp_dpp_context_t s_dpp_ctx; + +#define REQUEST_ADD 1 +#define REQUEST_CANCEL 0 + +#define DPP_API_LOCK() xSemaphoreTakeRecursive(s_dpp_api_lock, portMAX_DELAY) +#define DPP_API_UNLOCK() xSemaphoreGiveRecursive(s_dpp_api_lock) + +struct action_rx_param { + u8 sa[ETH_ALEN]; + u32 channel; + u32 frm_len; + u32 vendor_data_len; + struct ieee80211_action *action_frm; +}; + +int esp_dpp_post_evt(uint32_t evt_id, uint32_t data) +{ + DPP_API_LOCK(); + + dpp_event_t *evt = os_zalloc(sizeof(dpp_event_t)); + if (evt == NULL) { + DPP_API_UNLOCK(); + return ESP_ERR_DPP_NO_MEM; + } + evt->id = evt_id; + evt->data = data; + if ( xQueueSend(s_dpp_evt_queue, &evt, 10 / portTICK_PERIOD_MS ) != pdPASS) { + DPP_API_UNLOCK(); + os_free(evt); + return ESP_ERR_DPP_FAILURE; + } + DPP_API_UNLOCK(); + return ESP_OK; +} + +static void esp_dpp_call_cb(wifi_dpp_event_t evt, void *data) +{ + s_dpp_ctx.dpp_event_cb(evt, data); +} + +void esp_send_action_frame(uint8_t *dest_mac, const uint8_t *buf, uint32_t len, + uint8_t channel, uint32_t wait_time_ms) +{ + mgmt_tx_req_t *req = os_zalloc(sizeof(*req) + len);; + + req->ifx = ESP_IF_WIFI_STA; + req->subtype = WLAN_FC_STYPE_ACTION; + memcpy(req->dest_mac, dest_mac, ETH_ALEN); + req->no_ack = false; + req->data_len = len; + memcpy(req->data, buf, req->data_len); + + wpa_printf(MSG_DEBUG, "DPP: Mgmt Tx - MAC:" MACSTR ", Channel-%d, WaitT-%d", + MAC2STR(dest_mac), channel, wait_time_ms); + + if (ESP_OK != esp_wifi_mgmt_tx_req(REQUEST_ADD, channel, wait_time_ms, req)) { + wpa_printf(MSG_ERROR, "DPP: Failed to perfrm offchannel operation"); + esp_dpp_call_cb(WIFI_DPP_FAIL, (void *)ESP_ERR_DPP_TX_FAILURE); + os_free(req); + return; + } + + os_free(req); +} + +static void esp_dpp_rx_auth_req(struct action_rx_param *rx_param, uint8_t *dpp_data) +{ + size_t len = rx_param->vendor_data_len - 2; + const u8 *r_bootstrap, *i_bootstrap; + u16 r_bootstrap_len, i_bootstrap_len; + struct dpp_bootstrap_info *own_bi; + int rc; + + wpa_printf(MSG_INFO, "DPP: Authentication Request from " MACSTR, MAC2STR(rx_param->sa)); + + r_bootstrap = dpp_get_attr(dpp_data, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, + &r_bootstrap_len); + if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) { + wpa_printf(MSG_INFO, "DPP: Missing or invalid Responder Bootstrapping Key Hash attribute"); + rc = ESP_ERR_DPP_INVALID_ATTR; + goto fail; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash", r_bootstrap, r_bootstrap_len); + + i_bootstrap = dpp_get_attr(dpp_data, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH, + &i_bootstrap_len); + if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) { + wpa_printf(MSG_INFO, "DPP: Missing or invalid Initiator Bootstrapping Key Hash attribute"); + rc = ESP_ERR_DPP_INVALID_ATTR; + goto fail; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash", i_bootstrap, i_bootstrap_len); + + own_bi = dpp_bootstrap_get_id(s_dpp_ctx.dpp_global, s_dpp_ctx.id); + /* Try to find own and peer bootstrapping key matches based on the + * received hash values */ + if (os_memcmp(own_bi->pubkey_hash, r_bootstrap, SHA256_MAC_LEN)) { + wpa_printf(MSG_INFO, "DPP: No matching own bootstrapping key found as responder - ignore message"); + rc = ESP_ERR_DPP_INVALID_ATTR; + goto fail; + } + + s_dpp_ctx.dpp_auth = dpp_auth_req_rx(NULL, DPP_CAPAB_ENROLLEE, 0, NULL, + own_bi, rx_param->channel, + (const u8 *)&rx_param->action_frm->u.public_action.v, dpp_data, len); + os_memcpy(s_dpp_ctx.dpp_auth->peer_mac_addr, rx_param->sa, ETH_ALEN); + + esp_send_action_frame(rx_param->sa, wpabuf_head(s_dpp_ctx.dpp_auth->resp_msg), + wpabuf_len(s_dpp_ctx.dpp_auth->resp_msg), + rx_param->channel, OFFCHAN_TX_WAIT_TIME); + return; +fail: + esp_dpp_call_cb(WIFI_DPP_FAIL, (void *)rc); +} + +static void gas_query_req_tx(struct dpp_authentication *auth) +{ + struct wpabuf *buf; + int supp_op_classes[] = {81, 0}; + + buf = dpp_build_conf_req_helper(auth, NULL, 0, NULL, + supp_op_classes); + if (!buf) { + wpa_printf(MSG_DEBUG, "DPP: No configuration request data available"); + esp_dpp_call_cb(WIFI_DPP_FAIL, (void *)ESP_ERR_DPP_FAILURE); + return; + } + + wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (chan %u)", + MAC2STR(auth->peer_mac_addr), auth->curr_chan); + + esp_send_action_frame(auth->peer_mac_addr, wpabuf_head(buf), wpabuf_len(buf), + auth->curr_chan, OFFCHAN_TX_WAIT_TIME); +} + +static int esp_dpp_handle_config_obj(struct dpp_authentication *auth, + struct dpp_config_obj *conf) +{ + wifi_config_t *wifi_cfg = &s_dpp_ctx.wifi_cfg; + + if (conf->ssid_len) { + os_memcpy(wifi_cfg->sta.ssid, conf->ssid, conf->ssid_len); + } + + if (dpp_akm_legacy(conf->akm)) { + if (conf->passphrase[0]) + os_memcpy(wifi_cfg->sta.password, conf->passphrase, + sizeof(wifi_cfg->sta.password)); + if (conf->akm == DPP_AKM_PSK_SAE) { + wifi_cfg->sta.pmf_cfg.capable = true; + wifi_cfg->sta.pmf_cfg.required = true; + } + } + + if (conf->connector) { + /* TODO: Save the Connector and consider using a command + * to fetch the value instead of sending an event with + * it. The Connector could end up being larger than what + * most clients are ready to receive as an event + * message. */ + wpa_printf(MSG_INFO, DPP_EVENT_CONNECTOR "%s", + conf->connector); + } + s_dpp_auth_start = false; + esp_wifi_mgmt_tx_req(REQUEST_CANCEL, 0, 0, NULL); + esp_dpp_call_cb(WIFI_DPP_CFG_RECVD, wifi_cfg); + + return 0; +} + +static void esp_dpp_rx_auth_conf(struct action_rx_param *rx_param, uint8_t *dpp_data) +{ + struct dpp_authentication *auth = s_dpp_ctx.dpp_auth; + struct ieee80211_public_action *public_action = + &rx_param->action_frm->u.public_action; + size_t len = rx_param->vendor_data_len - 2; + int rc; + + wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR, + MAC2STR(rx_param->sa)); + + if (!auth) { + wpa_printf(MSG_DEBUG, "DPP: No DPP Authentication in progress - drop"); + rc = ESP_ERR_DPP_FAILURE; + goto fail; + } + + if (os_memcmp(rx_param->sa, auth->peer_mac_addr, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " + MACSTR ") - drop", MAC2STR(auth->peer_mac_addr)); + rc = ESP_ERR_DPP_FAILURE; + goto fail; + } + + if (dpp_auth_conf_rx(auth, (const u8 *)&public_action->v, + dpp_data, len) < 0) { + wpa_printf(MSG_DEBUG, "DPP: Authentication failed"); + rc = ESP_ERR_DPP_FAILURE; + goto fail; + } + + /* Send GAS Query Req */ + gas_query_req_tx(auth); + + return; + +fail: + esp_dpp_call_cb(WIFI_DPP_FAIL, (void *)rc); +} + +static void esp_dpp_rx_auth(struct action_rx_param *rx_param) +{ + uint8_t crypto_suit, type; + uint8_t *tmp; + + tmp = rx_param->action_frm->u.public_action.v.pa_vendor_spec.vendor_data; + crypto_suit = tmp[0]; + type = tmp[1]; + + if (crypto_suit != 1) { + wpa_printf(MSG_ERROR, "DPP: Unsupported crypto suit"); + esp_dpp_call_cb(WIFI_DPP_FAIL, (void *)ESP_ERR_DPP_NOT_SUPPORTED); + return; + } + + switch (type) { + case DPP_PA_AUTHENTICATION_REQ: + esp_dpp_rx_auth_req(rx_param, &tmp[2]); + break; + case DPP_PA_AUTHENTICATION_CONF: + esp_dpp_rx_auth_conf(rx_param, &tmp[2]); + break; + } +} + +static void gas_query_resp_rx(struct action_rx_param *rx_param) +{ + struct dpp_authentication *auth = s_dpp_ctx.dpp_auth; + uint8_t *pos = rx_param->action_frm->u.public_action.v.pa_gas_resp.data; + uint8_t *resp = &pos[10]; + int i, res; + + if (pos[1] == WLAN_EID_VENDOR_SPECIFIC && pos[2] == 5 && + WPA_GET_BE24(&pos[3]) == OUI_WFA && pos[6] == 0x1a && pos[7] == 1) { + if (dpp_conf_resp_rx(auth, resp, rx_param->vendor_data_len-2) < 0) { + wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); + goto fail; + } + + for (i = 0; i < auth->num_conf_obj; i++) { + res = esp_dpp_handle_config_obj(auth, &auth->conf_obj[i]); + if (res < 0) + goto fail; + } + } + + return; +fail: + esp_dpp_call_cb(WIFI_DPP_FAIL, (void *)ESP_ERR_DPP_FAILURE); +} + +static void esp_dpp_rx_action(struct action_rx_param *rx_param) +{ + if (rx_param->action_frm->category == WLAN_ACTION_PUBLIC) { + struct ieee80211_public_action *public_action = + &rx_param->action_frm->u.public_action; + + wpa_printf(MSG_DEBUG, "DPP: Rx Public Action frame: action - %d", + public_action->action); + + if (public_action->action == WLAN_PA_VENDOR_SPECIFIC && + WPA_GET_BE24(public_action->v.pa_vendor_spec.oui) == OUI_WFA && + public_action->v.pa_vendor_spec.wfa_stype == DPP_OUI_TYPE) { + + rx_param->vendor_data_len = rx_param->frm_len - + (size_t)(public_action->v.pa_vendor_spec.vendor_data - + (u8 *)rx_param->action_frm); + + if (!s_dpp_auth_start) { + s_dpp_auth_start = true; + esp_dpp_stop_listen(); + } + + esp_dpp_rx_auth(rx_param); + } else if (public_action->action == WLAN_PA_GAS_INITIAL_RESP && + public_action->v.pa_gas_resp.type == WLAN_EID_ADV_PROTO && + public_action->v.pa_gas_resp.length == 8 && + public_action->v.pa_gas_resp.status_code == 0) { + + rx_param->vendor_data_len = rx_param->frm_len - + (size_t)(public_action->v.pa_gas_resp.data + + public_action->v.pa_gas_resp.length - + (u8 *)rx_param->action_frm); + + gas_query_resp_rx(rx_param); + } + } + + os_free(rx_param->action_frm); + os_free(rx_param); +} + +void esp_dpp_task(void *pvParameters ) +{ + dpp_event_t *evt; + bool task_del = false; + + for (;;) { + if (xQueueReceive(s_dpp_evt_queue, &evt, portMAX_DELAY) == pdTRUE) { + if (evt->id < SIG_DPP_MAX) { + DPP_API_LOCK(); + } else { + os_free(evt); + continue; + } + + switch (evt->id) { + case SIG_DPP_DEL_TASK: + task_del = true; + break; + + case SIG_DPP_BOOTSTRAP_GEN: + { + char *command = (char *)evt->data; + const char *uri; + + s_dpp_ctx.id = dpp_bootstrap_gen(s_dpp_ctx.dpp_global, command); + uri = dpp_bootstrap_get_uri(s_dpp_ctx.dpp_global, s_dpp_ctx.id); + + esp_dpp_call_cb(WIFI_DPP_URI_READY, (void *)uri); + os_free(command); + } + break; + + case SIG_DPP_RX_ACTION: + { + esp_dpp_rx_action((struct action_rx_param *)evt->data); + } + break; + + default: + break; + } + + os_free(evt); + DPP_API_UNLOCK(); + + if (task_del) + break; + } + } + + vQueueDelete(s_dpp_evt_queue); + s_dpp_evt_queue = NULL; + + if (s_dpp_api_lock) { + vSemaphoreDelete(s_dpp_api_lock); + s_dpp_api_lock = NULL; + } + + /* At this point, we completed */ + vTaskDelete(NULL); +} + +int esp_dpp_rx_mgmt(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel) +{ + struct ieee80211_hdr *rx_hdr = (struct ieee80211_hdr *)hdr; + struct action_rx_param *rx_param; + + if (WLAN_FC_GET_STYPE(rx_hdr->frame_control) == WLAN_FC_STYPE_ACTION) { + rx_param = os_zalloc(sizeof(struct action_rx_param)); + os_memcpy(rx_param->sa, rx_hdr->addr2, ETH_ALEN); + rx_param->channel = channel; + rx_param->action_frm = os_zalloc(len); + rx_param->frm_len = len; + os_memcpy(rx_param->action_frm, payload, len); + + if (ESP_OK != esp_dpp_post_evt(SIG_DPP_RX_ACTION, (u32)rx_param)) { + os_free(rx_param->action_frm); + os_free(rx_param); + } + } + + return ESP_ERR_NOT_SUPPORTED; +} + +static void offchan_event_handler(void* arg, esp_event_base_t event_base, + int event_id, void* event_data) +{ + if (event_id == WIFI_EVENT_MGMT_TX_STATUS) { + wifi_event_mgmt_tx_status_t *evt = + (wifi_event_mgmt_tx_status_t *)event_data; + wpa_printf(MSG_DEBUG, "Mgmt Tx Status - %d, Cookie - 0x%x", + evt->status, (uint32_t)evt->cookie); + + if (evt->status) + esp_dpp_call_cb(WIFI_DPP_FAIL, (void *)ESP_ERR_DPP_TX_FAILURE); + + } else if (event_id == WIFI_EVENT_ROC_DONE) { + wifi_event_roc_done_t *evt = (wifi_event_roc_done_t *)event_data; + + if (!s_dpp_auth_start && evt->cookie == BOOTSTRAP_ROC_COOKIE) { + esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, REQUEST_ADD, + s_dpp_ctx.bootstrap_params.channel, + BOOTSTRAP_ROC_WAIT_TIME, + (void *)BOOTSTRAP_ROC_COOKIE); + } + } +} + +esp_err_t esp_dpp_bootstrap_gen(uint8_t channel, enum dpp_bootstrap_type type, + const char *key, const char *uri_info) +{ + struct dpp_bootstrap_params_t *params = &s_dpp_ctx.bootstrap_params; + char *command = os_zalloc(1200); + int ret; + + if (type != DPP_BOOTSTRAP_QR_CODE) { + wpa_printf(MSG_INFO, "Bootstrap type %d not supported", type); + os_free(command); + ret = ESP_ERR_DPP_NOT_SUPPORTED; + goto fail; + } + params->type = type; + params->channel = channel; + esp_wifi_get_mac(ESP_IF_WIFI_STA, params->mac); + + if (uri_info) { + params->info_len = strlen(uri_info); + if (params->info_len) { + params->info = os_zalloc(params->info_len+1); + if (!params->info) { + ret = ESP_ERR_DPP_NO_MEM; + goto fail; + } + os_memcpy(params->info, uri_info, params->info_len); + } + } + + if (key) { + params->key_len = strlen(key); + if (params->key_len) { + char prefix[] = "30310201010420"; + char postfix[] = "a00a06082a8648ce3d030107"; + + params->key = os_zalloc(params->key_len + + sizeof(prefix) + sizeof(postfix)); + if (!params->key) { + ret = ESP_ERR_DPP_NO_MEM; + goto fail; + } + sprintf(params->key, "%s%s%s", prefix, key, postfix); + } + } + + sprintf(command, "type=qrcode mac=" MACSTR " chan=81/%d %s%s%s%s", + MAC2STR(params->mac), channel, + params->key_len ? "key=" : "", + params->key_len ? params->key : "", + params->info_len ? " info=" : "", + params->info_len ? params->info : ""); + + ret = esp_dpp_post_evt(SIG_DPP_BOOTSTRAP_GEN, (u32)command); + if (ret != ESP_OK) { + os_free(command); + if (params->info) { + os_free(params->info); + params->info = NULL; + } + if (params->key) { + os_free(params->key); + params->key = NULL; + } + goto fail; + } + + return ESP_OK; +fail: + return ret; +} + +void esp_dpp_start_listen(uint8_t channel) +{ + esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, REQUEST_ADD, channel, + BOOTSTRAP_ROC_WAIT_TIME, (void *)BOOTSTRAP_ROC_COOKIE); +} + +void esp_dpp_stop_listen(void) +{ + esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, REQUEST_CANCEL, 0, 0, NULL); +} + +esp_err_t esp_supp_dpp_init(wifi_dpp_event_cb_t cb) +{ + struct dpp_global_config cfg = {0}; + + os_bzero(&s_dpp_ctx, sizeof(s_dpp_ctx)); + s_dpp_ctx.dpp_event_cb = cb; + + cfg.cb_ctx = &s_dpp_ctx; + cfg.msg_ctx = &s_dpp_ctx; + s_dpp_ctx.dpp_global = dpp_global_init(&cfg); + + s_dpp_auth_start = false; + s_dpp_evt_queue = xQueueCreate(3, sizeof(dpp_event_t)); + xTaskCreate(esp_dpp_task, "dppT", DPP_TASK_STACK_SIZE, NULL, 2, s_dpp_task_hdl); + + s_dpp_api_lock = xSemaphoreCreateRecursiveMutex(); + if (!s_dpp_api_lock) { + wpa_printf(MSG_ERROR, "DPP: dpp_init: failed to create DPP API lock"); + return ESP_ERR_DPP_NO_MEM; + } + + esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_MGMT_TX_STATUS, + &offchan_event_handler, NULL); + esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_ROC_DONE, + &offchan_event_handler, NULL); + + wpa_printf(MSG_INFO, "esp_dpp_task prio:%d, stack:%d\n", 2, DPP_TASK_STACK_SIZE); + + return ESP_OK; +} + +void esp_supp_dpp_deinit(void) +{ + struct dpp_bootstrap_params_t *params = &s_dpp_ctx.bootstrap_params; + + if (params->info) { + os_free(params->info); + params->info = NULL; + } + if (params->key) { + os_free(params->key); + params->key = NULL; + } + + s_dpp_auth_retries = 0; + dpp_global_deinit(s_dpp_ctx.dpp_global); + esp_dpp_post_evt(SIG_DPP_DEL_TASK, 0); +} diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_dpp_i.h b/components/wpa_supplicant/src/esp_supplicant/esp_dpp_i.h new file mode 100644 index 0000000000..43dce6a75d --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_dpp_i.h @@ -0,0 +1,69 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ESP_DPP_I_H +#define ESP_DPP_I_H + +#include "esp_err.h" +#include "utils/includes.h" +#include "utils/common.h" + +#include "common/dpp.h" +#include "esp_dpp.h" +#include "esp_wifi_driver.h" + +#define DPP_TASK_STACK_SIZE (6144 + TASK_STACK_SIZE_ADD) + +enum SIG_DPP { + SIG_DPP_RESET = 0, + SIG_DPP_BOOTSTRAP_GEN, + SIG_DPP_RX_ACTION, + SIG_DPP_DEL_TASK, + SIG_DPP_MAX, +}; + +typedef struct { + uint32_t id; + uint32_t data; +} dpp_event_t; + +#define BOOTSTRAP_ROC_WAIT_TIME 5000 +#define OFFCHAN_TX_WAIT_TIME 500 + +#define BOOTSTRAP_ROC_COOKIE 0xABABABAB + +struct dpp_bootstrap_params_t { + enum dpp_bootstrap_type type; + uint8_t channel; + uint8_t mac[6]; + uint32_t key_len; + char *key; + uint32_t info_len; + char *info; +}; + +struct esp_dpp_context_t { + struct dpp_bootstrap_params_t bootstrap_params; + struct dpp_authentication *dpp_auth; + int gas_dialog_token; + wifi_config_t wifi_config; + wifi_dpp_event_cb_t dpp_event_cb; + struct dpp_global *dpp_global; + wifi_config_t wifi_cfg; + int id; +}; + +int esp_dpp_rx_mgmt(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel); + +#endif /* ESP_DPP_I_H */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c index f2fad8643f..8177c9c1e7 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c @@ -36,6 +36,7 @@ #include "esp_wpa3_i.h" #include "esp_wpa2.h" #include "esp_common_i.h" +#include "esp_dpp_i.h" void wpa_install_key(enum wpa_alg alg, u8 *addr, int key_idx, int set_tx, u8 *seq, size_t seq_len, u8 *key, size_t key_len, int key_entry_valid) @@ -253,6 +254,7 @@ int esp_supplicant_init(void) wpa_cb->wpa_parse_wpa_ie = wpa_parse_wpa_ie_wrapper; wpa_cb->wpa_config_bss = NULL;//wpa_config_bss; wpa_cb->wpa_michael_mic_failure = wpa_michael_mic_failure; + wpa_cb->offchan_rx_mgmt = esp_dpp_rx_mgmt; esp_wifi_register_wpa3_cb(wpa_cb); esp_supplicant_common_init(wpa_cb);