Home | History | Annotate | Download | only in eap_server
      1 /*
      2  * hostapd / EAP-GTC (RFC 3748)
      3  * Copyright (c) 2004-2006, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License version 2 as
      7  * published by the Free Software Foundation.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  */
     14 
     15 #include "includes.h"
     16 
     17 #include "common.h"
     18 #include "eap_i.h"
     19 
     20 
     21 struct eap_gtc_data {
     22 	enum { CONTINUE, SUCCESS, FAILURE } state;
     23 	int prefix;
     24 };
     25 
     26 
     27 static void * eap_gtc_init(struct eap_sm *sm)
     28 {
     29 	struct eap_gtc_data *data;
     30 
     31 	data = os_zalloc(sizeof(*data));
     32 	if (data == NULL)
     33 		return NULL;
     34 	data->state = CONTINUE;
     35 
     36 #ifdef EAP_FAST
     37 	if (sm->m && sm->m->vendor == EAP_VENDOR_IETF &&
     38 	    sm->m->method == EAP_TYPE_FAST) {
     39 		wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix "
     40 			   "with challenge/response");
     41 		data->prefix = 1;
     42 	}
     43 #endif /* EAP_FAST */
     44 
     45 	return data;
     46 }
     47 
     48 
     49 static void eap_gtc_reset(struct eap_sm *sm, void *priv)
     50 {
     51 	struct eap_gtc_data *data = priv;
     52 	os_free(data);
     53 }
     54 
     55 
     56 static struct wpabuf * eap_gtc_buildReq(struct eap_sm *sm, void *priv, u8 id)
     57 {
     58 	struct eap_gtc_data *data = priv;
     59 	struct wpabuf *req;
     60 	char *msg;
     61 	size_t msg_len;
     62 
     63 	msg = data->prefix ? "CHALLENGE=Password" : "Password";
     64 
     65 	msg_len = os_strlen(msg);
     66 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, msg_len,
     67 			    EAP_CODE_REQUEST, id);
     68 	if (req == NULL) {
     69 		wpa_printf(MSG_ERROR, "EAP-GTC: Failed to allocate memory for "
     70 			   "request");
     71 		data->state = FAILURE;
     72 		return NULL;
     73 	}
     74 
     75 	wpabuf_put_data(req, msg, msg_len);
     76 
     77 	data->state = CONTINUE;
     78 
     79 	return req;
     80 }
     81 
     82 
     83 static Boolean eap_gtc_check(struct eap_sm *sm, void *priv,
     84 			     struct wpabuf *respData)
     85 {
     86 	const u8 *pos;
     87 	size_t len;
     88 
     89 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &len);
     90 	if (pos == NULL || len < 1) {
     91 		wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame");
     92 		return TRUE;
     93 	}
     94 
     95 	return FALSE;
     96 }
     97 
     98 
     99 static void eap_gtc_process(struct eap_sm *sm, void *priv,
    100 			    struct wpabuf *respData)
    101 {
    102 	struct eap_gtc_data *data = priv;
    103 	const u8 *pos;
    104 	size_t rlen;
    105 
    106 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &rlen);
    107 	if (pos == NULL || rlen < 1)
    108 		return; /* Should not happen - frame already validated */
    109 
    110 	wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen);
    111 
    112 #ifdef EAP_FAST
    113 	if (data->prefix) {
    114 		const u8 *pos2, *end;
    115 		/* "RESPONSE=<user>\0<password>" */
    116 		if (rlen < 10) {
    117 			wpa_printf(MSG_DEBUG, "EAP-GTC: Too short response "
    118 				   "for EAP-FAST prefix");
    119 			data->state = FAILURE;
    120 			return;
    121 		}
    122 
    123 		end = pos + rlen;
    124 		pos += 9;
    125 		pos2 = pos;
    126 		while (pos2 < end && *pos2)
    127 			pos2++;
    128 		if (pos2 == end) {
    129 			wpa_printf(MSG_DEBUG, "EAP-GTC: No password in "
    130 				   "response to EAP-FAST prefix");
    131 			data->state = FAILURE;
    132 			return;
    133 		}
    134 
    135 		wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Response user",
    136 				  pos, pos2 - pos);
    137 		if (sm->identity && sm->require_identity_match &&
    138 		    (pos2 - pos != (int) sm->identity_len ||
    139 		     os_memcmp(pos, sm->identity, sm->identity_len))) {
    140 			wpa_printf(MSG_DEBUG, "EAP-GTC: Phase 2 Identity did "
    141 				   "not match with required Identity");
    142 			wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Expected "
    143 					  "identity",
    144 					  sm->identity, sm->identity_len);
    145 			data->state = FAILURE;
    146 			return;
    147 		} else {
    148 			os_free(sm->identity);
    149 			sm->identity_len = pos2 - pos;
    150 			sm->identity = os_malloc(sm->identity_len);
    151 			if (sm->identity == NULL) {
    152 				data->state = FAILURE;
    153 				return;
    154 			}
    155 			os_memcpy(sm->identity, pos, sm->identity_len);
    156 		}
    157 
    158 		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
    159 			wpa_hexdump_ascii(MSG_DEBUG, "EAP-GTC: Phase2 "
    160 					  "Identity not found in the user "
    161 					  "database",
    162 					  sm->identity, sm->identity_len);
    163 			data->state = FAILURE;
    164 			return;
    165 		}
    166 
    167 		pos = pos2 + 1;
    168 		rlen = end - pos;
    169 		wpa_hexdump_ascii_key(MSG_MSGDUMP,
    170 				      "EAP-GTC: Response password",
    171 				      pos, rlen);
    172 	}
    173 #endif /* EAP_FAST */
    174 
    175 	if (sm->user == NULL || sm->user->password == NULL ||
    176 	    sm->user->password_hash) {
    177 		wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not "
    178 			   "configured");
    179 		data->state = FAILURE;
    180 		return;
    181 	}
    182 
    183 	if (rlen != sm->user->password_len ||
    184 	    os_memcmp(pos, sm->user->password, rlen) != 0) {
    185 		wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure");
    186 		data->state = FAILURE;
    187 	} else {
    188 		wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Success");
    189 		data->state = SUCCESS;
    190 	}
    191 }
    192 
    193 
    194 static Boolean eap_gtc_isDone(struct eap_sm *sm, void *priv)
    195 {
    196 	struct eap_gtc_data *data = priv;
    197 	return data->state != CONTINUE;
    198 }
    199 
    200 
    201 static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv)
    202 {
    203 	struct eap_gtc_data *data = priv;
    204 	return data->state == SUCCESS;
    205 }
    206 
    207 
    208 int eap_server_gtc_register(void)
    209 {
    210 	struct eap_method *eap;
    211 	int ret;
    212 
    213 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    214 				      EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC");
    215 	if (eap == NULL)
    216 		return -1;
    217 
    218 	eap->init = eap_gtc_init;
    219 	eap->reset = eap_gtc_reset;
    220 	eap->buildReq = eap_gtc_buildReq;
    221 	eap->check = eap_gtc_check;
    222 	eap->process = eap_gtc_process;
    223 	eap->isDone = eap_gtc_isDone;
    224 	eap->isSuccess = eap_gtc_isSuccess;
    225 
    226 	ret = eap_server_method_register(eap);
    227 	if (ret)
    228 		eap_server_method_free(eap);
    229 	return ret;
    230 }
    231