EAP-PEAP: Moved EAP-TLV processing into eap_peap.c
EAP-PEAP was the only method that used the external eap_tlv.c server implementation. This worked fine just for the simple protected result notification, but extending the TLV support for cryptobinding etc. is not trivial with such separation. With the TLV processing integrated into eap_peap.c, all the needed information is now available for using additional TLVs.
This commit is contained in:
parent
a865bd5031
commit
06726f0bdd
4 changed files with 152 additions and 259 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
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,
|
||||
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;
|
||||
|
|
|
@ -1,224 +0,0 @@
|
|||
/*
|
||||
* hostapd / EAP-TLV (draft-josefsson-pppext-eap-tls-eap-07.txt)
|
||||
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* 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;
|
||||
}
|
Loading…
Reference in a new issue