mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-07-15 08:32:42 +08:00
feat(wpa_supplicant): move wpa source file to SDK
This commit is contained in:
152
components/wpa_supplicant/port/esp_supplicant/wpa_main.c
Normal file
152
components/wpa_supplicant/port/esp_supplicant/wpa_main.c
Normal file
@ -0,0 +1,152 @@
|
||||
// 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.
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
#include "rsn_supp/wpa.h"
|
||||
#include "rsn_supp/wpa_i.h"
|
||||
#include "common/eapol_common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "rsn_supp/wpa_ie.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/aes_wrap.h"
|
||||
#include "esp_supplicant/esp_wpas_glue.h"
|
||||
|
||||
#include "esp_wifi_driver.h"
|
||||
#define LOCAL static
|
||||
|
||||
extern struct ieee80211_cipher tkip;
|
||||
extern struct ieee80211_cipher ccmp;
|
||||
extern struct ieee80211_cipher wep;
|
||||
|
||||
extern bool dhcpc_flag;
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
esp_wifi_set_sta_key_internal(alg, addr, key_idx, set_tx, seq, seq_len, key, key_len, key_entry_valid);
|
||||
}
|
||||
|
||||
int wpa_get_key(uint8_t *ifx, int *alg, u8 *addr, int *key_idx,
|
||||
u8 *key, size_t key_len, int key_entry_valid)
|
||||
{
|
||||
return esp_wifi_get_sta_key_internal(ifx, alg, addr, key_idx, key, key_len, key_entry_valid);
|
||||
}
|
||||
|
||||
/**
|
||||
* eapol_sm_notify_eap_success - Notification of external EAP success trigger
|
||||
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
|
||||
* @success: %TRUE = set success, %FALSE = clear success
|
||||
*
|
||||
* Notify the EAPOL state machine that external event has forced EAP state to
|
||||
* success (success = %TRUE). This can be cleared by setting success = %FALSE.
|
||||
*
|
||||
* This function is called to update EAP state when WPA-PSK key handshake has
|
||||
* been completed successfully since WPA-PSK does not use EAP state machine.
|
||||
*/
|
||||
|
||||
#include "esp_aio.h"
|
||||
#define EP_OFFSET 36
|
||||
int ieee80211_output_pbuf(esp_aio_t *aio);
|
||||
/* fix buf for tx for now */
|
||||
#define WPA_TX_MSG_BUFF_MAXLEN 200
|
||||
|
||||
LOCAL int ICACHE_FLASH_ATTR wpa_send_cb(esp_aio_t* aio)
|
||||
{
|
||||
char* pb = (char*)aio->arg;
|
||||
|
||||
os_free(pb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wpa_sendto_wrapper(void* dataptr, u16 datalen)
|
||||
{
|
||||
#ifndef IOT_SIP_MODE
|
||||
esp_aio_t aio;
|
||||
|
||||
aio.arg = dataptr - EP_OFFSET;
|
||||
aio.cb = wpa_send_cb;
|
||||
aio.fd = 0;
|
||||
aio.pbuf = (char *)dataptr;
|
||||
aio.len = datalen;
|
||||
aio.ret = 0;
|
||||
|
||||
if (ieee80211_output_pbuf(&aio) != 0) {
|
||||
os_free(dataptr - EP_OFFSET);
|
||||
}
|
||||
|
||||
#else
|
||||
esf_buf* eb = NULL;
|
||||
uint8_t* frm;
|
||||
|
||||
eb = ieee80211_getmgtframe(&frm, sizeof(struct ieee80211_frame), WPA_TX_MSG_BUFF_MAXLEN);
|
||||
os_memcpy(frm, msg, msg_len);
|
||||
// eb->hdr_len = sizeof(struct ieee80211_frame);
|
||||
eb->data_len = msg_len;
|
||||
EBUF_START(eb) = frm;
|
||||
ieee80211_output_pbuf(ic->ic_if0_conn, eb);
|
||||
#endif
|
||||
}
|
||||
|
||||
void wpa_deauthenticate(u8 reason_code)
|
||||
{
|
||||
esp_wifi_deauthenticate_internal(reason_code);
|
||||
}
|
||||
|
||||
void wpa_config_profile(void)
|
||||
{
|
||||
if (esp_wifi_sta_prof_is_wpa_internal()) {
|
||||
wpa_set_profile(WPA_PROTO_WPA, esp_wifi_sta_get_prof_authmode_internal());
|
||||
} else if (esp_wifi_sta_prof_is_wpa2_internal() || esp_wifi_sta_prof_is_wpa3_internal()) {
|
||||
wpa_set_profile(WPA_PROTO_RSN, esp_wifi_sta_get_prof_authmode_internal());
|
||||
} else {
|
||||
WPA_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
void wpa_config_bss(uint8_t *bssid)
|
||||
{
|
||||
u8 mac[6];
|
||||
struct wifi_ssid *ssid = esp_wifi_sta_get_prof_ssid_internal();
|
||||
esp_wifi_get_mac(WIFI_IF_STA, mac);
|
||||
|
||||
wpa_set_bss((char *)mac, (char *)bssid, esp_wifi_sta_get_pairwise_cipher_internal(), esp_wifi_sta_get_group_cipher_internal(),
|
||||
(char *)esp_wifi_sta_get_prof_password_internal(), ssid->ssid, ssid->len);
|
||||
}
|
||||
|
||||
void wpa_config_assoc_ie(u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len)
|
||||
{
|
||||
esp_wifi_set_appie_internal(proto, assoc_buf, assoc_wpa_ie_len, 0);
|
||||
}
|
||||
|
||||
void wpa_neg_complete(void)
|
||||
{
|
||||
esp_wifi_auth_done_internal();
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR wpa_sta_init()
|
||||
{
|
||||
wpa_register(NULL, wpa_sendto_wrapper,
|
||||
wpa_config_assoc_ie, wpa_install_key, wpa_get_key, wpa_deauthenticate, wpa_neg_complete);
|
||||
}
|
||||
|
||||
void wpa_sta_connect(uint8_t *bssid)
|
||||
{
|
||||
wpa_config_profile();
|
||||
wpa_config_bss(bssid);
|
||||
}
|
||||
|
120
components/wpa_supplicant/port/esp_supplicant/wpas_glue.c
Normal file
120
components/wpa_supplicant/port/esp_supplicant/wpas_glue.c
Normal file
@ -0,0 +1,120 @@
|
||||
// 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.
|
||||
|
||||
#ifdef EMBEDDED_SUPP
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
#include "common/eapol_common.h"
|
||||
#include "rsn_supp/wpa.h"
|
||||
#define EP_OFFSET 36
|
||||
|
||||
#define wpa_malloc_dram(s) heap_caps_malloc(s, MALLOC_CAP_8BIT)
|
||||
#define wpa_calloc_dram(n, s) heap_caps_calloc(n, s, MALLOC_CAP_8BIT)
|
||||
|
||||
static u8* wpa_alloc_eapol(struct wpa_sm *sm, u8 type,
|
||||
const void *data, u16 data_len,
|
||||
size_t *msg_len, void **data_pos)
|
||||
{
|
||||
struct ieee802_1x_hdr* hdr;
|
||||
|
||||
*msg_len = sizeof(*hdr) + data_len;
|
||||
hdr = (struct ieee802_1x_hdr*)((int)sm->wpadata + sizeof(struct l2_ethhdr)); //keep head byte remain for filling later
|
||||
|
||||
if (hdr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hdr->version = sm->eapol_version;
|
||||
hdr->type = type;
|
||||
hdr->length = host_to_be16(data_len);
|
||||
|
||||
if (data) {
|
||||
memcpy(hdr + 1, data, data_len);
|
||||
} else {
|
||||
memset(hdr + 1, 0, data_len);
|
||||
}
|
||||
|
||||
if (data_pos) {
|
||||
*data_pos = hdr + 1;
|
||||
}
|
||||
|
||||
return (u8 *) hdr;
|
||||
}
|
||||
|
||||
|
||||
u8* ICACHE_FLASH_ATTR wpa_sm_alloc_eapol(struct wpa_sm* sm, u8 type,
|
||||
const void* data, u16 data_len,
|
||||
size_t* msg_len, void** data_pos)
|
||||
{
|
||||
sm->wpadata = wpa_malloc_dram(256 + EP_OFFSET);
|
||||
sm->wpadata += EP_OFFSET;
|
||||
return wpa_alloc_eapol(sm, type, data, data_len, msg_len, data_pos);
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void wpa_sm_deauthenticate(struct wpa_sm *sm, u8 reason_code)
|
||||
{
|
||||
|
||||
/*only need send deauth frame when associated*/
|
||||
if (WPA_SM_STATE(sm) >= WPA_ASSOCIATED) {
|
||||
sm->wpa_deauthenticate(reason_code);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mlme_setprotection - MLME-SETPROTECTION.request primitive
|
||||
* @priv: Private driver interface data
|
||||
* @addr: Address of the station for which to set protection (may be
|
||||
* %NULL for group keys)
|
||||
* @protect_type: MLME_SETPROTECTION_PROTECT_TYPE_*
|
||||
* @key_type: MLME_SETPROTECTION_KEY_TYPE_*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This is an optional function that can be used to set the driver to
|
||||
* require protection for Tx and/or Rx frames. This uses the layer
|
||||
* interface defined in IEEE 802.11i-2004 clause 10.3.22.1
|
||||
* (MLME-SETPROTECTION.request). Many drivers do not use explicit
|
||||
* set protection operation; instead, they set protection implicitly
|
||||
* based on configured keys.
|
||||
*/
|
||||
int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr,
|
||||
int protect_type, int key_type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*use above two functions to get wpa_ie and rsn_ie, then don't need wpa_sm_get_beacon_ie function
|
||||
*/
|
||||
int wpa_sm_get_beacon_ie(struct wpa_sm *sm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* wpa_supplicant_disassociate - Disassociate the current connection
|
||||
* @wpa_s: Pointer to wpa_supplicant data
|
||||
* @reason_code: IEEE 802.11 reason code for the disassociate frame
|
||||
*
|
||||
* This function is used to request %wpa_supplicant to disassociate with the
|
||||
* current AP.
|
||||
*/
|
||||
void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code)
|
||||
{
|
||||
/*check if need clear internal state and data value*/
|
||||
}
|
||||
#endif
|
106
components/wpa_supplicant/src/ap/ap_config.c
Normal file
106
components/wpa_supplicant/src/ap/ap_config.c
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* hostapd / Configuration helper functions
|
||||
* Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "crypto/sha1.h"
|
||||
//#include "radius/radius_client.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/eapol_common.h"
|
||||
//#include "eap_common/eap_wsc_common.h"
|
||||
//#include "eap_server/eap.h"
|
||||
#include "ap/wpa_auth.h"
|
||||
//#include "sta_info.h"
|
||||
#include "ap/ap_config.h"
|
||||
#include "utils/wpa_debug.h"
|
||||
#include "esp_supplicant/esp_wifi_driver.h"
|
||||
|
||||
#ifdef MEMLEAK_DEBUG
|
||||
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
|
||||
#endif
|
||||
|
||||
|
||||
static int ICACHE_FLASH_ATTR hostapd_derive_psk(struct hostapd_ssid* ssid)
|
||||
{
|
||||
ssid->wpa_psk = (struct hostapd_wpa_psk*)os_zalloc(sizeof(struct hostapd_wpa_psk));
|
||||
|
||||
if (ssid->wpa_psk == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Unable to alloc space for PSK");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "SSID",
|
||||
(u8*) ssid->ssid, ssid->ssid_len);
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)",
|
||||
(u8*) ssid->wpa_passphrase,
|
||||
os_strlen(ssid->wpa_passphrase));
|
||||
/* It's too SLOW */
|
||||
// pbkdf2_sha1(ssid->wpa_passphrase,
|
||||
// ssid->ssid, ssid->ssid_len,
|
||||
// 4096, ssid->wpa_psk->psk, PMK_LEN);
|
||||
os_memcpy(ssid->wpa_psk->psk, esp_wifi_ap_get_prof_pmk_internal(), PMK_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)",
|
||||
ssid->wpa_psk->psk, PMK_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ICACHE_FLASH_ATTR hostapd_setup_wpa_psk(struct hostapd_bss_config* conf)
|
||||
{
|
||||
struct hostapd_ssid* ssid = &conf->ssid;
|
||||
|
||||
if (ssid->wpa_passphrase != NULL) {
|
||||
if (ssid->wpa_psk != NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK "
|
||||
"instead of passphrase");
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "Deriving WPA PSK based on "
|
||||
"passphrase");
|
||||
|
||||
if (hostapd_derive_psk(ssid) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ssid->wpa_psk->group = 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
if (ssid->wpa_psk_file) {
|
||||
if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
|
||||
&conf->ssid)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u8* ICACHE_FLASH_ATTR hostapd_get_psk(const struct hostapd_bss_config* conf,
|
||||
const u8* addr, const u8* prev_psk)
|
||||
{
|
||||
struct hostapd_wpa_psk* psk;
|
||||
int next_ok = prev_psk == NULL;
|
||||
|
||||
for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) {
|
||||
if (next_ok &&
|
||||
(psk->group || os_memcmp(psk->addr, addr, ETH_ALEN) == 0)) {
|
||||
return psk->psk;
|
||||
}
|
||||
|
||||
if (psk->psk == prev_psk) {
|
||||
next_ok = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
3498
components/wpa_supplicant/src/ap/wpa_auth.c
Normal file
3498
components/wpa_supplicant/src/ap/wpa_auth.c
Normal file
File diff suppressed because it is too large
Load Diff
705
components/wpa_supplicant/src/ap/wpa_auth_ie.c
Normal file
705
components/wpa_supplicant/src/ap/wpa_auth_ie.c
Normal file
@ -0,0 +1,705 @@
|
||||
/*
|
||||
* hostapd - WPA/RSN IE and KDE definitions
|
||||
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "ap/wpa_auth.h"
|
||||
#include "ap/wpa_auth_ie.h"
|
||||
#include "ap/wpa_auth_i.h"
|
||||
#include "common/wpa_common.h"
|
||||
#include "utils/wpa_debug.h"
|
||||
|
||||
#ifdef CONFIG_RSN_TESTING
|
||||
int rsn_testing = 0;
|
||||
#endif /* CONFIG_RSN_TESTING */
|
||||
|
||||
|
||||
static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
|
||||
{
|
||||
struct wpa_ie_hdr *hdr;
|
||||
int num_suites;
|
||||
u8 *pos, *count;
|
||||
u32 suite;
|
||||
|
||||
hdr = (struct wpa_ie_hdr *) buf;
|
||||
hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
|
||||
RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
|
||||
WPA_PUT_LE16(hdr->version, WPA_VERSION);
|
||||
pos = (u8 *) (hdr + 1);
|
||||
|
||||
suite = wpa_cipher_to_suite(WPA_PROTO_WPA, conf->wpa_group);
|
||||
if (suite == 0) {
|
||||
wpa_printf( MSG_DEBUG, "Invalid group cipher (%d).",
|
||||
conf->wpa_group);
|
||||
return -1;
|
||||
}
|
||||
RSN_SELECTOR_PUT(pos, suite);
|
||||
pos += WPA_SELECTOR_LEN;
|
||||
|
||||
count = pos;
|
||||
pos += 2;
|
||||
|
||||
num_suites = wpa_cipher_put_suites(pos, conf->wpa_pairwise);
|
||||
if (num_suites == 0) {
|
||||
wpa_printf( MSG_DEBUG, "Invalid pairwise cipher (%d).",
|
||||
conf->wpa_pairwise);
|
||||
return -1;
|
||||
}
|
||||
pos += num_suites * WPA_SELECTOR_LEN;
|
||||
WPA_PUT_LE16(count, num_suites);
|
||||
|
||||
num_suites = 0;
|
||||
count = pos;
|
||||
pos += 2;
|
||||
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
|
||||
RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
|
||||
pos += WPA_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
|
||||
RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
|
||||
pos += WPA_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
|
||||
if (num_suites == 0) {
|
||||
wpa_printf( MSG_DEBUG, "Invalid key management type (%d).",
|
||||
conf->wpa_key_mgmt);
|
||||
return -1;
|
||||
}
|
||||
WPA_PUT_LE16(count, num_suites);
|
||||
|
||||
/* WPA Capabilities; use defaults, so no need to include it */
|
||||
|
||||
hdr->len = (pos - buf) - 2;
|
||||
|
||||
return pos - buf;
|
||||
}
|
||||
|
||||
|
||||
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
|
||||
const u8 *pmkid)
|
||||
{
|
||||
struct rsn_ie_hdr *hdr;
|
||||
int num_suites, res;
|
||||
u8 *pos, *count;
|
||||
u16 capab;
|
||||
u32 suite;
|
||||
|
||||
hdr = (struct rsn_ie_hdr *) buf;
|
||||
hdr->elem_id = WLAN_EID_RSN;
|
||||
WPA_PUT_LE16(hdr->version, RSN_VERSION);
|
||||
pos = (u8 *) (hdr + 1);
|
||||
|
||||
suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
|
||||
if (suite == 0) {
|
||||
wpa_printf( MSG_DEBUG, "Invalid group cipher (%d).",
|
||||
conf->wpa_group);
|
||||
return -1;
|
||||
}
|
||||
RSN_SELECTOR_PUT(pos, suite);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
|
||||
num_suites = 0;
|
||||
count = pos;
|
||||
pos += 2;
|
||||
|
||||
#ifdef CONFIG_RSN_TESTING
|
||||
if (rsn_testing) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_RSN_TESTING */
|
||||
|
||||
res = rsn_cipher_put_suites(pos, conf->rsn_pairwise);
|
||||
num_suites += res;
|
||||
pos += res * RSN_SELECTOR_LEN;
|
||||
|
||||
#ifdef CONFIG_RSN_TESTING
|
||||
if (rsn_testing) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_RSN_TESTING */
|
||||
|
||||
if (num_suites == 0) {
|
||||
wpa_printf( MSG_DEBUG, "Invalid pairwise cipher (%d).",
|
||||
conf->rsn_pairwise);
|
||||
return -1;
|
||||
}
|
||||
WPA_PUT_LE16(count, num_suites);
|
||||
|
||||
num_suites = 0;
|
||||
count = pos;
|
||||
pos += 2;
|
||||
|
||||
#ifdef CONFIG_RSN_TESTING
|
||||
if (rsn_testing) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_RSN_TESTING */
|
||||
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_SAE
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
#ifdef CONFIG_RSN_TESTING
|
||||
if (rsn_testing) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_RSN_TESTING */
|
||||
|
||||
if (num_suites == 0) {
|
||||
wpa_printf( MSG_DEBUG, "Invalid key management type (%d).",
|
||||
conf->wpa_key_mgmt);
|
||||
return -1;
|
||||
}
|
||||
WPA_PUT_LE16(count, num_suites);
|
||||
|
||||
/* RSN Capabilities */
|
||||
capab = 0;
|
||||
if (conf->rsn_preauth)
|
||||
capab |= WPA_CAPABILITY_PREAUTH;
|
||||
if (conf->peerkey)
|
||||
capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
|
||||
if (conf->wmm_enabled) {
|
||||
/* 4 PTKSA replay counters when using WMM */
|
||||
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
|
||||
capab |= WPA_CAPABILITY_MFPC;
|
||||
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
|
||||
capab |= WPA_CAPABILITY_MFPR;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_RSN_TESTING
|
||||
if (rsn_testing)
|
||||
capab |= BIT(8) | BIT(14) | BIT(15);
|
||||
#endif /* CONFIG_RSN_TESTING */
|
||||
WPA_PUT_LE16(pos, capab);
|
||||
pos += 2;
|
||||
|
||||
if (pmkid) {
|
||||
if (pos + 2 + PMKID_LEN > buf + len)
|
||||
return -1;
|
||||
/* PMKID Count */
|
||||
WPA_PUT_LE16(pos, 1);
|
||||
pos += 2;
|
||||
memcpy(pos, pmkid, PMKID_LEN);
|
||||
pos += PMKID_LEN;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
|
||||
if (pos + 2 + 4 > buf + len)
|
||||
return -1;
|
||||
if (pmkid == NULL) {
|
||||
/* PMKID Count */
|
||||
WPA_PUT_LE16(pos, 0);
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
/* Management Group Cipher Suite */
|
||||
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
#ifdef CONFIG_RSN_TESTING
|
||||
if (rsn_testing) {
|
||||
/*
|
||||
* Fill in any defined fields and add extra data to the end of
|
||||
* the element.
|
||||
*/
|
||||
int pmkid_count_set = pmkid != NULL;
|
||||
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
|
||||
pmkid_count_set = 1;
|
||||
/* PMKID Count */
|
||||
WPA_PUT_LE16(pos, 0);
|
||||
pos += 2;
|
||||
if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
|
||||
/* Management Group Cipher Suite */
|
||||
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
}
|
||||
|
||||
memset(pos, 0x12, 17);
|
||||
pos += 17;
|
||||
}
|
||||
#endif /* CONFIG_RSN_TESTING */
|
||||
|
||||
hdr->len = (pos - buf) - 2;
|
||||
|
||||
return pos - buf;
|
||||
}
|
||||
|
||||
|
||||
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
|
||||
{
|
||||
u8 *pos, buf[128];
|
||||
int res;
|
||||
|
||||
pos = buf;
|
||||
|
||||
if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
|
||||
res = wpa_write_rsn_ie(&wpa_auth->conf,
|
||||
pos, buf + sizeof(buf) - pos, NULL);
|
||||
if (res < 0)
|
||||
return res;
|
||||
pos += res;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
|
||||
res = wpa_write_mdie(&wpa_auth->conf, pos,
|
||||
buf + sizeof(buf) - pos);
|
||||
if (res < 0)
|
||||
return res;
|
||||
pos += res;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
if (wpa_auth->conf.wpa & WPA_PROTO_WPA) {
|
||||
res = wpa_write_wpa_ie(&wpa_auth->conf,
|
||||
pos, buf + sizeof(buf) - pos);
|
||||
if (res < 0)
|
||||
return res;
|
||||
pos += res;
|
||||
}
|
||||
|
||||
os_free(wpa_auth->wpa_ie);
|
||||
wpa_auth->wpa_ie = os_malloc(pos - buf);
|
||||
if (wpa_auth->wpa_ie == NULL)
|
||||
return -1;
|
||||
memcpy(wpa_auth->wpa_ie, buf, pos - buf);
|
||||
wpa_auth->wpa_ie_len = pos - buf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
|
||||
const u8 *data2, size_t data2_len)
|
||||
{
|
||||
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
*pos++ = RSN_SELECTOR_LEN + data_len + data2_len;
|
||||
RSN_SELECTOR_PUT(pos, kde);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
memcpy(pos, data, data_len);
|
||||
pos += data_len;
|
||||
if (data2) {
|
||||
memcpy(pos, data2, data2_len);
|
||||
pos += data2_len;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm,
|
||||
const u8 *wpa_ie, size_t wpa_ie_len/*,
|
||||
const u8 *mdie, size_t mdie_len*/)
|
||||
{
|
||||
struct wpa_ie_data data;
|
||||
int ciphers, key_mgmt, res, version;
|
||||
u32 selector;
|
||||
|
||||
if (wpa_auth == NULL || sm == NULL)
|
||||
return WPA_NOT_ENABLED;
|
||||
|
||||
if (wpa_ie == NULL || wpa_ie_len < 1)
|
||||
return WPA_INVALID_IE;
|
||||
|
||||
if (wpa_ie[0] == WLAN_EID_RSN)
|
||||
version = WPA_PROTO_RSN;
|
||||
else
|
||||
version = WPA_PROTO_WPA;
|
||||
|
||||
if (!(wpa_auth->conf.wpa & version)) {
|
||||
wpa_printf( MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR,
|
||||
version, MAC2STR(sm->addr));
|
||||
return WPA_INVALID_PROTO;
|
||||
}
|
||||
|
||||
if (version == WPA_PROTO_RSN) {
|
||||
res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
|
||||
|
||||
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
|
||||
if (0) {
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
|
||||
selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
|
||||
selector = RSN_AUTH_KEY_MGMT_FT_PSK;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
|
||||
selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
|
||||
selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_SAE
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
|
||||
selector = RSN_AUTH_KEY_MGMT_SAE;
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE)
|
||||
selector = RSN_AUTH_KEY_MGMT_FT_SAE;
|
||||
#endif /* CONFIG_SAE */
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
|
||||
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
|
||||
selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
|
||||
|
||||
selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
|
||||
data.pairwise_cipher);
|
||||
if (!selector)
|
||||
selector = RSN_CIPHER_SUITE_CCMP;
|
||||
|
||||
selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
|
||||
data.group_cipher);
|
||||
if (!selector)
|
||||
selector = RSN_CIPHER_SUITE_CCMP;
|
||||
} else {
|
||||
res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data);
|
||||
|
||||
selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
|
||||
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
|
||||
selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
|
||||
selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X;
|
||||
|
||||
selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
|
||||
data.pairwise_cipher);
|
||||
if (!selector)
|
||||
selector = RSN_CIPHER_SUITE_TKIP;
|
||||
|
||||
selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
|
||||
data.group_cipher);
|
||||
if (!selector)
|
||||
selector = WPA_CIPHER_SUITE_TKIP;
|
||||
}
|
||||
if (res) {
|
||||
wpa_printf( MSG_DEBUG, "Failed to parse WPA/RSN IE from "
|
||||
MACSTR " (res=%d)", MAC2STR(sm->addr), res);
|
||||
wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len);
|
||||
return WPA_INVALID_IE;
|
||||
}
|
||||
|
||||
if (data.group_cipher != wpa_auth->conf.wpa_group) {
|
||||
wpa_printf( MSG_DEBUG, "Invalid WPA group cipher (0x%x) from "
|
||||
MACSTR, data.group_cipher, MAC2STR(sm->addr));
|
||||
return WPA_INVALID_GROUP;
|
||||
}
|
||||
|
||||
key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
|
||||
if (!key_mgmt) {
|
||||
wpa_printf( MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
|
||||
MACSTR, data.key_mgmt, MAC2STR(sm->addr));
|
||||
return WPA_INVALID_AKMP;
|
||||
}
|
||||
if (0) {
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
|
||||
else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
|
||||
else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_SAE
|
||||
else if (key_mgmt & WPA_KEY_MGMT_SAE)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
|
||||
else if (key_mgmt & WPA_KEY_MGMT_FT_SAE)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE;
|
||||
#endif /* CONFIG_SAE */
|
||||
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
|
||||
else
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
|
||||
|
||||
if (version == WPA_PROTO_RSN)
|
||||
ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise;
|
||||
else
|
||||
ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
|
||||
if (!ciphers) {
|
||||
wpa_printf( MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) "
|
||||
"from " MACSTR,
|
||||
version == WPA_PROTO_RSN ? "RSN" : "WPA",
|
||||
data.pairwise_cipher, MAC2STR(sm->addr));
|
||||
return WPA_INVALID_PAIRWISE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
|
||||
if (!(data.capabilities & WPA_CAPABILITY_MFPC)) {
|
||||
wpa_printf( MSG_DEBUG, "Management frame protection "
|
||||
"required, but client did not enable it");
|
||||
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
|
||||
}
|
||||
|
||||
if (ciphers & WPA_CIPHER_TKIP) {
|
||||
wpa_printf( MSG_DEBUG, "Management frame protection "
|
||||
"cannot use TKIP");
|
||||
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
|
||||
}
|
||||
|
||||
if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
|
||||
wpa_printf( MSG_DEBUG, "Unsupported management group "
|
||||
"cipher %d", data.mgmt_group_cipher);
|
||||
return WPA_INVALID_MGMT_GROUP_CIPHER;
|
||||
}
|
||||
}
|
||||
|
||||
if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
|
||||
!(data.capabilities & WPA_CAPABILITY_MFPC))
|
||||
sm->mgmt_frame_prot = 0;
|
||||
else
|
||||
sm->mgmt_frame_prot = 1;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
|
||||
if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
|
||||
wpa_printf( MSG_DEBUG, "RSN: Trying to use FT, but "
|
||||
"MDIE not included");
|
||||
return WPA_INVALID_MDIE;
|
||||
}
|
||||
if (memcmp(mdie, wpa_auth->conf.mobility_domain,
|
||||
MOBILITY_DOMAIN_ID_LEN) != 0) {
|
||||
wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown "
|
||||
"MDIE", mdie, MOBILITY_DOMAIN_ID_LEN);
|
||||
return WPA_INVALID_MDIE;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
if (ciphers & WPA_CIPHER_CCMP)
|
||||
sm->pairwise = WPA_CIPHER_CCMP;
|
||||
else if (ciphers & WPA_CIPHER_GCMP)
|
||||
sm->pairwise = WPA_CIPHER_GCMP;
|
||||
else
|
||||
sm->pairwise = WPA_CIPHER_TKIP;
|
||||
|
||||
/* TODO: clear WPA/WPA2 state if STA changes from one to another */
|
||||
if (wpa_ie[0] == WLAN_EID_RSN)
|
||||
sm->wpa = WPA_VERSION_WPA2;
|
||||
else
|
||||
sm->wpa = WPA_VERSION_WPA;
|
||||
|
||||
if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
|
||||
os_free(sm->wpa_ie);
|
||||
sm->wpa_ie = os_malloc(wpa_ie_len);
|
||||
if (sm->wpa_ie == NULL)
|
||||
return WPA_ALLOC_FAIL;
|
||||
}
|
||||
memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len);
|
||||
sm->wpa_ie_len = wpa_ie_len;
|
||||
|
||||
return WPA_IE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
|
||||
* @pos: Pointer to the IE header
|
||||
* @end: Pointer to the end of the Key Data buffer
|
||||
* @ie: Pointer to parsed IE data
|
||||
* Returns: 0 on success, 1 if end mark is found, -1 on failure
|
||||
*/
|
||||
static int wpa_parse_generic(const u8 *pos, const u8 *end,
|
||||
struct wpa_eapol_ie_parse *ie)
|
||||
{
|
||||
if (pos[1] == 0)
|
||||
return 1;
|
||||
|
||||
if (pos[1] >= 6 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
|
||||
pos[2 + WPA_SELECTOR_LEN] == 1 &&
|
||||
pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
|
||||
ie->wpa_ie = pos;
|
||||
ie->wpa_ie_len = pos[1] + 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pos + 1 + RSN_SELECTOR_LEN < end &&
|
||||
pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
|
||||
ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
|
||||
ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
|
||||
ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
|
||||
ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
|
||||
ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PEERKEY
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
|
||||
ie->smk = pos + 2 + RSN_SELECTOR_LEN;
|
||||
ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
|
||||
ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
|
||||
ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
|
||||
ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
|
||||
ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
|
||||
ie->error = pos + 2 + RSN_SELECTOR_LEN;
|
||||
ie->error_len = pos[1] - RSN_SELECTOR_LEN;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PEERKEY */
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
|
||||
ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
|
||||
ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
|
||||
* @buf: Pointer to the Key Data buffer
|
||||
* @len: Key Data Length
|
||||
* @ie: Pointer to parsed IE data
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
int ret = 0;
|
||||
|
||||
memset(ie, 0, sizeof(*ie));
|
||||
for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
|
||||
if (pos[0] == 0xdd &&
|
||||
((pos == buf + len - 1) || pos[1] == 0)) {
|
||||
/* Ignore padding */
|
||||
break;
|
||||
}
|
||||
if (pos + 2 + pos[1] > end) {
|
||||
wpa_printf( MSG_DEBUG, "WPA: EAPOL-Key Key Data "
|
||||
"underflow (ie=%d len=%d pos=%d)",
|
||||
pos[0], pos[1], (int) (pos - buf));
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
|
||||
buf, len);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
if (*pos == WLAN_EID_RSN) {
|
||||
ie->rsn_ie = pos;
|
||||
ie->rsn_ie_len = pos[1] + 2;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
|
||||
ie->mdie = pos;
|
||||
ie->mdie_len = pos[1] + 2;
|
||||
} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
|
||||
ie->ftie = pos;
|
||||
ie->ftie_len = pos[1] + 2;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
|
||||
ret = wpa_parse_generic(pos, end, ie);
|
||||
if (ret < 0)
|
||||
break;
|
||||
if (ret > 0) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
|
||||
"Key Data IE", pos, 2 + pos[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
|
||||
{
|
||||
return sm ? sm->mgmt_frame_prot : 0;
|
||||
}
|
675
components/wpa_supplicant/src/common/wpa_common.c
Normal file
675
components/wpa_supplicant/src/common/wpa_common.c
Normal file
@ -0,0 +1,675 @@
|
||||
/*
|
||||
* WPA/RSN - Shared functions for supplicant and authenticator
|
||||
* Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
#ifdef EMBEDDED_SUPP
|
||||
|
||||
#include "rom/ets_sys.h"
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
#include "common/defs.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/wpa_common.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "crypto/md5.h"
|
||||
#include "crypto/aes.h"
|
||||
|
||||
#ifndef CONFIG_NO_WPA2
|
||||
static int rsn_selector_to_bitfield(const u8 *s)
|
||||
{
|
||||
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
|
||||
return WPA_CIPHER_NONE;
|
||||
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40)
|
||||
return WPA_CIPHER_WEP40;
|
||||
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
|
||||
return WPA_CIPHER_TKIP;
|
||||
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
|
||||
return WPA_CIPHER_CCMP;
|
||||
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104)
|
||||
return WPA_CIPHER_WEP104;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
|
||||
return WPA_CIPHER_AES_128_CMAC;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsn_key_mgmt_to_bitfield(const u8 *s)
|
||||
{
|
||||
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
|
||||
return WPA_KEY_MGMT_IEEE8021X;
|
||||
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
|
||||
return WPA_KEY_MGMT_PSK;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
|
||||
return WPA_KEY_MGMT_FT_IEEE8021X;
|
||||
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
|
||||
return WPA_KEY_MGMT_FT_PSK;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#ifdef CONFIG_WPA3_SAE
|
||||
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
|
||||
return WPA_KEY_MGMT_SAE;
|
||||
#endif /* CONFIG_WPA3_SAE */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
|
||||
return WPA_KEY_MGMT_IEEE8021X_SHA256;
|
||||
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
|
||||
return WPA_KEY_MGMT_PSK_SHA256;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wpa_selector_to_bitfield(const u8 *s)
|
||||
{
|
||||
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
|
||||
return WPA_CIPHER_NONE;
|
||||
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
|
||||
return WPA_CIPHER_WEP40;
|
||||
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
|
||||
return WPA_CIPHER_TKIP;
|
||||
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
|
||||
return WPA_CIPHER_CCMP;
|
||||
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
|
||||
return WPA_CIPHER_WEP104;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wpa_key_mgmt_to_bitfield(const u8 *s)
|
||||
{
|
||||
if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
|
||||
return WPA_KEY_MGMT_IEEE8021X;
|
||||
if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
|
||||
return WPA_KEY_MGMT_PSK;
|
||||
if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
|
||||
return WPA_KEY_MGMT_WPA_NONE;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_NO_WPA2 */
|
||||
/**
|
||||
* wpa_parse_wpa_ie_rsn - Parse RSN IE
|
||||
* @rsn_ie: Buffer containing RSN IE
|
||||
* @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
|
||||
* @data: Pointer to structure that will be filled in with parsed data
|
||||
* Returns: 0 on success, <0 on failure
|
||||
*/
|
||||
int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
|
||||
struct wpa_ie_data *data)
|
||||
{
|
||||
#ifndef CONFIG_NO_WPA2
|
||||
const struct rsn_ie_hdr *hdr;
|
||||
const u8 *pos;
|
||||
int left;
|
||||
int i, count;
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->proto = WPA_PROTO_RSN;
|
||||
data->pairwise_cipher = WPA_CIPHER_CCMP;
|
||||
data->group_cipher = WPA_CIPHER_CCMP;
|
||||
data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
|
||||
data->capabilities = 0;
|
||||
data->pmkid = NULL;
|
||||
data->num_pmkid = 0;
|
||||
data->mgmt_group_cipher = 0;
|
||||
|
||||
if (rsn_ie_len == 0) {
|
||||
/* No RSN IE - fail silently */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
|
||||
#ifdef DEBUG_PRINT
|
||||
wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
|
||||
__func__, (unsigned long) rsn_ie_len);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr = (const struct rsn_ie_hdr *) rsn_ie;
|
||||
|
||||
if (hdr->elem_id != WLAN_EID_RSN ||
|
||||
hdr->len != rsn_ie_len - 2 ||
|
||||
WPA_GET_LE16(hdr->version) != RSN_VERSION) {
|
||||
#ifdef DEBUG_PRINT
|
||||
wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
|
||||
__func__);
|
||||
#endif
|
||||
return -2;
|
||||
}
|
||||
|
||||
pos = (const u8 *) (hdr + 1);
|
||||
left = rsn_ie_len - sizeof(*hdr);
|
||||
|
||||
if (left >= RSN_SELECTOR_LEN) {
|
||||
data->group_cipher = rsn_selector_to_bitfield(pos);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
left -= RSN_SELECTOR_LEN;
|
||||
} else if (left > 0) {
|
||||
#ifdef DEBUG_PRINT
|
||||
wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
|
||||
__func__, left);
|
||||
#endif
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (left >= 2) {
|
||||
data->pairwise_cipher = 0;
|
||||
count = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
left -= 2;
|
||||
if (count == 0 || left < count * RSN_SELECTOR_LEN) {
|
||||
#ifdef DEBUG_PRINT
|
||||
wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
|
||||
"count %u left %u", __func__, count, left);
|
||||
#endif
|
||||
return -4;
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
left -= RSN_SELECTOR_LEN;
|
||||
}
|
||||
} else if (left == 1) {
|
||||
#ifdef DEBUG_PRINT
|
||||
wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
|
||||
__func__);
|
||||
#endif
|
||||
return -5;
|
||||
}
|
||||
|
||||
if (left >= 2) {
|
||||
data->key_mgmt = 0;
|
||||
count = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
left -= 2;
|
||||
if (count == 0 || left < count * RSN_SELECTOR_LEN) {
|
||||
#ifdef DEBUG_PRINT
|
||||
wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
|
||||
"count %u left %u", __func__, count, left);
|
||||
#endif
|
||||
return -6;
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
left -= RSN_SELECTOR_LEN;
|
||||
}
|
||||
} else if (left == 1) {
|
||||
#ifdef DEBUG_PRINT
|
||||
wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
|
||||
__func__);
|
||||
#endif
|
||||
return -7;
|
||||
}
|
||||
|
||||
if (left >= 2) {
|
||||
data->capabilities = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
left -= 2;
|
||||
}
|
||||
|
||||
if (left >= 2) {
|
||||
data->num_pmkid = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
left -= 2;
|
||||
if (left < (int) data->num_pmkid * PMKID_LEN) {
|
||||
#ifdef DEBUG_PRINT
|
||||
wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
|
||||
"(num_pmkid=%lu left=%d)",
|
||||
__func__, (unsigned long) data->num_pmkid,
|
||||
left);
|
||||
#endif
|
||||
data->num_pmkid = 0;
|
||||
return -9;
|
||||
} else {
|
||||
data->pmkid = pos;
|
||||
pos += data->num_pmkid * PMKID_LEN;
|
||||
left -= data->num_pmkid * PMKID_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
if (left > 0) {
|
||||
#ifdef DEBUG_PRINT
|
||||
wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
|
||||
__func__, left);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else /* CONFIG_NO_WPA2 */
|
||||
return -1;
|
||||
#endif /* CONFIG_NO_WPA2 */
|
||||
}
|
||||
|
||||
int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
struct wpa_ie_data *data)
|
||||
{
|
||||
const struct wpa_ie_hdr *hdr;
|
||||
const u8 *pos;
|
||||
int left;
|
||||
int i, count;
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->proto = WPA_PROTO_WPA;
|
||||
data->pairwise_cipher = WPA_CIPHER_TKIP;
|
||||
data->group_cipher = WPA_CIPHER_TKIP;
|
||||
data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
|
||||
data->capabilities = 0;
|
||||
data->pmkid = NULL;
|
||||
data->num_pmkid = 0;
|
||||
data->mgmt_group_cipher = 0;
|
||||
|
||||
if (wpa_ie_len == 0) {
|
||||
/* No WPA IE - fail silently */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
|
||||
__func__, (unsigned long) wpa_ie_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr = (const struct wpa_ie_hdr *) wpa_ie;
|
||||
|
||||
if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
|
||||
hdr->len != wpa_ie_len - 2 ||
|
||||
RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
|
||||
WPA_GET_LE16(hdr->version) != WPA_VERSION) {
|
||||
wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
|
||||
__func__);
|
||||
return -2;
|
||||
}
|
||||
|
||||
pos = (const u8 *) (hdr + 1);
|
||||
left = wpa_ie_len - sizeof(*hdr);
|
||||
|
||||
if (left >= WPA_SELECTOR_LEN) {
|
||||
data->group_cipher = wpa_selector_to_bitfield(pos);
|
||||
pos += WPA_SELECTOR_LEN;
|
||||
left -= WPA_SELECTOR_LEN;
|
||||
} else if (left > 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
|
||||
__func__, left);
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (left >= 2) {
|
||||
data->pairwise_cipher = 0;
|
||||
count = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
left -= 2;
|
||||
if (count == 0 || left < count * WPA_SELECTOR_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
|
||||
"count %u left %u", __func__, count, left);
|
||||
return -4;
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
|
||||
pos += WPA_SELECTOR_LEN;
|
||||
left -= WPA_SELECTOR_LEN;
|
||||
}
|
||||
} else if (left == 1) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
|
||||
__func__);
|
||||
return -5;
|
||||
}
|
||||
|
||||
if (left >= 2) {
|
||||
data->key_mgmt = 0;
|
||||
count = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
left -= 2;
|
||||
if (count == 0 || left < count * WPA_SELECTOR_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
|
||||
"count %u left %u", __func__, count, left);
|
||||
return -6;
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
|
||||
pos += WPA_SELECTOR_LEN;
|
||||
left -= WPA_SELECTOR_LEN;
|
||||
}
|
||||
} else if (left == 1) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
|
||||
__func__);
|
||||
return -7;
|
||||
}
|
||||
|
||||
if (left >= 2) {
|
||||
data->capabilities = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
left -= 2;
|
||||
}
|
||||
|
||||
if (left > 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
|
||||
__func__, left);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_eapol_key_mic - Calculate EAPOL-Key MIC
|
||||
* @key: EAPOL-Key Key Confirmation Key (KCK)
|
||||
* @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
|
||||
* @buf: Pointer to the beginning of the EAPOL header (version field)
|
||||
* @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
|
||||
* @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
|
||||
* to be cleared (all zeroes) when calling this function.
|
||||
*
|
||||
* Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
|
||||
* description of the Key MIC calculation. It includes packet data from the
|
||||
* beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
|
||||
* happened during final editing of the standard and the correct behavior is
|
||||
* defined in the last draft (IEEE 802.11i/D10).
|
||||
*/
|
||||
int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
|
||||
u8 *mic)
|
||||
{
|
||||
u8 hash[SHA1_MAC_LEN];
|
||||
|
||||
switch (ver) {
|
||||
case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
|
||||
return hmac_md5(key, 16, buf, len, mic);
|
||||
case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
|
||||
if (hmac_sha1(key, 16, buf, len, hash))
|
||||
return -1;
|
||||
memcpy(mic, hash, MD5_MAC_LEN);
|
||||
break;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
#ifdef CONFIG_WPA3_SAE
|
||||
case WPA_KEY_INFO_TYPE_AKM_DEFINED:
|
||||
#endif
|
||||
case WPA_KEY_INFO_TYPE_AES_128_CMAC:
|
||||
return omac1_aes_128(key, buf, len, mic);
|
||||
#endif
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wpa_compare_rsn_ie(int ft_initial_assoc,
|
||||
const u8 *ie1, size_t ie1len,
|
||||
const u8 *ie2, size_t ie2len)
|
||||
{
|
||||
if (ie1 == NULL || ie2 == NULL)
|
||||
return -1;
|
||||
|
||||
if (ie1len == ie2len && memcmp(ie1, ie2, ie1len) == 0)
|
||||
return 0; /* identical IEs */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (ft_initial_assoc) {
|
||||
struct wpa_ie_data ie1d, ie2d;
|
||||
/*
|
||||
* The PMKID-List in RSN IE is different between Beacon/Probe
|
||||
* Response/(Re)Association Request frames and EAPOL-Key
|
||||
* messages in FT initial mobility domain association. Allow
|
||||
* for this, but verify that other parts of the RSN IEs are
|
||||
* identical.
|
||||
*/
|
||||
if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 ||
|
||||
wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0)
|
||||
return -1;
|
||||
if (ie1d.proto == ie2d.proto &&
|
||||
ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
|
||||
ie1d.group_cipher == ie2d.group_cipher &&
|
||||
ie1d.key_mgmt == ie2d.key_mgmt &&
|
||||
ie1d.capabilities == ie2d.capabilities &&
|
||||
ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
/**
|
||||
* wpa_cipher_txt - Convert cipher suite to a text string
|
||||
* @cipher: Cipher suite (WPA_CIPHER_* enum)
|
||||
* Returns: Pointer to a text string of the cipher suite name
|
||||
*/
|
||||
const char * wpa_cipher_txt(int cipher)
|
||||
{
|
||||
switch (cipher) {
|
||||
case WPA_CIPHER_NONE:
|
||||
return "NONE";
|
||||
case WPA_CIPHER_WEP40:
|
||||
return "WEP-40";
|
||||
case WPA_CIPHER_WEP104:
|
||||
return "WEP-104";
|
||||
case WPA_CIPHER_TKIP:
|
||||
return "TKIP";
|
||||
case WPA_CIPHER_CCMP:
|
||||
return "CCMP";
|
||||
case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
|
||||
return "CCMP+TKIP";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
|
||||
* @pmk: Pairwise master key
|
||||
* @pmk_len: Length of PMK
|
||||
* @label: Label to use in derivation
|
||||
* @addr1: AA or SA
|
||||
* @addr2: SA or AA
|
||||
* @nonce1: ANonce or SNonce
|
||||
* @nonce2: SNonce or ANonce
|
||||
* @ptk: Buffer for pairwise transient key
|
||||
* @ptk_len: Length of PTK
|
||||
* @use_sha256: Whether to use SHA256-based KDF
|
||||
*
|
||||
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
|
||||
* PTK = PRF-X(PMK, "Pairwise key expansion",
|
||||
* Min(AA, SA) || Max(AA, SA) ||
|
||||
* Min(ANonce, SNonce) || Max(ANonce, SNonce))
|
||||
*
|
||||
* STK = PRF-X(SMK, "Peer key expansion",
|
||||
* Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
|
||||
* Min(INonce, PNonce) || Max(INonce, PNonce))
|
||||
*/
|
||||
void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
|
||||
const u8 *addr1, const u8 *addr2,
|
||||
const u8 *nonce1, const u8 *nonce2,
|
||||
u8 *ptk, size_t ptk_len, int use_sha256)
|
||||
{
|
||||
u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
|
||||
|
||||
if (memcmp(addr1, addr2, ETH_ALEN) < 0) {
|
||||
memcpy(data, addr1, ETH_ALEN);
|
||||
memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
|
||||
} else {
|
||||
memcpy(data, addr2, ETH_ALEN);
|
||||
memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
|
||||
}
|
||||
|
||||
if (memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
|
||||
memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
|
||||
memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
|
||||
WPA_NONCE_LEN);
|
||||
} else {
|
||||
memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
|
||||
memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
|
||||
WPA_NONCE_LEN);
|
||||
}
|
||||
|
||||
if (use_sha256) {
|
||||
sha256_prf(pmk, pmk_len, label, data, sizeof(data),
|
||||
ptk, ptk_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk, ptk_len);
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR"\n",
|
||||
MAC2STR(addr1), MAC2STR(addr2));
|
||||
|
||||
wpa_hexdump(MSG_MSGDUMP, "WPA: PMK", pmk, pmk_len);
|
||||
wpa_hexdump(MSG_MSGDUMP, "WPA: PTK", ptk, ptk_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* rsn_pmkid - Calculate PMK identifier
|
||||
* @pmk: Pairwise master key
|
||||
* @pmk_len: Length of pmk in bytes
|
||||
* @aa: Authenticator address
|
||||
* @spa: Supplicant address
|
||||
* @pmkid: Buffer for PMKID
|
||||
* @use_sha256: Whether to use SHA256-based KDF
|
||||
*
|
||||
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
|
||||
* PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
|
||||
*/
|
||||
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
|
||||
u8 *pmkid, int use_sha256)
|
||||
{
|
||||
char* title = "PMK Name";
|
||||
const u8* addr[3];
|
||||
static const size_t len[3] ICACHE_RODATA_ATTR = { 8, ETH_ALEN, ETH_ALEN };
|
||||
unsigned char hash[SHA256_MAC_LEN];
|
||||
|
||||
addr[0] = (u8 *) title;
|
||||
addr[1] = aa;
|
||||
addr[2] = spa;
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (use_sha256) {
|
||||
hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
|
||||
}
|
||||
else
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
|
||||
memcpy(pmkid, hash, PMKID_LEN);
|
||||
}
|
||||
|
||||
int wpa_cipher_key_len(int cipher)
|
||||
{
|
||||
switch (cipher) {
|
||||
case WPA_CIPHER_CCMP:
|
||||
case WPA_CIPHER_GCMP:
|
||||
return 16;
|
||||
case WPA_CIPHER_TKIP:
|
||||
return 32;
|
||||
case WPA_CIPHER_WEP104:
|
||||
return 13;
|
||||
case WPA_CIPHER_WEP40:
|
||||
return 5;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wpa_cipher_to_alg(int cipher)
|
||||
{
|
||||
switch (cipher) {
|
||||
case WPA_CIPHER_CCMP:
|
||||
return WPA_ALG_CCMP;
|
||||
case WPA_CIPHER_GCMP:
|
||||
return WPA_ALG_GCMP;
|
||||
case WPA_CIPHER_TKIP:
|
||||
return WPA_ALG_TKIP;
|
||||
case WPA_CIPHER_WEP104:
|
||||
case WPA_CIPHER_WEP40:
|
||||
return WPA_ALG_WEP;
|
||||
}
|
||||
return WPA_ALG_NONE;
|
||||
}
|
||||
|
||||
u32 wpa_cipher_to_suite(int proto, int cipher)
|
||||
{
|
||||
if (cipher & WPA_CIPHER_CCMP)
|
||||
return (proto == WPA_PROTO_RSN ?
|
||||
RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
|
||||
if (cipher & WPA_CIPHER_GCMP)
|
||||
return RSN_CIPHER_SUITE_GCMP;
|
||||
if (cipher & WPA_CIPHER_TKIP)
|
||||
return (proto == WPA_PROTO_RSN ?
|
||||
RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
|
||||
if (cipher & WPA_CIPHER_WEP104)
|
||||
return (proto == WPA_PROTO_RSN ?
|
||||
RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104);
|
||||
if (cipher & WPA_CIPHER_WEP40)
|
||||
return (proto == WPA_PROTO_RSN ?
|
||||
RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40);
|
||||
if (cipher & WPA_CIPHER_NONE)
|
||||
return (proto == WPA_PROTO_RSN ?
|
||||
RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rsn_cipher_put_suites(u8 *pos, int ciphers)
|
||||
{
|
||||
int num_suites = 0;
|
||||
|
||||
if (ciphers & WPA_CIPHER_CCMP) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
if (ciphers & WPA_CIPHER_GCMP) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
if (ciphers & WPA_CIPHER_TKIP) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
if (ciphers & WPA_CIPHER_NONE) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
|
||||
return num_suites;
|
||||
}
|
||||
|
||||
int wpa_cipher_put_suites(u8 *pos, int ciphers)
|
||||
{
|
||||
int num_suites = 0;
|
||||
|
||||
if (ciphers & WPA_CIPHER_CCMP) {
|
||||
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
|
||||
pos += WPA_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
if (ciphers & WPA_CIPHER_TKIP) {
|
||||
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
|
||||
pos += WPA_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
if (ciphers & WPA_CIPHER_NONE) {
|
||||
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
|
||||
pos += WPA_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
|
||||
return num_suites;
|
||||
}
|
||||
|
||||
#endif // EMBEDDED_SUPP
|
||||
|
||||
|
2291
components/wpa_supplicant/src/rsn_supp/wpa.c
Normal file
2291
components/wpa_supplicant/src/rsn_supp/wpa.c
Normal file
File diff suppressed because it is too large
Load Diff
407
components/wpa_supplicant/src/rsn_supp/wpa_ie.c
Normal file
407
components/wpa_supplicant/src/rsn_supp/wpa_ie.c
Normal file
@ -0,0 +1,407 @@
|
||||
/*
|
||||
* wpa_supplicant - WPA/RSN IE and KDE processing
|
||||
* Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
#if 1//def EMBEDDED_SUPP
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "rsn_supp/wpa.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "rsn_supp/wpa_ie.h"
|
||||
#include "rsn_supp/pmksa_cache.h"
|
||||
|
||||
/**
|
||||
* wpa_parse_wpa_ie - Parse WPA/RSN IE
|
||||
* @wpa_ie: Pointer to WPA or RSN IE
|
||||
* @wpa_ie_len: Length of the WPA/RSN IE
|
||||
* @data: Pointer to data area for parsing results
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* Parse the contents of WPA or RSN IE and write the parsed data into data.
|
||||
*/
|
||||
int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
struct wpa_ie_data *data)
|
||||
{
|
||||
if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN)
|
||||
return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
|
||||
else
|
||||
return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
|
||||
int pairwise_cipher, int group_cipher,
|
||||
int key_mgmt)
|
||||
{
|
||||
u8 *pos;
|
||||
struct wpa_ie_hdr *hdr;
|
||||
|
||||
if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
|
||||
2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
|
||||
return -1;
|
||||
|
||||
hdr = (struct wpa_ie_hdr *) wpa_ie;
|
||||
hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
|
||||
RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
|
||||
WPA_PUT_LE16(hdr->version, WPA_VERSION);
|
||||
pos = (u8 *) (hdr + 1);
|
||||
|
||||
if (group_cipher == WPA_CIPHER_CCMP) {
|
||||
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
|
||||
} else if (group_cipher == WPA_CIPHER_TKIP) {
|
||||
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
|
||||
} else if (group_cipher == WPA_CIPHER_WEP104) {
|
||||
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
|
||||
} else if (group_cipher == WPA_CIPHER_WEP40) {
|
||||
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
|
||||
group_cipher);
|
||||
return -1;
|
||||
}
|
||||
pos += WPA_SELECTOR_LEN;
|
||||
|
||||
*pos++ = 1;
|
||||
*pos++ = 0;
|
||||
if (pairwise_cipher == WPA_CIPHER_CCMP) {
|
||||
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
|
||||
} else if (pairwise_cipher == WPA_CIPHER_TKIP) {
|
||||
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
|
||||
} else if (pairwise_cipher == WPA_CIPHER_NONE) {
|
||||
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
|
||||
pairwise_cipher);
|
||||
return -1;
|
||||
}
|
||||
pos += WPA_SELECTOR_LEN;
|
||||
|
||||
*pos++ = 1;
|
||||
*pos++ = 0;
|
||||
if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
|
||||
RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
|
||||
} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
|
||||
RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
|
||||
} else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
|
||||
RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
|
||||
key_mgmt);
|
||||
return -1;
|
||||
}
|
||||
pos += WPA_SELECTOR_LEN;
|
||||
|
||||
/* WPA Capabilities; use defaults, so no need to include it */
|
||||
|
||||
hdr->len = (pos - wpa_ie) - 2;
|
||||
|
||||
WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
|
||||
|
||||
return pos - wpa_ie;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
|
||||
int pairwise_cipher, int group_cipher,
|
||||
int key_mgmt, int mgmt_group_cipher,
|
||||
struct wpa_sm *sm)
|
||||
{
|
||||
#ifndef CONFIG_NO_WPA2
|
||||
u8 *pos;
|
||||
struct rsn_ie_hdr *hdr;
|
||||
u16 capab;
|
||||
u8 min_len = 0;
|
||||
|
||||
if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
|
||||
2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
|
||||
(sm->cur_pmksa ? 2 + PMKID_LEN : 0)) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)",
|
||||
(unsigned long) rsn_ie_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* For WPA2-PSK, if the RSNE in AP beacon/probe response doesn't specify the
|
||||
* pairwise cipher or AKM suite, the RSNE IE in association request
|
||||
* should only contain group cihpher suite, otherwise the WPA2 improvements
|
||||
* certification will fail.
|
||||
*/
|
||||
if ( (sm->ap_notify_completed_rsne == true) || (key_mgmt == WPA_KEY_MGMT_IEEE8021X) ) {
|
||||
min_len = sizeof(*hdr) + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2;
|
||||
} else {
|
||||
min_len = sizeof(*hdr) + RSN_SELECTOR_LEN;
|
||||
}
|
||||
|
||||
if (rsn_ie_len < min_len) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", (unsigned long) rsn_ie_len);
|
||||
}
|
||||
|
||||
hdr = (struct rsn_ie_hdr *) rsn_ie;
|
||||
hdr->elem_id = WLAN_EID_RSN;
|
||||
WPA_PUT_LE16(hdr->version, RSN_VERSION);
|
||||
pos = (u8 *) (hdr + 1);
|
||||
|
||||
if (group_cipher == WPA_CIPHER_CCMP) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
|
||||
} else if (group_cipher == WPA_CIPHER_TKIP) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
|
||||
} else if (group_cipher == WPA_CIPHER_WEP104) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
|
||||
} else if (group_cipher == WPA_CIPHER_WEP40) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
|
||||
group_cipher);
|
||||
return -1;
|
||||
}
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
|
||||
if ( (sm->ap_notify_completed_rsne == false) && (key_mgmt != WPA_KEY_MGMT_IEEE8021X) ) {
|
||||
hdr->len = (pos - rsn_ie) - 2;
|
||||
return (pos - rsn_ie);
|
||||
}
|
||||
|
||||
*pos++ = 1;
|
||||
*pos++ = 0;
|
||||
if (pairwise_cipher == WPA_CIPHER_CCMP) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
|
||||
} else if (pairwise_cipher == WPA_CIPHER_TKIP) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
|
||||
} else if (pairwise_cipher == WPA_CIPHER_NONE) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
|
||||
pairwise_cipher);
|
||||
return -1;
|
||||
}
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
|
||||
*pos++ = 1;
|
||||
*pos++ = 0;
|
||||
if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
|
||||
} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
} else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
|
||||
} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
|
||||
} else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_WPA3_SAE
|
||||
} else if (key_mgmt == WPA_KEY_MGMT_SAE) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
|
||||
#endif /* CONFIG_WPA3_SAE */
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
|
||||
key_mgmt);
|
||||
return -1;
|
||||
}
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
|
||||
/* RSN Capabilities */
|
||||
capab = 0;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (sm->pmf_cfg.capable) {
|
||||
capab |= WPA_CAPABILITY_MFPC;
|
||||
if (sm->pmf_cfg.required || key_mgmt == WPA_KEY_MGMT_SAE) {
|
||||
capab |= WPA_CAPABILITY_MFPR;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
WPA_PUT_LE16(pos, capab);
|
||||
pos += 2;
|
||||
|
||||
if (sm->cur_pmksa) {
|
||||
/* PMKID Count (2 octets, little endian) */
|
||||
*pos++ = 1;
|
||||
*pos++ = 0;
|
||||
/* PMKID */
|
||||
os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
|
||||
pos += PMKID_LEN;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
|
||||
if (!sm->cur_pmksa) {
|
||||
/* 0 PMKID Count */
|
||||
WPA_PUT_LE16(pos, 0);
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
/* Management Group Cipher Suite */
|
||||
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
hdr->len = (pos - rsn_ie) - 2;
|
||||
|
||||
WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
|
||||
|
||||
return pos - rsn_ie;
|
||||
#else /* CONFIG_NO_WPA2 */
|
||||
return -1;
|
||||
#endif /* CONFIG_NO_WPA2 */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
|
||||
* @sm: Pointer to WPA state machine data from wpa_sm_init()
|
||||
* @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
|
||||
* @wpa_ie_len: Maximum length of the generated WPA/RSN IE
|
||||
* Returns: Length of the generated WPA/RSN IE or -1 on failure
|
||||
*/
|
||||
int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
|
||||
{
|
||||
if (sm->proto == WPA_PROTO_RSN)
|
||||
return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
|
||||
sm->pairwise_cipher,
|
||||
sm->group_cipher,
|
||||
sm->key_mgmt, sm->mgmt_group_cipher,
|
||||
sm);
|
||||
else
|
||||
return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
|
||||
sm->pairwise_cipher,
|
||||
sm->group_cipher,
|
||||
sm->key_mgmt);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
|
||||
* @pos: Pointer to the IE header
|
||||
* @end: Pointer to the end of the Key Data buffer
|
||||
* @ie: Pointer to parsed IE data
|
||||
* Returns: 0 on success, 1 if end mark is found, -1 on failure
|
||||
*/
|
||||
static int wpa_parse_generic(const u8 *pos, const u8 *end,
|
||||
struct wpa_eapol_ie_parse *ie)
|
||||
{
|
||||
if (pos[1] == 0)
|
||||
return 1;
|
||||
|
||||
if (pos[1] >= 6 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
|
||||
pos[2 + WPA_SELECTOR_LEN] == 1 &&
|
||||
pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
|
||||
ie->wpa_ie = pos;
|
||||
ie->wpa_ie_len = pos[1] + 2;
|
||||
wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
|
||||
ie->wpa_ie, ie->wpa_ie_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pos + 1 + RSN_SELECTOR_LEN < end &&
|
||||
pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
|
||||
ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
|
||||
wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
|
||||
pos, pos[1] + 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
|
||||
ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
|
||||
ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
|
||||
wpa_hexdump(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
|
||||
pos, pos[1] + 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
|
||||
ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
|
||||
ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
|
||||
wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
|
||||
pos, pos[1] + 2);
|
||||
return 0;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
|
||||
ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
|
||||
ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
|
||||
wpa_hexdump(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
|
||||
pos, pos[1] + 2);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
|
||||
* @buf: Pointer to the Key Data buffer
|
||||
* @len: Key Data Length
|
||||
* @ie: Pointer to parsed IE data
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
|
||||
struct wpa_eapol_ie_parse *ie)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
int ret = 0;
|
||||
|
||||
memset(ie, 0, sizeof(*ie));
|
||||
for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
|
||||
if (pos[0] == 0xdd &&
|
||||
((pos == buf + len - 1) || pos[1] == 0)) {
|
||||
/* Ignore padding */
|
||||
break;
|
||||
}
|
||||
if (pos + 2 + pos[1] > end) {
|
||||
#ifdef DEBUG_PRINT
|
||||
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
|
||||
"underflow (ie=%d len=%d pos=%d)",
|
||||
pos[0], pos[1], (int) (pos - buf));
|
||||
#endif
|
||||
wpa_hexdump(MSG_DEBUG, "WPA: Key Data",
|
||||
buf, len);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
if (*pos == WLAN_EID_RSN) {
|
||||
ie->rsn_ie = pos;
|
||||
ie->rsn_ie_len = pos[1] + 2;
|
||||
wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
|
||||
ie->rsn_ie, ie->rsn_ie_len);
|
||||
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
|
||||
ret = wpa_parse_generic(pos, end, ie);
|
||||
if (ret < 0)
|
||||
break;
|
||||
if (ret > 0) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
|
||||
"Key Data IE", pos, 2 + pos[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#endif // EMBEDDED_SUPP
|
||||
|
237
components/wpa_supplicant/src/utils/common.c
Normal file
237
components/wpa_supplicant/src/utils/common.c
Normal file
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* wpa_supplicant/hostapd / common helper functions, etc.
|
||||
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
|
||||
#ifdef MEMLEAK_DEBUG
|
||||
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* inc_byte_array - Increment arbitrary length byte array by one
|
||||
* @counter: Pointer to byte array
|
||||
* @len: Length of the counter in bytes
|
||||
*
|
||||
* This function increments the last byte of the counter by one and continues
|
||||
* rolling over to more significant bytes if the byte was incremented from
|
||||
* 0xff to 0x00.
|
||||
*/
|
||||
void ICACHE_FLASH_ATTR inc_byte_array(u8* counter, size_t len)
|
||||
{
|
||||
int pos = len - 1;
|
||||
|
||||
while (pos >= 0) {
|
||||
counter[pos]++;
|
||||
|
||||
if (counter[pos] != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
pos--;
|
||||
}
|
||||
}
|
||||
|
||||
static int ICACHE_FLASH_ATTR hex2num(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
return c - 'A' + 10;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int ICACHE_FLASH_ATTR hex2byte(const char* hex)
|
||||
{
|
||||
int a, b;
|
||||
a = hex2num(*hex++);
|
||||
|
||||
if (a < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
b = hex2num(*hex++);
|
||||
|
||||
if (b < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (a << 4) | b;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hexstr2bin - Convert ASCII hex string into binary data
|
||||
* @hex: ASCII hex string (e.g., "01ab")
|
||||
* @buf: Buffer for the binary data
|
||||
* @len: Length of the text to convert in bytes (of buf); hex will be double
|
||||
* this size
|
||||
* Returns: 0 on success, -1 on failure (invalid hex string)
|
||||
*/
|
||||
int ICACHE_FLASH_ATTR hexstr2bin(const char* hex, u8* buf, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
int a;
|
||||
const char* ipos = hex;
|
||||
u8* opos = buf;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
a = hex2byte(ipos);
|
||||
|
||||
if (a < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*opos++ = a;
|
||||
ipos += 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR wpa_get_ntp_timestamp(u8* buf)
|
||||
{
|
||||
struct os_time now;
|
||||
u32 sec, usec;
|
||||
be32 tmp;
|
||||
|
||||
/* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */
|
||||
os_get_time(&now);
|
||||
sec = now.sec + 2208988800U; /* Epoch to 1900 */
|
||||
/* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */
|
||||
usec = now.usec;
|
||||
usec = 4295 * usec - (usec >> 5) - (usec >> 9);
|
||||
tmp = host_to_be32(sec);
|
||||
os_memcpy(buf, (u8*) &tmp, 4);
|
||||
tmp = host_to_be32(usec);
|
||||
os_memcpy(buf + 4, (u8*) &tmp, 4);
|
||||
}
|
||||
|
||||
char* ICACHE_FLASH_ATTR wpa_config_parse_string(const char* value, size_t* len)
|
||||
{
|
||||
if (*value == '"' && (os_strlen(value) == 7 || os_strlen(value) == 15)) {
|
||||
const char* pos;
|
||||
char* str;
|
||||
value++;
|
||||
pos = (char*)os_strrchr(value, '"');
|
||||
|
||||
if (pos == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*len = pos - value;
|
||||
str = (char*)os_malloc(*len + 1);
|
||||
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_memcpy(str, value, *len);
|
||||
str[*len] = '\0';
|
||||
return str;
|
||||
} else {
|
||||
u8* str;
|
||||
size_t tlen, hlen = os_strlen(value);
|
||||
|
||||
if (hlen == 5 || hlen == 13) {
|
||||
*len = hlen;
|
||||
str = (u8*)os_malloc(*len + 1);
|
||||
os_memcpy(str, value, *len);
|
||||
str[*len] = '\0';
|
||||
} else if (hlen == 10 || hlen == 26) {
|
||||
tlen = hlen / 2;
|
||||
str = (u8*)os_malloc(tlen + 1);
|
||||
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hexstr2bin(value, str, tlen)) {
|
||||
os_free(str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
str[tlen] = '\0';
|
||||
*len = tlen;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (char*) str;
|
||||
}
|
||||
}
|
||||
|
||||
char* ICACHE_FLASH_ATTR
|
||||
dup_binstr(const void* src, size_t len)
|
||||
{
|
||||
char* res;
|
||||
|
||||
if (src == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = os_malloc(len + 1);
|
||||
|
||||
if (res == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_memcpy(res, src, len);
|
||||
res[len] = '\0';
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void wpa_bin_clear_free(void *bin, size_t len)
|
||||
{
|
||||
if (bin) {
|
||||
os_memset(bin, 0, len);
|
||||
os_free(bin);
|
||||
}
|
||||
}
|
||||
|
||||
int int_array_len(const int *a)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; a && a[i]; i++)
|
||||
;
|
||||
return i;
|
||||
}
|
||||
|
||||
void bin_clear_free(void *bin, size_t len)
|
||||
{
|
||||
if (bin) {
|
||||
os_memset(bin, 0, len);
|
||||
os_free(bin);
|
||||
}
|
||||
}
|
||||
|
||||
void str_clear_free(char *str)
|
||||
{
|
||||
if (str) {
|
||||
size_t len = os_strlen(str);
|
||||
os_memset(str, 0, len);
|
||||
os_free(str);
|
||||
}
|
||||
}
|
80
components/wpa_supplicant/src/utils/wpa_debug.c
Normal file
80
components/wpa_supplicant/src/utils/wpa_debug.c
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* wpa_supplicant/hostapd / Debug prints
|
||||
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
#ifdef EMBEDDED_SUPP
|
||||
#include "rom/ets_sys.h"
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
|
||||
#if 0//def DEBUG_PRINT
|
||||
int ICACHE_FLASH_ATTR wpa_snprintf_hex(char* buf, size_t buf_size, const u8* data, size_t len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR wpa_debug_print_timestamp(void)
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
struct os_time tv;
|
||||
os_get_time(&tv);
|
||||
wpa_printf(MSG_DEBUG, "%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR wpa_hexdump(int level, const char* title, const u8* buf, size_t len)
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
size_t i;
|
||||
|
||||
if (level < MSG_MSGDUMP) {
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s - hexdump(len=%lu):", title, (unsigned long) len);
|
||||
|
||||
if (buf == NULL) {
|
||||
wpa_printf(MSG_DEBUG, " [NULL]");
|
||||
} else {
|
||||
for (i = 0; i < len; i++) {
|
||||
wpa_printf(MSG_DEBUG, " %02x", buf[i]);
|
||||
|
||||
if ((i + 1) % 16 == 0) {
|
||||
wpa_printf(MSG_DEBUG, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR wpa_hexdump_key(int level, const char* title, const u8* buf, size_t len)
|
||||
{
|
||||
wpa_hexdump(level, title, buf, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
int ICACHE_FLASH_ATTR eloop_cancel_timeout(eloop_timeout_handler handler,
|
||||
void* eloop_data, void* user_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ICACHE_FLASH_ATTR eloop_register_timeout(unsigned int secs, unsigned int usecs,
|
||||
eloop_timeout_handler handler,
|
||||
void* eloop_data, void* user_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif // EMBEDDED_SUPP
|
||||
|
369
components/wpa_supplicant/src/utils/wpabuf.c
Normal file
369
components/wpa_supplicant/src/utils/wpabuf.c
Normal file
@ -0,0 +1,369 @@
|
||||
/*
|
||||
* Dynamic data buffer
|
||||
* Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/wpabuf.h"
|
||||
#include "stdio.h"
|
||||
#include "stdarg.h"
|
||||
|
||||
#ifdef MEMLEAK_DEBUG
|
||||
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
|
||||
#endif
|
||||
|
||||
#define wpa_trace_show ets_printf
|
||||
|
||||
#ifdef WPA_TRACE
|
||||
#define WPABUF_MAGIC 0x51a974e3
|
||||
|
||||
struct wpabuf_trace {
|
||||
unsigned int magic;
|
||||
};
|
||||
|
||||
static struct wpabuf_trace* wpabuf_get_trace(const struct wpabuf* buf)
|
||||
{
|
||||
return (struct wpabuf_trace*)
|
||||
((const u8*) buf - sizeof(struct wpabuf_trace));
|
||||
}
|
||||
#endif /* WPA_TRACE */
|
||||
|
||||
|
||||
static void ICACHE_FLASH_ATTR wpabuf_overflow(const struct wpabuf* buf, size_t len)
|
||||
{
|
||||
#ifdef WPA_TRACE
|
||||
struct wpabuf_trace* trace = wpabuf_get_trace(buf);
|
||||
|
||||
if (trace->magic != WPABUF_MAGIC) {
|
||||
wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x",
|
||||
trace->magic);
|
||||
}
|
||||
|
||||
#endif /* WPA_TRACE */
|
||||
wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu",
|
||||
buf, (unsigned long) buf->size, (unsigned long) buf->used,
|
||||
(unsigned long) len);
|
||||
wpa_trace_show("wpabuf overflow");
|
||||
//abort();
|
||||
}
|
||||
|
||||
|
||||
int ICACHE_FLASH_ATTR wpabuf_resize(struct wpabuf** _buf, size_t add_len)
|
||||
{
|
||||
struct wpabuf* buf = *_buf;
|
||||
#ifdef WPA_TRACE
|
||||
struct wpabuf_trace* trace;
|
||||
#endif /* WPA_TRACE */
|
||||
|
||||
if (buf == NULL) {
|
||||
*_buf = wpabuf_alloc(add_len);
|
||||
return *_buf == NULL ? -1 : 0;
|
||||
}
|
||||
|
||||
#ifdef WPA_TRACE
|
||||
trace = wpabuf_get_trace(buf);
|
||||
|
||||
if (trace->magic != WPABUF_MAGIC) {
|
||||
wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x",
|
||||
trace->magic);
|
||||
wpa_trace_show("wpabuf_resize invalid magic");
|
||||
abort();
|
||||
}
|
||||
|
||||
#endif /* WPA_TRACE */
|
||||
|
||||
if (buf->used + add_len > buf->size) {
|
||||
unsigned char* nbuf;
|
||||
|
||||
if (buf->ext_data) {
|
||||
nbuf = (unsigned char*)os_realloc(buf->ext_data, buf->used + add_len);
|
||||
|
||||
if (nbuf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(nbuf + buf->used, 0, add_len);
|
||||
buf->ext_data = nbuf;
|
||||
} else {
|
||||
#ifdef WPA_TRACE
|
||||
nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) +
|
||||
sizeof(struct wpabuf) +
|
||||
buf->used + add_len);
|
||||
|
||||
if (nbuf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
trace = (struct wpabuf_trace*) nbuf;
|
||||
buf = (struct wpabuf*)(trace + 1);
|
||||
os_memset(nbuf + sizeof(struct wpabuf_trace) +
|
||||
sizeof(struct wpabuf) + buf->used, 0,
|
||||
add_len);
|
||||
#else /* WPA_TRACE */
|
||||
nbuf = (unsigned char*)os_realloc(buf, sizeof(struct wpabuf) +
|
||||
buf->used + add_len);
|
||||
|
||||
if (nbuf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = (struct wpabuf*) nbuf;
|
||||
os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0,
|
||||
add_len);
|
||||
#endif /* WPA_TRACE */
|
||||
*_buf = buf;
|
||||
}
|
||||
|
||||
buf->size = buf->used + add_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpabuf_alloc - Allocate a wpabuf of the given size
|
||||
* @len: Length for the allocated buffer
|
||||
* Returns: Buffer to the allocated wpabuf or %NULL on failure
|
||||
*/
|
||||
struct wpabuf* ICACHE_FLASH_ATTR wpabuf_alloc(size_t len)
|
||||
{
|
||||
#ifdef WPA_TRACE
|
||||
struct wpabuf_trace* trace = os_zalloc(sizeof(struct wpabuf_trace) +
|
||||
sizeof(struct wpabuf) + len);
|
||||
struct wpabuf* buf;
|
||||
|
||||
if (trace == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
trace->magic = WPABUF_MAGIC;
|
||||
buf = (struct wpabuf*)(trace + 1);
|
||||
#else /* WPA_TRACE */
|
||||
struct wpabuf* buf = (struct wpabuf*)os_zalloc(sizeof(struct wpabuf) + len);
|
||||
|
||||
if (buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* WPA_TRACE */
|
||||
|
||||
buf->size = len;
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf* ICACHE_FLASH_ATTR wpabuf_alloc_ext_data(u8* data, size_t len)
|
||||
{
|
||||
#ifdef WPA_TRACE
|
||||
struct wpabuf_trace* trace = os_zalloc(sizeof(struct wpabuf_trace) +
|
||||
sizeof(struct wpabuf));
|
||||
struct wpabuf* buf;
|
||||
|
||||
if (trace == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
trace->magic = WPABUF_MAGIC;
|
||||
buf = (struct wpabuf*)(trace + 1);
|
||||
#else /* WPA_TRACE */
|
||||
struct wpabuf* buf = (struct wpabuf*)os_zalloc(sizeof(struct wpabuf));
|
||||
|
||||
if (buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* WPA_TRACE */
|
||||
|
||||
buf->size = len;
|
||||
buf->used = len;
|
||||
buf->ext_data = data;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf* ICACHE_FLASH_ATTR wpabuf_alloc_copy(const void* data, size_t len)
|
||||
{
|
||||
struct wpabuf* buf = wpabuf_alloc(len);
|
||||
|
||||
if (buf) {
|
||||
wpabuf_put_data(buf, data, len);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf* ICACHE_FLASH_ATTR wpabuf_dup(const struct wpabuf* src)
|
||||
{
|
||||
struct wpabuf* buf = wpabuf_alloc(wpabuf_len(src));
|
||||
|
||||
if (buf) {
|
||||
wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src));
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpabuf_free - Free a wpabuf
|
||||
* @buf: wpabuf buffer
|
||||
*/
|
||||
void ICACHE_FLASH_ATTR wpabuf_free(struct wpabuf* buf)
|
||||
{
|
||||
#ifdef WPA_TRACE
|
||||
struct wpabuf_trace* trace;
|
||||
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
trace = wpabuf_get_trace(buf);
|
||||
|
||||
if (trace->magic != WPABUF_MAGIC) {
|
||||
wpa_printf(MSG_ERROR, "wpabuf_free: invalid magic %x",
|
||||
trace->magic);
|
||||
wpa_trace_show("wpabuf_free magic mismatch");
|
||||
abort();
|
||||
}
|
||||
|
||||
os_free(buf->ext_data);
|
||||
os_free(trace);
|
||||
#else /* WPA_TRACE */
|
||||
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
os_free(buf->ext_data);
|
||||
os_free(buf);
|
||||
#endif /* WPA_TRACE */
|
||||
}
|
||||
|
||||
|
||||
void* ICACHE_FLASH_ATTR wpabuf_put(struct wpabuf* buf, size_t len)
|
||||
{
|
||||
void* tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
|
||||
buf->used += len;
|
||||
|
||||
if (buf->used > buf->size) {
|
||||
wpabuf_overflow(buf, len);
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpabuf_concat - Concatenate two buffers into a newly allocated one
|
||||
* @a: First buffer
|
||||
* @b: Second buffer
|
||||
* Returns: wpabuf with concatenated a + b data or %NULL on failure
|
||||
*
|
||||
* Both buffers a and b will be freed regardless of the return value. Input
|
||||
* buffers can be %NULL which is interpreted as an empty buffer.
|
||||
*/
|
||||
struct wpabuf* ICACHE_FLASH_ATTR wpabuf_concat(struct wpabuf* a, struct wpabuf* b)
|
||||
{
|
||||
struct wpabuf* n = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
if (b == NULL) {
|
||||
return a;
|
||||
}
|
||||
|
||||
if (a) {
|
||||
len += wpabuf_len(a);
|
||||
}
|
||||
|
||||
if (b) {
|
||||
len += wpabuf_len(b);
|
||||
}
|
||||
|
||||
n = wpabuf_alloc(len);
|
||||
|
||||
if (n) {
|
||||
if (a) {
|
||||
wpabuf_put_buf(n, a);
|
||||
}
|
||||
|
||||
if (b) {
|
||||
wpabuf_put_buf(n, b);
|
||||
}
|
||||
}
|
||||
|
||||
wpabuf_free(a);
|
||||
wpabuf_free(b);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length
|
||||
* @buf: Buffer to be padded
|
||||
* @len: Length for the padded buffer
|
||||
* Returns: wpabuf padded to len octets or %NULL on failure
|
||||
*
|
||||
* If buf is longer than len octets or of same size, it will be returned as-is.
|
||||
* Otherwise a new buffer is allocated and prefixed with 0x00 octets followed
|
||||
* by the source data. The source buffer will be freed on error, i.e., caller
|
||||
* will only be responsible on freeing the returned buffer. If buf is %NULL,
|
||||
* %NULL will be returned.
|
||||
*/
|
||||
struct wpabuf* ICACHE_FLASH_ATTR wpabuf_zeropad(struct wpabuf* buf, size_t len)
|
||||
{
|
||||
struct wpabuf* ret;
|
||||
size_t blen;
|
||||
|
||||
if (buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
blen = wpabuf_len(buf);
|
||||
|
||||
if (blen >= len) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
ret = wpabuf_alloc(len);
|
||||
|
||||
if (ret) {
|
||||
os_memset(wpabuf_put(ret, len - blen), 0, len - blen);
|
||||
wpabuf_put_buf(ret, buf);
|
||||
}
|
||||
|
||||
wpabuf_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR wpabuf_printf(struct wpabuf* buf, char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
void* tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
|
||||
int res;
|
||||
|
||||
va_start(ap, fmt);
|
||||
res = vsnprintf(tmp, buf->size - buf->used, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (res < 0 || (size_t) res >= buf->size - buf->used) {
|
||||
wpabuf_overflow(buf, res);
|
||||
}
|
||||
|
||||
buf->used += res;
|
||||
}
|
Reference in New Issue
Block a user