LCOV - code coverage report
Current view: top level - src/eap_server - eap_server.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1401264779 Lines: 602 741 81.2 %
Date: 2014-05-28 Functions: 50 55 90.9 %

          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 : }

Generated by: LCOV version 1.10