Line data Source code
1 : /*
2 : * hostapd / EAP Full Authenticator state machine (RFC 4137)
3 : * Copyright (c) 2004-2007, 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 : * This state machine is based on the full authenticator state machine defined
9 : * in RFC 4137. However, to support backend authentication in RADIUS
10 : * authentication server functionality, parts of backend authenticator (also
11 : * from RFC 4137) are mixed in. This functionality is enabled by setting
12 : * backend_auth configuration variable to TRUE.
13 : */
14 :
15 : #include "includes.h"
16 :
17 : #include "common.h"
18 : #include "eap_i.h"
19 : #include "state_machine.h"
20 : #include "common/wpa_ctrl.h"
21 :
22 : #define STATE_MACHINE_DATA struct eap_sm
23 : #define STATE_MACHINE_DEBUG_PREFIX "EAP"
24 :
25 : #define EAP_MAX_AUTH_ROUNDS 50
26 :
27 : static void eap_user_free(struct eap_user *user);
28 :
29 :
30 : /* EAP state machines are described in RFC 4137 */
31 :
32 : static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
33 : int eapSRTT, int eapRTTVAR,
34 : int methodTimeout);
35 : static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp);
36 : static int eap_sm_getId(const struct wpabuf *data);
37 : static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id);
38 : static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id);
39 : static int eap_sm_nextId(struct eap_sm *sm, int id);
40 : static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
41 : size_t len);
42 : static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor);
43 : static int eap_sm_Policy_getDecision(struct eap_sm *sm);
44 : static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
45 :
46 :
47 7458 : static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src)
48 : {
49 7458 : if (src == NULL)
50 0 : return -1;
51 :
52 7458 : wpabuf_free(*dst);
53 7458 : *dst = wpabuf_dup(src);
54 7458 : return *dst ? 0 : -1;
55 : }
56 :
57 :
58 252 : static int eap_copy_data(u8 **dst, size_t *dst_len,
59 : const u8 *src, size_t src_len)
60 : {
61 252 : if (src == NULL)
62 0 : return -1;
63 :
64 252 : os_free(*dst);
65 252 : *dst = os_malloc(src_len);
66 252 : if (*dst) {
67 252 : os_memcpy(*dst, src, src_len);
68 252 : *dst_len = src_len;
69 252 : return 0;
70 : } else {
71 0 : *dst_len = 0;
72 0 : return -1;
73 : }
74 : }
75 :
76 : #define EAP_COPY(dst, src) \
77 : eap_copy_data((dst), (dst ## Len), (src), (src ## Len))
78 :
79 :
80 : /**
81 : * eap_user_get - Fetch user information from the database
82 : * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
83 : * @identity: Identity (User-Name) of the user
84 : * @identity_len: Length of identity in bytes
85 : * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user
86 : * Returns: 0 on success, or -1 on failure
87 : *
88 : * This function is used to fetch user information for EAP. The user will be
89 : * selected based on the specified identity. sm->user and
90 : * sm->user_eap_method_index are updated for the new user when a matching user
91 : * is found. sm->user can be used to get user information (e.g., password).
92 : */
93 746 : int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
94 : int phase2)
95 : {
96 : struct eap_user *user;
97 :
98 1492 : if (sm == NULL || sm->eapol_cb == NULL ||
99 746 : sm->eapol_cb->get_eap_user == NULL)
100 0 : return -1;
101 :
102 746 : eap_user_free(sm->user);
103 746 : sm->user = NULL;
104 :
105 746 : user = os_zalloc(sizeof(*user));
106 746 : if (user == NULL)
107 0 : return -1;
108 :
109 746 : if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity,
110 : identity_len, phase2, user) != 0) {
111 1 : eap_user_free(user);
112 1 : return -1;
113 : }
114 :
115 745 : sm->user = user;
116 745 : sm->user_eap_method_index = 0;
117 :
118 745 : return 0;
119 : }
120 :
121 :
122 2190 : void eap_log_msg(struct eap_sm *sm, const char *fmt, ...)
123 : {
124 : va_list ap;
125 : char *buf;
126 : int buflen;
127 :
128 2190 : if (sm == NULL || sm->eapol_cb == NULL || sm->eapol_cb->log_msg == NULL)
129 2706 : return;
130 :
131 837 : va_start(ap, fmt);
132 837 : buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
133 837 : va_end(ap);
134 :
135 837 : buf = os_malloc(buflen);
136 837 : if (buf == NULL)
137 0 : return;
138 837 : va_start(ap, fmt);
139 837 : vsnprintf(buf, buflen, fmt, ap);
140 837 : va_end(ap);
141 :
142 837 : sm->eapol_cb->log_msg(sm->eapol_ctx, buf);
143 :
144 837 : os_free(buf);
145 : }
146 :
147 :
148 1132 : SM_STATE(EAP, DISABLED)
149 : {
150 1132 : SM_ENTRY(EAP, DISABLED);
151 1132 : sm->num_rounds = 0;
152 1132 : }
153 :
154 :
155 851 : SM_STATE(EAP, INITIALIZE)
156 : {
157 851 : SM_ENTRY(EAP, INITIALIZE);
158 :
159 851 : if (sm->eap_if.eapRestart && !sm->eap_server && sm->identity) {
160 : /*
161 : * Need to allow internal Identity method to be used instead
162 : * of passthrough at the beginning of reauthentication.
163 : */
164 11 : eap_server_clear_identity(sm);
165 : }
166 :
167 851 : sm->currentId = -1;
168 851 : sm->eap_if.eapSuccess = FALSE;
169 851 : sm->eap_if.eapFail = FALSE;
170 851 : sm->eap_if.eapTimeout = FALSE;
171 851 : os_free(sm->eap_if.eapKeyData);
172 851 : sm->eap_if.eapKeyData = NULL;
173 851 : sm->eap_if.eapKeyDataLen = 0;
174 851 : sm->eap_if.eapKeyAvailable = FALSE;
175 851 : sm->eap_if.eapRestart = FALSE;
176 :
177 : /*
178 : * This is not defined in RFC 4137, but method state needs to be
179 : * reseted here so that it does not remain in success state when
180 : * re-authentication starts.
181 : */
182 851 : if (sm->m && sm->eap_method_priv) {
183 70 : sm->m->reset(sm, sm->eap_method_priv);
184 70 : sm->eap_method_priv = NULL;
185 : }
186 851 : sm->m = NULL;
187 851 : sm->user_eap_method_index = 0;
188 :
189 851 : if (sm->backend_auth) {
190 304 : sm->currentMethod = EAP_TYPE_NONE;
191 : /* parse rxResp, respId, respMethod */
192 304 : eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
193 304 : if (sm->rxResp) {
194 304 : sm->currentId = sm->respId;
195 : }
196 : }
197 851 : sm->num_rounds = 0;
198 851 : sm->method_pending = METHOD_PENDING_NONE;
199 :
200 5106 : wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
201 5106 : MACSTR, MAC2STR(sm->peer_addr));
202 851 : }
203 :
204 :
205 304 : SM_STATE(EAP, PICK_UP_METHOD)
206 : {
207 304 : SM_ENTRY(EAP, PICK_UP_METHOD);
208 :
209 304 : if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) {
210 304 : sm->currentMethod = sm->respMethod;
211 304 : if (sm->m && sm->eap_method_priv) {
212 0 : sm->m->reset(sm, sm->eap_method_priv);
213 0 : sm->eap_method_priv = NULL;
214 : }
215 304 : sm->m = eap_server_get_eap_method(EAP_VENDOR_IETF,
216 : sm->currentMethod);
217 304 : if (sm->m && sm->m->initPickUp) {
218 304 : sm->eap_method_priv = sm->m->initPickUp(sm);
219 608 : if (sm->eap_method_priv == NULL) {
220 0 : wpa_printf(MSG_DEBUG, "EAP: Failed to "
221 : "initialize EAP method %d",
222 0 : sm->currentMethod);
223 0 : sm->m = NULL;
224 0 : sm->currentMethod = EAP_TYPE_NONE;
225 : }
226 : } else {
227 0 : sm->m = NULL;
228 0 : sm->currentMethod = EAP_TYPE_NONE;
229 : }
230 : }
231 :
232 304 : wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
233 304 : "method=%u", sm->currentMethod);
234 304 : }
235 :
236 :
237 2956 : SM_STATE(EAP, IDLE)
238 : {
239 2956 : SM_ENTRY(EAP, IDLE);
240 :
241 2956 : sm->eap_if.retransWhile = eap_sm_calculateTimeout(
242 : sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR,
243 : sm->methodTimeout);
244 2956 : }
245 :
246 :
247 0 : SM_STATE(EAP, RETRANSMIT)
248 : {
249 0 : SM_ENTRY(EAP, RETRANSMIT);
250 :
251 0 : sm->retransCount++;
252 0 : if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
253 0 : if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
254 0 : sm->eap_if.eapReq = TRUE;
255 : }
256 0 : }
257 :
258 :
259 2946 : SM_STATE(EAP, RECEIVED)
260 : {
261 2946 : SM_ENTRY(EAP, RECEIVED);
262 :
263 : /* parse rxResp, respId, respMethod */
264 2946 : eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
265 2946 : sm->num_rounds++;
266 2946 : }
267 :
268 :
269 2 : SM_STATE(EAP, DISCARD)
270 : {
271 2 : SM_ENTRY(EAP, DISCARD);
272 2 : sm->eap_if.eapResp = FALSE;
273 2 : sm->eap_if.eapNoReq = TRUE;
274 2 : }
275 :
276 :
277 2954 : SM_STATE(EAP, SEND_REQUEST)
278 : {
279 2954 : SM_ENTRY(EAP, SEND_REQUEST);
280 :
281 2954 : sm->retransCount = 0;
282 2954 : if (sm->eap_if.eapReqData) {
283 2954 : if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
284 : {
285 2954 : sm->eap_if.eapResp = FALSE;
286 2954 : sm->eap_if.eapReq = TRUE;
287 : } else {
288 0 : sm->eap_if.eapResp = FALSE;
289 0 : sm->eap_if.eapReq = FALSE;
290 : }
291 : } else {
292 0 : wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData");
293 0 : sm->eap_if.eapResp = FALSE;
294 0 : sm->eap_if.eapReq = FALSE;
295 0 : sm->eap_if.eapNoReq = TRUE;
296 : }
297 2954 : }
298 :
299 :
300 2874 : SM_STATE(EAP, INTEGRITY_CHECK)
301 : {
302 2874 : SM_ENTRY(EAP, INTEGRITY_CHECK);
303 :
304 2874 : if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) {
305 0 : sm->ignore = TRUE;
306 2874 : return;
307 : }
308 :
309 2874 : if (sm->m->check) {
310 2874 : sm->ignore = sm->m->check(sm, sm->eap_method_priv,
311 : sm->eap_if.eapRespData);
312 : }
313 : }
314 :
315 :
316 2954 : SM_STATE(EAP, METHOD_REQUEST)
317 : {
318 2954 : SM_ENTRY(EAP, METHOD_REQUEST);
319 :
320 2954 : if (sm->m == NULL) {
321 0 : wpa_printf(MSG_DEBUG, "EAP: method not initialized");
322 2954 : return;
323 : }
324 :
325 2954 : sm->currentId = eap_sm_nextId(sm, sm->currentId);
326 2954 : wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d",
327 : sm->currentId);
328 2954 : sm->lastId = sm->currentId;
329 2954 : wpabuf_free(sm->eap_if.eapReqData);
330 5908 : sm->eap_if.eapReqData = sm->m->buildReq(sm, sm->eap_method_priv,
331 2954 : sm->currentId);
332 2954 : if (sm->m->getTimeout)
333 955 : sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv);
334 : else
335 1999 : sm->methodTimeout = 0;
336 : }
337 :
338 :
339 3253 : SM_STATE(EAP, METHOD_RESPONSE)
340 : {
341 3253 : SM_ENTRY(EAP, METHOD_RESPONSE);
342 :
343 3253 : if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1))
344 3253 : return;
345 :
346 3253 : sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData);
347 3253 : if (sm->m->isDone(sm, sm->eap_method_priv)) {
348 1374 : eap_sm_Policy_update(sm, NULL, 0);
349 1374 : os_free(sm->eap_if.eapKeyData);
350 1374 : if (sm->m->getKey) {
351 329 : sm->eap_if.eapKeyData = sm->m->getKey(
352 : sm, sm->eap_method_priv,
353 : &sm->eap_if.eapKeyDataLen);
354 : } else {
355 1045 : sm->eap_if.eapKeyData = NULL;
356 1045 : sm->eap_if.eapKeyDataLen = 0;
357 : }
358 1374 : sm->methodState = METHOD_END;
359 : } else {
360 1879 : sm->methodState = METHOD_CONTINUE;
361 : }
362 : }
363 :
364 :
365 1150 : SM_STATE(EAP, PROPOSE_METHOD)
366 : {
367 : int vendor;
368 : EapType type;
369 :
370 1150 : SM_ENTRY(EAP, PROPOSE_METHOD);
371 :
372 : try_another_method:
373 1150 : type = eap_sm_Policy_getNextMethod(sm, &vendor);
374 1150 : if (vendor == EAP_VENDOR_IETF)
375 943 : sm->currentMethod = type;
376 : else
377 207 : sm->currentMethod = EAP_TYPE_EXPANDED;
378 1150 : if (sm->m && sm->eap_method_priv) {
379 541 : sm->m->reset(sm, sm->eap_method_priv);
380 541 : sm->eap_method_priv = NULL;
381 : }
382 1150 : sm->m = eap_server_get_eap_method(vendor, type);
383 1150 : if (sm->m) {
384 1150 : sm->eap_method_priv = sm->m->init(sm);
385 1150 : if (sm->eap_method_priv == NULL) {
386 0 : wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP "
387 0 : "method %d", sm->currentMethod);
388 0 : sm->m = NULL;
389 0 : sm->currentMethod = EAP_TYPE_NONE;
390 0 : goto try_another_method;
391 : }
392 : }
393 1150 : if (sm->m == NULL) {
394 0 : wpa_printf(MSG_DEBUG, "EAP: Could not find suitable EAP method");
395 0 : eap_log_msg(sm, "Could not find suitable EAP method");
396 0 : sm->decision = DECISION_FAILURE;
397 1150 : return;
398 : }
399 1753 : if (sm->currentMethod == EAP_TYPE_IDENTITY ||
400 603 : sm->currentMethod == EAP_TYPE_NOTIFICATION)
401 547 : sm->methodState = METHOD_CONTINUE;
402 : else
403 603 : sm->methodState = METHOD_PROPOSED;
404 :
405 1150 : wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
406 1150 : "vendor=%u method=%u", vendor, sm->currentMethod);
407 1150 : eap_log_msg(sm, "Propose EAP method vendor=%u method=%u",
408 1150 : vendor, sm->currentMethod);
409 : }
410 :
411 :
412 70 : SM_STATE(EAP, NAK)
413 : {
414 : const struct eap_hdr *nak;
415 70 : size_t len = 0;
416 : const u8 *pos;
417 70 : const u8 *nak_list = NULL;
418 :
419 70 : SM_ENTRY(EAP, NAK);
420 :
421 70 : if (sm->eap_method_priv) {
422 70 : sm->m->reset(sm, sm->eap_method_priv);
423 70 : sm->eap_method_priv = NULL;
424 : }
425 70 : sm->m = NULL;
426 :
427 70 : if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1))
428 70 : return;
429 :
430 70 : nak = wpabuf_head(sm->eap_if.eapRespData);
431 70 : if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) {
432 70 : len = be_to_host16(nak->length);
433 70 : if (len > wpabuf_len(sm->eap_if.eapRespData))
434 0 : len = wpabuf_len(sm->eap_if.eapRespData);
435 70 : pos = (const u8 *) (nak + 1);
436 70 : len -= sizeof(*nak);
437 70 : if (*pos == EAP_TYPE_NAK) {
438 69 : pos++;
439 69 : len--;
440 69 : nak_list = pos;
441 : }
442 : }
443 70 : eap_sm_Policy_update(sm, nak_list, len);
444 : }
445 :
446 :
447 1991 : SM_STATE(EAP, SELECT_ACTION)
448 : {
449 1991 : SM_ENTRY(EAP, SELECT_ACTION);
450 :
451 1991 : sm->decision = eap_sm_Policy_getDecision(sm);
452 1991 : }
453 :
454 :
455 0 : SM_STATE(EAP, TIMEOUT_FAILURE)
456 : {
457 0 : SM_ENTRY(EAP, TIMEOUT_FAILURE);
458 :
459 0 : sm->eap_if.eapTimeout = TRUE;
460 0 : }
461 :
462 :
463 251 : SM_STATE(EAP, FAILURE)
464 : {
465 251 : SM_ENTRY(EAP, FAILURE);
466 :
467 251 : wpabuf_free(sm->eap_if.eapReqData);
468 251 : sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId);
469 251 : wpabuf_free(sm->lastReqData);
470 251 : sm->lastReqData = NULL;
471 251 : sm->eap_if.eapFail = TRUE;
472 :
473 1506 : wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
474 1506 : MACSTR, MAC2STR(sm->peer_addr));
475 251 : }
476 :
477 :
478 284 : SM_STATE(EAP, SUCCESS)
479 : {
480 284 : SM_ENTRY(EAP, SUCCESS);
481 :
482 284 : wpabuf_free(sm->eap_if.eapReqData);
483 284 : sm->eap_if.eapReqData = eap_sm_buildSuccess(sm, sm->currentId);
484 284 : wpabuf_free(sm->lastReqData);
485 284 : sm->lastReqData = NULL;
486 284 : if (sm->eap_if.eapKeyData)
487 284 : sm->eap_if.eapKeyAvailable = TRUE;
488 284 : sm->eap_if.eapSuccess = TRUE;
489 :
490 1704 : wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
491 1704 : MACSTR, MAC2STR(sm->peer_addr));
492 284 : }
493 :
494 :
495 306 : SM_STATE(EAP, INITIALIZE_PASSTHROUGH)
496 : {
497 306 : SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH);
498 :
499 306 : wpabuf_free(sm->eap_if.aaaEapRespData);
500 306 : sm->eap_if.aaaEapRespData = NULL;
501 306 : }
502 :
503 :
504 1301 : SM_STATE(EAP, IDLE2)
505 : {
506 1301 : SM_ENTRY(EAP, IDLE2);
507 :
508 1301 : sm->eap_if.retransWhile = eap_sm_calculateTimeout(
509 : sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR,
510 : sm->methodTimeout);
511 1301 : }
512 :
513 :
514 0 : SM_STATE(EAP, RETRANSMIT2)
515 : {
516 0 : SM_ENTRY(EAP, RETRANSMIT2);
517 :
518 0 : sm->retransCount++;
519 0 : if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
520 0 : if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
521 0 : sm->eap_if.eapReq = TRUE;
522 : }
523 0 : }
524 :
525 :
526 1298 : SM_STATE(EAP, RECEIVED2)
527 : {
528 1298 : SM_ENTRY(EAP, RECEIVED2);
529 :
530 : /* parse rxResp, respId, respMethod */
531 1298 : eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
532 1298 : }
533 :
534 :
535 0 : SM_STATE(EAP, DISCARD2)
536 : {
537 0 : SM_ENTRY(EAP, DISCARD2);
538 0 : sm->eap_if.eapResp = FALSE;
539 0 : sm->eap_if.eapNoReq = TRUE;
540 0 : }
541 :
542 :
543 1301 : SM_STATE(EAP, SEND_REQUEST2)
544 : {
545 1301 : SM_ENTRY(EAP, SEND_REQUEST2);
546 :
547 1301 : sm->retransCount = 0;
548 1301 : if (sm->eap_if.eapReqData) {
549 1301 : if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
550 : {
551 1301 : sm->eap_if.eapResp = FALSE;
552 1301 : sm->eap_if.eapReq = TRUE;
553 : } else {
554 0 : sm->eap_if.eapResp = FALSE;
555 0 : sm->eap_if.eapReq = FALSE;
556 : }
557 : } else {
558 0 : wpa_printf(MSG_INFO, "EAP: SEND_REQUEST2 - no eapReqData");
559 0 : sm->eap_if.eapResp = FALSE;
560 0 : sm->eap_if.eapReq = FALSE;
561 0 : sm->eap_if.eapNoReq = TRUE;
562 : }
563 1301 : }
564 :
565 :
566 1604 : SM_STATE(EAP, AAA_REQUEST)
567 : {
568 1604 : SM_ENTRY(EAP, AAA_REQUEST);
569 :
570 1604 : if (sm->eap_if.eapRespData == NULL) {
571 0 : wpa_printf(MSG_INFO, "EAP: AAA_REQUEST - no eapRespData");
572 1604 : return;
573 : }
574 :
575 : /*
576 : * if (respMethod == IDENTITY)
577 : * aaaIdentity = eapRespData
578 : * This is already taken care of by the EAP-Identity method which
579 : * stores the identity into sm->identity.
580 : */
581 :
582 1604 : eap_copy_buf(&sm->eap_if.aaaEapRespData, sm->eap_if.eapRespData);
583 : }
584 :
585 :
586 1301 : SM_STATE(EAP, AAA_RESPONSE)
587 : {
588 1301 : SM_ENTRY(EAP, AAA_RESPONSE);
589 :
590 1301 : eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
591 1301 : sm->currentId = eap_sm_getId(sm->eap_if.eapReqData);
592 1301 : sm->methodTimeout = sm->eap_if.aaaMethodTimeout;
593 1301 : }
594 :
595 :
596 1604 : SM_STATE(EAP, AAA_IDLE)
597 : {
598 1604 : SM_ENTRY(EAP, AAA_IDLE);
599 :
600 1604 : sm->eap_if.aaaFail = FALSE;
601 1604 : sm->eap_if.aaaSuccess = FALSE;
602 1604 : sm->eap_if.aaaEapReq = FALSE;
603 1604 : sm->eap_if.aaaEapNoReq = FALSE;
604 1604 : sm->eap_if.aaaEapResp = TRUE;
605 1604 : }
606 :
607 :
608 0 : SM_STATE(EAP, TIMEOUT_FAILURE2)
609 : {
610 0 : SM_ENTRY(EAP, TIMEOUT_FAILURE2);
611 :
612 0 : sm->eap_if.eapTimeout = TRUE;
613 0 : }
614 :
615 :
616 46 : SM_STATE(EAP, FAILURE2)
617 : {
618 46 : SM_ENTRY(EAP, FAILURE2);
619 :
620 46 : eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
621 46 : sm->eap_if.eapFail = TRUE;
622 46 : }
623 :
624 :
625 252 : SM_STATE(EAP, SUCCESS2)
626 : {
627 252 : SM_ENTRY(EAP, SUCCESS2);
628 :
629 252 : eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
630 :
631 252 : sm->eap_if.eapKeyAvailable = sm->eap_if.aaaEapKeyAvailable;
632 252 : if (sm->eap_if.aaaEapKeyAvailable) {
633 252 : EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData);
634 : } else {
635 0 : os_free(sm->eap_if.eapKeyData);
636 0 : sm->eap_if.eapKeyData = NULL;
637 0 : sm->eap_if.eapKeyDataLen = 0;
638 : }
639 :
640 252 : sm->eap_if.eapSuccess = TRUE;
641 :
642 : /*
643 : * Start reauthentication with identity request even though we know the
644 : * previously used identity. This is needed to get reauthentication
645 : * started properly.
646 : */
647 252 : sm->start_reauth = TRUE;
648 252 : }
649 :
650 :
651 46287 : SM_STEP(EAP)
652 : {
653 46287 : if (sm->eap_if.eapRestart && sm->eap_if.portEnabled)
654 851 : SM_ENTER_GLOBAL(EAP, INITIALIZE);
655 45436 : else if (!sm->eap_if.portEnabled)
656 1132 : SM_ENTER_GLOBAL(EAP, DISABLED);
657 44304 : else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
658 0 : if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
659 0 : wpa_printf(MSG_DEBUG, "EAP: more than %d "
660 : "authentication rounds - abort",
661 : EAP_MAX_AUTH_ROUNDS);
662 0 : sm->num_rounds++;
663 0 : SM_ENTER_GLOBAL(EAP, FAILURE);
664 : }
665 44304 : } else switch (sm->EAP_state) {
666 : case EAP_INITIALIZE:
667 851 : if (sm->backend_auth) {
668 304 : if (!sm->rxResp)
669 0 : SM_ENTER(EAP, SELECT_ACTION);
670 608 : else if (sm->rxResp &&
671 608 : (sm->respMethod == EAP_TYPE_NAK ||
672 304 : (sm->respMethod == EAP_TYPE_EXPANDED &&
673 0 : sm->respVendor == EAP_VENDOR_IETF &&
674 0 : sm->respVendorMethod == EAP_TYPE_NAK)))
675 0 : SM_ENTER(EAP, NAK);
676 : else
677 304 : SM_ENTER(EAP, PICK_UP_METHOD);
678 : } else {
679 547 : SM_ENTER(EAP, SELECT_ACTION);
680 : }
681 851 : break;
682 : case EAP_PICK_UP_METHOD:
683 304 : if (sm->currentMethod == EAP_TYPE_NONE) {
684 0 : SM_ENTER(EAP, SELECT_ACTION);
685 : } else {
686 304 : SM_ENTER(EAP, METHOD_RESPONSE);
687 : }
688 304 : break;
689 : case EAP_DISABLED:
690 0 : if (sm->eap_if.portEnabled)
691 0 : SM_ENTER(EAP, INITIALIZE);
692 0 : break;
693 : case EAP_IDLE:
694 8832 : if (sm->eap_if.retransWhile == 0)
695 0 : SM_ENTER(EAP, RETRANSMIT);
696 8832 : else if (sm->eap_if.eapResp)
697 2946 : SM_ENTER(EAP, RECEIVED);
698 8832 : break;
699 : case EAP_RETRANSMIT:
700 0 : if (sm->retransCount > sm->MaxRetrans)
701 0 : SM_ENTER(EAP, TIMEOUT_FAILURE);
702 : else
703 0 : SM_ENTER(EAP, IDLE);
704 0 : break;
705 : case EAP_RECEIVED:
706 5890 : if (sm->rxResp && (sm->respId == sm->currentId) &&
707 5819 : (sm->respMethod == EAP_TYPE_NAK ||
708 3849 : (sm->respMethod == EAP_TYPE_EXPANDED &&
709 975 : sm->respVendor == EAP_VENDOR_IETF &&
710 1 : sm->respVendorMethod == EAP_TYPE_NAK))
711 70 : && (sm->methodState == METHOD_PROPOSED))
712 70 : SM_ENTER(EAP, NAK);
713 5750 : else if (sm->rxResp && (sm->respId == sm->currentId) &&
714 2874 : ((sm->respMethod == sm->currentMethod) ||
715 0 : (sm->respMethod == EAP_TYPE_EXPANDED &&
716 0 : sm->respVendor == EAP_VENDOR_IETF &&
717 0 : sm->respVendorMethod == sm->currentMethod)))
718 2874 : SM_ENTER(EAP, INTEGRITY_CHECK);
719 : else {
720 4 : wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "
721 : "rxResp=%d respId=%d currentId=%d "
722 : "respMethod=%d currentMethod=%d",
723 2 : sm->rxResp, sm->respId, sm->currentId,
724 2 : sm->respMethod, sm->currentMethod);
725 2 : eap_log_msg(sm, "Discard received EAP message");
726 2 : SM_ENTER(EAP, DISCARD);
727 : }
728 2946 : break;
729 : case EAP_DISCARD:
730 2 : SM_ENTER(EAP, IDLE);
731 2 : break;
732 : case EAP_SEND_REQUEST:
733 2954 : SM_ENTER(EAP, IDLE);
734 2954 : break;
735 : case EAP_INTEGRITY_CHECK:
736 2874 : if (sm->ignore)
737 0 : SM_ENTER(EAP, DISCARD);
738 : else
739 2874 : SM_ENTER(EAP, METHOD_RESPONSE);
740 2874 : break;
741 : case EAP_METHOD_REQUEST:
742 2954 : if (sm->m == NULL) {
743 : /*
744 : * This transition is not mentioned in RFC 4137, but it
745 : * is needed to handle cleanly a case where EAP method
746 : * initialization fails.
747 : */
748 0 : SM_ENTER(EAP, FAILURE);
749 0 : break;
750 : }
751 2954 : SM_ENTER(EAP, SEND_REQUEST);
752 2954 : break;
753 : case EAP_METHOD_RESPONSE:
754 : /*
755 : * Note: Mechanism to allow EAP methods to wait while going
756 : * through pending processing is an extension to RFC 4137
757 : * which only defines the transits to SELECT_ACTION and
758 : * METHOD_REQUEST from this METHOD_RESPONSE state.
759 : */
760 3363 : if (sm->methodState == METHOD_END)
761 1374 : SM_ENTER(EAP, SELECT_ACTION);
762 1989 : else if (sm->method_pending == METHOD_PENDING_WAIT) {
763 110 : wpa_printf(MSG_DEBUG, "EAP: Method has pending "
764 : "processing - wait before proceeding to "
765 : "METHOD_REQUEST state");
766 1879 : } else if (sm->method_pending == METHOD_PENDING_CONT) {
767 75 : wpa_printf(MSG_DEBUG, "EAP: Method has completed "
768 : "pending processing - reprocess pending "
769 : "EAP message");
770 75 : sm->method_pending = METHOD_PENDING_NONE;
771 75 : SM_ENTER(EAP, METHOD_RESPONSE);
772 : } else
773 1804 : SM_ENTER(EAP, METHOD_REQUEST);
774 3363 : break;
775 : case EAP_PROPOSE_METHOD:
776 : /*
777 : * Note: Mechanism to allow EAP methods to wait while going
778 : * through pending processing is an extension to RFC 4137
779 : * which only defines the transit to METHOD_REQUEST from this
780 : * PROPOSE_METHOD state.
781 : */
782 1150 : if (sm->method_pending == METHOD_PENDING_WAIT) {
783 0 : wpa_printf(MSG_DEBUG, "EAP: Method has pending "
784 : "processing - wait before proceeding to "
785 : "METHOD_REQUEST state");
786 0 : if (sm->user_eap_method_index > 0)
787 0 : sm->user_eap_method_index--;
788 1150 : } else if (sm->method_pending == METHOD_PENDING_CONT) {
789 0 : wpa_printf(MSG_DEBUG, "EAP: Method has completed "
790 : "pending processing - reprocess pending "
791 : "EAP message");
792 0 : sm->method_pending = METHOD_PENDING_NONE;
793 0 : SM_ENTER(EAP, PROPOSE_METHOD);
794 : } else
795 1150 : SM_ENTER(EAP, METHOD_REQUEST);
796 1150 : break;
797 : case EAP_NAK:
798 70 : SM_ENTER(EAP, SELECT_ACTION);
799 70 : break;
800 : case EAP_SELECT_ACTION:
801 1991 : if (sm->decision == DECISION_FAILURE)
802 251 : SM_ENTER(EAP, FAILURE);
803 1740 : else if (sm->decision == DECISION_SUCCESS)
804 284 : SM_ENTER(EAP, SUCCESS);
805 1456 : else if (sm->decision == DECISION_PASSTHROUGH)
806 306 : SM_ENTER(EAP, INITIALIZE_PASSTHROUGH);
807 : else
808 1150 : SM_ENTER(EAP, PROPOSE_METHOD);
809 1991 : break;
810 : case EAP_TIMEOUT_FAILURE:
811 0 : break;
812 : case EAP_FAILURE:
813 251 : break;
814 : case EAP_SUCCESS:
815 392 : break;
816 :
817 : case EAP_INITIALIZE_PASSTHROUGH:
818 306 : if (sm->currentId == -1)
819 0 : SM_ENTER(EAP, AAA_IDLE);
820 : else
821 306 : SM_ENTER(EAP, AAA_REQUEST);
822 306 : break;
823 : case EAP_IDLE2:
824 3905 : if (sm->eap_if.eapResp)
825 1298 : SM_ENTER(EAP, RECEIVED2);
826 2607 : else if (sm->eap_if.retransWhile == 0)
827 0 : SM_ENTER(EAP, RETRANSMIT2);
828 3905 : break;
829 : case EAP_RETRANSMIT2:
830 0 : if (sm->retransCount > sm->MaxRetrans)
831 0 : SM_ENTER(EAP, TIMEOUT_FAILURE2);
832 : else
833 0 : SM_ENTER(EAP, IDLE2);
834 0 : break;
835 : case EAP_RECEIVED2:
836 1298 : if (sm->rxResp && (sm->respId == sm->currentId))
837 1298 : SM_ENTER(EAP, AAA_REQUEST);
838 : else
839 0 : SM_ENTER(EAP, DISCARD2);
840 1298 : break;
841 : case EAP_DISCARD2:
842 0 : SM_ENTER(EAP, IDLE2);
843 0 : break;
844 : case EAP_SEND_REQUEST2:
845 1301 : SM_ENTER(EAP, IDLE2);
846 1301 : break;
847 : case EAP_AAA_REQUEST:
848 1604 : SM_ENTER(EAP, AAA_IDLE);
849 1604 : break;
850 : case EAP_AAA_RESPONSE:
851 1301 : SM_ENTER(EAP, SEND_REQUEST2);
852 1301 : break;
853 : case EAP_AAA_IDLE:
854 4812 : if (sm->eap_if.aaaFail)
855 46 : SM_ENTER(EAP, FAILURE2);
856 4766 : else if (sm->eap_if.aaaSuccess)
857 252 : SM_ENTER(EAP, SUCCESS2);
858 4514 : else if (sm->eap_if.aaaEapReq)
859 1301 : SM_ENTER(EAP, AAA_RESPONSE);
860 3213 : else if (sm->eap_if.aaaTimeout)
861 0 : SM_ENTER(EAP, TIMEOUT_FAILURE2);
862 4812 : break;
863 : case EAP_TIMEOUT_FAILURE2:
864 0 : break;
865 : case EAP_FAILURE2:
866 46 : break;
867 : case EAP_SUCCESS2:
868 797 : break;
869 : }
870 46287 : }
871 :
872 :
873 4257 : static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
874 : int eapSRTT, int eapRTTVAR,
875 : int methodTimeout)
876 : {
877 : int rto, i;
878 :
879 4257 : if (methodTimeout) {
880 : /*
881 : * EAP method (either internal or through AAA server, provided
882 : * timeout hint. Use that as-is as a timeout for retransmitting
883 : * the EAP request if no response is received.
884 : */
885 955 : wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
886 : "(from EAP method hint)", methodTimeout);
887 955 : return methodTimeout;
888 : }
889 :
890 : /*
891 : * RFC 3748 recommends algorithms described in RFC 2988 for estimation
892 : * of the retransmission timeout. This should be implemented once
893 : * round-trip time measurements are available. For nowm a simple
894 : * backoff mechanism is used instead if there are no EAP method
895 : * specific hints.
896 : *
897 : * SRTT = smoothed round-trip time
898 : * RTTVAR = round-trip time variation
899 : * RTO = retransmission timeout
900 : */
901 :
902 : /*
903 : * RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for
904 : * initial retransmission and then double the RTO to provide back off
905 : * per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3
906 : * modified RTOmax.
907 : */
908 3302 : rto = 3;
909 3302 : for (i = 0; i < retransCount; i++) {
910 0 : rto *= 2;
911 0 : if (rto >= 20) {
912 0 : rto = 20;
913 0 : break;
914 : }
915 : }
916 :
917 3302 : wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
918 : "(from dynamic back off; retransCount=%d)",
919 : rto, retransCount);
920 :
921 3302 : return rto;
922 : }
923 :
924 :
925 4548 : static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
926 : {
927 : const struct eap_hdr *hdr;
928 : size_t plen;
929 :
930 : /* parse rxResp, respId, respMethod */
931 4548 : sm->rxResp = FALSE;
932 4548 : sm->respId = -1;
933 4548 : sm->respMethod = EAP_TYPE_NONE;
934 4548 : sm->respVendor = EAP_VENDOR_IETF;
935 4548 : sm->respVendorMethod = EAP_TYPE_NONE;
936 :
937 4548 : if (resp == NULL || wpabuf_len(resp) < sizeof(*hdr)) {
938 0 : wpa_printf(MSG_DEBUG, "EAP: parseEapResp: invalid resp=%p "
939 : "len=%lu", resp,
940 : resp ? (unsigned long) wpabuf_len(resp) : 0);
941 0 : return;
942 : }
943 :
944 4548 : hdr = wpabuf_head(resp);
945 4548 : plen = be_to_host16(hdr->length);
946 4548 : if (plen > wpabuf_len(resp)) {
947 0 : wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
948 : "(len=%lu plen=%lu)",
949 : (unsigned long) wpabuf_len(resp),
950 : (unsigned long) plen);
951 0 : return;
952 : }
953 :
954 4548 : sm->respId = hdr->identifier;
955 :
956 4548 : if (hdr->code == EAP_CODE_RESPONSE)
957 4548 : sm->rxResp = TRUE;
958 :
959 4548 : if (plen > sizeof(*hdr)) {
960 4548 : u8 *pos = (u8 *) (hdr + 1);
961 4548 : sm->respMethod = *pos++;
962 4548 : if (sm->respMethod == EAP_TYPE_EXPANDED) {
963 995 : if (plen < sizeof(*hdr) + 8) {
964 0 : wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
965 : "expanded EAP-Packet (plen=%lu)",
966 : (unsigned long) plen);
967 0 : return;
968 : }
969 995 : sm->respVendor = WPA_GET_BE24(pos);
970 995 : pos += 3;
971 995 : sm->respVendorMethod = WPA_GET_BE32(pos);
972 : }
973 : }
974 :
975 13644 : wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
976 : "respMethod=%u respVendor=%u respVendorMethod=%u",
977 9096 : sm->rxResp, sm->respId, sm->respMethod, sm->respVendor,
978 : sm->respVendorMethod);
979 : }
980 :
981 :
982 1301 : static int eap_sm_getId(const struct wpabuf *data)
983 : {
984 : const struct eap_hdr *hdr;
985 :
986 1301 : if (data == NULL || wpabuf_len(data) < sizeof(*hdr))
987 0 : return -1;
988 :
989 1301 : hdr = wpabuf_head(data);
990 1301 : wpa_printf(MSG_DEBUG, "EAP: getId: id=%d", hdr->identifier);
991 1301 : return hdr->identifier;
992 : }
993 :
994 :
995 284 : static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id)
996 : {
997 : struct wpabuf *msg;
998 : struct eap_hdr *resp;
999 284 : wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id);
1000 :
1001 284 : msg = wpabuf_alloc(sizeof(*resp));
1002 284 : if (msg == NULL)
1003 0 : return NULL;
1004 284 : resp = wpabuf_put(msg, sizeof(*resp));
1005 284 : resp->code = EAP_CODE_SUCCESS;
1006 284 : resp->identifier = id;
1007 284 : resp->length = host_to_be16(sizeof(*resp));
1008 :
1009 284 : return msg;
1010 : }
1011 :
1012 :
1013 251 : static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id)
1014 : {
1015 : struct wpabuf *msg;
1016 : struct eap_hdr *resp;
1017 251 : wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id);
1018 :
1019 251 : msg = wpabuf_alloc(sizeof(*resp));
1020 251 : if (msg == NULL)
1021 0 : return NULL;
1022 251 : resp = wpabuf_put(msg, sizeof(*resp));
1023 251 : resp->code = EAP_CODE_FAILURE;
1024 251 : resp->identifier = id;
1025 251 : resp->length = host_to_be16(sizeof(*resp));
1026 :
1027 251 : return msg;
1028 : }
1029 :
1030 :
1031 2954 : static int eap_sm_nextId(struct eap_sm *sm, int id)
1032 : {
1033 2954 : if (id < 0) {
1034 : /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a
1035 : * random number */
1036 547 : id = rand() & 0xff;
1037 547 : if (id != sm->lastId)
1038 546 : return id;
1039 : }
1040 2408 : return (id + 1) & 0xff;
1041 : }
1042 :
1043 :
1044 : /**
1045 : * eap_sm_process_nak - Process EAP-Response/Nak
1046 : * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1047 : * @nak_list: Nak list (allowed methods) from the supplicant
1048 : * @len: Length of nak_list in bytes
1049 : *
1050 : * This function is called when EAP-Response/Nak is received from the
1051 : * supplicant. This can happen for both phase 1 and phase 2 authentications.
1052 : */
1053 80 : void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len)
1054 : {
1055 : int i;
1056 : size_t j;
1057 :
1058 80 : if (sm->user == NULL)
1059 80 : return;
1060 :
1061 80 : wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
1062 : "index %d)", sm->user_eap_method_index);
1063 :
1064 80 : wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
1065 80 : (u8 *) sm->user->methods,
1066 : EAP_MAX_METHODS * sizeof(sm->user->methods[0]));
1067 80 : wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
1068 : nak_list, len);
1069 :
1070 80 : i = sm->user_eap_method_index;
1071 1064 : while (i < EAP_MAX_METHODS &&
1072 984 : (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
1073 492 : sm->user->methods[i].method != EAP_TYPE_NONE)) {
1074 412 : if (sm->user->methods[i].vendor != EAP_VENDOR_IETF)
1075 0 : goto not_found;
1076 751 : for (j = 0; j < len; j++) {
1077 412 : if (nak_list[j] == sm->user->methods[i].method) {
1078 73 : break;
1079 : }
1080 : }
1081 :
1082 412 : if (j < len) {
1083 : /* found */
1084 73 : i++;
1085 73 : continue;
1086 : }
1087 :
1088 : not_found:
1089 : /* not found - remove from the list */
1090 339 : if (i + 1 < EAP_MAX_METHODS) {
1091 339 : os_memmove(&sm->user->methods[i],
1092 : &sm->user->methods[i + 1],
1093 : (EAP_MAX_METHODS - i - 1) *
1094 : sizeof(sm->user->methods[0]));
1095 : }
1096 339 : sm->user->methods[EAP_MAX_METHODS - 1].vendor =
1097 : EAP_VENDOR_IETF;
1098 339 : sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
1099 : }
1100 :
1101 80 : wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
1102 80 : (u8 *) sm->user->methods, EAP_MAX_METHODS *
1103 : sizeof(sm->user->methods[0]));
1104 : }
1105 :
1106 :
1107 1444 : static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
1108 : size_t len)
1109 : {
1110 1444 : if (nak_list == NULL || sm == NULL || sm->user == NULL)
1111 1375 : return;
1112 :
1113 69 : if (sm->user->phase2) {
1114 0 : wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user"
1115 : " info was selected - reject");
1116 0 : sm->decision = DECISION_FAILURE;
1117 0 : return;
1118 : }
1119 :
1120 69 : eap_sm_process_nak(sm, nak_list, len);
1121 : }
1122 :
1123 :
1124 1150 : static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
1125 : {
1126 : EapType next;
1127 1150 : int idx = sm->user_eap_method_index;
1128 :
1129 : /* In theory, there should be no problems with starting
1130 : * re-authentication with something else than EAP-Request/Identity and
1131 : * this does indeed work with wpa_supplicant. However, at least Funk
1132 : * Supplicant seemed to ignore re-auth if it skipped
1133 : * EAP-Request/Identity.
1134 : * Re-auth sets currentId == -1, so that can be used here to select
1135 : * whether Identity needs to be requested again. */
1136 1150 : if (sm->identity == NULL || sm->currentId == -1) {
1137 547 : *vendor = EAP_VENDOR_IETF;
1138 547 : next = EAP_TYPE_IDENTITY;
1139 547 : sm->update_user = TRUE;
1140 1206 : } else if (sm->user && idx < EAP_MAX_METHODS &&
1141 999 : (sm->user->methods[idx].vendor != EAP_VENDOR_IETF ||
1142 396 : sm->user->methods[idx].method != EAP_TYPE_NONE)) {
1143 603 : *vendor = sm->user->methods[idx].vendor;
1144 603 : next = sm->user->methods[idx].method;
1145 603 : sm->user_eap_method_index++;
1146 : } else {
1147 0 : *vendor = EAP_VENDOR_IETF;
1148 0 : next = EAP_TYPE_NONE;
1149 : }
1150 1150 : wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d",
1151 : *vendor, next);
1152 1150 : return next;
1153 : }
1154 :
1155 :
1156 1991 : static int eap_sm_Policy_getDecision(struct eap_sm *sm)
1157 : {
1158 1991 : if (!sm->eap_server && sm->identity && !sm->start_reauth) {
1159 306 : wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH");
1160 306 : return DECISION_PASSTHROUGH;
1161 : }
1162 :
1163 2212 : if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY &&
1164 527 : sm->m->isSuccess(sm, sm->eap_method_priv)) {
1165 284 : wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
1166 : "SUCCESS");
1167 284 : sm->update_user = TRUE;
1168 284 : return DECISION_SUCCESS;
1169 : }
1170 :
1171 2185 : if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) &&
1172 784 : !sm->m->isSuccess(sm, sm->eap_method_priv)) {
1173 243 : wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
1174 : "FAILURE");
1175 243 : sm->update_user = TRUE;
1176 243 : return DECISION_FAILURE;
1177 : }
1178 :
1179 1699 : if ((sm->user == NULL || sm->update_user) && sm->identity &&
1180 541 : !sm->start_reauth) {
1181 : /*
1182 : * Allow Identity method to be started once to allow identity
1183 : * selection hint to be sent from the authentication server,
1184 : * but prevent a loop of Identity requests by only allowing
1185 : * this to happen once.
1186 : */
1187 541 : int id_req = 0;
1188 545 : if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY &&
1189 8 : sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
1190 4 : sm->user->methods[0].method == EAP_TYPE_IDENTITY)
1191 0 : id_req = 1;
1192 541 : if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) {
1193 0 : wpa_printf(MSG_DEBUG, "EAP: getDecision: user not "
1194 : "found from database -> FAILURE");
1195 0 : return DECISION_FAILURE;
1196 : }
1197 541 : if (id_req && sm->user &&
1198 0 : sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
1199 0 : sm->user->methods[0].method == EAP_TYPE_IDENTITY) {
1200 0 : wpa_printf(MSG_DEBUG, "EAP: getDecision: stop "
1201 : "identity request loop -> FAILURE");
1202 0 : sm->update_user = TRUE;
1203 0 : return DECISION_FAILURE;
1204 : }
1205 541 : sm->update_user = FALSE;
1206 : }
1207 1158 : sm->start_reauth = FALSE;
1208 :
1209 1773 : if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
1210 615 : (sm->user->methods[sm->user_eap_method_index].vendor !=
1211 408 : EAP_VENDOR_IETF ||
1212 408 : sm->user->methods[sm->user_eap_method_index].method !=
1213 : EAP_TYPE_NONE)) {
1214 607 : wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
1215 : "available -> CONTINUE");
1216 607 : return DECISION_CONTINUE;
1217 : }
1218 :
1219 551 : if (sm->identity == NULL || sm->currentId == -1) {
1220 543 : wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
1221 : "yet -> CONTINUE");
1222 543 : return DECISION_CONTINUE;
1223 : }
1224 :
1225 8 : wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> "
1226 : "FAILURE");
1227 8 : return DECISION_FAILURE;
1228 : }
1229 :
1230 :
1231 304 : static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
1232 : {
1233 304 : return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
1234 : }
1235 :
1236 :
1237 : /**
1238 : * eap_server_sm_step - Step EAP server state machine
1239 : * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1240 : * Returns: 1 if EAP state was changed or 0 if not
1241 : *
1242 : * This function advances EAP state machine to a new state to match with the
1243 : * current variables. This should be called whenever variables used by the EAP
1244 : * state machine have changed.
1245 : */
1246 14183 : int eap_server_sm_step(struct eap_sm *sm)
1247 : {
1248 14183 : int res = 0;
1249 : do {
1250 46287 : sm->changed = FALSE;
1251 46287 : SM_STEP_RUN(EAP);
1252 46287 : if (sm->changed)
1253 32104 : res = 1;
1254 46287 : } while (sm->changed);
1255 14183 : return res;
1256 : }
1257 :
1258 :
1259 1541 : static void eap_user_free(struct eap_user *user)
1260 : {
1261 1541 : if (user == NULL)
1262 2336 : return;
1263 746 : os_free(user->password);
1264 746 : user->password = NULL;
1265 746 : os_free(user);
1266 : }
1267 :
1268 :
1269 : /**
1270 : * eap_server_sm_init - Allocate and initialize EAP server state machine
1271 : * @eapol_ctx: Context data to be used with eapol_cb calls
1272 : * @eapol_cb: Pointer to EAPOL callback functions
1273 : * @conf: EAP configuration
1274 : * Returns: Pointer to the allocated EAP state machine or %NULL on failure
1275 : *
1276 : * This function allocates and initializes an EAP state machine.
1277 : */
1278 794 : struct eap_sm * eap_server_sm_init(void *eapol_ctx,
1279 : struct eapol_callbacks *eapol_cb,
1280 : struct eap_config *conf)
1281 : {
1282 : struct eap_sm *sm;
1283 :
1284 794 : sm = os_zalloc(sizeof(*sm));
1285 794 : if (sm == NULL)
1286 0 : return NULL;
1287 794 : sm->eapol_ctx = eapol_ctx;
1288 794 : sm->eapol_cb = eapol_cb;
1289 794 : sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */
1290 794 : sm->ssl_ctx = conf->ssl_ctx;
1291 794 : sm->msg_ctx = conf->msg_ctx;
1292 794 : sm->eap_sim_db_priv = conf->eap_sim_db_priv;
1293 794 : sm->backend_auth = conf->backend_auth;
1294 794 : sm->eap_server = conf->eap_server;
1295 794 : if (conf->pac_opaque_encr_key) {
1296 304 : sm->pac_opaque_encr_key = os_malloc(16);
1297 304 : if (sm->pac_opaque_encr_key) {
1298 304 : os_memcpy(sm->pac_opaque_encr_key,
1299 : conf->pac_opaque_encr_key, 16);
1300 : }
1301 : }
1302 794 : if (conf->eap_fast_a_id) {
1303 304 : sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
1304 304 : if (sm->eap_fast_a_id) {
1305 304 : os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id,
1306 : conf->eap_fast_a_id_len);
1307 304 : sm->eap_fast_a_id_len = conf->eap_fast_a_id_len;
1308 : }
1309 : }
1310 794 : if (conf->eap_fast_a_id_info)
1311 304 : sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
1312 794 : sm->eap_fast_prov = conf->eap_fast_prov;
1313 794 : sm->pac_key_lifetime = conf->pac_key_lifetime;
1314 794 : sm->pac_key_refresh_time = conf->pac_key_refresh_time;
1315 794 : sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
1316 794 : sm->tnc = conf->tnc;
1317 794 : sm->wps = conf->wps;
1318 794 : if (conf->assoc_wps_ie)
1319 200 : sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie);
1320 794 : if (conf->assoc_p2p_ie)
1321 108 : sm->assoc_p2p_ie = wpabuf_dup(conf->assoc_p2p_ie);
1322 794 : if (conf->peer_addr)
1323 489 : os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN);
1324 794 : sm->fragment_size = conf->fragment_size;
1325 794 : sm->pwd_group = conf->pwd_group;
1326 794 : sm->pbc_in_m1 = conf->pbc_in_m1;
1327 794 : sm->server_id = conf->server_id;
1328 794 : sm->server_id_len = conf->server_id_len;
1329 :
1330 : #ifdef CONFIG_TESTING_OPTIONS
1331 794 : sm->tls_test_flags = conf->tls_test_flags;
1332 : #endif /* CONFIG_TESTING_OPTIONS */
1333 :
1334 794 : wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
1335 :
1336 794 : return sm;
1337 : }
1338 :
1339 :
1340 : /**
1341 : * eap_server_sm_deinit - Deinitialize and free an EAP server state machine
1342 : * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1343 : *
1344 : * This function deinitializes EAP state machine and frees all allocated
1345 : * resources.
1346 : */
1347 794 : void eap_server_sm_deinit(struct eap_sm *sm)
1348 : {
1349 794 : if (sm == NULL)
1350 794 : return;
1351 794 : wpa_printf(MSG_DEBUG, "EAP: Server state machine removed");
1352 794 : if (sm->m && sm->eap_method_priv)
1353 773 : sm->m->reset(sm, sm->eap_method_priv);
1354 794 : wpabuf_free(sm->eap_if.eapReqData);
1355 794 : os_free(sm->eap_if.eapKeyData);
1356 794 : wpabuf_free(sm->lastReqData);
1357 794 : wpabuf_free(sm->eap_if.eapRespData);
1358 794 : os_free(sm->identity);
1359 794 : os_free(sm->pac_opaque_encr_key);
1360 794 : os_free(sm->eap_fast_a_id);
1361 794 : os_free(sm->eap_fast_a_id_info);
1362 794 : wpabuf_free(sm->eap_if.aaaEapReqData);
1363 794 : wpabuf_free(sm->eap_if.aaaEapRespData);
1364 794 : os_free(sm->eap_if.aaaEapKeyData);
1365 794 : eap_user_free(sm->user);
1366 794 : wpabuf_free(sm->assoc_wps_ie);
1367 794 : wpabuf_free(sm->assoc_p2p_ie);
1368 794 : os_free(sm);
1369 : }
1370 :
1371 :
1372 : /**
1373 : * eap_sm_notify_cached - Notify EAP state machine of cached PMK
1374 : * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1375 : *
1376 : * This function is called when PMKSA caching is used to skip EAP
1377 : * authentication.
1378 : */
1379 13 : void eap_sm_notify_cached(struct eap_sm *sm)
1380 : {
1381 13 : if (sm == NULL)
1382 13 : return;
1383 :
1384 13 : sm->EAP_state = EAP_SUCCESS;
1385 : }
1386 :
1387 :
1388 : /**
1389 : * eap_sm_pending_cb - EAP state machine callback for a pending EAP request
1390 : * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1391 : *
1392 : * This function is called when data for a pending EAP-Request is received.
1393 : */
1394 75 : void eap_sm_pending_cb(struct eap_sm *sm)
1395 : {
1396 75 : if (sm == NULL)
1397 75 : return;
1398 75 : wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received");
1399 75 : if (sm->method_pending == METHOD_PENDING_WAIT)
1400 75 : sm->method_pending = METHOD_PENDING_CONT;
1401 : }
1402 :
1403 :
1404 : /**
1405 : * eap_sm_method_pending - Query whether EAP method is waiting for pending data
1406 : * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1407 : * Returns: 1 if method is waiting for pending data or 0 if not
1408 : */
1409 45 : int eap_sm_method_pending(struct eap_sm *sm)
1410 : {
1411 45 : if (sm == NULL)
1412 0 : return 0;
1413 45 : return sm->method_pending == METHOD_PENDING_WAIT;
1414 : }
1415 :
1416 :
1417 : /**
1418 : * eap_get_identity - Get the user identity (from EAP-Response/Identity)
1419 : * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1420 : * @len: Buffer for returning identity length
1421 : * Returns: Pointer to the user identity or %NULL if not available
1422 : */
1423 306 : const u8 * eap_get_identity(struct eap_sm *sm, size_t *len)
1424 : {
1425 306 : *len = sm->identity_len;
1426 306 : return sm->identity;
1427 : }
1428 :
1429 :
1430 : /**
1431 : * eap_get_interface - Get pointer to EAP-EAPOL interface data
1432 : * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1433 : * Returns: Pointer to the EAP-EAPOL interface data
1434 : */
1435 794 : struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm)
1436 : {
1437 794 : return &sm->eap_if;
1438 : }
1439 :
1440 :
1441 : /**
1442 : * eap_server_clear_identity - Clear EAP identity information
1443 : * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1444 : *
1445 : * This function can be used to clear the EAP identity information in the EAP
1446 : * server context. This allows the EAP/Identity method to be used again after
1447 : * EAPOL-Start or EAPOL-Logoff.
1448 : */
1449 85 : void eap_server_clear_identity(struct eap_sm *sm)
1450 : {
1451 85 : os_free(sm->identity);
1452 85 : sm->identity = NULL;
1453 85 : }
|