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 1475438200 Lines: 921 1054 87.4 %
Date: 2016-10-02 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        2928 : static int eap_get_erp_send_reauth_start(struct eap_sm *sm)
      49             : {
      50        2928 :         if (sm->eapol_cb->get_erp_send_reauth_start)
      51        2912 :                 return sm->eapol_cb->get_erp_send_reauth_start(sm->eapol_ctx);
      52          16 :         return 0;
      53             : }
      54             : 
      55             : 
      56         106 : static const char * eap_get_erp_domain(struct eap_sm *sm)
      57             : {
      58         106 :         if (sm->eapol_cb->get_erp_domain)
      59         106 :                 return sm->eapol_cb->get_erp_domain(sm->eapol_ctx);
      60           0 :         return NULL;
      61             : }
      62             : 
      63             : 
      64             : #ifdef CONFIG_ERP
      65             : 
      66          27 : static struct eap_server_erp_key * eap_erp_get_key(struct eap_sm *sm,
      67             :                                                    const char *keyname)
      68             : {
      69          27 :         if (sm->eapol_cb->erp_get_key)
      70          27 :                 return sm->eapol_cb->erp_get_key(sm->eapol_ctx, keyname);
      71           0 :         return NULL;
      72             : }
      73             : 
      74             : 
      75          38 : static int eap_erp_add_key(struct eap_sm *sm, struct eap_server_erp_key *erp)
      76             : {
      77          38 :         if (sm->eapol_cb->erp_add_key)
      78          38 :                 return sm->eapol_cb->erp_add_key(sm->eapol_ctx, erp);
      79           0 :         return -1;
      80             : }
      81             : 
      82             : #endif /* CONFIG_ERP */
      83             : 
      84             : 
      85          68 : static struct wpabuf * eap_sm_buildInitiateReauthStart(struct eap_sm *sm,
      86             :                                                        u8 id)
      87             : {
      88             :         const char *domain;
      89          68 :         size_t plen = 1;
      90             :         struct wpabuf *msg;
      91          68 :         size_t domain_len = 0;
      92             : 
      93          68 :         domain = eap_get_erp_domain(sm);
      94          68 :         if (domain) {
      95          68 :                 domain_len = os_strlen(domain);
      96          68 :                 plen += 2 + domain_len;
      97             :         }
      98             : 
      99          68 :         msg = eap_msg_alloc(EAP_VENDOR_IETF,
     100             :                             (EapType) EAP_ERP_TYPE_REAUTH_START, plen,
     101             :                             EAP_CODE_INITIATE, id);
     102          68 :         if (msg == NULL)
     103           0 :                 return NULL;
     104          68 :         wpabuf_put_u8(msg, 0); /* Reserved */
     105          68 :         if (domain) {
     106             :                 /* Domain name TLV */
     107          68 :                 wpabuf_put_u8(msg, EAP_ERP_TLV_DOMAIN_NAME);
     108          68 :                 wpabuf_put_u8(msg, domain_len);
     109          68 :                 wpabuf_put_data(msg, domain, domain_len);
     110             :         }
     111             : 
     112          68 :         return msg;
     113             : }
     114             : 
     115             : 
     116       32191 : static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src)
     117             : {
     118       32191 :         if (src == NULL)
     119           5 :                 return -1;
     120             : 
     121       32186 :         wpabuf_free(*dst);
     122       32186 :         *dst = wpabuf_dup(src);
     123       32186 :         return *dst ? 0 : -1;
     124             : }
     125             : 
     126             : 
     127        1102 : static int eap_copy_data(u8 **dst, size_t *dst_len,
     128             :                          const u8 *src, size_t src_len)
     129             : {
     130        1102 :         if (src == NULL)
     131           0 :                 return -1;
     132             : 
     133        1102 :         os_free(*dst);
     134        1102 :         *dst = os_malloc(src_len);
     135        1102 :         if (*dst) {
     136        1101 :                 os_memcpy(*dst, src, src_len);
     137        1101 :                 *dst_len = src_len;
     138        1101 :                 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        3586 : 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        7172 :         if (sm == NULL || sm->eapol_cb == NULL ||
     168        3586 :             sm->eapol_cb->get_eap_user == NULL)
     169           0 :                 return -1;
     170             : 
     171        3586 :         eap_user_free(sm->user);
     172        3586 :         sm->user = NULL;
     173             : 
     174        3586 :         user = os_zalloc(sizeof(*user));
     175        3586 :         if (user == NULL)
     176           3 :             return -1;
     177             : 
     178        3583 :         if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity,
     179             :                                        identity_len, phase2, user) != 0) {
     180           8 :                 eap_user_free(user);
     181           8 :                 return -1;
     182             :         }
     183             : 
     184        3575 :         sm->user = user;
     185        3575 :         sm->user_eap_method_index = 0;
     186             : 
     187        3575 :         return 0;
     188             : }
     189             : 
     190             : 
     191       10784 : void eap_log_msg(struct eap_sm *sm, const char *fmt, ...)
     192             : {
     193             :         va_list ap;
     194             :         char *buf;
     195             :         int buflen;
     196             : 
     197       10784 :         if (sm == NULL || sm->eapol_cb == NULL || sm->eapol_cb->log_msg == NULL)
     198       13818 :                 return;
     199             : 
     200        3875 :         va_start(ap, fmt);
     201        3875 :         buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
     202        3875 :         va_end(ap);
     203             : 
     204        3875 :         buf = os_malloc(buflen);
     205        3875 :         if (buf == NULL)
     206           0 :                 return;
     207        3875 :         va_start(ap, fmt);
     208        3875 :         vsnprintf(buf, buflen, fmt, ap);
     209        3875 :         va_end(ap);
     210             : 
     211        3875 :         sm->eapol_cb->log_msg(sm->eapol_ctx, buf);
     212             : 
     213        3875 :         os_free(buf);
     214             : }
     215             : 
     216             : 
     217        3862 : SM_STATE(EAP, DISABLED)
     218             : {
     219        3862 :         SM_ENTRY(EAP, DISABLED);
     220        3862 :         sm->num_rounds = 0;
     221        3862 : }
     222             : 
     223             : 
     224        4663 : SM_STATE(EAP, INITIALIZE)
     225             : {
     226        4663 :         SM_ENTRY(EAP, INITIALIZE);
     227             : 
     228        4663 :         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          97 :                 eap_server_clear_identity(sm);
     234             :         }
     235             : 
     236        4663 :         sm->try_initiate_reauth = FALSE;
     237        4663 :         sm->currentId = -1;
     238        4663 :         sm->eap_if.eapSuccess = FALSE;
     239        4663 :         sm->eap_if.eapFail = FALSE;
     240        4663 :         sm->eap_if.eapTimeout = FALSE;
     241        4663 :         bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
     242        4663 :         sm->eap_if.eapKeyData = NULL;
     243        4663 :         sm->eap_if.eapKeyDataLen = 0;
     244        4663 :         os_free(sm->eap_if.eapSessionId);
     245        4663 :         sm->eap_if.eapSessionId = NULL;
     246        4663 :         sm->eap_if.eapSessionIdLen = 0;
     247        4663 :         sm->eap_if.eapKeyAvailable = FALSE;
     248        4663 :         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        4663 :         if (sm->m && sm->eap_method_priv) {
     256         298 :                 sm->m->reset(sm, sm->eap_method_priv);
     257         298 :                 sm->eap_method_priv = NULL;
     258             :         }
     259        4663 :         sm->m = NULL;
     260        4663 :         sm->user_eap_method_index = 0;
     261             : 
     262        4663 :         if (sm->backend_auth) {
     263        1656 :                 sm->currentMethod = EAP_TYPE_NONE;
     264             :                 /* parse rxResp, respId, respMethod */
     265        1656 :                 eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
     266        1656 :                 if (sm->rxResp) {
     267        1640 :                         sm->currentId = sm->respId;
     268             :                 }
     269             :         }
     270        4663 :         sm->num_rounds = 0;
     271        4663 :         sm->method_pending = METHOD_PENDING_NONE;
     272             : 
     273       27978 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
     274       27978 :                 MACSTR, MAC2STR(sm->peer_addr));
     275        4663 : }
     276             : 
     277             : 
     278        1640 : SM_STATE(EAP, PICK_UP_METHOD)
     279             : {
     280        1640 :         SM_ENTRY(EAP, PICK_UP_METHOD);
     281             : 
     282        1640 :         if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) {
     283        1640 :                 sm->currentMethod = sm->respMethod;
     284        1640 :                 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        1640 :                 sm->m = eap_server_get_eap_method(EAP_VENDOR_IETF,
     289             :                                                   sm->currentMethod);
     290        1640 :                 if (sm->m && sm->m->initPickUp) {
     291        1640 :                         sm->eap_method_priv = sm->m->initPickUp(sm);
     292        3280 :                         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        1640 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
     306        1640 :                 "method=%u", sm->currentMethod);
     307        1640 : }
     308             : 
     309             : 
     310       11954 : SM_STATE(EAP, IDLE)
     311             : {
     312       11954 :         SM_ENTRY(EAP, IDLE);
     313             : 
     314       11954 :         sm->eap_if.retransWhile = eap_sm_calculateTimeout(
     315             :                 sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR,
     316             :                 sm->methodTimeout);
     317       11954 : }
     318             : 
     319             : 
     320           4 : SM_STATE(EAP, RETRANSMIT)
     321             : {
     322           4 :         SM_ENTRY(EAP, RETRANSMIT);
     323             : 
     324           4 :         sm->retransCount++;
     325           4 :         if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
     326           4 :                 if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
     327           4 :                         sm->eap_if.eapReq = TRUE;
     328             :         }
     329           4 : }
     330             : 
     331             : 
     332       11490 : SM_STATE(EAP, RECEIVED)
     333             : {
     334       11490 :         SM_ENTRY(EAP, RECEIVED);
     335             : 
     336             :         /* parse rxResp, respId, respMethod */
     337       11490 :         eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
     338       11490 :         sm->num_rounds++;
     339       11490 : }
     340             : 
     341             : 
     342           9 : SM_STATE(EAP, DISCARD)
     343             : {
     344           9 :         SM_ENTRY(EAP, DISCARD);
     345           9 :         sm->eap_if.eapResp = FALSE;
     346           9 :         sm->eap_if.eapNoReq = TRUE;
     347           9 : }
     348             : 
     349             : 
     350       11962 : SM_STATE(EAP, SEND_REQUEST)
     351             : {
     352       11962 :         SM_ENTRY(EAP, SEND_REQUEST);
     353             : 
     354       11962 :         sm->retransCount = 0;
     355       11962 :         if (sm->eap_if.eapReqData) {
     356       11942 :                 if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
     357             :                 {
     358       11937 :                         sm->eap_if.eapResp = FALSE;
     359       11937 :                         sm->eap_if.eapReq = TRUE;
     360             :                 } else {
     361           5 :                         sm->eap_if.eapResp = FALSE;
     362           5 :                         sm->eap_if.eapReq = FALSE;
     363             :                 }
     364             :         } else {
     365          20 :                 wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData");
     366          20 :                 sm->eap_if.eapResp = FALSE;
     367          20 :                 sm->eap_if.eapReq = FALSE;
     368          20 :                 sm->eap_if.eapNoReq = TRUE;
     369             :         }
     370       11962 : }
     371             : 
     372             : 
     373       11058 : SM_STATE(EAP, INTEGRITY_CHECK)
     374             : {
     375       11058 :         SM_ENTRY(EAP, INTEGRITY_CHECK);
     376             : 
     377       11058 :         if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) {
     378           0 :                 sm->ignore = TRUE;
     379       11058 :                 return;
     380             :         }
     381             : 
     382       11058 :         if (sm->m->check) {
     383       11058 :                 sm->ignore = sm->m->check(sm, sm->eap_method_priv,
     384             :                                           sm->eap_if.eapRespData);
     385             :         }
     386             : }
     387             : 
     388             : 
     389       11898 : SM_STATE(EAP, METHOD_REQUEST)
     390             : {
     391       11898 :         SM_ENTRY(EAP, METHOD_REQUEST);
     392             : 
     393       11898 :         if (sm->m == NULL) {
     394           4 :                 wpa_printf(MSG_DEBUG, "EAP: method not initialized");
     395       11902 :                 return;
     396             :         }
     397             : 
     398       11894 :         sm->currentId = eap_sm_nextId(sm, sm->currentId);
     399       11894 :         wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d",
     400             :                    sm->currentId);
     401       11894 :         sm->lastId = sm->currentId;
     402       11894 :         wpabuf_free(sm->eap_if.eapReqData);
     403       23788 :         sm->eap_if.eapReqData = sm->m->buildReq(sm, sm->eap_method_priv,
     404       11894 :                                                 sm->currentId);
     405       11894 :         if (sm->m->getTimeout)
     406        2190 :                 sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv);
     407             :         else
     408        9704 :                 sm->methodTimeout = 0;
     409             : }
     410             : 
     411             : 
     412          38 : static void eap_server_erp_init(struct eap_sm *sm)
     413             : {
     414             : #ifdef CONFIG_ERP
     415          38 :         u8 *emsk = NULL;
     416          38 :         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          38 :         struct eap_server_erp_key *erp = NULL;
     422             :         int pos;
     423             : 
     424          38 :         domain = eap_get_erp_domain(sm);
     425          38 :         if (!domain)
     426           0 :                 return;
     427             : 
     428          38 :         domain_len = os_strlen(domain);
     429             : 
     430          38 :         nai_buf_len = 2 * EAP_EMSK_NAME_LEN + 1 + domain_len;
     431          38 :         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          38 :         nai_buf_len++; /* null termination */
     441          38 :         erp = os_zalloc(sizeof(*erp) + nai_buf_len);
     442          38 :         if (erp == NULL)
     443           0 :                 goto fail;
     444          38 :         erp->recv_seq = (u32) -1;
     445             : 
     446          38 :         emsk = sm->m->get_emsk(sm, sm->eap_method_priv, &emsk_len);
     447          38 :         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          38 :         wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
     454             : 
     455          38 :         WPA_PUT_BE16(len, 8);
     456          38 :         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          38 :         wpa_hexdump(MSG_DEBUG, "EAP: EMSKname", EMSKname, EAP_EMSK_NAME_LEN);
     463             : 
     464          38 :         pos = wpa_snprintf_hex(erp->keyname_nai, nai_buf_len,
     465             :                                EMSKname, EAP_EMSK_NAME_LEN);
     466          38 :         erp->keyname_nai[pos] = '@';
     467          38 :         os_memcpy(&erp->keyname_nai[pos + 1], domain, domain_len);
     468             : 
     469          38 :         WPA_PUT_BE16(len, emsk_len);
     470          76 :         if (hmac_sha256_kdf(emsk, emsk_len,
     471             :                             "EAP Re-authentication Root Key@ietf.org",
     472          38 :                             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          38 :         erp->rRK_len = emsk_len;
     477          38 :         wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
     478             : 
     479          76 :         if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
     480             :                             "EAP Re-authentication Integrity Key@ietf.org",
     481          38 :                             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          38 :         erp->rIK_len = erp->rRK_len;
     486          38 :         wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rIK", erp->rIK, erp->rIK_len);
     487             : 
     488          38 :         if (eap_erp_add_key(sm, erp) == 0) {
     489          38 :                 wpa_printf(MSG_DEBUG, "EAP: Stored ERP keys %s",
     490          38 :                            erp->keyname_nai);
     491          38 :                 erp = NULL;
     492             :         }
     493             : 
     494             : fail:
     495          38 :         bin_clear_free(emsk, emsk_len);
     496          38 :         bin_clear_free(erp, sizeof(*erp));
     497             : #endif /* CONFIG_ERP */
     498             : }
     499             : 
     500             : 
     501       12883 : SM_STATE(EAP, METHOD_RESPONSE)
     502             : {
     503       12883 :         SM_ENTRY(EAP, METHOD_RESPONSE);
     504             : 
     505       12883 :         if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1))
     506       12883 :                 return;
     507             : 
     508       12883 :         sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData);
     509       12883 :         if (sm->m->isDone(sm, sm->eap_method_priv)) {
     510        6509 :                 eap_sm_Policy_update(sm, NULL, 0);
     511        6509 :                 bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
     512        6509 :                 if (sm->m->getKey) {
     513        1525 :                         sm->eap_if.eapKeyData = sm->m->getKey(
     514             :                                 sm, sm->eap_method_priv,
     515             :                                 &sm->eap_if.eapKeyDataLen);
     516             :                 } else {
     517        4984 :                         sm->eap_if.eapKeyData = NULL;
     518        4984 :                         sm->eap_if.eapKeyDataLen = 0;
     519             :                 }
     520        6509 :                 os_free(sm->eap_if.eapSessionId);
     521        6509 :                 sm->eap_if.eapSessionId = NULL;
     522        6509 :                 if (sm->m->getSessionId) {
     523        1514 :                         sm->eap_if.eapSessionId = sm->m->getSessionId(
     524             :                                 sm, sm->eap_method_priv,
     525             :                                 &sm->eap_if.eapSessionIdLen);
     526        3028 :                         wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
     527        1514 :                                     sm->eap_if.eapSessionId,
     528             :                                     sm->eap_if.eapSessionIdLen);
     529             :                 }
     530        6509 :                 if (sm->erp && sm->m->get_emsk && sm->eap_if.eapSessionId)
     531          38 :                         eap_server_erp_init(sm);
     532        6509 :                 sm->methodState = METHOD_END;
     533             :         } else {
     534        6374 :                 sm->methodState = METHOD_CONTINUE;
     535             :         }
     536             : }
     537             : 
     538             : 
     539        5710 : SM_STATE(EAP, PROPOSE_METHOD)
     540             : {
     541             :         int vendor;
     542             :         EapType type;
     543             : 
     544        5710 :         SM_ENTRY(EAP, PROPOSE_METHOD);
     545             : 
     546        5710 :         sm->try_initiate_reauth = FALSE;
     547             : try_another_method:
     548        5716 :         type = eap_sm_Policy_getNextMethod(sm, &vendor);
     549        5716 :         if (vendor == EAP_VENDOR_IETF)
     550        5158 :                 sm->currentMethod = type;
     551             :         else
     552         558 :                 sm->currentMethod = EAP_TYPE_EXPANDED;
     553        5716 :         if (sm->m && sm->eap_method_priv) {
     554        2478 :                 sm->m->reset(sm, sm->eap_method_priv);
     555        2478 :                 sm->eap_method_priv = NULL;
     556             :         }
     557        5716 :         sm->m = eap_server_get_eap_method(vendor, type);
     558        5716 :         if (sm->m) {
     559        5712 :                 sm->eap_method_priv = sm->m->init(sm);
     560        5712 :                 if (sm->eap_method_priv == NULL) {
     561           6 :                         wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP "
     562           6 :                                    "method %d", sm->currentMethod);
     563           6 :                         sm->m = NULL;
     564           6 :                         sm->currentMethod = EAP_TYPE_NONE;
     565           6 :                         goto try_another_method;
     566             :                 }
     567             :         }
     568        5710 :         if (sm->m == NULL) {
     569           4 :                 wpa_printf(MSG_DEBUG, "EAP: Could not find suitable EAP method");
     570           4 :                 eap_log_msg(sm, "Could not find suitable EAP method");
     571           4 :                 sm->decision = DECISION_FAILURE;
     572        5714 :                 return;
     573             :         }
     574        8473 :         if (sm->currentMethod == EAP_TYPE_IDENTITY ||
     575        2767 :             sm->currentMethod == EAP_TYPE_NOTIFICATION)
     576        2939 :                 sm->methodState = METHOD_CONTINUE;
     577             :         else
     578        2767 :                 sm->methodState = METHOD_PROPOSED;
     579             : 
     580        5706 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
     581        5706 :                 "vendor=%u method=%u", vendor, sm->currentMethod);
     582        5706 :         eap_log_msg(sm, "Propose EAP method vendor=%u method=%u",
     583        5706 :                     vendor, sm->currentMethod);
     584             : }
     585             : 
     586             : 
     587         396 : SM_STATE(EAP, NAK)
     588             : {
     589             :         const struct eap_hdr *nak;
     590         396 :         size_t len = 0;
     591             :         const u8 *pos;
     592         396 :         const u8 *nak_list = NULL;
     593             : 
     594         396 :         SM_ENTRY(EAP, NAK);
     595             : 
     596         396 :         if (sm->eap_method_priv) {
     597         396 :                 sm->m->reset(sm, sm->eap_method_priv);
     598         396 :                 sm->eap_method_priv = NULL;
     599             :         }
     600         396 :         sm->m = NULL;
     601             : 
     602         396 :         if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1))
     603         396 :                 return;
     604             : 
     605         396 :         nak = wpabuf_head(sm->eap_if.eapRespData);
     606         396 :         if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) {
     607         396 :                 len = be_to_host16(nak->length);
     608         396 :                 if (len > wpabuf_len(sm->eap_if.eapRespData))
     609           0 :                         len = wpabuf_len(sm->eap_if.eapRespData);
     610         396 :                 pos = (const u8 *) (nak + 1);
     611         396 :                 len -= sizeof(*nak);
     612         396 :                 if (*pos == EAP_TYPE_NAK) {
     613         377 :                         pos++;
     614         377 :                         len--;
     615         377 :                         nak_list = pos;
     616             :                 }
     617             :         }
     618         396 :         eap_sm_Policy_update(sm, nak_list, len);
     619             : }
     620             : 
     621             : 
     622        9944 : SM_STATE(EAP, SELECT_ACTION)
     623             : {
     624        9944 :         SM_ENTRY(EAP, SELECT_ACTION);
     625             : 
     626        9944 :         sm->decision = eap_sm_Policy_getDecision(sm);
     627        9944 : }
     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         832 : SM_STATE(EAP, FAILURE)
     639             : {
     640         832 :         SM_ENTRY(EAP, FAILURE);
     641             : 
     642         832 :         wpabuf_free(sm->eap_if.eapReqData);
     643         832 :         sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId);
     644         832 :         wpabuf_free(sm->lastReqData);
     645         832 :         sm->lastReqData = NULL;
     646         832 :         sm->eap_if.eapFail = TRUE;
     647             : 
     648        4992 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
     649        4992 :                 MACSTR, MAC2STR(sm->peer_addr));
     650         832 : }
     651             : 
     652             : 
     653        1265 : SM_STATE(EAP, SUCCESS)
     654             : {
     655        1265 :         SM_ENTRY(EAP, SUCCESS);
     656             : 
     657        1265 :         wpabuf_free(sm->eap_if.eapReqData);
     658        1265 :         sm->eap_if.eapReqData = eap_sm_buildSuccess(sm, sm->currentId);
     659        1265 :         wpabuf_free(sm->lastReqData);
     660        1265 :         sm->lastReqData = NULL;
     661        1265 :         if (sm->eap_if.eapKeyData)
     662        1263 :                 sm->eap_if.eapKeyAvailable = TRUE;
     663        1265 :         sm->eap_if.eapSuccess = TRUE;
     664             : 
     665        7590 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
     666        7590 :                 MACSTR, MAC2STR(sm->peer_addr));
     667        1265 : }
     668             : 
     669             : 
     670          68 : SM_STATE(EAP, INITIATE_REAUTH_START)
     671             : {
     672          68 :         SM_ENTRY(EAP, INITIATE_REAUTH_START);
     673             : 
     674          68 :         sm->initiate_reauth_start_sent = TRUE;
     675          68 :         sm->try_initiate_reauth = TRUE;
     676          68 :         sm->currentId = eap_sm_nextId(sm, sm->currentId);
     677          68 :         wpa_printf(MSG_DEBUG,
     678             :                    "EAP: building EAP-Initiate-Re-auth-Start: Identifier %d",
     679             :                    sm->currentId);
     680          68 :         sm->lastId = sm->currentId;
     681          68 :         wpabuf_free(sm->eap_if.eapReqData);
     682          68 :         sm->eap_if.eapReqData = eap_sm_buildInitiateReauthStart(sm,
     683          68 :                                                                 sm->currentId);
     684          68 :         wpabuf_free(sm->lastReqData);
     685          68 :         sm->lastReqData = NULL;
     686          68 : }
     687             : 
     688             : 
     689             : #ifdef CONFIG_ERP
     690             : 
     691          27 : 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          27 :         if (erp) {
     702          26 :                 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          26 :                         hash_len = 16;
     708          26 :                         break;
     709             :                 default:
     710           1 :                         return;
     711             :                 }
     712             :         } else
     713           1 :                 hash_len = 0;
     714             : 
     715          27 :         plen = 1 + 2 + 2 + os_strlen(nai);
     716          27 :         if (hash_len)
     717          26 :                 plen += 1 + hash_len;
     718          27 :         msg = eap_msg_alloc(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
     719             :                             plen, EAP_CODE_FINISH, id);
     720          27 :         if (msg == NULL)
     721           0 :                 return;
     722          27 :         wpabuf_put_u8(msg, flags);
     723          27 :         wpabuf_put_be16(msg, seq);
     724             : 
     725          27 :         wpabuf_put_u8(msg, EAP_ERP_TLV_KEYNAME_NAI);
     726          27 :         wpabuf_put_u8(msg, os_strlen(nai));
     727          27 :         wpabuf_put_str(msg, nai);
     728             : 
     729          27 :         if (erp) {
     730          26 :                 wpabuf_put_u8(msg, erp->cryptosuite);
     731          52 :                 if (hmac_sha256(erp->rIK, erp->rIK_len,
     732          26 :                                 wpabuf_head(msg), wpabuf_len(msg), hash) < 0) {
     733           0 :                         wpabuf_free(msg);
     734           0 :                         return;
     735             :                 }
     736          26 :                 wpabuf_put_data(msg, hash, hash_len);
     737             :         }
     738             : 
     739          27 :         wpa_printf(MSG_DEBUG, "EAP: Send EAP-Finish/Re-auth (%s)",
     740          27 :                    flags & 0x80 ? "failure" : "success");
     741             : 
     742          27 :         sm->lastId = sm->currentId;
     743          27 :         sm->currentId = id;
     744          27 :         wpabuf_free(sm->eap_if.eapReqData);
     745          27 :         sm->eap_if.eapReqData = msg;
     746          27 :         wpabuf_free(sm->lastReqData);
     747          27 :         sm->lastReqData = NULL;
     748             : 
     749          27 :         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          26 :         bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
     757          26 :         sm->eap_if.eapKeyDataLen = 0;
     758          26 :         sm->eap_if.eapKeyData = os_malloc(erp->rRK_len);
     759          26 :         if (!sm->eap_if.eapKeyData)
     760           0 :                 return;
     761             : 
     762          26 :         WPA_PUT_BE16(seed, seq);
     763          26 :         WPA_PUT_BE16(&seed[2], erp->rRK_len);
     764          26 :         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          26 :         sm->eap_if.eapKeyDataLen = erp->rRK_len;
     774          26 :         sm->eap_if.eapKeyAvailable = TRUE;
     775          52 :         wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
     776          26 :                         sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
     777          26 :         sm->eap_if.eapSuccess = TRUE;
     778             : 
     779         156 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
     780         156 :                 MACSTR, MAC2STR(sm->peer_addr));
     781             : }
     782             : 
     783             : 
     784          43 : 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          43 :         u8 resp_flags = 0x80; /* default to failure; cleared on success */
     798             : 
     799          43 :         SM_ENTRY(EAP, INITIATE_RECEIVED);
     800             : 
     801          43 :         sm->rxInitiate = FALSE;
     802             : 
     803          43 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
     804          43 :                                sm->eap_if.eapRespData, &len);
     805          43 :         if (pos == NULL) {
     806           0 :                 wpa_printf(MSG_INFO, "EAP-Initiate: Invalid frame");
     807           0 :                 goto fail;
     808             :         }
     809          43 :         hdr = wpabuf_head(sm->eap_if.eapRespData);
     810          43 :         ehdr = wpabuf_head(sm->eap_if.eapRespData);
     811             : 
     812          43 :         wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth", pos, len);
     813          43 :         if (len < 4) {
     814           0 :                 wpa_printf(MSG_INFO, "EAP: Too short EAP-Initiate/Re-auth");
     815           0 :                 goto fail;
     816             :         }
     817          43 :         end = pos + len;
     818             : 
     819          43 :         flags = *pos++;
     820          43 :         seq = WPA_GET_BE16(pos);
     821          43 :         pos += 2;
     822          43 :         wpa_printf(MSG_DEBUG, "EAP: Flags=0x%x SEQ=%u", flags, seq);
     823          43 :         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          43 :         if (erp_parse_tlvs(tlvs, end, &parse, 1) < 0)
     832           0 :                 goto fail;
     833             : 
     834          43 :         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          86 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Initiate/Re-auth - keyName-NAI",
     841          86 :                           parse.keyname, parse.keyname_len);
     842          43 :         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          43 :         os_memcpy(nai, parse.keyname, parse.keyname_len);
     848          43 :         nai[parse.keyname_len] = '\0';
     849             : 
     850          43 :         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          59 :                 return;
     866             :         }
     867             : 
     868          27 :         erp = eap_erp_get_key(sm, nai);
     869          27 :         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          26 :         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          26 :         start = parse.keyname + parse.keyname_len;
     884          26 :         max_len = end - start;
     885          26 :         if (max_len <
     886          26 :             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          26 :         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           6 :                 if (end[-17] != erp->cryptosuite) {
     903           0 :                         wpa_printf(MSG_DEBUG,
     904             :                                    "EAP: Different Cryptosuite used");
     905           0 :                         goto fail;
     906             :                 }
     907           6 :                 hash_len = 16;
     908           6 :                 break;
     909             :         default:
     910          20 :                 hash_len = 0;
     911          20 :                 break;
     912             :         }
     913             : 
     914          26 :         if (hash_len) {
     915           6 :                 if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
     916           6 :                                 end - hdr - hash_len, hash) < 0)
     917           0 :                         goto fail;
     918           6 :                 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          26 :         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          26 :         if (!hash_len && end[-17] == EAP_ERP_CS_HMAC_SHA256_128) {
     940          20 :                 if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
     941          20 :                                 end - hdr - 16, hash) < 0)
     942           0 :                         goto fail;
     943          20 :                 if (os_memcmp(end - 16, hash, 16) == 0) {
     944          20 :                         wpa_printf(MSG_DEBUG,
     945             :                                    "EAP: Authentication Tag match using HMAC-SHA256-128");
     946          20 :                         hash_len = 16;
     947          20 :                         erp->cryptosuite = EAP_ERP_CS_HMAC_SHA256_128;
     948             :                 }
     949             :         }
     950             : 
     951          26 :         if (!hash_len) {
     952           0 :                 wpa_printf(MSG_DEBUG,
     953             :                            "EAP: No supported cryptosuite matched Authentication Tag");
     954           0 :                 goto fail;
     955             :         }
     956          26 :         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          26 :         wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth TVs/TLVs",
     963          26 :                     tlvs, end - tlvs);
     964          26 :         if (erp_parse_tlvs(tlvs, end, &parse, 0) < 0)
     965           0 :                 goto fail;
     966             : 
     967          52 :         wpa_printf(MSG_DEBUG, "EAP: ERP key %s SEQ updated to %u",
     968          26 :                    erp->keyname_nai, seq);
     969          26 :         erp->recv_seq = seq;
     970          26 :         resp_flags &= ~0x80; /* R=0 - success */
     971             : 
     972             : report_error:
     973          27 :         erp_send_finish_reauth(sm, erp, ehdr->identifier, resp_flags, seq, nai);
     974          27 :         return;
     975             : 
     976             : fail:
     977           0 :         sm->ignore = TRUE;
     978             : }
     979             : 
     980             : #endif /* CONFIG_ERP */
     981             : 
     982             : 
     983        2079 : SM_STATE(EAP, INITIALIZE_PASSTHROUGH)
     984             : {
     985        2079 :         SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH);
     986             : 
     987        2079 :         wpabuf_free(sm->eap_if.aaaEapRespData);
     988        2079 :         sm->eap_if.aaaEapRespData = NULL;
     989        2079 :         sm->try_initiate_reauth = FALSE;
     990        2079 : }
     991             : 
     992             : 
     993        5837 : SM_STATE(EAP, IDLE2)
     994             : {
     995        5837 :         SM_ENTRY(EAP, IDLE2);
     996             : 
     997        5837 :         sm->eap_if.retransWhile = eap_sm_calculateTimeout(
     998             :                 sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR,
     999             :                 sm->methodTimeout);
    1000        5837 : }
    1001             : 
    1002             : 
    1003           6 : SM_STATE(EAP, RETRANSMIT2)
    1004             : {
    1005           6 :         SM_ENTRY(EAP, RETRANSMIT2);
    1006             : 
    1007           6 :         sm->retransCount++;
    1008           6 :         if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
    1009           6 :                 if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
    1010           6 :                         sm->eap_if.eapReq = TRUE;
    1011             :         }
    1012           6 : }
    1013             : 
    1014             : 
    1015        5201 : SM_STATE(EAP, RECEIVED2)
    1016             : {
    1017        5201 :         SM_ENTRY(EAP, RECEIVED2);
    1018             : 
    1019             :         /* parse rxResp, respId, respMethod */
    1020        5201 :         eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
    1021        5201 : }
    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        5829 : SM_STATE(EAP, SEND_REQUEST2)
    1033             : {
    1034        5829 :         SM_ENTRY(EAP, SEND_REQUEST2);
    1035             : 
    1036        5829 :         sm->retransCount = 0;
    1037        5829 :         if (sm->eap_if.eapReqData) {
    1038        5827 :                 if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
    1039             :                 {
    1040        5827 :                         sm->eap_if.eapResp = FALSE;
    1041        5827 :                         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        5829 : }
    1053             : 
    1054             : 
    1055        7278 : SM_STATE(EAP, AAA_REQUEST)
    1056             : {
    1057        7278 :         SM_ENTRY(EAP, AAA_REQUEST);
    1058             : 
    1059        7278 :         if (sm->eap_if.eapRespData == NULL) {
    1060           0 :                 wpa_printf(MSG_INFO, "EAP: AAA_REQUEST - no eapRespData");
    1061        7278 :                 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        7278 :         eap_copy_buf(&sm->eap_if.aaaEapRespData, sm->eap_if.eapRespData);
    1072             : }
    1073             : 
    1074             : 
    1075        5829 : SM_STATE(EAP, AAA_RESPONSE)
    1076             : {
    1077        5829 :         SM_ENTRY(EAP, AAA_RESPONSE);
    1078             : 
    1079        5829 :         eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
    1080        5829 :         sm->currentId = eap_sm_getId(sm->eap_if.eapReqData);
    1081        5829 :         sm->methodTimeout = sm->eap_if.aaaMethodTimeout;
    1082        5829 : }
    1083             : 
    1084             : 
    1085        7278 : SM_STATE(EAP, AAA_IDLE)
    1086             : {
    1087        7278 :         SM_ENTRY(EAP, AAA_IDLE);
    1088             : 
    1089        7278 :         sm->eap_if.aaaFail = FALSE;
    1090        7278 :         sm->eap_if.aaaSuccess = FALSE;
    1091        7278 :         sm->eap_if.aaaEapReq = FALSE;
    1092        7278 :         sm->eap_if.aaaEapNoReq = FALSE;
    1093        7278 :         sm->eap_if.aaaEapResp = TRUE;
    1094        7278 : }
    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         186 : SM_STATE(EAP, FAILURE2)
    1106             : {
    1107         186 :         SM_ENTRY(EAP, FAILURE2);
    1108             : 
    1109         186 :         eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
    1110         186 :         sm->eap_if.eapFail = TRUE;
    1111         186 : }
    1112             : 
    1113             : 
    1114        1119 : SM_STATE(EAP, SUCCESS2)
    1115             : {
    1116        1119 :         SM_ENTRY(EAP, SUCCESS2);
    1117             : 
    1118        1119 :         eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
    1119             : 
    1120        1119 :         sm->eap_if.eapKeyAvailable = sm->eap_if.aaaEapKeyAvailable;
    1121        1119 :         if (sm->eap_if.aaaEapKeyAvailable) {
    1122        1102 :                 EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData);
    1123             :         } else {
    1124          17 :                 bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
    1125          17 :                 sm->eap_if.eapKeyData = NULL;
    1126          17 :                 sm->eap_if.eapKeyDataLen = 0;
    1127             :         }
    1128             : 
    1129        1119 :         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        1119 :         sm->start_reauth = TRUE;
    1137        1119 : }
    1138             : 
    1139             : 
    1140      201213 : SM_STEP(EAP)
    1141             : {
    1142      201213 :         if (sm->eap_if.eapRestart && sm->eap_if.portEnabled)
    1143        4663 :                 SM_ENTER_GLOBAL(EAP, INITIALIZE);
    1144      196550 :         else if (!sm->eap_if.portEnabled)
    1145        3862 :                 SM_ENTER_GLOBAL(EAP, DISABLED);
    1146      192688 :         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      192688 :         } else switch (sm->EAP_state) {
    1155             :         case EAP_INITIALIZE:
    1156        4663 :                 if (sm->backend_auth) {
    1157        1656 :                         if (!sm->rxResp)
    1158          16 :                                 SM_ENTER(EAP, SELECT_ACTION);
    1159        3280 :                         else if (sm->rxResp &&
    1160        3280 :                                  (sm->respMethod == EAP_TYPE_NAK ||
    1161        1640 :                                   (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        1640 :                                 SM_ENTER(EAP, PICK_UP_METHOD);
    1167             :                 } else {
    1168        3007 :                         SM_ENTER(EAP, SELECT_ACTION);
    1169             :                 }
    1170        4663 :                 break;
    1171             :         case EAP_PICK_UP_METHOD:
    1172        1640 :                 if (sm->currentMethod == EAP_TYPE_NONE) {
    1173           0 :                         SM_ENTER(EAP, SELECT_ACTION);
    1174             :                 } else {
    1175        1640 :                         SM_ENTER(EAP, METHOD_RESPONSE);
    1176             :                 }
    1177        1640 :                 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       39264 :                 if (sm->eap_if.retransWhile == 0) {
    1184           4 :                         if (sm->try_initiate_reauth) {
    1185           0 :                                 sm->try_initiate_reauth = FALSE;
    1186           0 :                                 SM_ENTER(EAP, SELECT_ACTION);
    1187             :                         } else {
    1188           4 :                                 SM_ENTER(EAP, RETRANSMIT);
    1189             :                         }
    1190       39260 :                 } else if (sm->eap_if.eapResp)
    1191       11490 :                         SM_ENTER(EAP, RECEIVED);
    1192       39264 :                 break;
    1193             :         case EAP_RETRANSMIT:
    1194           4 :                 if (sm->retransCount > sm->MaxRetrans)
    1195           0 :                         SM_ENTER(EAP, TIMEOUT_FAILURE);
    1196             :                 else
    1197           4 :                         SM_ENTER(EAP, IDLE);
    1198           4 :                 break;
    1199             :         case EAP_RECEIVED:
    1200       22944 :                 if (sm->rxResp && (sm->respId == sm->currentId) &&
    1201       22531 :                     (sm->respMethod == EAP_TYPE_NAK ||
    1202       13212 :                      (sm->respMethod == EAP_TYPE_EXPANDED &&
    1203        2154 :                       sm->respVendor == EAP_VENDOR_IETF &&
    1204          19 :                       sm->respVendorMethod == EAP_TYPE_NAK))
    1205         396 :                     && (sm->methodState == METHOD_PROPOSED))
    1206         396 :                         SM_ENTER(EAP, NAK);
    1207       22152 :                 else if (sm->rxResp && (sm->respId == sm->currentId) &&
    1208       11058 :                          ((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       11058 :                         SM_ENTER(EAP, INTEGRITY_CHECK);
    1213             : #ifdef CONFIG_ERP
    1214          36 :                 else if (sm->rxInitiate)
    1215          27 :                         SM_ENTER(EAP, INITIATE_RECEIVED);
    1216             : #endif /* CONFIG_ERP */
    1217             :                 else {
    1218          18 :                         wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "
    1219             :                                    "rxResp=%d respId=%d currentId=%d "
    1220             :                                    "respMethod=%d currentMethod=%d",
    1221           9 :                                    sm->rxResp, sm->respId, sm->currentId,
    1222           9 :                                    sm->respMethod, sm->currentMethod);
    1223           9 :                         eap_log_msg(sm, "Discard received EAP message");
    1224           9 :                         SM_ENTER(EAP, DISCARD);
    1225             :                 }
    1226       11490 :                 break;
    1227             :         case EAP_DISCARD:
    1228           9 :                 SM_ENTER(EAP, IDLE);
    1229           9 :                 break;
    1230             :         case EAP_SEND_REQUEST:
    1231       11941 :                 SM_ENTER(EAP, IDLE);
    1232       11941 :                 break;
    1233             :         case EAP_INTEGRITY_CHECK:
    1234       11058 :                 if (sm->ignore)
    1235           0 :                         SM_ENTER(EAP, DISCARD);
    1236             :                 else
    1237       11058 :                         SM_ENTER(EAP, METHOD_RESPONSE);
    1238       11058 :                 break;
    1239             :         case EAP_METHOD_REQUEST:
    1240       11898 :                 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           4 :                         SM_ENTER(EAP, FAILURE);
    1247           4 :                         break;
    1248             :                 }
    1249       11894 :                 SM_ENTER(EAP, SEND_REQUEST);
    1250       11894 :                 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          21 :                         wpa_printf(MSG_DEBUG,
    1257             :                                    "EAP: Method did not return a request");
    1258          21 :                         SM_ENTER(EAP, FAILURE);
    1259          21 :                         break;
    1260             :                 }
    1261       11873 :                 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       13131 :                 if (sm->methodState == METHOD_END)
    1270        6509 :                         SM_ENTER(EAP, SELECT_ACTION);
    1271        6622 :                 else if (sm->method_pending == METHOD_PENDING_WAIT) {
    1272         248 :                         wpa_printf(MSG_DEBUG, "EAP: Method has pending "
    1273             :                                    "processing - wait before proceeding to "
    1274             :                                    "METHOD_REQUEST state");
    1275        6374 :                 } else if (sm->method_pending == METHOD_PENDING_CONT) {
    1276         185 :                         wpa_printf(MSG_DEBUG, "EAP: Method has completed "
    1277             :                                    "pending processing - reprocess pending "
    1278             :                                    "EAP message");
    1279         185 :                         sm->method_pending = METHOD_PENDING_NONE;
    1280         185 :                         SM_ENTER(EAP, METHOD_RESPONSE);
    1281             :                 } else
    1282        6189 :                         SM_ENTER(EAP, METHOD_REQUEST);
    1283       13131 :                 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        5712 :                 if (sm->method_pending == METHOD_PENDING_WAIT) {
    1292           2 :                         wpa_printf(MSG_DEBUG, "EAP: Method has pending "
    1293             :                                    "processing - wait before proceeding to "
    1294             :                                    "METHOD_REQUEST state");
    1295           2 :                         if (sm->user_eap_method_index > 0)
    1296           1 :                                 sm->user_eap_method_index--;
    1297        5710 :                 } else if (sm->method_pending == METHOD_PENDING_CONT) {
    1298           1 :                         wpa_printf(MSG_DEBUG, "EAP: Method has completed "
    1299             :                                    "pending processing - reprocess pending "
    1300             :                                    "EAP message");
    1301           1 :                         sm->method_pending = METHOD_PENDING_NONE;
    1302           1 :                         SM_ENTER(EAP, PROPOSE_METHOD);
    1303             :                 } else
    1304        5709 :                         SM_ENTER(EAP, METHOD_REQUEST);
    1305        5712 :                 break;
    1306             :         case EAP_NAK:
    1307         396 :                 SM_ENTER(EAP, SELECT_ACTION);
    1308         396 :                 break;
    1309             :         case EAP_SELECT_ACTION:
    1310        9944 :                 if (sm->decision == DECISION_FAILURE)
    1311         807 :                         SM_ENTER(EAP, FAILURE);
    1312        9137 :                 else if (sm->decision == DECISION_SUCCESS)
    1313        1265 :                         SM_ENTER(EAP, SUCCESS);
    1314        7872 :                 else if (sm->decision == DECISION_PASSTHROUGH)
    1315        2079 :                         SM_ENTER(EAP, INITIALIZE_PASSTHROUGH);
    1316        5793 :                 else if (sm->decision == DECISION_INITIATE_REAUTH_START)
    1317          68 :                         SM_ENTER(EAP, INITIATE_REAUTH_START);
    1318             : #ifdef CONFIG_ERP
    1319        5725 :                 else if (sm->eap_server && sm->erp && sm->rxInitiate)
    1320          16 :                         SM_ENTER(EAP, INITIATE_RECEIVED);
    1321             : #endif /* CONFIG_ERP */
    1322             :                 else
    1323        5709 :                         SM_ENTER(EAP, PROPOSE_METHOD);
    1324        9944 :                 break;
    1325             :         case EAP_INITIATE_REAUTH_START:
    1326          68 :                 SM_ENTER(EAP, SEND_REQUEST);
    1327          68 :                 break;
    1328             :         case EAP_INITIATE_RECEIVED:
    1329          60 :                 if (!sm->eap_server)
    1330          16 :                         SM_ENTER(EAP, SELECT_ACTION);
    1331          60 :                 break;
    1332             :         case EAP_TIMEOUT_FAILURE:
    1333           0 :                 break;
    1334             :         case EAP_FAILURE:
    1335         832 :                 break;
    1336             :         case EAP_SUCCESS:
    1337        1716 :                 break;
    1338             : 
    1339             :         case EAP_INITIALIZE_PASSTHROUGH:
    1340        2079 :                 if (sm->currentId == -1)
    1341           0 :                         SM_ENTER(EAP, AAA_IDLE);
    1342             :                 else
    1343        2079 :                         SM_ENTER(EAP, AAA_REQUEST);
    1344        2079 :                 break;
    1345             :         case EAP_IDLE2:
    1346       16919 :                 if (sm->eap_if.eapResp)
    1347        5201 :                         SM_ENTER(EAP, RECEIVED2);
    1348       11718 :                 else if (sm->eap_if.retransWhile == 0)
    1349           6 :                         SM_ENTER(EAP, RETRANSMIT2);
    1350       16919 :                 break;
    1351             :         case EAP_RETRANSMIT2:
    1352           6 :                 if (sm->retransCount > sm->MaxRetrans)
    1353           0 :                         SM_ENTER(EAP, TIMEOUT_FAILURE2);
    1354             :                 else
    1355           6 :                         SM_ENTER(EAP, IDLE2);
    1356           6 :                 break;
    1357             :         case EAP_RECEIVED2:
    1358        5201 :                 if (sm->rxResp && (sm->respId == sm->currentId))
    1359        5199 :                         SM_ENTER(EAP, AAA_REQUEST);
    1360             :                 else
    1361           2 :                         SM_ENTER(EAP, DISCARD2);
    1362        5201 :                 break;
    1363             :         case EAP_DISCARD2:
    1364           2 :                 SM_ENTER(EAP, IDLE2);
    1365           2 :                 break;
    1366             :         case EAP_SEND_REQUEST2:
    1367        5829 :                 SM_ENTER(EAP, IDLE2);
    1368        5829 :                 break;
    1369             :         case EAP_AAA_REQUEST:
    1370        7278 :                 SM_ENTER(EAP, AAA_IDLE);
    1371        7278 :                 break;
    1372             :         case EAP_AAA_RESPONSE:
    1373        5829 :                 SM_ENTER(EAP, SEND_REQUEST2);
    1374        5829 :                 break;
    1375             :         case EAP_AAA_IDLE:
    1376       22035 :                 if (sm->eap_if.aaaFail)
    1377         186 :                         SM_ENTER(EAP, FAILURE2);
    1378       21849 :                 else if (sm->eap_if.aaaSuccess)
    1379        1119 :                         SM_ENTER(EAP, SUCCESS2);
    1380       20730 :                 else if (sm->eap_if.aaaEapReq)
    1381        5829 :                         SM_ENTER(EAP, AAA_RESPONSE);
    1382       14901 :                 else if (sm->eap_if.aaaTimeout)
    1383           0 :                         SM_ENTER(EAP, TIMEOUT_FAILURE2);
    1384       22035 :                 break;
    1385             :         case EAP_TIMEOUT_FAILURE2:
    1386           0 :                 break;
    1387             :         case EAP_FAILURE2:
    1388         186 :                 break;
    1389             :         case EAP_SUCCESS2:
    1390        3498 :                 break;
    1391             :         }
    1392      201213 : }
    1393             : 
    1394             : 
    1395       17791 : 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       17791 :         if (sm->try_initiate_reauth) {
    1402          68 :                 wpa_printf(MSG_DEBUG,
    1403             :                            "EAP: retransmit timeout 1 second for EAP-Initiate-Re-auth-Start");
    1404          68 :                 return 1;
    1405             :         }
    1406             : 
    1407       17723 :         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        2185 :                 wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
    1414             :                            "(from EAP method hint)", methodTimeout);
    1415        2185 :                 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       15538 :         rto = 3;
    1437       15548 :         for (i = 0; i < retransCount; i++) {
    1438          10 :                 rto *= 2;
    1439          10 :                 if (rto >= 20) {
    1440           0 :                         rto = 20;
    1441           0 :                         break;
    1442             :                 }
    1443             :         }
    1444             : 
    1445       15538 :         wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
    1446             :                    "(from dynamic back off; retransCount=%d)",
    1447             :                    rto, retransCount);
    1448             : 
    1449       15538 :         return rto;
    1450             : }
    1451             : 
    1452             : 
    1453       18347 : 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       18347 :         sm->rxResp = FALSE;
    1460       18347 :         sm->rxInitiate = FALSE;
    1461       18347 :         sm->respId = -1;
    1462       18347 :         sm->respMethod = EAP_TYPE_NONE;
    1463       18347 :         sm->respVendor = EAP_VENDOR_IETF;
    1464       18347 :         sm->respVendorMethod = EAP_TYPE_NONE;
    1465             : 
    1466       18347 :         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       18347 :         hdr = wpabuf_head(resp);
    1474       18347 :         plen = be_to_host16(hdr->length);
    1475       18347 :         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       18347 :         sm->respId = hdr->identifier;
    1484             : 
    1485       18347 :         if (hdr->code == EAP_CODE_RESPONSE)
    1486       18304 :                 sm->rxResp = TRUE;
    1487          43 :         else if (hdr->code == EAP_CODE_INITIATE)
    1488          43 :                 sm->rxInitiate = TRUE;
    1489             : 
    1490       18347 :         if (plen > sizeof(*hdr)) {
    1491       18347 :                 u8 *pos = (u8 *) (hdr + 1);
    1492       18347 :                 sm->respMethod = *pos++;
    1493       18347 :                 if (sm->respMethod == EAP_TYPE_EXPANDED) {
    1494        2172 :                         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        2172 :                         sm->respVendor = WPA_GET_BE24(pos);
    1501        2172 :                         pos += 3;
    1502        2172 :                         sm->respVendorMethod = WPA_GET_BE32(pos);
    1503             :                 }
    1504             :         }
    1505             : 
    1506       55041 :         wpa_printf(MSG_DEBUG,
    1507             :                    "EAP: parseEapResp: rxResp=%d rxInitiate=%d respId=%d respMethod=%u respVendor=%u respVendorMethod=%u",
    1508       36694 :                    sm->rxResp, sm->rxInitiate, sm->respId, sm->respMethod,
    1509             :                    sm->respVendor, sm->respVendorMethod);
    1510             : }
    1511             : 
    1512             : 
    1513        5829 : static int eap_sm_getId(const struct wpabuf *data)
    1514             : {
    1515             :         const struct eap_hdr *hdr;
    1516             : 
    1517        5829 :         if (data == NULL || wpabuf_len(data) < sizeof(*hdr))
    1518           2 :                 return -1;
    1519             : 
    1520        5827 :         hdr = wpabuf_head(data);
    1521        5827 :         wpa_printf(MSG_DEBUG, "EAP: getId: id=%d", hdr->identifier);
    1522        5827 :         return hdr->identifier;
    1523             : }
    1524             : 
    1525             : 
    1526        1265 : static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id)
    1527             : {
    1528             :         struct wpabuf *msg;
    1529             :         struct eap_hdr *resp;
    1530        1265 :         wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id);
    1531             : 
    1532        1265 :         msg = wpabuf_alloc(sizeof(*resp));
    1533        1265 :         if (msg == NULL)
    1534           0 :                 return NULL;
    1535        1265 :         resp = wpabuf_put(msg, sizeof(*resp));
    1536        1265 :         resp->code = EAP_CODE_SUCCESS;
    1537        1265 :         resp->identifier = id;
    1538        1265 :         resp->length = host_to_be16(sizeof(*resp));
    1539             : 
    1540        1265 :         return msg;
    1541             : }
    1542             : 
    1543             : 
    1544         832 : static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id)
    1545             : {
    1546             :         struct wpabuf *msg;
    1547             :         struct eap_hdr *resp;
    1548         832 :         wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id);
    1549             : 
    1550         832 :         msg = wpabuf_alloc(sizeof(*resp));
    1551         832 :         if (msg == NULL)
    1552           0 :                 return NULL;
    1553         832 :         resp = wpabuf_put(msg, sizeof(*resp));
    1554         832 :         resp->code = EAP_CODE_FAILURE;
    1555         832 :         resp->identifier = id;
    1556         832 :         resp->length = host_to_be16(sizeof(*resp));
    1557             : 
    1558         832 :         return msg;
    1559             : }
    1560             : 
    1561             : 
    1562       11962 : static int eap_sm_nextId(struct eap_sm *sm, int id)
    1563             : {
    1564       11962 :         if (id < 0) {
    1565             :                 /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a
    1566             :                  * random number */
    1567        3007 :                 id = rand() & 0xff;
    1568        3007 :                 if (id != sm->lastId)
    1569        2999 :                         return id;
    1570             :         }
    1571        8963 :         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         422 : 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         422 :         if (sm->user == NULL)
    1590         422 :                 return;
    1591             : 
    1592         422 :         wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
    1593             :                    "index %d)", sm->user_eap_method_index);
    1594             : 
    1595         422 :         wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
    1596         422 :                     (u8 *) sm->user->methods,
    1597             :                     EAP_MAX_METHODS * sizeof(sm->user->methods[0]));
    1598         422 :         wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
    1599             :                     nak_list, len);
    1600             : 
    1601         422 :         i = sm->user_eap_method_index;
    1602        5104 :         while (i < EAP_MAX_METHODS &&
    1603        4682 :                (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
    1604        2341 :                 sm->user->methods[i].method != EAP_TYPE_NONE)) {
    1605        1919 :                 if (sm->user->methods[i].vendor != EAP_VENDOR_IETF)
    1606           0 :                         goto not_found;
    1607        3501 :                 for (j = 0; j < len; j++) {
    1608        1919 :                         if (nak_list[j] == sm->user->methods[i].method) {
    1609         337 :                                 break;
    1610             :                         }
    1611             :                 }
    1612             : 
    1613        1919 :                 if (j < len) {
    1614             :                         /* found */
    1615         337 :                         i++;
    1616         337 :                         continue;
    1617             :                 }
    1618             : 
    1619             :         not_found:
    1620             :                 /* not found - remove from the list */
    1621        1582 :                 if (i + 1 < EAP_MAX_METHODS) {
    1622        1582 :                         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        1582 :                 sm->user->methods[EAP_MAX_METHODS - 1].vendor =
    1628             :                         EAP_VENDOR_IETF;
    1629        1582 :                 sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
    1630             :         }
    1631             : 
    1632         422 :         wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
    1633         422 :                     (u8 *) sm->user->methods, EAP_MAX_METHODS *
    1634             :                     sizeof(sm->user->methods[0]));
    1635             : }
    1636             : 
    1637             : 
    1638        6905 : static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
    1639             :                                  size_t len)
    1640             : {
    1641        6905 :         if (nak_list == NULL || sm == NULL || sm->user == NULL)
    1642        6528 :                 return;
    1643             : 
    1644         377 :         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         377 :         eap_sm_process_nak(sm, nak_list, len);
    1652             : }
    1653             : 
    1654             : 
    1655        5716 : static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
    1656             : {
    1657             :         EapType next;
    1658        5716 :         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        5716 :         if (sm->identity == NULL || sm->currentId == -1) {
    1668        2941 :                 *vendor = EAP_VENDOR_IETF;
    1669        2941 :                 next = EAP_TYPE_IDENTITY;
    1670        2941 :                 sm->update_user = TRUE;
    1671        5550 :         } else if (sm->user && idx < EAP_MAX_METHODS &&
    1672        4992 :                    (sm->user->methods[idx].vendor != EAP_VENDOR_IETF ||
    1673        2217 :                     sm->user->methods[idx].method != EAP_TYPE_NONE)) {
    1674        2771 :                 *vendor = sm->user->methods[idx].vendor;
    1675        2771 :                 next = sm->user->methods[idx].method;
    1676        2771 :                 sm->user_eap_method_index++;
    1677             :         } else {
    1678           4 :                 *vendor = EAP_VENDOR_IETF;
    1679           4 :                 next = EAP_TYPE_NONE;
    1680             :         }
    1681        5716 :         wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d",
    1682             :                    *vendor, next);
    1683        5716 :         return next;
    1684             : }
    1685             : 
    1686             : 
    1687        9944 : static int eap_sm_Policy_getDecision(struct eap_sm *sm)
    1688             : {
    1689        9944 :         if (!sm->eap_server && sm->identity && !sm->start_reauth) {
    1690        2079 :                 wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH");
    1691        2079 :                 return DECISION_PASSTHROUGH;
    1692             :         }
    1693             : 
    1694        9830 :         if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY &&
    1695        1965 :             sm->m->isSuccess(sm, sm->eap_method_priv)) {
    1696        1265 :                 wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
    1697             :                            "SUCCESS");
    1698        1265 :                 sm->update_user = TRUE;
    1699        1265 :                 return DECISION_SUCCESS;
    1700             :         }
    1701             : 
    1702        9781 :         if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) &&
    1703        3181 :             !sm->m->isSuccess(sm, sm->eap_method_priv)) {
    1704         703 :                 wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
    1705             :                            "FAILURE");
    1706         703 :                 sm->update_user = TRUE;
    1707         703 :                 return DECISION_FAILURE;
    1708             :         }
    1709             : 
    1710        8435 :         if ((sm->user == NULL || sm->update_user) && sm->identity &&
    1711        2538 :             !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        2538 :                 int id_req = 0;
    1719        2634 :                 if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY &&
    1720         190 :                     sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
    1721          94 :                     sm->user->methods[0].method == EAP_TYPE_IDENTITY)
    1722           0 :                         id_req = 1;
    1723        2538 :                 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        2537 :                 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        2537 :                 sm->update_user = FALSE;
    1737             :         }
    1738        5896 :         sm->start_reauth = FALSE;
    1739             : 
    1740        8869 :         if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
    1741        2973 :             (sm->user->methods[sm->user_eap_method_index].vendor !=
    1742        2413 :              EAP_VENDOR_IETF ||
    1743        2413 :              sm->user->methods[sm->user_eap_method_index].method !=
    1744             :              EAP_TYPE_NONE)) {
    1745        2865 :                 wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
    1746             :                            "available -> CONTINUE");
    1747        2865 :                 return DECISION_CONTINUE;
    1748             :         }
    1749             : 
    1750        3143 :         if (!sm->identity && eap_get_erp_send_reauth_start(sm) &&
    1751         112 :             !sm->initiate_reauth_start_sent) {
    1752          68 :                 wpa_printf(MSG_DEBUG,
    1753             :                            "EAP: getDecision: send EAP-Initiate/Re-auth-Start");
    1754          68 :                 return DECISION_INITIATE_REAUTH_START;
    1755             :         }
    1756             : 
    1757        2963 :         if (sm->identity == NULL || sm->currentId == -1) {
    1758        2860 :                 wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
    1759             :                            "yet -> CONTINUE");
    1760        2860 :                 return DECISION_CONTINUE;
    1761             :         }
    1762             : 
    1763         103 :         wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> "
    1764             :                    "FAILURE");
    1765         103 :         return DECISION_FAILURE;
    1766             : }
    1767             : 
    1768             : 
    1769        1640 : static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
    1770             : {
    1771        1640 :         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       63992 : int eap_server_sm_step(struct eap_sm *sm)
    1785             : {
    1786       63992 :         int res = 0;
    1787             :         do {
    1788      201213 :                 sm->changed = FALSE;
    1789      201213 :                 SM_STEP_RUN(EAP);
    1790      201213 :                 if (sm->changed)
    1791      137221 :                         res = 1;
    1792      201213 :         } while (sm->changed);
    1793       63992 :         return res;
    1794             : }
    1795             : 
    1796             : 
    1797        7953 : static void eap_user_free(struct eap_user *user)
    1798             : {
    1799        7953 :         if (user == NULL)
    1800       12323 :                 return;
    1801        3583 :         bin_clear_free(user->password, user->password_len);
    1802        3583 :         user->password = NULL;
    1803        3583 :         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        4359 : 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        4359 :         sm = os_zalloc(sizeof(*sm));
    1823        4359 :         if (sm == NULL)
    1824           0 :                 return NULL;
    1825        4359 :         sm->eapol_ctx = eapol_ctx;
    1826        4359 :         sm->eapol_cb = eapol_cb;
    1827        4359 :         sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */
    1828        4359 :         sm->ssl_ctx = conf->ssl_ctx;
    1829        4359 :         sm->msg_ctx = conf->msg_ctx;
    1830        4359 :         sm->eap_sim_db_priv = conf->eap_sim_db_priv;
    1831        4359 :         sm->backend_auth = conf->backend_auth;
    1832        4359 :         sm->eap_server = conf->eap_server;
    1833        4359 :         if (conf->pac_opaque_encr_key) {
    1834        1654 :                 sm->pac_opaque_encr_key = os_malloc(16);
    1835        1654 :                 if (sm->pac_opaque_encr_key) {
    1836        1654 :                         os_memcpy(sm->pac_opaque_encr_key,
    1837             :                                   conf->pac_opaque_encr_key, 16);
    1838             :                 }
    1839             :         }
    1840        4359 :         if (conf->eap_fast_a_id) {
    1841        1654 :                 sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
    1842        1654 :                 if (sm->eap_fast_a_id) {
    1843        1654 :                         os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id,
    1844             :                                   conf->eap_fast_a_id_len);
    1845        1654 :                         sm->eap_fast_a_id_len = conf->eap_fast_a_id_len;
    1846             :                 }
    1847             :         }
    1848        4359 :         if (conf->eap_fast_a_id_info)
    1849        1654 :                 sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
    1850        4359 :         sm->eap_fast_prov = conf->eap_fast_prov;
    1851        4359 :         sm->pac_key_lifetime = conf->pac_key_lifetime;
    1852        4359 :         sm->pac_key_refresh_time = conf->pac_key_refresh_time;
    1853        4359 :         sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
    1854        4359 :         sm->tnc = conf->tnc;
    1855        4359 :         sm->wps = conf->wps;
    1856        4359 :         if (conf->assoc_wps_ie)
    1857         535 :                 sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie);
    1858        4359 :         if (conf->assoc_p2p_ie)
    1859         242 :                 sm->assoc_p2p_ie = wpabuf_dup(conf->assoc_p2p_ie);
    1860        4359 :         if (conf->peer_addr)
    1861        2698 :                 os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN);
    1862        4359 :         sm->fragment_size = conf->fragment_size;
    1863        4359 :         sm->pwd_group = conf->pwd_group;
    1864        4359 :         sm->pbc_in_m1 = conf->pbc_in_m1;
    1865        4359 :         sm->server_id = conf->server_id;
    1866        4359 :         sm->server_id_len = conf->server_id_len;
    1867        4359 :         sm->erp = conf->erp;
    1868        4359 :         sm->tls_session_lifetime = conf->tls_session_lifetime;
    1869             : 
    1870             : #ifdef CONFIG_TESTING_OPTIONS
    1871        4359 :         sm->tls_test_flags = conf->tls_test_flags;
    1872             : #endif /* CONFIG_TESTING_OPTIONS */
    1873             : 
    1874        4359 :         wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
    1875             : 
    1876        4359 :         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        4359 : void eap_server_sm_deinit(struct eap_sm *sm)
    1888             : {
    1889        4359 :         if (sm == NULL)
    1890        4359 :                 return;
    1891        4359 :         wpa_printf(MSG_DEBUG, "EAP: Server state machine removed");
    1892        4359 :         if (sm->m && sm->eap_method_priv)
    1893        4174 :                 sm->m->reset(sm, sm->eap_method_priv);
    1894        4359 :         wpabuf_free(sm->eap_if.eapReqData);
    1895        4359 :         bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
    1896        4359 :         os_free(sm->eap_if.eapSessionId);
    1897        4359 :         wpabuf_free(sm->lastReqData);
    1898        4359 :         wpabuf_free(sm->eap_if.eapRespData);
    1899        4359 :         os_free(sm->identity);
    1900        4359 :         os_free(sm->pac_opaque_encr_key);
    1901        4359 :         os_free(sm->eap_fast_a_id);
    1902        4359 :         os_free(sm->eap_fast_a_id_info);
    1903        4359 :         wpabuf_free(sm->eap_if.aaaEapReqData);
    1904        4359 :         wpabuf_free(sm->eap_if.aaaEapRespData);
    1905        4359 :         bin_clear_free(sm->eap_if.aaaEapKeyData, sm->eap_if.aaaEapKeyDataLen);
    1906        4359 :         eap_user_free(sm->user);
    1907        4359 :         wpabuf_free(sm->assoc_wps_ie);
    1908        4359 :         wpabuf_free(sm->assoc_p2p_ie);
    1909        4359 :         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          41 : void eap_sm_notify_cached(struct eap_sm *sm)
    1921             : {
    1922          41 :         if (sm == NULL)
    1923          41 :                 return;
    1924             : 
    1925          41 :         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         187 : void eap_sm_pending_cb(struct eap_sm *sm)
    1936             : {
    1937         187 :         if (sm == NULL)
    1938         187 :                 return;
    1939         187 :         wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received");
    1940         187 :         if (sm->method_pending == METHOD_PENDING_WAIT)
    1941         186 :                 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         134 : int eap_sm_method_pending(struct eap_sm *sm)
    1951             : {
    1952         134 :         if (sm == NULL)
    1953           0 :                 return 0;
    1954         134 :         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        2079 : const u8 * eap_get_identity(struct eap_sm *sm, size_t *len)
    1965             : {
    1966        2079 :         *len = sm->identity_len;
    1967        2079 :         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        4359 : struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm)
    1977             : {
    1978        4359 :         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         292 : void eap_server_clear_identity(struct eap_sm *sm)
    1991             : {
    1992         292 :         os_free(sm->identity);
    1993         292 :         sm->identity = NULL;
    1994         292 : }
    1995             : 
    1996             : 
    1997             : #ifdef CONFIG_TESTING_OPTIONS
    1998         265 : 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         265 :         if (username)
    2006         265 :                 printf_encode(user, sizeof(user), username, username_len);
    2007             :         else
    2008           0 :                 user[0] = '\0';
    2009         265 :         wpa_snprintf_hex_sep(hex_challenge, sizeof(hex_challenge),
    2010             :                              challenge, sizeof(challenge), ':');
    2011         265 :         wpa_snprintf_hex_sep(hex_response, sizeof(hex_response), response, 24,
    2012             :                              ':');
    2013         265 :         wpa_printf(MSG_DEBUG, "[%s/user=%s] asleap -C %s -R %s",
    2014             :                    source, user, hex_challenge, hex_response);
    2015         265 : }
    2016             : #endif /* CONFIG_TESTING_OPTIONS */

Generated by: LCOV version 1.10