Merge branch 'bugfix/wpa3_pmf_memleak_fix_v4.0' into 'release/v4.0'

WPA3 / PMF memory leak fixes (backport v4.0)

See merge request espressif/esp-idf!8677
This commit is contained in:
Jiang Jiang Jian 2020-05-15 15:11:44 +08:00
commit 94917184be
4 changed files with 160 additions and 131 deletions

@ -1 +1 @@
Subproject commit 16c944a39dc494f9da9aec76ab86272a0e2c7970 Subproject commit f6981a38f6c2394fc27ae3985e73af0405893084

View file

@ -21,190 +21,216 @@
static struct sae_data g_sae_data; static struct sae_data g_sae_data;
static struct wpabuf *g_sae_token = NULL; static struct wpabuf *g_sae_token = NULL;
static struct wpabuf *g_sae_commit = NULL;
static struct wpabuf *g_sae_confirm = NULL;
int g_allowed_groups[] = { IANA_SECP256R1, 0 }; int g_allowed_groups[] = { IANA_SECP256R1, 0 };
static struct wpabuf *wpa3_build_sae_commit(u8 *bssid) static esp_err_t wpa3_build_sae_commit(u8 *bssid)
{ {
int default_group = IANA_SECP256R1; int default_group = IANA_SECP256R1;
struct wpabuf *buf; u32 len = 0;
u32 len = 0; u8 own_addr[ETH_ALEN];
u8 own_addr[ETH_ALEN]; const u8 *pw;
const u8 *pw;
if (wpa_sta_is_cur_pmksa_set()) { if (wpa_sta_is_cur_pmksa_set()) {
wpa_printf(MSG_INFO, "wpa3: Skip SAE and use cached PMK instead"); wpa_printf(MSG_INFO, "wpa3: Skip SAE and use cached PMK instead");
return NULL; return ESP_FAIL;
} }
if (g_sae_token) { if (g_sae_commit) {
len = wpabuf_len(g_sae_token); wpabuf_free(g_sae_commit);
goto reuse_data; g_sae_commit = NULL;
} }
memset(&g_sae_data, 0, sizeof(g_sae_data)); if (g_sae_token) {
if (sae_set_group(&g_sae_data, default_group)) { len = wpabuf_len(g_sae_token);
wpa_printf(MSG_ERROR, "wpa3: could not set SAE group %d", default_group); goto reuse_data;
return NULL; }
}
esp_wifi_get_macaddr_internal(WIFI_IF_STA, own_addr); memset(&g_sae_data, 0, sizeof(g_sae_data));
if (!bssid) { if (sae_set_group(&g_sae_data, default_group)) {
wpa_printf(MSG_ERROR, "wpa3: cannot prepare SAE commit with no BSSID!"); wpa_printf(MSG_ERROR, "wpa3: could not set SAE group %d", default_group);
return NULL; return ESP_FAIL;
} }
pw = (const u8 *)esp_wifi_sta_get_prof_password_internal(); esp_wifi_get_macaddr_internal(WIFI_IF_STA, own_addr);
if (sae_prepare_commit(own_addr, bssid, pw, strlen((const char *)pw), NULL, &g_sae_data) < 0) { if (!bssid) {
wpa_printf(MSG_ERROR, "wpa3: failed to prepare SAE commit!"); wpa_printf(MSG_ERROR, "wpa3: cannot prepare SAE commit with no BSSID!");
return NULL; return ESP_FAIL;
} }
pw = (const u8 *)esp_wifi_sta_get_prof_password_internal();
if (sae_prepare_commit(own_addr, bssid, pw, strlen((const char *)pw), NULL, &g_sae_data) < 0) {
wpa_printf(MSG_ERROR, "wpa3: failed to prepare SAE commit!");
return ESP_FAIL;
}
reuse_data: reuse_data:
len += SAE_COMMIT_MAX_LEN; len += SAE_COMMIT_MAX_LEN;
buf = wpabuf_alloc(len); g_sae_commit = wpabuf_alloc(len);
if (!buf) { if (!g_sae_commit) {
wpa_printf(MSG_ERROR, "wpa3: failed to allocate buffer for commit msg"); wpa_printf(MSG_ERROR, "wpa3: failed to allocate buffer for commit msg");
return NULL; return ESP_FAIL;
} }
if (sae_write_commit(&g_sae_data, buf, g_sae_token, NULL) != ESP_OK) { if (sae_write_commit(&g_sae_data, g_sae_commit, g_sae_token, NULL) != ESP_OK) {
wpa_printf(MSG_ERROR, "wpa3: failed to write SAE commit msg"); wpa_printf(MSG_ERROR, "wpa3: failed to write SAE commit msg");
wpabuf_free(buf); wpabuf_free(g_sae_commit);
return NULL; g_sae_commit = NULL;
} return ESP_FAIL;
}
if (g_sae_token) { if (g_sae_token) {
wpabuf_free(g_sae_token); wpabuf_free(g_sae_token);
g_sae_token = NULL; g_sae_token = NULL;
} }
g_sae_data.state = SAE_COMMITTED; g_sae_data.state = SAE_COMMITTED;
return buf; return ESP_OK;
} }
static struct wpabuf *wpa3_build_sae_confirm(void) static esp_err_t wpa3_build_sae_confirm(void)
{ {
struct wpabuf *buf; if (g_sae_data.state != SAE_COMMITTED)
return ESP_FAIL;
if (g_sae_data.state != SAE_COMMITTED) if (g_sae_confirm) {
return NULL; wpabuf_free(g_sae_confirm);
g_sae_confirm = NULL;
}
buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN); g_sae_confirm = wpabuf_alloc(SAE_COMMIT_MAX_LEN);
if (!buf) { if (!g_sae_confirm) {
wpa_printf(MSG_ERROR, "wpa3: failed to allocate buffer for confirm msg"); wpa_printf(MSG_ERROR, "wpa3: failed to allocate buffer for confirm msg");
return NULL; return ESP_FAIL;
} }
if (sae_write_confirm(&g_sae_data, buf) != ESP_OK) { if (sae_write_confirm(&g_sae_data, g_sae_confirm) != ESP_OK) {
wpa_printf(MSG_ERROR, "wpa3: failed to write SAE confirm msg"); wpa_printf(MSG_ERROR, "wpa3: failed to write SAE confirm msg");
wpabuf_free(buf); wpabuf_free(g_sae_confirm);
return NULL; g_sae_confirm = NULL;
} return ESP_FAIL;
g_sae_data.state = SAE_CONFIRMED; }
g_sae_data.state = SAE_CONFIRMED;
return buf; return ESP_OK;
}
void esp_wpa3_free_sae_data(void)
{
if (g_sae_commit) {
wpabuf_free(g_sae_commit);
g_sae_commit = NULL;
}
if (g_sae_confirm) {
wpabuf_free(g_sae_confirm);
g_sae_confirm = NULL;
}
sae_clear_data(&g_sae_data);
} }
static u8 *wpa3_build_sae_msg(u8 *bssid, u32 sae_msg_type, u32 *sae_msg_len) static u8 *wpa3_build_sae_msg(u8 *bssid, u32 sae_msg_type, u32 *sae_msg_len)
{ {
struct wpabuf *buf = NULL; u8 *buf = NULL;
switch (sae_msg_type) { switch (sae_msg_type) {
case SAE_MSG_COMMIT: case SAE_MSG_COMMIT:
buf = wpa3_build_sae_commit(bssid); if (ESP_OK != wpa3_build_sae_commit(bssid))
break; return NULL;
case SAE_MSG_CONFIRM: *sae_msg_len = (u32)wpabuf_len(g_sae_commit);
buf = wpa3_build_sae_confirm(); buf = wpabuf_mhead_u8(g_sae_commit);
break; break;
default: case SAE_MSG_CONFIRM:
break; if (ESP_OK != wpa3_build_sae_confirm())
} return NULL;
*sae_msg_len = (u32)wpabuf_len(g_sae_confirm);
if (buf) { buf = wpabuf_mhead_u8(g_sae_confirm);
*sae_msg_len = (u32)wpabuf_len(buf); break;
return wpabuf_mhead_u8(buf); default:
} else { break;
return NULL;
} }
return buf;
} }
static int wpa3_parse_sae_commit(u8 *buf, u32 len, u16 status) static int wpa3_parse_sae_commit(u8 *buf, u32 len, u16 status)
{ {
int ret; int ret;
if (g_sae_data.state != SAE_COMMITTED) { if (g_sae_data.state != SAE_COMMITTED) {
wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE commit in state(%d)!", wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE commit in state(%d)!",
g_sae_data.state); g_sae_data.state);
return ESP_FAIL; return ESP_FAIL;
} }
if (status == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ) { if (status == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ) {
if (g_sae_token) if (g_sae_token)
wpabuf_free(g_sae_token); wpabuf_free(g_sae_token);
g_sae_token = wpabuf_alloc_copy(buf + 2, len - 2); g_sae_token = wpabuf_alloc_copy(buf + 2, len - 2);
return ESP_OK; return ESP_OK;
} }
ret = sae_parse_commit(&g_sae_data, buf, len, NULL, 0, g_allowed_groups); ret = sae_parse_commit(&g_sae_data, buf, len, NULL, 0, g_allowed_groups);
if (ret) { if (ret) {
wpa_printf(MSG_ERROR, "wpa3: could not parse commit(%d)", ret); wpa_printf(MSG_ERROR, "wpa3: could not parse commit(%d)", ret);
return ret; return ret;
} }
ret = sae_process_commit(&g_sae_data); ret = sae_process_commit(&g_sae_data);
if (ret) { if (ret) {
wpa_printf(MSG_ERROR, "wpa3: could not process commit(%d)", ret); wpa_printf(MSG_ERROR, "wpa3: could not process commit(%d)", ret);
return ret; return ret;
} }
return ESP_OK; return ESP_OK;
} }
static int wpa3_parse_sae_confirm(u8 *buf, u32 len) static int wpa3_parse_sae_confirm(u8 *buf, u32 len)
{ {
if (g_sae_data.state != SAE_CONFIRMED) { if (g_sae_data.state != SAE_CONFIRMED) {
wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE commit in state(%d)!", wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE commit in state(%d)!",
g_sae_data.state); g_sae_data.state);
return ESP_FAIL; return ESP_FAIL;
} }
if (sae_check_confirm(&g_sae_data, buf, len) != ESP_OK) { if (sae_check_confirm(&g_sae_data, buf, len) != ESP_OK) {
wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE confirm"); wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE confirm");
return ESP_FAIL; return ESP_FAIL;
} }
g_sae_data.state = SAE_ACCEPTED; g_sae_data.state = SAE_ACCEPTED;
wpa_set_pmk(g_sae_data.pmk, g_sae_data.pmkid, true); wpa_set_pmk(g_sae_data.pmk, g_sae_data.pmkid, true);
memcpy(esp_wifi_sta_get_ap_info_prof_pmk_internal(), g_sae_data.pmk, PMK_LEN); memcpy(esp_wifi_sta_get_ap_info_prof_pmk_internal(), g_sae_data.pmk, PMK_LEN);
return ESP_OK; return ESP_OK;
} }
static int wpa3_parse_sae_msg(u8 *buf, u32 len, u32 sae_msg_type, u16 status) static int wpa3_parse_sae_msg(u8 *buf, u32 len, u32 sae_msg_type, u16 status)
{ {
int ret = ESP_OK; int ret = ESP_OK;
switch (sae_msg_type) { switch (sae_msg_type) {
case SAE_MSG_COMMIT: case SAE_MSG_COMMIT:
ret = wpa3_parse_sae_commit(buf, len, status); ret = wpa3_parse_sae_commit(buf, len, status);
break; break;
case SAE_MSG_CONFIRM: case SAE_MSG_CONFIRM:
ret = wpa3_parse_sae_confirm(buf, len); ret = wpa3_parse_sae_confirm(buf, len);
break; esp_wpa3_free_sae_data();
default: break;
wpa_printf(MSG_ERROR, "wpa3: Invalid SAE msg type(%d)!", default:
sae_msg_type); wpa_printf(MSG_ERROR, "wpa3: Invalid SAE msg type(%d)!", sae_msg_type);
ret = ESP_FAIL; ret = ESP_FAIL;
break; break;
} }
return ret; return ret;
} }
void esp_wifi_register_wpa3_cb(struct wpa_funcs *wpa_cb) void esp_wifi_register_wpa3_cb(struct wpa_funcs *wpa_cb)
{ {
wpa_cb->wpa3_build_sae_msg = wpa3_build_sae_msg; wpa_cb->wpa3_build_sae_msg = wpa3_build_sae_msg;
wpa_cb->wpa3_parse_sae_msg = wpa3_parse_sae_msg; wpa_cb->wpa3_parse_sae_msg = wpa3_parse_sae_msg;
} }
#endif /* CONFIG_WPA3_SAE */ #endif /* CONFIG_WPA3_SAE */

View file

@ -21,6 +21,7 @@
#ifdef CONFIG_WPA3_SAE #ifdef CONFIG_WPA3_SAE
void esp_wifi_register_wpa3_cb(struct wpa_funcs *wpa_cb); void esp_wifi_register_wpa3_cb(struct wpa_funcs *wpa_cb);
void esp_wpa3_free_sae_data(void);
#else /* CONFIG_WPA3_SAE */ #else /* CONFIG_WPA3_SAE */

View file

@ -26,6 +26,7 @@
#include "esp_wpas_glue.h" #include "esp_wpas_glue.h"
#include "esp_hostap.h" #include "esp_hostap.h"
#include "esp_system.h"
#include "crypto/crypto.h" #include "crypto/crypto.h"
#include "crypto/sha1.h" #include "crypto/sha1.h"
#include "crypto/aes_wrap.h" #include "crypto/aes_wrap.h"
@ -188,6 +189,7 @@ static void wpa_sta_disconnected_cb(uint8_t reason_code)
case WIFI_REASON_AUTH_FAIL: case WIFI_REASON_AUTH_FAIL:
case WIFI_REASON_ASSOC_FAIL: case WIFI_REASON_ASSOC_FAIL:
case WIFI_REASON_CONNECTION_FAIL: case WIFI_REASON_CONNECTION_FAIL:
esp_wpa3_free_sae_data();
wpa_sta_clear_curr_pmksa(); wpa_sta_clear_curr_pmksa();
break; break;
default: default: