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