mirror of
https://github.com/espressif/esp-idf.git
synced 2024-09-20 00:36:01 -04:00
Merge branch 'feature/support_eap_fast_release_v4.4' into 'release/v4.4'
Add support for EAP-FAST authentication (backport v4.4) See merge request espressif/esp-idf!16279
This commit is contained in:
commit
d483bd9518
@ -32,6 +32,9 @@ set(srcs "port/os_xtensa.c"
|
||||
"src/eap_peer/eap_tls_common.c"
|
||||
"src/eap_peer/eap_ttls.c"
|
||||
"src/eap_peer/mschapv2.c"
|
||||
"src/eap_peer/eap_fast.c"
|
||||
"src/eap_peer/eap_fast_common.c"
|
||||
"src/eap_peer/eap_fast_pac.c"
|
||||
"src/rsn_supp/pmksa_cache.c"
|
||||
"src/rsn_supp/wpa.c"
|
||||
"src/rsn_supp/wpa_ie.c"
|
||||
@ -139,6 +142,7 @@ else()
|
||||
"src/crypto/sha1-internal.c"
|
||||
"src/crypto/sha1-pbkdf2.c"
|
||||
"src/crypto/sha1.c"
|
||||
"src/crypto/sha1-tprf.c"
|
||||
"src/crypto/sha256-internal.c"
|
||||
"src/crypto/sha384-internal.c"
|
||||
"src/crypto/sha512-internal.c"
|
||||
@ -179,6 +183,7 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE
|
||||
EAP_TTLS
|
||||
EAP_TLS
|
||||
EAP_PEAP
|
||||
EAP_FAST
|
||||
USE_WPA2_TASK
|
||||
CONFIG_WPS2
|
||||
CONFIG_WPS_PIN
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -17,7 +17,13 @@ typedef enum {
|
||||
ESP_EAP_TTLS_PHASE2_MSCHAP,
|
||||
ESP_EAP_TTLS_PHASE2_PAP,
|
||||
ESP_EAP_TTLS_PHASE2_CHAP
|
||||
} esp_eap_ttls_phase2_types ;
|
||||
} esp_eap_ttls_phase2_types;
|
||||
|
||||
typedef struct {
|
||||
int fast_provisioning;
|
||||
int fast_max_pac_list_len;
|
||||
bool fast_pac_format_binary;
|
||||
} esp_eap_fast_config;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -211,6 +217,35 @@ esp_err_t esp_wifi_sta_wpa2_ent_set_ttls_phase2_method(esp_eap_ttls_phase2_types
|
||||
*/
|
||||
esp_err_t esp_wifi_sta_wpa2_set_suiteb_192bit_certification(bool enable);
|
||||
|
||||
/**
|
||||
* @brief Set client pac file
|
||||
*
|
||||
* @attention 1. For files read from the file system, length has to be decremented by 1 byte.
|
||||
* @attention 2. Disabling the WPA_MBEDTLS_CRYPTO config is required to use EAP-FAST.
|
||||
*
|
||||
* @param pac_file: pointer to the pac file
|
||||
* pac_file_len: length of the pac file
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_NO_MEM: fail(internal memory malloc fail)
|
||||
*/
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_pac_file(const unsigned char *pac_file, int pac_file_len);
|
||||
|
||||
/**
|
||||
* @brief Set Phase 1 parameters for EAP-FAST
|
||||
*
|
||||
* @attention 1. Disabling the WPA_MBEDTLS_CRYPTO config is required to use EAP-FAST.
|
||||
*
|
||||
* @param config: eap fast phase 1 configuration
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_INVALID_ARG: fail(out of bound arguments)
|
||||
* - ESP_ERR_NO_MEM: fail(internal memory malloc fail)
|
||||
*/
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_fast_phase1_params(esp_eap_fast_config config);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -43,6 +43,15 @@
|
||||
#define DATA_MUTEX_TAKE() xSemaphoreTakeRecursive(s_wpa2_data_lock,portMAX_DELAY)
|
||||
#define DATA_MUTEX_GIVE() xSemaphoreGiveRecursive(s_wpa2_data_lock)
|
||||
|
||||
//length of the string "fast_provisioning={0/1/2} "
|
||||
#define FAST_PROVISIONING_CONFIG_STR_LEN 20
|
||||
//length of the string "fast_max_pac_list_len=(int < 100) "
|
||||
#define FAST_MAX_PAC_LIST_CONFIG_STR_LEN 25
|
||||
//length of the string "fast_pac_format=binary"
|
||||
#define FAST_PAC_FORMAT_STR_LEN 22
|
||||
//Total
|
||||
#define PHASE1_PARAM_STRING_LEN FAST_PROVISIONING_CONFIG_STR_LEN + FAST_MAX_PAC_LIST_CONFIG_STR_LEN + FAST_PAC_FORMAT_STR_LEN
|
||||
|
||||
static void *s_wpa2_data_lock = NULL;
|
||||
|
||||
static struct eap_sm *gEapSm = NULL;
|
||||
@ -978,6 +987,9 @@ void esp_wifi_sta_wpa2_ent_clear_cert_key(void)
|
||||
g_wpa_private_key_len = 0;
|
||||
g_wpa_private_key_passwd = NULL;
|
||||
g_wpa_private_key_passwd_len = 0;
|
||||
os_free(g_wpa_pac_file);
|
||||
g_wpa_pac_file = NULL;
|
||||
g_wpa_pac_file_len = 0;
|
||||
}
|
||||
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_ca_cert(const unsigned char *ca_cert, int ca_cert_len)
|
||||
@ -1175,3 +1187,57 @@ esp_err_t esp_wifi_sta_wpa2_set_suiteb_192bit_certification(bool enable)
|
||||
return ESP_FAIL;
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_pac_file(const unsigned char *pac_file, int pac_file_len)
|
||||
{
|
||||
if (pac_file && pac_file_len > -1) {
|
||||
if (pac_file_len < 512) { // The file contains less than 1 pac and is to be rewritten later
|
||||
g_wpa_pac_file = (u8 *)os_zalloc(512);
|
||||
if (g_wpa_pac_file == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
g_wpa_pac_file_len = 0;
|
||||
} else { // The file contains pac data
|
||||
g_wpa_pac_file = (u8 *)os_zalloc(pac_file_len);
|
||||
if (g_wpa_pac_file == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
os_memcpy(g_wpa_pac_file, pac_file, pac_file_len);
|
||||
g_wpa_pac_file_len = pac_file_len;
|
||||
}
|
||||
} else {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_fast_phase1_params(esp_eap_fast_config config)
|
||||
{
|
||||
char config_for_supplicant[PHASE1_PARAM_STRING_LEN] = "";
|
||||
if ((config.fast_provisioning > -1) && (config.fast_provisioning <= 2)) {
|
||||
os_sprintf((char *) &config_for_supplicant, "fast_provisioning=%d ", config.fast_provisioning);
|
||||
} else {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (config.fast_max_pac_list_len && config.fast_max_pac_list_len < 100) {
|
||||
os_sprintf((char *) &config_for_supplicant + strlen(config_for_supplicant), "fast_max_pac_list_len=%d ", config.fast_max_pac_list_len);
|
||||
} else if (config.fast_max_pac_list_len >= 100) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (config.fast_pac_format_binary) {
|
||||
os_strcat((char *) &config_for_supplicant, (const char *) "fast_pac_format=binary");
|
||||
}
|
||||
|
||||
// Free the old buffer if it already exists
|
||||
if (g_wpa_phase1_options != NULL) {
|
||||
os_free(g_wpa_phase1_options);
|
||||
}
|
||||
g_wpa_phase1_options = (char *)os_zalloc(sizeof(config_for_supplicant));
|
||||
if (g_wpa_phase1_options == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
os_memcpy(g_wpa_phase1_options, &config_for_supplicant, sizeof(config_for_supplicant));
|
||||
return ESP_OK;
|
||||
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len);
|
||||
struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len);
|
||||
struct wpabuf * wpabuf_dup(const struct wpabuf *src);
|
||||
void wpabuf_free(struct wpabuf *buf);
|
||||
void wpabuf_clear_free(struct wpabuf *buf);
|
||||
void * wpabuf_put(struct wpabuf *buf, size_t len);
|
||||
struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
|
||||
struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len);
|
||||
|
@ -289,6 +289,9 @@ char * ets_strdup(const char *s);
|
||||
#ifndef os_strlcpy
|
||||
#define os_strlcpy(d, s, n) strlcpy((d), (s), (n))
|
||||
#endif
|
||||
#ifndef os_strcat
|
||||
#define os_strcat(d, s) strcat((d), (s))
|
||||
#endif
|
||||
|
||||
#ifndef os_snprintf
|
||||
#ifdef _MSC_VER
|
||||
@ -297,6 +300,9 @@ char * ets_strdup(const char *s);
|
||||
#define os_snprintf snprintf
|
||||
#endif
|
||||
#endif
|
||||
#ifndef os_sprintf
|
||||
#define os_sprintf sprintf
|
||||
#endif
|
||||
|
||||
static inline int os_snprintf_error(size_t size, int res)
|
||||
{
|
||||
|
@ -18,15 +18,6 @@
|
||||
#include "sae.h"
|
||||
#include "esp_wifi_crypto_types.h"
|
||||
|
||||
/*TBD Move the this api to proper files once they are taken out of lib*/
|
||||
void wpabuf_clear_free(struct wpabuf *buf)
|
||||
{
|
||||
if (buf) {
|
||||
os_memset(wpabuf_mhead(buf), 0, wpabuf_len(buf));
|
||||
wpabuf_free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
int sae_set_group(struct sae_data *sae, int group)
|
||||
{
|
||||
struct sae_temporary_data *tmp;
|
||||
|
72
components/wpa_supplicant/src/crypto/sha1-tprf.c
Normal file
72
components/wpa_supplicant/src/crypto/sha1-tprf.c
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* SHA1 T-PRF for EAP-FAST
|
||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "sha1.h"
|
||||
#include "crypto.h"
|
||||
|
||||
/**
|
||||
* sha1_t_prf - EAP-FAST Pseudo-Random Function (T-PRF)
|
||||
* @key: Key for PRF
|
||||
* @key_len: Length of the key in bytes
|
||||
* @label: A unique label for each purpose of the PRF
|
||||
* @seed: Seed value to bind into the key
|
||||
* @seed_len: Length of the seed
|
||||
* @buf: Buffer for the generated pseudo-random key
|
||||
* @buf_len: Number of bytes of key to generate
|
||||
* Returns: 0 on success, -1 of failure
|
||||
*
|
||||
* This function is used to derive new, cryptographically separate keys from a
|
||||
* given key for EAP-FAST. T-PRF is defined in RFC 4851, Section 5.5.
|
||||
*/
|
||||
int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
|
||||
const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len)
|
||||
{
|
||||
unsigned char counter = 0;
|
||||
size_t pos, plen;
|
||||
u8 hash[SHA1_MAC_LEN];
|
||||
size_t label_len = os_strlen(label);
|
||||
u8 output_len[2];
|
||||
const unsigned char *addr[5];
|
||||
size_t len[5];
|
||||
|
||||
addr[0] = hash;
|
||||
len[0] = 0;
|
||||
addr[1] = (unsigned char *) label;
|
||||
len[1] = label_len + 1;
|
||||
addr[2] = seed;
|
||||
len[2] = seed_len;
|
||||
addr[3] = output_len;
|
||||
len[3] = 2;
|
||||
addr[4] = &counter;
|
||||
len[4] = 1;
|
||||
|
||||
output_len[0] = (buf_len >> 8) & 0xff;
|
||||
output_len[1] = buf_len & 0xff;
|
||||
pos = 0;
|
||||
while (pos < buf_len) {
|
||||
counter++;
|
||||
plen = buf_len - pos;
|
||||
if (hmac_sha1_vector(key, key_len, 5, addr, len, hash))
|
||||
return -1;
|
||||
if (plen >= SHA1_MAC_LEN) {
|
||||
os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
|
||||
pos += SHA1_MAC_LEN;
|
||||
} else {
|
||||
os_memcpy(&buf[pos], hash, plen);
|
||||
break;
|
||||
}
|
||||
len[0] = SHA1_MAC_LEN;
|
||||
}
|
||||
|
||||
forced_memzero(hash, SHA1_MAC_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
@ -623,7 +623,8 @@ int tls_global_set_verify(void *tls_ctx, int check_crl)
|
||||
}
|
||||
|
||||
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
|
||||
int verify_peer)
|
||||
int verify_peer, unsigned int flags,
|
||||
const u8 *session_ctx, size_t session_ctx_len)
|
||||
{
|
||||
wpa_printf(MSG_INFO, "TLS: tls_connection_set_verify not supported");
|
||||
return -1;
|
||||
@ -928,11 +929,27 @@ static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
|
||||
}
|
||||
|
||||
int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *label, u8 *out, size_t out_len)
|
||||
const char *label, const u8 *context,
|
||||
size_t context_len, u8 *out, size_t out_len)
|
||||
{
|
||||
return tls_connection_prf(tls_ctx, conn, label, 0, out, out_len);
|
||||
}
|
||||
|
||||
int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
|
||||
u8 *out, size_t out_len)
|
||||
{
|
||||
wpa_printf(MSG_INFO, "TLS: tls_connection_get_eap_fast_key not supported, please unset mbedtls crypto and try again");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
|
||||
int ext_type, const u8 *data,
|
||||
size_t data_len)
|
||||
{
|
||||
wpa_printf(MSG_INFO, "TLS: tls_connection_client_hello_ext not supported, please unset mbedtls crypto and try again");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
|
||||
{
|
||||
if (conn->tls_io_data.in_data) {
|
||||
|
@ -213,6 +213,13 @@ int eap_peer_register_methods(void)
|
||||
ret = eap_peer_mschapv2_register();
|
||||
#endif
|
||||
|
||||
#ifndef USE_MBEDTLS_CRYPTO
|
||||
#ifdef EAP_FAST
|
||||
if (ret == 0)
|
||||
ret = eap_peer_fast_register();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef EAP_PEAP
|
||||
if (ret == 0)
|
||||
ret = eap_peer_peap_register();
|
||||
@ -435,11 +442,12 @@ int eap_peer_config_init(
|
||||
sm->config.client_cert = (u8 *)sm->blob[0].name;
|
||||
sm->config.private_key = (u8 *)sm->blob[1].name;
|
||||
sm->config.ca_cert = (u8 *)sm->blob[2].name;
|
||||
|
||||
sm->config.ca_path = NULL;
|
||||
|
||||
sm->config.fragment_size = 1400; /* fragment size */
|
||||
|
||||
sm->config.pac_file = (char *) "blob://";
|
||||
|
||||
/* anonymous identity */
|
||||
if (g_wpa_anonymous_identity && g_wpa_anonymous_identity_len > 0) {
|
||||
sm->config.anonymous_identity_len = g_wpa_anonymous_identity_len;
|
||||
@ -487,6 +495,10 @@ int eap_peer_config_init(
|
||||
sm->config.flags = TLS_CONN_SUITEB;
|
||||
}
|
||||
|
||||
/* To be used only for EAP-FAST */
|
||||
if (g_wpa_phase1_options) {
|
||||
sm->config.phase1 = g_wpa_phase1_options;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
@ -543,6 +555,17 @@ int eap_peer_blob_init(struct eap_sm *sm)
|
||||
sm->blob[2].data = g_wpa_ca_cert;
|
||||
}
|
||||
|
||||
if (g_wpa_pac_file && g_wpa_pac_file_len) {
|
||||
sm->blob[3].name = (char *)os_zalloc(sizeof(char) * 8);
|
||||
if (sm->blob[3].name == NULL) {
|
||||
ret = -2;
|
||||
goto _out;
|
||||
}
|
||||
os_strncpy(sm->blob[3].name, "blob://", 8);
|
||||
sm->blob[3].len = g_wpa_pac_file_len;
|
||||
sm->blob[3].data = g_wpa_pac_file;
|
||||
}
|
||||
|
||||
return 0;
|
||||
_out:
|
||||
for (i = 0; i < BLOB_NUM; i++) {
|
||||
@ -615,6 +638,37 @@ void eap_sm_request_identity(struct eap_sm *sm)
|
||||
eap_sm_request(sm, WPA_CTRL_REQ_EAP_IDENTITY, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_sm_request_password - Request password from user (ctrl_iface)
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
*
|
||||
* EAP methods can call this function to request password information for the
|
||||
* current network. This is normally called when the password is not included
|
||||
* in the network configuration. The request will be sent to monitor programs
|
||||
* through the control interface.
|
||||
*/
|
||||
void eap_sm_request_password(struct eap_sm *sm)
|
||||
{
|
||||
eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSWORD, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_sm_request_new_password - Request new password from user (ctrl_iface)
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
*
|
||||
* EAP methods can call this function to request new password information for
|
||||
* the current network. This is normally called when the EAP method indicates
|
||||
* that the current password has expired and password change is required. The
|
||||
* request will be sent to monitor programs through the control interface.
|
||||
*/
|
||||
void eap_sm_request_new_password(struct eap_sm *sm)
|
||||
{
|
||||
eap_sm_request(sm, WPA_CTRL_REQ_EAP_NEW_PASSWORD, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
void eap_peer_blob_deinit(struct eap_sm *sm)
|
||||
{
|
||||
int i;
|
||||
@ -629,6 +683,7 @@ void eap_peer_blob_deinit(struct eap_sm *sm)
|
||||
sm->config.client_cert = NULL;
|
||||
sm->config.private_key = NULL;
|
||||
sm->config.ca_cert = NULL;
|
||||
sm->config.pac_file = NULL;
|
||||
}
|
||||
|
||||
void eap_sm_abort(struct eap_sm *sm)
|
||||
@ -721,6 +776,40 @@ const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len)
|
||||
*len = config->new_password_len;
|
||||
return config->new_password;
|
||||
}
|
||||
|
||||
|
||||
static int eap_copy_buf(u8 **dst, size_t *dst_len,
|
||||
const u8 *src, size_t src_len)
|
||||
{
|
||||
if (src) {
|
||||
*dst = os_memdup(src, src_len);
|
||||
if (*dst == NULL)
|
||||
return -1;
|
||||
*dst_len = src_len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_set_config_blob - Set or add a named configuration blob
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @blob: New value for the blob
|
||||
*
|
||||
* Adds a new configuration blob or replaces the current value of an existing
|
||||
* blob.
|
||||
*/
|
||||
void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob)
|
||||
{
|
||||
if (!sm)
|
||||
return;
|
||||
|
||||
if (eap_copy_buf((u8 **)&sm->blob[3].data, (size_t *)&sm->blob[3].len, blob->data, blob->len) < 0) {
|
||||
wpa_printf(MSG_ERROR, "EAP: Set config blob: Unable to modify the configuration blob");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_get_config_blob - Get a named configuration blob
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
|
@ -40,6 +40,10 @@ u8 *g_wpa_new_password;
|
||||
int g_wpa_new_password_len;
|
||||
|
||||
char *g_wpa_ttls_phase2_type;
|
||||
char *g_wpa_phase1_options;
|
||||
|
||||
u8 *g_wpa_pac_file;
|
||||
int g_wpa_pac_file_len;
|
||||
|
||||
bool g_wpa_suiteb_certification;
|
||||
|
||||
@ -56,5 +60,7 @@ void eap_peer_config_deinit(struct eap_sm *sm);
|
||||
void eap_sm_abort(struct eap_sm *sm);
|
||||
int eap_peer_register_methods(void);
|
||||
void eap_sm_request_identity(struct eap_sm *sm);
|
||||
void eap_sm_request_password(struct eap_sm *sm);
|
||||
void eap_sm_request_new_password(struct eap_sm *sm);
|
||||
|
||||
#endif /* EAP_H */
|
||||
|
@ -294,6 +294,15 @@ struct eap_peer_config {
|
||||
*/
|
||||
int pending_req_passphrase;
|
||||
|
||||
/**
|
||||
* pending_req_sim - Pending SIM request
|
||||
*
|
||||
* This field should not be set in configuration step. It is only used
|
||||
* internally when control interface is used to request needed
|
||||
* information.
|
||||
*/
|
||||
int pending_req_sim;
|
||||
|
||||
/**
|
||||
* pending_req_otp - Whether there is a pending OTP request
|
||||
*
|
||||
@ -303,6 +312,18 @@ struct eap_peer_config {
|
||||
*/
|
||||
char *pending_req_otp;
|
||||
|
||||
/**
|
||||
* pac_file - File path or blob name for the PAC entries (EAP-FAST)
|
||||
*
|
||||
* wpa_supplicant will need to be able to create this file and write
|
||||
* updates to it when PAC is being provisioned or refreshed. Full path
|
||||
* to the file should be used since working directory may change when
|
||||
* wpa_supplicant is run in the background.
|
||||
* Alternatively, a named configuration blob can be used by setting
|
||||
* this to blob://blob_name.
|
||||
*/
|
||||
char *pac_file;
|
||||
|
||||
/**
|
||||
* mschapv2_retry - MSCHAPv2 retry in progress
|
||||
*
|
||||
@ -358,6 +379,26 @@ struct eap_peer_config {
|
||||
* 2 = require valid OCSP stapling response
|
||||
*/
|
||||
int ocsp;
|
||||
|
||||
/**
|
||||
* erp - Whether EAP Re-authentication Protocol (ERP) is enabled
|
||||
*/
|
||||
int erp;
|
||||
|
||||
/**
|
||||
* pending_ext_cert_check - External server certificate check status
|
||||
*
|
||||
* This field should not be set in configuration step. It is only used
|
||||
* internally when control interface is used to request external
|
||||
* validation of server certificate chain.
|
||||
*/
|
||||
enum {
|
||||
NO_CHECK = 0,
|
||||
PENDING_CHECK,
|
||||
EXT_CERT_CHECK_GOOD,
|
||||
EXT_CERT_CHECK_BAD,
|
||||
} pending_ext_cert_check;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
1807
components/wpa_supplicant/src/eap_peer/eap_fast.c
Normal file
1807
components/wpa_supplicant/src/eap_peer/eap_fast.c
Normal file
File diff suppressed because it is too large
Load Diff
270
components/wpa_supplicant/src/eap_peer/eap_fast_common.c
Normal file
270
components/wpa_supplicant/src/eap_peer/eap_fast_common.c
Normal file
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* EAP-FAST common helper functions (RFC 4851)
|
||||
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "tls/tls.h"
|
||||
#include "eap_peer/eap_defs.h"
|
||||
#include "eap_peer/eap_tlv_common.h"
|
||||
#include "eap_peer/eap_fast_common.h"
|
||||
|
||||
|
||||
void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
|
||||
{
|
||||
struct pac_tlv_hdr hdr;
|
||||
hdr.type = host_to_be16(type);
|
||||
hdr.len = host_to_be16(len);
|
||||
wpabuf_put_data(buf, &hdr, sizeof(hdr));
|
||||
}
|
||||
|
||||
|
||||
void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data,
|
||||
u16 len)
|
||||
{
|
||||
eap_fast_put_tlv_hdr(buf, type, len);
|
||||
wpabuf_put_data(buf, data, len);
|
||||
}
|
||||
|
||||
|
||||
void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type,
|
||||
const struct wpabuf *data)
|
||||
{
|
||||
eap_fast_put_tlv_hdr(buf, type, wpabuf_len(data));
|
||||
wpabuf_put_buf(buf, data);
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf)
|
||||
{
|
||||
struct wpabuf *e;
|
||||
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Encapsulate EAP packet in EAP-Payload TLV */
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: Add EAP-Payload TLV");
|
||||
e = wpabuf_alloc(sizeof(struct pac_tlv_hdr) + wpabuf_len(buf));
|
||||
if (e == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
|
||||
"for TLV encapsulation");
|
||||
wpabuf_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
eap_fast_put_tlv_buf(e,
|
||||
EAP_TLV_TYPE_MANDATORY | EAP_TLV_EAP_PAYLOAD_TLV,
|
||||
buf);
|
||||
wpabuf_free(buf);
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
|
||||
const u8 *client_random, u8 *master_secret)
|
||||
{
|
||||
#define TLS_RANDOM_LEN 32
|
||||
#define TLS_MASTER_SECRET_LEN 48
|
||||
u8 seed[2 * TLS_RANDOM_LEN];
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
|
||||
client_random, TLS_RANDOM_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
|
||||
server_random, TLS_RANDOM_LEN);
|
||||
|
||||
/*
|
||||
* RFC 4851, Section 5.1:
|
||||
* master_secret = T-PRF(PAC-Key, "PAC to master secret label hash",
|
||||
* server_random + client_random, 48)
|
||||
*/
|
||||
os_memcpy(seed, server_random, TLS_RANDOM_LEN);
|
||||
os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN);
|
||||
sha1_t_prf(pac_key, EAP_FAST_PAC_KEY_LEN,
|
||||
"PAC to master secret label hash",
|
||||
seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN);
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret",
|
||||
master_secret, TLS_MASTER_SECRET_LEN);
|
||||
}
|
||||
|
||||
|
||||
u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, size_t len)
|
||||
{
|
||||
u8 *out;
|
||||
|
||||
out = os_malloc(len);
|
||||
if (out == NULL)
|
||||
return NULL;
|
||||
|
||||
if (tls_connection_get_eap_fast_key(ssl_ctx, conn, out, len)) {
|
||||
os_free(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
int eap_fast_derive_eap_msk(const u8 *simck, u8 *msk)
|
||||
{
|
||||
/*
|
||||
* RFC 4851, Section 5.4: EAP Master Session Key Generation
|
||||
* MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64)
|
||||
*/
|
||||
|
||||
if (sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
|
||||
"Session Key Generating Function", (u8 *) "", 0,
|
||||
msk, EAP_FAST_KEY_LEN) < 0)
|
||||
return -1;
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
|
||||
msk, EAP_FAST_KEY_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
|
||||
{
|
||||
/*
|
||||
* RFC 4851, Section 5.4: EAP Master Session Key Genreration
|
||||
* EMSK = T-PRF(S-IMCK[j],
|
||||
* "Extended Session Key Generating Function", 64)
|
||||
*/
|
||||
|
||||
if (sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
|
||||
"Extended Session Key Generating Function", (u8 *) "", 0,
|
||||
emsk, EAP_EMSK_LEN) < 0)
|
||||
return -1;
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
|
||||
emsk, EAP_EMSK_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
|
||||
int tlv_type, u8 *pos, size_t len)
|
||||
{
|
||||
switch (tlv_type) {
|
||||
case EAP_TLV_EAP_PAYLOAD_TLV:
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP-Payload TLV",
|
||||
pos, len);
|
||||
if (tlv->eap_payload_tlv) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
|
||||
"EAP-Payload TLV in the message");
|
||||
tlv->iresult = EAP_TLV_RESULT_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
tlv->eap_payload_tlv = pos;
|
||||
tlv->eap_payload_tlv_len = len;
|
||||
break;
|
||||
case EAP_TLV_RESULT_TLV:
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len);
|
||||
if (tlv->result) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
|
||||
"Result TLV in the message");
|
||||
tlv->result = EAP_TLV_RESULT_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
if (len < 2) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
|
||||
"Result TLV");
|
||||
tlv->result = EAP_TLV_RESULT_FAILURE;
|
||||
break;
|
||||
}
|
||||
tlv->result = WPA_GET_BE16(pos);
|
||||
if (tlv->result != EAP_TLV_RESULT_SUCCESS &&
|
||||
tlv->result != EAP_TLV_RESULT_FAILURE) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Result %d",
|
||||
tlv->result);
|
||||
tlv->result = EAP_TLV_RESULT_FAILURE;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s",
|
||||
tlv->result == EAP_TLV_RESULT_SUCCESS ?
|
||||
"Success" : "Failure");
|
||||
break;
|
||||
case EAP_TLV_INTERMEDIATE_RESULT_TLV:
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate Result TLV",
|
||||
pos, len);
|
||||
if (len < 2) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
|
||||
"Intermediate-Result TLV");
|
||||
tlv->iresult = EAP_TLV_RESULT_FAILURE;
|
||||
break;
|
||||
}
|
||||
if (tlv->iresult) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
|
||||
"Intermediate-Result TLV in the message");
|
||||
tlv->iresult = EAP_TLV_RESULT_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
tlv->iresult = WPA_GET_BE16(pos);
|
||||
if (tlv->iresult != EAP_TLV_RESULT_SUCCESS &&
|
||||
tlv->iresult != EAP_TLV_RESULT_FAILURE) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Intermediate "
|
||||
"Result %d", tlv->iresult);
|
||||
tlv->iresult = EAP_TLV_RESULT_FAILURE;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s",
|
||||
tlv->iresult == EAP_TLV_RESULT_SUCCESS ?
|
||||
"Success" : "Failure");
|
||||
break;
|
||||
case EAP_TLV_CRYPTO_BINDING_TLV:
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV",
|
||||
pos, len);
|
||||
if (tlv->crypto_binding) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
|
||||
"Crypto-Binding TLV in the message");
|
||||
tlv->iresult = EAP_TLV_RESULT_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
tlv->crypto_binding_len = sizeof(struct eap_tlv_hdr) + len;
|
||||
if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
|
||||
"Crypto-Binding TLV");
|
||||
tlv->iresult = EAP_TLV_RESULT_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
tlv->crypto_binding = (struct eap_tlv_crypto_binding_tlv *)
|
||||
(pos - sizeof(struct eap_tlv_hdr));
|
||||
break;
|
||||
case EAP_TLV_REQUEST_ACTION_TLV:
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Request-Action TLV",
|
||||
pos, len);
|
||||
if (tlv->request_action) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
|
||||
"Request-Action TLV in the message");
|
||||
tlv->iresult = EAP_TLV_RESULT_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
if (len < 2) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
|
||||
"Request-Action TLV");
|
||||
tlv->iresult = EAP_TLV_RESULT_FAILURE;
|
||||
break;
|
||||
}
|
||||
tlv->request_action = WPA_GET_BE16(pos);
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: Request-Action: %d",
|
||||
tlv->request_action);
|
||||
break;
|
||||
case EAP_TLV_PAC_TLV:
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len);
|
||||
if (tlv->pac) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
|
||||
"PAC TLV in the message");
|
||||
tlv->iresult = EAP_TLV_RESULT_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
tlv->pac = pos;
|
||||
tlv->pac_len = len;
|
||||
break;
|
||||
default:
|
||||
/* Unknown TLV */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
107
components/wpa_supplicant/src/eap_peer/eap_fast_common.h
Normal file
107
components/wpa_supplicant/src/eap_peer/eap_fast_common.h
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* EAP-FAST definitions (RFC 4851)
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef EAP_FAST_H
|
||||
#define EAP_FAST_H
|
||||
|
||||
#define EAP_FAST_VERSION 1
|
||||
#define EAP_FAST_KEY_LEN 64
|
||||
#define EAP_FAST_SIMCK_LEN 40
|
||||
#define EAP_FAST_SKS_LEN 40
|
||||
#define EAP_FAST_CMK_LEN 20
|
||||
|
||||
#define TLS_EXT_PAC_OPAQUE 35
|
||||
|
||||
/*
|
||||
* RFC 5422: Section 4.2.1 - Formats for PAC TLV Attributes / Type Field
|
||||
* Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined
|
||||
* in the general PAC TLV format (Section 4.2).
|
||||
*/
|
||||
#define PAC_TYPE_PAC_KEY 1
|
||||
#define PAC_TYPE_PAC_OPAQUE 2
|
||||
#define PAC_TYPE_CRED_LIFETIME 3
|
||||
#define PAC_TYPE_A_ID 4
|
||||
#define PAC_TYPE_I_ID 5
|
||||
/*
|
||||
* 6 was previous assigned for SERVER_PROTECTED_DATA, but
|
||||
* draft-cam-winget-eap-fast-provisioning-02.txt changed this to Reserved.
|
||||
*/
|
||||
#define PAC_TYPE_A_ID_INFO 7
|
||||
#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8
|
||||
#define PAC_TYPE_PAC_INFO 9
|
||||
#define PAC_TYPE_PAC_TYPE 10
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
struct pac_tlv_hdr {
|
||||
be16 type;
|
||||
be16 len;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
|
||||
#define EAP_FAST_PAC_KEY_LEN 32
|
||||
|
||||
/* RFC 5422: 4.2.6 PAC-Type TLV */
|
||||
#define PAC_TYPE_TUNNEL_PAC 1
|
||||
/* Application Specific Short Lived PACs (only in volatile storage) */
|
||||
/* User Authorization PAC */
|
||||
#define PAC_TYPE_USER_AUTHORIZATION 3
|
||||
/* Application Specific Long Lived PACs */
|
||||
/* Machine Authentication PAC */
|
||||
#define PAC_TYPE_MACHINE_AUTHENTICATION 2
|
||||
|
||||
|
||||
/*
|
||||
* RFC 5422:
|
||||
* Section 3.3 - Key Derivations Used in the EAP-FAST Provisioning Exchange
|
||||
*/
|
||||
struct eap_fast_key_block_provisioning {
|
||||
/* Extra key material after TLS key_block */
|
||||
u8 session_key_seed[EAP_FAST_SKS_LEN];
|
||||
u8 server_challenge[16]; /* MSCHAPv2 ServerChallenge */
|
||||
u8 client_challenge[16]; /* MSCHAPv2 ClientChallenge */
|
||||
};
|
||||
|
||||
|
||||
struct wpabuf;
|
||||
struct tls_connection;
|
||||
|
||||
struct eap_fast_tlv_parse {
|
||||
u8 *eap_payload_tlv;
|
||||
size_t eap_payload_tlv_len;
|
||||
struct eap_tlv_crypto_binding_tlv *crypto_binding;
|
||||
size_t crypto_binding_len;
|
||||
int iresult;
|
||||
int result;
|
||||
int request_action;
|
||||
u8 *pac;
|
||||
size_t pac_len;
|
||||
};
|
||||
|
||||
void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len);
|
||||
void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data,
|
||||
u16 len);
|
||||
void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type,
|
||||
const struct wpabuf *data);
|
||||
struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf);
|
||||
void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
|
||||
const u8 *client_random, u8 *master_secret);
|
||||
u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
|
||||
size_t len);
|
||||
int eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
|
||||
int eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk);
|
||||
int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
|
||||
int tlv_type, u8 *pos, size_t len);
|
||||
|
||||
#endif /* EAP_FAST_H */
|
932
components/wpa_supplicant/src/eap_peer/eap_fast_pac.c
Normal file
932
components/wpa_supplicant/src/eap_peer/eap_fast_pac.c
Normal file
@ -0,0 +1,932 @@
|
||||
/*
|
||||
* EAP peer method: EAP-FAST PAC file processing
|
||||
* Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "os.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "eap_peer/eap_config.h"
|
||||
#include "eap_peer/eap_i.h"
|
||||
#include "eap_peer/eap_fast_pac.h"
|
||||
|
||||
/* TODO: encrypt PAC-Key in the PAC file */
|
||||
|
||||
|
||||
/* Text data format */
|
||||
static const char *pac_file_hdr =
|
||||
"wpa_supplicant EAP-FAST PAC file - version 1";
|
||||
|
||||
/*
|
||||
* Binary data format
|
||||
* 4-octet magic value: 6A E4 92 0C
|
||||
* 2-octet version (big endian)
|
||||
* <version specific data>
|
||||
*
|
||||
* version=0:
|
||||
* Sequence of PAC entries:
|
||||
* 2-octet PAC-Type (big endian)
|
||||
* 32-octet PAC-Key
|
||||
* 2-octet PAC-Opaque length (big endian)
|
||||
* <variable len> PAC-Opaque data (length bytes)
|
||||
* 2-octet PAC-Info length (big endian)
|
||||
* <variable len> PAC-Info data (length bytes)
|
||||
*/
|
||||
|
||||
#define EAP_FAST_PAC_BINARY_MAGIC 0x6ae4920c
|
||||
#define EAP_FAST_PAC_BINARY_FORMAT_VERSION 0
|
||||
|
||||
|
||||
/**
|
||||
* eap_fast_free_pac - Free PAC data
|
||||
* @pac: Pointer to the PAC entry
|
||||
*
|
||||
* Note that the PAC entry must not be in a list since this function does not
|
||||
* remove the list links.
|
||||
*/
|
||||
void eap_fast_free_pac(struct eap_fast_pac *pac)
|
||||
{
|
||||
os_free(pac->pac_opaque);
|
||||
os_free(pac->pac_info);
|
||||
os_free(pac->a_id);
|
||||
os_free(pac->i_id);
|
||||
os_free(pac->a_id_info);
|
||||
os_free(pac);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_fast_get_pac - Get a PAC entry based on A-ID
|
||||
* @pac_root: Pointer to root of the PAC list
|
||||
* @a_id: A-ID to search for
|
||||
* @a_id_len: Length of A-ID
|
||||
* @pac_type: PAC-Type to search for
|
||||
* Returns: Pointer to the PAC entry, or %NULL if A-ID not found
|
||||
*/
|
||||
struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_pac *pac_root,
|
||||
const u8 *a_id, size_t a_id_len,
|
||||
u16 pac_type)
|
||||
{
|
||||
struct eap_fast_pac *pac = pac_root;
|
||||
|
||||
while (pac) {
|
||||
if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
|
||||
os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
|
||||
return pac;
|
||||
}
|
||||
pac = pac->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void eap_fast_remove_pac(struct eap_fast_pac **pac_root,
|
||||
struct eap_fast_pac **pac_current,
|
||||
const u8 *a_id, size_t a_id_len, u16 pac_type)
|
||||
{
|
||||
struct eap_fast_pac *pac, *prev;
|
||||
|
||||
pac = *pac_root;
|
||||
prev = NULL;
|
||||
|
||||
while (pac) {
|
||||
if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
|
||||
os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
|
||||
if (prev == NULL)
|
||||
*pac_root = pac->next;
|
||||
else
|
||||
prev->next = pac->next;
|
||||
if (*pac_current == pac)
|
||||
*pac_current = NULL;
|
||||
eap_fast_free_pac(pac);
|
||||
break;
|
||||
}
|
||||
prev = pac;
|
||||
pac = pac->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int eap_fast_copy_buf(u8 **dst, size_t *dst_len,
|
||||
const u8 *src, size_t src_len)
|
||||
{
|
||||
if (src) {
|
||||
*dst = os_memdup(src, src_len);
|
||||
if (*dst == NULL)
|
||||
return -1;
|
||||
*dst_len = src_len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_fast_add_pac - Add a copy of a PAC entry to a list
|
||||
* @pac_root: Pointer to PAC list root pointer
|
||||
* @pac_current: Pointer to the current PAC pointer
|
||||
* @entry: New entry to clone and add to the list
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This function makes a clone of the given PAC entry and adds this copied
|
||||
* entry to the list (pac_root). If an old entry for the same A-ID is found,
|
||||
* it will be removed from the PAC list and in this case, pac_current entry
|
||||
* is set to %NULL if it was the removed entry.
|
||||
*/
|
||||
int eap_fast_add_pac(struct eap_fast_pac **pac_root,
|
||||
struct eap_fast_pac **pac_current,
|
||||
struct eap_fast_pac *entry)
|
||||
{
|
||||
struct eap_fast_pac *pac;
|
||||
|
||||
if (entry == NULL || entry->a_id == NULL)
|
||||
return -1;
|
||||
|
||||
/* Remove a possible old entry for the matching A-ID. */
|
||||
eap_fast_remove_pac(pac_root, pac_current,
|
||||
entry->a_id, entry->a_id_len, entry->pac_type);
|
||||
|
||||
/* Allocate a new entry and add it to the list of PACs. */
|
||||
pac = os_zalloc(sizeof(*pac));
|
||||
if (pac == NULL)
|
||||
return -1;
|
||||
|
||||
pac->pac_type = entry->pac_type;
|
||||
os_memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN);
|
||||
if (eap_fast_copy_buf(&pac->pac_opaque, &pac->pac_opaque_len,
|
||||
entry->pac_opaque, entry->pac_opaque_len) < 0 ||
|
||||
eap_fast_copy_buf(&pac->pac_info, &pac->pac_info_len,
|
||||
entry->pac_info, entry->pac_info_len) < 0 ||
|
||||
eap_fast_copy_buf(&pac->a_id, &pac->a_id_len,
|
||||
entry->a_id, entry->a_id_len) < 0 ||
|
||||
eap_fast_copy_buf(&pac->i_id, &pac->i_id_len,
|
||||
entry->i_id, entry->i_id_len) < 0 ||
|
||||
eap_fast_copy_buf(&pac->a_id_info, &pac->a_id_info_len,
|
||||
entry->a_id_info, entry->a_id_info_len) < 0) {
|
||||
eap_fast_free_pac(pac);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pac->next = *pac_root;
|
||||
*pac_root = pac;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct eap_fast_read_ctx {
|
||||
FILE *f;
|
||||
const char *pos;
|
||||
const char *end;
|
||||
int line;
|
||||
char *buf;
|
||||
size_t buf_len;
|
||||
};
|
||||
|
||||
static int eap_fast_read_line(struct eap_fast_read_ctx *rc, char **value)
|
||||
{
|
||||
char *pos;
|
||||
|
||||
rc->line++;
|
||||
if (rc->f) {
|
||||
if (fgets(rc->buf, rc->buf_len, rc->f) == NULL)
|
||||
return -1;
|
||||
} else {
|
||||
const char *l_end;
|
||||
size_t len;
|
||||
if (rc->pos >= rc->end)
|
||||
return -1;
|
||||
l_end = rc->pos;
|
||||
while (l_end < rc->end && *l_end != '\n')
|
||||
l_end++;
|
||||
len = l_end - rc->pos;
|
||||
if (len >= rc->buf_len)
|
||||
len = rc->buf_len - 1;
|
||||
os_memcpy(rc->buf, rc->pos, len);
|
||||
rc->buf[len] = '\0';
|
||||
rc->pos = l_end + 1;
|
||||
}
|
||||
|
||||
rc->buf[rc->buf_len - 1] = '\0';
|
||||
pos = rc->buf;
|
||||
while (*pos != '\0') {
|
||||
if (*pos == '\n' || *pos == '\r') {
|
||||
*pos = '\0';
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
pos = os_strchr(rc->buf, '=');
|
||||
if (pos)
|
||||
*pos++ = '\0';
|
||||
*value = pos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_fast_parse_hex(const char *value, size_t *len)
|
||||
{
|
||||
int hlen;
|
||||
u8 *buf;
|
||||
|
||||
if (value == NULL)
|
||||
return NULL;
|
||||
hlen = os_strlen(value);
|
||||
if (hlen & 1)
|
||||
return NULL;
|
||||
*len = hlen / 2;
|
||||
buf = os_malloc(*len);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
if (hexstr2bin(value, buf, *len)) {
|
||||
os_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static int eap_fast_init_pac_data(struct eap_sm *sm, const char *pac_file,
|
||||
struct eap_fast_read_ctx *rc)
|
||||
{
|
||||
os_memset(rc, 0, sizeof(*rc));
|
||||
|
||||
rc->buf_len = 2048;
|
||||
rc->buf = os_malloc(rc->buf_len);
|
||||
if (rc->buf == NULL)
|
||||
return -1;
|
||||
|
||||
if (os_strncmp(pac_file, "blob://", 7) == 0) {
|
||||
const struct wpa_config_blob *blob;
|
||||
blob = eap_get_config_blob(sm, pac_file);
|
||||
if (blob == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - "
|
||||
"assume no PAC entries have been "
|
||||
"provisioned", pac_file);
|
||||
os_free(rc->buf);
|
||||
return -1;
|
||||
}
|
||||
rc->pos = (char *) blob->data;
|
||||
rc->end = (char *) blob->data + blob->len;
|
||||
} else {
|
||||
rc->f = fopen(pac_file, "rb");
|
||||
if (rc->f == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
|
||||
"assume no PAC entries have been "
|
||||
"provisioned", pac_file);
|
||||
os_free(rc->buf);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void eap_fast_deinit_pac_data(struct eap_fast_read_ctx *rc)
|
||||
{
|
||||
os_free(rc->buf);
|
||||
if (rc->f)
|
||||
fclose(rc->f);
|
||||
}
|
||||
|
||||
|
||||
static const char * eap_fast_parse_start(struct eap_fast_pac **pac)
|
||||
{
|
||||
if (*pac)
|
||||
return "START line without END";
|
||||
|
||||
*pac = os_zalloc(sizeof(struct eap_fast_pac));
|
||||
if (*pac == NULL)
|
||||
return "No memory for PAC entry";
|
||||
(*pac)->pac_type = PAC_TYPE_TUNNEL_PAC;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static const char * eap_fast_parse_end(struct eap_fast_pac **pac_root,
|
||||
struct eap_fast_pac **pac)
|
||||
{
|
||||
if (*pac == NULL)
|
||||
return "END line without START";
|
||||
if (*pac_root) {
|
||||
struct eap_fast_pac *end = *pac_root;
|
||||
while (end->next)
|
||||
end = end->next;
|
||||
end->next = *pac;
|
||||
} else
|
||||
*pac_root = *pac;
|
||||
|
||||
*pac = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static const char * eap_fast_parse_pac_type(struct eap_fast_pac *pac,
|
||||
char *pos)
|
||||
{
|
||||
if (!pos)
|
||||
return "Cannot parse pac type";
|
||||
pac->pac_type = atoi(pos);
|
||||
if (pac->pac_type != PAC_TYPE_TUNNEL_PAC &&
|
||||
pac->pac_type != PAC_TYPE_USER_AUTHORIZATION &&
|
||||
pac->pac_type != PAC_TYPE_MACHINE_AUTHENTICATION)
|
||||
return "Unrecognized PAC-Type";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static const char * eap_fast_parse_pac_key(struct eap_fast_pac *pac, char *pos)
|
||||
{
|
||||
u8 *key;
|
||||
size_t key_len;
|
||||
|
||||
key = eap_fast_parse_hex(pos, &key_len);
|
||||
if (key == NULL || key_len != EAP_FAST_PAC_KEY_LEN) {
|
||||
os_free(key);
|
||||
return "Invalid PAC-Key";
|
||||
}
|
||||
|
||||
os_memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN);
|
||||
os_free(key);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static const char * eap_fast_parse_pac_opaque(struct eap_fast_pac *pac,
|
||||
char *pos)
|
||||
{
|
||||
os_free(pac->pac_opaque);
|
||||
pac->pac_opaque = eap_fast_parse_hex(pos, &pac->pac_opaque_len);
|
||||
if (pac->pac_opaque == NULL)
|
||||
return "Invalid PAC-Opaque";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static const char * eap_fast_parse_a_id(struct eap_fast_pac *pac, char *pos)
|
||||
{
|
||||
os_free(pac->a_id);
|
||||
pac->a_id = eap_fast_parse_hex(pos, &pac->a_id_len);
|
||||
if (pac->a_id == NULL)
|
||||
return "Invalid A-ID";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static const char * eap_fast_parse_i_id(struct eap_fast_pac *pac, char *pos)
|
||||
{
|
||||
os_free(pac->i_id);
|
||||
pac->i_id = eap_fast_parse_hex(pos, &pac->i_id_len);
|
||||
if (pac->i_id == NULL)
|
||||
return "Invalid I-ID";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static const char * eap_fast_parse_a_id_info(struct eap_fast_pac *pac,
|
||||
char *pos)
|
||||
{
|
||||
os_free(pac->a_id_info);
|
||||
pac->a_id_info = eap_fast_parse_hex(pos, &pac->a_id_info_len);
|
||||
if (pac->a_id_info == NULL)
|
||||
return "Invalid A-ID-Info";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_fast_load_pac - Load PAC entries (text format)
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @pac_root: Pointer to root of the PAC list (to be filled)
|
||||
* @pac_file: Name of the PAC file/blob to load
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root,
|
||||
const char *pac_file)
|
||||
{
|
||||
struct eap_fast_read_ctx rc;
|
||||
struct eap_fast_pac *pac = NULL;
|
||||
int count = 0;
|
||||
char *pos;
|
||||
const char *err = NULL;
|
||||
|
||||
if (pac_file == NULL)
|
||||
return -1;
|
||||
|
||||
if (eap_fast_init_pac_data(sm, pac_file, &rc) < 0)
|
||||
return 0;
|
||||
|
||||
if (eap_fast_read_line(&rc, &pos) < 0) {
|
||||
/* empty file - assume it is fine to overwrite */
|
||||
printf("\n\nassuming it is fine to overwrite... \n\n");
|
||||
eap_fast_deinit_pac_data(&rc);
|
||||
return 0;
|
||||
}
|
||||
printf("\n\nPAC FILE =\n%s", rc.pos);
|
||||
if (os_strcmp(pac_file_hdr, rc.buf) != 0)
|
||||
err = "Unrecognized header line";
|
||||
|
||||
while (!err && eap_fast_read_line(&rc, &pos) == 0) {
|
||||
if (os_strcmp(rc.buf, "START") == 0)
|
||||
err = eap_fast_parse_start(&pac);
|
||||
else if (os_strcmp(rc.buf, "END") == 0) {
|
||||
err = eap_fast_parse_end(pac_root, &pac);
|
||||
count++;
|
||||
} else if (!pac)
|
||||
err = "Unexpected line outside START/END block";
|
||||
else if (os_strcmp(rc.buf, "PAC-Type") == 0)
|
||||
err = eap_fast_parse_pac_type(pac, pos);
|
||||
else if (os_strcmp(rc.buf, "PAC-Key") == 0)
|
||||
err = eap_fast_parse_pac_key(pac, pos);
|
||||
else if (os_strcmp(rc.buf, "PAC-Opaque") == 0)
|
||||
err = eap_fast_parse_pac_opaque(pac, pos);
|
||||
else if (os_strcmp(rc.buf, "A-ID") == 0)
|
||||
err = eap_fast_parse_a_id(pac, pos);
|
||||
else if (os_strcmp(rc.buf, "I-ID") == 0)
|
||||
err = eap_fast_parse_i_id(pac, pos);
|
||||
else if (os_strcmp(rc.buf, "A-ID-Info") == 0)
|
||||
err = eap_fast_parse_a_id_info(pac, pos);
|
||||
}
|
||||
|
||||
if (pac) {
|
||||
if (!err)
|
||||
err = "PAC block not terminated with END";
|
||||
eap_fast_free_pac(pac);
|
||||
}
|
||||
|
||||
eap_fast_deinit_pac_data(&rc);
|
||||
|
||||
if (err) {
|
||||
wpa_printf(MSG_INFO, "EAP-FAST: %s in '%s:%d'",
|
||||
err, pac_file, rc.line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: Read %d PAC entries from '%s'",
|
||||
count, pac_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void eap_fast_write(char **buf, char **pos, size_t *buf_len,
|
||||
const char *field, const u8 *data,
|
||||
size_t len, int txt)
|
||||
{
|
||||
size_t i, need;
|
||||
int ret;
|
||||
char *end;
|
||||
|
||||
if (data == NULL || buf == NULL || *buf == NULL ||
|
||||
pos == NULL || *pos == NULL || *pos < *buf)
|
||||
return;
|
||||
|
||||
need = os_strlen(field) + len * 2 + 30;
|
||||
if (txt)
|
||||
need += os_strlen(field) + len + 20;
|
||||
|
||||
if (*pos - *buf + need > *buf_len) {
|
||||
char *nbuf = os_realloc(*buf, *buf_len + need);
|
||||
if (nbuf == NULL) {
|
||||
os_free(*buf);
|
||||
*buf = NULL;
|
||||
return;
|
||||
}
|
||||
*pos = nbuf + (*pos - *buf);
|
||||
*buf = nbuf;
|
||||
*buf_len += need;
|
||||
}
|
||||
end = *buf + *buf_len;
|
||||
|
||||
ret = os_snprintf(*pos, end - *pos, "%s=", field);
|
||||
if (os_snprintf_error(end - *pos, ret))
|
||||
return;
|
||||
*pos += ret;
|
||||
*pos += wpa_snprintf_hex(*pos, end - *pos, data, len);
|
||||
ret = os_snprintf(*pos, end - *pos, "\n");
|
||||
if (os_snprintf_error(end - *pos, ret))
|
||||
return;
|
||||
*pos += ret;
|
||||
|
||||
if (txt) {
|
||||
ret = os_snprintf(*pos, end - *pos, "%s-txt=", field);
|
||||
if (os_snprintf_error(end - *pos, ret))
|
||||
return;
|
||||
*pos += ret;
|
||||
for (i = 0; i < len; i++) {
|
||||
ret = os_snprintf(*pos, end - *pos, "%c", data[i]);
|
||||
if (os_snprintf_error(end - *pos, ret))
|
||||
return;
|
||||
*pos += ret;
|
||||
}
|
||||
ret = os_snprintf(*pos, end - *pos, "\n");
|
||||
if (os_snprintf_error(end - *pos, ret))
|
||||
return;
|
||||
*pos += ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int eap_fast_write_pac(struct eap_sm *sm, const char *pac_file,
|
||||
char *buf, size_t len)
|
||||
{
|
||||
if (os_strncmp(pac_file, "blob://", 7) == 0) {
|
||||
struct wpa_config_blob *blob;
|
||||
blob = os_zalloc(sizeof(*blob));
|
||||
if (blob == NULL)
|
||||
return -1;
|
||||
blob->data = (u8 *) buf;
|
||||
blob->len = len;
|
||||
buf = NULL;
|
||||
blob->name = os_strdup(pac_file + 7);
|
||||
if (blob->name == NULL) {
|
||||
os_free(blob);
|
||||
return -1;
|
||||
}
|
||||
eap_set_config_blob(sm, blob);
|
||||
} else {
|
||||
FILE *f;
|
||||
f = fopen(pac_file, "wb");
|
||||
if (f == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC "
|
||||
"file '%s' for writing", pac_file);
|
||||
return -1;
|
||||
}
|
||||
if (fwrite(buf, 1, len, f) != len) {
|
||||
wpa_printf(MSG_INFO, "EAP-FAST: Failed to write all "
|
||||
"PACs into '%s'", pac_file);
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
os_free(buf);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int eap_fast_add_pac_data(struct eap_fast_pac *pac, char **buf,
|
||||
char **pos, size_t *buf_len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = os_snprintf(*pos, *buf + *buf_len - *pos,
|
||||
"START\nPAC-Type=%d\n", pac->pac_type);
|
||||
if (os_snprintf_error(*buf + *buf_len - *pos, ret))
|
||||
return -1;
|
||||
|
||||
*pos += ret;
|
||||
eap_fast_write(buf, pos, buf_len, "PAC-Key",
|
||||
pac->pac_key, EAP_FAST_PAC_KEY_LEN, 0);
|
||||
eap_fast_write(buf, pos, buf_len, "PAC-Opaque",
|
||||
pac->pac_opaque, pac->pac_opaque_len, 0);
|
||||
eap_fast_write(buf, pos, buf_len, "PAC-Info",
|
||||
pac->pac_info, pac->pac_info_len, 0);
|
||||
eap_fast_write(buf, pos, buf_len, "A-ID",
|
||||
pac->a_id, pac->a_id_len, 0);
|
||||
eap_fast_write(buf, pos, buf_len, "I-ID",
|
||||
pac->i_id, pac->i_id_len, 1);
|
||||
eap_fast_write(buf, pos, buf_len, "A-ID-Info",
|
||||
pac->a_id_info, pac->a_id_info_len, 1);
|
||||
if (*buf == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: No memory for PAC "
|
||||
"data");
|
||||
return -1;
|
||||
}
|
||||
ret = os_snprintf(*pos, *buf + *buf_len - *pos, "END\n");
|
||||
if (os_snprintf_error(*buf + *buf_len - *pos, ret))
|
||||
return -1;
|
||||
*pos += ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_fast_save_pac - Save PAC entries (text format)
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @pac_root: Root of the PAC list
|
||||
* @pac_file: Name of the PAC file/blob
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_pac *pac_root,
|
||||
const char *pac_file)
|
||||
{
|
||||
struct eap_fast_pac *pac;
|
||||
int ret, count = 0;
|
||||
char *buf, *pos;
|
||||
size_t buf_len;
|
||||
|
||||
if (pac_file == NULL)
|
||||
return -1;
|
||||
|
||||
buf_len = 1024;
|
||||
pos = buf = os_malloc(buf_len);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
|
||||
if (os_snprintf_error(buf + buf_len - pos, ret)) {
|
||||
os_free(buf);
|
||||
return -1;
|
||||
}
|
||||
pos += ret;
|
||||
|
||||
pac = pac_root;
|
||||
while (pac) {
|
||||
if (eap_fast_add_pac_data(pac, &buf, &pos, &buf_len)) {
|
||||
os_free(buf);
|
||||
return -1;
|
||||
}
|
||||
count++;
|
||||
pac = pac->next;
|
||||
}
|
||||
|
||||
if (eap_fast_write_pac(sm, pac_file, buf, pos - buf)) {
|
||||
os_free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "PAC file: %s", (sm->blob[3].data));
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %d PAC entries into '%s'",
|
||||
count, pac_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_fast_pac_list_truncate - Truncate a PAC list to the given length
|
||||
* @pac_root: Root of the PAC list
|
||||
* @max_len: Maximum length of the list (>= 1)
|
||||
* Returns: Number of PAC entries removed
|
||||
*/
|
||||
size_t eap_fast_pac_list_truncate(struct eap_fast_pac *pac_root,
|
||||
size_t max_len)
|
||||
{
|
||||
struct eap_fast_pac *pac, *prev;
|
||||
size_t count;
|
||||
|
||||
pac = pac_root;
|
||||
prev = NULL;
|
||||
count = 0;
|
||||
|
||||
while (pac) {
|
||||
count++;
|
||||
if (count > max_len)
|
||||
break;
|
||||
prev = pac;
|
||||
pac = pac->next;
|
||||
}
|
||||
|
||||
if (count <= max_len || prev == NULL)
|
||||
return 0;
|
||||
|
||||
count = 0;
|
||||
prev->next = NULL;
|
||||
|
||||
while (pac) {
|
||||
prev = pac;
|
||||
pac = pac->next;
|
||||
eap_fast_free_pac(prev);
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static void eap_fast_pac_get_a_id(struct eap_fast_pac *pac)
|
||||
{
|
||||
u8 *pos, *end;
|
||||
u16 type, len;
|
||||
|
||||
pos = pac->pac_info;
|
||||
end = pos + pac->pac_info_len;
|
||||
|
||||
while (end - pos > 4) {
|
||||
type = WPA_GET_BE16(pos);
|
||||
pos += 2;
|
||||
len = WPA_GET_BE16(pos);
|
||||
pos += 2;
|
||||
if (len > (unsigned int) (end - pos))
|
||||
break;
|
||||
|
||||
if (type == PAC_TYPE_A_ID) {
|
||||
os_free(pac->a_id);
|
||||
pac->a_id = os_memdup(pos, len);
|
||||
if (pac->a_id == NULL)
|
||||
break;
|
||||
pac->a_id_len = len;
|
||||
}
|
||||
|
||||
if (type == PAC_TYPE_A_ID_INFO) {
|
||||
os_free(pac->a_id_info);
|
||||
pac->a_id_info = os_memdup(pos, len);
|
||||
if (pac->a_id_info == NULL)
|
||||
break;
|
||||
pac->a_id_info_len = len;
|
||||
}
|
||||
|
||||
pos += len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_fast_load_pac_bin - Load PAC entries (binary format)
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @pac_root: Pointer to root of the PAC list (to be filled)
|
||||
* @pac_file: Name of the PAC file/blob to load
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root,
|
||||
const char *pac_file)
|
||||
{
|
||||
const struct wpa_config_blob *blob = NULL;
|
||||
u8 *buf, *end, *pos;
|
||||
size_t len = 0;
|
||||
size_t count = 0;
|
||||
struct eap_fast_pac *pac, *prev;
|
||||
|
||||
*pac_root = NULL;
|
||||
|
||||
if (pac_file == NULL)
|
||||
return -1;
|
||||
|
||||
if (sm->config.pac_file != NULL) { //if (os_strncmp(pac_file, "blob://", 7) == 0) {
|
||||
blob = eap_get_config_blob(sm, PAC_FILE_NAME);
|
||||
if (blob == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - "
|
||||
"assume no PAC entries have been "
|
||||
"provisioned", pac_file);
|
||||
return 0;
|
||||
}
|
||||
buf = (u8 *) blob->data;
|
||||
len = blob->len;
|
||||
} else {
|
||||
buf = (u8 *) sm->blob[3].data; //(u8 *) os_readfile(pac_file, &len);
|
||||
if (buf == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
|
||||
"assume no PAC entries have been "
|
||||
"provisioned", pac_file);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
if (blob == NULL)
|
||||
os_free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len < 6 || WPA_GET_BE32(buf) != EAP_FAST_PAC_BINARY_MAGIC ||
|
||||
WPA_GET_BE16(buf + 4) != EAP_FAST_PAC_BINARY_FORMAT_VERSION) {
|
||||
wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC file '%s' (bin)",
|
||||
pac_file);
|
||||
if (blob == NULL)
|
||||
os_free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pac = prev = NULL;
|
||||
pos = buf + 6;
|
||||
end = buf + len;
|
||||
while (pos < end) {
|
||||
u16 val;
|
||||
|
||||
if (end - pos < 2 + EAP_FAST_PAC_KEY_LEN + 2 + 2) {
|
||||
pac = NULL;
|
||||
goto parse_fail;
|
||||
}
|
||||
|
||||
pac = os_zalloc(sizeof(*pac));
|
||||
if (pac == NULL)
|
||||
goto parse_fail;
|
||||
|
||||
pac->pac_type = WPA_GET_BE16(pos);
|
||||
pos += 2;
|
||||
os_memcpy(pac->pac_key, pos, EAP_FAST_PAC_KEY_LEN);
|
||||
pos += EAP_FAST_PAC_KEY_LEN;
|
||||
val = WPA_GET_BE16(pos);
|
||||
pos += 2;
|
||||
if (val > end - pos)
|
||||
goto parse_fail;
|
||||
pac->pac_opaque_len = val;
|
||||
pac->pac_opaque = os_memdup(pos, pac->pac_opaque_len);
|
||||
if (pac->pac_opaque == NULL)
|
||||
goto parse_fail;
|
||||
pos += pac->pac_opaque_len;
|
||||
if (2 > end - pos)
|
||||
goto parse_fail;
|
||||
val = WPA_GET_BE16(pos);
|
||||
pos += 2;
|
||||
if (val > end - pos)
|
||||
goto parse_fail;
|
||||
pac->pac_info_len = val;
|
||||
pac->pac_info = os_memdup(pos, pac->pac_info_len);
|
||||
if (pac->pac_info == NULL)
|
||||
goto parse_fail;
|
||||
pos += pac->pac_info_len;
|
||||
eap_fast_pac_get_a_id(pac);
|
||||
|
||||
count++;
|
||||
if (prev)
|
||||
prev->next = pac;
|
||||
else
|
||||
*pac_root = pac;
|
||||
prev = pac;
|
||||
}
|
||||
|
||||
if (blob == NULL)
|
||||
os_free(buf);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: Read %lu PAC entries from '%s' (bin)",
|
||||
(unsigned long) count, pac_file);
|
||||
|
||||
return 0;
|
||||
|
||||
parse_fail:
|
||||
wpa_printf(MSG_INFO, "EAP-FAST: Failed to parse PAC file '%s' (bin)",
|
||||
pac_file);
|
||||
if (blob == NULL)
|
||||
os_free(buf);
|
||||
if (pac)
|
||||
eap_fast_free_pac(pac);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_fast_save_pac_bin - Save PAC entries (binary format)
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @pac_root: Root of the PAC list
|
||||
* @pac_file: Name of the PAC file/blob
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int eap_fast_save_pac_bin(struct eap_sm *sm, struct eap_fast_pac *pac_root,
|
||||
const char *pac_file)
|
||||
{
|
||||
size_t len, count = 0;
|
||||
struct eap_fast_pac *pac;
|
||||
u8 *buf, *pos;
|
||||
|
||||
len = 6;
|
||||
pac = pac_root;
|
||||
while (pac) {
|
||||
if (pac->pac_opaque_len > 65535 ||
|
||||
pac->pac_info_len > 65535)
|
||||
return -1;
|
||||
len += 2 + EAP_FAST_PAC_KEY_LEN + 2 + pac->pac_opaque_len +
|
||||
2 + pac->pac_info_len;
|
||||
pac = pac->next;
|
||||
}
|
||||
|
||||
buf = os_malloc(len);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
pos = buf;
|
||||
WPA_PUT_BE32(pos, EAP_FAST_PAC_BINARY_MAGIC);
|
||||
pos += 4;
|
||||
WPA_PUT_BE16(pos, EAP_FAST_PAC_BINARY_FORMAT_VERSION);
|
||||
pos += 2;
|
||||
|
||||
pac = pac_root;
|
||||
while (pac) {
|
||||
WPA_PUT_BE16(pos, pac->pac_type);
|
||||
pos += 2;
|
||||
os_memcpy(pos, pac->pac_key, EAP_FAST_PAC_KEY_LEN);
|
||||
pos += EAP_FAST_PAC_KEY_LEN;
|
||||
WPA_PUT_BE16(pos, pac->pac_opaque_len);
|
||||
pos += 2;
|
||||
os_memcpy(pos, pac->pac_opaque, pac->pac_opaque_len);
|
||||
pos += pac->pac_opaque_len;
|
||||
WPA_PUT_BE16(pos, pac->pac_info_len);
|
||||
pos += 2;
|
||||
os_memcpy(pos, pac->pac_info, pac->pac_info_len);
|
||||
pos += pac->pac_info_len;
|
||||
|
||||
pac = pac->next;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (eap_fast_write_pac(sm, pac_file, (char *) buf, len)) {
|
||||
os_free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %lu PAC entries into '%s' "
|
||||
"(bin)", (unsigned long) count, pac_file);
|
||||
|
||||
return 0;
|
||||
}
|
50
components/wpa_supplicant/src/eap_peer/eap_fast_pac.h
Normal file
50
components/wpa_supplicant/src/eap_peer/eap_fast_pac.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* EAP peer method: EAP-FAST PAC file processing
|
||||
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef EAP_FAST_PAC_H
|
||||
#define EAP_FAST_PAC_H
|
||||
|
||||
#include "eap_peer/eap_fast_common.h"
|
||||
|
||||
struct eap_fast_pac {
|
||||
struct eap_fast_pac *next;
|
||||
|
||||
u8 pac_key[EAP_FAST_PAC_KEY_LEN];
|
||||
u8 *pac_opaque;
|
||||
size_t pac_opaque_len;
|
||||
u8 *pac_info;
|
||||
size_t pac_info_len;
|
||||
u8 *a_id;
|
||||
size_t a_id_len;
|
||||
u8 *i_id;
|
||||
size_t i_id_len;
|
||||
u8 *a_id_info;
|
||||
size_t a_id_info_len;
|
||||
u16 pac_type;
|
||||
};
|
||||
|
||||
|
||||
void eap_fast_free_pac(struct eap_fast_pac *pac);
|
||||
struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_pac *pac_root,
|
||||
const u8 *a_id, size_t a_id_len,
|
||||
u16 pac_type);
|
||||
int eap_fast_add_pac(struct eap_fast_pac **pac_root,
|
||||
struct eap_fast_pac **pac_current,
|
||||
struct eap_fast_pac *entry);
|
||||
int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root,
|
||||
const char *pac_file);
|
||||
int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_pac *pac_root,
|
||||
const char *pac_file);
|
||||
size_t eap_fast_pac_list_truncate(struct eap_fast_pac *pac_root,
|
||||
size_t max_len);
|
||||
int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root,
|
||||
const char *pac_file);
|
||||
int eap_fast_save_pac_bin(struct eap_sm *sm, struct eap_fast_pac *pac_root,
|
||||
const char *pac_file);
|
||||
|
||||
#endif /* EAP_FAST_PAC_H */
|
@ -263,8 +263,9 @@ struct eap_method {
|
||||
#define CLIENT_CERT_NAME "CLC"
|
||||
#define CA_CERT_NAME "CAC"
|
||||
#define PRIVATE_KEY_NAME "PVK"
|
||||
#define PAC_FILE_NAME "PAC"
|
||||
#define BLOB_NAME_LEN 3
|
||||
#define BLOB_NUM 3
|
||||
#define BLOB_NUM 4
|
||||
|
||||
enum SIG_WPA2 {
|
||||
SIG_WPA2_START = 0,
|
||||
@ -282,6 +283,7 @@ struct eap_sm {
|
||||
void *eap_method_priv;
|
||||
int init_phase2;
|
||||
|
||||
void *msg_ctx;
|
||||
void *ssl_ctx;
|
||||
|
||||
unsigned int workaround;
|
||||
@ -296,6 +298,12 @@ struct eap_sm {
|
||||
#endif
|
||||
u8 finish_state;
|
||||
|
||||
/* Optional challenges generated in Phase 1 (EAP-FAST) */
|
||||
u8 *peer_challenge, *auth_challenge;
|
||||
|
||||
unsigned int expected_failure:1;
|
||||
unsigned int ext_cert_check:1;
|
||||
unsigned int waiting_ext_cert_check:1;
|
||||
bool peap_done;
|
||||
|
||||
u8 *eapKeyData;
|
||||
@ -319,6 +327,7 @@ const char * eap_get_config_phase1(struct eap_sm *sm);
|
||||
const char * eap_get_config_phase2(struct eap_sm *sm);
|
||||
int eap_get_config_fragment_size(struct eap_sm *sm);
|
||||
struct eap_peer_config * eap_get_config(struct eap_sm *sm);
|
||||
void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob);
|
||||
const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm, const char *name);
|
||||
bool wifi_sta_get_enterprise_disable_time_check(void);
|
||||
|
||||
|
@ -30,6 +30,7 @@ void eap_peer_unregister_methods(void);
|
||||
int eap_peer_tls_register(void);
|
||||
int eap_peer_peap_register(void);
|
||||
int eap_peer_ttls_register(void);
|
||||
int eap_peer_fast_register(void);
|
||||
int eap_peer_mschapv2_register(void);
|
||||
|
||||
void eap_peer_unregister_methods(void);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "eap_peer/eap_config.h"
|
||||
#include "eap_peer/mschapv2.h"
|
||||
#include "eap_peer/eap_methods.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
|
||||
#define MSCHAPV2_OP_CHALLENGE 1
|
||||
#define MSCHAPV2_OP_RESPONSE 2
|
||||
@ -104,6 +105,24 @@ eap_mschapv2_init(struct eap_sm *sm)
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
if (sm->peer_challenge) {
|
||||
data->peer_challenge = os_memdup(sm->peer_challenge,
|
||||
MSCHAPV2_CHAL_LEN);
|
||||
if (data->peer_challenge == NULL) {
|
||||
eap_mschapv2_deinit(sm, data);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (sm->auth_challenge) {
|
||||
data->auth_challenge = os_memdup(sm->auth_challenge,
|
||||
MSCHAPV2_CHAL_LEN);
|
||||
if (data->auth_challenge == NULL) {
|
||||
eap_mschapv2_deinit(sm, data);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
data->phase2 = sm->init_phase2;
|
||||
|
||||
return data;
|
||||
@ -139,8 +158,15 @@ eap_mschapv2_challenge_reply(
|
||||
ms = wpabuf_put(resp, sizeof(*ms));
|
||||
ms->op_code = MSCHAPV2_OP_RESPONSE;
|
||||
ms->mschapv2_id = mschapv2_id;
|
||||
if (data->prev_error)
|
||||
if (data->prev_error) {
|
||||
/*
|
||||
* TODO: this does not seem to be enough when processing two
|
||||
* or more failure messages. IAS did not increment mschapv2_id
|
||||
* in its own packets, but it seemed to expect the peer to
|
||||
* increment this for all packets(?).
|
||||
*/
|
||||
ms->mschapv2_id++;
|
||||
}
|
||||
WPA_PUT_BE16(ms->ms_length, ms_len);
|
||||
wpabuf_put_u8(resp, sizeof(*r));
|
||||
|
||||
@ -148,33 +174,53 @@ eap_mschapv2_challenge_reply(
|
||||
r = wpabuf_put(resp, sizeof(*r));
|
||||
peer_challenge = r->peer_challenge;
|
||||
if (data->peer_challenge) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated "
|
||||
"in Phase 1");
|
||||
peer_challenge = data->peer_challenge;
|
||||
os_memset(r->peer_challenge, 0, MSCHAPV2_CHAL_LEN);
|
||||
os_memset(r->peer_challenge, 0, MSCHAPV2_CHAL_LEN);
|
||||
} else if (random_get_bytes(peer_challenge, MSCHAPV2_CHAL_LEN)) {
|
||||
wpabuf_free(resp);
|
||||
return NULL;
|
||||
}
|
||||
os_memset(r->reserved, 0, 8);
|
||||
if (data->auth_challenge)
|
||||
if (data->auth_challenge) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated "
|
||||
"in Phase 1");
|
||||
auth_challenge = data->auth_challenge;
|
||||
}
|
||||
if (mschapv2_derive_response(identity, identity_len, password,
|
||||
password_len, pwhash, auth_challenge,
|
||||
peer_challenge, r->nt_response,
|
||||
data->auth_response, data->master_key)) {
|
||||
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to derive "
|
||||
"response");
|
||||
wpabuf_free(resp);
|
||||
return NULL;
|
||||
}
|
||||
data->auth_response_valid = 1;
|
||||
data->master_key_valid = 1;
|
||||
|
||||
r->flags = 0;
|
||||
r->flags = 0; /* reserved, must be zero */
|
||||
|
||||
wpabuf_put_data(resp, identity, identity_len);
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
|
||||
"(response)", id, ms->mschapv2_id);
|
||||
return resp;
|
||||
}
|
||||
|
||||
static struct wpabuf *
|
||||
eap_mschapv2_challenge(
|
||||
|
||||
/**
|
||||
* eap_mschapv2_process - Process an EAP-MSCHAPv2 challenge message
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @data: Pointer to private EAP method data from eap_mschapv2_init()
|
||||
* @ret: Return values from EAP request validation and processing
|
||||
* @req: Pointer to EAP-MSCHAPv2 header from the request
|
||||
* @req_len: Length of the EAP-MSCHAPv2 data
|
||||
* @id: EAP identifier used in the request
|
||||
* Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
|
||||
* no reply available
|
||||
*/
|
||||
static struct wpabuf * eap_mschapv2_challenge(
|
||||
struct eap_sm *sm, struct eap_mschapv2_data *data,
|
||||
struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req,
|
||||
size_t req_len, u8 id)
|
||||
@ -186,7 +232,10 @@ eap_mschapv2_challenge(
|
||||
eap_get_config_password(sm, &len) == NULL)
|
||||
return NULL;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge");
|
||||
if (req_len < sizeof(*req) + 1) {
|
||||
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge data "
|
||||
"(len %lu)", (unsigned long) req_len);
|
||||
ret->ignore = true;
|
||||
return NULL;
|
||||
}
|
||||
@ -194,21 +243,30 @@ eap_mschapv2_challenge(
|
||||
challenge_len = *pos++;
|
||||
len = req_len - sizeof(*req) - 1;
|
||||
if (challenge_len != MSCHAPV2_CHAL_LEN) {
|
||||
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length "
|
||||
"%lu", (unsigned long) challenge_len);
|
||||
ret->ignore = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (len < challenge_len) {
|
||||
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
|
||||
" packet: len=%lu challenge_len=%lu",
|
||||
(unsigned long) len, (unsigned long) challenge_len);
|
||||
ret->ignore = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (data->passwd_change_challenge_valid)
|
||||
if (data->passwd_change_challenge_valid) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using challenge from the "
|
||||
"failure message");
|
||||
challenge = data->passwd_change_challenge;
|
||||
else
|
||||
} else
|
||||
challenge = pos;
|
||||
pos += challenge_len;
|
||||
len -= challenge_len;
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername",
|
||||
pos, len);
|
||||
|
||||
ret->ignore = false;
|
||||
ret->methodState = METHOD_MAY_CONT;
|
||||
@ -225,9 +283,13 @@ eap_mschapv2_password_changed(struct eap_sm *sm,
|
||||
{
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
if (config && config->new_password) {
|
||||
wpa_msg(sm->msg_ctx, MSG_INFO,
|
||||
WPA_EVENT_PASSWORD_CHANGED
|
||||
"EAP-MSCHAPV2: Password changed successfully");
|
||||
data->prev_error = 0;
|
||||
os_free(config->password);
|
||||
if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
|
||||
/* TODO: update external storage */
|
||||
} else if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) {
|
||||
config->password = os_malloc(16);
|
||||
config->password_len = 16;
|
||||
@ -257,11 +319,14 @@ eap_mschapv2_success(struct eap_sm *sm,
|
||||
const u8 *pos;
|
||||
size_t len;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received success");
|
||||
len = req_len - sizeof(*req);
|
||||
pos = (const u8 *)(req + 1);
|
||||
pos = (const u8 *) (req + 1);
|
||||
if (!data->auth_response_valid ||
|
||||
mschapv2_verify_auth_response(data->auth_response, pos, len)) {
|
||||
ret->methodState = METHOD_NONE;
|
||||
wpa_printf(MSG_WARNING, "EAP-MSCHAPV2: Invalid authenticator "
|
||||
"response in success request");
|
||||
ret->methodState = METHOD_DONE;
|
||||
ret->decision = DECISION_FAIL;
|
||||
return NULL;
|
||||
}
|
||||
@ -271,15 +336,23 @@ eap_mschapv2_success(struct eap_sm *sm,
|
||||
pos++;
|
||||
len--;
|
||||
}
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Success message",
|
||||
pos, len);
|
||||
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Authentication succeeded");
|
||||
|
||||
/* Note: Only op_code of the EAP-MSCHAPV2 header is included in success
|
||||
* message. */
|
||||
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1,
|
||||
EAP_CODE_RESPONSE, id);
|
||||
if (resp == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Failed to allocate "
|
||||
"buffer for success response");
|
||||
ret->ignore = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wpabuf_put_u8(resp, MSCHAPV2_OP_SUCCESS);
|
||||
wpabuf_put_u8(resp, MSCHAPV2_OP_SUCCESS); /* op_code */
|
||||
|
||||
ret->methodState = METHOD_DONE;
|
||||
ret->decision = DECISION_UNCOND_SUCC;
|
||||
ret->allowNotifications = false;
|
||||
@ -291,19 +364,25 @@ eap_mschapv2_success(struct eap_sm *sm,
|
||||
return resp;
|
||||
}
|
||||
|
||||
static int
|
||||
eap_mschapv2_failure_txt(struct eap_sm *sm,
|
||||
struct eap_mschapv2_data *data, char *txt)
|
||||
|
||||
static int eap_mschapv2_failure_txt(struct eap_sm *sm,
|
||||
struct eap_mschapv2_data *data, char *txt)
|
||||
{
|
||||
char *pos;
|
||||
char *pos = "";
|
||||
int retry = 1;
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
|
||||
/* For example:
|
||||
* E=691 R=1 C=<32 octets hex challenge> V=3 M=Authentication Failure
|
||||
*/
|
||||
|
||||
pos = txt;
|
||||
|
||||
if (pos && os_strncmp(pos, "E=", 2) == 0) {
|
||||
pos += 2;
|
||||
data->prev_error = atoi(pos);
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: error %d",
|
||||
data->prev_error);
|
||||
pos = (char *)os_strchr(pos, ' ');
|
||||
if (pos)
|
||||
pos++;
|
||||
@ -312,6 +391,8 @@ eap_mschapv2_failure_txt(struct eap_sm *sm,
|
||||
if (pos && os_strncmp(pos, "R=", 2) == 0) {
|
||||
pos += 2;
|
||||
retry = atoi(pos);
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: retry is %sallowed",
|
||||
retry == 1 ? "" : "not ");
|
||||
pos = (char *)os_strchr(pos, ' ');
|
||||
if (pos)
|
||||
pos++;
|
||||
@ -324,19 +405,32 @@ eap_mschapv2_failure_txt(struct eap_sm *sm,
|
||||
if (hex_len == PASSWD_CHANGE_CHAL_LEN * 2) {
|
||||
if (hexstr2bin(pos, data->passwd_change_challenge,
|
||||
PASSWD_CHANGE_CHAL_LEN)) {
|
||||
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: invalid failure challenge\n");
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid "
|
||||
"failure challenge");
|
||||
} else {
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: failure "
|
||||
"challenge",
|
||||
data->passwd_change_challenge,
|
||||
PASSWD_CHANGE_CHAL_LEN);
|
||||
data->passwd_change_challenge_valid = 1;
|
||||
}
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: required challenge field "
|
||||
"was not present in failure message\n");
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid failure "
|
||||
"challenge len %d", hex_len);
|
||||
}
|
||||
pos = os_strchr(pos, ' ');
|
||||
if (pos)
|
||||
pos++;
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: required challenge field "
|
||||
"was not present in failure message");
|
||||
}
|
||||
|
||||
if (pos && os_strncmp(pos, "V=", 2) == 0) {
|
||||
pos += 2;
|
||||
data->passwd_change_version = atoi(pos);
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: password changing "
|
||||
"protocol version %d", data->passwd_change_version);
|
||||
pos = (char *)os_strchr(pos, ' ');
|
||||
if (pos)
|
||||
pos++;
|
||||
@ -345,24 +439,38 @@ eap_mschapv2_failure_txt(struct eap_sm *sm,
|
||||
if (pos && os_strncmp(pos, "M=", 2) == 0) {
|
||||
pos += 2;
|
||||
}
|
||||
if (data->prev_error == ERROR_AUTHENTICATION_FAILURE && retry &&
|
||||
config && config->phase2 &&
|
||||
os_strstr(config->phase2, "mschapv2_retry=0")) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"EAP-MSCHAPV2: mark password retry disabled based on local configuration");
|
||||
retry = 0;
|
||||
}
|
||||
if (data->prev_error == ERROR_PASSWD_EXPIRED &&
|
||||
data->passwd_change_version == 3 && config) {
|
||||
if (config->new_password == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Password expired - "
|
||||
"password change reqired\n");
|
||||
wpa_msg(sm->msg_ctx, MSG_INFO,
|
||||
"EAP-MSCHAPV2: Password expired - password "
|
||||
"change required");
|
||||
eap_sm_request_new_password(sm);
|
||||
}
|
||||
} else if (retry == 1 && config) {
|
||||
/* TODO: could prevent the current password from being used
|
||||
* again at least for some period of time */
|
||||
if (!config->mschapv2_retry)
|
||||
eap_sm_request_identity(sm);
|
||||
eap_sm_request_password(sm);
|
||||
config->mschapv2_retry = 1;
|
||||
} else if (config) {
|
||||
/* TODO: prevent retries using same username/password */
|
||||
config->mschapv2_retry = 0;
|
||||
}
|
||||
|
||||
return retry == 1;
|
||||
}
|
||||
|
||||
static struct wpabuf *
|
||||
eap_mschapv2_change_password(
|
||||
|
||||
static struct wpabuf * eap_mschapv2_change_password(
|
||||
struct eap_sm *sm, struct eap_mschapv2_data *data,
|
||||
struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, u8 id)
|
||||
{
|
||||
@ -393,46 +501,67 @@ eap_mschapv2_change_password(
|
||||
EAP_CODE_RESPONSE, id);
|
||||
if (resp == NULL)
|
||||
return NULL;
|
||||
|
||||
ms = wpabuf_put(resp, sizeof(*ms));
|
||||
ms->op_code = MSCHAPV2_OP_CHANGE_PASSWORD;
|
||||
ms->mschapv2_id = req->mschapv2_id + 1;
|
||||
WPA_PUT_BE16(ms->ms_length, ms_len);
|
||||
cp = wpabuf_put(resp, sizeof(*cp));
|
||||
|
||||
/* Encrypted-Password */
|
||||
if (pwhash) {
|
||||
if (encrypt_pw_block_with_password_hash(
|
||||
new_password, new_password_len,
|
||||
password, cp->encr_password))
|
||||
new_password, new_password_len,
|
||||
password, cp->encr_password))
|
||||
goto fail;
|
||||
} else {
|
||||
if (new_password_encrypted_with_old_nt_password_hash(
|
||||
new_password, new_password_len,
|
||||
password, password_len, cp->encr_password))
|
||||
new_password, new_password_len,
|
||||
password, password_len, cp->encr_password))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Encrypted-Hash */
|
||||
if (pwhash) {
|
||||
u8 new_password_hash[16];
|
||||
nt_password_hash(new_password, new_password_len,
|
||||
new_password_hash);
|
||||
nt_password_hash_encrypted_with_block(password,
|
||||
new_password_hash,
|
||||
cp->encr_hash);
|
||||
if (nt_password_hash(new_password, new_password_len,
|
||||
new_password_hash) ||
|
||||
nt_password_hash_encrypted_with_block(password,
|
||||
new_password_hash,
|
||||
cp->encr_hash))
|
||||
goto fail;
|
||||
} else {
|
||||
old_nt_password_hash_encrypted_with_new_nt_password_hash(
|
||||
new_password, new_password_len,
|
||||
password, password_len, cp->encr_hash);
|
||||
if (old_nt_password_hash_encrypted_with_new_nt_password_hash(
|
||||
new_password, new_password_len,
|
||||
password, password_len, cp->encr_hash))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Peer-Challenge */
|
||||
if (random_get_bytes(cp->peer_challenge, MSCHAPV2_CHAL_LEN))
|
||||
goto fail;
|
||||
|
||||
/* Reserved, must be zero */
|
||||
os_memset(cp->reserved, 0, 8);
|
||||
|
||||
/* NT-Response */
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge",
|
||||
data->passwd_change_challenge, PASSWD_CHANGE_CHAL_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge",
|
||||
cp->peer_challenge, MSCHAPV2_CHAL_LEN);
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username",
|
||||
username, username_len);
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: new password",
|
||||
new_password, new_password_len);
|
||||
generate_nt_response(data->passwd_change_challenge, cp->peer_challenge,
|
||||
username, username_len, new_password,
|
||||
new_password_len, cp->nt_response);
|
||||
username, username_len,
|
||||
new_password, new_password_len,
|
||||
cp->nt_response);
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: NT-Response",
|
||||
cp->nt_response, MSCHAPV2_NT_RESPONSE_LEN);
|
||||
|
||||
/* Authenticator response is not really needed yet, but calculate it
|
||||
* here so that challenges need not be saved. */
|
||||
generate_authenticator_response(new_password, new_password_len,
|
||||
cp->peer_challenge,
|
||||
data->passwd_change_challenge,
|
||||
@ -440,13 +569,23 @@ eap_mschapv2_change_password(
|
||||
cp->nt_response, data->auth_response);
|
||||
data->auth_response_valid = 1;
|
||||
|
||||
nt_password_hash(new_password, new_password_len, password_hash);
|
||||
hash_nt_password_hash(password_hash, password_hash_hash);
|
||||
get_master_key(password_hash_hash, cp->nt_response, data->master_key);
|
||||
/* Likewise, generate master_key here since we have the needed data
|
||||
* available. */
|
||||
if (nt_password_hash(new_password, new_password_len, password_hash) ||
|
||||
hash_nt_password_hash(password_hash, password_hash_hash) ||
|
||||
get_master_key(password_hash_hash, cp->nt_response,
|
||||
data->master_key)) {
|
||||
data->auth_response_valid = 0;
|
||||
goto fail;
|
||||
}
|
||||
data->master_key_valid = 1;
|
||||
|
||||
/* Flags */
|
||||
os_memset(cp->flags, 0, 2);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
|
||||
"(change pw)", id, ms->mschapv2_id);
|
||||
|
||||
return resp;
|
||||
|
||||
fail:
|
||||
@ -454,19 +593,38 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct wpabuf *
|
||||
eap_mschapv2_failure(struct eap_sm *sm,
|
||||
struct eap_mschapv2_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
const struct eap_mschapv2_hdr *req,
|
||||
size_t req_len, u8 id)
|
||||
|
||||
/**
|
||||
* eap_mschapv2_process - Process an EAP-MSCHAPv2 failure message
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @data: Pointer to private EAP method data from eap_mschapv2_init()
|
||||
* @ret: Return values from EAP request validation and processing
|
||||
* @req: Pointer to EAP-MSCHAPv2 header from the request
|
||||
* @req_len: Length of the EAP-MSCHAPv2 data
|
||||
* @id: EAP identifier used in th erequest
|
||||
* Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
|
||||
* no reply available
|
||||
*/
|
||||
static struct wpabuf * eap_mschapv2_failure(struct eap_sm *sm,
|
||||
struct eap_mschapv2_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
const struct eap_mschapv2_hdr *req,
|
||||
size_t req_len, u8 id)
|
||||
{
|
||||
struct wpabuf *resp;
|
||||
const u8 *msdata = (const u8 *)(req + 1);
|
||||
const u8 *msdata = (const u8 *) (req + 1);
|
||||
char *buf;
|
||||
size_t len = req_len - sizeof(*req);
|
||||
int retry = 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received failure");
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Failure data",
|
||||
msdata, len);
|
||||
/*
|
||||
* eap_mschapv2_failure_txt() expects a nul terminated string, so we
|
||||
* must allocate a large enough temporary buffer to create that since
|
||||
* the received message does not include nul termination.
|
||||
*/
|
||||
buf = (char *)dup_binstr(msdata, len);
|
||||
if (buf) {
|
||||
retry = eap_mschapv2_failure_txt(sm, data, buf);
|
||||
@ -482,23 +640,31 @@ eap_mschapv2_failure(struct eap_sm *sm,
|
||||
data->passwd_change_version == 3) {
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
if (config && config->new_password)
|
||||
return eap_mschapv2_change_password(sm, data, ret,
|
||||
req, id);
|
||||
return eap_mschapv2_change_password(sm, data, ret, req,
|
||||
id);
|
||||
if (config && config->pending_req_new_password)
|
||||
return NULL;
|
||||
} else if (retry && data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
|
||||
/* TODO: could try to retry authentication, e.g, after having
|
||||
* changed the username/password. In this case, EAP MS-CHAP-v2
|
||||
* Failure Response would not be sent here. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Note: Only op_code of the EAP-MSCHAPV2 header is included in failure
|
||||
* message. */
|
||||
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1,
|
||||
EAP_CODE_RESPONSE, id);
|
||||
if (resp == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_put_u8(resp, MSCHAPV2_OP_FAILURE);
|
||||
wpabuf_put_u8(resp, MSCHAPV2_OP_FAILURE); /* op_code */
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
static int
|
||||
eap_mschapv2_check_config(struct eap_sm *sm)
|
||||
|
||||
static int eap_mschapv2_check_config(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
|
||||
@ -520,19 +686,24 @@ eap_mschapv2_check_config(struct eap_sm *sm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
eap_mschapv2_check_mslen(struct eap_sm *sm, size_t len,
|
||||
const struct eap_mschapv2_hdr *ms)
|
||||
|
||||
static int eap_mschapv2_check_mslen(struct eap_sm *sm, size_t len,
|
||||
const struct eap_mschapv2_hdr *ms)
|
||||
{
|
||||
size_t ms_len = WPA_GET_BE16(ms->ms_length);
|
||||
|
||||
if (ms_len == len)
|
||||
return 0;
|
||||
|
||||
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%lu "
|
||||
"ms_len=%lu", (unsigned long) len, (unsigned long) ms_len);
|
||||
if (sm->workaround) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Workaround, ignore Invalid"
|
||||
" header len=%lu ms_len=%lu\n",
|
||||
(unsigned long)len, (unsigned long)ms_len);
|
||||
/* Some authentication servers use invalid ms_len,
|
||||
* ignore it for interoperability. */
|
||||
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: workaround, ignore"
|
||||
" invalid ms_len %lu (len %lu)",
|
||||
(unsigned long) ms_len,
|
||||
(unsigned long) len);
|
||||
return 0;
|
||||
}
|
||||
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Invalid header len=%lu ms_len=%lu\n",
|
||||
@ -541,18 +712,31 @@ eap_mschapv2_check_mslen(struct eap_sm *sm, size_t len,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
eap_mschapv2_copy_challenge(struct eap_mschapv2_data *data,
|
||||
const struct wpabuf *reqData)
|
||||
|
||||
static void eap_mschapv2_copy_challenge(struct eap_mschapv2_data *data,
|
||||
const struct wpabuf *reqData)
|
||||
{
|
||||
/*
|
||||
* Store a copy of the challenge message, so that it can be processed
|
||||
* again in case retry is allowed after a possible failure.
|
||||
*/
|
||||
wpabuf_free(data->prev_challenge);
|
||||
data->prev_challenge = wpabuf_dup(reqData);
|
||||
}
|
||||
|
||||
static struct wpabuf *
|
||||
eap_mschapv2_process(struct eap_sm *sm, void *priv,
|
||||
struct eap_method_ret *ret,
|
||||
const struct wpabuf *reqData)
|
||||
|
||||
/**
|
||||
* eap_mschapv2_process - Process an EAP-MSCHAPv2 request
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @priv: Pointer to private EAP method data from eap_mschapv2_init()
|
||||
* @ret: Return values from EAP request validation and processing
|
||||
* @reqData: EAP request to be processed (eapReqData)
|
||||
* Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
|
||||
* no reply available
|
||||
*/
|
||||
static struct wpabuf * eap_mschapv2_process(struct eap_sm *sm, void *priv,
|
||||
struct eap_method_ret *ret,
|
||||
const struct wpabuf *reqData)
|
||||
{
|
||||
u8 id;
|
||||
size_t len;
|
||||
@ -569,27 +753,31 @@ eap_mschapv2_process(struct eap_sm *sm, void *priv,
|
||||
|
||||
if (config->mschapv2_retry && data->prev_challenge &&
|
||||
data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Replacing pending packet "
|
||||
"with the previous challenge");
|
||||
|
||||
reqData = data->prev_challenge;
|
||||
using_prev_challenge = 1;
|
||||
config->mschapv2_retry = 0;
|
||||
}
|
||||
|
||||
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
|
||||
reqData, &len);
|
||||
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqData,
|
||||
&len);
|
||||
if (pos == NULL || len < sizeof(*ms) + 1) {
|
||||
ret->ignore = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ms = (const struct eap_mschapv2_hdr *)pos;
|
||||
ms = (const struct eap_mschapv2_hdr *) pos;
|
||||
if (eap_mschapv2_check_mslen(sm, len, ms)) {
|
||||
ret->ignore = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
id = eap_get_id(reqData);
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: RX identifier %d mschapv2_id %d\n",
|
||||
id, ms->mschapv2_id);
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: RX identifier %d mschapv2_id %d",
|
||||
id, ms->mschapv2_id);
|
||||
|
||||
switch (ms->op_code) {
|
||||
case MSCHAPV2_OP_CHALLENGE:
|
||||
if (!using_prev_challenge)
|
||||
@ -602,19 +790,20 @@ eap_mschapv2_process(struct eap_sm *sm, void *priv,
|
||||
default:
|
||||
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Unknown op code %d - ignored\n",
|
||||
ms->op_code);
|
||||
ret->ignore = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)
|
||||
|
||||
static bool eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_mschapv2_data *data = priv;
|
||||
return data->success && data->master_key_valid;
|
||||
}
|
||||
|
||||
static u8 *
|
||||
eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
|
||||
|
||||
static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
|
||||
{
|
||||
struct eap_mschapv2_data *data = priv;
|
||||
u8 *key;
|
||||
@ -626,20 +815,31 @@ eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
|
||||
key_len = 2 * MSCHAPV2_KEY_LEN;
|
||||
|
||||
key = os_malloc(key_len);
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
|
||||
/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key,
|
||||
* peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */
|
||||
get_asymetric_start_key(data->master_key, key,
|
||||
MSCHAPV2_KEY_LEN, 1, 0);
|
||||
/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e.,
|
||||
* peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */
|
||||
get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, 0);
|
||||
get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
|
||||
MSCHAPV2_KEY_LEN, 0, 0);
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key",
|
||||
key, key_len);
|
||||
|
||||
*len = key_len;
|
||||
return key;
|
||||
}
|
||||
|
||||
int
|
||||
eap_peer_mschapv2_register(void)
|
||||
|
||||
/**
|
||||
* eap_peer_mschapv2_register - Register EAP-MSCHAPv2 peer method
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This function is used to register EAP-MSCHAPv2 peer method into the EAP
|
||||
* method list.
|
||||
*/
|
||||
int eap_peer_mschapv2_register(void)
|
||||
{
|
||||
struct eap_method *eap;
|
||||
int ret;
|
||||
|
@ -16,6 +16,10 @@
|
||||
#include "eap_peer/eap_config.h"
|
||||
#include "eap_peer/eap_methods.h"
|
||||
|
||||
|
||||
static void eap_tls_deinit(struct eap_sm *sm, void *priv);
|
||||
|
||||
|
||||
struct eap_tls_data {
|
||||
struct eap_ssl_data ssl;
|
||||
u8 *key_data;
|
||||
@ -26,19 +30,6 @@ struct eap_tls_data {
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void eap_tls_deinit(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
if (data == NULL)
|
||||
return;
|
||||
eap_peer_tls_ssl_deinit(sm, &data->ssl);
|
||||
os_free(data->key_data);
|
||||
os_free(data->session_id);
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
||||
static void * eap_tls_init(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_tls_data *data;
|
||||
@ -66,6 +57,19 @@ static void * eap_tls_init(struct eap_sm *sm)
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static void eap_tls_deinit(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
if (data == NULL)
|
||||
return;
|
||||
eap_peer_tls_ssl_deinit(sm, &data->ssl);
|
||||
os_free(data->key_data);
|
||||
os_free(data->session_id);
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * eap_tls_failure(struct eap_sm *sm,
|
||||
struct eap_tls_data *data,
|
||||
struct eap_method_ret *ret, int res,
|
||||
|
@ -107,6 +107,10 @@ static int eap_tls_params_from_conf(struct eap_sm *sm,
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLS: using phase1 config options");
|
||||
eap_tls_params_from_conf1(params, config);
|
||||
if (data->eap_type == EAP_TYPE_FAST) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-TYPE == EAP-FAST #####################################");
|
||||
params->flags |= TLS_CONN_EAP_FAST;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use blob data, if available. Otherwise, leave reference to external
|
||||
@ -259,7 +263,7 @@ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
|
||||
if (out == NULL)
|
||||
return NULL;
|
||||
|
||||
if (tls_connection_export_key(data->ssl_ctx, data->conn, label, out,
|
||||
if (tls_connection_export_key(data->ssl_ctx, data->conn, label, 0, 0, out,
|
||||
len)) {
|
||||
os_free(out);
|
||||
return NULL;
|
||||
|
@ -14,10 +14,11 @@ const u8 * mschapv2_remove_domain(const u8 *username, size_t *len)
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* MSCHAPV2 does not include optional domain name in the
|
||||
* MSCHAPv2 does not include optional domain name in the
|
||||
* challenge-response calculation, so remove domain prefix
|
||||
* (if present)
|
||||
* (if present).
|
||||
*/
|
||||
|
||||
for (i = 0; i < *len; i++) {
|
||||
if (username[i] == '\\') {
|
||||
*len -= i + 1;
|
||||
@ -28,31 +29,48 @@ const u8 * mschapv2_remove_domain(const u8 *username, size_t *len)
|
||||
return username;
|
||||
}
|
||||
|
||||
|
||||
int mschapv2_derive_response(const u8 *identity, size_t identity_len,
|
||||
const u8 *password, size_t password_len,
|
||||
int pwhash,
|
||||
const u8 *auth_challenge,
|
||||
const u8 *peer_challenge,
|
||||
u8 *nt_response, u8 *auth_response,
|
||||
u8 *master_key)
|
||||
const u8 *password, size_t password_len,
|
||||
int pwhash,
|
||||
const u8 *auth_challenge,
|
||||
const u8 *peer_challenge,
|
||||
u8 *nt_response, u8 *auth_response,
|
||||
u8 *master_key)
|
||||
{
|
||||
const u8 *username;
|
||||
size_t username_len;
|
||||
u8 password_hash[16], password_hash_hash[16];
|
||||
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Identity",
|
||||
identity, identity_len);
|
||||
username_len = identity_len;
|
||||
username = mschapv2_remove_domain(identity, &username_len);
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Username",
|
||||
username, username_len);
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "MSCHAPV2: auth_challenge",
|
||||
auth_challenge, MSCHAPV2_CHAL_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "MSCHAPV2: peer_challenge",
|
||||
peer_challenge, MSCHAPV2_CHAL_LEN);
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: username",
|
||||
username, username_len);
|
||||
/* Authenticator response is not really needed yet, but calculate it
|
||||
* here so that challenges need not be saved. */
|
||||
if (pwhash) {
|
||||
wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash",
|
||||
password, password_len);
|
||||
if (generate_nt_response_pwhash(auth_challenge, peer_challenge,
|
||||
username, username_len,
|
||||
password, nt_response) ||
|
||||
generate_authenticator_response_pwhash(
|
||||
password, peer_challenge, auth_challenge,
|
||||
username, username_len, nt_response,
|
||||
auth_response))
|
||||
password, peer_challenge, auth_challenge,
|
||||
username, username_len, nt_response,
|
||||
auth_response))
|
||||
return -1;
|
||||
} else {
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password",
|
||||
password, password_len);
|
||||
if (generate_nt_response(auth_challenge, peer_challenge,
|
||||
username, username_len,
|
||||
password, password_len,
|
||||
@ -65,7 +83,12 @@ int mschapv2_derive_response(const u8 *identity, size_t identity_len,
|
||||
auth_response))
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response",
|
||||
nt_response, MSCHAPV2_NT_RESPONSE_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response",
|
||||
auth_response, MSCHAPV2_AUTH_RESPONSE_LEN);
|
||||
|
||||
/* Generate master_key here since we have the needed data available. */
|
||||
if (pwhash) {
|
||||
if (hash_nt_password_hash(password, password_hash_hash))
|
||||
return -1;
|
||||
@ -76,17 +99,20 @@ int mschapv2_derive_response(const u8 *identity, size_t identity_len,
|
||||
}
|
||||
if (get_master_key(password_hash_hash, nt_response, master_key))
|
||||
return -1;
|
||||
wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key",
|
||||
master_key, MSCHAPV2_MASTER_KEY_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int mschapv2_verify_auth_response(const u8 *auth_response,
|
||||
const u8 *buf, size_t buf_len)
|
||||
const u8 *buf, size_t buf_len)
|
||||
{
|
||||
u8 recv_response[MSCHAPV2_AUTH_RESPONSE_LEN];
|
||||
if (buf_len < 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN ||
|
||||
buf[0] != 'S' || buf[1] != '=' ||
|
||||
hexstr2bin((char *)(buf + 2), recv_response,
|
||||
hexstr2bin((char *) (buf + 2), recv_response,
|
||||
MSCHAPV2_AUTH_RESPONSE_LEN) ||
|
||||
os_memcmp(auth_response, recv_response,
|
||||
MSCHAPV2_AUTH_RESPONSE_LEN) != 0)
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
* WPA Supplicant - WPA state machine and EAPOL-Key processing
|
||||
* Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
|
||||
@ -12,6 +11,7 @@
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
|
@ -83,6 +83,7 @@ struct tls_config {
|
||||
#define TLS_CONN_REQUEST_OCSP BIT(3)
|
||||
#define TLS_CONN_REQUIRE_OCSP BIT(4)
|
||||
#define TLS_CONN_SUITEB BIT(11)
|
||||
#define TLS_CONN_EAP_FAST BIT(7)
|
||||
|
||||
/**
|
||||
* struct tls_connection_params - Parameters for TLS connection
|
||||
@ -279,17 +280,23 @@ int __must_check tls_global_set_verify(void *tls_ctx, int check_crl);
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @verify_peer: 1 = verify peer certificate
|
||||
* @flags: Connection flags (TLS_CONN_*)
|
||||
* @session_ctx: Session caching context or %NULL to use default
|
||||
* @session_ctx_len: Length of @session_ctx in bytes.
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int __must_check tls_connection_set_verify(void *tls_ctx,
|
||||
int tls_connection_set_verify(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
int verify_peer);
|
||||
int verify_peer,
|
||||
unsigned int flags,
|
||||
const u8 *session_ctx,
|
||||
size_t session_ctx_len);
|
||||
|
||||
/**
|
||||
* tls_connection_get_random - Get random data from TLS connection
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @keys: Structure of key/random data (filled on success)
|
||||
* @data: Structure of client/server random data (filled on success)
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int __must_check tls_connection_get_random(void *tls_ctx,
|
||||
@ -301,17 +308,39 @@ int __must_check tls_connection_get_random(void *tls_ctx,
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @label: Label (e.g., description of the key) for PRF
|
||||
* @context: Optional extra upper-layer context (max len 2^16)
|
||||
* @context_len: The length of the context value
|
||||
* @out: Buffer for output data from TLS-PRF
|
||||
* @out_len: Length of the output buffer
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* Exports keying material using the mechanism described in RFC 5705.
|
||||
* Exports keying material using the mechanism described in RFC 5705. If
|
||||
* context is %NULL, context is not provided; otherwise, context is provided
|
||||
* (including the case of empty context with context_len == 0).
|
||||
*/
|
||||
int __must_check tls_connection_export_key(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const char *label,
|
||||
const u8 *context,
|
||||
size_t context_len,
|
||||
u8 *out, size_t out_len);
|
||||
|
||||
/**
|
||||
* tls_connection_get_eap_fast_key - Derive key material for EAP-FAST
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @out: Buffer for output data from TLS-PRF
|
||||
* @out_len: Length of the output buffer
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* Exports key material after the normal TLS key block for use with
|
||||
* EAP-FAST. Most callers will want tls_connection_export_key(), but EAP-FAST
|
||||
* uses a different legacy mechanism.
|
||||
*/
|
||||
int __must_check tls_connection_get_eap_fast_key(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
u8 *out, size_t out_len);
|
||||
|
||||
/**
|
||||
* tls_connection_handshake - Process TLS handshake (client side)
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
@ -413,7 +442,9 @@ enum {
|
||||
TLS_CIPHER_RC4_SHA /* 0x0005 */,
|
||||
TLS_CIPHER_AES128_SHA /* 0x002f */,
|
||||
TLS_CIPHER_RSA_DHE_AES128_SHA /* 0x0031 */,
|
||||
TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */
|
||||
TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */,
|
||||
TLS_CIPHER_RSA_DHE_AES256_SHA /* 0x0039 */,
|
||||
TLS_CIPHER_AES256_SHA /* 0x0035 */,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -267,7 +267,8 @@ int tls_global_set_verify(void *tls_ctx, int check_crl)
|
||||
|
||||
|
||||
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
|
||||
int verify_peer)
|
||||
int verify_peer, unsigned int flags,
|
||||
const u8 *session_ctx, size_t session_ctx_len)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server)
|
||||
@ -276,6 +277,7 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
|
||||
struct tls_random *data)
|
||||
{
|
||||
@ -290,6 +292,7 @@ int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int tls_get_keyblock_size(struct tls_connection *conn)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
@ -303,8 +306,10 @@ static int tls_get_keyblock_size(struct tls_connection *conn)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *label, int server_random_first,
|
||||
const char *label, const u8 *context,
|
||||
size_t context_len, int server_random_first,
|
||||
int skip_keyblock, u8 *out, size_t out_len)
|
||||
{
|
||||
int ret = -1, skip = 0;
|
||||
@ -320,33 +325,46 @@ static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
|
||||
return -1;
|
||||
_out = tmp_out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (conn->client) {
|
||||
ret = tlsv1_client_prf(conn->client, label,
|
||||
server_random_first,
|
||||
out, out_len);
|
||||
server_random_first,
|
||||
_out, skip + out_len);
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server) {
|
||||
ret = tlsv1_server_prf(conn->server, label,
|
||||
server_random_first,
|
||||
out, out_len);
|
||||
server_random_first,
|
||||
_out, skip + out_len);
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
if (ret == 0 && skip_keyblock)
|
||||
os_memcpy(out, _out + skip, out_len);
|
||||
wpa_bin_clear_free(tmp_out, skip);
|
||||
bin_clear_free(tmp_out, skip);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *label, u8 *out, size_t out_len)
|
||||
const char *label, const u8 *context,
|
||||
size_t context_len, u8 *out, size_t out_len)
|
||||
{
|
||||
return tls_connection_prf(tls_ctx, conn, label, 0, 0, out, out_len);
|
||||
return tls_connection_prf(tls_ctx, conn, label, context, context_len,
|
||||
0, 0, out, out_len);
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
|
||||
u8 *out, size_t out_len)
|
||||
{
|
||||
return tls_connection_prf(tls_ctx, conn, "key expansion", NULL, 0,
|
||||
1, 1, out, out_len);
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_handshake(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const struct wpabuf *in_data,
|
||||
|
@ -207,6 +207,15 @@ void wpabuf_free(struct wpabuf *buf)
|
||||
}
|
||||
|
||||
|
||||
void wpabuf_clear_free(struct wpabuf *buf)
|
||||
{
|
||||
if (buf) {
|
||||
os_memset(wpabuf_mhead(buf), 0, wpabuf_len(buf));
|
||||
wpabuf_free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void * wpabuf_put(struct wpabuf *buf, size_t len)
|
||||
{
|
||||
void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
|
||||
|
9
examples/wifi/wifi_eap_fast/CMakeLists.txt
Normal file
9
examples/wifi/wifi_eap_fast/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
# (Automatically converted from project Makefile by convert_to_cmake.py.)
|
||||
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(wifi_eap_fast)
|
8
examples/wifi/wifi_eap_fast/Makefile
Normal file
8
examples/wifi/wifi_eap_fast/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := wifi_eap_fast
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
67
examples/wifi/wifi_eap_fast/README.md
Normal file
67
examples/wifi/wifi_eap_fast/README.md
Normal file
@ -0,0 +1,67 @@
|
||||
# WPA2 Enterprise Example
|
||||
|
||||
This example shows how ESP32 connects to AP with Wi-Fi enterprise encryption using the EAP-FAST method. The example does the following steps:
|
||||
|
||||
1. Install CA certificate which is optional.
|
||||
2. Set user name and password and identity.
|
||||
3. Set the PAC file which may be empty.
|
||||
4. Enable wpa2 enterprise.
|
||||
5. Connect to AP.
|
||||
|
||||
*Note:* 1. EAP-FAST is not supported with `CONFIG_WPA_MBEDTLS_CRYPTO` and so is disabled by default.
|
||||
2. Setting the config `fast_provisioning` to methods 0 and 1 do not support saving the PAC credentials in case of a restart or loss of power.
|
||||
3. The certificates present in the `examples/wifi/wifi_eap_fast/main` folder contain server certificates which have the corresponding CA as well. These can be used for server validation which is opptional.
|
||||
4. The expiration date of these certificates is 2027/06/05.
|
||||
|
||||
### Configuration
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
* Set SSID of Access Point to connect in Example Configuration.
|
||||
* Enter EAP-ID.
|
||||
* Enter Username and Password.
|
||||
* Enable or disable Validate Server option.
|
||||
|
||||
### Build and Flash the project.
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
### Example output
|
||||
|
||||
Here is an example of wpa2 enterprise (FAST method) console output.
|
||||
```
|
||||
I (690) example: Setting WiFi configuration SSID wpa2_test...
|
||||
I (690) phy_init: phy_version 4670,719f9f6,Feb 18 2021,17:07:07
|
||||
I (800) wifi:mode : sta (24:6f:28:80:41:78)
|
||||
I (800) wifi:enable tsf
|
||||
I (1410) wifi:new:<6,0>, old:<1,0>, ap:<255,255>, sta:<6,0>, prof:1
|
||||
I (2410) wifi:state: init -> auth (b0)
|
||||
I (2420) wifi:state: auth -> assoc (0)
|
||||
E (2420) wifi:Association refused temporarily, comeback time 3072 mSec
|
||||
I (5500) wifi:state: assoc -> assoc (0)
|
||||
I (5500) wifi:state: assoc -> init (6c0)
|
||||
I (5500) wifi:new:<6,0>, old:<6,0>, ap:<255,255>, sta:<6,0>, prof:1
|
||||
I (7560) wifi:new:<6,0>, old:<6,0>, ap:<255,255>, sta:<6,0>, prof:1
|
||||
I (7560) wifi:state: init -> auth (b0)
|
||||
I (7560) wifi:state: auth -> assoc (0)
|
||||
I (7570) wifi:state: assoc -> run (10)
|
||||
I (7770) wifi:connected with wpa2_test, aid = 1, channel 6, BW20, bssid = 24:4b:fe:ab:be:99
|
||||
I (7770) wifi:security: WPA2-ENT, phy: bg, rssi: -80
|
||||
I (7780) wifi:pm start, type: 1
|
||||
|
||||
I (7800) example: ~~~~~~~~~~~
|
||||
I (7800) example: IP:0.0.0.0
|
||||
I (7800) example: MASK:0.0.0.0
|
||||
I (7800) example: GW:0.0.0.0
|
||||
I (7800) example: ~~~~~~~~~~~
|
||||
I (7870) wifi:AP's beacon interval = 102400 us, DTIM period = 1
|
||||
I (8580) esp_netif_handlers: sta ip: 192.168.5.3, mask: 255.255.255.0, gw: 192.168.5.1
|
||||
I (12800) example: ~~~~~~~~~~~
|
||||
I (12800) example: IP:192.168.5.3
|
||||
I (12800) example: MASK:255.255.255.0
|
||||
I (12800) example: GW:192.168.5.1
|
||||
I (12800) example: ~~~~~~~~~~~
|
||||
```
|
4
examples/wifi/wifi_eap_fast/main/CMakeLists.txt
Normal file
4
examples/wifi/wifi_eap_fast/main/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
# Embed CA, certificate & key directly into binary
|
||||
idf_component_register(SRCS "wifi_eap_fast_main.c"
|
||||
INCLUDE_DIRS "."
|
||||
EMBED_TXTFILES ca.pem pac_file.pac)
|
53
examples/wifi/wifi_eap_fast/main/Kconfig.projbuild
Normal file
53
examples/wifi/wifi_eap_fast/main/Kconfig.projbuild
Normal file
@ -0,0 +1,53 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice
|
||||
prompt "Enterprise configuration to be used"
|
||||
default EXAMPLE_WPA_WPA2_ENTERPRISE
|
||||
config EXAMPLE_WPA_WPA2_ENTERPRISE
|
||||
bool "WPA_WPA2_ENT"
|
||||
config EXAMPLE_WPA3_ENTERPRISE
|
||||
bool "WPA3_ENT"
|
||||
depends on IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
|
||||
select ESP_WIFI_GCMP_SUPPORT
|
||||
select ESP_WIFI_GMAC_SUPPORT
|
||||
select WPA_SUITE_B_192
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_WIFI_SSID
|
||||
string "WiFi SSID"
|
||||
default "wpa2_test"
|
||||
help
|
||||
SSID (network name) for the example to connect to.
|
||||
|
||||
if EXAMPLE_WPA_WPA2_ENTERPRISE
|
||||
config EXAMPLE_VALIDATE_SERVER_CERT
|
||||
bool "Validate server"
|
||||
default y
|
||||
help
|
||||
Validate the servers' certificate using CA cert.
|
||||
endif
|
||||
|
||||
if !EXAMPLE_WPA_WPA2_ENTERPRISE
|
||||
config EXAMPLE_VALIDATE_SERVER_CERT
|
||||
default y
|
||||
endif
|
||||
|
||||
config EXAMPLE_EAP_ID
|
||||
string "EAP ID"
|
||||
default "example@espressif.com"
|
||||
help
|
||||
Identity in phase 1 of EAP procedure.
|
||||
|
||||
config EXAMPLE_EAP_USERNAME
|
||||
string "EAP USERNAME"
|
||||
default "espressif"
|
||||
help
|
||||
Username for EAP method.
|
||||
|
||||
config EXAMPLE_EAP_PASSWORD
|
||||
string "EAP PASSWORD"
|
||||
default "test11"
|
||||
help
|
||||
Password for EAP method.
|
||||
|
||||
endmenu
|
23
examples/wifi/wifi_eap_fast/main/ca.pem
Normal file
23
examples/wifi/wifi_eap_fast/main/ca.pem
Normal file
@ -0,0 +1,23 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID3DCCA0WgAwIBAgIJAMnlgL1czsmjMA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD
|
||||
VQQGEwJGUjEPMA0GA1UECAwGUmFkaXVzMRIwEAYDVQQHDAlTb21ld2hlcmUxFTAT
|
||||
BgNVBAoMDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBs
|
||||
ZS5jb20xJjAkBgNVBAMMHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4X
|
||||
DTE3MDYwNzA4MDY0OVoXDTI3MDYwNTA4MDY0OVowgZMxCzAJBgNVBAYTAkZSMQ8w
|
||||
DQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMGA1UECgwMRXhh
|
||||
bXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTEmMCQG
|
||||
A1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwgZ8wDQYJKoZIhvcN
|
||||
AQEBBQADgY0AMIGJAoGBALpWR23fn/TmHxsXsHdrydzPSd17fZkc71WsaicgQR66
|
||||
1tIVYb22UWGfj9KPM8THMsV74ew4ZkaQ39qvU0iuQIRrKARFHFok+vbaecgWMeWe
|
||||
vGIqdnmyB9gJYaFOKgtSkfXsu2ddsqdvLYwcDbczrq8X9yEXpN6mnxXeCcPG4F0p
|
||||
AgMBAAGjggE0MIIBMDAdBgNVHQ4EFgQUgigpdAUpONoDq0pQ3yfxrslCSpcwgcgG
|
||||
A1UdIwSBwDCBvYAUgigpdAUpONoDq0pQ3yfxrslCSpehgZmkgZYwgZMxCzAJBgNV
|
||||
BAYTAkZSMQ8wDQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMG
|
||||
A1UECgwMRXhhbXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxl
|
||||
LmNvbTEmMCQGA1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCCQDJ
|
||||
5YC9XM7JozAMBgNVHRMEBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly93
|
||||
d3cuZXhhbXBsZS5jb20vZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcNAQELBQADgYEA
|
||||
euxOBPInSJRKAIseMxPmAabtAqKNslZSmpG4He3lkKt+HM3jfznUt3psmD7j1hFW
|
||||
S4l7KXzzajvaGYybDq5N9MqrDjhGn3VXZqOLMUNDL7OQq96TzgqsTBT1dmVSbNlt
|
||||
PQgiAeKAk3tmH4lRRi9MTBSyJ6I92JYcS5H6Bs4ZwCc=
|
||||
-----END CERTIFICATE-----
|
9
examples/wifi/wifi_eap_fast/main/component.mk
Normal file
9
examples/wifi/wifi_eap_fast/main/component.mk
Normal file
@ -0,0 +1,9 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
||||
# embed files from the "certs" directory as binary data symbols
|
||||
# in the app
|
||||
COMPONENT_EMBED_TXTFILES := ca.pem
|
||||
COMPONENT_EMBED_TXTFILES += pac_file.pac
|
0
examples/wifi/wifi_eap_fast/main/pac_file.pac
Normal file
0
examples/wifi/wifi_eap_fast/main/pac_file.pac
Normal file
70
examples/wifi/wifi_eap_fast/main/server.crt
Normal file
70
examples/wifi/wifi_eap_fast/main/server.crt
Normal file
@ -0,0 +1,70 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 47 (0x2f)
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
Issuer: C=FR, ST=Radius, L=Somewhere, O=Example Inc./emailAddress=admin@example.com, CN=Example Certificate Authority
|
||||
Validity
|
||||
Not Before: Jun 7 08:06:49 2017 GMT
|
||||
Not After : Jun 5 08:06:49 2027 GMT
|
||||
Subject: C=FR, ST=Radius, O=Example Inc., CN=Example Server Certificate/emailAddress=admin@example.com
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:c9:d8:e2:e0:75:91:83:87:d8:c8:80:c6:20:4d:
|
||||
e9:14:24:30:98:33:53:fa:56:0e:ec:9a:43:7f:87:
|
||||
a9:22:94:26:06:c7:ac:b5:d9:ec:55:06:81:b7:0d:
|
||||
c9:24:51:49:fa:47:fb:4b:4e:fc:ed:75:8a:e1:28:
|
||||
32:bc:c5:e0:4c:45:c4:58:60:15:67:1e:6b:40:19:
|
||||
3f:f0:ab:92:61:92:2d:71:10:2e:f2:eb:bc:81:2f:
|
||||
5a:3b:74:ca:5f:fd:e0:ee:d1:d9:07:6a:6c:20:c0:
|
||||
07:88:b4:8b:0f:ad:1e:c9:4f:7c:11:98:37:89:15:
|
||||
de:24:b1:11:1a:7c:97:4a:cf:f3:c8:cb:79:9e:9c:
|
||||
c3:71:da:a6:94:97:f5:95:fd:61:06:44:e2:3f:12:
|
||||
43:0b:1d:33:48:91:d2:ce:4f:97:a1:ed:6a:30:c7:
|
||||
5d:98:b5:6e:0a:b7:4f:d9:03:ec:80:76:09:b0:40:
|
||||
a1:a1:af:ab:2a:59:c4:0f:56:22:bc:be:14:be:18:
|
||||
df:10:7d:5d:22:bf:e5:04:77:7a:75:6b:3e:eb:6d:
|
||||
20:a1:a7:60:d4:f1:87:9d:9f:60:b9:d3:db:2c:25:
|
||||
f4:91:4a:f1:d2:40:e5:a1:10:88:a0:41:5a:98:40:
|
||||
ca:15:d7:e3:e6:3e:c0:6a:d5:46:b2:b4:90:b4:ae:
|
||||
3b:e3
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Extended Key Usage:
|
||||
TLS Web Server Authentication
|
||||
X509v3 CRL Distribution Points:
|
||||
|
||||
Full Name:
|
||||
URI:http://www.example.com/example_ca.crl
|
||||
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
a4:25:21:51:0b:22:6c:63:8d:a9:c1:4f:04:33:69:79:34:f0:
|
||||
36:dd:8f:6a:27:5f:07:a2:1d:ef:8b:f0:96:e6:e7:a3:b8:3b:
|
||||
85:5e:3f:26:43:8a:8e:95:58:9c:a6:db:9c:51:bf:ea:53:16:
|
||||
3e:c1:a8:11:1a:c6:cf:0e:a1:17:18:64:d2:05:f1:c0:9c:a6:
|
||||
2b:16:c4:29:54:03:d2:17:bd:15:74:d6:ad:8a:8f:2d:cc:27:
|
||||
3b:88:88:f2:ea:d0:a2:cb:e9:42:57:df:26:9f:8a:a2:02:2f:
|
||||
35:b6:19:1d:26:43:44:af:12:4b:bc:b9:84:50:02:fd:1d:fa:
|
||||
50:e8
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDWTCCAsKgAwIBAgIBLzANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMCRlIx
|
||||
DzANBgNVBAgMBlJhZGl1czESMBAGA1UEBwwJU29tZXdoZXJlMRUwEwYDVQQKDAxF
|
||||
eGFtcGxlIEluYy4xIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMSYw
|
||||
JAYDVQQDDB1FeGFtcGxlIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNzA2MDcw
|
||||
ODA2NDlaFw0yNzA2MDUwODA2NDlaMHwxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIDAZS
|
||||
YWRpdXMxFTATBgNVBAoMDEV4YW1wbGUgSW5jLjEjMCEGA1UEAwwaRXhhbXBsZSBT
|
||||
ZXJ2ZXIgQ2VydGlmaWNhdGUxIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUu
|
||||
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAydji4HWRg4fYyIDG
|
||||
IE3pFCQwmDNT+lYO7JpDf4epIpQmBsestdnsVQaBtw3JJFFJ+kf7S0787XWK4Sgy
|
||||
vMXgTEXEWGAVZx5rQBk/8KuSYZItcRAu8uu8gS9aO3TKX/3g7tHZB2psIMAHiLSL
|
||||
D60eyU98EZg3iRXeJLERGnyXSs/zyMt5npzDcdqmlJf1lf1hBkTiPxJDCx0zSJHS
|
||||
zk+Xoe1qMMddmLVuCrdP2QPsgHYJsEChoa+rKlnED1YivL4UvhjfEH1dIr/lBHd6
|
||||
dWs+620goadg1PGHnZ9gudPbLCX0kUrx0kDloRCIoEFamEDKFdfj5j7AatVGsrSQ
|
||||
tK474wIDAQABo08wTTATBgNVHSUEDDAKBggrBgEFBQcDATA2BgNVHR8ELzAtMCug
|
||||
KaAnhiVodHRwOi8vd3d3LmV4YW1wbGUuY29tL2V4YW1wbGVfY2EuY3JsMA0GCSqG
|
||||
SIb3DQEBBQUAA4GBAKQlIVELImxjjanBTwQzaXk08Dbdj2onXweiHe+L8Jbm56O4
|
||||
O4VePyZDio6VWJym25xRv+pTFj7BqBEaxs8OoRcYZNIF8cCcpisWxClUA9IXvRV0
|
||||
1q2Kjy3MJzuIiPLq0KLL6UJX3yafiqICLzW2GR0mQ0SvEku8uYRQAv0d+lDo
|
||||
-----END CERTIFICATE-----
|
27
examples/wifi/wifi_eap_fast/main/server.key
Normal file
27
examples/wifi/wifi_eap_fast/main/server.key
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAydji4HWRg4fYyIDGIE3pFCQwmDNT+lYO7JpDf4epIpQmBses
|
||||
tdnsVQaBtw3JJFFJ+kf7S0787XWK4SgyvMXgTEXEWGAVZx5rQBk/8KuSYZItcRAu
|
||||
8uu8gS9aO3TKX/3g7tHZB2psIMAHiLSLD60eyU98EZg3iRXeJLERGnyXSs/zyMt5
|
||||
npzDcdqmlJf1lf1hBkTiPxJDCx0zSJHSzk+Xoe1qMMddmLVuCrdP2QPsgHYJsECh
|
||||
oa+rKlnED1YivL4UvhjfEH1dIr/lBHd6dWs+620goadg1PGHnZ9gudPbLCX0kUrx
|
||||
0kDloRCIoEFamEDKFdfj5j7AatVGsrSQtK474wIDAQABAoIBAQC2kGDEPBJdMSW2
|
||||
VCLfXRiPixwYzXQLXIMrJWwfkQg9qlmqkDd6U50aWkRA2UswegW7RhfYSZ0i+cmf
|
||||
VMhvTVpOIlwwwtcY6b5/v1bBy60eaySGuuh79xQMlFO8qynQIMStvUfbGTqrdIRb
|
||||
9VBB4YeS9T12fILejtTZwv2BQ2dj1Y1SCay6Ri85UzJqSClRKgHISybvVdLNjPvP
|
||||
0TRFBr57zyjL6WE8teKiKchzQko2u86No5uBCdKGsrAkrsdcR0YqlM/pZxd3VKNm
|
||||
+eny0k+dZZlvcPxzkzP4hEp9+Rw5rP9/s3s/cCwvuuC5JO32ATBWKCbTvPv/XPDb
|
||||
MdSJtOshAoGBAPzk0eswkcbFYtpnpBNmBAr1dtAdW1lfjUI2ucMMwt7Wns0P/tt+
|
||||
gq6Hi1wTaGP0l/dIECgeHwjtWj31ZJjQtFJ1y/kafxo4o9cA8vCydpdvSZaldAfg
|
||||
sbLlDTDYzEpelaDIbNQBBXFoC5U9JlBhBsIFCL5Z8ZuIeFPsb7t5wwuHAoGBAMxT
|
||||
jyWfNm1uNxp1xgCnrRsLPQPVnURrSFAqcHrECqRu3F7sozTN7q/cZViemxPvVDGQ
|
||||
p9c+9bHwaYvW4trO5qDHJ++gGwm5L52bMAY1VUfeTt67fqrey43XpdmzcTX1V9Uj
|
||||
QWawPUCSDzFjL1MjfCIejtyYf5ash53vj+T8r/vFAoGAA/OPVB1uKazr3n3AEo2F
|
||||
gqZTNO1AgCT+EArK3EFWyiSQVqPpV4SihheYFdg3yVgJB9QYbIgL9BfBUTaEW97m
|
||||
8mLkzP+c/Mvlw3ZAVYJ0V+llPPVY2saoACOUES9SAdd4fwqiqK1baGo3xB0wfBEI
|
||||
CgAKIu9E1ylKuAT5ufQtGAECgYEAtP/kU5h5N3El4QupTdU7VDSdZTMqsHw0v8cI
|
||||
gsf9AXKvRmtrnBA8u46KPHmruHoO5CVXeSZtsaXdaaH+rYQQ6yXg67WxnehtFLlv
|
||||
TmCaXiLBTS9cYvMf8FOyuGnsBLeEietEOTov2G5KhR5uwsAxa2wUc7endor5S9/2
|
||||
YQuyvV0CgYALbiFpILd5l1ip65eE6JdA3hfttUbV2j2NSW12ej69vqbeOfaSgNse
|
||||
uYCcXFsBbQPhNPwA+4d1oCe8SyXZg1f7gE812z2Tyr/3vdVnNZlitoxhsHmGiyS7
|
||||
gZdaTYCb78l9z0EBdaCVvA16owEle4SR6f9eCwzSI0WPOUra+x/hrA==
|
||||
-----END RSA PRIVATE KEY-----
|
57
examples/wifi/wifi_eap_fast/main/server.pem
Normal file
57
examples/wifi/wifi_eap_fast/main/server.pem
Normal file
@ -0,0 +1,57 @@
|
||||
Bag Attributes
|
||||
localKeyID: 63 3B C1 EE 3A 4A 9B 3E FF 9E E7 BC 17 50 D7 F7 B7 7E 3B C0
|
||||
subject=/C=FR/ST=Radius/O=Example Inc./CN=Example Server Certificate/emailAddress=admin@example.com
|
||||
issuer=/C=FR/ST=Radius/L=Somewhere/O=Example Inc./emailAddress=admin@example.com/CN=Example Certificate Authority
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDWTCCAsKgAwIBAgIBLzANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMCRlIx
|
||||
DzANBgNVBAgMBlJhZGl1czESMBAGA1UEBwwJU29tZXdoZXJlMRUwEwYDVQQKDAxF
|
||||
eGFtcGxlIEluYy4xIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMSYw
|
||||
JAYDVQQDDB1FeGFtcGxlIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNzA2MDcw
|
||||
ODA2NDlaFw0yNzA2MDUwODA2NDlaMHwxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIDAZS
|
||||
YWRpdXMxFTATBgNVBAoMDEV4YW1wbGUgSW5jLjEjMCEGA1UEAwwaRXhhbXBsZSBT
|
||||
ZXJ2ZXIgQ2VydGlmaWNhdGUxIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUu
|
||||
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAydji4HWRg4fYyIDG
|
||||
IE3pFCQwmDNT+lYO7JpDf4epIpQmBsestdnsVQaBtw3JJFFJ+kf7S0787XWK4Sgy
|
||||
vMXgTEXEWGAVZx5rQBk/8KuSYZItcRAu8uu8gS9aO3TKX/3g7tHZB2psIMAHiLSL
|
||||
D60eyU98EZg3iRXeJLERGnyXSs/zyMt5npzDcdqmlJf1lf1hBkTiPxJDCx0zSJHS
|
||||
zk+Xoe1qMMddmLVuCrdP2QPsgHYJsEChoa+rKlnED1YivL4UvhjfEH1dIr/lBHd6
|
||||
dWs+620goadg1PGHnZ9gudPbLCX0kUrx0kDloRCIoEFamEDKFdfj5j7AatVGsrSQ
|
||||
tK474wIDAQABo08wTTATBgNVHSUEDDAKBggrBgEFBQcDATA2BgNVHR8ELzAtMCug
|
||||
KaAnhiVodHRwOi8vd3d3LmV4YW1wbGUuY29tL2V4YW1wbGVfY2EuY3JsMA0GCSqG
|
||||
SIb3DQEBBQUAA4GBAKQlIVELImxjjanBTwQzaXk08Dbdj2onXweiHe+L8Jbm56O4
|
||||
O4VePyZDio6VWJym25xRv+pTFj7BqBEaxs8OoRcYZNIF8cCcpisWxClUA9IXvRV0
|
||||
1q2Kjy3MJzuIiPLq0KLL6UJX3yafiqICLzW2GR0mQ0SvEku8uYRQAv0d+lDo
|
||||
-----END CERTIFICATE-----
|
||||
Bag Attributes
|
||||
localKeyID: 63 3B C1 EE 3A 4A 9B 3E FF 9E E7 BC 17 50 D7 F7 B7 7E 3B C0
|
||||
Key Attributes: <No Attributes>
|
||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIzOJcU8NzjKACAggA
|
||||
MBQGCCqGSIb3DQMHBAjdK4dY0QgcrgSCBMgCv4euS7bxaRTMSXYliVA+UrAI0iJL
|
||||
oQgZ6cGFqXqasKu7K6BltLXaKJLX321gV2ofHHAxa1CWFwIgrv/bhci10cJr6BaL
|
||||
a3+5L5e/EO0eRKVzoplput9mTP27pcJSu8jN5jOu054oamzFKtgGcBuL9mRCAfVq
|
||||
JSCwbSUHPrwZX6jVDsLggrvE78SIXEYAQDfUrbvBY1kGNNV+U9v410SREYXI3q+8
|
||||
a4Paotf2HN5G0nvr0BSJUbY0NUe4AP1NfOM1VE8UiLL3LfZE3ZbOm6XsM8Mxf8rV
|
||||
BkDOzhErF/dXOE65b5xG4KfoXy78WN7OeJpjNgNUDUl1/3+bc++8f7ZBzOtVAjP7
|
||||
diDYU/UrQeLUrLVxTLD6C9J9HvbW5JCEa1FN+pKQKxeaQ9j/dDhJ7XI4ctaIIQui
|
||||
zrOTLEhBqC10TaNabLNVsLFCgFQMREBVYZoBYbFIZLT4FuRk5yaAYRDCrRKgqlu6
|
||||
61E0jOD/hDZIbBO/Vf94d+VaypeFonoz6SdrWgf4heN530d5fd5nOxElRl8LmUcH
|
||||
LriwJIXB7XCfwgjREceRQpjiqmWPl8hcfe9E2NzwldbE+eLN0mlXgRyLlU+eXova
|
||||
3r1u60Hb9ocLux3kHUXpZ+MomwkwqIn9qFC0U3KBGt7SmhUWypmoNUPiXP0U4Lno
|
||||
tynPBODzhDeRv2T0qxULc6OznDE3WOuy88B94/JXhB5D56bRb9FkkpHpmn8MP8SW
|
||||
fIV3cK/cBoGxgyk+IaL0aQbojFtyeyKbkrz1W3WnPtB3/kqd8USzpCvUBMBVG83D
|
||||
XzHcU/mRYO61BgyGv0VBXdBtPbmW1CK73eX7gc/uOtqhxUQc3g5hNZDL2rxPCpID
|
||||
alyGlSQxY8cPWJbYMPq2RHoJNDxnTbFhDm3mdOoTg5qK4+cUZMBqfq1kswXM9Z4p
|
||||
LSnIviRjpL4a7hhDVAJYOo29rBP+QNdt5CkyLNwjnDv+l8jHOMTP4t1RPvoQx6hc
|
||||
aOQOcSQnIqDgzot3//dnC2mBTQ66jsOnRPMMs9MQ4up6Wrc5PEt5avBi3B4AQC2Q
|
||||
TUjL6QAcMR5cJbkecp+5h7W5pUw3OYcYpg6G+unJVGSgZkye2lySGgNuRLmcYjVA
|
||||
gXfA9a8+HN/TFGHP668pZvHQrfV470ETnHhrh+NLN5AIDR+UFG8is7Xj7Ly2/5bN
|
||||
M3Q3AYSCb8P8/ZrV3Dfm3qoCoxuNYax0PYt/JBWXTtPG1SClUQg+yo8VMiNw877h
|
||||
IEdkg1QBxKWY5x+ThK79y+Cwub795ym9bYTwAtH8kpLmamoBT8UvgJumh0i8NGg3
|
||||
04B/oyg1P8/TxfbD0uaTPC+tmbIKVyHybTQL6/E0bs2knPp2Zyxno3yE3AI70msZ
|
||||
mGNuK9mkxITIUbijiRZyeQvZz/x/daYwQ0WuaXXpPQvKcFu7LyIEad8QpIqtSCax
|
||||
VS9Mtwe7zTCp0jmQDBGltlk1B2rUlQ5rxsFN6kJtBULdQc1TTj0NUp3ESeAE3A/l
|
||||
wE8fPzBht1OKghJqVndGoh01XhKJfpfaQ85CES0HzA6Nll8SQO0bn6u4SBZGEvBT
|
||||
pFarRrtS6KbulTDB3yBPrKgd1ZoBQv5/ScW8fPcLi55U6nhR28uu+zKy4yZFgOFR
|
||||
2KU=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
148
examples/wifi/wifi_eap_fast/main/wifi_eap_fast_main.c
Normal file
148
examples/wifi/wifi_eap_fast/main/wifi_eap_fast_main.c
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_wpa2.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_netif.h"
|
||||
|
||||
/* The examples use simple WiFi configuration that you can set via
|
||||
project configuration menu.
|
||||
|
||||
If you'd rather not, just change the below entries to strings with
|
||||
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
|
||||
|
||||
*/
|
||||
#define EXAMPLE_WIFI_SSID CONFIG_EXAMPLE_WIFI_SSID
|
||||
|
||||
#define EXAMPLE_EAP_ID CONFIG_EXAMPLE_EAP_ID
|
||||
#define EXAMPLE_EAP_USERNAME CONFIG_EXAMPLE_EAP_USERNAME
|
||||
#define EXAMPLE_EAP_PASSWORD CONFIG_EXAMPLE_EAP_PASSWORD
|
||||
|
||||
/* FreeRTOS event group to signal when we are connected & ready to make a request */
|
||||
static EventGroupHandle_t wifi_event_group;
|
||||
|
||||
/* esp netif object representing the WIFI station */
|
||||
static esp_netif_t *sta_netif = NULL;
|
||||
|
||||
/* The event group allows multiple bits for each event,
|
||||
but we only care about one event - are we connected
|
||||
to the AP with an IP? */
|
||||
const int CONNECTED_BIT = BIT0;
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
/* CA cert, taken from ca.pem
|
||||
|
||||
To embed it in the app binary, the PEM, CRT and KEY file is named
|
||||
in the component.mk COMPONENT_EMBED_TXTFILES variable.
|
||||
*/
|
||||
#if defined(CONFIG_EXAMPLE_VALIDATE_SERVER_CERT)
|
||||
extern uint8_t ca_pem_start[] asm("_binary_ca_pem_start");
|
||||
extern uint8_t ca_pem_end[] asm("_binary_ca_pem_end");
|
||||
#endif
|
||||
extern uint8_t pac_file_pac_start[] asm("_binary_pac_file_pac_start");
|
||||
extern uint8_t pac_file_pac_end[] asm("_binary_pac_file_pac_end");
|
||||
|
||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
{
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
esp_wifi_connect();
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
esp_wifi_connect();
|
||||
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
static void initialise_wifi(void)
|
||||
{
|
||||
#if defined(CONFIG_EXAMPLE_VALIDATE_SERVER_CERT)
|
||||
unsigned int ca_pem_bytes = ca_pem_end - ca_pem_start;
|
||||
#endif
|
||||
unsigned int pac_file_bytes = pac_file_pac_end - pac_file_pac_start;
|
||||
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
wifi_event_group = xEventGroupCreate();
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
sta_netif = esp_netif_create_default_wifi_sta();
|
||||
assert(sta_netif);
|
||||
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
|
||||
ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
|
||||
ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );
|
||||
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
|
||||
wifi_config_t wifi_config = {
|
||||
.sta = {
|
||||
.ssid = EXAMPLE_WIFI_SSID,
|
||||
#if defined(CONFIG_EXAMPLE_WPA3_ENTERPRISE)
|
||||
.pmf_cfg = {
|
||||
.capable = true,
|
||||
.required = false
|
||||
},
|
||||
#endif
|
||||
},
|
||||
};
|
||||
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
|
||||
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
|
||||
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
|
||||
ESP_ERROR_CHECK( esp_wifi_sta_wpa2_ent_set_identity((uint8_t *)EXAMPLE_EAP_ID, strlen(EXAMPLE_EAP_ID)) );
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_VALIDATE_SERVER_CERT) || \
|
||||
defined(CONFIG_EXAMPLE_WPA3_ENTERPRISE)
|
||||
ESP_ERROR_CHECK( esp_wifi_sta_wpa2_ent_set_ca_cert(ca_pem_start, ca_pem_bytes) );
|
||||
#endif /* CONFIG_EXAMPLE_VALIDATE_SERVER_CERT */ /* EXAMPLE_WPA3_ENTERPRISE */
|
||||
|
||||
ESP_ERROR_CHECK( esp_wifi_sta_wpa2_ent_set_username((uint8_t *)EXAMPLE_EAP_USERNAME, strlen(EXAMPLE_EAP_USERNAME)) );
|
||||
ESP_ERROR_CHECK( esp_wifi_sta_wpa2_ent_set_password((uint8_t *)EXAMPLE_EAP_PASSWORD, strlen(EXAMPLE_EAP_PASSWORD)) );
|
||||
ESP_ERROR_CHECK( esp_wifi_sta_wpa2_ent_set_pac_file(pac_file_pac_start, pac_file_bytes - 1) );
|
||||
esp_eap_fast_config eap_fast_config = {
|
||||
.fast_provisioning = 2,
|
||||
.fast_max_pac_list_len = 0,
|
||||
.fast_pac_format_binary = false
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_wifi_sta_wpa2_ent_set_fast_phase1_params(eap_fast_config) );
|
||||
|
||||
ESP_ERROR_CHECK( esp_wifi_sta_wpa2_ent_enable() );
|
||||
ESP_ERROR_CHECK( esp_wifi_start() );
|
||||
}
|
||||
|
||||
static void wpa2_enterprise_example_task(void *pvParameters)
|
||||
{
|
||||
esp_netif_ip_info_t ip;
|
||||
memset(&ip, 0, sizeof(esp_netif_ip_info_t));
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
|
||||
while (1) {
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
|
||||
if (esp_netif_get_ip_info(sta_netif, &ip) == 0) {
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~");
|
||||
ESP_LOGI(TAG, "IP:"IPSTR, IP2STR(&ip.ip));
|
||||
ESP_LOGI(TAG, "MASK:"IPSTR, IP2STR(&ip.netmask));
|
||||
ESP_LOGI(TAG, "GW:"IPSTR, IP2STR(&ip.gw));
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK( nvs_flash_init() );
|
||||
initialise_wifi();
|
||||
xTaskCreate(&wpa2_enterprise_example_task, "wpa2_enterprise_example_task", 4096, NULL, 5, NULL);
|
||||
}
|
1
examples/wifi/wifi_eap_fast/sdkconfig.defaults
Normal file
1
examples/wifi/wifi_eap_fast/sdkconfig.defaults
Normal file
@ -0,0 +1 @@
|
||||
CONFIG_WPA_MBEDTLS_CRYPTO=n
|
Loading…
Reference in New Issue
Block a user