wpa_supplicant: add support for PAP, MS-CHAP and CHAP as Phase 2 algorithms for TTLS alongside MS-CHAPv2

This commit is contained in:
Hrudaynath Dhabe 2020-06-23 14:04:23 +05:30 committed by bot
parent a60dccb8c2
commit d7ccad371a
12 changed files with 1154 additions and 77 deletions

View File

@ -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

View File

@ -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)

View 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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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;
/**

View File

@ -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);

View File

@ -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)

View File

@ -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;
}

View File

@ -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 */

View File

@ -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"

View File

@ -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() );
}