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