mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/support_phase2TTLS_algos' into 'master'
wpa_supplicant: add support for PAP, MS-CHAP and CHAP as Phase 2 algorithms for TTLS alongside MS-CHAPv2 Closes FCS-361 See merge request espressif/esp-idf!8816
This commit is contained in:
commit
c27bd40d54
@ -19,6 +19,14 @@
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
typedef enum {
|
||||
ESP_EAP_TTLS_PHASE2_EAP,
|
||||
ESP_EAP_TTLS_PHASE2_MSCHAPV2,
|
||||
ESP_EAP_TTLS_PHASE2_MSCHAP,
|
||||
ESP_EAP_TTLS_PHASE2_PAP,
|
||||
ESP_EAP_TTLS_PHASE2_CHAP
|
||||
} esp_eap_ttls_phase2_types ;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -191,6 +199,16 @@ esp_err_t esp_wifi_sta_wpa2_ent_set_disable_time_check(bool disable);
|
||||
*/
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_get_disable_time_check(bool *disable);
|
||||
|
||||
/**
|
||||
* @brief Set wpa2 enterprise ttls phase2 method
|
||||
*
|
||||
* @param type: the type of phase 2 method to be used
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
*/
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_ttls_phase2_method(esp_eap_ttls_phase2_types type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -2,12 +2,13 @@
|
||||
* CHAP-MD5
|
||||
*
|
||||
*/
|
||||
#ifdef CHAP_MD5
|
||||
#ifndef CHAP_MD5
|
||||
#define CHAP_MD5
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "wpa2/eap_peer/chap.h"
|
||||
#include "eap_peer/chap.h"
|
||||
|
||||
int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge,
|
||||
size_t challenge_len, u8 *response)
|
||||
|
17
components/wpa_supplicant/src/eap_peer/chap.h
Normal file
17
components/wpa_supplicant/src/eap_peer/chap.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* CHAP-MD5 (RFC 1994)
|
||||
* Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef CHAP_H
|
||||
#define CHAP_H
|
||||
|
||||
#define CHAP_MD5_LEN 16
|
||||
|
||||
int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge,
|
||||
size_t challenge_len, u8 *response);
|
||||
|
||||
#endif /* CHAP_H */
|
@ -27,6 +27,7 @@
|
||||
#include "rsn_supp/wpa.h"
|
||||
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/sha256.h"
|
||||
|
||||
#include "utils/ext_password.h"
|
||||
#include "tls/tls.h"
|
||||
@ -191,6 +192,8 @@ void eap_peer_unregister_methods(void)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int eap_peer_register_methods(void)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -232,6 +235,90 @@ void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
|
||||
sm->m = NULL;
|
||||
}
|
||||
|
||||
static int eap_sm_set_scard_pin(struct eap_sm *sm,
|
||||
struct eap_peer_config *conf)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int eap_sm_get_scard_identity(struct eap_sm *sm,
|
||||
struct eap_peer_config *conf)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_sm_buildIdentity - Build EAP-Identity/Response for the current network
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @id: EAP identifier for the packet
|
||||
* @encrypted: Whether the packet is for encrypted tunnel (EAP phase 2)
|
||||
* Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on
|
||||
* failure
|
||||
*
|
||||
* This function allocates and builds an EAP-Identity/Response packet for the
|
||||
* current network. The caller is responsible for freeing the returned data.
|
||||
*/
|
||||
struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted)
|
||||
{
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
struct wpabuf *resp;
|
||||
const u8 *identity;
|
||||
size_t identity_len;
|
||||
|
||||
if (config == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP: buildIdentity: configuration "
|
||||
"was not available");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sm->m && sm->m->get_identity &&
|
||||
(identity = sm->m->get_identity(sm, sm->eap_method_priv,
|
||||
&identity_len)) != NULL) {
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth "
|
||||
"identity", identity, identity_len);
|
||||
} else if (!encrypted && config->anonymous_identity) {
|
||||
identity = config->anonymous_identity;
|
||||
identity_len = config->anonymous_identity_len;
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
|
||||
identity, identity_len);
|
||||
} else {
|
||||
identity = config->identity;
|
||||
identity_len = config->identity_len;
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity",
|
||||
identity, identity_len);
|
||||
}
|
||||
|
||||
if (identity == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP: buildIdentity: identity "
|
||||
"configuration was not available");
|
||||
if (config->pcsc) {
|
||||
if (eap_sm_get_scard_identity(sm, config) < 0)
|
||||
return NULL;
|
||||
identity = config->identity;
|
||||
identity_len = config->identity_len;
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
|
||||
"IMSI", identity, identity_len);
|
||||
} else {
|
||||
eap_sm_request_identity(sm);
|
||||
return NULL;
|
||||
}
|
||||
} else if (config->pcsc) {
|
||||
if (eap_sm_set_scard_pin(sm, config) < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, identity_len,
|
||||
EAP_CODE_RESPONSE, id);
|
||||
if (resp == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_put_data(resp, identity, identity_len);
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * eap_sm_build_identity_resp(struct eap_sm *sm, u8 id, int encrypted)
|
||||
{
|
||||
const u8 *identity;
|
||||
@ -389,6 +476,10 @@ int eap_peer_config_init(
|
||||
sm->config.new_password_len);
|
||||
}
|
||||
|
||||
if (g_wpa_ttls_phase2_type) {
|
||||
sm->config.phase2 = g_wpa_ttls_phase2_type;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
@ -458,6 +549,65 @@ _out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
|
||||
static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
|
||||
const char *msg, size_t msglen)
|
||||
{
|
||||
struct eap_peer_config *config;
|
||||
|
||||
if (sm == NULL)
|
||||
return;
|
||||
config = eap_get_config(sm);
|
||||
if (config == NULL)
|
||||
return;
|
||||
|
||||
switch (field) {
|
||||
case WPA_CTRL_REQ_EAP_IDENTITY:
|
||||
config->pending_req_identity++;
|
||||
break;
|
||||
case WPA_CTRL_REQ_EAP_PASSWORD:
|
||||
config->pending_req_password++;
|
||||
break;
|
||||
case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
|
||||
config->pending_req_new_password++;
|
||||
break;
|
||||
case WPA_CTRL_REQ_EAP_PIN:
|
||||
config->pending_req_pin++;
|
||||
break;
|
||||
case WPA_CTRL_REQ_EAP_PASSPHRASE:
|
||||
config->pending_req_passphrase++;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
|
||||
#define eap_sm_request(sm, type, msg, msglen) do { } while (0)
|
||||
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
|
||||
|
||||
const char * eap_sm_get_method_name(struct eap_sm *sm)
|
||||
{
|
||||
if (sm->m == NULL)
|
||||
return "UNKNOWN";
|
||||
return sm->m->name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_sm_request_identity - Request identity from user (ctrl_iface)
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
*
|
||||
* EAP methods can call this function to request identity information for the
|
||||
* current network. This is normally called when the identity is not included
|
||||
* in the network configuration. The request will be sent to monitor programs
|
||||
* through the control interface.
|
||||
*/
|
||||
void eap_sm_request_identity(struct eap_sm *sm)
|
||||
{
|
||||
eap_sm_request(sm, WPA_CTRL_REQ_EAP_IDENTITY, NULL, 0);
|
||||
}
|
||||
|
||||
void eap_peer_blob_deinit(struct eap_sm *sm)
|
||||
{
|
||||
int i;
|
||||
@ -495,6 +645,13 @@ struct eap_peer_config * eap_get_config(struct eap_sm *sm)
|
||||
return &sm->config;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_get_config_identity - Get identity from the network configuration
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @len: Buffer for the length of the identity
|
||||
* Returns: Pointer to the identity or %NULL if not found
|
||||
*/
|
||||
const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
|
||||
{
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
@ -504,6 +661,13 @@ const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
|
||||
return config->identity;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_get_config_password - Get password from the network configuration
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @len: Buffer for the length of the password
|
||||
* Returns: Pointer to the password or %NULL if not found
|
||||
*/
|
||||
const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
|
||||
{
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
@ -513,6 +677,16 @@ const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
|
||||
return config->password;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_get_config_password2 - Get password from the network configuration
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @len: Buffer for the length of the password
|
||||
* @hash: Buffer for returning whether the password is stored as a
|
||||
* NtPasswordHash instead of plaintext password; can be %NULL if this
|
||||
* information is not needed
|
||||
* Returns: Pointer to the password or %NULL if not found
|
||||
*/
|
||||
const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
|
||||
{
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
@ -525,6 +699,13 @@ const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
|
||||
return config->password;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_get_config_new_password - Get new password from network configuration
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @len: Buffer for the length of the new password
|
||||
* Returns: Pointer to the new password or %NULL if not found
|
||||
*/
|
||||
const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len)
|
||||
{
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
|
@ -39,9 +39,12 @@ int g_wpa_password_len;
|
||||
u8 *g_wpa_new_password;
|
||||
int g_wpa_new_password_len;
|
||||
|
||||
char *g_wpa_ttls_phase2_type;
|
||||
|
||||
const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
|
||||
void eap_deinit_prev_method(struct eap_sm *sm, const char *txt);
|
||||
struct wpabuf * eap_sm_build_nak(struct eap_sm *sm, EapType type, u8 id);
|
||||
struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted);
|
||||
int eap_peer_blob_init(struct eap_sm *sm);
|
||||
void eap_peer_blob_deinit(struct eap_sm *sm);
|
||||
int eap_peer_config_init(
|
||||
@ -50,5 +53,6 @@ int eap_peer_config_init(
|
||||
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);
|
||||
|
||||
#endif /* EAP_H */
|
||||
|
@ -26,8 +26,24 @@ struct eap_peer_config {
|
||||
*/
|
||||
size_t identity_len;
|
||||
|
||||
/**
|
||||
* anonymous_identity - Anonymous EAP Identity
|
||||
*
|
||||
* This field is used for unencrypted use with EAP types that support
|
||||
* different tunnelled identity, e.g., EAP-TTLS, in order to reveal the
|
||||
* real identity (identity field) only to the authentication server.
|
||||
*
|
||||
* If not set, the identity field will be used for both unencrypted and
|
||||
* protected fields.
|
||||
*
|
||||
* This field can also be used with EAP-SIM/AKA/AKA' to store the
|
||||
* pseudonym identity.
|
||||
*/
|
||||
u8 *anonymous_identity;
|
||||
|
||||
/**
|
||||
* anonymous_identity_len - Length of anonymous_identity
|
||||
*/
|
||||
size_t anonymous_identity_len;
|
||||
|
||||
/**
|
||||
@ -148,24 +164,80 @@ struct eap_peer_config {
|
||||
*/
|
||||
u8 *ca_cert2;
|
||||
|
||||
/**
|
||||
* ca_path2 - Directory path for CA certificate files (PEM) (Phase 2)
|
||||
*
|
||||
* This path may contain multiple CA certificates in OpenSSL format.
|
||||
* Common use for this is to point to system trusted CA list which is
|
||||
* often installed into directory like /etc/ssl/certs. If configured,
|
||||
* these certificates are added to the list of trusted CAs. ca_cert
|
||||
* may also be included in that case, but it is not required.
|
||||
*
|
||||
* This field is like ca_path, but used for phase 2 (inside
|
||||
* EAP-TTLS/PEAP/FAST tunnel) authentication.
|
||||
*/
|
||||
u8 *ca_path2;
|
||||
|
||||
/**
|
||||
* client_cert2 - File path to client certificate file
|
||||
*
|
||||
* This field is like client_cert, but used for phase 2 (inside
|
||||
* EAP-TTLS/PEAP/FAST tunnel) authentication. 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.
|
||||
*/
|
||||
u8 *client_cert2;
|
||||
|
||||
/**
|
||||
* private_key2 - File path to client private key file
|
||||
*
|
||||
* This field is like private_key, but used for phase 2 (inside
|
||||
* EAP-TTLS/PEAP/FAST tunnel) authentication. 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.
|
||||
*/
|
||||
u8 *private_key2;
|
||||
|
||||
u8 *private_key2_password;
|
||||
|
||||
/**
|
||||
* eap_methods - Allowed EAP methods
|
||||
*
|
||||
* (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of
|
||||
* allowed EAP methods or %NULL if all methods are accepted.
|
||||
*/
|
||||
struct eap_method_type *eap_methods;
|
||||
|
||||
|
||||
char *phase1;
|
||||
|
||||
/**
|
||||
* phase2 - Phase2 (inner authentication with TLS tunnel) parameters
|
||||
*
|
||||
* String with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
|
||||
* "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS. "mschapv2_retry=0" can
|
||||
* be used to disable MSCHAPv2 password retry in authentication failure
|
||||
* cases.
|
||||
*/
|
||||
char *phase2;
|
||||
|
||||
/**
|
||||
* pcsc - Parameters for PC/SC smartcard interface for USIM and GSM SIM
|
||||
*
|
||||
* This field is used to configure PC/SC smartcard interface.
|
||||
* Currently, the only configuration is whether this field is %NULL (do
|
||||
* not use PC/SC) or non-NULL (e.g., "") to enable PC/SC.
|
||||
*
|
||||
* This field is used for EAP-SIM and EAP-AKA.
|
||||
*/
|
||||
char *pcsc;
|
||||
|
||||
/**
|
||||
* pin - PIN for USIM, GSM SIM, and smartcards
|
||||
*
|
||||
@ -177,8 +249,80 @@ struct eap_peer_config {
|
||||
*/
|
||||
char *pin;
|
||||
|
||||
/**
|
||||
* pending_req_identity - Whether there is a pending identity 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_identity;
|
||||
|
||||
/**
|
||||
* pending_req_password - Whether there is a pending password 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_password;
|
||||
|
||||
/**
|
||||
* pending_req_pin - Whether there is a pending PIN 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_pin;
|
||||
|
||||
/**
|
||||
* pending_req_new_password - Pending password update 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_new_password;
|
||||
|
||||
/**
|
||||
* pending_req_passphrase - Pending passphrase 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_passphrase;
|
||||
|
||||
/**
|
||||
* pending_req_otp - Whether there is a pending OTP request
|
||||
*
|
||||
* This field should not be set in configuration step. It is only used
|
||||
* internally when control interface is used to request needed
|
||||
* information.
|
||||
*/
|
||||
char *pending_req_otp;
|
||||
|
||||
/**
|
||||
* mschapv2_retry - MSCHAPv2 retry in progress
|
||||
*
|
||||
* This field is used internally by EAP-MSCHAPv2 and should not be set
|
||||
* as part of configuration.
|
||||
*/
|
||||
int mschapv2_retry;
|
||||
|
||||
/**
|
||||
* new_password - New password for password update
|
||||
*
|
||||
* This field is used during MSCHAPv2 password update. This is normally
|
||||
* requested from the user through the control interface and not set
|
||||
* from configuration.
|
||||
*/
|
||||
u8 *new_password;
|
||||
|
||||
/**
|
||||
* new_password_len - Length of new_password field
|
||||
*/
|
||||
size_t new_password_len;
|
||||
|
||||
/**
|
||||
|
@ -57,38 +57,206 @@ struct eap_method_ret {
|
||||
|
||||
struct eap_sm;
|
||||
|
||||
/**
|
||||
* struct eap_method - EAP method interface
|
||||
* This structure defines the EAP method interface. Each method will need to
|
||||
* register its own EAP type, EAP name, and set of function pointers for method
|
||||
* specific operations. This interface is based on section 4.4 of RFC 4137.
|
||||
*/
|
||||
struct eap_method {
|
||||
/**
|
||||
* vendor -EAP Vendor-ID
|
||||
* vendor - EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
|
||||
*/
|
||||
int vendor;
|
||||
|
||||
/**
|
||||
* method - EAP type number
|
||||
* method - EAP type number (EAP_TYPE_*)
|
||||
*/
|
||||
EapType method;
|
||||
EapType method;
|
||||
|
||||
/**
|
||||
* name - Name of the method (e.g., "TLS")
|
||||
*/
|
||||
const char *name;
|
||||
|
||||
struct eap_method *next;
|
||||
|
||||
/**
|
||||
* init - Initialize an EAP method
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* Returns: Pointer to allocated private data, or %NULL on failure
|
||||
*
|
||||
* This function is used to initialize the EAP method explicitly
|
||||
* instead of using METHOD_INIT state as specific in RFC 4137. The
|
||||
* method is expected to initialize it method-specific state and return
|
||||
* a pointer that will be used as the priv argument to other calls.
|
||||
*/
|
||||
void * (*init)(struct eap_sm *sm);
|
||||
|
||||
/**
|
||||
* deinit - Deinitialize an EAP method
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @priv: Pointer to private EAP method data from eap_method::init()
|
||||
*
|
||||
* Deinitialize the EAP method and free any allocated private data.
|
||||
*/
|
||||
void (*deinit)(struct eap_sm *sm, void *priv);
|
||||
|
||||
/**
|
||||
* process - Process an EAP request
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @priv: Pointer to private EAP method data from eap_method::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)
|
||||
*
|
||||
* This function is a combination of m.check(), m.process(), and
|
||||
* m.buildResp() procedures defined in section 4.4 of RFC 4137 In other
|
||||
* words, this function validates the incoming request, processes it,
|
||||
* and build a response packet. m.check() and m.process() return values
|
||||
* are returned through struct eap_method_ret *ret variable. Caller is
|
||||
* responsible for freeing the returned EAP response packet.
|
||||
*/
|
||||
struct wpabuf * (*process)(struct eap_sm *sm, void *priv,
|
||||
struct eap_method_ret *ret,
|
||||
const struct wpabuf *reqData);
|
||||
bool (*isKeyAvailable)(struct eap_sm *sm, void *priv);
|
||||
u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);
|
||||
|
||||
/**
|
||||
* get_status - Get EAP method status
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @priv: Pointer to private EAP method data from eap_method::init()
|
||||
* @buf: Buffer for status information
|
||||
* @buflen: Maximum buffer length
|
||||
* @verbose: Whether to include verbose status information
|
||||
* Returns: Number of bytes written to buf
|
||||
*
|
||||
* Query EAP method for status information. This function fills in a
|
||||
* text area with current status information from the EAP method. If
|
||||
* the buffer (buf) is not large enough, status information will be
|
||||
* truncated to fit the buffer.
|
||||
*/
|
||||
int (*get_status)(struct eap_sm *sm, void *priv, char *buf,
|
||||
size_t buflen, int verbose);
|
||||
const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);
|
||||
void (*free)(struct eap_method *method);
|
||||
|
||||
/**
|
||||
* has_reauth_data - Whether method is ready for fast reauthentication
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @priv: Pointer to private EAP method data from eap_method::init()
|
||||
* Returns: %TRUE or %FALSE based on whether fast reauthentication is
|
||||
* possible
|
||||
*
|
||||
* This function is an optional handler that only EAP methods
|
||||
* supporting fast re-authentication need to implement.
|
||||
*/
|
||||
bool (*has_reauth_data)(struct eap_sm *sm, void *priv);
|
||||
|
||||
/**
|
||||
* deinit_for_reauth - Release data that is not needed for fast re-auth
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @priv: Pointer to private EAP method data from eap_method::init()
|
||||
*
|
||||
* This function is an optional handler that only EAP methods
|
||||
* supporting fast re-authentication need to implement. This is called
|
||||
* when authentication has been completed and EAP state machine is
|
||||
* requesting that enough state information is maintained for fast
|
||||
* re-authentication
|
||||
*/
|
||||
void (*deinit_for_reauth)(struct eap_sm *sm, void *priv);
|
||||
|
||||
/**
|
||||
* init_for_reauth - Prepare for start of fast re-authentication
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @priv: Pointer to private EAP method data from eap_method::init()
|
||||
*
|
||||
* This function is an optional handler that only EAP methods
|
||||
* supporting fast re-authentication need to implement. This is called
|
||||
* when EAP authentication is started and EAP state machine is
|
||||
* requesting fast re-authentication to be used.
|
||||
*/
|
||||
void * (*init_for_reauth)(struct eap_sm *sm, void *priv);
|
||||
|
||||
/**
|
||||
* get_identity - Get method specific identity for re-authentication
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @priv: Pointer to private EAP method data from eap_method::init()
|
||||
* @len: Length of the returned identity
|
||||
* Returns: Pointer to the method specific identity or %NULL if default
|
||||
* identity is to be used
|
||||
*
|
||||
* This function is an optional handler that only EAP methods
|
||||
* that use method specific identity need to implement.
|
||||
*/
|
||||
const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);
|
||||
|
||||
/**
|
||||
* free - Free EAP method data
|
||||
* @method: Pointer to the method data registered with
|
||||
* eap_peer_method_register().
|
||||
*
|
||||
* This function will be called when the EAP method is being
|
||||
* unregistered. If the EAP method allocated resources during
|
||||
* registration (e.g., allocated struct eap_method), they should be
|
||||
* freed in this function. No other method functions will be called
|
||||
* after this call. If this function is not defined (i.e., function
|
||||
* pointer is %NULL), a default handler is used to release the method
|
||||
* data with free(method). This is suitable for most cases.
|
||||
*/
|
||||
void (*free)(struct eap_method *method);
|
||||
|
||||
#define EAP_PEER_METHOD_INTERFACE_VERSION 1
|
||||
/**
|
||||
* version - Version of the EAP peer method interface
|
||||
*
|
||||
* The EAP peer method implementation should set this variable to
|
||||
* EAP_PEER_METHOD_INTERFACE_VERSION. This is used to verify that the
|
||||
* EAP method is using supported API version when using dynamically
|
||||
* loadable EAP methods.
|
||||
*/
|
||||
int version;
|
||||
|
||||
/**
|
||||
* next - Pointer to the next EAP method
|
||||
*
|
||||
* This variable is used internally in the EAP method registration code
|
||||
* to create a linked list of registered EAP methods.
|
||||
*/
|
||||
struct eap_method *next;
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_EAP_METHODS
|
||||
/**
|
||||
* dl_handle - Handle for the dynamic library
|
||||
*
|
||||
* This variable is used internally in the EAP method registration code
|
||||
* to store a handle for the dynamic library. If the method is linked
|
||||
* in statically, this is %NULL.
|
||||
*/
|
||||
void *dl_handle;
|
||||
#endif /* CONFIG_DYNAMIC_EAP_METHODS */
|
||||
|
||||
/**
|
||||
* get_emsk - Get EAP method specific keying extended material (EMSK)
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @priv: Pointer to private EAP method data from eap_method::init()
|
||||
* @len: Pointer to a variable to store EMSK length
|
||||
* Returns: EMSK or %NULL if not available
|
||||
*
|
||||
* This function can be used to get the extended keying material from
|
||||
* the EAP method. The key may already be stored in the method-specific
|
||||
* private data or this function may derive the key.
|
||||
*/
|
||||
u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);
|
||||
|
||||
/**
|
||||
* getSessionId - Get EAP method specific Session-Id
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @priv: Pointer to private EAP method data from eap_method::init()
|
||||
* @len: Pointer to a variable to store Session-Id length
|
||||
* Returns: Session-Id or %NULL if not available
|
||||
*
|
||||
* This function can be used to get the Session-Id from the EAP method.
|
||||
* The Session-Id may already be stored in the method-specific private
|
||||
* data or this function may derive the Session-Id.
|
||||
*/
|
||||
u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);
|
||||
};
|
||||
|
||||
@ -109,7 +277,10 @@ enum SIG_WPA2 {
|
||||
* struct eap_sm - EAP state machine data
|
||||
*/
|
||||
struct eap_sm {
|
||||
/* not defined in RFC 4137 */
|
||||
Boolean changed;
|
||||
void *eap_method_priv;
|
||||
int init_phase2;
|
||||
|
||||
void *ssl_ctx;
|
||||
|
||||
@ -125,7 +296,6 @@ struct eap_sm {
|
||||
#endif
|
||||
u8 finish_state;
|
||||
|
||||
int init_phase2;
|
||||
bool peap_done;
|
||||
|
||||
u8 *eapKeyData;
|
||||
@ -143,6 +313,11 @@ const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
|
||||
const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len);
|
||||
const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash);
|
||||
const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len);
|
||||
const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len);
|
||||
void eap_clear_config_otp(struct eap_sm *sm);
|
||||
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);
|
||||
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);
|
||||
|
@ -10,8 +10,10 @@
|
||||
|
||||
#ifdef EAP_TTLS
|
||||
#include "utils/common.h"
|
||||
#include "crypto/ms_funcs.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "tls/tls.h"
|
||||
#include "eap_peer/chap.h"
|
||||
#include "eap_peer/eap.h"
|
||||
#include "eap_peer/eap_ttls.h"
|
||||
#include "eap_peer/mschapv2.h"
|
||||
@ -74,29 +76,21 @@ static void * eap_ttls_init(struct eap_sm *sm)
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
data->ttls_version = EAP_TTLS_VERSION;
|
||||
data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
|
||||
data->phase2_type = EAP_TTLS_PHASE2_EAP;
|
||||
|
||||
/*
|
||||
selected = "MSCHAPV2";
|
||||
if (config && config->phase2) {
|
||||
if (os_strstr(config->phase2, "autheap=")) {
|
||||
selected = "EAP";
|
||||
data->phase2_type = EAP_TTLS_PHASE2_EAP;
|
||||
} else if (os_strstr(config->phase2, "auth=MSCHAPV2")) {
|
||||
selected = "MSCHAPV2";
|
||||
data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
|
||||
} else if (os_strstr(config->phase2, "auth=MSCHAP")) {
|
||||
selected = "MSCHAP";
|
||||
data->phase2_type = EAP_TTLS_PHASE2_MSCHAP;
|
||||
} else if (os_strstr(config->phase2, "auth=PAP")) {
|
||||
selected = "PAP";
|
||||
data->phase2_type = EAP_TTLS_PHASE2_PAP;
|
||||
} else if (os_strstr(config->phase2, "auth=CHAP")) {
|
||||
selected = "CHAP";
|
||||
data->phase2_type = EAP_TTLS_PHASE2_CHAP;
|
||||
}
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected);
|
||||
|
||||
if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
|
||||
if (eap_peer_select_phase2_methods(config, "autheap=",
|
||||
@ -110,7 +104,6 @@ static void * eap_ttls_init(struct eap_sm *sm)
|
||||
data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
|
||||
data->phase2_eap_type.method = EAP_TYPE_NONE;
|
||||
}
|
||||
*/
|
||||
|
||||
if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) {
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to initialize SSL.\n");
|
||||
@ -121,6 +114,7 @@ static void * eap_ttls_init(struct eap_sm *sm)
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm,
|
||||
struct eap_ttls_data *data)
|
||||
{
|
||||
@ -131,6 +125,7 @@ static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_ttls_data *data = priv;
|
||||
@ -145,6 +140,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id,
|
||||
int mandatory, size_t len)
|
||||
{
|
||||
@ -181,6 +177,32 @@ static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code,
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
|
||||
int mandatory)
|
||||
{
|
||||
struct wpabuf *msg;
|
||||
u8 *avp, *pos;
|
||||
|
||||
msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4);
|
||||
if (msg == NULL) {
|
||||
wpabuf_free(*resp);
|
||||
*resp = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
avp = wpabuf_mhead(msg);
|
||||
pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp));
|
||||
os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp));
|
||||
pos += wpabuf_len(*resp);
|
||||
AVP_PAD(avp, pos);
|
||||
wpabuf_free(*resp);
|
||||
wpabuf_put(msg, pos - avp);
|
||||
*resp = msg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int eap_ttls_v0_derive_key(struct eap_sm *sm,
|
||||
struct eap_ttls_data *data)
|
||||
{
|
||||
@ -193,11 +215,19 @@ static int eap_ttls_v0_derive_key(struct eap_sm *sm,
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
|
||||
data->key_data, EAP_TLS_KEY_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived EMSK",
|
||||
data->key_data + EAP_TLS_KEY_LEN,
|
||||
EAP_EMSK_LEN);
|
||||
|
||||
os_free(data->session_id);
|
||||
data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
|
||||
EAP_TYPE_TTLS,
|
||||
&data->id_len);
|
||||
if (data->session_id) {
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id",
|
||||
data->session_id, data->id_len);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id\n");
|
||||
}
|
||||
@ -206,17 +236,187 @@ static int eap_ttls_v0_derive_key(struct eap_sm *sm,
|
||||
}
|
||||
|
||||
|
||||
#ifndef CONFIG_FIPS
|
||||
static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
|
||||
struct eap_ttls_data *data, size_t len)
|
||||
{
|
||||
return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len);
|
||||
}
|
||||
#endif /* CONFIG_FIPS */
|
||||
|
||||
|
||||
static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data,
|
||||
u8 method)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < data->num_phase2_eap_types; i++) {
|
||||
if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF ||
|
||||
data->phase2_eap_types[i].method != method)
|
||||
continue;
|
||||
|
||||
data->phase2_eap_type.vendor =
|
||||
data->phase2_eap_types[i].vendor;
|
||||
data->phase2_eap_type.method =
|
||||
data->phase2_eap_types[i].method;
|
||||
wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
|
||||
"Phase 2 EAP vendor %d method %d",
|
||||
data->phase2_eap_type.vendor,
|
||||
data->phase2_eap_type.method);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int eap_ttls_phase2_eap_process(struct eap_sm *sm,
|
||||
struct eap_ttls_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
struct eap_hdr *hdr, size_t len,
|
||||
struct wpabuf **resp)
|
||||
{
|
||||
struct wpabuf msg;
|
||||
struct eap_method_ret iret;
|
||||
|
||||
os_memset(&iret, 0, sizeof(iret));
|
||||
wpabuf_set(&msg, hdr, len);
|
||||
*resp = data->phase2_method->process(sm, data->phase2_priv, &iret,
|
||||
&msg);
|
||||
if ((iret.methodState == METHOD_DONE ||
|
||||
iret.methodState == METHOD_MAY_CONT) &&
|
||||
(iret.decision == DECISION_UNCOND_SUCC ||
|
||||
iret.decision == DECISION_COND_SUCC ||
|
||||
iret.decision == DECISION_FAIL)) {
|
||||
ret->methodState = iret.methodState;
|
||||
ret->decision = iret.decision;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm,
|
||||
struct eap_ttls_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
struct eap_hdr *hdr, size_t len,
|
||||
u8 method, struct wpabuf **resp)
|
||||
{
|
||||
#ifdef EAP_TNC
|
||||
if (data->tnc_started && data->phase2_method &&
|
||||
data->phase2_priv && method == EAP_TYPE_TNC &&
|
||||
data->phase2_eap_type.method == EAP_TYPE_TNC)
|
||||
return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len,
|
||||
resp);
|
||||
|
||||
if (data->ready_for_tnc && !data->tnc_started &&
|
||||
method == EAP_TYPE_TNC) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed "
|
||||
"EAP method");
|
||||
data->tnc_started = 1;
|
||||
}
|
||||
|
||||
if (data->tnc_started) {
|
||||
if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF ||
|
||||
data->phase2_eap_type.method == EAP_TYPE_TNC) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected EAP "
|
||||
"type %d for TNC", method);
|
||||
return -1;
|
||||
}
|
||||
|
||||
data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
|
||||
data->phase2_eap_type.method = method;
|
||||
wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
|
||||
"Phase 2 EAP vendor %d method %d (TNC)",
|
||||
data->phase2_eap_type.vendor,
|
||||
data->phase2_eap_type.method);
|
||||
|
||||
if (data->phase2_type == EAP_TTLS_PHASE2_EAP)
|
||||
eap_ttls_phase2_eap_deinit(sm, data);
|
||||
}
|
||||
#endif /* EAP_TNC */
|
||||
|
||||
if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF &&
|
||||
data->phase2_eap_type.method == EAP_TYPE_NONE)
|
||||
eap_ttls_phase2_select_eap_method(data, method);
|
||||
|
||||
if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE)
|
||||
{
|
||||
if (eap_peer_tls_phase2_nak(data->phase2_eap_types,
|
||||
data->num_phase2_eap_types,
|
||||
hdr, resp))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data->phase2_priv == NULL) {
|
||||
data->phase2_method = eap_peer_get_eap_method(
|
||||
EAP_VENDOR_IETF, method);
|
||||
if (data->phase2_method) {
|
||||
sm->init_phase2 = 1;
|
||||
data->phase2_priv = data->phase2_method->init(sm);
|
||||
sm->init_phase2 = 0;
|
||||
}
|
||||
}
|
||||
if (data->phase2_priv == NULL || data->phase2_method == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize "
|
||||
"Phase 2 EAP method %d", method);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp);
|
||||
}
|
||||
|
||||
|
||||
static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
|
||||
struct eap_ttls_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
struct eap_hdr *hdr,
|
||||
struct wpabuf **resp)
|
||||
{
|
||||
size_t len = be_to_host16(hdr->length);
|
||||
u8 *pos;
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
|
||||
if (len <= sizeof(struct eap_hdr)) {
|
||||
wpa_printf(MSG_INFO, "EAP-TTLS: too short "
|
||||
"Phase 2 request (len=%lu)", (unsigned long) len);
|
||||
return -1;
|
||||
}
|
||||
pos = (u8 *) (hdr + 1);
|
||||
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos);
|
||||
switch (*pos) {
|
||||
case EAP_TYPE_IDENTITY:
|
||||
*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
|
||||
break;
|
||||
default:
|
||||
if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len,
|
||||
*pos, resp) < 0)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*resp == NULL &&
|
||||
(config->pending_req_identity || config->pending_req_password ||
|
||||
config->pending_req_otp)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*resp == NULL)
|
||||
return -1;
|
||||
|
||||
wpa_hexdump_buf(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response",
|
||||
*resp);
|
||||
return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1);
|
||||
}
|
||||
|
||||
|
||||
static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
|
||||
struct eap_ttls_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
struct wpabuf **resp)
|
||||
struct eap_ttls_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
struct wpabuf **resp)
|
||||
{
|
||||
#ifdef CONFIG_FIPS
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPV2 not supported in FIPS build");
|
||||
return -1;
|
||||
#else /* CONFIG_FIPS */
|
||||
#ifdef EAP_MSCHAPv2
|
||||
struct wpabuf *msg;
|
||||
u8 *buf, *pos, *challenge, *peer_challenge;
|
||||
@ -309,8 +509,232 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build\n");
|
||||
return -1;
|
||||
#endif /* EAP_MSCHAPv2 */
|
||||
#endif /* CONFIG_FIPS */
|
||||
}
|
||||
|
||||
|
||||
static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
|
||||
struct eap_ttls_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
struct wpabuf **resp)
|
||||
{
|
||||
#ifdef CONFIG_FIPS
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAP not supported in FIPS build");
|
||||
return -1;
|
||||
#else /* CONFIG_FIPS */
|
||||
struct wpabuf *msg;
|
||||
u8 *buf, *pos, *challenge;
|
||||
const u8 *identity, *password;
|
||||
size_t identity_len, password_len;
|
||||
int pwhash;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request");
|
||||
|
||||
identity = eap_get_config_identity(sm, &identity_len);
|
||||
password = eap_get_config_password2(sm, &password_len, &pwhash);
|
||||
if (identity == NULL || password == NULL)
|
||||
return -1;
|
||||
|
||||
msg = wpabuf_alloc(identity_len + 1000);
|
||||
if (msg == NULL) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"EAP-TTLS/MSCHAP: Failed to allocate memory");
|
||||
return -1;
|
||||
}
|
||||
pos = buf = wpabuf_mhead(msg);
|
||||
|
||||
/* User-Name */
|
||||
pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
|
||||
identity, identity_len);
|
||||
|
||||
/* MS-CHAP-Challenge */
|
||||
challenge = eap_ttls_implicit_challenge(
|
||||
sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
|
||||
if (challenge == NULL) {
|
||||
wpabuf_free(msg);
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive "
|
||||
"implicit challenge");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE,
|
||||
RADIUS_VENDOR_ID_MICROSOFT, 1,
|
||||
challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN);
|
||||
|
||||
/* MS-CHAP-Response */
|
||||
pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE,
|
||||
RADIUS_VENDOR_ID_MICROSOFT, 1,
|
||||
EAP_TTLS_MSCHAP_RESPONSE_LEN);
|
||||
data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN];
|
||||
*pos++ = data->ident;
|
||||
*pos++ = 1; /* Flags: Use NT style passwords */
|
||||
os_memset(pos, 0, 24); /* LM-Response */
|
||||
pos += 24;
|
||||
if (pwhash) {
|
||||
challenge_response(challenge, password, pos); /* NT-Response */
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash",
|
||||
password, 16);
|
||||
} else {
|
||||
nt_challenge_response(challenge, password, password_len,
|
||||
pos); /* NT-Response */
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password",
|
||||
password, password_len);
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge",
|
||||
challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24);
|
||||
pos += 24;
|
||||
os_free(challenge);
|
||||
AVP_PAD(buf, pos);
|
||||
|
||||
wpabuf_put(msg, pos - buf);
|
||||
*resp = msg;
|
||||
|
||||
/* EAP-TTLS/MSCHAP does not provide tunneled success
|
||||
* notification, so assume that Phase2 succeeds. */
|
||||
ret->methodState = METHOD_DONE;
|
||||
ret->decision = DECISION_COND_SUCC;
|
||||
|
||||
return 0;
|
||||
#endif /* CONFIG_FIPS */
|
||||
}
|
||||
|
||||
|
||||
static int eap_ttls_phase2_request_pap(struct eap_sm *sm,
|
||||
struct eap_ttls_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
struct wpabuf **resp)
|
||||
{
|
||||
struct wpabuf *msg;
|
||||
u8 *buf, *pos;
|
||||
size_t pad;
|
||||
const u8 *identity, *password;
|
||||
size_t identity_len, password_len;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request");
|
||||
|
||||
identity = eap_get_config_identity(sm, &identity_len);
|
||||
password = eap_get_config_password(sm, &password_len);
|
||||
if (identity == NULL || password == NULL)
|
||||
return -1;
|
||||
|
||||
msg = wpabuf_alloc(identity_len + password_len + 100);
|
||||
if (msg == NULL) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"EAP-TTLS/PAP: Failed to allocate memory");
|
||||
return -1;
|
||||
}
|
||||
pos = buf = wpabuf_mhead(msg);
|
||||
|
||||
/* User-Name */
|
||||
pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
|
||||
identity, identity_len);
|
||||
|
||||
/* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts
|
||||
* the data, so no separate encryption is used in the AVP itself.
|
||||
* However, the password is padded to obfuscate its length. */
|
||||
pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15;
|
||||
pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1,
|
||||
password_len + pad);
|
||||
os_memcpy(pos, password, password_len);
|
||||
pos += password_len;
|
||||
os_memset(pos, 0, pad);
|
||||
pos += pad;
|
||||
AVP_PAD(buf, pos);
|
||||
|
||||
wpabuf_put(msg, pos - buf);
|
||||
*resp = msg;
|
||||
|
||||
/* EAP-TTLS/PAP does not provide tunneled success notification,
|
||||
* so assume that Phase2 succeeds. */
|
||||
ret->methodState = METHOD_DONE;
|
||||
ret->decision = DECISION_COND_SUCC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
|
||||
struct eap_ttls_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
struct wpabuf **resp)
|
||||
{
|
||||
#ifdef CONFIG_FIPS
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS: CHAP not supported in FIPS build");
|
||||
return -1;
|
||||
#else /* CONFIG_FIPS */
|
||||
struct wpabuf *msg;
|
||||
u8 *buf, *pos, *challenge;
|
||||
const u8 *identity, *password;
|
||||
size_t identity_len, password_len;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request");
|
||||
|
||||
identity = eap_get_config_identity(sm, &identity_len);
|
||||
password = eap_get_config_password(sm, &password_len);
|
||||
if (identity == NULL || password == NULL)
|
||||
return -1;
|
||||
|
||||
msg = wpabuf_alloc(identity_len + 1000);
|
||||
if (msg == NULL) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"EAP-TTLS/CHAP: Failed to allocate memory");
|
||||
return -1;
|
||||
}
|
||||
pos = buf = wpabuf_mhead(msg);
|
||||
|
||||
/* User-Name */
|
||||
pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
|
||||
identity, identity_len);
|
||||
|
||||
/* CHAP-Challenge */
|
||||
challenge = eap_ttls_implicit_challenge(
|
||||
sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
|
||||
if (challenge == NULL) {
|
||||
wpabuf_free(msg);
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive "
|
||||
"implicit challenge");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1,
|
||||
challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
|
||||
|
||||
/* CHAP-Password */
|
||||
pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1,
|
||||
1 + EAP_TTLS_CHAP_PASSWORD_LEN);
|
||||
data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN];
|
||||
*pos++ = data->ident;
|
||||
|
||||
/* MD5(Ident + Password + Challenge) */
|
||||
chap_md5(data->ident, password, password_len, challenge,
|
||||
EAP_TTLS_CHAP_CHALLENGE_LEN, pos);
|
||||
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username",
|
||||
identity, identity_len);
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password",
|
||||
password, password_len);
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge",
|
||||
challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password",
|
||||
pos, EAP_TTLS_CHAP_PASSWORD_LEN);
|
||||
pos += EAP_TTLS_CHAP_PASSWORD_LEN;
|
||||
os_free(challenge);
|
||||
AVP_PAD(buf, pos);
|
||||
|
||||
wpabuf_put(msg, pos - buf);
|
||||
*resp = msg;
|
||||
|
||||
/* EAP-TTLS/CHAP does not provide tunneled success
|
||||
* notification, so assume that Phase2 succeeds. */
|
||||
ret->methodState = METHOD_DONE;
|
||||
ret->decision = DECISION_COND_SUCC;
|
||||
|
||||
return 0;
|
||||
#endif /* CONFIG_FIPS */
|
||||
}
|
||||
|
||||
|
||||
static int eap_ttls_phase2_request(struct eap_sm *sm,
|
||||
struct eap_ttls_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
@ -329,32 +753,14 @@ static int eap_ttls_phase2_request(struct eap_sm *sm,
|
||||
}
|
||||
#endif /* EAP_TNC */
|
||||
|
||||
if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2) {
|
||||
if (eap_get_config_identity(sm, &len) == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS: Identity not configured\n");
|
||||
printf("[Debug] Return because no identity EAP_TTLS_PHASE2_MSCHAPV2\n");
|
||||
return 0;
|
||||
}
|
||||
if (eap_get_config_password(sm, &len) == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS: Password not configured\n");
|
||||
printf("[Debug] Return because no password EAP_TTLS_PHASE2_MSCHAPV2\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown type %d\n", phase2_type);
|
||||
res = -1;
|
||||
}
|
||||
|
||||
/* if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 ||
|
||||
if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 ||
|
||||
phase2_type == EAP_TTLS_PHASE2_MSCHAP ||
|
||||
phase2_type == EAP_TTLS_PHASE2_PAP ||
|
||||
phase2_type == EAP_TTLS_PHASE2_CHAP) {
|
||||
if (eap_get_config_identity(sm, &len) == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS: Identity not configured\n");
|
||||
if (eap_get_config_password(sm, &len) == NULL);
|
||||
printf("[Debug] Return because no identity EAP_TTLS_PHASE2_MSCHAPV2 EAP_TTLS_PHASE2_MSCHAP\n");
|
||||
if (eap_get_config_password(sm, &len) == NULL)
|
||||
printf("[Debug] Return because no identity EAP_TTLS_PHASE2_MSCHAPV2 EAP_TTLS_PHASE2_MSCHAP\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -367,31 +773,25 @@ static int eap_ttls_phase2_request(struct eap_sm *sm,
|
||||
|
||||
switch (phase2_type) {
|
||||
case EAP_TTLS_PHASE2_EAP:
|
||||
printf("[Debug] EAP_TTLS_PHASE2_EAP typed \n");
|
||||
res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp);
|
||||
break;
|
||||
case EAP_TTLS_PHASE2_MSCHAPV2:
|
||||
printf("[Debug] EAP_TTLS_PHASE2_MSCHAPV2 typed \n");
|
||||
res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp);
|
||||
break;
|
||||
case EAP_TTLS_PHASE2_MSCHAP:
|
||||
printf("[Debug] EAP_TTLS_PHASE2_MSCHAP typed \n");
|
||||
res = eap_ttls_phase2_request_mschap(sm, data, ret, resp);
|
||||
break;
|
||||
case EAP_TTLS_PHASE2_PAP:
|
||||
printf("[Debug] EAP_TTLS_PHASE2_PAP typed \n");
|
||||
res = eap_ttls_phase2_request_pap(sm, data, ret, resp);
|
||||
break;
|
||||
case EAP_TTLS_PHASE2_CHAP:
|
||||
printf("[Debug] EAP_TTLS_PHASE2_CHAP typed \n");
|
||||
res = eap_ttls_phase2_request_chap(sm, data, ret, resp);
|
||||
break;
|
||||
default:
|
||||
printf("[Debug] Default typed \n");
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown\n");
|
||||
res = -1;
|
||||
break;
|
||||
}*/
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
ret->methodState = METHOD_DONE;
|
||||
@ -483,14 +883,20 @@ static int eap_ttls_parse_avp(u8 *pos, size_t left,
|
||||
dlen -= 4;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen);
|
||||
|
||||
if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) {
|
||||
if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0)
|
||||
return -1;
|
||||
} else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) {
|
||||
/* This is an optional message that can be displayed to
|
||||
* the user. */
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: AVP - Reply-Message",
|
||||
dpos, dlen);
|
||||
} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
|
||||
avp_code == RADIUS_ATTR_MS_CHAP2_SUCCESS) {
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP2-Success",
|
||||
dpos, dlen);
|
||||
if (dlen != 43) {
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS: Unexpected "
|
||||
"MS-CHAP2-Success length "
|
||||
@ -501,6 +907,8 @@ static int eap_ttls_parse_avp(u8 *pos, size_t left,
|
||||
parse->mschapv2 = dpos;
|
||||
} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
|
||||
avp_code == RADIUS_ATTR_MS_CHAP_ERROR) {
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP-Error",
|
||||
dpos, dlen);
|
||||
parse->mschapv2_error = 1;
|
||||
} else if (avp_flags & AVP_FLAGS_MANDATORY) {
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS: Unsupported mandatory AVP "
|
||||
@ -526,6 +934,7 @@ static int eap_ttls_parse_avps(struct wpabuf *in_decrypted,
|
||||
|
||||
pos = wpabuf_mhead(in_decrypted);
|
||||
left = wpabuf_len(in_decrypted);
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", pos, left);
|
||||
if (left < sizeof(struct ttls_avp)) {
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS: Too short Phase 2 AVP frame"
|
||||
" len=%lu expected %lu or more - dropped\n",
|
||||
@ -597,6 +1006,63 @@ static int eap_ttls_encrypt_response(struct eap_sm *sm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int eap_ttls_process_phase2_eap(struct eap_sm *sm,
|
||||
struct eap_ttls_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
struct ttls_parse_avp *parse,
|
||||
struct wpabuf **resp)
|
||||
{
|
||||
struct eap_hdr *hdr;
|
||||
size_t len;
|
||||
|
||||
if (parse->eapdata == NULL) {
|
||||
wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the "
|
||||
"packet - dropped");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP",
|
||||
parse->eapdata, parse->eap_len);
|
||||
hdr = (struct eap_hdr *) parse->eapdata;
|
||||
|
||||
if (parse->eap_len < sizeof(*hdr)) {
|
||||
wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP "
|
||||
"frame (len=%lu, expected %lu or more) - dropped",
|
||||
(unsigned long) parse->eap_len,
|
||||
(unsigned long) sizeof(*hdr));
|
||||
return -1;
|
||||
}
|
||||
len = be_to_host16(hdr->length);
|
||||
if (len > parse->eap_len) {
|
||||
wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 "
|
||||
"EAP frame (EAP hdr len=%lu, EAP data len in "
|
||||
"AVP=%lu)",
|
||||
(unsigned long) len,
|
||||
(unsigned long) parse->eap_len);
|
||||
return -1;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d "
|
||||
"identifier=%d length=%lu",
|
||||
hdr->code, hdr->identifier, (unsigned long) len);
|
||||
switch (hdr->code) {
|
||||
case EAP_CODE_REQUEST:
|
||||
if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) {
|
||||
wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request "
|
||||
"processing failed");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in "
|
||||
"Phase 2 EAP header", hdr->code);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
|
||||
struct eap_ttls_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
@ -701,6 +1167,7 @@ static int eap_ttls_process_decrypted(struct eap_sm *sm,
|
||||
struct wpabuf *resp = NULL;
|
||||
int res;
|
||||
enum phase2_types phase2_type = data->phase2_type;
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
|
||||
#ifdef EAP_TNC
|
||||
if (data->tnc_started)
|
||||
@ -708,6 +1175,11 @@ static int eap_ttls_process_decrypted(struct eap_sm *sm,
|
||||
#endif /* EAP_TNC */
|
||||
|
||||
switch (phase2_type) {
|
||||
case EAP_TTLS_PHASE2_EAP:
|
||||
if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) <
|
||||
0)
|
||||
return -1;
|
||||
break;
|
||||
case EAP_TTLS_PHASE2_MSCHAPV2:
|
||||
res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse);
|
||||
#ifdef EAP_TNC
|
||||
@ -724,11 +1196,6 @@ static int eap_ttls_process_decrypted(struct eap_sm *sm,
|
||||
}
|
||||
#endif /* EAP_TNC */
|
||||
return res;
|
||||
/* case EAP_TTLS_PHASE2_EAP:
|
||||
if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) <
|
||||
0)
|
||||
return -1;
|
||||
break;
|
||||
case EAP_TTLS_PHASE2_MSCHAP:
|
||||
case EAP_TTLS_PHASE2_PAP:
|
||||
case EAP_TTLS_PHASE2_CHAP:
|
||||
@ -737,32 +1204,26 @@ static int eap_ttls_process_decrypted(struct eap_sm *sm,
|
||||
0)
|
||||
return -1;
|
||||
break;
|
||||
#else // EAP_TNC
|
||||
// EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled
|
||||
// requests to the supplicant
|
||||
wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 received unexpected "
|
||||
"tunneled data\n");
|
||||
return -1;
|
||||
#endif // EAP_TNC
|
||||
*/
|
||||
default:
|
||||
#else /* EAP_TNC */
|
||||
/* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled
|
||||
* requests to the supplicant */
|
||||
wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected "
|
||||
"tunneled data");
|
||||
return -1;
|
||||
#endif /* EAP_TNC */
|
||||
}
|
||||
|
||||
if (resp) {
|
||||
if (eap_ttls_encrypt_response(sm, data, resp, identifier,
|
||||
out_data) < 0)
|
||||
return -1;
|
||||
} else {
|
||||
wpabuf_free(data->pending_phase2_req);
|
||||
data->pending_phase2_req = wpabuf_dup(in_decrypted);
|
||||
}/* else if (config->pending_req_identity ||
|
||||
} else if (config->pending_req_identity ||
|
||||
config->pending_req_password ||
|
||||
config->pending_req_otp ||
|
||||
config->pending_req_new_password) {
|
||||
wpabuf_free(data->pending_phase2_req);
|
||||
data->pending_phase2_req = wpabuf_dup(in_decrypted);
|
||||
}*/
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -791,11 +1252,12 @@ static int eap_ttls_implicit_identity_request(struct eap_sm *sm,
|
||||
"processing failed\n");
|
||||
retval = -1;
|
||||
} else {
|
||||
if (resp == NULL) {/* &&
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
if (resp == NULL &&
|
||||
(config->pending_req_identity ||
|
||||
config->pending_req_password ||
|
||||
config->pending_req_otp ||
|
||||
config->pending_req_new_password)) {*/
|
||||
config->pending_req_new_password)) {
|
||||
/*
|
||||
* Use empty buffer to force implicit request
|
||||
* processing when EAP request is re-processed after
|
||||
@ -1118,15 +1580,15 @@ static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf,
|
||||
return len;
|
||||
len += ret;
|
||||
switch (data->phase2_type) {
|
||||
/*case EAP_TTLS_PHASE2_EAP:
|
||||
case EAP_TTLS_PHASE2_EAP:
|
||||
ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n",
|
||||
data->phase2_method ?
|
||||
data->phase2_method->name : "?");
|
||||
break;*/
|
||||
break;
|
||||
case EAP_TTLS_PHASE2_MSCHAPV2:
|
||||
ret = snprintf(buf + len, buflen - len, "MSCHAPV2\n");
|
||||
break;
|
||||
/*case EAP_TTLS_PHASE2_MSCHAP:
|
||||
case EAP_TTLS_PHASE2_MSCHAP:
|
||||
ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n");
|
||||
break;
|
||||
case EAP_TTLS_PHASE2_PAP:
|
||||
@ -1134,7 +1596,7 @@ static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf,
|
||||
break;
|
||||
case EAP_TTLS_PHASE2_CHAP:
|
||||
ret = os_snprintf(buf + len, buflen - len, "CHAP\n");
|
||||
break;*/
|
||||
break;
|
||||
default:
|
||||
ret = 0;
|
||||
break;
|
||||
@ -1191,6 +1653,26 @@ static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
|
||||
{
|
||||
struct eap_ttls_data *data = priv;
|
||||
u8 *key;
|
||||
|
||||
if (data->key_data == NULL)
|
||||
return NULL;
|
||||
|
||||
key = os_malloc(EAP_EMSK_LEN);
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
|
||||
*len = EAP_EMSK_LEN;
|
||||
os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
int eap_peer_ttls_register(void)
|
||||
{
|
||||
struct eap_method *eap;
|
||||
@ -1211,6 +1693,7 @@ int eap_peer_ttls_register(void)
|
||||
eap->has_reauth_data = eap_ttls_has_reauth_data;
|
||||
eap->deinit_for_reauth = eap_ttls_deinit_for_reauth;
|
||||
eap->init_for_reauth = eap_ttls_init_for_reauth;
|
||||
eap->get_emsk = eap_ttls_get_emsk;
|
||||
|
||||
ret = eap_peer_method_register(eap);
|
||||
if (ret)
|
||||
|
@ -1148,3 +1148,28 @@ esp_err_t esp_wifi_sta_wpa2_ent_get_disable_time_check(bool *disable)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_ttls_phase2_method(esp_eap_ttls_phase2_types type)
|
||||
{
|
||||
switch (type) {
|
||||
case ESP_EAP_TTLS_PHASE2_EAP:
|
||||
g_wpa_ttls_phase2_type = "auth=EAP";
|
||||
break;
|
||||
case ESP_EAP_TTLS_PHASE2_MSCHAPV2:
|
||||
g_wpa_ttls_phase2_type = "auth=MSCHAPV2";
|
||||
break;
|
||||
case ESP_EAP_TTLS_PHASE2_MSCHAP:
|
||||
g_wpa_ttls_phase2_type = "auth=MSCHAP";
|
||||
break;
|
||||
case ESP_EAP_TTLS_PHASE2_PAP:
|
||||
g_wpa_ttls_phase2_type = "auth=PAP";
|
||||
break;
|
||||
case ESP_EAP_TTLS_PHASE2_CHAP:
|
||||
g_wpa_ttls_phase2_type = "auth=CHAP";
|
||||
break;
|
||||
default:
|
||||
g_wpa_ttls_phase2_type = "auth=MSCHAPV2";
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ void ext_password_free(struct wpabuf *pw);
|
||||
|
||||
#define ext_password_init(b, p)
|
||||
#define ext_password_deinit(d)
|
||||
#define ext_password_get(d, n)
|
||||
#define ext_password_get(d, n) NULL
|
||||
#define ext_password_free(p)
|
||||
|
||||
#endif /* CONFIG_EXT_PASSWORD */
|
||||
|
@ -29,6 +29,27 @@ menu "Example Configuration"
|
||||
default 1 if EXAMPLE_EAP_METHOD_PEAP
|
||||
default 2 if EXAMPLE_EAP_METHOD_TTLS
|
||||
|
||||
choice
|
||||
prompt "Phase2 method for TTLS"
|
||||
depends on EXAMPLE_EAP_METHOD_TTLS
|
||||
default EXAMPLE_EAP_METHOD_TTLS_PHASE2_MSCHAPV2
|
||||
config EXAMPLE_EAP_METHOD_TTLS_PHASE2_MSCHAPV2
|
||||
bool "MSCHAPV2"
|
||||
config EXAMPLE_EAP_METHOD_TTLS_PHASE2_MSCHAP
|
||||
bool "MSCHAP"
|
||||
config EXAMPLE_EAP_METHOD_TTLS_PHASE2_PAP
|
||||
bool "PAP"
|
||||
config EXAMPLE_EAP_METHOD_TTLS_PHASE2_CHAP
|
||||
bool "CHAP"
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_EAP_METHOD_TTLS_PHASE_2
|
||||
int
|
||||
default 1 if EXAMPLE_EAP_METHOD_TTLS_PHASE2_MSCHAPV2
|
||||
default 2 if EXAMPLE_EAP_METHOD_TTLS_PHASE2_MSCHAP
|
||||
default 3 if EXAMPLE_EAP_METHOD_TTLS_PHASE2_PAP
|
||||
default 4 if EXAMPLE_EAP_METHOD_TTLS_PHASE2_CHAP
|
||||
|
||||
config EXAMPLE_EAP_ID
|
||||
string "EAP ID"
|
||||
default "example@espressif.com"
|
||||
|
@ -80,6 +80,10 @@ extern uint8_t client_key_start[] asm("_binary_wpa2_client_key_start");
|
||||
extern uint8_t client_key_end[] asm("_binary_wpa2_client_key_end");
|
||||
#endif /* CONFIG_EXAMPLE_EAP_METHOD_TLS */
|
||||
|
||||
#if defined CONFIG_EXAMPLE_EAP_METHOD_TTLS
|
||||
esp_eap_ttls_phase2_types TTLS_PHASE2_METHOD = CONFIG_EXAMPLE_EAP_METHOD_TTLS_PHASE_2;
|
||||
#endif /* CONFIG_EXAMPLE_EAP_METHOD_TTLS */
|
||||
|
||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
{
|
||||
@ -139,6 +143,10 @@ static void initialise_wifi(void)
|
||||
ESP_ERROR_CHECK( esp_wifi_sta_wpa2_ent_set_password((uint8_t *)EXAMPLE_EAP_PASSWORD, strlen(EXAMPLE_EAP_PASSWORD)) );
|
||||
#endif /* CONFIG_EXAMPLE_EAP_METHOD_PEAP || CONFIG_EXAMPLE_EAP_METHOD_TTLS */
|
||||
|
||||
#if defined CONFIG_EXAMPLE_EAP_METHOD_TTLS
|
||||
ESP_ERROR_CHECK( esp_wifi_sta_wpa2_ent_set_ttls_phase2_method(TTLS_PHASE2_METHOD) );
|
||||
#endif /* CONFIG_EXAMPLE_EAP_METHOD_TTLS */
|
||||
|
||||
ESP_ERROR_CHECK( esp_wifi_sta_wpa2_ent_enable() );
|
||||
ESP_ERROR_CHECK( esp_wifi_start() );
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user