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