/*
* hostapd / EAP-TTLS (draft-ietf-pppext-eap-ttls-05.txt)
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include "hostapd.h"
#include "common.h"
#include "eap_i.h"
#include "eap_tls_common.h"
#include "ms_funcs.h"
#include "md5.h"
#include "crypto.h"
#include "tls.h"
#include "eap_ttls.h"
#define EAP_TTLS_VERSION 0
static void eap_ttls_reset(struct eap_sm *sm, void *priv);
struct eap_ttls_data {
struct eap_ssl_data ssl;
enum {
START, PHASE1, PHASE2_START, PHASE2_METHOD,
PHASE2_MSCHAPV2_RESP, SUCCESS, FAILURE
} state;
int ttls_version;
const struct eap_method *phase2_method;
void *phase2_priv;
int mschapv2_resp_ok;
u8 mschapv2_auth_response[20];
u8 mschapv2_ident;
};
static const char * eap_ttls_state_txt(int state)
{
switch (state) {
case START:
return "START";
case PHASE1:
return "PHASE1";
case PHASE2_START:
return "PHASE2_START";
case PHASE2_METHOD:
return "PHASE2_METHOD";
case PHASE2_MSCHAPV2_RESP:
return "PHASE2_MSCHAPV2_RESP";
case SUCCESS:
return "SUCCESS";
case FAILURE:
return "FAILURE";
default:
return "Unknown?!";
}
}
static void eap_ttls_state(struct eap_ttls_data *data, int state)
{
wpa_printf(MSG_DEBUG, "EAP-TTLS: %s -> %s",
eap_ttls_state_txt(data->state),
eap_ttls_state_txt(state));
data->state = state;
}
static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id,
int mandatory, size_t len)
{
struct ttls_avp_vendor *avp;
u8 flags;
size_t hdrlen;
avp = (struct ttls_avp_vendor *) avphdr;
flags = mandatory ? AVP_FLAGS_MANDATORY : 0;
if (vendor_id) {
flags |= AVP_FLAGS_VENDOR;
hdrlen = sizeof(*avp);
avp->vendor_id = host_to_be32(vendor_id);
} else {
hdrlen = sizeof(struct ttls_avp);
}
avp->avp_code = host_to_be32(avp_code);
avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len));
return avphdr + hdrlen;
}
static int eap_ttls_avp_encapsulate(u8 **resp, size_t *resp_len, u32 avp_code,
int mandatory)
{
u8 *avp, *pos;
avp = malloc(sizeof(struct ttls_avp) + *resp_len + 4);
if (avp == NULL) {
free(*resp);
*resp_len = 0;
return -1;
}
pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, *resp_len);
memcpy(pos, *resp, *resp_len);
pos += *resp_len;
AVP_PAD(avp, pos);
free(*resp);
*resp = avp;
*resp_len = pos - avp;
return 0;
}
struct eap_ttls_avp {
/* Note: eap is allocated memory; caller is responsible for freeing
* it. All the other pointers are pointing to the packet data, i.e.,
* they must not be freed separately. */
u8 *eap;
size_t eap_len;
u8 *user_name;
size_t user_name_len;
u8 *user_password;
size_t user_password_len;
u8 *chap_challenge;
size_t chap_challenge_len;
u8 *chap_password;
size_t chap_password_len;
u8 *mschap_challenge;
size_t mschap_challenge_len;
u8 *mschap_response;
size_t mschap_response_len;
u8 *mschap2_response;
size_t mschap2_response_len;
};
static int eap_ttls_avp_parse(u8 *buf, size_t len, struct eap_ttls_avp *parse)
{
struct ttls_avp *avp;
u8 *pos;
int left;
pos = buf;
left = len;
memset(parse, 0, sizeof(*parse));
while (left > 0) {
u32 avp_code, avp_length, vendor_id = 0;
u8 avp_flags, *dpos;
size_t pad, dlen;
avp = (struct ttls_avp *) pos;
avp_code = be_to_host32(avp->avp_code);
avp_length = be_to_host32(avp->avp_length);
avp_flags = (avp_length >> 24) & 0xff;
avp_length &= 0xffffff;
wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x "
"length=%d", (int) avp_code, avp_flags,
(int) avp_length);
if (avp_length > left) {
wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow "
"(len=%d, left=%d) - dropped",
(int) avp_length, left);
return -1;
}
dpos = (u8 *) (avp + 1);
dlen = avp_length - sizeof(*avp);
if (avp_flags & AVP_FLAGS_VENDOR) {
if (dlen < 4) {
wpa_printf(MSG_WARNING, "EAP-TTLS: vendor AVP "
"underflow");
return -1;
}
vendor_id = be_to_host32(* (u32 *) dpos);
wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d",
(int) vendor_id);
dpos += 4;
dlen -= 4;
}
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen);
if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message");
if (parse->eap == NULL) {
parse->eap = malloc(dlen);
if (parse->eap == NULL) {
wpa_printf(MSG_WARNING, "EAP-TTLS: "
"failed to allocate memory "
"for Phase 2 EAP data");
return -1;
}
memcpy(parse->eap, dpos, dlen);
parse->eap_len = dlen;
} else {
u8 *neweap = realloc(parse->eap,
parse->eap_len + dlen);
if (neweap == NULL) {
wpa_printf(MSG_WARNING, "EAP-TTLS: "
"failed to allocate memory "
"for Phase 2 EAP data");
free(parse->eap);
parse->eap = NULL;
return -1;
}
memcpy(neweap + parse->eap_len, dpos, dlen);
parse->eap = neweap;
parse->eap_len += dlen;
}
} else if (vendor_id == 0 &&
avp_code == RADIUS_ATTR_USER_NAME) {
wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: User-Name",
dpos, dlen);
parse->user_name = dpos;
parse->user_name_len = dlen;
} else if (vendor_id == 0 &&
avp_code == RADIUS_ATTR_USER_PASSWORD) {
u8 *password = dpos;
size_t password_len = dlen;
while (password_len > 0 &&
password[password_len - 1] == '\0') {
password_len--;
}
wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: "
"User-Password (PAP)",
password, password_len);
parse->user_password = password;
parse->user_password_len = password_len;
} else if (vendor_id == 0 &&
avp_code == RADIUS_ATTR_CHAP_CHALLENGE) {
wpa_hexdump(MSG_DEBUG,
"EAP-TTLS: CHAP-Challenge (CHAP)",
dpos, dlen);
parse->chap_challenge = dpos;
parse->chap_challenge_len = dlen;
} else if (vendor_id == 0 &&
avp_code == RADIUS_ATTR_CHAP_PASSWORD) {
wpa_hexdump(MSG_DEBUG,
"EAP-TTLS: CHAP-Password (CHAP)",
dpos, dlen);
parse->chap_password = dpos;
parse->chap_password_len = dlen;
} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
avp_code == RADIUS_ATTR_MS_CHAP_CHALLENGE) {
wpa_hexdump(MSG_DEBUG,
"EAP-TTLS: MS-CHAP-Challenge",
dpos, dlen);
parse->mschap_challenge = dpos;
parse->mschap_challenge_len = dlen;
} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
avp_code == RADIUS_ATTR_MS_CHAP_RESPONSE) {
wpa_hexdump(MSG_DEBUG,
"EAP-TTLS: MS-CHAP-Response (MSCHAP)",
dpos, dlen);
parse->mschap_response = dpos;
parse->mschap_response_len = dlen;
} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
avp_code == RADIUS_ATTR_MS_CHAP2_RESPONSE) {
wpa_hexdump(MSG_DEBUG,
"EAP-TTLS: MS-CHAP2-Response (MSCHAPV2)",
dpos, dlen);
parse->mschap2_response = dpos;
parse->mschap2_response_len = dlen;
} else if (avp_flags & AVP_FLAGS_MANDATORY) {
wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported "
"mandatory AVP code %d vendor_id %d - "
"dropped", (int) avp_code, (int) vendor_id);
return -1;
} else {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported "
"AVP code %d vendor_id %d",
(int) avp_code, (int) vendor_id);
}
pad = (4 - (avp_length & 3)) & 3;
pos += avp_length + pad;
left -= avp_length + pad;
}
return 0;
}
static void * eap_ttls_init(struct eap_sm *sm)
{
struct eap_ttls_data *data;
data = malloc(sizeof(*data));
if (data == NULL)
return data;
memset(data, 0, sizeof(*data));
data->ttls_version = EAP_TTLS_VERSION;
data->state = START;
if (eap_
评论1