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