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