diff --git a/hostapd/Makefile b/hostapd/Makefile index 7f0fb2ae5..a43e93a5d 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -166,7 +166,6 @@ ifdef CONFIG_EAP_PEAP CFLAGS += -DEAP_PEAP OBJS += ../src/eap_server/eap_peap.o TLS_FUNCS=y -CONFIG_EAP_TLV=y CONFIG_EAP_MSCHAPV2=y endif @@ -238,11 +237,6 @@ CFLAGS += -DEAP_VENDOR_TEST OBJS += ../src/eap_server/eap_vendor_test.o endif -ifdef CONFIG_EAP_TLV -CFLAGS += -DEAP_TLV -OBJS += ../src/eap_server/eap_tlv.o -endif - ifdef CONFIG_EAP_FAST CFLAGS += -DEAP_FAST OBJS += ../src/eap_server/eap_fast.o diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h index 696c65a17..6ff823583 100644 --- a/src/eap_server/eap_i.h +++ b/src/eap_server/eap_i.h @@ -157,7 +157,6 @@ struct eap_sm { int user_eap_method_index; int init_phase2; void *ssl_ctx; - enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request; void *eap_sim_db_priv; Boolean backend_auth; Boolean update_user; diff --git a/src/eap_server/eap_peap.c b/src/eap_server/eap_peap.c index 114032b96..980d8c3f0 100644 --- a/src/eap_server/eap_peap.c +++ b/src/eap_server/eap_peap.c @@ -45,6 +45,7 @@ struct eap_peap_data { void *phase2_priv; int force_version; struct wpabuf *pending_phase2_resp; + enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request; }; @@ -115,43 +116,37 @@ static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf) } -static EapType eap_peap_req_success(struct eap_sm *sm, - struct eap_peap_data *data) +static void eap_peap_req_success(struct eap_sm *sm, + struct eap_peap_data *data) { if (data->state == FAILURE || data->state == FAILURE_REQ) { eap_peap_state(data, FAILURE); - return EAP_TYPE_NONE; + return; } if (data->peap_version == 0) { - sm->tlv_request = TLV_REQ_SUCCESS; + data->tlv_request = TLV_REQ_SUCCESS; eap_peap_state(data, PHASE2_TLV); - return EAP_TYPE_TLV; } else { eap_peap_state(data, SUCCESS_REQ); - return EAP_TYPE_NONE; } } -static EapType eap_peap_req_failure(struct eap_sm *sm, - struct eap_peap_data *data) +static void eap_peap_req_failure(struct eap_sm *sm, + struct eap_peap_data *data) { if (data->state == FAILURE || data->state == FAILURE_REQ || - data->state == SUCCESS_REQ || - (data->phase2_method && - data->phase2_method->method == EAP_TYPE_TLV)) { + data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) { eap_peap_state(data, FAILURE); - return EAP_TYPE_NONE; + return; } if (data->peap_version == 0) { - sm->tlv_request = TLV_REQ_FAILURE; + data->tlv_request = TLV_REQ_FAILURE; eap_peap_state(data, PHASE2_TLV); - return EAP_TYPE_TLV; } else { eap_peap_state(data, FAILURE_REQ); - return EAP_TYPE_NONE; } } @@ -308,6 +303,36 @@ static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm, } +static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm, + struct eap_peap_data *data, + u8 id) +{ + struct wpabuf *buf, *encr_req; + + buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 6, + EAP_CODE_REQUEST, id); + if (buf == NULL) + return NULL; + + wpabuf_put_u8(buf, 0x80); /* Mandatory */ + wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV); + /* Length */ + wpabuf_put_be16(buf, 2); + /* Status */ + wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ? + EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE); + + wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data", + buf); + + encr_req = eap_peap_encrypt(sm, data, id, wpabuf_head(buf), + wpabuf_len(buf)); + wpabuf_free(buf); + + return encr_req; +} + + static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm, struct eap_peap_data *data, u8 id, int success) @@ -347,8 +372,9 @@ static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id) return eap_peap_build_req(sm, data, id); case PHASE2_ID: case PHASE2_METHOD: - case PHASE2_TLV: return eap_peap_build_phase2_req(sm, data, id); + case PHASE2_TLV: + return eap_peap_build_phase2_tlv(sm, data, id); case SUCCESS_REQ: return eap_peap_build_phase2_term(sm, data, id, 1); case FAILURE_REQ: @@ -397,6 +423,103 @@ static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data, } +static void eap_peap_process_phase2_tlv(struct eap_sm *sm, + struct eap_peap_data *data, + struct wpabuf *in_data) +{ + const u8 *pos; + size_t left; + const u8 *result_tlv = NULL; + size_t result_tlv_len = 0; + int tlv_type, mandatory, tlv_len; + + pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left); + if (pos == NULL) { + wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header"); + return; + } + + /* Parse TLVs */ + wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left); + while (left >= 4) { + mandatory = !!(pos[0] & 0x80); + tlv_type = pos[0] & 0x3f; + tlv_type = (tlv_type << 8) | pos[1]; + tlv_len = ((int) pos[2] << 8) | pos[3]; + pos += 4; + left -= 4; + if ((size_t) tlv_len > left) { + wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun " + "(tlv_len=%d left=%lu)", tlv_len, + (unsigned long) left); + eap_peap_state(data, FAILURE); + return; + } + switch (tlv_type) { + case EAP_TLV_RESULT_TLV: + result_tlv = pos; + result_tlv_len = tlv_len; + break; + default: + wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type " + "%d%s", tlv_type, + mandatory ? " (mandatory)" : ""); + if (mandatory) { + eap_peap_state(data, FAILURE); + return; + } + /* Ignore this TLV, but process other TLVs */ + break; + } + + pos += tlv_len; + left -= tlv_len; + } + if (left) { + wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in " + "Request (left=%lu)", (unsigned long) left); + eap_peap_state(data, FAILURE); + return; + } + + /* Process supported TLVs */ + if (result_tlv) { + int status; + const char *requested; + + wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV", + result_tlv, result_tlv_len); + if (result_tlv_len < 2) { + wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV " + "(len=%lu)", + (unsigned long) result_tlv_len); + eap_peap_state(data, FAILURE); + return; + } + requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" : + "Failure"; + status = WPA_GET_BE16(result_tlv); + if (status == EAP_TLV_RESULT_SUCCESS) { + wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success " + "- requested %s", requested); + if (data->tlv_request == TLV_REQ_SUCCESS) + eap_peap_state(data, SUCCESS); + else + eap_peap_state(data, FAILURE); + + } else if (status == EAP_TLV_RESULT_FAILURE) { + wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure - " + "requested %s", requested); + eap_peap_state(data, FAILURE); + } else { + wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result " + "Status %d", status); + eap_peap_state(data, FAILURE); + } + } +} + + static void eap_peap_process_phase2_response(struct eap_sm *sm, struct eap_peap_data *data, struct wpabuf *in_data) @@ -406,6 +529,11 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm, const u8 *pos; size_t left; + if (data->state == PHASE2_TLV) { + eap_peap_process_phase2_tlv(sm, data, in_data); + return; + } + if (data->phase2_priv == NULL) { wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not " "initialized?!", __func__); @@ -428,7 +556,8 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type); } else { - next_type = eap_peap_req_failure(sm, data); + eap_peap_req_failure(sm, data); + next_type = EAP_TYPE_NONE; } eap_peap_phase2_init(sm, data, next_type); return; @@ -454,7 +583,8 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm, if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed"); - next_type = eap_peap_req_failure(sm, data); + eap_peap_req_failure(sm, data); + next_type = EAP_TYPE_NONE; eap_peap_phase2_init(sm, data, next_type); return; } @@ -467,7 +597,8 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm, "Identity not found in the user " "database", sm->identity, sm->identity_len); - next_type = eap_peap_req_failure(sm, data); + eap_peap_req_failure(sm, data); + next_type = EAP_TYPE_NONE; break; } @@ -477,15 +608,8 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type); break; case PHASE2_METHOD: - next_type = eap_peap_req_success(sm, data); - break; - case PHASE2_TLV: - if (sm->tlv_request == TLV_REQ_SUCCESS || - data->state == SUCCESS_REQ) { - eap_peap_state(data, SUCCESS); - } else { - eap_peap_state(data, FAILURE); - } + eap_peap_req_success(sm, data); + next_type = EAP_TYPE_NONE; break; case FAILURE: break; diff --git a/src/eap_server/eap_tlv.c b/src/eap_server/eap_tlv.c deleted file mode 100644 index 4290c8023..000000000 --- a/src/eap_server/eap_tlv.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * hostapd / EAP-TLV (draft-josefsson-pppext-eap-tls-eap-07.txt) - * Copyright (c) 2004-2007, Jouni Malinen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eap_i.h" -#include "eap_common/eap_tlv_common.h" - - -struct eap_tlv_data { - enum { CONTINUE, SUCCESS, FAILURE } state; -}; - - -static void * eap_tlv_init(struct eap_sm *sm) -{ - struct eap_tlv_data *data; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->state = CONTINUE; - - return data; -} - - -static void eap_tlv_reset(struct eap_sm *sm, void *priv) -{ - struct eap_tlv_data *data = priv; - os_free(data); -} - - -static struct wpabuf * eap_tlv_buildReq(struct eap_sm *sm, void *priv, u8 id) -{ - struct wpabuf *req; - u16 status; - - if (sm->tlv_request == TLV_REQ_SUCCESS) { - status = EAP_TLV_RESULT_SUCCESS; - } else { - status = EAP_TLV_RESULT_FAILURE; - } - - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 6, - EAP_CODE_REQUEST, id); - if (req == NULL) - return NULL; - - wpabuf_put_u8(req, 0x80); /* Mandatory */ - wpabuf_put_u8(req, EAP_TLV_RESULT_TLV); - /* Length */ - wpabuf_put_be16(req, 2); - /* Status */ - wpabuf_put_be16(req, status); - - return req; -} - - -static Boolean eap_tlv_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_TLV, respData, &len); - if (pos == NULL) { - wpa_printf(MSG_INFO, "EAP-TLV: Invalid frame"); - return TRUE; - } - - return FALSE; -} - - -static void eap_tlv_process(struct eap_sm *sm, void *priv, - struct wpabuf *respData) -{ - struct eap_tlv_data *data = priv; - const u8 *pos; - size_t left; - const u8 *result_tlv = NULL; - size_t result_tlv_len = 0; - int tlv_type, mandatory, tlv_len; - - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, respData, &left); - if (pos == NULL) - return; - - /* Parse TLVs */ - wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left); - while (left >= 4) { - mandatory = !!(pos[0] & 0x80); - tlv_type = pos[0] & 0x3f; - tlv_type = (tlv_type << 8) | pos[1]; - tlv_len = ((int) pos[2] << 8) | pos[3]; - pos += 4; - left -= 4; - if ((size_t) tlv_len > left) { - wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun " - "(tlv_len=%d left=%lu)", tlv_len, - (unsigned long) left); - data->state = FAILURE; - return; - } - switch (tlv_type) { - case EAP_TLV_RESULT_TLV: - result_tlv = pos; - result_tlv_len = tlv_len; - break; - default: - wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type " - "%d%s", tlv_type, - mandatory ? " (mandatory)" : ""); - if (mandatory) { - data->state = FAILURE; - return; - } - /* Ignore this TLV, but process other TLVs */ - break; - } - - pos += tlv_len; - left -= tlv_len; - } - if (left) { - wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in " - "Request (left=%lu)", (unsigned long) left); - data->state = FAILURE; - return; - } - - /* Process supported TLVs */ - if (result_tlv) { - int status; - const char *requested; - - wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV", - result_tlv, result_tlv_len); - if (result_tlv_len < 2) { - wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV " - "(len=%lu)", - (unsigned long) result_tlv_len); - data->state = FAILURE; - return; - } - requested = sm->tlv_request == TLV_REQ_SUCCESS ? "Success" : - "Failure"; - status = WPA_GET_BE16(result_tlv); - if (status == EAP_TLV_RESULT_SUCCESS) { - wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success " - "- requested %s", requested); - if (sm->tlv_request == TLV_REQ_SUCCESS) - data->state = SUCCESS; - else - data->state = FAILURE; - - } else if (status == EAP_TLV_RESULT_FAILURE) { - wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure - " - "requested %s", requested); - if (sm->tlv_request == TLV_REQ_FAILURE) - data->state = SUCCESS; - else - data->state = FAILURE; - } else { - wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result " - "Status %d", status); - data->state = FAILURE; - } - } -} - - -static Boolean eap_tlv_isDone(struct eap_sm *sm, void *priv) -{ - struct eap_tlv_data *data = priv; - return data->state != CONTINUE; -} - - -static Boolean eap_tlv_isSuccess(struct eap_sm *sm, void *priv) -{ - struct eap_tlv_data *data = priv; - return data->state == SUCCESS; -} - - -int eap_server_tlv_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_TLV, "TLV"); - if (eap == NULL) - return -1; - - eap->init = eap_tlv_init; - eap->reset = eap_tlv_reset; - eap->buildReq = eap_tlv_buildReq; - eap->check = eap_tlv_check; - eap->process = eap_tlv_process; - eap->isDone = eap_tlv_isDone; - eap->isSuccess = eap_tlv_isSuccess; - - ret = eap_server_method_register(eap); - if (ret) - eap_server_method_free(eap); - return ret; -}