1/*
2 * EAP-WSC server for Wi-Fi Protected Setup
3 * Copyright (c) 2007-2008, Jouni Malinen <j@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 "eloop.h"
13#include "eap_i.h"
14#include "eap_common/eap_wsc_common.h"
15#include "p2p/p2p.h"
16#include "wps/wps.h"
17
18
19struct eap_wsc_data {
20	enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
21	int registrar;
22	struct wpabuf *in_buf;
23	struct wpabuf *out_buf;
24	enum wsc_op_code in_op_code, out_op_code;
25	size_t out_used;
26	size_t fragment_size;
27	struct wps_data *wps;
28	int ext_reg_timeout;
29};
30
31
32#ifndef CONFIG_NO_STDOUT_DEBUG
33static const char * eap_wsc_state_txt(int state)
34{
35	switch (state) {
36	case START:
37		return "START";
38	case MESG:
39		return "MESG";
40	case FRAG_ACK:
41		return "FRAG_ACK";
42	case WAIT_FRAG_ACK:
43		return "WAIT_FRAG_ACK";
44	case DONE:
45		return "DONE";
46	case FAIL:
47		return "FAIL";
48	default:
49		return "?";
50	}
51}
52#endif /* CONFIG_NO_STDOUT_DEBUG */
53
54
55static void eap_wsc_state(struct eap_wsc_data *data, int state)
56{
57	wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
58		   eap_wsc_state_txt(data->state),
59		   eap_wsc_state_txt(state));
60	data->state = state;
61}
62
63
64static void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx)
65{
66	struct eap_sm *sm = eloop_ctx;
67	struct eap_wsc_data *data = timeout_ctx;
68
69	if (sm->method_pending != METHOD_PENDING_WAIT)
70		return;
71
72	wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External "
73		   "Registrar");
74	data->ext_reg_timeout = 1;
75	eap_sm_pending_cb(sm);
76}
77
78
79static void * eap_wsc_init(struct eap_sm *sm)
80{
81	struct eap_wsc_data *data;
82	int registrar;
83	struct wps_config cfg;
84
85	if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN &&
86	    os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) ==
87	    0)
88		registrar = 0; /* Supplicant is Registrar */
89	else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN &&
90		 os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN)
91		 == 0)
92		registrar = 1; /* Supplicant is Enrollee */
93	else {
94		wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
95				  sm->identity, sm->identity_len);
96		return NULL;
97	}
98
99	data = os_zalloc(sizeof(*data));
100	if (data == NULL)
101		return NULL;
102	data->state = registrar ? START : MESG;
103	data->registrar = registrar;
104
105	os_memset(&cfg, 0, sizeof(cfg));
106	cfg.wps = sm->wps;
107	cfg.registrar = registrar;
108	if (registrar) {
109		if (sm->wps == NULL || sm->wps->registrar == NULL) {
110			wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not "
111				   "initialized");
112			os_free(data);
113			return NULL;
114		}
115	} else {
116		if (sm->user == NULL || sm->user->password == NULL) {
117			/*
118			 * In theory, this should not really be needed, but
119			 * Windows 7 uses Registrar mode to probe AP's WPS
120			 * capabilities before trying to use Enrollee and fails
121			 * if the AP does not allow that probing to happen..
122			 */
123			wpa_printf(MSG_DEBUG, "EAP-WSC: No AP PIN (password) "
124				   "configured for Enrollee functionality - "
125				   "allow for probing capabilities (M1)");
126		} else {
127			cfg.pin = sm->user->password;
128			cfg.pin_len = sm->user->password_len;
129		}
130	}
131	cfg.assoc_wps_ie = sm->assoc_wps_ie;
132	cfg.peer_addr = sm->peer_addr;
133#ifdef CONFIG_P2P
134	if (sm->assoc_p2p_ie) {
135		wpa_printf(MSG_DEBUG, "EAP-WSC: Prefer PSK format for P2P "
136			   "client");
137		cfg.use_psk_key = 1;
138		cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie);
139	}
140#endif /* CONFIG_P2P */
141	cfg.pbc_in_m1 = sm->pbc_in_m1;
142	data->wps = wps_init(&cfg);
143	if (data->wps == NULL) {
144		os_free(data);
145		return NULL;
146	}
147	data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
148		WSC_FRAGMENT_SIZE;
149
150	return data;
151}
152
153
154static void eap_wsc_reset(struct eap_sm *sm, void *priv)
155{
156	struct eap_wsc_data *data = priv;
157	eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
158	wpabuf_free(data->in_buf);
159	wpabuf_free(data->out_buf);
160	wps_deinit(data->wps);
161	os_free(data);
162}
163
164
165static struct wpabuf * eap_wsc_build_start(struct eap_sm *sm,
166					   struct eap_wsc_data *data, u8 id)
167{
168	struct wpabuf *req;
169
170	req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2,
171			    EAP_CODE_REQUEST, id);
172	if (req == NULL) {
173		wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
174			   "request");
175		return NULL;
176	}
177
178	wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start");
179	wpabuf_put_u8(req, WSC_Start); /* Op-Code */
180	wpabuf_put_u8(req, 0); /* Flags */
181
182	return req;
183}
184
185
186static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id)
187{
188	struct wpabuf *req;
189	u8 flags;
190	size_t send_len, plen;
191
192	flags = 0;
193	send_len = wpabuf_len(data->out_buf) - data->out_used;
194	if (2 + send_len > data->fragment_size) {
195		send_len = data->fragment_size - 2;
196		flags |= WSC_FLAGS_MF;
197		if (data->out_used == 0) {
198			flags |= WSC_FLAGS_LF;
199			send_len -= 2;
200		}
201	}
202	plen = 2 + send_len;
203	if (flags & WSC_FLAGS_LF)
204		plen += 2;
205	req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
206			    EAP_CODE_REQUEST, id);
207	if (req == NULL) {
208		wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
209			   "request");
210		return NULL;
211	}
212
213	wpabuf_put_u8(req, data->out_op_code); /* Op-Code */
214	wpabuf_put_u8(req, flags); /* Flags */
215	if (flags & WSC_FLAGS_LF)
216		wpabuf_put_be16(req, wpabuf_len(data->out_buf));
217
218	wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
219			send_len);
220	data->out_used += send_len;
221
222	if (data->out_used == wpabuf_len(data->out_buf)) {
223		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
224			   "(message sent completely)",
225			   (unsigned long) send_len);
226		wpabuf_free(data->out_buf);
227		data->out_buf = NULL;
228		data->out_used = 0;
229		eap_wsc_state(data, MESG);
230	} else {
231		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
232			   "(%lu more to send)", (unsigned long) send_len,
233			   (unsigned long) wpabuf_len(data->out_buf) -
234			   data->out_used);
235		eap_wsc_state(data, WAIT_FRAG_ACK);
236	}
237
238	return req;
239}
240
241
242static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id)
243{
244	struct eap_wsc_data *data = priv;
245
246	switch (data->state) {
247	case START:
248		return eap_wsc_build_start(sm, data, id);
249	case MESG:
250		if (data->out_buf == NULL) {
251			data->out_buf = wps_get_msg(data->wps,
252						    &data->out_op_code);
253			if (data->out_buf == NULL) {
254				wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to "
255					   "receive message from WPS");
256				return NULL;
257			}
258			data->out_used = 0;
259		}
260		/* fall through */
261	case WAIT_FRAG_ACK:
262		return eap_wsc_build_msg(data, id);
263	case FRAG_ACK:
264		return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST);
265	default:
266		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in "
267			   "buildReq", data->state);
268		return NULL;
269	}
270}
271
272
273static Boolean eap_wsc_check(struct eap_sm *sm, void *priv,
274			     struct wpabuf *respData)
275{
276	const u8 *pos;
277	size_t len;
278
279	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
280			       respData, &len);
281	if (pos == NULL || len < 2) {
282		wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame");
283		return TRUE;
284	}
285
286	return FALSE;
287}
288
289
290static int eap_wsc_process_cont(struct eap_wsc_data *data,
291				const u8 *buf, size_t len, u8 op_code)
292{
293	/* Process continuation of a pending message */
294	if (op_code != data->in_op_code) {
295		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
296			   "fragment (expected %d)",
297			   op_code, data->in_op_code);
298		eap_wsc_state(data, FAIL);
299		return -1;
300	}
301
302	if (len > wpabuf_tailroom(data->in_buf)) {
303		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
304		eap_wsc_state(data, FAIL);
305		return -1;
306	}
307
308	wpabuf_put_data(data->in_buf, buf, len);
309	wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu "
310		   "bytes more", (unsigned long) len,
311		   (unsigned long) wpabuf_tailroom(data->in_buf));
312
313	return 0;
314}
315
316
317static int eap_wsc_process_fragment(struct eap_wsc_data *data,
318				    u8 flags, u8 op_code, u16 message_length,
319				    const u8 *buf, size_t len)
320{
321	/* Process a fragment that is not the last one of the message */
322	if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
323		wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length "
324			   "field in a fragmented packet");
325		return -1;
326	}
327
328	if (data->in_buf == NULL) {
329		/* First fragment of the message */
330		data->in_buf = wpabuf_alloc(message_length);
331		if (data->in_buf == NULL) {
332			wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
333				   "message");
334			return -1;
335		}
336		data->in_op_code = op_code;
337		wpabuf_put_data(data->in_buf, buf, len);
338		wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in "
339			   "first fragment, waiting for %lu bytes more",
340			   (unsigned long) len,
341			   (unsigned long) wpabuf_tailroom(data->in_buf));
342	}
343
344	return 0;
345}
346
347
348static void eap_wsc_process(struct eap_sm *sm, void *priv,
349			    struct wpabuf *respData)
350{
351	struct eap_wsc_data *data = priv;
352	const u8 *start, *pos, *end;
353	size_t len;
354	u8 op_code, flags;
355	u16 message_length = 0;
356	enum wps_process_res res;
357	struct wpabuf tmpbuf;
358
359	eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
360	if (data->ext_reg_timeout) {
361		eap_wsc_state(data, FAIL);
362		return;
363	}
364
365	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
366			       respData, &len);
367	if (pos == NULL || len < 2)
368		return; /* Should not happen; message already verified */
369
370	start = pos;
371	end = start + len;
372
373	op_code = *pos++;
374	flags = *pos++;
375	if (flags & WSC_FLAGS_LF) {
376		if (end - pos < 2) {
377			wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
378			return;
379		}
380		message_length = WPA_GET_BE16(pos);
381		pos += 2;
382
383		if (message_length < end - pos || message_length > 50000) {
384			wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
385				   "Length");
386			return;
387		}
388	}
389
390	wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
391		   "Flags 0x%x Message Length %d",
392		   op_code, flags, message_length);
393
394	if (data->state == WAIT_FRAG_ACK) {
395		if (op_code != WSC_FRAG_ACK) {
396			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
397				   "in WAIT_FRAG_ACK state", op_code);
398			eap_wsc_state(data, FAIL);
399			return;
400		}
401		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
402		eap_wsc_state(data, MESG);
403		return;
404	}
405
406	if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
407	    op_code != WSC_Done) {
408		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
409			   op_code);
410		eap_wsc_state(data, FAIL);
411		return;
412	}
413
414	if (data->in_buf &&
415	    eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
416		eap_wsc_state(data, FAIL);
417		return;
418	}
419
420	if (flags & WSC_FLAGS_MF) {
421		if (eap_wsc_process_fragment(data, flags, op_code,
422					     message_length, pos, end - pos) <
423		    0)
424			eap_wsc_state(data, FAIL);
425		else
426			eap_wsc_state(data, FRAG_ACK);
427		return;
428	}
429
430	if (data->in_buf == NULL) {
431		/* Wrap unfragmented messages as wpabuf without extra copy */
432		wpabuf_set(&tmpbuf, pos, end - pos);
433		data->in_buf = &tmpbuf;
434	}
435
436	res = wps_process_msg(data->wps, op_code, data->in_buf);
437	switch (res) {
438	case WPS_DONE:
439		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
440			   "successfully - report EAP failure");
441		eap_wsc_state(data, FAIL);
442		break;
443	case WPS_CONTINUE:
444		eap_wsc_state(data, MESG);
445		break;
446	case WPS_FAILURE:
447		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
448		eap_wsc_state(data, FAIL);
449		break;
450	case WPS_PENDING:
451		eap_wsc_state(data, MESG);
452		sm->method_pending = METHOD_PENDING_WAIT;
453		eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
454		eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout,
455				       sm, data);
456		break;
457	}
458
459	if (data->in_buf != &tmpbuf)
460		wpabuf_free(data->in_buf);
461	data->in_buf = NULL;
462}
463
464
465static Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv)
466{
467	struct eap_wsc_data *data = priv;
468	return data->state == FAIL;
469}
470
471
472static Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv)
473{
474	/* EAP-WSC will always result in EAP-Failure */
475	return FALSE;
476}
477
478
479static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv)
480{
481	/* Recommended retransmit times: retransmit timeout 5 seconds,
482	 * per-message timeout 15 seconds, i.e., 3 tries. */
483	sm->MaxRetrans = 2; /* total 3 attempts */
484	return 5;
485}
486
487
488int eap_server_wsc_register(void)
489{
490	struct eap_method *eap;
491
492	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
493				      EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
494				      "WSC");
495	if (eap == NULL)
496		return -1;
497
498	eap->init = eap_wsc_init;
499	eap->reset = eap_wsc_reset;
500	eap->buildReq = eap_wsc_buildReq;
501	eap->check = eap_wsc_check;
502	eap->process = eap_wsc_process;
503	eap->isDone = eap_wsc_isDone;
504	eap->isSuccess = eap_wsc_isSuccess;
505	eap->getTimeout = eap_wsc_getTimeout;
506
507	return eap_server_method_register(eap);
508}
509