mirror of
https://github.com/espressif/esp-idf.git
synced 2025-10-10 15:04:53 +00:00
wpa_supplicant: Add upstream files for wps registrar
This commit is contained in:
295
components/wpa_supplicant/src/eap_server/eap.h
Normal file
295
components/wpa_supplicant/src/eap_server/eap.h
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* hostapd / EAP Full Authenticator state machine (RFC 4137)
|
||||
* Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef EAP_H
|
||||
#define EAP_H
|
||||
|
||||
#include "common/defs.h"
|
||||
#include "utils/list.h"
|
||||
#include "eap_common/eap_defs.h"
|
||||
#include "eap_server/eap_methods.h"
|
||||
#include "wpabuf.h"
|
||||
|
||||
struct eap_sm;
|
||||
|
||||
#define EAP_TTLS_AUTH_PAP 1
|
||||
#define EAP_TTLS_AUTH_CHAP 2
|
||||
#define EAP_TTLS_AUTH_MSCHAP 4
|
||||
#define EAP_TTLS_AUTH_MSCHAPV2 8
|
||||
|
||||
struct eap_user {
|
||||
struct {
|
||||
int vendor;
|
||||
u32 method;
|
||||
} methods[EAP_MAX_METHODS];
|
||||
u8 *password;
|
||||
size_t password_len;
|
||||
int password_hash; /* whether password is hashed with
|
||||
* nt_password_hash() */
|
||||
u8 *salt;
|
||||
size_t salt_len;
|
||||
int phase2;
|
||||
int force_version;
|
||||
unsigned int remediation:1;
|
||||
unsigned int macacl:1;
|
||||
int ttls_auth; /* bitfield of
|
||||
* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
|
||||
struct hostapd_radius_attr *accept_attr;
|
||||
u32 t_c_timestamp;
|
||||
};
|
||||
|
||||
struct eap_eapol_interface {
|
||||
/* Lower layer to full authenticator variables */
|
||||
bool eapResp; /* shared with EAPOL Backend Authentication */
|
||||
struct wpabuf *eapRespData;
|
||||
bool portEnabled;
|
||||
int retransWhile;
|
||||
bool eapRestart; /* shared with EAPOL Authenticator PAE */
|
||||
int eapSRTT;
|
||||
int eapRTTVAR;
|
||||
|
||||
/* Full authenticator to lower layer variables */
|
||||
bool eapReq; /* shared with EAPOL Backend Authentication */
|
||||
bool eapNoReq; /* shared with EAPOL Backend Authentication */
|
||||
bool eapSuccess;
|
||||
bool eapFail;
|
||||
bool eapTimeout;
|
||||
struct wpabuf *eapReqData;
|
||||
u8 *eapKeyData;
|
||||
size_t eapKeyDataLen;
|
||||
u8 *eapSessionId;
|
||||
size_t eapSessionIdLen;
|
||||
bool eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */
|
||||
|
||||
/* AAA interface to full authenticator variables */
|
||||
bool aaaEapReq;
|
||||
bool aaaEapNoReq;
|
||||
bool aaaSuccess;
|
||||
bool aaaFail;
|
||||
struct wpabuf *aaaEapReqData;
|
||||
u8 *aaaEapKeyData;
|
||||
size_t aaaEapKeyDataLen;
|
||||
bool aaaEapKeyAvailable;
|
||||
int aaaMethodTimeout;
|
||||
|
||||
/* Full authenticator to AAA interface variables */
|
||||
bool aaaEapResp;
|
||||
struct wpabuf *aaaEapRespData;
|
||||
/* aaaIdentity -> eap_get_identity() */
|
||||
bool aaaTimeout;
|
||||
};
|
||||
|
||||
struct eap_server_erp_key {
|
||||
struct dl_list list;
|
||||
size_t rRK_len;
|
||||
size_t rIK_len;
|
||||
u8 rRK[ERP_MAX_KEY_LEN];
|
||||
u8 rIK[ERP_MAX_KEY_LEN];
|
||||
u32 recv_seq;
|
||||
u8 cryptosuite;
|
||||
char keyname_nai[];
|
||||
};
|
||||
|
||||
struct eapol_callbacks {
|
||||
int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
|
||||
int phase2, struct eap_user *user);
|
||||
const char * (*get_eap_req_id_text)(void *ctx, size_t *len);
|
||||
void (*log_msg)(void *ctx, const char *msg);
|
||||
int (*get_erp_send_reauth_start)(void *ctx);
|
||||
const char * (*get_erp_domain)(void *ctx);
|
||||
struct eap_server_erp_key * (*erp_get_key)(void *ctx,
|
||||
const char *keyname);
|
||||
int (*erp_add_key)(void *ctx, struct eap_server_erp_key *erp);
|
||||
};
|
||||
|
||||
struct eap_config {
|
||||
/**
|
||||
* ssl_ctx - TLS context
|
||||
*
|
||||
* This is passed to the EAP server implementation as a callback
|
||||
* context for TLS operations.
|
||||
*/
|
||||
void *ssl_ctx;
|
||||
void *msg_ctx;
|
||||
|
||||
/**
|
||||
* eap_sim_db_priv - EAP-SIM/AKA database context
|
||||
*
|
||||
* This is passed to the EAP-SIM/AKA server implementation as a
|
||||
* callback context.
|
||||
*/
|
||||
void *eap_sim_db_priv;
|
||||
bool backend_auth;
|
||||
int eap_server;
|
||||
|
||||
/**
|
||||
* pwd_group - The D-H group assigned for EAP-pwd
|
||||
*
|
||||
* If EAP-pwd is not used it can be set to zero.
|
||||
*/
|
||||
u16 pwd_group;
|
||||
|
||||
/**
|
||||
* pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
|
||||
*
|
||||
* This parameter is used to set a key for EAP-FAST to encrypt the
|
||||
* PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
|
||||
* set, must point to a 16-octet key.
|
||||
*/
|
||||
u8 *pac_opaque_encr_key;
|
||||
|
||||
/**
|
||||
* eap_fast_a_id - EAP-FAST authority identity (A-ID)
|
||||
*
|
||||
* If EAP-FAST is not used, this can be set to %NULL. In theory, this
|
||||
* is a variable length field, but due to some existing implementations
|
||||
* requiring A-ID to be 16 octets in length, it is recommended to use
|
||||
* that length for the field to provide interoperability with deployed
|
||||
* peer implementations.
|
||||
*/
|
||||
u8 *eap_fast_a_id;
|
||||
|
||||
/**
|
||||
* eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
|
||||
*/
|
||||
size_t eap_fast_a_id_len;
|
||||
/**
|
||||
* eap_fast_a_id_info - EAP-FAST authority identifier information
|
||||
*
|
||||
* This A-ID-Info contains a user-friendly name for the A-ID. For
|
||||
* example, this could be the enterprise and server names in
|
||||
* human-readable format. This field is encoded as UTF-8. If EAP-FAST
|
||||
* is not used, this can be set to %NULL.
|
||||
*/
|
||||
char *eap_fast_a_id_info;
|
||||
|
||||
/**
|
||||
* eap_fast_prov - EAP-FAST provisioning modes
|
||||
*
|
||||
* 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
|
||||
* 2 = only authenticated provisioning allowed, 3 = both provisioning
|
||||
* modes allowed.
|
||||
*/
|
||||
enum {
|
||||
NO_PROV, ANON_PROV, AUTH_PROV, BOTH_PROV
|
||||
} eap_fast_prov;
|
||||
|
||||
/**
|
||||
* pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
|
||||
*
|
||||
* This is the hard limit on how long a provisioned PAC-Key can be
|
||||
* used.
|
||||
*/
|
||||
int pac_key_lifetime;
|
||||
|
||||
/**
|
||||
* pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
|
||||
*
|
||||
* This is a soft limit on the PAC-Key. The server will automatically
|
||||
* generate a new PAC-Key when this number of seconds (or fewer) of the
|
||||
* lifetime remains.
|
||||
*/
|
||||
int pac_key_refresh_time;
|
||||
int eap_teap_auth;
|
||||
int eap_teap_pac_no_inner;
|
||||
int eap_teap_separate_result;
|
||||
enum eap_teap_id {
|
||||
EAP_TEAP_ID_ALLOW_ANY = 0,
|
||||
EAP_TEAP_ID_REQUIRE_USER = 1,
|
||||
EAP_TEAP_ID_REQUIRE_MACHINE = 2,
|
||||
EAP_TEAP_ID_REQUEST_USER_ACCEPT_MACHINE = 3,
|
||||
EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER = 4,
|
||||
EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE = 5,
|
||||
} eap_teap_id;
|
||||
|
||||
/**
|
||||
* eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
|
||||
*
|
||||
* This controls whether the protected success/failure indication
|
||||
* (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
|
||||
*/
|
||||
int eap_sim_aka_result_ind;
|
||||
int eap_sim_id;
|
||||
|
||||
/**
|
||||
* tnc - Trusted Network Connect (TNC)
|
||||
*
|
||||
* This controls whether TNC is enabled and will be required before the
|
||||
* peer is allowed to connect. Note: This is only used with EAP-TTLS
|
||||
* and EAP-FAST. If any other EAP method is enabled, the peer will be
|
||||
* allowed to connect without TNC.
|
||||
*/
|
||||
int tnc;
|
||||
|
||||
/**
|
||||
* wps - Wi-Fi Protected Setup context
|
||||
*
|
||||
* If WPS is used with an external RADIUS server (which is quite
|
||||
* unlikely configuration), this is used to provide a pointer to WPS
|
||||
* context data. Normally, this can be set to %NULL.
|
||||
*/
|
||||
struct wps_context *wps;
|
||||
int fragment_size;
|
||||
|
||||
int pbc_in_m1;
|
||||
|
||||
/**
|
||||
* server_id - Server identity
|
||||
*/
|
||||
u8 *server_id;
|
||||
size_t server_id_len;
|
||||
|
||||
/**
|
||||
* erp - Whether EAP Re-authentication Protocol (ERP) is enabled
|
||||
*
|
||||
* This controls whether the authentication server derives ERP key
|
||||
* hierarchy (rRK and rIK) from full EAP authentication and allows
|
||||
* these keys to be used to perform ERP to derive rMSK instead of full
|
||||
* EAP authentication to derive MSK.
|
||||
*/
|
||||
int erp;
|
||||
unsigned int tls_session_lifetime;
|
||||
unsigned int tls_flags;
|
||||
|
||||
unsigned int max_auth_rounds;
|
||||
unsigned int max_auth_rounds_short;
|
||||
};
|
||||
|
||||
struct eap_session_data {
|
||||
const struct wpabuf *assoc_wps_ie;
|
||||
const struct wpabuf *assoc_p2p_ie;
|
||||
const u8 *peer_addr;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
u32 tls_test_flags;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
};
|
||||
|
||||
|
||||
struct eap_sm * eap_server_sm_init(void *eapol_ctx,
|
||||
const struct eapol_callbacks *eapol_cb,
|
||||
const struct eap_config *conf,
|
||||
const struct eap_session_data *sess);
|
||||
void eap_server_sm_deinit(struct eap_sm *sm);
|
||||
int eap_server_sm_step(struct eap_sm *sm);
|
||||
void eap_sm_notify_cached(struct eap_sm *sm);
|
||||
void eap_sm_pending_cb(struct eap_sm *sm);
|
||||
int eap_sm_method_pending(struct eap_sm *sm);
|
||||
const u8 * eap_get_identity(struct eap_sm *sm, size_t *len);
|
||||
const char * eap_get_serial_num(struct eap_sm *sm);
|
||||
const char * eap_get_method(struct eap_sm *sm);
|
||||
const char * eap_get_imsi(struct eap_sm *sm);
|
||||
struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm);
|
||||
void eap_server_clear_identity(struct eap_sm *sm);
|
||||
void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source,
|
||||
const u8 *username, size_t username_len,
|
||||
const u8 *challenge, const u8 *response);
|
||||
void eap_erp_update_identity(struct eap_sm *sm, const u8 *eap, size_t len);
|
||||
void eap_user_free(struct eap_user *user);
|
||||
void eap_server_config_free(struct eap_config *cfg);
|
||||
|
||||
#endif /* EAP_H */
|
203
components/wpa_supplicant/src/eap_server/eap_i.h
Normal file
203
components/wpa_supplicant/src/eap_server/eap_i.h
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* hostapd / EAP Authenticator state machine internal structures (RFC 4137)
|
||||
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef EAP_I_H
|
||||
#define EAP_I_H
|
||||
|
||||
#include "wpabuf.h"
|
||||
#include "eap_server/eap.h"
|
||||
#include "eap_common/eap_common.h"
|
||||
|
||||
/* RFC 4137 - EAP Standalone Authenticator */
|
||||
|
||||
/**
|
||||
* 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 5.4 of RFC 4137.
|
||||
*/
|
||||
struct eap_method {
|
||||
int vendor;
|
||||
enum eap_type method;
|
||||
const char *name;
|
||||
|
||||
void * (*init)(struct eap_sm *sm);
|
||||
void * (*initPickUp)(struct eap_sm *sm);
|
||||
void (*reset)(struct eap_sm *sm, void *priv);
|
||||
|
||||
struct wpabuf * (*buildReq)(struct eap_sm *sm, void *priv, u8 id);
|
||||
int (*getTimeout)(struct eap_sm *sm, void *priv);
|
||||
bool (*check)(struct eap_sm *sm, void *priv, struct wpabuf *respData);
|
||||
void (*process)(struct eap_sm *sm, void *priv,
|
||||
struct wpabuf *respData);
|
||||
bool (*isDone)(struct eap_sm *sm, void *priv);
|
||||
u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);
|
||||
/* isSuccess is not specified in draft-ietf-eap-statemachine-05.txt,
|
||||
* but it is useful in implementing Policy.getDecision() */
|
||||
bool (*isSuccess)(struct eap_sm *sm, void *priv);
|
||||
|
||||
/**
|
||||
* free - Free EAP method data
|
||||
* @method: Pointer to the method data registered with
|
||||
* eap_server_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_SERVER_METHOD_INTERFACE_VERSION 1
|
||||
/**
|
||||
* version - Version of the EAP server method interface
|
||||
*
|
||||
* The EAP server method implementation should set this variable to
|
||||
* EAP_SERVER_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;
|
||||
|
||||
/**
|
||||
* get_emsk - Get EAP method specific keying extended material (EMSK)
|
||||
* @sm: Pointer to EAP state machine allocated with eap_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_server_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);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct eap_sm - EAP server state machine data
|
||||
*/
|
||||
struct eap_sm {
|
||||
enum {
|
||||
EAP_DISABLED, EAP_INITIALIZE, EAP_IDLE, EAP_RECEIVED,
|
||||
EAP_INTEGRITY_CHECK, EAP_METHOD_RESPONSE, EAP_METHOD_REQUEST,
|
||||
EAP_PROPOSE_METHOD, EAP_SELECT_ACTION, EAP_SEND_REQUEST,
|
||||
EAP_DISCARD, EAP_NAK, EAP_RETRANSMIT, EAP_SUCCESS, EAP_FAILURE,
|
||||
EAP_TIMEOUT_FAILURE, EAP_PICK_UP_METHOD,
|
||||
EAP_INITIALIZE_PASSTHROUGH, EAP_IDLE2, EAP_RETRANSMIT2,
|
||||
EAP_RECEIVED2, EAP_DISCARD2, EAP_SEND_REQUEST2,
|
||||
EAP_AAA_REQUEST, EAP_AAA_RESPONSE, EAP_AAA_IDLE,
|
||||
EAP_TIMEOUT_FAILURE2, EAP_FAILURE2, EAP_SUCCESS2,
|
||||
EAP_INITIATE_REAUTH_START, EAP_INITIATE_RECEIVED
|
||||
} EAP_state;
|
||||
|
||||
/* Constants */
|
||||
int MaxRetrans;
|
||||
|
||||
struct eap_eapol_interface eap_if;
|
||||
|
||||
/* Full authenticator state machine local variables */
|
||||
|
||||
/* Long-term (maintained between packets) */
|
||||
enum eap_type currentMethod;
|
||||
int currentId;
|
||||
enum {
|
||||
METHOD_PROPOSED, METHOD_CONTINUE, METHOD_END
|
||||
} methodState;
|
||||
int retransCount;
|
||||
struct wpabuf *lastReqData;
|
||||
int methodTimeout;
|
||||
|
||||
/* Short-term (not maintained between packets) */
|
||||
bool rxResp;
|
||||
bool rxInitiate;
|
||||
int respId;
|
||||
enum eap_type respMethod;
|
||||
int respVendor;
|
||||
u32 respVendorMethod;
|
||||
bool ignore;
|
||||
enum {
|
||||
DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE,
|
||||
DECISION_PASSTHROUGH, DECISION_INITIATE_REAUTH_START
|
||||
} decision;
|
||||
|
||||
/* Miscellaneous variables */
|
||||
const struct eap_method *m; /* selected EAP method */
|
||||
/* not defined in RFC 4137 */
|
||||
bool changed;
|
||||
void *eapol_ctx;
|
||||
const struct eapol_callbacks *eapol_cb;
|
||||
void *eap_method_priv;
|
||||
u8 *identity;
|
||||
size_t identity_len;
|
||||
char *serial_num;
|
||||
char imsi[20];
|
||||
/* Whether Phase 2 method should validate identity match */
|
||||
int require_identity_match;
|
||||
int lastId; /* Identifier used in the last EAP-Packet */
|
||||
struct eap_user *user;
|
||||
int user_eap_method_index;
|
||||
int init_phase2;
|
||||
const struct eap_config *cfg;
|
||||
struct eap_config cfg_buf;
|
||||
bool update_user;
|
||||
|
||||
unsigned int num_rounds;
|
||||
unsigned int num_rounds_short;
|
||||
enum {
|
||||
METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT
|
||||
} method_pending;
|
||||
|
||||
u8 *auth_challenge;
|
||||
u8 *peer_challenge;
|
||||
|
||||
struct wpabuf *assoc_wps_ie;
|
||||
struct wpabuf *assoc_p2p_ie;
|
||||
|
||||
bool start_reauth;
|
||||
|
||||
u8 peer_addr[ETH_ALEN];
|
||||
|
||||
bool initiate_reauth_start_sent;
|
||||
bool try_initiate_reauth;
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
u32 tls_test_flags;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
};
|
||||
|
||||
int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
|
||||
int phase2);
|
||||
void eap_log_msg(struct eap_sm *sm, const char *fmt, ...)
|
||||
PRINTF_FORMAT(2, 3);
|
||||
void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len);
|
||||
|
||||
#endif /* EAP_I_H */
|
52
components/wpa_supplicant/src/eap_server/eap_methods.h
Normal file
52
components/wpa_supplicant/src/eap_server/eap_methods.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* EAP server method registration
|
||||
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef EAP_SERVER_METHODS_H
|
||||
#define EAP_SERVER_METHODS_H
|
||||
|
||||
#include "eap_common/eap_defs.h"
|
||||
|
||||
const struct eap_method * eap_server_get_eap_method(int vendor,
|
||||
enum eap_type method);
|
||||
struct eap_method * eap_server_method_alloc(int version, int vendor,
|
||||
enum eap_type method,
|
||||
const char *name);
|
||||
int eap_server_method_register(struct eap_method *method);
|
||||
|
||||
enum eap_type eap_server_get_type(const char *name, int *vendor);
|
||||
void eap_server_unregister_methods(void);
|
||||
const char * eap_server_get_name(int vendor, enum eap_type type);
|
||||
|
||||
/* EAP server method registration calls for statically linked in methods */
|
||||
int eap_server_identity_register(void);
|
||||
int eap_server_md5_register(void);
|
||||
int eap_server_tls_register(void);
|
||||
int eap_server_unauth_tls_register(void);
|
||||
int eap_server_wfa_unauth_tls_register(void);
|
||||
int eap_server_mschapv2_register(void);
|
||||
int eap_server_peap_register(void);
|
||||
int eap_server_tlv_register(void);
|
||||
int eap_server_gtc_register(void);
|
||||
int eap_server_ttls_register(void);
|
||||
int eap_server_sim_register(void);
|
||||
int eap_server_aka_register(void);
|
||||
int eap_server_aka_prime_register(void);
|
||||
int eap_server_pax_register(void);
|
||||
int eap_server_psk_register(void);
|
||||
int eap_server_sake_register(void);
|
||||
int eap_server_gpsk_register(void);
|
||||
int eap_server_vendor_test_register(void);
|
||||
int eap_server_fast_register(void);
|
||||
int eap_server_teap_register(void);
|
||||
int eap_server_wsc_register(void);
|
||||
int eap_server_ikev2_register(void);
|
||||
int eap_server_tnc_register(void);
|
||||
int eap_server_pwd_register(void);
|
||||
int eap_server_eke_register(void);
|
||||
|
||||
#endif /* EAP_SERVER_METHODS_H */
|
2104
components/wpa_supplicant/src/eap_server/eap_server.c
Normal file
2104
components/wpa_supplicant/src/eap_server/eap_server.c
Normal file
File diff suppressed because it is too large
Load Diff
177
components/wpa_supplicant/src/eap_server/eap_server_identity.c
Normal file
177
components/wpa_supplicant/src/eap_server/eap_server_identity.c
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* hostapd / EAP-Identity
|
||||
* Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "eap_i.h"
|
||||
|
||||
|
||||
struct eap_identity_data {
|
||||
enum { CONTINUE, SUCCESS, FAILURE } state;
|
||||
int pick_up;
|
||||
};
|
||||
|
||||
|
||||
static void * eap_identity_init(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_identity_data *data;
|
||||
|
||||
data = os_zalloc(sizeof(*data));
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
data->state = CONTINUE;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static void * eap_identity_initPickUp(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_identity_data *data;
|
||||
data = eap_identity_init(sm);
|
||||
if (data) {
|
||||
data->pick_up = 1;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static void eap_identity_reset(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_identity_data *data = priv;
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * eap_identity_buildReq(struct eap_sm *sm, void *priv,
|
||||
u8 id)
|
||||
{
|
||||
struct eap_identity_data *data = priv;
|
||||
struct wpabuf *req;
|
||||
const char *req_data;
|
||||
size_t req_data_len;
|
||||
|
||||
if (sm->eapol_cb->get_eap_req_id_text) {
|
||||
req_data = sm->eapol_cb->get_eap_req_id_text(sm->eapol_ctx,
|
||||
&req_data_len);
|
||||
} else {
|
||||
req_data = NULL;
|
||||
req_data_len = 0;
|
||||
}
|
||||
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req_data_len,
|
||||
EAP_CODE_REQUEST, id);
|
||||
if (req == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP-Identity: Failed to allocate "
|
||||
"memory for request");
|
||||
data->state = FAILURE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wpabuf_put_data(req, req_data, req_data_len);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
static bool eap_identity_check(struct eap_sm *sm, void *priv,
|
||||
struct wpabuf *respData)
|
||||
{
|
||||
const u8 *pos;
|
||||
size_t len;
|
||||
|
||||
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
|
||||
respData, &len);
|
||||
if (pos == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-Identity: Invalid frame");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static void eap_identity_process(struct eap_sm *sm, void *priv,
|
||||
struct wpabuf *respData)
|
||||
{
|
||||
struct eap_identity_data *data = priv;
|
||||
const u8 *pos;
|
||||
size_t len;
|
||||
char *buf;
|
||||
|
||||
if (data->pick_up) {
|
||||
if (eap_identity_check(sm, data, respData)) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-Identity: failed to pick "
|
||||
"up already started negotiation");
|
||||
data->state = FAILURE;
|
||||
return;
|
||||
}
|
||||
data->pick_up = 0;
|
||||
}
|
||||
|
||||
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
|
||||
respData, &len);
|
||||
if (pos == NULL)
|
||||
return; /* Should not happen - frame already validated */
|
||||
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-Identity: Peer identity", pos, len);
|
||||
buf = os_malloc(len * 4 + 1);
|
||||
if (buf) {
|
||||
printf_encode(buf, len * 4 + 1, pos, len);
|
||||
eap_log_msg(sm, "EAP-Response/Identity '%s'", buf);
|
||||
os_free(buf);
|
||||
}
|
||||
if (sm->identity)
|
||||
sm->update_user = true;
|
||||
os_free(sm->identity);
|
||||
sm->identity = os_malloc(len ? len : 1);
|
||||
if (sm->identity == NULL) {
|
||||
data->state = FAILURE;
|
||||
} else {
|
||||
os_memcpy(sm->identity, pos, len);
|
||||
sm->identity_len = len;
|
||||
data->state = SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool eap_identity_isDone(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_identity_data *data = priv;
|
||||
return data->state != CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
static bool eap_identity_isSuccess(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_identity_data *data = priv;
|
||||
return data->state == SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int eap_server_identity_register(void)
|
||||
{
|
||||
struct eap_method *eap;
|
||||
|
||||
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
|
||||
EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
|
||||
"Identity");
|
||||
if (eap == NULL)
|
||||
return -1;
|
||||
|
||||
eap->init = eap_identity_init;
|
||||
eap->initPickUp = eap_identity_initPickUp;
|
||||
eap->reset = eap_identity_reset;
|
||||
eap->buildReq = eap_identity_buildReq;
|
||||
eap->check = eap_identity_check;
|
||||
eap->process = eap_identity_process;
|
||||
eap->isDone = eap_identity_isDone;
|
||||
eap->isSuccess = eap_identity_isSuccess;
|
||||
|
||||
return eap_server_method_register(eap);
|
||||
}
|
178
components/wpa_supplicant/src/eap_server/eap_server_methods.c
Normal file
178
components/wpa_supplicant/src/eap_server/eap_server_methods.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* EAP server method registration
|
||||
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "eap_i.h"
|
||||
#include "eap_methods.h"
|
||||
|
||||
|
||||
static struct eap_method *eap_methods;
|
||||
|
||||
|
||||
/**
|
||||
* eap_server_get_eap_method - Get EAP method based on type number
|
||||
* @vendor: EAP Vendor-Id (0 = IETF)
|
||||
* @method: EAP type number
|
||||
* Returns: Pointer to EAP method or %NULL if not found
|
||||
*/
|
||||
const struct eap_method * eap_server_get_eap_method(int vendor,
|
||||
enum eap_type method)
|
||||
{
|
||||
struct eap_method *m;
|
||||
for (m = eap_methods; m; m = m->next) {
|
||||
if (m->vendor == vendor && m->method == method)
|
||||
return m;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_server_get_type - Get EAP type for the given EAP method name
|
||||
* @name: EAP method name, e.g., TLS
|
||||
* @vendor: Buffer for returning EAP Vendor-Id
|
||||
* Returns: EAP method type or %EAP_TYPE_NONE if not found
|
||||
*
|
||||
* This function maps EAP type names into EAP type numbers based on the list of
|
||||
* EAP methods included in the build.
|
||||
*/
|
||||
enum eap_type eap_server_get_type(const char *name, int *vendor)
|
||||
{
|
||||
struct eap_method *m;
|
||||
for (m = eap_methods; m; m = m->next) {
|
||||
if (os_strcmp(m->name, name) == 0) {
|
||||
*vendor = m->vendor;
|
||||
return m->method;
|
||||
}
|
||||
}
|
||||
*vendor = EAP_VENDOR_IETF;
|
||||
return EAP_TYPE_NONE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_server_method_alloc - Allocate EAP server method structure
|
||||
* @version: Version of the EAP server method interface (set to
|
||||
* EAP_SERVER_METHOD_INTERFACE_VERSION)
|
||||
* @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
|
||||
* @method: EAP type number (EAP_TYPE_*)
|
||||
* @name: Name of the method (e.g., "TLS")
|
||||
* Returns: Allocated EAP method structure or %NULL on failure
|
||||
*
|
||||
* The returned structure should be freed with eap_server_method_free() when it
|
||||
* is not needed anymore.
|
||||
*/
|
||||
struct eap_method * eap_server_method_alloc(int version, int vendor,
|
||||
enum eap_type method,
|
||||
const char *name)
|
||||
{
|
||||
struct eap_method *eap;
|
||||
eap = os_zalloc(sizeof(*eap));
|
||||
if (eap == NULL)
|
||||
return NULL;
|
||||
eap->version = version;
|
||||
eap->vendor = vendor;
|
||||
eap->method = method;
|
||||
eap->name = name;
|
||||
return eap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_server_method_free - Free EAP server method structure
|
||||
* @method: Method structure allocated with eap_server_method_alloc()
|
||||
*/
|
||||
static void eap_server_method_free(struct eap_method *method)
|
||||
{
|
||||
os_free(method);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_server_method_register - Register an EAP server method
|
||||
* @method: EAP method to register from eap_server_method_alloc()
|
||||
* Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method
|
||||
* has already been registered
|
||||
*
|
||||
* Each EAP server method needs to call this function to register itself as a
|
||||
* supported EAP method. The caller must not free the allocated method data
|
||||
* regardless of the return value.
|
||||
*/
|
||||
int eap_server_method_register(struct eap_method *method)
|
||||
{
|
||||
struct eap_method *m, *last = NULL;
|
||||
|
||||
if (method == NULL || method->name == NULL ||
|
||||
method->version != EAP_SERVER_METHOD_INTERFACE_VERSION) {
|
||||
eap_server_method_free(method);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (m = eap_methods; m; m = m->next) {
|
||||
if ((m->vendor == method->vendor &&
|
||||
m->method == method->method) ||
|
||||
os_strcmp(m->name, method->name) == 0) {
|
||||
eap_server_method_free(method);
|
||||
return -2;
|
||||
}
|
||||
last = m;
|
||||
}
|
||||
|
||||
if (last)
|
||||
last->next = method;
|
||||
else
|
||||
eap_methods = method;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_server_unregister_methods - Unregister EAP server methods
|
||||
*
|
||||
* This function is called at program termination to unregister all EAP server
|
||||
* methods.
|
||||
*/
|
||||
void eap_server_unregister_methods(void)
|
||||
{
|
||||
struct eap_method *m;
|
||||
|
||||
while (eap_methods) {
|
||||
m = eap_methods;
|
||||
eap_methods = eap_methods->next;
|
||||
|
||||
if (m->free)
|
||||
m->free(m);
|
||||
else
|
||||
eap_server_method_free(m);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_server_get_name - Get EAP method name for the given EAP type
|
||||
* @vendor: EAP Vendor-Id (0 = IETF)
|
||||
* @type: EAP method type
|
||||
* Returns: EAP method name, e.g., TLS, or "unknown" if not found
|
||||
*
|
||||
* This function maps EAP type numbers into EAP type names based on the list of
|
||||
* EAP methods included in the build.
|
||||
*/
|
||||
const char * eap_server_get_name(int vendor, enum eap_type type)
|
||||
{
|
||||
struct eap_method *m;
|
||||
if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
|
||||
return "expanded";
|
||||
for (m = eap_methods; m; m = m->next) {
|
||||
if (m->vendor == vendor && m->method == type)
|
||||
return m->name;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
510
components/wpa_supplicant/src/eap_server/eap_server_wsc.c
Normal file
510
components/wpa_supplicant/src/eap_server/eap_server_wsc.c
Normal file
@@ -0,0 +1,510 @@
|
||||
/*
|
||||
* EAP-WSC server for Wi-Fi Protected Setup
|
||||
* Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "eloop.h"
|
||||
#include "eap_i.h"
|
||||
#include "eap_common/eap_wsc_common.h"
|
||||
#include "p2p/p2p.h"
|
||||
#include "wps/wps.h"
|
||||
|
||||
|
||||
struct eap_wsc_data {
|
||||
enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
|
||||
int registrar;
|
||||
struct wpabuf *in_buf;
|
||||
struct wpabuf *out_buf;
|
||||
enum wsc_op_code in_op_code, out_op_code;
|
||||
size_t out_used;
|
||||
size_t fragment_size;
|
||||
struct wps_data *wps;
|
||||
int ext_reg_timeout;
|
||||
};
|
||||
|
||||
|
||||
#ifndef CONFIG_NO_STDOUT_DEBUG
|
||||
static const char * eap_wsc_state_txt(int state)
|
||||
{
|
||||
switch (state) {
|
||||
case START:
|
||||
return "START";
|
||||
case MESG:
|
||||
return "MESG";
|
||||
case FRAG_ACK:
|
||||
return "FRAG_ACK";
|
||||
case WAIT_FRAG_ACK:
|
||||
return "WAIT_FRAG_ACK";
|
||||
case DONE:
|
||||
return "DONE";
|
||||
case FAIL:
|
||||
return "FAIL";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
||||
|
||||
|
||||
static void eap_wsc_state(struct eap_wsc_data *data, int state)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
|
||||
eap_wsc_state_txt(data->state),
|
||||
eap_wsc_state_txt(state));
|
||||
data->state = state;
|
||||
}
|
||||
|
||||
|
||||
static void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct eap_sm *sm = eloop_ctx;
|
||||
struct eap_wsc_data *data = timeout_ctx;
|
||||
|
||||
if (sm->method_pending != METHOD_PENDING_WAIT)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External "
|
||||
"Registrar");
|
||||
data->ext_reg_timeout = 1;
|
||||
eap_sm_pending_cb(sm);
|
||||
}
|
||||
|
||||
|
||||
static void * eap_wsc_init(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_wsc_data *data;
|
||||
int registrar;
|
||||
struct wps_config cfg;
|
||||
|
||||
if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN &&
|
||||
os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) ==
|
||||
0)
|
||||
registrar = 0; /* Supplicant is Registrar */
|
||||
else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN &&
|
||||
os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN)
|
||||
== 0)
|
||||
registrar = 1; /* Supplicant is Enrollee */
|
||||
else {
|
||||
wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
|
||||
sm->identity, sm->identity_len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = os_zalloc(sizeof(*data));
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
data->state = registrar ? START : MESG;
|
||||
data->registrar = registrar;
|
||||
|
||||
os_memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.wps = sm->cfg->wps;
|
||||
cfg.registrar = registrar;
|
||||
if (registrar) {
|
||||
if (!sm->cfg->wps || !sm->cfg->wps->registrar) {
|
||||
wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not "
|
||||
"initialized");
|
||||
os_free(data);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (sm->user == NULL || sm->user->password == NULL) {
|
||||
/*
|
||||
* In theory, this should not really be needed, but
|
||||
* Windows 7 uses Registrar mode to probe AP's WPS
|
||||
* capabilities before trying to use Enrollee and fails
|
||||
* if the AP does not allow that probing to happen..
|
||||
*/
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: No AP PIN (password) "
|
||||
"configured for Enrollee functionality - "
|
||||
"allow for probing capabilities (M1)");
|
||||
} else {
|
||||
cfg.pin = sm->user->password;
|
||||
cfg.pin_len = sm->user->password_len;
|
||||
}
|
||||
}
|
||||
cfg.assoc_wps_ie = sm->assoc_wps_ie;
|
||||
cfg.peer_addr = sm->peer_addr;
|
||||
#ifdef CONFIG_P2P
|
||||
if (sm->assoc_p2p_ie) {
|
||||
if (!sm->cfg->wps->use_passphrase) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"EAP-WSC: Prefer PSK format for non-6 GHz P2P client");
|
||||
cfg.use_psk_key = 1;
|
||||
}
|
||||
cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie);
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
cfg.pbc_in_m1 = sm->cfg->pbc_in_m1;
|
||||
data->wps = wps_init(&cfg);
|
||||
if (data->wps == NULL) {
|
||||
os_free(data);
|
||||
return NULL;
|
||||
}
|
||||
data->fragment_size = sm->cfg->fragment_size > 0 ?
|
||||
sm->cfg->fragment_size : WSC_FRAGMENT_SIZE;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static void eap_wsc_reset(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_wsc_data *data = priv;
|
||||
eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
|
||||
wpabuf_free(data->in_buf);
|
||||
wpabuf_free(data->out_buf);
|
||||
wps_deinit(data->wps);
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * eap_wsc_build_start(struct eap_sm *sm,
|
||||
struct eap_wsc_data *data, u8 id)
|
||||
{
|
||||
struct wpabuf *req;
|
||||
|
||||
req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2,
|
||||
EAP_CODE_REQUEST, id);
|
||||
if (req == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
|
||||
"request");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start");
|
||||
wpabuf_put_u8(req, WSC_Start); /* Op-Code */
|
||||
wpabuf_put_u8(req, 0); /* Flags */
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id)
|
||||
{
|
||||
struct wpabuf *req;
|
||||
u8 flags;
|
||||
size_t send_len, plen;
|
||||
|
||||
flags = 0;
|
||||
send_len = wpabuf_len(data->out_buf) - data->out_used;
|
||||
if (2 + send_len > data->fragment_size) {
|
||||
send_len = data->fragment_size - 2;
|
||||
flags |= WSC_FLAGS_MF;
|
||||
if (data->out_used == 0) {
|
||||
flags |= WSC_FLAGS_LF;
|
||||
send_len -= 2;
|
||||
}
|
||||
}
|
||||
plen = 2 + send_len;
|
||||
if (flags & WSC_FLAGS_LF)
|
||||
plen += 2;
|
||||
req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
|
||||
EAP_CODE_REQUEST, id);
|
||||
if (req == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
|
||||
"request");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wpabuf_put_u8(req, data->out_op_code); /* Op-Code */
|
||||
wpabuf_put_u8(req, flags); /* Flags */
|
||||
if (flags & WSC_FLAGS_LF)
|
||||
wpabuf_put_be16(req, wpabuf_len(data->out_buf));
|
||||
|
||||
wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
|
||||
send_len);
|
||||
data->out_used += send_len;
|
||||
|
||||
if (data->out_used == wpabuf_len(data->out_buf)) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
|
||||
"(message sent completely)",
|
||||
(unsigned long) send_len);
|
||||
wpabuf_free(data->out_buf);
|
||||
data->out_buf = NULL;
|
||||
data->out_used = 0;
|
||||
eap_wsc_state(data, MESG);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
|
||||
"(%lu more to send)", (unsigned long) send_len,
|
||||
(unsigned long) wpabuf_len(data->out_buf) -
|
||||
data->out_used);
|
||||
eap_wsc_state(data, WAIT_FRAG_ACK);
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id)
|
||||
{
|
||||
struct eap_wsc_data *data = priv;
|
||||
|
||||
switch (data->state) {
|
||||
case START:
|
||||
return eap_wsc_build_start(sm, data, id);
|
||||
case MESG:
|
||||
if (data->out_buf == NULL) {
|
||||
data->out_buf = wps_get_msg(data->wps,
|
||||
&data->out_op_code);
|
||||
if (data->out_buf == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to "
|
||||
"receive message from WPS");
|
||||
return NULL;
|
||||
}
|
||||
data->out_used = 0;
|
||||
}
|
||||
/* fall through */
|
||||
case WAIT_FRAG_ACK:
|
||||
return eap_wsc_build_msg(data, id);
|
||||
case FRAG_ACK:
|
||||
return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST);
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in "
|
||||
"buildReq", data->state);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool eap_wsc_check(struct eap_sm *sm, void *priv,
|
||||
struct wpabuf *respData)
|
||||
{
|
||||
const u8 *pos;
|
||||
size_t len;
|
||||
|
||||
pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
|
||||
respData, &len);
|
||||
if (pos == NULL || len < 2) {
|
||||
wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static int eap_wsc_process_cont(struct eap_wsc_data *data,
|
||||
const u8 *buf, size_t len, u8 op_code)
|
||||
{
|
||||
/* Process continuation of a pending message */
|
||||
if (op_code != data->in_op_code) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
|
||||
"fragment (expected %d)",
|
||||
op_code, data->in_op_code);
|
||||
eap_wsc_state(data, FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len > wpabuf_tailroom(data->in_buf)) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
|
||||
eap_wsc_state(data, FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpabuf_put_data(data->in_buf, buf, len);
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu "
|
||||
"bytes more", (unsigned long) len,
|
||||
(unsigned long) wpabuf_tailroom(data->in_buf));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int eap_wsc_process_fragment(struct eap_wsc_data *data,
|
||||
u8 flags, u8 op_code, u16 message_length,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
/* Process a fragment that is not the last one of the message */
|
||||
if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length "
|
||||
"field in a fragmented packet");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data->in_buf == NULL) {
|
||||
/* First fragment of the message */
|
||||
data->in_buf = wpabuf_alloc(message_length);
|
||||
if (data->in_buf == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
|
||||
"message");
|
||||
return -1;
|
||||
}
|
||||
data->in_op_code = op_code;
|
||||
wpabuf_put_data(data->in_buf, buf, len);
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in "
|
||||
"first fragment, waiting for %lu bytes more",
|
||||
(unsigned long) len,
|
||||
(unsigned long) wpabuf_tailroom(data->in_buf));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void eap_wsc_process(struct eap_sm *sm, void *priv,
|
||||
struct wpabuf *respData)
|
||||
{
|
||||
struct eap_wsc_data *data = priv;
|
||||
const u8 *start, *pos, *end;
|
||||
size_t len;
|
||||
u8 op_code, flags;
|
||||
u16 message_length = 0;
|
||||
enum wps_process_res res;
|
||||
struct wpabuf tmpbuf;
|
||||
|
||||
eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
|
||||
if (data->ext_reg_timeout) {
|
||||
eap_wsc_state(data, FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
|
||||
respData, &len);
|
||||
if (pos == NULL || len < 2)
|
||||
return; /* Should not happen; message already verified */
|
||||
|
||||
start = pos;
|
||||
end = start + len;
|
||||
|
||||
op_code = *pos++;
|
||||
flags = *pos++;
|
||||
if (flags & WSC_FLAGS_LF) {
|
||||
if (end - pos < 2) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
|
||||
return;
|
||||
}
|
||||
message_length = WPA_GET_BE16(pos);
|
||||
pos += 2;
|
||||
|
||||
if (message_length < end - pos || message_length > 50000) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
|
||||
"Length");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
|
||||
"Flags 0x%x Message Length %d",
|
||||
op_code, flags, message_length);
|
||||
|
||||
if (data->state == WAIT_FRAG_ACK) {
|
||||
if (op_code != WSC_FRAG_ACK) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
|
||||
"in WAIT_FRAG_ACK state", op_code);
|
||||
eap_wsc_state(data, FAIL);
|
||||
return;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
|
||||
eap_wsc_state(data, MESG);
|
||||
return;
|
||||
}
|
||||
|
||||
if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
|
||||
op_code != WSC_Done) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
|
||||
op_code);
|
||||
eap_wsc_state(data, FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data->in_buf &&
|
||||
eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
|
||||
eap_wsc_state(data, FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags & WSC_FLAGS_MF) {
|
||||
if (eap_wsc_process_fragment(data, flags, op_code,
|
||||
message_length, pos, end - pos) <
|
||||
0)
|
||||
eap_wsc_state(data, FAIL);
|
||||
else
|
||||
eap_wsc_state(data, FRAG_ACK);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data->in_buf == NULL) {
|
||||
/* Wrap unfragmented messages as wpabuf without extra copy */
|
||||
wpabuf_set(&tmpbuf, pos, end - pos);
|
||||
data->in_buf = &tmpbuf;
|
||||
}
|
||||
|
||||
res = wps_process_msg(data->wps, op_code, data->in_buf);
|
||||
switch (res) {
|
||||
case WPS_DONE:
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
|
||||
"successfully - report EAP failure");
|
||||
eap_wsc_state(data, FAIL);
|
||||
break;
|
||||
case WPS_CONTINUE:
|
||||
eap_wsc_state(data, MESG);
|
||||
break;
|
||||
case WPS_FAILURE:
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
|
||||
eap_wsc_state(data, FAIL);
|
||||
break;
|
||||
case WPS_PENDING:
|
||||
eap_wsc_state(data, MESG);
|
||||
sm->method_pending = METHOD_PENDING_WAIT;
|
||||
eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
|
||||
eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout,
|
||||
sm, data);
|
||||
break;
|
||||
}
|
||||
|
||||
if (data->in_buf != &tmpbuf)
|
||||
wpabuf_free(data->in_buf);
|
||||
data->in_buf = NULL;
|
||||
}
|
||||
|
||||
|
||||
static bool eap_wsc_isDone(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_wsc_data *data = priv;
|
||||
return data->state == FAIL;
|
||||
}
|
||||
|
||||
|
||||
static bool eap_wsc_isSuccess(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
/* EAP-WSC will always result in EAP-Failure */
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
/* Recommended retransmit times: retransmit timeout 5 seconds,
|
||||
* per-message timeout 15 seconds, i.e., 3 tries. */
|
||||
sm->MaxRetrans = 2; /* total 3 attempts */
|
||||
return 5;
|
||||
}
|
||||
|
||||
|
||||
int eap_server_wsc_register(void)
|
||||
{
|
||||
struct eap_method *eap;
|
||||
|
||||
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
|
||||
EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
|
||||
"WSC");
|
||||
if (eap == NULL)
|
||||
return -1;
|
||||
|
||||
eap->init = eap_wsc_init;
|
||||
eap->reset = eap_wsc_reset;
|
||||
eap->buildReq = eap_wsc_buildReq;
|
||||
eap->check = eap_wsc_check;
|
||||
eap->process = eap_wsc_process;
|
||||
eap->isDone = eap_wsc_isDone;
|
||||
eap->isSuccess = eap_wsc_isSuccess;
|
||||
eap->getTimeout = eap_wsc_getTimeout;
|
||||
|
||||
return eap_server_method_register(eap);
|
||||
}
|
Reference in New Issue
Block a user