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