xref: /freebsd/contrib/wpa/src/eap_server/eap_server_gtc.c (revision 10b59a9b4add0320d52c15ce057dd697261e7dfc)
1 /*
2  * hostapd / EAP-GTC (RFC 3748)
3  * Copyright (c) 2004-2006, Jouni Malinen <j@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_SERVER_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_SERVER_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_SERVER_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_SERVER_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