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 1443382998 Lines: 916 1054 86.9 %
Date: 2015-09-27 Functions: 63 65 96.9 %

          Line data    Source code
       1             : /*
       2             :  * hostapd / EAP Full Authenticator state machine (RFC 4137)
       3             :  * Copyright (c) 2004-2014, 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 "crypto/sha256.h"
      19             : #include "eap_i.h"
      20             : #include "state_machine.h"
      21             : #include "common/wpa_ctrl.h"
      22             : 
      23             : #define STATE_MACHINE_DATA struct eap_sm
      24             : #define STATE_MACHINE_DEBUG_PREFIX "EAP"
      25             : 
      26             : #define EAP_MAX_AUTH_ROUNDS 50
      27             : 
      28             : static void eap_user_free(struct eap_user *user);
      29             : 
      30             : 
      31             : /* EAP state machines are described in RFC 4137 */
      32             : 
      33             : static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
      34             :                                    int eapSRTT, int eapRTTVAR,
      35             :                                    int methodTimeout);
      36             : static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp);
      37             : static int eap_sm_getId(const struct wpabuf *data);
      38             : static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id);
      39             : static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id);
      40             : static int eap_sm_nextId(struct eap_sm *sm, int id);
      41             : static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
      42             :                                  size_t len);
      43             : static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor);
      44             : static int eap_sm_Policy_getDecision(struct eap_sm *sm);
      45             : static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
      46             : 
      47             : 
      48        1685 : static int eap_get_erp_send_reauth_start(struct eap_sm *sm)
      49             : {
      50        1685 :         if (sm->eapol_cb->get_erp_send_reauth_start)
      51        1669 :                 return sm->eapol_cb->get_erp_send_reauth_start(sm->eapol_ctx);
      52          16 :         return 0;
      53             : }
      54             : 
      55             : 
      56          60 : static const char * eap_get_erp_domain(struct eap_sm *sm)
      57             : {
      58          60 :         if (sm->eapol_cb->get_erp_domain)
      59          60 :                 return sm->eapol_cb->get_erp_domain(sm->eapol_ctx);
      60           0 :         return NULL;
      61             : }
      62             : 
      63             : 
      64             : #ifdef CONFIG_ERP
      65             : 
      66          21 : static struct eap_server_erp_key * eap_erp_get_key(struct eap_sm *sm,
      67             :                                                    const char *keyname)
      68             : {
      69          21 :         if (sm->eapol_cb->erp_get_key)
      70          21 :                 return sm->eapol_cb->erp_get_key(sm->eapol_ctx, keyname);
      71           0 :         return NULL;
      72             : }
      73             : 
      74             : 
      75          19 : static int eap_erp_add_key(struct eap_sm *sm, struct eap_server_erp_key *erp)
      76             : {
      77          19 :         if (sm->eapol_cb->erp_add_key)
      78          19 :                 return sm->eapol_cb->erp_add_key(sm->eapol_ctx, erp);
      79           0 :         return -1;
      80             : }
      81             : 
      82             : #endif /* CONFIG_ERP */
      83             : 
      84             : 
      85          41 : static struct wpabuf * eap_sm_buildInitiateReauthStart(struct eap_sm *sm,
      86             :                                                        u8 id)
      87             : {
      88             :         const char *domain;
      89          41 :         size_t plen = 1;
      90             :         struct wpabuf *msg;
      91          41 :         size_t domain_len = 0;
      92             : 
      93          41 :         domain = eap_get_erp_domain(sm);
      94          41 :         if (domain) {
      95          41 :                 domain_len = os_strlen(domain);
      96          41 :                 plen += 2 + domain_len;
      97             :         }
      98             : 
      99          41 :         msg = eap_msg_alloc(EAP_VENDOR_IETF,
     100             :                             (EapType) EAP_ERP_TYPE_REAUTH_START, plen,
     101             :                             EAP_CODE_INITIATE, id);
     102          41 :         if (msg == NULL)
     103           0 :                 return NULL;
     104          41 :         wpabuf_put_u8(msg, 0); /* Reserved */
     105          41 :         if (domain) {
     106             :                 /* Domain name TLV */
     107          41 :                 wpabuf_put_u8(msg, EAP_ERP_TLV_DOMAIN_NAME);
     108          41 :                 wpabuf_put_u8(msg, domain_len);
     109          41 :                 wpabuf_put_data(msg, domain, domain_len);
     110             :         }
     111             : 
     112          41 :         return msg;
     113             : }
     114             : 
     115             : 
     116       17116 : static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src)
     117             : {
     118       17116 :         if (src == NULL)
     119           4 :                 return -1;
     120             : 
     121       17112 :         wpabuf_free(*dst);
     122       17112 :         *dst = wpabuf_dup(src);
     123       17112 :         return *dst ? 0 : -1;
     124             : }
     125             : 
     126             : 
     127         653 : static int eap_copy_data(u8 **dst, size_t *dst_len,
     128             :                          const u8 *src, size_t src_len)
     129             : {
     130         653 :         if (src == NULL)
     131           0 :                 return -1;
     132             : 
     133         653 :         os_free(*dst);
     134         653 :         *dst = os_malloc(src_len);
     135         653 :         if (*dst) {
     136         652 :                 os_memcpy(*dst, src, src_len);
     137         652 :                 *dst_len = src_len;
     138         652 :                 return 0;
     139             :         } else {
     140           1 :                 *dst_len = 0;
     141           1 :                 return -1;
     142             :         }
     143             : }
     144             : 
     145             : #define EAP_COPY(dst, src) \
     146             :         eap_copy_data((dst), (dst ## Len), (src), (src ## Len))
     147             : 
     148             : 
     149             : /**
     150             :  * eap_user_get - Fetch user information from the database
     151             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
     152             :  * @identity: Identity (User-Name) of the user
     153             :  * @identity_len: Length of identity in bytes
     154             :  * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user
     155             :  * Returns: 0 on success, or -1 on failure
     156             :  *
     157             :  * This function is used to fetch user information for EAP. The user will be
     158             :  * selected based on the specified identity. sm->user and
     159             :  * sm->user_eap_method_index are updated for the new user when a matching user
     160             :  * is found. sm->user can be used to get user information (e.g., password).
     161             :  */
     162        1852 : int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
     163             :                  int phase2)
     164             : {
     165             :         struct eap_user *user;
     166             : 
     167        3704 :         if (sm == NULL || sm->eapol_cb == NULL ||
     168        1852 :             sm->eapol_cb->get_eap_user == NULL)
     169           0 :                 return -1;
     170             : 
     171        1852 :         eap_user_free(sm->user);
     172        1852 :         sm->user = NULL;
     173             : 
     174        1852 :         user = os_zalloc(sizeof(*user));
     175        1852 :         if (user == NULL)
     176           3 :             return -1;
     177             : 
     178        1849 :         if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity,
     179             :                                        identity_len, phase2, user) != 0) {
     180           5 :                 eap_user_free(user);
     181           5 :                 return -1;
     182             :         }
     183             : 
     184        1844 :         sm->user = user;
     185        1844 :         sm->user_eap_method_index = 0;
     186             : 
     187        1844 :         return 0;
     188             : }
     189             : 
     190             : 
     191        5951 : void eap_log_msg(struct eap_sm *sm, const char *fmt, ...)
     192             : {
     193             :         va_list ap;
     194             :         char *buf;
     195             :         int buflen;
     196             : 
     197        5951 :         if (sm == NULL || sm->eapol_cb == NULL || sm->eapol_cb->log_msg == NULL)
     198        8088 :                 return;
     199             : 
     200        1907 :         va_start(ap, fmt);
     201        1907 :         buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
     202        1907 :         va_end(ap);
     203             : 
     204        1907 :         buf = os_malloc(buflen);
     205        1907 :         if (buf == NULL)
     206           0 :                 return;
     207        1907 :         va_start(ap, fmt);
     208        1907 :         vsnprintf(buf, buflen, fmt, ap);
     209        1907 :         va_end(ap);
     210             : 
     211        1907 :         sm->eapol_cb->log_msg(sm->eapol_ctx, buf);
     212             : 
     213        1907 :         os_free(buf);
     214             : }
     215             : 
     216             : 
     217        2852 : SM_STATE(EAP, DISABLED)
     218             : {
     219        2852 :         SM_ENTRY(EAP, DISABLED);
     220        2852 :         sm->num_rounds = 0;
     221        2852 : }
     222             : 
     223             : 
     224        2530 : SM_STATE(EAP, INITIALIZE)
     225             : {
     226        2530 :         SM_ENTRY(EAP, INITIALIZE);
     227             : 
     228        2530 :         if (sm->eap_if.eapRestart && !sm->eap_server && sm->identity) {
     229             :                 /*
     230             :                  * Need to allow internal Identity method to be used instead
     231             :                  * of passthrough at the beginning of reauthentication.
     232             :                  */
     233          60 :                 eap_server_clear_identity(sm);
     234             :         }
     235             : 
     236        2530 :         sm->try_initiate_reauth = FALSE;
     237        2530 :         sm->currentId = -1;
     238        2530 :         sm->eap_if.eapSuccess = FALSE;
     239        2530 :         sm->eap_if.eapFail = FALSE;
     240        2530 :         sm->eap_if.eapTimeout = FALSE;
     241        2530 :         bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
     242        2530 :         sm->eap_if.eapKeyData = NULL;
     243        2530 :         sm->eap_if.eapKeyDataLen = 0;
     244        2530 :         os_free(sm->eap_if.eapSessionId);
     245        2530 :         sm->eap_if.eapSessionId = NULL;
     246        2530 :         sm->eap_if.eapSessionIdLen = 0;
     247        2530 :         sm->eap_if.eapKeyAvailable = FALSE;
     248        2530 :         sm->eap_if.eapRestart = FALSE;
     249             : 
     250             :         /*
     251             :          * This is not defined in RFC 4137, but method state needs to be
     252             :          * reseted here so that it does not remain in success state when
     253             :          * re-authentication starts.
     254             :          */
     255        2530 :         if (sm->m && sm->eap_method_priv) {
     256         196 :                 sm->m->reset(sm, sm->eap_method_priv);
     257         196 :                 sm->eap_method_priv = NULL;
     258             :         }
     259        2530 :         sm->m = NULL;
     260        2530 :         sm->user_eap_method_index = 0;
     261             : 
     262        2530 :         if (sm->backend_auth) {
     263         807 :                 sm->currentMethod = EAP_TYPE_NONE;
     264             :                 /* parse rxResp, respId, respMethod */
     265         807 :                 eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
     266         807 :                 if (sm->rxResp) {
     267         791 :                         sm->currentId = sm->respId;
     268             :                 }
     269             :         }
     270        2530 :         sm->num_rounds = 0;
     271        2530 :         sm->method_pending = METHOD_PENDING_NONE;
     272             : 
     273       15180 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
     274       15180 :                 MACSTR, MAC2STR(sm->peer_addr));
     275        2530 : }
     276             : 
     277             : 
     278         791 : SM_STATE(EAP, PICK_UP_METHOD)
     279             : {
     280         791 :         SM_ENTRY(EAP, PICK_UP_METHOD);
     281             : 
     282         791 :         if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) {
     283         791 :                 sm->currentMethod = sm->respMethod;
     284         791 :                 if (sm->m && sm->eap_method_priv) {
     285           0 :                         sm->m->reset(sm, sm->eap_method_priv);
     286           0 :                         sm->eap_method_priv = NULL;
     287             :                 }
     288         791 :                 sm->m = eap_server_get_eap_method(EAP_VENDOR_IETF,
     289             :                                                   sm->currentMethod);
     290         791 :                 if (sm->m && sm->m->initPickUp) {
     291         791 :                         sm->eap_method_priv = sm->m->initPickUp(sm);
     292        1582 :                         if (sm->eap_method_priv == NULL) {
     293           0 :                                 wpa_printf(MSG_DEBUG, "EAP: Failed to "
     294             :                                            "initialize EAP method %d",
     295           0 :                                            sm->currentMethod);
     296           0 :                                 sm->m = NULL;
     297           0 :                                 sm->currentMethod = EAP_TYPE_NONE;
     298             :                         }
     299             :                 } else {
     300           0 :                         sm->m = NULL;
     301           0 :                         sm->currentMethod = EAP_TYPE_NONE;
     302             :                 }
     303             :         }
     304             : 
     305         791 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
     306         791 :                 "method=%u", sm->currentMethod);
     307         791 : }
     308             : 
     309             : 
     310        6632 : SM_STATE(EAP, IDLE)
     311             : {
     312        6632 :         SM_ENTRY(EAP, IDLE);
     313             : 
     314        6632 :         sm->eap_if.retransWhile = eap_sm_calculateTimeout(
     315             :                 sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR,
     316             :                 sm->methodTimeout);
     317        6632 : }
     318             : 
     319             : 
     320           2 : SM_STATE(EAP, RETRANSMIT)
     321             : {
     322           2 :         SM_ENTRY(EAP, RETRANSMIT);
     323             : 
     324           2 :         sm->retransCount++;
     325           2 :         if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
     326           2 :                 if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
     327           2 :                         sm->eap_if.eapReq = TRUE;
     328             :         }
     329           2 : }
     330             : 
     331             : 
     332        6471 : SM_STATE(EAP, RECEIVED)
     333             : {
     334        6471 :         SM_ENTRY(EAP, RECEIVED);
     335             : 
     336             :         /* parse rxResp, respId, respMethod */
     337        6471 :         eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
     338        6471 :         sm->num_rounds++;
     339        6471 : }
     340             : 
     341             : 
     342           4 : SM_STATE(EAP, DISCARD)
     343             : {
     344           4 :         SM_ENTRY(EAP, DISCARD);
     345           4 :         sm->eap_if.eapResp = FALSE;
     346           4 :         sm->eap_if.eapNoReq = TRUE;
     347           4 : }
     348             : 
     349             : 
     350        6646 : SM_STATE(EAP, SEND_REQUEST)
     351             : {
     352        6646 :         SM_ENTRY(EAP, SEND_REQUEST);
     353             : 
     354        6646 :         sm->retransCount = 0;
     355        6646 :         if (sm->eap_if.eapReqData) {
     356        6627 :                 if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
     357             :                 {
     358        6623 :                         sm->eap_if.eapResp = FALSE;
     359        6623 :                         sm->eap_if.eapReq = TRUE;
     360             :                 } else {
     361           4 :                         sm->eap_if.eapResp = FALSE;
     362           4 :                         sm->eap_if.eapReq = FALSE;
     363             :                 }
     364             :         } else {
     365          19 :                 wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData");
     366          19 :                 sm->eap_if.eapResp = FALSE;
     367          19 :                 sm->eap_if.eapReq = FALSE;
     368          19 :                 sm->eap_if.eapNoReq = TRUE;
     369             :         }
     370        6646 : }
     371             : 
     372             : 
     373        6316 : SM_STATE(EAP, INTEGRITY_CHECK)
     374             : {
     375        6316 :         SM_ENTRY(EAP, INTEGRITY_CHECK);
     376             : 
     377        6316 :         if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) {
     378           0 :                 sm->ignore = TRUE;
     379        6316 :                 return;
     380             :         }
     381             : 
     382        6316 :         if (sm->m->check) {
     383        6316 :                 sm->ignore = sm->m->check(sm, sm->eap_method_priv,
     384             :                                           sm->eap_if.eapRespData);
     385             :         }
     386             : }
     387             : 
     388             : 
     389        6608 : SM_STATE(EAP, METHOD_REQUEST)
     390             : {
     391        6608 :         SM_ENTRY(EAP, METHOD_REQUEST);
     392             : 
     393        6608 :         if (sm->m == NULL) {
     394           3 :                 wpa_printf(MSG_DEBUG, "EAP: method not initialized");
     395        6611 :                 return;
     396             :         }
     397             : 
     398        6605 :         sm->currentId = eap_sm_nextId(sm, sm->currentId);
     399        6605 :         wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d",
     400             :                    sm->currentId);
     401        6605 :         sm->lastId = sm->currentId;
     402        6605 :         wpabuf_free(sm->eap_if.eapReqData);
     403       13210 :         sm->eap_if.eapReqData = sm->m->buildReq(sm, sm->eap_method_priv,
     404        6605 :                                                 sm->currentId);
     405        6605 :         if (sm->m->getTimeout)
     406        1845 :                 sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv);
     407             :         else
     408        4760 :                 sm->methodTimeout = 0;
     409             : }
     410             : 
     411             : 
     412          19 : static void eap_server_erp_init(struct eap_sm *sm)
     413             : {
     414             : #ifdef CONFIG_ERP
     415          19 :         u8 *emsk = NULL;
     416          19 :         size_t emsk_len = 0;
     417             :         u8 EMSKname[EAP_EMSK_NAME_LEN];
     418             :         u8 len[2];
     419             :         const char *domain;
     420             :         size_t domain_len, nai_buf_len;
     421          19 :         struct eap_server_erp_key *erp = NULL;
     422             :         int pos;
     423             : 
     424          19 :         domain = eap_get_erp_domain(sm);
     425          19 :         if (!domain)
     426           0 :                 return;
     427             : 
     428          19 :         domain_len = os_strlen(domain);
     429             : 
     430          19 :         nai_buf_len = 2 * EAP_EMSK_NAME_LEN + 1 + domain_len;
     431          19 :         if (nai_buf_len > 253) {
     432             :                 /*
     433             :                  * keyName-NAI has a maximum length of 253 octet to fit in
     434             :                  * RADIUS attributes.
     435             :                  */
     436           0 :                 wpa_printf(MSG_DEBUG,
     437             :                            "EAP: Too long realm for ERP keyName-NAI maximum length");
     438           0 :                 return;
     439             :         }
     440          19 :         nai_buf_len++; /* null termination */
     441          19 :         erp = os_zalloc(sizeof(*erp) + nai_buf_len);
     442          19 :         if (erp == NULL)
     443           0 :                 goto fail;
     444          19 :         erp->recv_seq = (u32) -1;
     445             : 
     446          19 :         emsk = sm->m->get_emsk(sm, sm->eap_method_priv, &emsk_len);
     447          19 :         if (!emsk || emsk_len == 0 || emsk_len > ERP_MAX_KEY_LEN) {
     448           0 :                 wpa_printf(MSG_DEBUG,
     449             :                            "EAP: No suitable EMSK available for ERP");
     450           0 :                 goto fail;
     451             :         }
     452             : 
     453          19 :         wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
     454             : 
     455          19 :         WPA_PUT_BE16(len, 8);
     456          19 :         if (hmac_sha256_kdf(sm->eap_if.eapSessionId, sm->eap_if.eapSessionIdLen,
     457             :                             "EMSK", len, sizeof(len),
     458             :                             EMSKname, EAP_EMSK_NAME_LEN) < 0) {
     459           0 :                 wpa_printf(MSG_DEBUG, "EAP: Could not derive EMSKname");
     460           0 :                 goto fail;
     461             :         }
     462          19 :         wpa_hexdump(MSG_DEBUG, "EAP: EMSKname", EMSKname, EAP_EMSK_NAME_LEN);
     463             : 
     464          19 :         pos = wpa_snprintf_hex(erp->keyname_nai, nai_buf_len,
     465             :                                EMSKname, EAP_EMSK_NAME_LEN);
     466          19 :         erp->keyname_nai[pos] = '@';
     467          19 :         os_memcpy(&erp->keyname_nai[pos + 1], domain, domain_len);
     468             : 
     469          19 :         WPA_PUT_BE16(len, emsk_len);
     470          38 :         if (hmac_sha256_kdf(emsk, emsk_len,
     471             :                             "EAP Re-authentication Root Key@ietf.org",
     472          19 :                             len, sizeof(len), erp->rRK, emsk_len) < 0) {
     473           0 :                 wpa_printf(MSG_DEBUG, "EAP: Could not derive rRK for ERP");
     474           0 :                 goto fail;
     475             :         }
     476          19 :         erp->rRK_len = emsk_len;
     477          19 :         wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
     478             : 
     479          38 :         if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
     480             :                             "EAP Re-authentication Integrity Key@ietf.org",
     481          19 :                             len, sizeof(len), erp->rIK, erp->rRK_len) < 0) {
     482           0 :                 wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
     483           0 :                 goto fail;
     484             :         }
     485          19 :         erp->rIK_len = erp->rRK_len;
     486          19 :         wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rIK", erp->rIK, erp->rIK_len);
     487             : 
     488          19 :         if (eap_erp_add_key(sm, erp) == 0) {
     489          19 :                 wpa_printf(MSG_DEBUG, "EAP: Stored ERP keys %s",
     490          19 :                            erp->keyname_nai);
     491          19 :                 erp = NULL;
     492             :         }
     493             : 
     494             : fail:
     495          19 :         bin_clear_free(emsk, emsk_len);
     496          19 :         bin_clear_free(erp, sizeof(*erp));
     497             : #endif /* CONFIG_ERP */
     498             : }
     499             : 
     500             : 
     501        7243 : SM_STATE(EAP, METHOD_RESPONSE)
     502             : {
     503        7243 :         SM_ENTRY(EAP, METHOD_RESPONSE);
     504             : 
     505        7243 :         if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1))
     506        7243 :                 return;
     507             : 
     508        7243 :         sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData);
     509        7243 :         if (sm->m->isDone(sm, sm->eap_method_priv)) {
     510        3700 :                 eap_sm_Policy_update(sm, NULL, 0);
     511        3700 :                 bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
     512        3700 :                 if (sm->m->getKey) {
     513         869 :                         sm->eap_if.eapKeyData = sm->m->getKey(
     514             :                                 sm, sm->eap_method_priv,
     515             :                                 &sm->eap_if.eapKeyDataLen);
     516             :                 } else {
     517        2831 :                         sm->eap_if.eapKeyData = NULL;
     518        2831 :                         sm->eap_if.eapKeyDataLen = 0;
     519             :                 }
     520        3700 :                 os_free(sm->eap_if.eapSessionId);
     521        3700 :                 sm->eap_if.eapSessionId = NULL;
     522        3700 :                 if (sm->m->getSessionId) {
     523         861 :                         sm->eap_if.eapSessionId = sm->m->getSessionId(
     524             :                                 sm, sm->eap_method_priv,
     525             :                                 &sm->eap_if.eapSessionIdLen);
     526        1722 :                         wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
     527         861 :                                     sm->eap_if.eapSessionId,
     528             :                                     sm->eap_if.eapSessionIdLen);
     529             :                 }
     530        3700 :                 if (sm->erp && sm->m->get_emsk && sm->eap_if.eapSessionId)
     531          19 :                         eap_server_erp_init(sm);
     532        3700 :                 sm->methodState = METHOD_END;
     533             :         } else {
     534        3543 :                 sm->methodState = METHOD_CONTINUE;
     535             :         }
     536             : }
     537             : 
     538             : 
     539        3201 : SM_STATE(EAP, PROPOSE_METHOD)
     540             : {
     541             :         int vendor;
     542             :         EapType type;
     543             : 
     544        3201 :         SM_ENTRY(EAP, PROPOSE_METHOD);
     545             : 
     546        3201 :         sm->try_initiate_reauth = FALSE;
     547             : try_another_method:
     548        3206 :         type = eap_sm_Policy_getNextMethod(sm, &vendor);
     549        3206 :         if (vendor == EAP_VENDOR_IETF)
     550        2737 :                 sm->currentMethod = type;
     551             :         else
     552         469 :                 sm->currentMethod = EAP_TYPE_EXPANDED;
     553        3206 :         if (sm->m && sm->eap_method_priv) {
     554        1402 :                 sm->m->reset(sm, sm->eap_method_priv);
     555        1402 :                 sm->eap_method_priv = NULL;
     556             :         }
     557        3206 :         sm->m = eap_server_get_eap_method(vendor, type);
     558        3206 :         if (sm->m) {
     559        3203 :                 sm->eap_method_priv = sm->m->init(sm);
     560        3203 :                 if (sm->eap_method_priv == NULL) {
     561           5 :                         wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP "
     562           5 :                                    "method %d", sm->currentMethod);
     563           5 :                         sm->m = NULL;
     564           5 :                         sm->currentMethod = EAP_TYPE_NONE;
     565           5 :                         goto try_another_method;
     566             :                 }
     567             :         }
     568        3201 :         if (sm->m == NULL) {
     569           3 :                 wpa_printf(MSG_DEBUG, "EAP: Could not find suitable EAP method");
     570           3 :                 eap_log_msg(sm, "Could not find suitable EAP method");
     571           3 :                 sm->decision = DECISION_FAILURE;
     572        3204 :                 return;
     573             :         }
     574        4714 :         if (sm->currentMethod == EAP_TYPE_IDENTITY ||
     575        1516 :             sm->currentMethod == EAP_TYPE_NOTIFICATION)
     576        1682 :                 sm->methodState = METHOD_CONTINUE;
     577             :         else
     578        1516 :                 sm->methodState = METHOD_PROPOSED;
     579             : 
     580        3198 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
     581        3198 :                 "vendor=%u method=%u", vendor, sm->currentMethod);
     582        3198 :         eap_log_msg(sm, "Propose EAP method vendor=%u method=%u",
     583        3198 :                     vendor, sm->currentMethod);
     584             : }
     585             : 
     586             : 
     587         130 : SM_STATE(EAP, NAK)
     588             : {
     589             :         const struct eap_hdr *nak;
     590         130 :         size_t len = 0;
     591             :         const u8 *pos;
     592         130 :         const u8 *nak_list = NULL;
     593             : 
     594         130 :         SM_ENTRY(EAP, NAK);
     595             : 
     596         130 :         if (sm->eap_method_priv) {
     597         130 :                 sm->m->reset(sm, sm->eap_method_priv);
     598         130 :                 sm->eap_method_priv = NULL;
     599             :         }
     600         130 :         sm->m = NULL;
     601             : 
     602         130 :         if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1))
     603         130 :                 return;
     604             : 
     605         130 :         nak = wpabuf_head(sm->eap_if.eapRespData);
     606         130 :         if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) {
     607         130 :                 len = be_to_host16(nak->length);
     608         130 :                 if (len > wpabuf_len(sm->eap_if.eapRespData))
     609           0 :                         len = wpabuf_len(sm->eap_if.eapRespData);
     610         130 :                 pos = (const u8 *) (nak + 1);
     611         130 :                 len -= sizeof(*nak);
     612         130 :                 if (*pos == EAP_TYPE_NAK) {
     613         126 :                         pos++;
     614         126 :                         len--;
     615         126 :                         nak_list = pos;
     616             :                 }
     617             :         }
     618         130 :         eap_sm_Policy_update(sm, nak_list, len);
     619             : }
     620             : 
     621             : 
     622        5585 : SM_STATE(EAP, SELECT_ACTION)
     623             : {
     624        5585 :         SM_ENTRY(EAP, SELECT_ACTION);
     625             : 
     626        5585 :         sm->decision = eap_sm_Policy_getDecision(sm);
     627        5585 : }
     628             : 
     629             : 
     630           0 : SM_STATE(EAP, TIMEOUT_FAILURE)
     631             : {
     632           0 :         SM_ENTRY(EAP, TIMEOUT_FAILURE);
     633             : 
     634           0 :         sm->eap_if.eapTimeout = TRUE;
     635           0 : }
     636             : 
     637             : 
     638         551 : SM_STATE(EAP, FAILURE)
     639             : {
     640         551 :         SM_ENTRY(EAP, FAILURE);
     641             : 
     642         551 :         wpabuf_free(sm->eap_if.eapReqData);
     643         551 :         sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId);
     644         551 :         wpabuf_free(sm->lastReqData);
     645         551 :         sm->lastReqData = NULL;
     646         551 :         sm->eap_if.eapFail = TRUE;
     647             : 
     648        3306 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
     649        3306 :                 MACSTR, MAC2STR(sm->peer_addr));
     650         551 : }
     651             : 
     652             : 
     653         731 : SM_STATE(EAP, SUCCESS)
     654             : {
     655         731 :         SM_ENTRY(EAP, SUCCESS);
     656             : 
     657         731 :         wpabuf_free(sm->eap_if.eapReqData);
     658         731 :         sm->eap_if.eapReqData = eap_sm_buildSuccess(sm, sm->currentId);
     659         731 :         wpabuf_free(sm->lastReqData);
     660         731 :         sm->lastReqData = NULL;
     661         731 :         if (sm->eap_if.eapKeyData)
     662         730 :                 sm->eap_if.eapKeyAvailable = TRUE;
     663         731 :         sm->eap_if.eapSuccess = TRUE;
     664             : 
     665        4386 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
     666        4386 :                 MACSTR, MAC2STR(sm->peer_addr));
     667         731 : }
     668             : 
     669             : 
     670          41 : SM_STATE(EAP, INITIATE_REAUTH_START)
     671             : {
     672          41 :         SM_ENTRY(EAP, INITIATE_REAUTH_START);
     673             : 
     674          41 :         sm->initiate_reauth_start_sent = TRUE;
     675          41 :         sm->try_initiate_reauth = TRUE;
     676          41 :         sm->currentId = eap_sm_nextId(sm, sm->currentId);
     677          41 :         wpa_printf(MSG_DEBUG,
     678             :                    "EAP: building EAP-Initiate-Re-auth-Start: Identifier %d",
     679             :                    sm->currentId);
     680          41 :         sm->lastId = sm->currentId;
     681          41 :         wpabuf_free(sm->eap_if.eapReqData);
     682          41 :         sm->eap_if.eapReqData = eap_sm_buildInitiateReauthStart(sm,
     683          41 :                                                                 sm->currentId);
     684          41 :         wpabuf_free(sm->lastReqData);
     685          41 :         sm->lastReqData = NULL;
     686          41 : }
     687             : 
     688             : 
     689             : #ifdef CONFIG_ERP
     690             : 
     691          21 : static void erp_send_finish_reauth(struct eap_sm *sm,
     692             :                                    struct eap_server_erp_key *erp, u8 id,
     693             :                                    u8 flags, u16 seq, const char *nai)
     694             : {
     695             :         size_t plen;
     696             :         struct wpabuf *msg;
     697             :         u8 hash[SHA256_MAC_LEN];
     698             :         size_t hash_len;
     699             :         u8 seed[4];
     700             : 
     701          21 :         if (erp) {
     702          20 :                 switch (erp->cryptosuite) {
     703             :                 case EAP_ERP_CS_HMAC_SHA256_256:
     704           0 :                         hash_len = 32;
     705           0 :                         break;
     706             :                 case EAP_ERP_CS_HMAC_SHA256_128:
     707          20 :                         hash_len = 16;
     708          20 :                         break;
     709             :                 default:
     710           1 :                         return;
     711             :                 }
     712             :         } else
     713           1 :                 hash_len = 0;
     714             : 
     715          21 :         plen = 1 + 2 + 2 + os_strlen(nai);
     716          21 :         if (hash_len)
     717          20 :                 plen += 1 + hash_len;
     718          21 :         msg = eap_msg_alloc(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
     719             :                             plen, EAP_CODE_FINISH, id);
     720          21 :         if (msg == NULL)
     721           0 :                 return;
     722          21 :         wpabuf_put_u8(msg, flags);
     723          21 :         wpabuf_put_be16(msg, seq);
     724             : 
     725          21 :         wpabuf_put_u8(msg, EAP_ERP_TLV_KEYNAME_NAI);
     726          21 :         wpabuf_put_u8(msg, os_strlen(nai));
     727          21 :         wpabuf_put_str(msg, nai);
     728             : 
     729          21 :         if (erp) {
     730          20 :                 wpabuf_put_u8(msg, erp->cryptosuite);
     731          40 :                 if (hmac_sha256(erp->rIK, erp->rIK_len,
     732          20 :                                 wpabuf_head(msg), wpabuf_len(msg), hash) < 0) {
     733           0 :                         wpabuf_free(msg);
     734           0 :                         return;
     735             :                 }
     736          20 :                 wpabuf_put_data(msg, hash, hash_len);
     737             :         }
     738             : 
     739          21 :         wpa_printf(MSG_DEBUG, "EAP: Send EAP-Finish/Re-auth (%s)",
     740          21 :                    flags & 0x80 ? "failure" : "success");
     741             : 
     742          21 :         sm->lastId = sm->currentId;
     743          21 :         sm->currentId = id;
     744          21 :         wpabuf_free(sm->eap_if.eapReqData);
     745          21 :         sm->eap_if.eapReqData = msg;
     746          21 :         wpabuf_free(sm->lastReqData);
     747          21 :         sm->lastReqData = NULL;
     748             : 
     749          21 :         if ((flags & 0x80) || !erp) {
     750           1 :                 sm->eap_if.eapFail = TRUE;
     751           6 :                 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
     752           6 :                         MACSTR, MAC2STR(sm->peer_addr));
     753           1 :                 return;
     754             :         }
     755             : 
     756          20 :         bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
     757          20 :         sm->eap_if.eapKeyDataLen = 0;
     758          20 :         sm->eap_if.eapKeyData = os_malloc(erp->rRK_len);
     759          20 :         if (!sm->eap_if.eapKeyData)
     760           0 :                 return;
     761             : 
     762          20 :         WPA_PUT_BE16(seed, seq);
     763          20 :         WPA_PUT_BE16(&seed[2], erp->rRK_len);
     764          20 :         if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
     765             :                             "Re-authentication Master Session Key@ietf.org",
     766             :                             seed, sizeof(seed),
     767             :                             sm->eap_if.eapKeyData, erp->rRK_len) < 0) {
     768           0 :                 wpa_printf(MSG_DEBUG, "EAP: Could not derive rMSK for ERP");
     769           0 :                 bin_clear_free(sm->eap_if.eapKeyData, erp->rRK_len);
     770           0 :                 sm->eap_if.eapKeyData = NULL;
     771           0 :                 return;
     772             :         }
     773          20 :         sm->eap_if.eapKeyDataLen = erp->rRK_len;
     774          20 :         sm->eap_if.eapKeyAvailable = TRUE;
     775          40 :         wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
     776          20 :                         sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
     777          20 :         sm->eap_if.eapSuccess = TRUE;
     778             : 
     779         120 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
     780         120 :                 MACSTR, MAC2STR(sm->peer_addr));
     781             : }
     782             : 
     783             : 
     784          37 : SM_STATE(EAP, INITIATE_RECEIVED)
     785             : {
     786             :         const u8 *pos, *end, *start, *tlvs, *hdr;
     787             :         const struct eap_hdr *ehdr;
     788             :         size_t len;
     789             :         u8 flags;
     790             :         u16 seq;
     791             :         char nai[254];
     792             :         struct eap_server_erp_key *erp;
     793             :         int max_len;
     794             :         u8 hash[SHA256_MAC_LEN];
     795             :         size_t hash_len;
     796             :         struct erp_tlvs parse;
     797          37 :         u8 resp_flags = 0x80; /* default to failure; cleared on success */
     798             : 
     799          37 :         SM_ENTRY(EAP, INITIATE_RECEIVED);
     800             : 
     801          37 :         sm->rxInitiate = FALSE;
     802             : 
     803          37 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
     804          37 :                                sm->eap_if.eapRespData, &len);
     805          37 :         if (pos == NULL) {
     806           0 :                 wpa_printf(MSG_INFO, "EAP-Initiate: Invalid frame");
     807           0 :                 goto fail;
     808             :         }
     809          37 :         hdr = wpabuf_head(sm->eap_if.eapRespData);
     810          37 :         ehdr = wpabuf_head(sm->eap_if.eapRespData);
     811             : 
     812          37 :         wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth", pos, len);
     813          37 :         if (len < 4) {
     814           0 :                 wpa_printf(MSG_INFO, "EAP: Too short EAP-Initiate/Re-auth");
     815           0 :                 goto fail;
     816             :         }
     817          37 :         end = pos + len;
     818             : 
     819          37 :         flags = *pos++;
     820          37 :         seq = WPA_GET_BE16(pos);
     821          37 :         pos += 2;
     822          37 :         wpa_printf(MSG_DEBUG, "EAP: Flags=0x%x SEQ=%u", flags, seq);
     823          37 :         tlvs = pos;
     824             : 
     825             :         /*
     826             :          * Parse TVs/TLVs. Since we do not yet know the length of the
     827             :          * Authentication Tag, stop parsing if an unknown TV/TLV is seen and
     828             :          * just try to find the keyName-NAI first so that we can check the
     829             :          * Authentication Tag.
     830             :          */
     831          37 :         if (erp_parse_tlvs(tlvs, end, &parse, 1) < 0)
     832           0 :                 goto fail;
     833             : 
     834          37 :         if (!parse.keyname) {
     835           0 :                 wpa_printf(MSG_DEBUG,
     836             :                            "EAP: No keyName-NAI in EAP-Initiate/Re-auth Packet");
     837           0 :                 goto fail;
     838             :         }
     839             : 
     840          74 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Initiate/Re-auth - keyName-NAI",
     841          74 :                           parse.keyname, parse.keyname_len);
     842          37 :         if (parse.keyname_len > 253) {
     843           0 :                 wpa_printf(MSG_DEBUG,
     844             :                            "EAP: Too long keyName-NAI in EAP-Initiate/Re-auth");
     845           0 :                 goto fail;
     846             :         }
     847          37 :         os_memcpy(nai, parse.keyname, parse.keyname_len);
     848          37 :         nai[parse.keyname_len] = '\0';
     849             : 
     850          37 :         if (!sm->eap_server) {
     851             :                 /*
     852             :                  * In passthrough case, EAP-Initiate/Re-auth replaces
     853             :                  * EAP Identity exchange. Use keyName-NAI as the user identity
     854             :                  * and forward EAP-Initiate/Re-auth to the backend
     855             :                  * authentication server.
     856             :                  */
     857          16 :                 wpa_printf(MSG_DEBUG,
     858             :                            "EAP: Use keyName-NAI as user identity for backend authentication");
     859          16 :                 eap_server_clear_identity(sm);
     860          16 :                 sm->identity = (u8 *) dup_binstr(parse.keyname,
     861          16 :                                                  parse.keyname_len);
     862          16 :                 if (!sm->identity)
     863           0 :                         goto fail;
     864          16 :                 sm->identity_len = parse.keyname_len;
     865          53 :                 return;
     866             :         }
     867             : 
     868          21 :         erp = eap_erp_get_key(sm, nai);
     869          21 :         if (!erp) {
     870           1 :                 wpa_printf(MSG_DEBUG, "EAP: No matching ERP key found for %s",
     871             :                            nai);
     872           1 :                 goto report_error;
     873             :         }
     874             : 
     875          20 :         if (erp->recv_seq != (u32) -1 && erp->recv_seq >= seq) {
     876           0 :                 wpa_printf(MSG_DEBUG,
     877             :                            "EAP: SEQ=%u replayed (already received SEQ=%u)",
     878             :                            seq, erp->recv_seq);
     879           0 :                 goto fail;
     880             :         }
     881             : 
     882             :         /* Is there enough room for Cryptosuite and Authentication Tag? */
     883          20 :         start = parse.keyname + parse.keyname_len;
     884          20 :         max_len = end - start;
     885          20 :         if (max_len <
     886          20 :             1 + (erp->cryptosuite == EAP_ERP_CS_HMAC_SHA256_256 ? 32 : 16)) {
     887           0 :                 wpa_printf(MSG_DEBUG,
     888             :                            "EAP: Not enough room for Authentication Tag");
     889           0 :                 goto fail;
     890             :         }
     891             : 
     892          20 :         switch (erp->cryptosuite) {
     893             :         case EAP_ERP_CS_HMAC_SHA256_256:
     894           0 :                 if (end[-33] != erp->cryptosuite) {
     895           0 :                         wpa_printf(MSG_DEBUG,
     896             :                                    "EAP: Different Cryptosuite used");
     897           0 :                         goto fail;
     898             :                 }
     899           0 :                 hash_len = 32;
     900           0 :                 break;
     901             :         case EAP_ERP_CS_HMAC_SHA256_128:
     902           4 :                 if (end[-17] != erp->cryptosuite) {
     903           0 :                         wpa_printf(MSG_DEBUG,
     904             :                                    "EAP: Different Cryptosuite used");
     905           0 :                         goto fail;
     906             :                 }
     907           4 :                 hash_len = 16;
     908           4 :                 break;
     909             :         default:
     910          16 :                 hash_len = 0;
     911          16 :                 break;
     912             :         }
     913             : 
     914          20 :         if (hash_len) {
     915           4 :                 if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
     916           4 :                                 end - hdr - hash_len, hash) < 0)
     917           0 :                         goto fail;
     918           4 :                 if (os_memcmp(end - hash_len, hash, hash_len) != 0) {
     919           0 :                         wpa_printf(MSG_DEBUG,
     920             :                                    "EAP: Authentication Tag mismatch");
     921           0 :                         goto fail;
     922             :                 }
     923             :         }
     924             : 
     925             :         /* Check if any supported CS results in matching tag */
     926          20 :         if (!hash_len && max_len >= 1 + 32 &&
     927           0 :             end[-33] == EAP_ERP_CS_HMAC_SHA256_256) {
     928           0 :                 if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
     929           0 :                                 end - hdr - 32, hash) < 0)
     930           0 :                         goto fail;
     931           0 :                 if (os_memcmp(end - 32, hash, 32) == 0) {
     932           0 :                         wpa_printf(MSG_DEBUG,
     933             :                                    "EAP: Authentication Tag match using HMAC-SHA256-256");
     934           0 :                         hash_len = 32;
     935           0 :                         erp->cryptosuite = EAP_ERP_CS_HMAC_SHA256_256;
     936             :                 }
     937             :         }
     938             : 
     939          20 :         if (!hash_len && end[-17] == EAP_ERP_CS_HMAC_SHA256_128) {
     940          16 :                 if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
     941          16 :                                 end - hdr - 16, hash) < 0)
     942           0 :                         goto fail;
     943          16 :                 if (os_memcmp(end - 16, hash, 16) == 0) {
     944          16 :                         wpa_printf(MSG_DEBUG,
     945             :                                    "EAP: Authentication Tag match using HMAC-SHA256-128");
     946          16 :                         hash_len = 16;
     947          16 :                         erp->cryptosuite = EAP_ERP_CS_HMAC_SHA256_128;
     948             :                 }
     949             :         }
     950             : 
     951          20 :         if (!hash_len) {
     952           0 :                 wpa_printf(MSG_DEBUG,
     953             :                            "EAP: No supported cryptosuite matched Authentication Tag");
     954           0 :                 goto fail;
     955             :         }
     956          20 :         end -= 1 + hash_len;
     957             : 
     958             :         /*
     959             :          * Parse TVs/TLVs again now that we know the exact part of the buffer
     960             :          * that contains them.
     961             :          */
     962          20 :         wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth TVs/TLVs",
     963          20 :                     tlvs, end - tlvs);
     964          20 :         if (erp_parse_tlvs(tlvs, end, &parse, 0) < 0)
     965           0 :                 goto fail;
     966             : 
     967          40 :         wpa_printf(MSG_DEBUG, "EAP: ERP key %s SEQ updated to %u",
     968          20 :                    erp->keyname_nai, seq);
     969          20 :         erp->recv_seq = seq;
     970          20 :         resp_flags &= ~0x80; /* R=0 - success */
     971             : 
     972             : report_error:
     973          21 :         erp_send_finish_reauth(sm, erp, ehdr->identifier, resp_flags, seq, nai);
     974          21 :         return;
     975             : 
     976             : fail:
     977           0 :         sm->ignore = TRUE;
     978             : }
     979             : 
     980             : #endif /* CONFIG_ERP */
     981             : 
     982             : 
     983        1068 : SM_STATE(EAP, INITIALIZE_PASSTHROUGH)
     984             : {
     985        1068 :         SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH);
     986             : 
     987        1068 :         wpabuf_free(sm->eap_if.aaaEapRespData);
     988        1068 :         sm->eap_if.aaaEapRespData = NULL;
     989        1068 :         sm->try_initiate_reauth = FALSE;
     990        1068 : }
     991             : 
     992             : 
     993        2980 : SM_STATE(EAP, IDLE2)
     994             : {
     995        2980 :         SM_ENTRY(EAP, IDLE2);
     996             : 
     997        2980 :         sm->eap_if.retransWhile = eap_sm_calculateTimeout(
     998             :                 sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR,
     999             :                 sm->methodTimeout);
    1000        2980 : }
    1001             : 
    1002             : 
    1003           5 : SM_STATE(EAP, RETRANSMIT2)
    1004             : {
    1005           5 :         SM_ENTRY(EAP, RETRANSMIT2);
    1006             : 
    1007           5 :         sm->retransCount++;
    1008           5 :         if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
    1009           5 :                 if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
    1010           5 :                         sm->eap_if.eapReq = TRUE;
    1011             :         }
    1012           5 : }
    1013             : 
    1014             : 
    1015        2703 : SM_STATE(EAP, RECEIVED2)
    1016             : {
    1017        2703 :         SM_ENTRY(EAP, RECEIVED2);
    1018             : 
    1019             :         /* parse rxResp, respId, respMethod */
    1020        2703 :         eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
    1021        2703 : }
    1022             : 
    1023             : 
    1024           2 : SM_STATE(EAP, DISCARD2)
    1025             : {
    1026           2 :         SM_ENTRY(EAP, DISCARD2);
    1027           2 :         sm->eap_if.eapResp = FALSE;
    1028           2 :         sm->eap_if.eapNoReq = TRUE;
    1029           2 : }
    1030             : 
    1031             : 
    1032        2973 : SM_STATE(EAP, SEND_REQUEST2)
    1033             : {
    1034        2973 :         SM_ENTRY(EAP, SEND_REQUEST2);
    1035             : 
    1036        2973 :         sm->retransCount = 0;
    1037        2973 :         if (sm->eap_if.eapReqData) {
    1038        2971 :                 if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
    1039             :                 {
    1040        2971 :                         sm->eap_if.eapResp = FALSE;
    1041        2971 :                         sm->eap_if.eapReq = TRUE;
    1042             :                 } else {
    1043           0 :                         sm->eap_if.eapResp = FALSE;
    1044           0 :                         sm->eap_if.eapReq = FALSE;
    1045             :                 }
    1046             :         } else {
    1047           2 :                 wpa_printf(MSG_INFO, "EAP: SEND_REQUEST2 - no eapReqData");
    1048           2 :                 sm->eap_if.eapResp = FALSE;
    1049           2 :                 sm->eap_if.eapReq = FALSE;
    1050           2 :                 sm->eap_if.eapNoReq = TRUE;
    1051             :         }
    1052        2973 : }
    1053             : 
    1054             : 
    1055        3769 : SM_STATE(EAP, AAA_REQUEST)
    1056             : {
    1057        3769 :         SM_ENTRY(EAP, AAA_REQUEST);
    1058             : 
    1059        3769 :         if (sm->eap_if.eapRespData == NULL) {
    1060           0 :                 wpa_printf(MSG_INFO, "EAP: AAA_REQUEST - no eapRespData");
    1061        3769 :                 return;
    1062             :         }
    1063             : 
    1064             :         /*
    1065             :          * if (respMethod == IDENTITY)
    1066             :          *      aaaIdentity = eapRespData
    1067             :          * This is already taken care of by the EAP-Identity method which
    1068             :          * stores the identity into sm->identity.
    1069             :          */
    1070             : 
    1071        3769 :         eap_copy_buf(&sm->eap_if.aaaEapRespData, sm->eap_if.eapRespData);
    1072             : }
    1073             : 
    1074             : 
    1075        2973 : SM_STATE(EAP, AAA_RESPONSE)
    1076             : {
    1077        2973 :         SM_ENTRY(EAP, AAA_RESPONSE);
    1078             : 
    1079        2973 :         eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
    1080        2973 :         sm->currentId = eap_sm_getId(sm->eap_if.eapReqData);
    1081        2973 :         sm->methodTimeout = sm->eap_if.aaaMethodTimeout;
    1082        2973 : }
    1083             : 
    1084             : 
    1085        3769 : SM_STATE(EAP, AAA_IDLE)
    1086             : {
    1087        3769 :         SM_ENTRY(EAP, AAA_IDLE);
    1088             : 
    1089        3769 :         sm->eap_if.aaaFail = FALSE;
    1090        3769 :         sm->eap_if.aaaSuccess = FALSE;
    1091        3769 :         sm->eap_if.aaaEapReq = FALSE;
    1092        3769 :         sm->eap_if.aaaEapNoReq = FALSE;
    1093        3769 :         sm->eap_if.aaaEapResp = TRUE;
    1094        3769 : }
    1095             : 
    1096             : 
    1097           0 : SM_STATE(EAP, TIMEOUT_FAILURE2)
    1098             : {
    1099           0 :         SM_ENTRY(EAP, TIMEOUT_FAILURE2);
    1100             : 
    1101           0 :         sm->eap_if.eapTimeout = TRUE;
    1102           0 : }
    1103             : 
    1104             : 
    1105         102 : SM_STATE(EAP, FAILURE2)
    1106             : {
    1107         102 :         SM_ENTRY(EAP, FAILURE2);
    1108             : 
    1109         102 :         eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
    1110         102 :         sm->eap_if.eapFail = TRUE;
    1111         102 : }
    1112             : 
    1113             : 
    1114         667 : SM_STATE(EAP, SUCCESS2)
    1115             : {
    1116         667 :         SM_ENTRY(EAP, SUCCESS2);
    1117             : 
    1118         667 :         eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
    1119             : 
    1120         667 :         sm->eap_if.eapKeyAvailable = sm->eap_if.aaaEapKeyAvailable;
    1121         667 :         if (sm->eap_if.aaaEapKeyAvailable) {
    1122         653 :                 EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData);
    1123             :         } else {
    1124          14 :                 bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
    1125          14 :                 sm->eap_if.eapKeyData = NULL;
    1126          14 :                 sm->eap_if.eapKeyDataLen = 0;
    1127             :         }
    1128             : 
    1129         667 :         sm->eap_if.eapSuccess = TRUE;
    1130             : 
    1131             :         /*
    1132             :          * Start reauthentication with identity request even though we know the
    1133             :          * previously used identity. This is needed to get reauthentication
    1134             :          * started properly.
    1135             :          */
    1136         667 :         sm->start_reauth = TRUE;
    1137         667 : }
    1138             : 
    1139             : 
    1140      110402 : SM_STEP(EAP)
    1141             : {
    1142      110402 :         if (sm->eap_if.eapRestart && sm->eap_if.portEnabled)
    1143        2530 :                 SM_ENTER_GLOBAL(EAP, INITIALIZE);
    1144      107872 :         else if (!sm->eap_if.portEnabled)
    1145        2852 :                 SM_ENTER_GLOBAL(EAP, DISABLED);
    1146      105020 :         else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
    1147           0 :                 if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
    1148           0 :                         wpa_printf(MSG_DEBUG, "EAP: more than %d "
    1149             :                                    "authentication rounds - abort",
    1150             :                                    EAP_MAX_AUTH_ROUNDS);
    1151           0 :                         sm->num_rounds++;
    1152           0 :                         SM_ENTER_GLOBAL(EAP, FAILURE);
    1153             :                 }
    1154      105020 :         } else switch (sm->EAP_state) {
    1155             :         case EAP_INITIALIZE:
    1156        2530 :                 if (sm->backend_auth) {
    1157         807 :                         if (!sm->rxResp)
    1158          16 :                                 SM_ENTER(EAP, SELECT_ACTION);
    1159        1582 :                         else if (sm->rxResp &&
    1160        1582 :                                  (sm->respMethod == EAP_TYPE_NAK ||
    1161         791 :                                   (sm->respMethod == EAP_TYPE_EXPANDED &&
    1162           0 :                                    sm->respVendor == EAP_VENDOR_IETF &&
    1163           0 :                                    sm->respVendorMethod == EAP_TYPE_NAK)))
    1164           0 :                                 SM_ENTER(EAP, NAK);
    1165             :                         else
    1166         791 :                                 SM_ENTER(EAP, PICK_UP_METHOD);
    1167             :                 } else {
    1168        1723 :                         SM_ENTER(EAP, SELECT_ACTION);
    1169             :                 }
    1170        2530 :                 break;
    1171             :         case EAP_PICK_UP_METHOD:
    1172         791 :                 if (sm->currentMethod == EAP_TYPE_NONE) {
    1173           0 :                         SM_ENTER(EAP, SELECT_ACTION);
    1174             :                 } else {
    1175         791 :                         SM_ENTER(EAP, METHOD_RESPONSE);
    1176             :                 }
    1177         791 :                 break;
    1178             :         case EAP_DISABLED:
    1179           0 :                 if (sm->eap_if.portEnabled)
    1180           0 :                         SM_ENTER(EAP, INITIALIZE);
    1181           0 :                 break;
    1182             :         case EAP_IDLE:
    1183       21862 :                 if (sm->eap_if.retransWhile == 0) {
    1184           2 :                         if (sm->try_initiate_reauth) {
    1185           0 :                                 sm->try_initiate_reauth = FALSE;
    1186           0 :                                 SM_ENTER(EAP, SELECT_ACTION);
    1187             :                         } else {
    1188           2 :                                 SM_ENTER(EAP, RETRANSMIT);
    1189             :                         }
    1190       21860 :                 } else if (sm->eap_if.eapResp)
    1191        6471 :                         SM_ENTER(EAP, RECEIVED);
    1192       21862 :                 break;
    1193             :         case EAP_RETRANSMIT:
    1194           2 :                 if (sm->retransCount > sm->MaxRetrans)
    1195           0 :                         SM_ENTER(EAP, TIMEOUT_FAILURE);
    1196             :                 else
    1197           2 :                         SM_ENTER(EAP, IDLE);
    1198           2 :                 break;
    1199             :         case EAP_RECEIVED:
    1200       12917 :                 if (sm->rxResp && (sm->respId == sm->currentId) &&
    1201       12766 :                     (sm->respMethod == EAP_TYPE_NAK ||
    1202        8108 :                      (sm->respMethod == EAP_TYPE_EXPANDED &&
    1203        1792 :                       sm->respVendor == EAP_VENDOR_IETF &&
    1204           4 :                       sm->respVendorMethod == EAP_TYPE_NAK))
    1205         130 :                     && (sm->methodState == METHOD_PROPOSED))
    1206         130 :                         SM_ENTER(EAP, NAK);
    1207       12657 :                 else if (sm->rxResp && (sm->respId == sm->currentId) &&
    1208        6316 :                          ((sm->respMethod == sm->currentMethod) ||
    1209           0 :                           (sm->respMethod == EAP_TYPE_EXPANDED &&
    1210           0 :                            sm->respVendor == EAP_VENDOR_IETF &&
    1211           0 :                            sm->respVendorMethod == sm->currentMethod)))
    1212        6316 :                         SM_ENTER(EAP, INTEGRITY_CHECK);
    1213             : #ifdef CONFIG_ERP
    1214          25 :                 else if (sm->rxInitiate)
    1215          21 :                         SM_ENTER(EAP, INITIATE_RECEIVED);
    1216             : #endif /* CONFIG_ERP */
    1217             :                 else {
    1218           8 :                         wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "
    1219             :                                    "rxResp=%d respId=%d currentId=%d "
    1220             :                                    "respMethod=%d currentMethod=%d",
    1221           4 :                                    sm->rxResp, sm->respId, sm->currentId,
    1222           4 :                                    sm->respMethod, sm->currentMethod);
    1223           4 :                         eap_log_msg(sm, "Discard received EAP message");
    1224           4 :                         SM_ENTER(EAP, DISCARD);
    1225             :                 }
    1226        6471 :                 break;
    1227             :         case EAP_DISCARD:
    1228           4 :                 SM_ENTER(EAP, IDLE);
    1229           4 :                 break;
    1230             :         case EAP_SEND_REQUEST:
    1231        6626 :                 SM_ENTER(EAP, IDLE);
    1232        6626 :                 break;
    1233             :         case EAP_INTEGRITY_CHECK:
    1234        6316 :                 if (sm->ignore)
    1235           0 :                         SM_ENTER(EAP, DISCARD);
    1236             :                 else
    1237        6316 :                         SM_ENTER(EAP, METHOD_RESPONSE);
    1238        6316 :                 break;
    1239             :         case EAP_METHOD_REQUEST:
    1240        6608 :                 if (sm->m == NULL) {
    1241             :                         /*
    1242             :                          * This transition is not mentioned in RFC 4137, but it
    1243             :                          * is needed to handle cleanly a case where EAP method
    1244             :                          * initialization fails.
    1245             :                          */
    1246           3 :                         SM_ENTER(EAP, FAILURE);
    1247           3 :                         break;
    1248             :                 }
    1249        6605 :                 SM_ENTER(EAP, SEND_REQUEST);
    1250        6605 :                 if (sm->eap_if.eapNoReq && !sm->eap_if.eapReq) {
    1251             :                         /*
    1252             :                          * This transition is not mentioned in RFC 4137, but it
    1253             :                          * is needed to handle cleanly a case where EAP method
    1254             :                          * buildReq fails.
    1255             :                          */
    1256          20 :                         wpa_printf(MSG_DEBUG,
    1257             :                                    "EAP: Method did not return a request");
    1258          20 :                         SM_ENTER(EAP, FAILURE);
    1259          20 :                         break;
    1260             :                 }
    1261        6585 :                 break;
    1262             :         case EAP_METHOD_RESPONSE:
    1263             :                 /*
    1264             :                  * Note: Mechanism to allow EAP methods to wait while going
    1265             :                  * through pending processing is an extension to RFC 4137
    1266             :                  * which only defines the transits to SELECT_ACTION and
    1267             :                  * METHOD_REQUEST from this METHOD_RESPONSE state.
    1268             :                  */
    1269        7431 :                 if (sm->methodState == METHOD_END)
    1270        3700 :                         SM_ENTER(EAP, SELECT_ACTION);
    1271        3731 :                 else if (sm->method_pending == METHOD_PENDING_WAIT) {
    1272         188 :                         wpa_printf(MSG_DEBUG, "EAP: Method has pending "
    1273             :                                    "processing - wait before proceeding to "
    1274             :                                    "METHOD_REQUEST state");
    1275        3543 :                 } else if (sm->method_pending == METHOD_PENDING_CONT) {
    1276         136 :                         wpa_printf(MSG_DEBUG, "EAP: Method has completed "
    1277             :                                    "pending processing - reprocess pending "
    1278             :                                    "EAP message");
    1279         136 :                         sm->method_pending = METHOD_PENDING_NONE;
    1280         136 :                         SM_ENTER(EAP, METHOD_RESPONSE);
    1281             :                 } else
    1282        3407 :                         SM_ENTER(EAP, METHOD_REQUEST);
    1283        7431 :                 break;
    1284             :         case EAP_PROPOSE_METHOD:
    1285             :                 /*
    1286             :                  * Note: Mechanism to allow EAP methods to wait while going
    1287             :                  * through pending processing is an extension to RFC 4137
    1288             :                  * which only defines the transit to METHOD_REQUEST from this
    1289             :                  * PROPOSE_METHOD state.
    1290             :                  */
    1291        3201 :                 if (sm->method_pending == METHOD_PENDING_WAIT) {
    1292           0 :                         wpa_printf(MSG_DEBUG, "EAP: Method has pending "
    1293             :                                    "processing - wait before proceeding to "
    1294             :                                    "METHOD_REQUEST state");
    1295           0 :                         if (sm->user_eap_method_index > 0)
    1296           0 :                                 sm->user_eap_method_index--;
    1297        3201 :                 } else if (sm->method_pending == METHOD_PENDING_CONT) {
    1298           0 :                         wpa_printf(MSG_DEBUG, "EAP: Method has completed "
    1299             :                                    "pending processing - reprocess pending "
    1300             :                                    "EAP message");
    1301           0 :                         sm->method_pending = METHOD_PENDING_NONE;
    1302           0 :                         SM_ENTER(EAP, PROPOSE_METHOD);
    1303             :                 } else
    1304        3201 :                         SM_ENTER(EAP, METHOD_REQUEST);
    1305        3201 :                 break;
    1306             :         case EAP_NAK:
    1307         130 :                 SM_ENTER(EAP, SELECT_ACTION);
    1308         130 :                 break;
    1309             :         case EAP_SELECT_ACTION:
    1310        5585 :                 if (sm->decision == DECISION_FAILURE)
    1311         528 :                         SM_ENTER(EAP, FAILURE);
    1312        5057 :                 else if (sm->decision == DECISION_SUCCESS)
    1313         731 :                         SM_ENTER(EAP, SUCCESS);
    1314        4326 :                 else if (sm->decision == DECISION_PASSTHROUGH)
    1315        1068 :                         SM_ENTER(EAP, INITIALIZE_PASSTHROUGH);
    1316        3258 :                 else if (sm->decision == DECISION_INITIATE_REAUTH_START)
    1317          41 :                         SM_ENTER(EAP, INITIATE_REAUTH_START);
    1318             : #ifdef CONFIG_ERP
    1319        3217 :                 else if (sm->eap_server && sm->erp && sm->rxInitiate)
    1320          16 :                         SM_ENTER(EAP, INITIATE_RECEIVED);
    1321             : #endif /* CONFIG_ERP */
    1322             :                 else
    1323        3201 :                         SM_ENTER(EAP, PROPOSE_METHOD);
    1324        5585 :                 break;
    1325             :         case EAP_INITIATE_REAUTH_START:
    1326          41 :                 SM_ENTER(EAP, SEND_REQUEST);
    1327          41 :                 break;
    1328             :         case EAP_INITIATE_RECEIVED:
    1329          45 :                 if (!sm->eap_server)
    1330          16 :                         SM_ENTER(EAP, SELECT_ACTION);
    1331          45 :                 break;
    1332             :         case EAP_TIMEOUT_FAILURE:
    1333           0 :                 break;
    1334             :         case EAP_FAILURE:
    1335         551 :                 break;
    1336             :         case EAP_SUCCESS:
    1337        1043 :                 break;
    1338             : 
    1339             :         case EAP_INITIALIZE_PASSTHROUGH:
    1340        1068 :                 if (sm->currentId == -1)
    1341           0 :                         SM_ENTER(EAP, AAA_IDLE);
    1342             :                 else
    1343        1068 :                         SM_ENTER(EAP, AAA_REQUEST);
    1344        1068 :                 break;
    1345             :         case EAP_IDLE2:
    1346        8691 :                 if (sm->eap_if.eapResp)
    1347        2703 :                         SM_ENTER(EAP, RECEIVED2);
    1348        5988 :                 else if (sm->eap_if.retransWhile == 0)
    1349           5 :                         SM_ENTER(EAP, RETRANSMIT2);
    1350        8691 :                 break;
    1351             :         case EAP_RETRANSMIT2:
    1352           5 :                 if (sm->retransCount > sm->MaxRetrans)
    1353           0 :                         SM_ENTER(EAP, TIMEOUT_FAILURE2);
    1354             :                 else
    1355           5 :                         SM_ENTER(EAP, IDLE2);
    1356           5 :                 break;
    1357             :         case EAP_RECEIVED2:
    1358        2703 :                 if (sm->rxResp && (sm->respId == sm->currentId))
    1359        2701 :                         SM_ENTER(EAP, AAA_REQUEST);
    1360             :                 else
    1361           2 :                         SM_ENTER(EAP, DISCARD2);
    1362        2703 :                 break;
    1363             :         case EAP_DISCARD2:
    1364           2 :                 SM_ENTER(EAP, IDLE2);
    1365           2 :                 break;
    1366             :         case EAP_SEND_REQUEST2:
    1367        2973 :                 SM_ENTER(EAP, IDLE2);
    1368        2973 :                 break;
    1369             :         case EAP_AAA_REQUEST:
    1370        3769 :                 SM_ENTER(EAP, AAA_IDLE);
    1371        3769 :                 break;
    1372             :         case EAP_AAA_RESPONSE:
    1373        2973 :                 SM_ENTER(EAP, SEND_REQUEST2);
    1374        2973 :                 break;
    1375             :         case EAP_AAA_IDLE:
    1376       11388 :                 if (sm->eap_if.aaaFail)
    1377         102 :                         SM_ENTER(EAP, FAILURE2);
    1378       11286 :                 else if (sm->eap_if.aaaSuccess)
    1379         667 :                         SM_ENTER(EAP, SUCCESS2);
    1380       10619 :                 else if (sm->eap_if.aaaEapReq)
    1381        2973 :                         SM_ENTER(EAP, AAA_RESPONSE);
    1382        7646 :                 else if (sm->eap_if.aaaTimeout)
    1383           0 :                         SM_ENTER(EAP, TIMEOUT_FAILURE2);
    1384       11388 :                 break;
    1385             :         case EAP_TIMEOUT_FAILURE2:
    1386           0 :                 break;
    1387             :         case EAP_FAILURE2:
    1388         102 :                 break;
    1389             :         case EAP_SUCCESS2:
    1390        2109 :                 break;
    1391             :         }
    1392      110402 : }
    1393             : 
    1394             : 
    1395        9612 : static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
    1396             :                                    int eapSRTT, int eapRTTVAR,
    1397             :                                    int methodTimeout)
    1398             : {
    1399             :         int rto, i;
    1400             : 
    1401        9612 :         if (sm->try_initiate_reauth) {
    1402          41 :                 wpa_printf(MSG_DEBUG,
    1403             :                            "EAP: retransmit timeout 1 second for EAP-Initiate-Re-auth-Start");
    1404          41 :                 return 1;
    1405             :         }
    1406             : 
    1407        9571 :         if (methodTimeout) {
    1408             :                 /*
    1409             :                  * EAP method (either internal or through AAA server, provided
    1410             :                  * timeout hint. Use that as-is as a timeout for retransmitting
    1411             :                  * the EAP request if no response is received.
    1412             :                  */
    1413        1840 :                 wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
    1414             :                            "(from EAP method hint)", methodTimeout);
    1415        1840 :                 return methodTimeout;
    1416             :         }
    1417             : 
    1418             :         /*
    1419             :          * RFC 3748 recommends algorithms described in RFC 2988 for estimation
    1420             :          * of the retransmission timeout. This should be implemented once
    1421             :          * round-trip time measurements are available. For nowm a simple
    1422             :          * backoff mechanism is used instead if there are no EAP method
    1423             :          * specific hints.
    1424             :          *
    1425             :          * SRTT = smoothed round-trip time
    1426             :          * RTTVAR = round-trip time variation
    1427             :          * RTO = retransmission timeout
    1428             :          */
    1429             : 
    1430             :         /*
    1431             :          * RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for
    1432             :          * initial retransmission and then double the RTO to provide back off
    1433             :          * per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3
    1434             :          * modified RTOmax.
    1435             :          */
    1436        7731 :         rto = 3;
    1437        7739 :         for (i = 0; i < retransCount; i++) {
    1438           8 :                 rto *= 2;
    1439           8 :                 if (rto >= 20) {
    1440           0 :                         rto = 20;
    1441           0 :                         break;
    1442             :                 }
    1443             :         }
    1444             : 
    1445        7731 :         wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
    1446             :                    "(from dynamic back off; retransCount=%d)",
    1447             :                    rto, retransCount);
    1448             : 
    1449        7731 :         return rto;
    1450             : }
    1451             : 
    1452             : 
    1453        9981 : static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
    1454             : {
    1455             :         const struct eap_hdr *hdr;
    1456             :         size_t plen;
    1457             : 
    1458             :         /* parse rxResp, respId, respMethod */
    1459        9981 :         sm->rxResp = FALSE;
    1460        9981 :         sm->rxInitiate = FALSE;
    1461        9981 :         sm->respId = -1;
    1462        9981 :         sm->respMethod = EAP_TYPE_NONE;
    1463        9981 :         sm->respVendor = EAP_VENDOR_IETF;
    1464        9981 :         sm->respVendorMethod = EAP_TYPE_NONE;
    1465             : 
    1466        9981 :         if (resp == NULL || wpabuf_len(resp) < sizeof(*hdr)) {
    1467           0 :                 wpa_printf(MSG_DEBUG, "EAP: parseEapResp: invalid resp=%p "
    1468             :                            "len=%lu", resp,
    1469             :                            resp ? (unsigned long) wpabuf_len(resp) : 0);
    1470           0 :                 return;
    1471             :         }
    1472             : 
    1473        9981 :         hdr = wpabuf_head(resp);
    1474        9981 :         plen = be_to_host16(hdr->length);
    1475        9981 :         if (plen > wpabuf_len(resp)) {
    1476           0 :                 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
    1477             :                            "(len=%lu plen=%lu)",
    1478             :                            (unsigned long) wpabuf_len(resp),
    1479             :                            (unsigned long) plen);
    1480           0 :                 return;
    1481             :         }
    1482             : 
    1483        9981 :         sm->respId = hdr->identifier;
    1484             : 
    1485        9981 :         if (hdr->code == EAP_CODE_RESPONSE)
    1486        9944 :                 sm->rxResp = TRUE;
    1487          37 :         else if (hdr->code == EAP_CODE_INITIATE)
    1488          37 :                 sm->rxInitiate = TRUE;
    1489             : 
    1490        9981 :         if (plen > sizeof(*hdr)) {
    1491        9981 :                 u8 *pos = (u8 *) (hdr + 1);
    1492        9981 :                 sm->respMethod = *pos++;
    1493        9981 :                 if (sm->respMethod == EAP_TYPE_EXPANDED) {
    1494        1813 :                         if (plen < sizeof(*hdr) + 8) {
    1495           0 :                                 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
    1496             :                                            "expanded EAP-Packet (plen=%lu)",
    1497             :                                            (unsigned long) plen);
    1498           0 :                                 return;
    1499             :                         }
    1500        1813 :                         sm->respVendor = WPA_GET_BE24(pos);
    1501        1813 :                         pos += 3;
    1502        1813 :                         sm->respVendorMethod = WPA_GET_BE32(pos);
    1503             :                 }
    1504             :         }
    1505             : 
    1506       29943 :         wpa_printf(MSG_DEBUG,
    1507             :                    "EAP: parseEapResp: rxResp=%d rxInitiate=%d respId=%d respMethod=%u respVendor=%u respVendorMethod=%u",
    1508       19962 :                    sm->rxResp, sm->rxInitiate, sm->respId, sm->respMethod,
    1509             :                    sm->respVendor, sm->respVendorMethod);
    1510             : }
    1511             : 
    1512             : 
    1513        2973 : static int eap_sm_getId(const struct wpabuf *data)
    1514             : {
    1515             :         const struct eap_hdr *hdr;
    1516             : 
    1517        2973 :         if (data == NULL || wpabuf_len(data) < sizeof(*hdr))
    1518           2 :                 return -1;
    1519             : 
    1520        2971 :         hdr = wpabuf_head(data);
    1521        2971 :         wpa_printf(MSG_DEBUG, "EAP: getId: id=%d", hdr->identifier);
    1522        2971 :         return hdr->identifier;
    1523             : }
    1524             : 
    1525             : 
    1526         731 : static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id)
    1527             : {
    1528             :         struct wpabuf *msg;
    1529             :         struct eap_hdr *resp;
    1530         731 :         wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id);
    1531             : 
    1532         731 :         msg = wpabuf_alloc(sizeof(*resp));
    1533         731 :         if (msg == NULL)
    1534           1 :                 return NULL;
    1535         730 :         resp = wpabuf_put(msg, sizeof(*resp));
    1536         730 :         resp->code = EAP_CODE_SUCCESS;
    1537         730 :         resp->identifier = id;
    1538         730 :         resp->length = host_to_be16(sizeof(*resp));
    1539             : 
    1540         730 :         return msg;
    1541             : }
    1542             : 
    1543             : 
    1544         551 : static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id)
    1545             : {
    1546             :         struct wpabuf *msg;
    1547             :         struct eap_hdr *resp;
    1548         551 :         wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id);
    1549             : 
    1550         551 :         msg = wpabuf_alloc(sizeof(*resp));
    1551         551 :         if (msg == NULL)
    1552           0 :                 return NULL;
    1553         551 :         resp = wpabuf_put(msg, sizeof(*resp));
    1554         551 :         resp->code = EAP_CODE_FAILURE;
    1555         551 :         resp->identifier = id;
    1556         551 :         resp->length = host_to_be16(sizeof(*resp));
    1557             : 
    1558         551 :         return msg;
    1559             : }
    1560             : 
    1561             : 
    1562        6646 : static int eap_sm_nextId(struct eap_sm *sm, int id)
    1563             : {
    1564        6646 :         if (id < 0) {
    1565             :                 /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a
    1566             :                  * random number */
    1567        1723 :                 id = rand() & 0xff;
    1568        1723 :                 if (id != sm->lastId)
    1569        1721 :                         return id;
    1570             :         }
    1571        4925 :         return (id + 1) & 0xff;
    1572             : }
    1573             : 
    1574             : 
    1575             : /**
    1576             :  * eap_sm_process_nak - Process EAP-Response/Nak
    1577             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1578             :  * @nak_list: Nak list (allowed methods) from the supplicant
    1579             :  * @len: Length of nak_list in bytes
    1580             :  *
    1581             :  * This function is called when EAP-Response/Nak is received from the
    1582             :  * supplicant. This can happen for both phase 1 and phase 2 authentications.
    1583             :  */
    1584         148 : void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len)
    1585             : {
    1586             :         int i;
    1587             :         size_t j;
    1588             : 
    1589         148 :         if (sm->user == NULL)
    1590         148 :                 return;
    1591             : 
    1592         148 :         wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
    1593             :                    "index %d)", sm->user_eap_method_index);
    1594             : 
    1595         148 :         wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
    1596         148 :                     (u8 *) sm->user->methods,
    1597             :                     EAP_MAX_METHODS * sizeof(sm->user->methods[0]));
    1598         148 :         wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
    1599             :                     nak_list, len);
    1600             : 
    1601         148 :         i = sm->user_eap_method_index;
    1602        1984 :         while (i < EAP_MAX_METHODS &&
    1603        1836 :                (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
    1604         918 :                 sm->user->methods[i].method != EAP_TYPE_NONE)) {
    1605         770 :                 if (sm->user->methods[i].vendor != EAP_VENDOR_IETF)
    1606           0 :                         goto not_found;
    1607        1401 :                 for (j = 0; j < len; j++) {
    1608         770 :                         if (nak_list[j] == sm->user->methods[i].method) {
    1609         139 :                                 break;
    1610             :                         }
    1611             :                 }
    1612             : 
    1613         770 :                 if (j < len) {
    1614             :                         /* found */
    1615         139 :                         i++;
    1616         139 :                         continue;
    1617             :                 }
    1618             : 
    1619             :         not_found:
    1620             :                 /* not found - remove from the list */
    1621         631 :                 if (i + 1 < EAP_MAX_METHODS) {
    1622         631 :                         os_memmove(&sm->user->methods[i],
    1623             :                                    &sm->user->methods[i + 1],
    1624             :                                    (EAP_MAX_METHODS - i - 1) *
    1625             :                                    sizeof(sm->user->methods[0]));
    1626             :                 }
    1627         631 :                 sm->user->methods[EAP_MAX_METHODS - 1].vendor =
    1628             :                         EAP_VENDOR_IETF;
    1629         631 :                 sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
    1630             :         }
    1631             : 
    1632         148 :         wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
    1633         148 :                     (u8 *) sm->user->methods, EAP_MAX_METHODS *
    1634             :                     sizeof(sm->user->methods[0]));
    1635             : }
    1636             : 
    1637             : 
    1638        3830 : static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
    1639             :                                  size_t len)
    1640             : {
    1641        3830 :         if (nak_list == NULL || sm == NULL || sm->user == NULL)
    1642        3704 :                 return;
    1643             : 
    1644         126 :         if (sm->user->phase2) {
    1645           0 :                 wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user"
    1646             :                            " info was selected - reject");
    1647           0 :                 sm->decision = DECISION_FAILURE;
    1648           0 :                 return;
    1649             :         }
    1650             : 
    1651         126 :         eap_sm_process_nak(sm, nak_list, len);
    1652             : }
    1653             : 
    1654             : 
    1655        3206 : static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
    1656             : {
    1657             :         EapType next;
    1658        3206 :         int idx = sm->user_eap_method_index;
    1659             : 
    1660             :         /* In theory, there should be no problems with starting
    1661             :          * re-authentication with something else than EAP-Request/Identity and
    1662             :          * this does indeed work with wpa_supplicant. However, at least Funk
    1663             :          * Supplicant seemed to ignore re-auth if it skipped
    1664             :          * EAP-Request/Identity.
    1665             :          * Re-auth sets currentId == -1, so that can be used here to select
    1666             :          * whether Identity needs to be requested again. */
    1667        3206 :         if (sm->identity == NULL || sm->currentId == -1) {
    1668        1684 :                 *vendor = EAP_VENDOR_IETF;
    1669        1684 :                 next = EAP_TYPE_IDENTITY;
    1670        1684 :                 sm->update_user = TRUE;
    1671        3044 :         } else if (sm->user && idx < EAP_MAX_METHODS &&
    1672        2575 :                    (sm->user->methods[idx].vendor != EAP_VENDOR_IETF ||
    1673        1053 :                     sm->user->methods[idx].method != EAP_TYPE_NONE)) {
    1674        1519 :                 *vendor = sm->user->methods[idx].vendor;
    1675        1519 :                 next = sm->user->methods[idx].method;
    1676        1519 :                 sm->user_eap_method_index++;
    1677             :         } else {
    1678           3 :                 *vendor = EAP_VENDOR_IETF;
    1679           3 :                 next = EAP_TYPE_NONE;
    1680             :         }
    1681        3206 :         wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d",
    1682             :                    *vendor, next);
    1683        3206 :         return next;
    1684             : }
    1685             : 
    1686             : 
    1687        5585 : static int eap_sm_Policy_getDecision(struct eap_sm *sm)
    1688             : {
    1689        5585 :         if (!sm->eap_server && sm->identity && !sm->start_reauth) {
    1690        1068 :                 wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH");
    1691        1068 :                 return DECISION_PASSTHROUGH;
    1692             :         }
    1693             : 
    1694        5760 :         if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY &&
    1695        1243 :             sm->m->isSuccess(sm, sm->eap_method_priv)) {
    1696         731 :                 wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
    1697             :                            "SUCCESS");
    1698         731 :                 sm->update_user = TRUE;
    1699         731 :                 return DECISION_SUCCESS;
    1700             :         }
    1701             : 
    1702        5703 :         if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) &&
    1703        1917 :             !sm->m->isSuccess(sm, sm->eap_method_priv)) {
    1704         514 :                 wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
    1705             :                            "FAILURE");
    1706         514 :                 sm->update_user = TRUE;
    1707         514 :                 return DECISION_FAILURE;
    1708             :         }
    1709             : 
    1710        4708 :         if ((sm->user == NULL || sm->update_user) && sm->identity &&
    1711        1436 :             !sm->start_reauth) {
    1712             :                 /*
    1713             :                  * Allow Identity method to be started once to allow identity
    1714             :                  * selection hint to be sent from the authentication server,
    1715             :                  * but prevent a loop of Identity requests by only allowing
    1716             :                  * this to happen once.
    1717             :                  */
    1718        1436 :                 int id_req = 0;
    1719        1494 :                 if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY &&
    1720         116 :                     sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
    1721          58 :                     sm->user->methods[0].method == EAP_TYPE_IDENTITY)
    1722           0 :                         id_req = 1;
    1723        1436 :                 if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) {
    1724           1 :                         wpa_printf(MSG_DEBUG, "EAP: getDecision: user not "
    1725             :                                    "found from database -> FAILURE");
    1726           1 :                         return DECISION_FAILURE;
    1727             :                 }
    1728        1435 :                 if (id_req && sm->user &&
    1729           0 :                     sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
    1730           0 :                     sm->user->methods[0].method == EAP_TYPE_IDENTITY) {
    1731           0 :                         wpa_printf(MSG_DEBUG, "EAP: getDecision: stop "
    1732             :                                    "identity request loop -> FAILURE");
    1733           0 :                         sm->update_user = TRUE;
    1734           0 :                         return DECISION_FAILURE;
    1735             :                 }
    1736        1435 :                 sm->update_user = FALSE;
    1737             :         }
    1738        3271 :         sm->start_reauth = FALSE;
    1739             : 
    1740        4862 :         if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
    1741        1591 :             (sm->user->methods[sm->user_eap_method_index].vendor !=
    1742        1122 :              EAP_VENDOR_IETF ||
    1743        1122 :              sm->user->methods[sm->user_eap_method_index].method !=
    1744             :              EAP_TYPE_NONE)) {
    1745        1573 :                 wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
    1746             :                            "available -> CONTINUE");
    1747        1573 :                 return DECISION_CONTINUE;
    1748             :         }
    1749             : 
    1750        1759 :         if (!sm->identity && eap_get_erp_send_reauth_start(sm) &&
    1751          61 :             !sm->initiate_reauth_start_sent) {
    1752          41 :                 wpa_printf(MSG_DEBUG,
    1753             :                            "EAP: getDecision: send EAP-Initiate/Re-auth-Start");
    1754          41 :                 return DECISION_INITIATE_REAUTH_START;
    1755             :         }
    1756             : 
    1757        1657 :         if (sm->identity == NULL || sm->currentId == -1) {
    1758        1644 :                 wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
    1759             :                            "yet -> CONTINUE");
    1760        1644 :                 return DECISION_CONTINUE;
    1761             :         }
    1762             : 
    1763          13 :         wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> "
    1764             :                    "FAILURE");
    1765          13 :         return DECISION_FAILURE;
    1766             : }
    1767             : 
    1768             : 
    1769         791 : static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
    1770             : {
    1771         791 :         return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
    1772             : }
    1773             : 
    1774             : 
    1775             : /**
    1776             :  * eap_server_sm_step - Step EAP server state machine
    1777             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1778             :  * Returns: 1 if EAP state was changed or 0 if not
    1779             :  *
    1780             :  * This function advances EAP state machine to a new state to match with the
    1781             :  * current variables. This should be called whenever variables used by the EAP
    1782             :  * state machine have changed.
    1783             :  */
    1784       35319 : int eap_server_sm_step(struct eap_sm *sm)
    1785             : {
    1786       35319 :         int res = 0;
    1787             :         do {
    1788      110402 :                 sm->changed = FALSE;
    1789      110402 :                 SM_STEP_RUN(EAP);
    1790      110402 :                 if (sm->changed)
    1791       75083 :                         res = 1;
    1792      110402 :         } while (sm->changed);
    1793       35319 :         return res;
    1794             : }
    1795             : 
    1796             : 
    1797        4210 : static void eap_user_free(struct eap_user *user)
    1798             : {
    1799        4210 :         if (user == NULL)
    1800        6571 :                 return;
    1801        1849 :         bin_clear_free(user->password, user->password_len);
    1802        1849 :         user->password = NULL;
    1803        1849 :         os_free(user);
    1804             : }
    1805             : 
    1806             : 
    1807             : /**
    1808             :  * eap_server_sm_init - Allocate and initialize EAP server state machine
    1809             :  * @eapol_ctx: Context data to be used with eapol_cb calls
    1810             :  * @eapol_cb: Pointer to EAPOL callback functions
    1811             :  * @conf: EAP configuration
    1812             :  * Returns: Pointer to the allocated EAP state machine or %NULL on failure
    1813             :  *
    1814             :  * This function allocates and initializes an EAP state machine.
    1815             :  */
    1816        2353 : struct eap_sm * eap_server_sm_init(void *eapol_ctx,
    1817             :                                    const struct eapol_callbacks *eapol_cb,
    1818             :                                    struct eap_config *conf)
    1819             : {
    1820             :         struct eap_sm *sm;
    1821             : 
    1822        2353 :         sm = os_zalloc(sizeof(*sm));
    1823        2353 :         if (sm == NULL)
    1824           0 :                 return NULL;
    1825        2353 :         sm->eapol_ctx = eapol_ctx;
    1826        2353 :         sm->eapol_cb = eapol_cb;
    1827        2353 :         sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */
    1828        2353 :         sm->ssl_ctx = conf->ssl_ctx;
    1829        2353 :         sm->msg_ctx = conf->msg_ctx;
    1830        2353 :         sm->eap_sim_db_priv = conf->eap_sim_db_priv;
    1831        2353 :         sm->backend_auth = conf->backend_auth;
    1832        2353 :         sm->eap_server = conf->eap_server;
    1833        2353 :         if (conf->pac_opaque_encr_key) {
    1834         798 :                 sm->pac_opaque_encr_key = os_malloc(16);
    1835         798 :                 if (sm->pac_opaque_encr_key) {
    1836         798 :                         os_memcpy(sm->pac_opaque_encr_key,
    1837             :                                   conf->pac_opaque_encr_key, 16);
    1838             :                 }
    1839             :         }
    1840        2353 :         if (conf->eap_fast_a_id) {
    1841         798 :                 sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
    1842         798 :                 if (sm->eap_fast_a_id) {
    1843         798 :                         os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id,
    1844             :                                   conf->eap_fast_a_id_len);
    1845         798 :                         sm->eap_fast_a_id_len = conf->eap_fast_a_id_len;
    1846             :                 }
    1847             :         }
    1848        2353 :         if (conf->eap_fast_a_id_info)
    1849         798 :                 sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
    1850        2353 :         sm->eap_fast_prov = conf->eap_fast_prov;
    1851        2353 :         sm->pac_key_lifetime = conf->pac_key_lifetime;
    1852        2353 :         sm->pac_key_refresh_time = conf->pac_key_refresh_time;
    1853        2353 :         sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
    1854        2353 :         sm->tnc = conf->tnc;
    1855        2353 :         sm->wps = conf->wps;
    1856        2353 :         if (conf->assoc_wps_ie)
    1857         462 :                 sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie);
    1858        2353 :         if (conf->assoc_p2p_ie)
    1859         184 :                 sm->assoc_p2p_ie = wpabuf_dup(conf->assoc_p2p_ie);
    1860        2353 :         if (conf->peer_addr)
    1861        1541 :                 os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN);
    1862        2353 :         sm->fragment_size = conf->fragment_size;
    1863        2353 :         sm->pwd_group = conf->pwd_group;
    1864        2353 :         sm->pbc_in_m1 = conf->pbc_in_m1;
    1865        2353 :         sm->server_id = conf->server_id;
    1866        2353 :         sm->server_id_len = conf->server_id_len;
    1867        2353 :         sm->erp = conf->erp;
    1868        2353 :         sm->tls_session_lifetime = conf->tls_session_lifetime;
    1869             : 
    1870             : #ifdef CONFIG_TESTING_OPTIONS
    1871        2353 :         sm->tls_test_flags = conf->tls_test_flags;
    1872             : #endif /* CONFIG_TESTING_OPTIONS */
    1873             : 
    1874        2353 :         wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
    1875             : 
    1876        2353 :         return sm;
    1877             : }
    1878             : 
    1879             : 
    1880             : /**
    1881             :  * eap_server_sm_deinit - Deinitialize and free an EAP server state machine
    1882             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1883             :  *
    1884             :  * This function deinitializes EAP state machine and frees all allocated
    1885             :  * resources.
    1886             :  */
    1887        2353 : void eap_server_sm_deinit(struct eap_sm *sm)
    1888             : {
    1889        2353 :         if (sm == NULL)
    1890        2353 :                 return;
    1891        2353 :         wpa_printf(MSG_DEBUG, "EAP: Server state machine removed");
    1892        2353 :         if (sm->m && sm->eap_method_priv)
    1893        2261 :                 sm->m->reset(sm, sm->eap_method_priv);
    1894        2353 :         wpabuf_free(sm->eap_if.eapReqData);
    1895        2353 :         bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
    1896        2353 :         os_free(sm->eap_if.eapSessionId);
    1897        2353 :         wpabuf_free(sm->lastReqData);
    1898        2353 :         wpabuf_free(sm->eap_if.eapRespData);
    1899        2353 :         os_free(sm->identity);
    1900        2353 :         os_free(sm->pac_opaque_encr_key);
    1901        2353 :         os_free(sm->eap_fast_a_id);
    1902        2353 :         os_free(sm->eap_fast_a_id_info);
    1903        2353 :         wpabuf_free(sm->eap_if.aaaEapReqData);
    1904        2353 :         wpabuf_free(sm->eap_if.aaaEapRespData);
    1905        2353 :         bin_clear_free(sm->eap_if.aaaEapKeyData, sm->eap_if.aaaEapKeyDataLen);
    1906        2353 :         eap_user_free(sm->user);
    1907        2353 :         wpabuf_free(sm->assoc_wps_ie);
    1908        2353 :         wpabuf_free(sm->assoc_p2p_ie);
    1909        2353 :         os_free(sm);
    1910             : }
    1911             : 
    1912             : 
    1913             : /**
    1914             :  * eap_sm_notify_cached - Notify EAP state machine of cached PMK
    1915             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1916             :  *
    1917             :  * This function is called when PMKSA caching is used to skip EAP
    1918             :  * authentication.
    1919             :  */
    1920          37 : void eap_sm_notify_cached(struct eap_sm *sm)
    1921             : {
    1922          37 :         if (sm == NULL)
    1923          37 :                 return;
    1924             : 
    1925          37 :         sm->EAP_state = EAP_SUCCESS;
    1926             : }
    1927             : 
    1928             : 
    1929             : /**
    1930             :  * eap_sm_pending_cb - EAP state machine callback for a pending EAP request
    1931             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1932             :  *
    1933             :  * This function is called when data for a pending EAP-Request is received.
    1934             :  */
    1935         137 : void eap_sm_pending_cb(struct eap_sm *sm)
    1936             : {
    1937         137 :         if (sm == NULL)
    1938         137 :                 return;
    1939         137 :         wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received");
    1940         137 :         if (sm->method_pending == METHOD_PENDING_WAIT)
    1941         136 :                 sm->method_pending = METHOD_PENDING_CONT;
    1942             : }
    1943             : 
    1944             : 
    1945             : /**
    1946             :  * eap_sm_method_pending - Query whether EAP method is waiting for pending data
    1947             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1948             :  * Returns: 1 if method is waiting for pending data or 0 if not
    1949             :  */
    1950          91 : int eap_sm_method_pending(struct eap_sm *sm)
    1951             : {
    1952          91 :         if (sm == NULL)
    1953           0 :                 return 0;
    1954          91 :         return sm->method_pending == METHOD_PENDING_WAIT;
    1955             : }
    1956             : 
    1957             : 
    1958             : /**
    1959             :  * eap_get_identity - Get the user identity (from EAP-Response/Identity)
    1960             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1961             :  * @len: Buffer for returning identity length
    1962             :  * Returns: Pointer to the user identity or %NULL if not available
    1963             :  */
    1964        1067 : const u8 * eap_get_identity(struct eap_sm *sm, size_t *len)
    1965             : {
    1966        1067 :         *len = sm->identity_len;
    1967        1067 :         return sm->identity;
    1968             : }
    1969             : 
    1970             : 
    1971             : /**
    1972             :  * eap_get_interface - Get pointer to EAP-EAPOL interface data
    1973             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1974             :  * Returns: Pointer to the EAP-EAPOL interface data
    1975             :  */
    1976        2353 : struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm)
    1977             : {
    1978        2353 :         return &sm->eap_if;
    1979             : }
    1980             : 
    1981             : 
    1982             : /**
    1983             :  * eap_server_clear_identity - Clear EAP identity information
    1984             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1985             :  *
    1986             :  * This function can be used to clear the EAP identity information in the EAP
    1987             :  * server context. This allows the EAP/Identity method to be used again after
    1988             :  * EAPOL-Start or EAPOL-Logoff.
    1989             :  */
    1990         195 : void eap_server_clear_identity(struct eap_sm *sm)
    1991             : {
    1992         195 :         os_free(sm->identity);
    1993         195 :         sm->identity = NULL;
    1994         195 : }
    1995             : 
    1996             : 
    1997             : #ifdef CONFIG_TESTING_OPTIONS
    1998         159 : void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source,
    1999             :                                    const u8 *username, size_t username_len,
    2000             :                                    const u8 *challenge, const u8 *response)
    2001             : {
    2002             :         char hex_challenge[30], hex_response[90], user[100];
    2003             : 
    2004             :         /* Print out Challenge and Response in format supported by asleap. */
    2005         159 :         if (username)
    2006         159 :                 printf_encode(user, sizeof(user), username, username_len);
    2007             :         else
    2008           0 :                 user[0] = '\0';
    2009         159 :         wpa_snprintf_hex_sep(hex_challenge, sizeof(hex_challenge),
    2010             :                              challenge, sizeof(challenge), ':');
    2011         159 :         wpa_snprintf_hex_sep(hex_response, sizeof(hex_response), response, 24,
    2012             :                              ':');
    2013         159 :         wpa_printf(MSG_DEBUG, "[%s/user=%s] asleap -C %s -R %s",
    2014             :                    source, user, hex_challenge, hex_response);
    2015         159 : }
    2016             : #endif /* CONFIG_TESTING_OPTIONS */

Generated by: LCOV version 1.10