wifi: Add PMK caching feature for station WPA2-enterprise

1) Added PMK caching module from wpa_supplicant.
2) Modified wpa_sm to
    a) Add entry to PMK cache when first time associated to an AP.
    b) Maintain entry across the associations.
    c) Clear current PMKSA when deauth happens.
    d) Search for an entry when re-associating to the same AP and
       set it as current PMKSA
    e) Wait for msg 1/4 from AP instead of starting EAP authentication.
    f) Check PMKID in msg 1 with current PMKSA/cache.
    g) Use the cached PMK to complete 4-way handshake.
3) Remove config_bss callback as it was redundant and used to cause
   problems for PMK caching flow.

Closes IDF-969
This commit is contained in:
Sagar Bijwe 2019-09-19 16:53:56 +05:30 committed by Nachiket Kukade
parent b9fa6b0b1a
commit 2da4ffa2aa
15 changed files with 1793 additions and 384 deletions

View file

@ -46,6 +46,7 @@ set(srcs "port/os_xtensa.c"
"src/esp_supplicant/esp_wpa_main.c"
"src/esp_supplicant/esp_wpas_glue.c"
"src/esp_supplicant/esp_wps.c"
"src/rsn_supp/pmksa_cache.c"
"src/rsn_supp/wpa.c"
"src/rsn_supp/wpa_ie.c"
"src/tls/asn1.c"

View file

@ -2,14 +2,8 @@
* 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.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef COMMON_H
@ -65,6 +59,7 @@ static inline unsigned int wpa_swap_32(unsigned int v)
#define be_to_host16(n) wpa_swap_16(n)
#define host_to_be16(n) wpa_swap_16(n)
#define le_to_host32(n) (n)
#define host_to_le32(n) (n)
#define be_to_host32(n) wpa_swap_32(n)
#define host_to_be32(n) wpa_swap_32(n)
@ -125,80 +120,122 @@ static inline unsigned int wpa_swap_32(unsigned int v)
/* Macros for handling unaligned memory accesses */
#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
#define WPA_PUT_BE16(a, val) \
do { \
(a)[0] = ((u16) (val)) >> 8; \
(a)[1] = ((u16) (val)) & 0xff; \
} while (0)
static inline u16 WPA_GET_BE16(const u8 *a)
{
return (a[0] << 8) | a[1];
}
#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0]))
#define WPA_PUT_LE16(a, val) \
do { \
(a)[1] = ((u16) (val)) >> 8; \
(a)[0] = ((u16) (val)) & 0xff; \
} while (0)
static inline void WPA_PUT_BE16(u8 *a, u16 val)
{
a[0] = val >> 8;
a[1] = val & 0xff;
}
#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
((u32) (a)[2]))
#define WPA_PUT_BE24(a, val) \
do { \
(a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \
(a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \
(a)[2] = (u8) (((u32) (val)) & 0xff); \
} while (0)
static inline u16 WPA_GET_LE16(const u8 *a)
{
return (a[1] << 8) | a[0];
}
#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
(((u32) (a)[2]) << 8) | ((u32) (a)[3]))
#define WPA_PUT_BE32(a, val) \
do { \
(a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \
(a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \
(a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \
(a)[3] = (u8) (((u32) (val)) & 0xff); \
} while (0)
static inline void WPA_PUT_LE16(u8 *a, u16 val)
{
a[1] = val >> 8;
a[0] = val & 0xff;
}
#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \
(((u32) (a)[1]) << 8) | ((u32) (a)[0]))
#define WPA_PUT_LE32(a, val) \
do { \
(a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \
(a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \
(a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \
(a)[0] = (u8) (((u32) (val)) & 0xff); \
} while (0)
static inline u32 WPA_GET_BE24(const u8 *a)
{
return (a[0] << 16) | (a[1] << 8) | a[2];
}
#define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \
(((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \
(((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \
(((u64) (a)[6]) << 8) | ((u64) (a)[7]))
#define WPA_PUT_BE64(a, val) \
do { \
(a)[0] = (u8) (((u64) (val)) >> 56); \
(a)[1] = (u8) (((u64) (val)) >> 48); \
(a)[2] = (u8) (((u64) (val)) >> 40); \
(a)[3] = (u8) (((u64) (val)) >> 32); \
(a)[4] = (u8) (((u64) (val)) >> 24); \
(a)[5] = (u8) (((u64) (val)) >> 16); \
(a)[6] = (u8) (((u64) (val)) >> 8); \
(a)[7] = (u8) (((u64) (val)) & 0xff); \
} while (0)
static inline void WPA_PUT_BE24(u8 *a, u32 val)
{
a[0] = (val >> 16) & 0xff;
a[1] = (val >> 8) & 0xff;
a[2] = val & 0xff;
}
#define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \
(((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \
(((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \
(((u64) (a)[1]) << 8) | ((u64) (a)[0]))
static inline u32 WPA_GET_BE32(const u8 *a)
{
return ((u32) a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
}
static inline void WPA_PUT_BE32(u8 *a, u32 val)
{
a[0] = (val >> 24) & 0xff;
a[1] = (val >> 16) & 0xff;
a[2] = (val >> 8) & 0xff;
a[3] = val & 0xff;
}
static inline u32 WPA_GET_LE32(const u8 *a)
{
return ((u32) a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0];
}
static inline void WPA_PUT_LE32(u8 *a, u32 val)
{
a[3] = (val >> 24) & 0xff;
a[2] = (val >> 16) & 0xff;
a[1] = (val >> 8) & 0xff;
a[0] = val & 0xff;
}
static inline u64 WPA_GET_BE64(const u8 *a)
{
return (((u64) a[0]) << 56) | (((u64) a[1]) << 48) |
(((u64) a[2]) << 40) | (((u64) a[3]) << 32) |
(((u64) a[4]) << 24) | (((u64) a[5]) << 16) |
(((u64) a[6]) << 8) | ((u64) a[7]);
}
static inline void WPA_PUT_BE64(u8 *a, u64 val)
{
a[0] = val >> 56;
a[1] = val >> 48;
a[2] = val >> 40;
a[3] = val >> 32;
a[4] = val >> 24;
a[5] = val >> 16;
a[6] = val >> 8;
a[7] = val & 0xff;
}
static inline u64 WPA_GET_LE64(const u8 *a)
{
return (((u64) a[7]) << 56) | (((u64) a[6]) << 48) |
(((u64) a[5]) << 40) | (((u64) a[4]) << 32) |
(((u64) a[3]) << 24) | (((u64) a[2]) << 16) |
(((u64) a[1]) << 8) | ((u64) a[0]);
}
static inline void WPA_PUT_LE64(u8 *a, u64 val)
{
a[7] = val >> 56;
a[6] = val >> 48;
a[5] = val >> 40;
a[4] = val >> 32;
a[3] = val >> 24;
a[2] = val >> 16;
a[1] = val >> 8;
a[0] = val & 0xff;
}
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
//#ifndef IFNAMSIZ
//#define IFNAMSIZ 16
//#endif
#ifndef ETH_HLEN
#define ETH_HLEN 14
#endif
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
#ifndef ETH_P_ALL
#define ETH_P_ALL 0x0003
#endif
#ifndef ETH_P_80211_ENCAP
#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */
#endif
#ifndef ETH_P_PAE
#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
#endif /* ETH_P_PAE */
@ -221,8 +258,31 @@ static inline unsigned int wpa_swap_32(unsigned int v)
#define STRUCT_PACKED
#endif
#ifdef CONFIG_ANSI_C_EXTRA
#if !defined(_MSC_VER) || _MSC_VER < 1400
/* snprintf - used in number of places; sprintf() is _not_ a good replacement
* due to possible buffer overflow; see, e.g.,
* http://www.ijs.si/software/snprintf/ for portable implementation of
* snprintf. */
int snprintf(char *str, size_t size, const char *format, ...);
/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */
/* getopt - only used in main.c */
int getopt(int argc, char *const argv[], const char *optstring);
extern char *optarg;
extern int optind;
#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF
#ifndef __socklen_t_defined
typedef int socklen_t;
#endif
#endif
/* inline - define as __inline or just define it to be empty, if needed */
#ifdef CONFIG_NO_INLINE
#define inline
@ -258,10 +318,16 @@ void perror(const char *s);
#ifndef MAC2STR
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
/*
* Compact form for string representation of MAC address
* To be used, e.g., for constructing dbus paths for P2P Devices
*/
#define COMPACT_MACSTR "%02x%02x%02x%02x%02x%02x"
#endif
#ifndef BIT
#define BIT(x) (1 << (x))
#define BIT(x) (1U << (x))
#endif
/*
@ -291,15 +357,31 @@ typedef u64 __bitwise le64;
#endif /* __GNUC__ */
#endif /* __must_check */
#ifndef __maybe_unused
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
#define __maybe_unused __attribute__((unused))
#else
#define __maybe_unused
#endif /* __GNUC__ */
#endif /* __must_check */
int hwaddr_aton(const char *txt, u8 *addr);
int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable);
int hwaddr_compact_aton(const char *txt, u8 *addr);
int hwaddr_aton2(const char *txt, u8 *addr);
int hex2byte(const char *hex);
int hexstr2bin(const char *hex, u8 *buf, size_t len);
void inc_byte_array(u8 *counter, size_t len);
void wpa_get_ntp_timestamp(u8 *buf);
int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...);
int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len,
char sep);
int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
size_t len);
int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask);
#ifdef CONFIG_NATIVE_WINDOWS
void wpa_unicode2ascii_inplace(TCHAR *str);
TCHAR * wpa_strdup_tchar(const char *str);
@ -308,21 +390,74 @@ TCHAR * wpa_strdup_tchar(const char *str);
#define wpa_strdup_tchar(s) strdup((s))
#endif /* CONFIG_NATIVE_WINDOWS */
void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len);
size_t printf_decode(u8 *buf, size_t maxlen, const char *str);
const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
char * wpa_config_parse_string(const char *value, size_t *len);
int is_hex(const u8 *data, size_t len);
size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len);
char * dup_binstr(const void *src, size_t len);
static inline int is_zero_ether_addr(const u8 *a)
{
return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
}
extern const struct eth_addr ethbroadcast;
#define broadcast_ether_addr &ethbroadcast
static inline int is_broadcast_ether_addr(const u8 *a)
{
return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff;
}
static inline int is_multicast_ether_addr(const u8 *a)
{
return a[0] & 0x01;
}
#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff"
#include "wpabuf.h"
#include "wpa_debug.h"
struct wpa_freq_range_list {
struct wpa_freq_range {
unsigned int min;
unsigned int max;
} *range;
unsigned int num;
};
int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value);
int freq_range_list_includes(const struct wpa_freq_range_list *list,
unsigned int freq);
char * freq_range_list_str(const struct wpa_freq_range_list *list);
int int_array_len(const int *a);
void int_array_concat(int **res, const int *a);
void int_array_sort_unique(int *a);
void int_array_add_unique(int **res, int a);
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
void str_clear_free(char *str);
void bin_clear_free(void *bin, size_t len);
int random_mac_addr(u8 *addr);
int random_mac_addr_keep_oui(u8 *addr);
const char * cstr_token(const char *str, const char *delim, const char **last);
char * str_token(char *str, const char *delim, char **context);
size_t utf8_escape(const char *inp, size_t in_size,
char *outp, size_t out_size);
size_t utf8_unescape(const char *inp, size_t in_size,
char *outp, size_t out_size);
int is_ctrl_char(char c);
/*
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
* networking socket uses that do not really result in a real problem and
@ -335,4 +470,11 @@ extern const struct eth_addr ethbroadcast;
void * __hide_aliasing_typecast(void *foo);
#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a))
#ifdef CONFIG_VALGRIND
#include <valgrind/memcheck.h>
#define WPA_MEM_DEFINED(ptr, len) VALGRIND_MAKE_MEM_DEFINED((ptr), (len))
#else /* CONFIG_VALGRIND */
#define WPA_MEM_DEFINED(ptr, len) do { } while (0)
#endif /* CONFIG_VALGRIND */
#endif /* COMMON_H */

View file

@ -228,6 +228,10 @@ char * ets_strdup(const char *s);
#ifndef os_memcmp
#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n))
#endif
#ifndef os_memcmp_const
#define os_memcmp_const(s1, s2, n) memcmp((s1), (s2), (n))
#endif
#ifndef os_strlen
#define os_strlen(s) strlen(s)
@ -274,6 +278,11 @@ char * ets_strdup(const char *s);
#endif
#endif
static inline int os_snprintf_error(size_t size, int res)
{
return res < 0 || (unsigned int) res >= size;
}
/**
* os_strlcpy - Copy a string with size bound and NUL-termination
* @dest: Destination

View file

@ -1,15 +1,9 @@
/*
* WPA Supplicant - Common definitions
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2015, 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.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef DEFS_H
@ -41,43 +35,95 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
#define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
#define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
#define WPA_KEY_MGMT_WPS BIT(9)
#define WPA_KEY_MGMT_SAE BIT(10)
#define WPA_KEY_MGMT_FT_SAE BIT(11)
#define WPA_KEY_MGMT_WAPI_PSK BIT(12)
#define WPA_KEY_MGMT_WAPI_CERT BIT(13)
#define WPA_KEY_MGMT_CCKM BIT(14)
#define WPA_KEY_MGMT_OSEN BIT(15)
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B BIT(16)
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 BIT(17)
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
{
return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
WPA_KEY_MGMT_FT_IEEE8021X |
WPA_KEY_MGMT_CCKM |
WPA_KEY_MGMT_IEEE8021X_SHA256));
WPA_KEY_MGMT_OSEN |
WPA_KEY_MGMT_IEEE8021X_SHA256 |
WPA_KEY_MGMT_IEEE8021X_SUITE_B |
WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
}
static inline int wpa_key_mgmt_wpa_psk(int akm)
{
return akm == WPA_KEY_MGMT_PSK ||
akm == WPA_KEY_MGMT_FT_PSK ||
akm == WPA_KEY_MGMT_PSK_SHA256;
return !!(akm & (WPA_KEY_MGMT_PSK |
WPA_KEY_MGMT_FT_PSK |
WPA_KEY_MGMT_PSK_SHA256 |
WPA_KEY_MGMT_SAE |
WPA_KEY_MGMT_FT_SAE));
}
static inline int wpa_key_mgmt_ft(int akm)
{
return akm == WPA_KEY_MGMT_FT_PSK ||
akm == WPA_KEY_MGMT_FT_IEEE8021X;
return !!(akm & (WPA_KEY_MGMT_FT_PSK |
WPA_KEY_MGMT_FT_IEEE8021X |
WPA_KEY_MGMT_FT_SAE));
}
static inline int wpa_key_mgmt_sae(int akm)
{
return !!(akm & (WPA_KEY_MGMT_SAE |
WPA_KEY_MGMT_FT_SAE));
}
static inline int wpa_key_mgmt_sha256(int akm)
{
return akm == WPA_KEY_MGMT_PSK_SHA256 ||
akm == WPA_KEY_MGMT_IEEE8021X_SHA256;
return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
WPA_KEY_MGMT_IEEE8021X_SHA256 |
WPA_KEY_MGMT_OSEN |
WPA_KEY_MGMT_IEEE8021X_SUITE_B));
}
static inline int wpa_key_mgmt_sha384(int akm)
{
return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192);
}
static inline int wpa_key_mgmt_suite_b(int akm)
{
return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B |
WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
}
static inline int wpa_key_mgmt_wpa(int akm)
{
return wpa_key_mgmt_wpa_ieee8021x(akm) ||
wpa_key_mgmt_wpa_psk(akm) ||
wpa_key_mgmt_sae(akm);
}
static inline int wpa_key_mgmt_wpa_any(int akm)
{
return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE);
}
static inline int wpa_key_mgmt_cckm(int akm)
{
return akm == WPA_KEY_MGMT_CCKM;
}
#define WPA_PROTO_WPA BIT(0)
#define WPA_PROTO_RSN BIT(1)
#define WPA_PROTO_WAPI BIT(2)
#define WPA_PROTO_OSEN BIT(3)
#define WPA_AUTH_ALG_OPEN BIT(0)
#define WPA_AUTH_ALG_SHARED BIT(1)
#define WPA_AUTH_ALG_LEAP BIT(2)
#define WPA_AUTH_ALG_FT BIT(3)
#define WPA_AUTH_ALG_SAE BIT(4)
enum wifi_key_alg {
@ -147,6 +193,15 @@ enum wpa_states {
*/
WPA_DISCONNECTED,
/**
* WPA_INTERFACE_DISABLED - Interface disabled
*
* This state is entered if the network interface is disabled, e.g.,
* due to rfkill. wpa_supplicant refuses any new operations that would
* use the radio until the interface has been enabled.
*/
WPA_INTERFACE_DISABLED,
/**
* WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
*
@ -249,6 +304,17 @@ enum wpa_states {
#define MLME_SETPROTECTION_KEY_TYPE_GROUP 0
#define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1
/**
* enum mfp_options - Management frame protection (IEEE 802.11w) options
*/
enum mfp_options {
NO_MGMT_FRAME_PROTECTION = 0,
MGMT_FRAME_PROTECTION_OPTIONAL = 1,
MGMT_FRAME_PROTECTION_REQUIRED = 2,
};
#define MGMT_FRAME_PROTECTION_DEFAULT 3
/**
* enum hostapd_hw_mode - Hardware mode
*/
@ -257,7 +323,43 @@ enum hostapd_hw_mode {
HOSTAPD_MODE_IEEE80211G,
HOSTAPD_MODE_IEEE80211A,
HOSTAPD_MODE_IEEE80211AD,
HOSTAPD_MODE_IEEE80211ANY,
NUM_HOSTAPD_MODES
};
/**
* enum wpa_ctrl_req_type - Control interface request types
*/
enum wpa_ctrl_req_type {
WPA_CTRL_REQ_UNKNOWN,
WPA_CTRL_REQ_EAP_IDENTITY,
WPA_CTRL_REQ_EAP_PASSWORD,
WPA_CTRL_REQ_EAP_NEW_PASSWORD,
WPA_CTRL_REQ_EAP_PIN,
WPA_CTRL_REQ_EAP_OTP,
WPA_CTRL_REQ_EAP_PASSPHRASE,
WPA_CTRL_REQ_SIM,
WPA_CTRL_REQ_PSK_PASSPHRASE,
NUM_WPA_CTRL_REQS
};
/* Maximum number of EAP methods to store for EAP server user information */
#define EAP_MAX_METHODS 8
enum mesh_plink_state {
PLINK_LISTEN = 1,
PLINK_OPEN_SENT,
PLINK_OPEN_RCVD,
PLINK_CNF_RCVD,
PLINK_ESTAB,
PLINK_HOLDING,
PLINK_BLOCKED,
};
enum set_band {
WPA_SETBAND_AUTO,
WPA_SETBAND_5G,
WPA_SETBAND_2G
};
#endif /* DEFS_H */

View file

@ -105,7 +105,7 @@ typedef struct {
} wifi_wpa_ie_t;
struct wpa_funcs {
void (*wpa_sta_init)(void);
bool (*wpa_sta_init)(void);
bool (*wpa_sta_deinit)(void);
void (*wpa_sta_connect)(uint8_t *bssid);
int (*wpa_sta_rx_eapol)(u8 *src_addr, u8 *buf, u32 len);

View file

@ -58,7 +58,7 @@ static struct eap_sm *gEapSm = NULL;
static int eap_peer_sm_init(void);
static void eap_peer_sm_deinit(void);
static int wpa2_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid);
static int eap_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid);
static int wpa2_start_eapol_internal(void);
int wpa2_post(uint32_t sig, uint32_t par);
@ -216,7 +216,7 @@ void wpa2_task(void *pvParameters )
struct wpa2_rx_param *param = NULL;
while ((param = wpa2_rxq_dequeue()) != NULL){
wpa2_sm_rx_eapol_internal(param->sa, param->buf, param->len, param->bssid);
eap_sm_rx_eapol_internal(param->sa, param->buf, param->len, param->bssid);
os_free(param->buf);
os_free(param);
}
@ -541,12 +541,11 @@ static int wpa2_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid)
}
#else
return wpa2_sm_rx_eapol_internal(src_addr, buf, len, bssid);
return eap_sm_rx_eapol_internal(src_addr, buf, len, bssid);
#endif
}
static int wpa2_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid)
static int eap_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid)
{
struct eap_sm *sm = gEapSm;
u32 plen, data_len;
@ -666,6 +665,18 @@ static int wpa2_start_eapol_internal(void)
if (!sm) {
return ESP_FAIL;
}
if (wpa_sta_is_cur_pmksa_set()) {
if (0) {
wpa_printf(MSG_DEBUG,
"RSN: Timeout on waiting for the AP to initiate 4-way handshake \
for PMKSA caching or EAP authentication \
- try to force it to start EAP authentication");
} else {
wpa_printf(MSG_DEBUG,
"RSN: PMKSA caching - do not send EAPOL-Start");
return -1;
}
}
ret = esp_wifi_get_assoc_bssid_internal(bssid);
if (ret != 0) {

View file

@ -106,18 +106,21 @@ void wpa_neg_complete()
esp_wifi_auth_done_internal();
}
void wpa_attach(void)
bool wpa_attach(void)
{
bool ret = true;
#ifndef IOT_SIP_MODE
wpa_register(NULL, wpa_sendto_wrapper,
ret = wpa_sm_init(NULL, wpa_sendto_wrapper,
wpa_config_assoc_ie, wpa_install_key, wpa_get_key, wpa_deauthenticate, wpa_neg_complete);
#else
u8 *payload = (u8 *)os_malloc(WPA_TX_MSG_BUFF_MAXLEN);
wpa_register(payload, wpa_sendto_wrapper,
ret = wpa_sm_init(payload, wpa_sendto_wrapper,
wpa_config_assoc_ie, wpa_install_key, wpa_get_key, wpa_deauthenticate, wpa_neg_complete);
#endif
esp_wifi_register_tx_cb_internal(eapol_txcb, WIFI_TXCB_EAPOL_ID);
if(ret) {
ret = (esp_wifi_register_tx_cb_internal(eapol_txcb, WIFI_TXCB_EAPOL_ID) == ESP_OK);
}
return ret;
}
uint8_t *wpa_ap_get_wpa_ie(uint8_t *ie_len)
@ -148,6 +151,7 @@ bool wpa_ap_rx_eapol(void *hapd_data, void *sm_data, u8 *data, size_t data_len)
bool wpa_deattach(void)
{
wpa_sm_deinit();
return true;
}
@ -224,7 +228,7 @@ int esp_supplicant_init(void)
wpa_cb->wpa_config_parse_string = wpa_config_parse_string;
wpa_cb->wpa_parse_wpa_ie = wpa_parse_wpa_ie_wrapper;
wpa_cb->wpa_config_bss = wpa_config_bss;
wpa_cb->wpa_config_bss = NULL;//wpa_config_bss;
wpa_cb->wpa_michael_mic_failure = wpa_michael_mic_failure;
esp_wifi_register_wpa_cb_internal(wpa_cb);

View file

@ -18,6 +18,7 @@
#include "utils/common.h"
#include "common/eapol_common.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/pmksa_cache.h"
u8 *wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type,
const void *data, u16 data_len,
@ -65,6 +66,7 @@ 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) {
pmksa_cache_clear_current(sm);
sm->wpa_deauthenticate(reason_code);
}
}

View file

@ -0,0 +1,528 @@
/*
* WPA Supplicant - RSN PMKSA cache
* Copyright (c) 2004-2009, 2011-2015, 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 "rsn_supp/wpa.h"
#include "rsn_supp/wpa_i.h"
#include "common/eapol_common.h"
#include "common/ieee802_11_defs.h"
#include "pmksa_cache.h"
#ifdef IEEE8021X_EAPOL
static const int pmksa_cache_max_entries = 10;
struct rsn_pmksa_cache {
struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */
int pmksa_count; /* number of entries in PMKSA cache */
struct wpa_sm *sm; /* TODO: get rid of this reference(?) */
void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx,
enum pmksa_free_reason reason);
void *ctx;
};
//static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
{
bin_clear_free(entry, sizeof(*entry));
}
static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry,
enum pmksa_free_reason reason)
{
//wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid);
pmksa->pmksa_count--;
pmksa->free_cb(entry, pmksa->ctx, reason);
_pmksa_cache_free_entry(entry);
}
#if 0
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
{
struct rsn_pmksa_cache *pmksa = eloop_ctx;
struct os_reltime now;
os_get_reltime(&now);
while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
pmksa->pmksa = entry->next;
wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
MACSTR, MAC2STR(entry->aa));
pmksa_cache_free_entry(pmksa, entry, PMKSA_EXPIRE);
}
pmksa_cache_set_expiration(pmksa);
}
static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx)
{
struct rsn_pmksa_cache *pmksa = eloop_ctx;
pmksa->sm->cur_pmksa = NULL;
eapol_sm_request_reauth(pmksa->sm->eapol);
}
static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
{
int sec;
struct rsn_pmksa_cache_entry *entry;
struct os_reltime now;
eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL);
if (pmksa->pmksa == NULL)
return;
os_get_reltime(&now);
sec = pmksa->pmksa->expiration - now.sec;
if (sec < 0)
sec = 0;
eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa :
pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL);
if (entry) {
sec = pmksa->pmksa->reauth_time - now.sec;
if (sec < 0)
sec = 0;
eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa,
NULL);
}
}
#endif
/**
* pmksa_cache_add - Add a PMKSA cache entry
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @pmk: The new pairwise master key
* @pmk_len: PMK length in bytes, usually PMK_LEN (32)
* @kck: Key confirmation key or %NULL if not yet derived
* @kck_len: KCK length in bytes
* @aa: Authenticator address
* @spa: Supplicant address
* @network_ctx: Network configuration context for this PMK
* @akmp: WPA_KEY_MGMT_* used in key derivation
* Returns: Pointer to the added PMKSA cache entry or %NULL on error
*
* This function create a PMKSA entry for a new PMK and adds it to the PMKSA
* cache. If an old entry is already in the cache for the same Authenticator,
* this entry will be replaced with the new entry. PMKID will be calculated
* based on the PMK and the driver interface is notified of the new PMKID.
*/
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
{
struct rsn_pmksa_cache_entry *entry, *pos, *prev;
//struct os_reltime now;
if (pmk_len > PMK_LEN)
return NULL;
if (wpa_key_mgmt_suite_b(akmp) && !kck)
return NULL;
entry = os_zalloc(sizeof(*entry));
if (entry == NULL)
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
wpa_key_mgmt_sha256(akmp));
//os_get_reltime(&now);
//entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
/*entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;*/
entry->akmp = akmp;
os_memcpy(entry->aa, aa, ETH_ALEN);
entry->network_ctx = network_ctx;
/* Replace an old entry for the same Authenticator (if found) with the
* new entry */
pos = pmksa->pmksa;
prev = NULL;
while (pos) {
if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
if (pos->pmk_len == pmk_len &&
os_memcmp_const(pos->pmk, pmk, pmk_len) == 0 &&
os_memcmp_const(pos->pmkid, entry->pmkid,
PMKID_LEN) == 0) {
wpa_printf(MSG_DEBUG, "WPA: reusing previous "
"PMKSA entry");
os_free(entry);
return pos;
}
if (prev == NULL)
pmksa->pmksa = pos->next;
else
prev->next = pos->next;
/*
* If OKC is used, there may be other PMKSA cache
* entries based on the same PMK. These needs to be
* flushed so that a new entry can be created based on
* the new PMK. Only clear other entries if they have a
* matching PMK and this PMK has been used successfully
* with the current AP, i.e., if opportunistic flag has
* been cleared in wpa_supplicant_key_neg_complete().
*/
wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
"the current AP and any PMKSA cache entry "
"that was based on the old PMK");
if (!pos->opportunistic)
pmksa_cache_flush(pmksa, network_ctx, pos->pmk,
pos->pmk_len);
pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
break;
}
prev = pos;
pos = pos->next;
}
if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
/* Remove the oldest entry to make room for the new entry */
pos = pmksa->pmksa;
if (pos == pmksa->sm->cur_pmksa) {
/*
* Never remove the current PMKSA cache entry, since
* it's in use, and removing it triggers a needless
* deauthentication.
*/
pos = pos->next;
pmksa->pmksa->next = pos ? pos->next : NULL;
} else
pmksa->pmksa = pos->next;
if (pos) {
wpa_printf(MSG_DEBUG, "RSN: removed the oldest idle "
"PMKSA cache entry (for " MACSTR ") to "
"make room for new one",
MAC2STR(pos->aa));
pmksa_cache_free_entry(pmksa, pos, PMKSA_FREE);
}
}
/* Add the new entry; order by expiration time */
pos = pmksa->pmksa;
prev = NULL;
while (pos) {
if (pos->expiration > entry->expiration)
break;
prev = pos;
pos = pos->next;
}
if (prev == NULL) {
entry->next = pmksa->pmksa;
pmksa->pmksa = entry;
//pmksa_cache_set_expiration(pmksa);
} else {
entry->next = prev->next;
prev->next = entry;
}
pmksa->pmksa_count++;
wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR
" network_ctx=%p", MAC2STR(entry->aa), network_ctx);
//wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid);
return entry;
}
/**
* pmksa_cache_flush - Flush PMKSA cache entries for a specific network
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @network_ctx: Network configuration context or %NULL to flush all entries
* @pmk: PMK to match for or %NYLL to match all PMKs
* @pmk_len: PMK length
*/
void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
const u8 *pmk, size_t pmk_len)
{
struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
int removed = 0;
entry = pmksa->pmksa;
while (entry) {
if ((entry->network_ctx == network_ctx ||
network_ctx == NULL) &&
(pmk == NULL ||
(pmk_len == entry->pmk_len &&
os_memcmp(pmk, entry->pmk, pmk_len) == 0))) {
wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
"for " MACSTR, MAC2STR(entry->aa));
if (prev)
prev->next = entry->next;
else
pmksa->pmksa = entry->next;
tmp = entry;
entry = entry->next;
pmksa_cache_free_entry(pmksa, tmp, PMKSA_FREE);
removed++;
} else {
prev = entry;
entry = entry->next;
}
}
/*if (removed)
pmksa_cache_set_expiration(pmksa);*/
}
/**
* pmksa_cache_deinit - Free all entries in PMKSA cache
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
*/
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
{
struct rsn_pmksa_cache_entry *entry, *prev;
if (pmksa == NULL)
return;
entry = pmksa->pmksa;
pmksa->pmksa = NULL;
while (entry) {
prev = entry;
entry = entry->next;
os_free(prev);
}
//pmksa_cache_set_expiration(pmksa);
os_free(pmksa);
}
/**
* pmksa_cache_get - Fetch a PMKSA cache entry
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @aa: Authenticator address or %NULL to match any
* @pmkid: PMKID or %NULL to match any
* @network_ctx: Network context or %NULL to match any
* Returns: Pointer to PMKSA cache entry or %NULL if no match was found
*/
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
const u8 *aa, const u8 *pmkid,
const void *network_ctx)
{
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
while (entry) {
if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
(pmkid == NULL ||
os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) &&
(network_ctx == NULL || network_ctx == entry->network_ctx))
return entry;
entry = entry->next;
}
return NULL;
}
static struct rsn_pmksa_cache_entry *
pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
const struct rsn_pmksa_cache_entry *old_entry,
const u8 *aa)
{
struct rsn_pmksa_cache_entry *new_entry;
new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
NULL, 0,
aa, pmksa->sm->own_addr,
old_entry->network_ctx, old_entry->akmp);
if (new_entry == NULL)
return NULL;
/* TODO: reorder entries based on expiration time? */
new_entry->expiration = old_entry->expiration;
new_entry->opportunistic = 1;
return new_entry;
}
/**
* pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @network_ctx: Network configuration context
* @aa: Authenticator address for the new AP
* Returns: Pointer to a new PMKSA cache entry or %NULL if not available
*
* Try to create a new PMKSA cache entry opportunistically by guessing that the
* new AP is sharing the same PMK as another AP that has the same SSID and has
* already an entry in PMKSA cache.
*/
struct rsn_pmksa_cache_entry *
pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
const u8 *aa)
{
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
wpa_printf(MSG_DEBUG, "RSN: Consider " MACSTR " for OKC", MAC2STR(aa));
if (network_ctx == NULL)
return NULL;
while (entry) {
if (entry->network_ctx == network_ctx) {
entry = pmksa_cache_clone_entry(pmksa, entry, aa);
if (entry) {
wpa_printf(MSG_DEBUG, "RSN: added "
"opportunistic PMKSA cache entry "
"for " MACSTR, MAC2STR(aa));
}
return entry;
}
entry = entry->next;
}
return NULL;
}
/**
* pmksa_cache_get_current - Get the current used PMKSA entry
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* Returns: Pointer to the current PMKSA cache entry or %NULL if not available
*/
struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm)
{
if (sm == NULL)
return NULL;
return sm->cur_pmksa;
}
/**
* pmksa_cache_clear_current - Clear the current PMKSA entry selection
* @sm: Pointer to WPA state machine data from wpa_sm_init()
*/
void pmksa_cache_clear_current(struct wpa_sm *sm)
{
if (sm == NULL)
return;
sm->cur_pmksa = NULL;
}
/**
* pmksa_cache_set_current - Set the current PMKSA entry selection
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @pmkid: PMKID for selecting PMKSA or %NULL if not used
* @bssid: BSSID for PMKSA or %NULL if not used
* @network_ctx: Network configuration context
* @try_opportunistic: Whether to allow opportunistic PMKSA caching
* Returns: 0 if PMKSA was found or -1 if no matching entry was found
*/
int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
const u8 *bssid, void *network_ctx,
int try_opportunistic)
{
struct rsn_pmksa_cache *pmksa = sm->pmksa;
wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p "
"try_opportunistic=%d", network_ctx, try_opportunistic);
if (pmkid)
wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID",
pmkid, PMKID_LEN);
if (bssid)
wpa_printf(MSG_DEBUG, "RSN: Search for BSSID " MACSTR,
MAC2STR(bssid));
sm->cur_pmksa = NULL;
if (pmkid)
sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid,
network_ctx);
if (sm->cur_pmksa == NULL && bssid)
sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL,
network_ctx);
if (sm->cur_pmksa == NULL && try_opportunistic && bssid)
sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa,
network_ctx,
bssid);
if (sm->cur_pmksa) {
wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID",
sm->cur_pmksa->pmkid, PMKID_LEN);
return 0;
}
wpa_printf(MSG_DEBUG, "RSN: No PMKSA cache entry found");
return -1;
}
/**
* pmksa_cache_list - Dump text list of entries in PMKSA cache
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @buf: Buffer for the list
* @len: Length of the buffer
* Returns: number of bytes written to buffer
*
* This function is used to generate a text format representation of the
* current PMKSA cache contents for the ctrl_iface PMKSA command.
*/
int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
{
int i, ret;
char *pos = buf;
struct rsn_pmksa_cache_entry *entry;
//struct os_reltime now;
//os_get_reltime(&now);
ret = os_snprintf(pos, buf + len - pos,
"Index / AA / PMKID / expiration (in seconds) / "
"opportunistic\n");
if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;
i = 0;
entry = pmksa->pmksa;
while (entry) {
i++;
ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
i, MAC2STR(entry->aa));
if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;
pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
PMKID_LEN);
ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
(int) (entry->expiration),// - now.sec),
entry->opportunistic);
if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;
entry = entry->next;
}
return pos - buf;
}
/**
* pmksa_cache_init - Initialize PMKSA cache
* @free_cb: Callback function to be called when a PMKSA cache entry is freed
* @ctx: Context pointer for free_cb function
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* Returns: Pointer to PMKSA cache data or %NULL on failure
*/
struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
void *ctx, enum pmksa_free_reason reason),
void *ctx, struct wpa_sm *sm)
{
struct rsn_pmksa_cache *pmksa;
pmksa = os_zalloc(sizeof(*pmksa));
if (pmksa) {
pmksa->free_cb = free_cb;
pmksa->ctx = ctx;
pmksa->sm = sm;
}
return pmksa;
}
#endif /* IEEE8021X_EAPOL */

View file

@ -0,0 +1,134 @@
/*
* wpa_supplicant - WPA2/RSN PMKSA cache functions
* Copyright (c) 2003-2009, 2011-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef PMKSA_CACHE_H
#define PMKSA_CACHE_H
/**
* struct rsn_pmksa_cache_entry - PMKSA cache entry
*/
struct rsn_pmksa_cache_entry {
struct rsn_pmksa_cache_entry *next;
u8 pmkid[PMKID_LEN];
u8 pmk[PMK_LEN];
size_t pmk_len;
os_time_t expiration;
int akmp; /* WPA_KEY_MGMT_* */
u8 aa[ETH_ALEN];
os_time_t reauth_time;
/**
* network_ctx - Network configuration context
*
* This field is only used to match PMKSA cache entries to a specific
* network configuration (e.g., a specific SSID and security policy).
* This can be a pointer to the configuration entry, but PMKSA caching
* code does not dereference the value and this could be any kind of
* identifier.
*/
void *network_ctx;
int opportunistic;
};
struct rsn_pmksa_cache;
enum pmksa_free_reason {
PMKSA_FREE,
PMKSA_REPLACE,
PMKSA_EXPIRE,
};
#ifdef IEEE8021X_EAPOL
struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
void *ctx, enum pmksa_free_reason reason),
void *ctx, struct wpa_sm *sm);
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
const u8 *aa, const u8 *pmkid,
const void *network_ctx);
int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
void pmksa_cache_clear_current(struct wpa_sm *sm);
int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
const u8 *bssid, void *network_ctx,
int try_opportunistic);
struct rsn_pmksa_cache_entry *
pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
void *network_ctx, const u8 *aa);
void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
const u8 *pmk, size_t pmk_len);
#else /* IEEE8021X_EAPOL */
static inline struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
void *ctx, enum pmksa_free_reason reason),
void *ctx, struct wpa_sm *sm)
{
return (void *) -1;
}
static inline void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
{
}
static inline struct rsn_pmksa_cache_entry *
pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid,
const void *network_ctx)
{
return NULL;
}
static inline struct rsn_pmksa_cache_entry *
pmksa_cache_get_current(struct wpa_sm *sm)
{
return NULL;
}
static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf,
size_t len)
{
return -1;
}
static inline struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
{
return NULL;
}
static inline void pmksa_cache_clear_current(struct wpa_sm *sm)
{
}
static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
const u8 *bssid,
void *network_ctx,
int try_opportunistic)
{
return -1;
}
static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
void *network_ctx,
const u8 *pmk, size_t pmk_len)
{
}
#endif /* IEEE8021X_EAPOL */
#endif /* PMKSA_CACHE_H */

View file

@ -16,6 +16,7 @@
#include "utils/common.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/pmksa_cache.h"
#include "rsn_supp/wpa_i.h"
#include "common/eapol_common.h"
#include "common/ieee802_11_defs.h"
@ -45,7 +46,7 @@
/* fix buf for tx for now */
#define WPA_TX_MSG_BUFF_MAXLEN 200
#define ASSOC_IE_LEN 24
#define ASSOC_IE_LEN 24 + 2 + PMKID_LEN
u8 assoc_ie_buf[ASSOC_IE_LEN+2];
void set_assoc_ie(u8 * assoc_buf);
@ -60,6 +61,7 @@ int wpa_sm_get_key(uint8_t *ifx, int *alg, u8 *addr, int *key_idx, u8 *key, size
void wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len);
void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm);
static inline enum wpa_states wpa_sm_get_state(struct wpa_sm *sm)
{
return sm->wpa_state;;
@ -226,7 +228,7 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
reply->key_mic : NULL);
wpa_sm_free_eapol(rbuf);
}
/*
int wpa_supplicant_get_pmk(struct wpa_sm *sm)
{
if(sm->pmk_len >0) {
@ -235,6 +237,178 @@ int wpa_supplicant_get_pmk(struct wpa_sm *sm)
return 1;
}
}
*/
static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
void *ctx, enum pmksa_free_reason reason)
{
struct wpa_sm *sm = ctx;
int deauth = 0;
wpa_printf( MSG_DEBUG, "RSN: PMKSA cache entry free_cb: "
MACSTR " reason=%d", MAC2STR(entry->aa), reason);
if (sm->cur_pmksa == entry) {
wpa_printf( MSG_DEBUG,
"RSN: %s current PMKSA entry",
reason == PMKSA_REPLACE ? "replaced" : "removed");
pmksa_cache_clear_current(sm);
/*
* If an entry is simply being replaced, there's no need to
* deauthenticate because it will be immediately re-added.
* This happens when EAP authentication is completed again
* (reauth or failed PMKSA caching attempt).
* */
if (reason != PMKSA_REPLACE)
deauth = 1;
}
if (reason == PMKSA_EXPIRE &&
(sm->pmk_len == entry->pmk_len &&
os_memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0)) {
wpa_printf( MSG_DEBUG,
"RSN: deauthenticating due to expired PMK");
pmksa_cache_clear_current(sm);
deauth = 1;
}
if (deauth) {
os_memset(sm->pmk, 0, sizeof(sm->pmk));
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
}
static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
const unsigned char *src_addr,
const u8 *pmkid)
{
int abort_cached = 0;
if (pmkid && !sm->cur_pmksa) {
/* When using drivers that generate RSN IE, wpa_supplicant may
* not have enough time to get the association information
* event before receiving this 1/4 message, so try to find a
* matching PMKSA cache entry here. */
sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid,
NULL);
if (sm->cur_pmksa) {
wpa_printf(MSG_DEBUG,
"RSN: found matching PMKID from PMKSA cache");
} else {
wpa_printf( MSG_DEBUG,
"RSN: no matching PMKID found");
abort_cached = 1;
}
}
if (pmkid && sm->cur_pmksa &&
os_memcmp_const(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN);
wpa_sm_set_pmk_from_pmksa(sm);
wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache",
sm->pmk, sm->pmk_len);
//eapol_sm_notify_cached(sm->eapol);
#ifdef CONFIG_IEEE80211R
sm->xxkey_len = 0;
#endif /* CONFIG_IEEE80211R */
} else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) {
int res = 0, pmk_len;
pmk_len = PMK_LEN;
/* For ESP_SUPPLICANT this is already set using wpa_set_pmk*/
//res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN);
if(!sm->pmk_len) {
res = -1;
}
if (res == 0) {
struct rsn_pmksa_cache_entry *sa = NULL;
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
"machines", sm->pmk, pmk_len);
sm->pmk_len = pmk_len;
//wpa_supplicant_key_mgmt_set_pmk(sm);
if (sm->proto == WPA_PROTO_RSN &&
!wpa_key_mgmt_suite_b(sm->key_mgmt) &&
!wpa_key_mgmt_ft(sm->key_mgmt)) {
sa = pmksa_cache_add(sm->pmksa,
sm->pmk, pmk_len,
NULL, 0,
src_addr, sm->own_addr,
sm->network_ctx,
sm->key_mgmt);
}
if (!sm->cur_pmksa && pmkid &&
pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL))
{
wpa_printf( MSG_DEBUG,
"RSN: the new PMK matches with the "
"PMKID");
abort_cached = 0;
} else if (sa && !sm->cur_pmksa && pmkid) {
/*
* It looks like the authentication server
* derived mismatching MSK. This should not
* really happen, but bugs happen.. There is not
* much we can do here without knowing what
* exactly caused the server to misbehave.
*/
wpa_printf( MSG_INFO,
"RSN: PMKID mismatch - authentication server may have derived different MSK?!");
return -1;
}
if (!sm->cur_pmksa)
sm->cur_pmksa = sa;
} else {
wpa_printf( MSG_WARNING,
"WPA: Failed to get master session key from "
"EAPOL state machines - key handshake "
"aborted");
if (sm->cur_pmksa) {
wpa_printf( MSG_DEBUG,
"RSN: Cancelled PMKSA caching "
"attempt");
sm->cur_pmksa = NULL;
abort_cached = 1;
} else if (!abort_cached) {
return -1;
}
}
}
if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) &&
!wpa_key_mgmt_suite_b(sm->key_mgmt) &&
!wpa_key_mgmt_ft(sm->key_mgmt) && sm->key_mgmt != WPA_KEY_MGMT_OSEN)
{
/* Send EAPOL-Start to trigger full EAP authentication. */
u8 *buf;
size_t buflen;
wpa_printf( MSG_DEBUG,
"RSN: no PMKSA entry found - trigger "
"full EAP authentication");
buf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START,
NULL, 0, &buflen, NULL);
if (buf) {
wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL,
buf, buflen);
os_free(buf);
return -2;
}
return -1;
}
return 0;
}
/**
* wpa_supplicant_send_2_of_4 - Send message 2 of WPA/RSN 4-Way Handshake
@ -342,9 +516,9 @@ void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
}
}
#endif /* CONFIG_NO_WPA2 */
res = wpa_supplicant_get_pmk(sm);
if (res == -2) {
res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
if (res == -2) {
#ifdef DEBUG_PRINT
wpa_printf(MSG_DEBUG, "RSN: Do not reply to msg 1/4 - "
"requesting full EAP authentication");
@ -1699,8 +1873,65 @@ void wpa_sm_set_state(enum wpa_states state)
sm->wpa_state= state;
}
/**
* wpa_sm_set_pmk - Set PMK
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @pmk: The new PMK
* @pmk_len: The length of the new PMK in bytes
* @bssid: AA to add into PMKSA cache or %NULL to not cache the PMK
*
* Configure the PMK for WPA state machine.
*/
void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
const u8 *bssid)
{
if (sm == NULL)
return;
sm->pmk_len = pmk_len;
os_memcpy(sm->pmk, pmk, pmk_len);
#ifdef CONFIG_IEEE80211R
/* Set XXKey to be PSK for FT key derivation */
sm->xxkey_len = pmk_len;
os_memcpy(sm->xxkey, pmk, pmk_len);
#endif /* CONFIG_IEEE80211R */
if (bssid) {
pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL, 0,
bssid, sm->own_addr,
sm->network_ctx, sm->key_mgmt);
}
}
/**
* wpa_sm_set_pmk_from_pmksa - Set PMK based on the current PMKSA
* @sm: Pointer to WPA state machine data from wpa_sm_init()
*
* Take the PMK from the current PMKSA into use. If no PMKSA is active, the PMK
* will be cleared.
*/
void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
{
if (sm == NULL)
return;
if (sm->cur_pmksa) {
sm->pmk_len = sm->cur_pmksa->pmk_len;
os_memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len);
} else {
sm->pmk_len = PMK_LEN;
os_memset(sm->pmk, 0, PMK_LEN);
}
}
#ifdef ESP_SUPPLICANT
void wpa_register(char * payload, WPA_SEND_FUNC snd_func,
bool wpa_sm_init(char * payload, WPA_SEND_FUNC snd_func,
WPA_SET_ASSOC_IE set_assoc_ie_func, WPA_INSTALL_KEY ppinstallkey, WPA_GET_KEY ppgetkey, WPA_DEAUTH_FUNC wpa_deauth,
WPA_NEG_COMPLETE wpa_neg_complete)
{
@ -1716,8 +1947,26 @@ void wpa_register(char * payload, WPA_SEND_FUNC snd_func,
sm->key_entry_valid = 0;
sm->key_install = false;
wpa_sm_set_state(WPA_INACTIVE);
sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb, sm, sm);
if (sm->pmksa == NULL) {
wpa_printf(MSG_ERROR,
"RSN: PMKSA cache initialization failed");
return false;
}
return true;
}
/**
* * wpa_sm_deinit - Deinitialize WPA state machine
* */
void wpa_sm_deinit(void)
{
struct wpa_sm *sm = &gWpaSm;
pmksa_cache_deinit(sm->pmksa);
}
void wpa_set_profile(u32 wpa_proto, u8 auth_mode)
{
struct wpa_sm *sm = &gWpaSm;
@ -1751,8 +2000,15 @@ wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, cha
memcpy(sm->own_addr, macddr, ETH_ALEN);
memcpy(sm->bssid, bssid, ETH_ALEN);
sm->ap_notify_completed_rsne = esp_wifi_sta_is_ap_notify_completed_rsne_internal();
if (esp_wifi_sta_prof_is_wpa2_internal()
&& esp_wifi_sta_get_prof_authmode_internal() == WPA2_AUTH_ENT) {
pmksa_cache_set_current(sm, NULL, (const u8*) bssid, 0, 0);
wpa_sm_set_pmk_from_pmksa(sm);
}
set_assoc_ie(assoc_ie_buf); /* use static buffer */
wpa_gen_wpa_ie(sm, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len); //TODO: NEED TO DEBUG!!
wpa_set_passphrase(passphrase, ssid, ssid_len);
}
@ -1790,8 +2046,8 @@ wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len)
/* TODO nothing */
} else {
memcpy(sm->pmk, esp_wifi_sta_get_ap_info_prof_pmk_internal(), PMK_LEN);
sm->pmk_len = PMK_LEN;
}
sm->pmk_len = PMK_LEN;
}
void
@ -1971,5 +2227,10 @@ bool wpa_sta_in_4way_handshake(void)
return false;
}
bool wpa_sta_is_cur_pmksa_set(void) {
struct wpa_sm *sm = &gWpaSm;
return (pmksa_cache_get_current(sm) != NULL);
}
#endif // ESP_SUPPLICANT

View file

@ -28,6 +28,7 @@
struct wpa_sm;
int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len);
bool wpa_sta_is_cur_pmksa_set(void);
bool wpa_sta_in_4way_handshake(void);
#define WPA_ASSERT assert

View file

@ -41,11 +41,14 @@ struct wpa_sm {
u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
int rx_replay_counter_set;
u8 request_counter[WPA_REPLAY_COUNTER_LEN];
struct rsn_pmksa_cache *pmksa; /* PMKSA cache */
struct rsn_pmksa_cache_entry *cur_pmksa; /* current PMKSA entry */
unsigned int pairwise_cipher;
unsigned int group_cipher;
unsigned int key_mgmt;
unsigned int mgmt_group_cipher;
void *network_ctx;
int rsn_enabled; /* Whether RSN is enabled in configuration */
@ -147,12 +150,14 @@ typedef void (*WPA_DEAUTH_FUNC)(u8 reason_code);
typedef void (*WPA_NEG_COMPLETE)();
void wpa_register(char * payload, WPA_SEND_FUNC snd_func, \
WPA_SET_ASSOC_IE set_assoc_ie_func, \
WPA_INSTALL_KEY ppinstallkey, \
WPA_GET_KEY ppgetkey, \
WPA_DEAUTH_FUNC wpa_deauth, \
WPA_NEG_COMPLETE wpa_neg_complete);
bool wpa_sm_init(char * payload, WPA_SEND_FUNC snd_func, \
WPA_SET_ASSOC_IE set_assoc_ie_func, \
WPA_INSTALL_KEY ppinstallkey, \
WPA_GET_KEY ppgetkey, \
WPA_DEAUTH_FUNC wpa_deauth, \
WPA_NEG_COMPLETE wpa_neg_complete);
void wpa_sm_deinit(void);
void eapol_txcb(void *eb);

View file

@ -19,6 +19,7 @@
#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
@ -38,6 +39,246 @@ int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
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 */
} 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->mfp)
capab |= WPA_CAPABILITY_MFPC;
if (sm->mfp == 2)
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) {
/* 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
@ -146,226 +387,5 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
}
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;
/* 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 */
} 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->mfp)
capab |= WPA_CAPABILITY_MFPC;
if (sm->mfp == 2)
capab |= WPA_CAPABILITY_MFPR;
#endif /* CONFIG_IEEE80211W */
WPA_PUT_LE16(pos, capab);
pos += 2;
#ifdef CONFIG_IEEE80211W
if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
if (!sm->cur_pmksa) {
/* 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);
}
#endif // ESP_SUPPLICANT

View file

@ -2,14 +2,8 @@
* 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.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -99,68 +93,263 @@ void wpa_get_ntp_timestamp(u8 *buf)
usec = now.usec;
usec = 4295 * usec - (usec >> 5) - (usec >> 9);
tmp = host_to_be32(sec);
memcpy(buf, (u8 *) &tmp, 4);
os_memcpy(buf, (u8 *) &tmp, 4);
tmp = host_to_be32(usec);
memcpy(buf + 4, (u8 *) &tmp, 4);
os_memcpy(buf + 4, (u8 *) &tmp, 4);
}
void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
{
char *end = txt + maxlen;
size_t i;
for (i = 0; i < len; i++) {
if (txt + 4 >= end)
break;
switch (data[i]) {
case '\"':
*txt++ = '\\';
*txt++ = '\"';
break;
case '\\':
*txt++ = '\\';
*txt++ = '\\';
break;
case '\033':
*txt++ = '\\';
*txt++ = 'e';
break;
case '\n':
*txt++ = '\\';
*txt++ = 'n';
break;
case '\r':
*txt++ = '\\';
*txt++ = 'r';
break;
case '\t':
*txt++ = '\\';
*txt++ = 't';
break;
default:
if (data[i] >= 32 && data[i] <= 127) {
*txt++ = data[i];
} else {
txt += os_snprintf(txt, end - txt, "\\x%02x",
data[i]);
}
break;
}
}
*txt = '\0';
}
size_t printf_decode(u8 *buf, size_t maxlen, const char *str)
{
const char *pos = str;
size_t len = 0;
int val;
while (*pos) {
if (len + 1 >= maxlen)
break;
switch (*pos) {
case '\\':
pos++;
switch (*pos) {
case '\\':
buf[len++] = '\\';
pos++;
break;
case '"':
buf[len++] = '"';
pos++;
break;
case 'n':
buf[len++] = '\n';
pos++;
break;
case 'r':
buf[len++] = '\r';
pos++;
break;
case 't':
buf[len++] = '\t';
pos++;
break;
case 'e':
buf[len++] = '\033';
pos++;
break;
case 'x':
pos++;
val = hex2byte(pos);
if (val < 0) {
val = hex2num(*pos);
if (val < 0)
break;
buf[len++] = val;
pos++;
} else {
buf[len++] = val;
pos += 2;
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
val = *pos++ - '0';
if (*pos >= '0' && *pos <= '7')
val = val * 8 + (*pos++ - '0');
if (*pos >= '0' && *pos <= '7')
val = val * 8 + (*pos++ - '0');
buf[len++] = val;
break;
default:
break;
}
break;
default:
buf[len++] = *pos++;
break;
}
}
if (maxlen > len)
buf[len] = '\0';
return len;
}
char * wpa_config_parse_string(const char *value, size_t *len)
{
if (*value == '"' && (strlen(value) == 7 || strlen(value) == 15)) {
if (*value == '"') {
const char *pos;
char *str;
value++;
pos = (char *)strrchr(value, '"');
if (pos == NULL)
pos = os_strrchr(value, '"');
if (pos == NULL || pos[1] != '\0')
return NULL;
*len = pos - value;
str = (char *)os_malloc(*len + 1);
str = dup_binstr(value, *len);
if (str == NULL)
return NULL;
memcpy(str, value, *len);
str[*len] = '\0';
return str;
} else if (*value == 'P' && value[1] == '"') {
const char *pos;
char *tstr, *str;
size_t tlen;
value += 2;
pos = os_strrchr(value, '"');
if (pos == NULL || pos[1] != '\0')
return NULL;
tlen = pos - value;
tstr = dup_binstr(value, tlen);
if (tstr == NULL)
return NULL;
str = os_malloc(tlen + 1);
if (str == NULL) {
os_free(tstr);
return NULL;
}
*len = printf_decode((u8 *) str, tlen + 1, tstr);
os_free(tstr);
return str;
} else {
u8 *str;
size_t tlen, hlen = strlen(value);
if (hlen == 5 || hlen == 13) {
*len = hlen;
str = (u8 *)os_malloc(*len + 1);
if (str == NULL) {
return NULL;
}
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 {
size_t tlen, hlen = os_strlen(value);
if (hlen & 1)
return NULL;
tlen = hlen / 2;
str = os_malloc(tlen + 1);
if (str == NULL)
return NULL;
if (hexstr2bin(value, str, tlen)) {
os_free(str);
return NULL;
}
str[tlen] = '\0';
*len = tlen;
return (char *) str;
}
}
char * dup_binstr(const void *src, size_t len)
int is_hex(const u8 *data, size_t len)
{
char *res;
size_t i;
if (src == NULL)
return NULL;
res = os_malloc(len + 1);
if (res == NULL)
return NULL;
memcpy(res, src, len);
res[len] = '\0';
return res;
for (i = 0; i < len; i++) {
if (data[i] < 32 || data[i] >= 127)
return 1;
}
return 0;
}
size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len)
{
size_t len = 0;
os_memset(res, 0, res_len);
if (src1) {
if (src1_len >= res_len) {
os_memcpy(res, src1, res_len);
return res_len;
}
os_memcpy(res, src1, src1_len);
len += src1_len;
}
if (src2) {
if (len + src2_len >= res_len) {
os_memcpy(res + len, src2, res_len - len);
return res_len;
}
os_memcpy(res + len, src2, src2_len);
len += src2_len;
}
return len;
}
char * 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 bin_clear_free(void *bin, size_t len)
{
if (bin) {
os_memset(bin, 0, len);
os_free(bin);
}
}