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:
Jouni Malinen 2008-03-18 08:31:04 +02:00
parent a865bd5031
commit 06726f0bdd
4 changed files with 152 additions and 259 deletions

View file

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

View file

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

View file

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

View file

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