LCOV - code coverage report
Current view: top level - src/eapol_supp - eapol_supp_sm.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1388613141 Lines: 663 863 76.8 %
Date: 2014-01-02 Functions: 70 79 88.6 %
Branches: 310 579 53.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * EAPOL supplicant state machines
       3                 :            :  * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
       4                 :            :  *
       5                 :            :  * This software may be distributed under the terms of the BSD license.
       6                 :            :  * See README for more details.
       7                 :            :  */
       8                 :            : 
       9                 :            : #include "includes.h"
      10                 :            : 
      11                 :            : #include "common.h"
      12                 :            : #include "state_machine.h"
      13                 :            : #include "wpabuf.h"
      14                 :            : #include "eloop.h"
      15                 :            : #include "crypto/crypto.h"
      16                 :            : #include "crypto/md5.h"
      17                 :            : #include "common/eapol_common.h"
      18                 :            : #include "eap_peer/eap.h"
      19                 :            : #include "eap_peer/eap_proxy.h"
      20                 :            : #include "eapol_supp_sm.h"
      21                 :            : 
      22                 :            : #define STATE_MACHINE_DATA struct eapol_sm
      23                 :            : #define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
      24                 :            : 
      25                 :            : 
      26                 :            : /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
      27                 :            : 
      28                 :            : /**
      29                 :            :  * struct eapol_sm - Internal data for EAPOL state machines
      30                 :            :  */
      31                 :            : struct eapol_sm {
      32                 :            :         /* Timers */
      33                 :            :         unsigned int authWhile;
      34                 :            :         unsigned int heldWhile;
      35                 :            :         unsigned int startWhen;
      36                 :            :         unsigned int idleWhile; /* for EAP state machine */
      37                 :            :         int timer_tick_enabled;
      38                 :            : 
      39                 :            :         /* Global variables */
      40                 :            :         Boolean eapFail;
      41                 :            :         Boolean eapolEap;
      42                 :            :         Boolean eapSuccess;
      43                 :            :         Boolean initialize;
      44                 :            :         Boolean keyDone;
      45                 :            :         Boolean keyRun;
      46                 :            :         PortControl portControl;
      47                 :            :         Boolean portEnabled;
      48                 :            :         PortStatus suppPortStatus;  /* dot1xSuppControlledPortStatus */
      49                 :            :         Boolean portValid;
      50                 :            :         Boolean suppAbort;
      51                 :            :         Boolean suppFail;
      52                 :            :         Boolean suppStart;
      53                 :            :         Boolean suppSuccess;
      54                 :            :         Boolean suppTimeout;
      55                 :            : 
      56                 :            :         /* Supplicant PAE state machine */
      57                 :            :         enum {
      58                 :            :                 SUPP_PAE_UNKNOWN = 0,
      59                 :            :                 SUPP_PAE_DISCONNECTED = 1,
      60                 :            :                 SUPP_PAE_LOGOFF = 2,
      61                 :            :                 SUPP_PAE_CONNECTING = 3,
      62                 :            :                 SUPP_PAE_AUTHENTICATING = 4,
      63                 :            :                 SUPP_PAE_AUTHENTICATED = 5,
      64                 :            :                 /* unused(6) */
      65                 :            :                 SUPP_PAE_HELD = 7,
      66                 :            :                 SUPP_PAE_RESTART = 8,
      67                 :            :                 SUPP_PAE_S_FORCE_AUTH = 9,
      68                 :            :                 SUPP_PAE_S_FORCE_UNAUTH = 10
      69                 :            :         } SUPP_PAE_state; /* dot1xSuppPaeState */
      70                 :            :         /* Variables */
      71                 :            :         Boolean userLogoff;
      72                 :            :         Boolean logoffSent;
      73                 :            :         unsigned int startCount;
      74                 :            :         Boolean eapRestart;
      75                 :            :         PortControl sPortMode;
      76                 :            :         /* Constants */
      77                 :            :         unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
      78                 :            :         unsigned int startPeriod; /* dot1xSuppStartPeriod */
      79                 :            :         unsigned int maxStart; /* dot1xSuppMaxStart */
      80                 :            : 
      81                 :            :         /* Key Receive state machine */
      82                 :            :         enum {
      83                 :            :                 KEY_RX_UNKNOWN = 0,
      84                 :            :                 KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
      85                 :            :         } KEY_RX_state;
      86                 :            :         /* Variables */
      87                 :            :         Boolean rxKey;
      88                 :            : 
      89                 :            :         /* Supplicant Backend state machine */
      90                 :            :         enum {
      91                 :            :                 SUPP_BE_UNKNOWN = 0,
      92                 :            :                 SUPP_BE_INITIALIZE = 1,
      93                 :            :                 SUPP_BE_IDLE = 2,
      94                 :            :                 SUPP_BE_REQUEST = 3,
      95                 :            :                 SUPP_BE_RECEIVE = 4,
      96                 :            :                 SUPP_BE_RESPONSE = 5,
      97                 :            :                 SUPP_BE_FAIL = 6,
      98                 :            :                 SUPP_BE_TIMEOUT = 7, 
      99                 :            :                 SUPP_BE_SUCCESS = 8
     100                 :            :         } SUPP_BE_state; /* dot1xSuppBackendPaeState */
     101                 :            :         /* Variables */
     102                 :            :         Boolean eapNoResp;
     103                 :            :         Boolean eapReq;
     104                 :            :         Boolean eapResp;
     105                 :            :         /* Constants */
     106                 :            :         unsigned int authPeriod; /* dot1xSuppAuthPeriod */
     107                 :            : 
     108                 :            :         /* Statistics */
     109                 :            :         unsigned int dot1xSuppEapolFramesRx;
     110                 :            :         unsigned int dot1xSuppEapolFramesTx;
     111                 :            :         unsigned int dot1xSuppEapolStartFramesTx;
     112                 :            :         unsigned int dot1xSuppEapolLogoffFramesTx;
     113                 :            :         unsigned int dot1xSuppEapolRespFramesTx;
     114                 :            :         unsigned int dot1xSuppEapolReqIdFramesRx;
     115                 :            :         unsigned int dot1xSuppEapolReqFramesRx;
     116                 :            :         unsigned int dot1xSuppInvalidEapolFramesRx;
     117                 :            :         unsigned int dot1xSuppEapLengthErrorFramesRx;
     118                 :            :         unsigned int dot1xSuppLastEapolFrameVersion;
     119                 :            :         unsigned char dot1xSuppLastEapolFrameSource[6];
     120                 :            : 
     121                 :            :         /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
     122                 :            :         Boolean changed;
     123                 :            :         struct eap_sm *eap;
     124                 :            :         struct eap_peer_config *config;
     125                 :            :         Boolean initial_req;
     126                 :            :         u8 *last_rx_key;
     127                 :            :         size_t last_rx_key_len;
     128                 :            :         struct wpabuf *eapReqData; /* for EAP */
     129                 :            :         Boolean altAccept; /* for EAP */
     130                 :            :         Boolean altReject; /* for EAP */
     131                 :            :         Boolean replay_counter_valid;
     132                 :            :         u8 last_replay_counter[16];
     133                 :            :         struct eapol_config conf;
     134                 :            :         struct eapol_ctx *ctx;
     135                 :            :         enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
     136                 :            :                 cb_status;
     137                 :            :         Boolean cached_pmk;
     138                 :            : 
     139                 :            :         Boolean unicast_key_received, broadcast_key_received;
     140                 :            : #ifdef CONFIG_EAP_PROXY
     141                 :            :         Boolean use_eap_proxy;
     142                 :            :         struct eap_proxy_sm *eap_proxy;
     143                 :            : #endif /* CONFIG_EAP_PROXY */
     144                 :            : };
     145                 :            : 
     146                 :            : 
     147                 :            : static void eapol_sm_txLogoff(struct eapol_sm *sm);
     148                 :            : static void eapol_sm_txStart(struct eapol_sm *sm);
     149                 :            : static void eapol_sm_processKey(struct eapol_sm *sm);
     150                 :            : static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
     151                 :            : static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
     152                 :            : static void eapol_sm_abortSupp(struct eapol_sm *sm);
     153                 :            : static void eapol_sm_abort_cached(struct eapol_sm *sm);
     154                 :            : static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
     155                 :            : static void eapol_sm_set_port_authorized(struct eapol_sm *sm);
     156                 :            : static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm);
     157                 :            : 
     158                 :            : 
     159                 :            : /* Port Timers state machine - implemented as a function that will be called
     160                 :            :  * once a second as a registered event loop timeout */
     161                 :        297 : static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
     162                 :            : {
     163                 :        297 :         struct eapol_sm *sm = timeout_ctx;
     164                 :            : 
     165         [ +  + ]:        297 :         if (sm->authWhile > 0) {
     166                 :         21 :                 sm->authWhile--;
     167         [ -  + ]:         21 :                 if (sm->authWhile == 0)
     168                 :          0 :                         wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
     169                 :            :         }
     170         [ -  + ]:        297 :         if (sm->heldWhile > 0) {
     171                 :          0 :                 sm->heldWhile--;
     172         [ #  # ]:          0 :                 if (sm->heldWhile == 0)
     173                 :          0 :                         wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
     174                 :            :         }
     175         [ +  + ]:        297 :         if (sm->startWhen > 0) {
     176                 :        107 :                 sm->startWhen--;
     177         [ +  + ]:        107 :                 if (sm->startWhen == 0)
     178                 :        105 :                         wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
     179                 :            :         }
     180         [ +  + ]:        297 :         if (sm->idleWhile > 0) {
     181                 :         50 :                 sm->idleWhile--;
     182         [ -  + ]:         50 :                 if (sm->idleWhile == 0)
     183                 :          0 :                         wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
     184                 :            :         }
     185                 :            : 
     186         [ +  + ]:        297 :         if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
     187                 :         50 :                 eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
     188                 :            :                                        sm);
     189                 :            :         } else {
     190                 :        247 :                 wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
     191                 :        247 :                 sm->timer_tick_enabled = 0;
     192                 :            :         }
     193                 :        297 :         eapol_sm_step(sm);
     194                 :        297 : }
     195                 :            : 
     196                 :            : 
     197                 :       3010 : static void eapol_enable_timer_tick(struct eapol_sm *sm)
     198                 :            : {
     199         [ +  + ]:       3010 :         if (sm->timer_tick_enabled)
     200                 :       3010 :                 return;
     201                 :        229 :         wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
     202                 :        229 :         sm->timer_tick_enabled = 1;
     203                 :        229 :         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
     204                 :        229 :         eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
     205                 :            : }
     206                 :            : 
     207                 :            : 
     208                 :          1 : SM_STATE(SUPP_PAE, LOGOFF)
     209                 :            : {
     210 [ +  - ][ +  - ]:          1 :         SM_ENTRY(SUPP_PAE, LOGOFF);
     211                 :          1 :         eapol_sm_txLogoff(sm);
     212                 :          1 :         sm->logoffSent = TRUE;
     213                 :          1 :         sm->suppPortStatus = Unauthorized;
     214                 :          1 :         eapol_sm_set_port_unauthorized(sm);
     215                 :          1 : }
     216                 :            : 
     217                 :            : 
     218                 :       6507 : SM_STATE(SUPP_PAE, DISCONNECTED)
     219                 :            : {
     220 [ +  + ][ +  + ]:       6507 :         SM_ENTRY(SUPP_PAE, DISCONNECTED);
     221                 :       6507 :         sm->sPortMode = Auto;
     222                 :       6507 :         sm->startCount = 0;
     223                 :       6507 :         sm->logoffSent = FALSE;
     224                 :       6507 :         sm->suppPortStatus = Unauthorized;
     225                 :       6507 :         eapol_sm_set_port_unauthorized(sm);
     226                 :       6507 :         sm->suppAbort = TRUE;
     227                 :            : 
     228                 :       6507 :         sm->unicast_key_received = FALSE;
     229                 :       6507 :         sm->broadcast_key_received = FALSE;
     230                 :            : 
     231                 :            :         /*
     232                 :            :          * IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so
     233                 :            :          * allows the timer tick to be stopped more quickly when the port is
     234                 :            :          * not enabled. Since this variable is used only within HELD state,
     235                 :            :          * clearing it on initialization does not change actual state machine
     236                 :            :          * behavior.
     237                 :            :          */
     238                 :       6507 :         sm->heldWhile = 0;
     239                 :       6507 : }
     240                 :            : 
     241                 :            : 
     242                 :        364 : SM_STATE(SUPP_PAE, CONNECTING)
     243                 :            : {
     244                 :        364 :         int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
     245 [ -  + ][ #  # ]:        364 :         SM_ENTRY(SUPP_PAE, CONNECTING);
     246         [ +  + ]:        364 :         if (send_start) {
     247                 :          9 :                 sm->startWhen = sm->startPeriod;
     248                 :          9 :                 sm->startCount++;
     249                 :            :         } else {
     250                 :            :                 /*
     251                 :            :                  * Do not send EAPOL-Start immediately since in most cases,
     252                 :            :                  * Authenticator is going to start authentication immediately
     253                 :            :                  * after association and an extra EAPOL-Start is just going to
     254                 :            :                  * delay authentication. Use a short timeout to send the first
     255                 :            :                  * EAPOL-Start if Authenticator does not start authentication.
     256                 :            :                  */
     257                 :            : #ifdef CONFIG_WPS
     258                 :            :                 /* Reduce latency on starting WPS negotiation. */
     259                 :        355 :                 sm->startWhen = 1;
     260                 :            : #else /* CONFIG_WPS */
     261                 :            :                 sm->startWhen = 3;
     262                 :            : #endif /* CONFIG_WPS */
     263                 :            :         }
     264                 :        364 :         eapol_enable_timer_tick(sm);
     265                 :        364 :         sm->eapolEap = FALSE;
     266         [ +  + ]:        364 :         if (send_start)
     267                 :          9 :                 eapol_sm_txStart(sm);
     268                 :        364 : }
     269                 :            : 
     270                 :            : 
     271                 :        376 : SM_STATE(SUPP_PAE, AUTHENTICATING)
     272                 :            : {
     273 [ -  + ][ #  # ]:        376 :         SM_ENTRY(SUPP_PAE, AUTHENTICATING);
     274                 :        376 :         sm->startCount = 0;
     275                 :        376 :         sm->suppSuccess = FALSE;
     276                 :        376 :         sm->suppFail = FALSE;
     277                 :        376 :         sm->suppTimeout = FALSE;
     278                 :        376 :         sm->keyRun = FALSE;
     279                 :        376 :         sm->keyDone = FALSE;
     280                 :        376 :         sm->suppStart = TRUE;
     281                 :        376 : }
     282                 :            : 
     283                 :            : 
     284                 :         95 : SM_STATE(SUPP_PAE, HELD)
     285                 :            : {
     286 [ -  + ][ #  # ]:         95 :         SM_ENTRY(SUPP_PAE, HELD);
     287                 :         95 :         sm->heldWhile = sm->heldPeriod;
     288                 :         95 :         eapol_enable_timer_tick(sm);
     289                 :         95 :         sm->suppPortStatus = Unauthorized;
     290                 :         95 :         eapol_sm_set_port_unauthorized(sm);
     291                 :         95 :         sm->cb_status = EAPOL_CB_FAILURE;
     292                 :         95 : }
     293                 :            : 
     294                 :            : 
     295                 :        274 : SM_STATE(SUPP_PAE, AUTHENTICATED)
     296                 :            : {
     297 [ -  + ][ #  # ]:        274 :         SM_ENTRY(SUPP_PAE, AUTHENTICATED);
     298                 :        274 :         sm->suppPortStatus = Authorized;
     299                 :        274 :         eapol_sm_set_port_authorized(sm);
     300                 :        274 :         sm->cb_status = EAPOL_CB_SUCCESS;
     301                 :        274 : }
     302                 :            : 
     303                 :            : 
     304                 :        183 : SM_STATE(SUPP_PAE, RESTART)
     305                 :            : {
     306 [ -  + ][ #  # ]:        183 :         SM_ENTRY(SUPP_PAE, RESTART);
     307                 :        183 :         sm->eapRestart = TRUE;
     308                 :        183 : }
     309                 :            : 
     310                 :            : 
     311                 :         90 : SM_STATE(SUPP_PAE, S_FORCE_AUTH)
     312                 :            : {
     313 [ +  - ][ +  - ]:         90 :         SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
     314                 :         90 :         sm->suppPortStatus = Authorized;
     315                 :         90 :         eapol_sm_set_port_authorized(sm);
     316                 :         90 :         sm->sPortMode = ForceAuthorized;
     317                 :         90 : }
     318                 :            : 
     319                 :            : 
     320                 :          0 : SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
     321                 :            : {
     322 [ #  # ][ #  # ]:          0 :         SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
     323                 :          0 :         sm->suppPortStatus = Unauthorized;
     324                 :          0 :         eapol_sm_set_port_unauthorized(sm);
     325                 :          0 :         sm->sPortMode = ForceUnauthorized;
     326                 :          0 :         eapol_sm_txLogoff(sm);
     327                 :          0 : }
     328                 :            : 
     329                 :            : 
     330                 :      14606 : SM_STEP(SUPP_PAE)
     331                 :            : {
     332 [ +  + ][ +  + ]:      14606 :         if ((sm->userLogoff && !sm->logoffSent) &&
                 [ +  - ]
     333         [ +  + ]:          3 :             !(sm->initialize || !sm->portEnabled))
     334                 :          1 :                 SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
     335 [ +  + ][ +  - ]:      14605 :         else if (((sm->portControl == Auto) &&
     336         [ +  + ]:      14605 :                   (sm->sPortMode != sm->portControl)) ||
     337         [ +  + ]:      14543 :                  sm->initialize || !sm->portEnabled)
     338                 :       6491 :                 SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
     339 [ +  + ][ +  + ]:       8114 :         else if ((sm->portControl == ForceAuthorized) &&
     340         [ +  - ]:         90 :                  (sm->sPortMode != sm->portControl) &&
     341         [ +  - ]:         90 :                  !(sm->initialize || !sm->portEnabled))
     342                 :         90 :                 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
     343 [ -  + ][ #  # ]:       8024 :         else if ((sm->portControl == ForceUnauthorized) &&
     344         [ #  # ]:          0 :                  (sm->sPortMode != sm->portControl) &&
     345         [ #  # ]:          0 :                  !(sm->initialize || !sm->portEnabled))
     346                 :          0 :                 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
     347   [ -  +  +  +  :       8024 :         else switch (sm->SUPP_PAE_state) {
          +  +  +  +  +  
                   -  - ]
     348                 :            :         case SUPP_PAE_UNKNOWN:
     349                 :          0 :                 break;
     350                 :            :         case SUPP_PAE_LOGOFF:
     351         [ -  + ]:          1 :                 if (!sm->userLogoff)
     352                 :          0 :                         SM_ENTER(SUPP_PAE, DISCONNECTED);
     353                 :          1 :                 break;
     354                 :            :         case SUPP_PAE_DISCONNECTED:
     355                 :        355 :                 SM_ENTER(SUPP_PAE, CONNECTING);
     356                 :        355 :                 break;
     357                 :            :         case SUPP_PAE_CONNECTING:
     358 [ +  + ][ +  - ]:       1162 :                 if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
     359                 :          9 :                         SM_ENTER(SUPP_PAE, CONNECTING);
     360 [ -  + ][ #  # ]:       1153 :                 else if (sm->startWhen == 0 &&
     361         [ #  # ]:          0 :                          sm->startCount >= sm->maxStart &&
     362                 :          0 :                          sm->portValid)
     363                 :          0 :                         SM_ENTER(SUPP_PAE, AUTHENTICATED);
     364 [ +  + ][ -  + ]:       1153 :                 else if (sm->eapSuccess || sm->eapFail)
     365                 :        193 :                         SM_ENTER(SUPP_PAE, AUTHENTICATING);
     366         [ +  + ]:        960 :                 else if (sm->eapolEap)
     367                 :        161 :                         SM_ENTER(SUPP_PAE, RESTART);
     368 [ -  + ][ #  # ]:        799 :                 else if (sm->startWhen == 0 &&
     369         [ #  # ]:          0 :                          sm->startCount >= sm->maxStart &&
     370                 :          0 :                          !sm->portValid)
     371                 :          0 :                         SM_ENTER(SUPP_PAE, HELD);
     372                 :       1162 :                 break;
     373                 :            :         case SUPP_PAE_AUTHENTICATING:
     374 [ +  + ][ +  + ]:       5023 :                 if (sm->eapSuccess && !sm->portValid &&
                 [ +  + ]
     375         [ +  + ]:         16 :                     sm->conf.accept_802_1x_keys &&
     376                 :         16 :                     sm->conf.required_keys == 0) {
     377                 :          2 :                         wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
     378                 :            :                                    "plaintext connection; no EAPOL-Key frames "
     379                 :            :                                    "required");
     380                 :          2 :                         sm->portValid = TRUE;
     381         [ +  - ]:          2 :                         if (sm->ctx->eapol_done_cb)
     382                 :          2 :                                 sm->ctx->eapol_done_cb(sm->ctx->ctx);
     383                 :            :                 }
     384 [ +  + ][ +  + ]:       5023 :                 if (sm->eapSuccess && sm->portValid)
     385                 :        274 :                         SM_ENTER(SUPP_PAE, AUTHENTICATED);
     386 [ +  + ][ -  + ]:       4749 :                 else if (sm->eapFail || (sm->keyDone && !sm->portValid))
                 [ #  # ]
     387                 :         95 :                         SM_ENTER(SUPP_PAE, HELD);
     388         [ -  + ]:       4654 :                 else if (sm->suppTimeout)
     389                 :          0 :                         SM_ENTER(SUPP_PAE, CONNECTING);
     390                 :       5023 :                 break;
     391                 :            :         case SUPP_PAE_HELD:
     392         [ -  + ]:        285 :                 if (sm->heldWhile == 0)
     393                 :          0 :                         SM_ENTER(SUPP_PAE, CONNECTING);
     394         [ -  + ]:        285 :                 else if (sm->eapolEap)
     395                 :          0 :                         SM_ENTER(SUPP_PAE, RESTART);
     396                 :        285 :                 break;
     397                 :            :         case SUPP_PAE_AUTHENTICATED:
     398 [ +  + ][ +  - ]:        901 :                 if (sm->eapolEap && sm->portValid)
     399                 :         22 :                         SM_ENTER(SUPP_PAE, RESTART);
     400         [ +  + ]:        879 :                 else if (!sm->portValid)
     401                 :         16 :                         SM_ENTER(SUPP_PAE, DISCONNECTED);
     402                 :        901 :                 break;
     403                 :            :         case SUPP_PAE_RESTART:
     404         [ +  - ]:        183 :                 if (!sm->eapRestart)
     405                 :        183 :                         SM_ENTER(SUPP_PAE, AUTHENTICATING);
     406                 :        183 :                 break;
     407                 :            :         case SUPP_PAE_S_FORCE_AUTH:
     408                 :        114 :                 break;
     409                 :            :         case SUPP_PAE_S_FORCE_UNAUTH:
     410                 :          0 :                 break;
     411                 :            :         }
     412                 :      14606 : }
     413                 :            : 
     414                 :            : 
     415                 :       6491 : SM_STATE(KEY_RX, NO_KEY_RECEIVE)
     416                 :            : {
     417 [ +  - ][ +  + ]:       6491 :         SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
     418                 :       6491 : }
     419                 :            : 
     420                 :            : 
     421                 :          4 : SM_STATE(KEY_RX, KEY_RECEIVE)
     422                 :            : {
     423 [ -  + ][ #  # ]:          4 :         SM_ENTRY(KEY_RX, KEY_RECEIVE);
     424                 :          4 :         eapol_sm_processKey(sm);
     425                 :          4 :         sm->rxKey = FALSE;
     426                 :          4 : }
     427                 :            : 
     428                 :            : 
     429                 :      14606 : SM_STEP(KEY_RX)
     430                 :            : {
     431 [ +  + ][ +  + ]:      14606 :         if (sm->initialize || !sm->portEnabled)
     432                 :       6491 :                 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
     433   [ -  +  +  - ]:      14606 :         switch (sm->KEY_RX_state) {
     434                 :            :         case KEY_RX_UNKNOWN:
     435                 :          0 :                 break;
     436                 :            :         case KEY_RX_NO_KEY_RECEIVE:
     437         [ +  + ]:      14598 :                 if (sm->rxKey)
     438                 :          2 :                         SM_ENTER(KEY_RX, KEY_RECEIVE);
     439                 :      14598 :                 break;
     440                 :            :         case KEY_RX_KEY_RECEIVE:
     441         [ +  + ]:          8 :                 if (sm->rxKey)
     442                 :          2 :                         SM_ENTER(KEY_RX, KEY_RECEIVE);
     443                 :          8 :                 break;
     444                 :            :         }
     445                 :      14606 : }
     446                 :            : 
     447                 :            : 
     448                 :       1187 : SM_STATE(SUPP_BE, REQUEST)
     449                 :            : {
     450 [ -  + ][ #  # ]:       1187 :         SM_ENTRY(SUPP_BE, REQUEST);
     451                 :       1187 :         sm->authWhile = 0;
     452                 :       1187 :         sm->eapReq = TRUE;
     453                 :       1187 :         eapol_sm_getSuppRsp(sm);
     454                 :       1187 : }
     455                 :            : 
     456                 :            : 
     457                 :       1005 : SM_STATE(SUPP_BE, RESPONSE)
     458                 :            : {
     459 [ -  + ][ #  # ]:       1005 :         SM_ENTRY(SUPP_BE, RESPONSE);
     460                 :       1005 :         eapol_sm_txSuppRsp(sm);
     461                 :       1005 :         sm->eapResp = FALSE;
     462                 :       1005 : }
     463                 :            : 
     464                 :            : 
     465                 :        280 : SM_STATE(SUPP_BE, SUCCESS)
     466                 :            : {
     467 [ -  + ][ #  # ]:        280 :         SM_ENTRY(SUPP_BE, SUCCESS);
     468                 :        280 :         sm->keyRun = TRUE;
     469                 :        280 :         sm->suppSuccess = TRUE;
     470                 :            : 
     471                 :            : #ifdef CONFIG_EAP_PROXY
     472                 :            :         if (sm->use_eap_proxy) {
     473                 :            :                 if (eap_proxy_key_available(sm->eap_proxy)) {
     474                 :            :                         /* New key received - clear IEEE 802.1X EAPOL-Key replay
     475                 :            :                          * counter */
     476                 :            :                         sm->replay_counter_valid = FALSE;
     477                 :            :                 }
     478                 :            :                 return;
     479                 :            :         }
     480                 :            : #endif /* CONFIG_EAP_PROXY */
     481                 :            : 
     482         [ +  + ]:        280 :         if (eap_key_available(sm->eap)) {
     483                 :            :                 /* New key received - clear IEEE 802.1X EAPOL-Key replay
     484                 :            :                  * counter */
     485                 :        125 :                 sm->replay_counter_valid = FALSE;
     486                 :            :         }
     487                 :        280 : }
     488                 :            : 
     489                 :            : 
     490                 :         95 : SM_STATE(SUPP_BE, FAIL)
     491                 :            : {
     492 [ -  + ][ #  # ]:         95 :         SM_ENTRY(SUPP_BE, FAIL);
     493                 :         95 :         sm->suppFail = TRUE;
     494                 :         95 : }
     495                 :            : 
     496                 :            : 
     497                 :          0 : SM_STATE(SUPP_BE, TIMEOUT)
     498                 :            : {
     499 [ #  # ][ #  # ]:          0 :         SM_ENTRY(SUPP_BE, TIMEOUT);
     500                 :          0 :         sm->suppTimeout = TRUE;
     501                 :          0 : }
     502                 :            : 
     503                 :            : 
     504                 :        820 : SM_STATE(SUPP_BE, IDLE)
     505                 :            : {
     506 [ -  + ][ #  # ]:        820 :         SM_ENTRY(SUPP_BE, IDLE);
     507                 :        820 :         sm->suppStart = FALSE;
     508                 :        820 :         sm->initial_req = TRUE;
     509                 :        820 : }
     510                 :            : 
     511                 :            : 
     512                 :       6507 : SM_STATE(SUPP_BE, INITIALIZE)
     513                 :            : {
     514 [ +  - ][ +  + ]:       6507 :         SM_ENTRY(SUPP_BE, INITIALIZE);
     515                 :       6507 :         eapol_sm_abortSupp(sm);
     516                 :       6507 :         sm->suppAbort = FALSE;
     517                 :            : 
     518                 :            :         /*
     519                 :            :          * IEEE Std 802.1X-2004 does not clear authWhile here, but doing so
     520                 :            :          * allows the timer tick to be stopped more quickly when the port is
     521                 :            :          * not enabled. Since this variable is used only within RECEIVE state,
     522                 :            :          * clearing it on initialization does not change actual state machine
     523                 :            :          * behavior.
     524                 :            :          */
     525                 :       6507 :         sm->authWhile = 0;
     526                 :       6507 : }
     527                 :            : 
     528                 :            : 
     529                 :       1187 : SM_STATE(SUPP_BE, RECEIVE)
     530                 :            : {
     531 [ -  + ][ #  # ]:       1187 :         SM_ENTRY(SUPP_BE, RECEIVE);
     532                 :       1187 :         sm->authWhile = sm->authPeriod;
     533                 :       1187 :         eapol_enable_timer_tick(sm);
     534                 :       1187 :         sm->eapolEap = FALSE;
     535                 :       1187 :         sm->eapNoResp = FALSE;
     536                 :       1187 :         sm->initial_req = FALSE;
     537                 :       1187 : }
     538                 :            : 
     539                 :            : 
     540                 :      14606 : SM_STEP(SUPP_BE)
     541                 :            : {
     542 [ +  + ][ +  + ]:      14606 :         if (sm->initialize || sm->suppAbort)
     543                 :       6507 :                 SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
     544   [ -  +  +  +  :       8099 :         else switch (sm->SUPP_BE_state) {
          +  -  +  +  +  
                      - ]
     545                 :            :         case SUPP_BE_UNKNOWN:
     546                 :          0 :                 break;
     547                 :            :         case SUPP_BE_REQUEST:
     548                 :            :                 /*
     549                 :            :                  * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
     550                 :            :                  * and SUCCESS based on eapFail and eapSuccess, respectively.
     551                 :            :                  * However, IEEE Std 802.1X-2004 is also specifying that
     552                 :            :                  * eapNoResp should be set in conjunction with eapSuccess and
     553                 :            :                  * eapFail which would mean that more than one of the
     554                 :            :                  * transitions here would be activated at the same time.
     555                 :            :                  * Skipping RESPONSE and/or RECEIVE states in these cases can
     556                 :            :                  * cause problems and the direct transitions to do not seem
     557                 :            :                  * correct. Because of this, the conditions for these
     558                 :            :                  * transitions are verified only after eapNoResp. They are
     559                 :            :                  * unlikely to be used since eapNoResp should always be set if
     560                 :            :                  * either of eapSuccess or eapFail is set.
     561                 :            :                  */
     562 [ +  + ][ -  + ]:       1191 :                 if (sm->eapResp && sm->eapNoResp) {
     563                 :          0 :                         wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
     564                 :            :                                    "eapResp and eapNoResp set?!");
     565                 :            :                 }
     566         [ +  + ]:       1191 :                 if (sm->eapResp)
     567                 :       1005 :                         SM_ENTER(SUPP_BE, RESPONSE);
     568         [ +  + ]:        186 :                 else if (sm->eapNoResp)
     569                 :        182 :                         SM_ENTER(SUPP_BE, RECEIVE);
     570         [ -  + ]:          4 :                 else if (sm->eapFail)
     571                 :          0 :                         SM_ENTER(SUPP_BE, FAIL);
     572         [ -  + ]:          4 :                 else if (sm->eapSuccess)
     573                 :          0 :                         SM_ENTER(SUPP_BE, SUCCESS);
     574                 :       1191 :                 break;
     575                 :            :         case SUPP_BE_RESPONSE:
     576                 :       1005 :                 SM_ENTER(SUPP_BE, RECEIVE);
     577                 :       1005 :                 break;
     578                 :            :         case SUPP_BE_SUCCESS:
     579                 :        280 :                 SM_ENTER(SUPP_BE, IDLE);
     580                 :        280 :                 break;
     581                 :            :         case SUPP_BE_FAIL:
     582                 :         95 :                 SM_ENTER(SUPP_BE, IDLE);
     583                 :         95 :                 break;
     584                 :            :         case SUPP_BE_TIMEOUT:
     585                 :          0 :                 SM_ENTER(SUPP_BE, IDLE);
     586                 :          0 :                 break;
     587                 :            :         case SUPP_BE_IDLE:
     588 [ +  + ][ -  + ]:       2887 :                 if (sm->eapFail && sm->suppStart)
     589                 :          0 :                         SM_ENTER(SUPP_BE, FAIL);
     590 [ +  + ][ +  + ]:       2887 :                 else if (sm->eapolEap && sm->suppStart)
     591                 :        183 :                         SM_ENTER(SUPP_BE, REQUEST);
     592 [ +  + ][ +  + ]:       2704 :                 else if (sm->eapSuccess && sm->suppStart)
     593                 :        193 :                         SM_ENTER(SUPP_BE, SUCCESS);
     594                 :       2887 :                 break;
     595                 :            :         case SUPP_BE_INITIALIZE:
     596                 :        445 :                 SM_ENTER(SUPP_BE, IDLE);
     597                 :        445 :                 break;
     598                 :            :         case SUPP_BE_RECEIVE:
     599         [ +  + ]:       2196 :                 if (sm->eapolEap)
     600                 :       1004 :                         SM_ENTER(SUPP_BE, REQUEST);
     601         [ +  + ]:       1192 :                 else if (sm->eapFail)
     602                 :         95 :                         SM_ENTER(SUPP_BE, FAIL);
     603         [ -  + ]:       1097 :                 else if (sm->authWhile == 0)
     604                 :          0 :                         SM_ENTER(SUPP_BE, TIMEOUT);
     605         [ +  + ]:       1097 :                 else if (sm->eapSuccess)
     606                 :         87 :                         SM_ENTER(SUPP_BE, SUCCESS);
     607                 :       2196 :                 break;
     608                 :            :         }
     609                 :      14606 : }
     610                 :            : 
     611                 :            : 
     612                 :          1 : static void eapol_sm_txLogoff(struct eapol_sm *sm)
     613                 :            : {
     614                 :          1 :         wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
     615                 :          1 :         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
     616                 :            :                             IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
     617                 :          1 :         sm->dot1xSuppEapolLogoffFramesTx++;
     618                 :          1 :         sm->dot1xSuppEapolFramesTx++;
     619                 :          1 : }
     620                 :            : 
     621                 :            : 
     622                 :         31 : static void eapol_sm_txStart(struct eapol_sm *sm)
     623                 :            : {
     624                 :         31 :         wpa_printf(MSG_DEBUG, "EAPOL: txStart");
     625                 :         31 :         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
     626                 :            :                             IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
     627                 :         31 :         sm->dot1xSuppEapolStartFramesTx++;
     628                 :         31 :         sm->dot1xSuppEapolFramesTx++;
     629                 :         31 : }
     630                 :            : 
     631                 :            : 
     632                 :            : #define IEEE8021X_ENCR_KEY_LEN 32
     633                 :            : #define IEEE8021X_SIGN_KEY_LEN 32
     634                 :            : 
     635                 :            : struct eap_key_data {
     636                 :            :         u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
     637                 :            :         u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
     638                 :            : };
     639                 :            : 
     640                 :            : 
     641                 :          4 : static void eapol_sm_processKey(struct eapol_sm *sm)
     642                 :            : {
     643                 :            : #ifndef CONFIG_FIPS
     644                 :            :         struct ieee802_1x_hdr *hdr;
     645                 :            :         struct ieee802_1x_eapol_key *key;
     646                 :            :         struct eap_key_data keydata;
     647                 :            :         u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
     648                 :            :         u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
     649                 :            :         int key_len, res, sign_key_len, encr_key_len;
     650                 :            :         u16 rx_key_length;
     651                 :            :         size_t plen;
     652                 :            : 
     653                 :          4 :         wpa_printf(MSG_DEBUG, "EAPOL: processKey");
     654         [ -  + ]:          4 :         if (sm->last_rx_key == NULL)
     655                 :          0 :                 return;
     656                 :            : 
     657         [ -  + ]:          4 :         if (!sm->conf.accept_802_1x_keys) {
     658                 :          0 :                 wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
     659                 :            :                            " even though this was not accepted - "
     660                 :            :                            "ignoring this packet");
     661                 :          0 :                 return;
     662                 :            :         }
     663                 :            : 
     664         [ -  + ]:          4 :         if (sm->last_rx_key_len < sizeof(*hdr) + sizeof(*key))
     665                 :          0 :                 return;
     666                 :          4 :         hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
     667                 :          4 :         key = (struct ieee802_1x_eapol_key *) (hdr + 1);
     668                 :          4 :         plen = be_to_host16(hdr->length);
     669 [ +  - ][ -  + ]:          4 :         if (sizeof(*hdr) + plen > sm->last_rx_key_len || plen < sizeof(*key)) {
     670                 :          0 :                 wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
     671                 :          0 :                 return;
     672                 :            :         }
     673                 :          4 :         rx_key_length = WPA_GET_BE16(key->key_length);
     674                 :          4 :         wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
     675                 :            :                    "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
     676                 :         12 :                    hdr->version, hdr->type, be_to_host16(hdr->length),
     677                 :          8 :                    key->type, rx_key_length, key->key_index);
     678                 :            : 
     679                 :          4 :         eapol_sm_notify_lower_layer_success(sm, 1);
     680                 :          4 :         sign_key_len = IEEE8021X_SIGN_KEY_LEN;
     681                 :          4 :         encr_key_len = IEEE8021X_ENCR_KEY_LEN;
     682                 :          4 :         res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
     683         [ -  + ]:          4 :         if (res < 0) {
     684                 :          0 :                 wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
     685                 :            :                            "decrypting EAPOL-Key keys");
     686                 :          0 :                 return;
     687                 :            :         }
     688         [ -  + ]:          4 :         if (res == 16) {
     689                 :            :                 /* LEAP derives only 16 bytes of keying material. */
     690                 :          0 :                 res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
     691         [ #  # ]:          0 :                 if (res) {
     692                 :          0 :                         wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
     693                 :            :                                    "master key for decrypting EAPOL-Key keys");
     694                 :          0 :                         return;
     695                 :            :                 }
     696                 :          0 :                 sign_key_len = 16;
     697                 :          0 :                 encr_key_len = 16;
     698                 :          0 :                 os_memcpy(keydata.sign_key, keydata.encr_key, 16);
     699         [ -  + ]:          4 :         } else if (res) {
     700                 :          0 :                 wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
     701                 :            :                            "data for decrypting EAPOL-Key keys (res=%d)", res);
     702                 :          0 :                 return;
     703                 :            :         }
     704                 :            : 
     705                 :            :         /* The key replay_counter must increase when same master key */
     706 [ +  + ][ -  + ]:          4 :         if (sm->replay_counter_valid &&
     707                 :          2 :             os_memcmp(sm->last_replay_counter, key->replay_counter,
     708                 :            :                       IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
     709                 :          0 :                 wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
     710                 :            :                            "not increase - ignoring key");
     711                 :          0 :                 wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
     712                 :          0 :                             sm->last_replay_counter,
     713                 :            :                             IEEE8021X_REPLAY_COUNTER_LEN);
     714                 :          0 :                 wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
     715                 :          0 :                             key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
     716                 :          0 :                 return;
     717                 :            :         }
     718                 :            : 
     719                 :            :         /* Verify key signature (HMAC-MD5) */
     720                 :          4 :         os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
     721                 :          4 :         os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
     722                 :          4 :         hmac_md5(keydata.sign_key, sign_key_len,
     723                 :          8 :                  sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
     724                 :          4 :                  key->key_signature);
     725         [ -  + ]:          4 :         if (os_memcmp(orig_key_sign, key->key_signature,
     726                 :            :                       IEEE8021X_KEY_SIGN_LEN) != 0) {
     727                 :          0 :                 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
     728                 :            :                            "EAPOL-Key packet");
     729                 :          0 :                 os_memcpy(key->key_signature, orig_key_sign,
     730                 :            :                           IEEE8021X_KEY_SIGN_LEN);
     731                 :          0 :                 return;
     732                 :            :         }
     733                 :          4 :         wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
     734                 :            : 
     735                 :          4 :         key_len = plen - sizeof(*key);
     736 [ +  - ][ -  + ]:          4 :         if (key_len > 32 || rx_key_length > 32) {
     737         [ #  # ]:          0 :                 wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
     738                 :            :                            key_len ? key_len : rx_key_length);
     739                 :          0 :                 return;
     740                 :            :         }
     741         [ +  - ]:          4 :         if (key_len == rx_key_length) {
     742                 :          4 :                 os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
     743                 :          4 :                 os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
     744                 :            :                           encr_key_len);
     745                 :          4 :                 os_memcpy(datakey, key + 1, key_len);
     746                 :          4 :                 rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
     747                 :            :                          datakey, key_len);
     748                 :          4 :                 wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
     749                 :            :                                 datakey, key_len);
     750         [ #  # ]:          0 :         } else if (key_len == 0) {
     751                 :            :                 /*
     752                 :            :                  * IEEE 802.1X-2004 specifies that least significant Key Length
     753                 :            :                  * octets from MS-MPPE-Send-Key are used as the key if the key
     754                 :            :                  * data is not present. This seems to be meaning the beginning
     755                 :            :                  * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
     756                 :            :                  * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
     757                 :            :                  * Anyway, taking the beginning of the keying material from EAP
     758                 :            :                  * seems to interoperate with Authenticators.
     759                 :            :                  */
     760                 :          0 :                 key_len = rx_key_length;
     761                 :          0 :                 os_memcpy(datakey, keydata.encr_key, key_len);
     762                 :          0 :                 wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
     763                 :            :                                 "material data encryption key",
     764                 :            :                                 datakey, key_len);
     765                 :            :         } else {
     766                 :          0 :                 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
     767                 :            :                            "(key_length=%d)", key_len, rx_key_length);
     768                 :          0 :                 return;
     769                 :            :         }
     770                 :            : 
     771                 :          4 :         sm->replay_counter_valid = TRUE;
     772                 :          4 :         os_memcpy(sm->last_replay_counter, key->replay_counter,
     773                 :            :                   IEEE8021X_REPLAY_COUNTER_LEN);
     774                 :            : 
     775         [ +  + ]:          4 :         wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
     776                 :            :                    "len %d",
     777                 :          4 :                    key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
     778                 :            :                    "unicast" : "broadcast",
     779                 :          4 :                    key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
     780                 :            : 
     781   [ +  -  -  + ]:          8 :         if (sm->ctx->set_wep_key &&
     782                 :          4 :             sm->ctx->set_wep_key(sm->ctx->ctx,
     783                 :          4 :                                  key->key_index & IEEE8021X_KEY_INDEX_FLAG,
     784                 :          4 :                                  key->key_index & IEEE8021X_KEY_INDEX_MASK,
     785                 :            :                                  datakey, key_len) < 0) {
     786                 :          0 :                 wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
     787                 :            :                            " driver.");
     788                 :            :         } else {
     789         [ +  + ]:          4 :                 if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
     790                 :          2 :                         sm->unicast_key_received = TRUE;
     791                 :            :                 else
     792                 :          2 :                         sm->broadcast_key_received = TRUE;
     793                 :            : 
     794 [ +  + ][ -  + ]:          4 :                 if ((sm->unicast_key_received ||
     795         [ -  + ]:          2 :                      !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
     796         [ #  # ]:          0 :                     (sm->broadcast_key_received ||
     797                 :          0 :                      !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
     798                 :            :                 {
     799                 :          2 :                         wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
     800                 :            :                                    "frames received");
     801                 :          2 :                         sm->portValid = TRUE;
     802         [ +  - ]:          2 :                         if (sm->ctx->eapol_done_cb)
     803                 :          4 :                                 sm->ctx->eapol_done_cb(sm->ctx->ctx);
     804                 :            :                 }
     805                 :            :         }
     806                 :            : #endif /* CONFIG_FIPS */
     807                 :            : }
     808                 :            : 
     809                 :            : 
     810                 :       1187 : static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
     811                 :            : {
     812                 :       1187 :         wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
     813                 :            :         /* EAP layer processing; no special code is needed, since Supplicant
     814                 :            :          * Backend state machine is waiting for eapNoResp or eapResp to be set
     815                 :            :          * and these are only set in the EAP state machine when the processing
     816                 :            :          * has finished. */
     817                 :       1187 : }
     818                 :            : 
     819                 :            : 
     820                 :       1005 : static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
     821                 :            : {
     822                 :            :         struct wpabuf *resp;
     823                 :            : 
     824                 :       1005 :         wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
     825                 :            : 
     826                 :            : #ifdef CONFIG_EAP_PROXY
     827                 :            :         if (sm->use_eap_proxy) {
     828                 :            :                 /* Get EAP Response from EAP Proxy */
     829                 :            :                 resp = eap_proxy_get_eapRespData(sm->eap_proxy);
     830                 :            :                 if (resp == NULL) {
     831                 :            :                         wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP Proxy "
     832                 :            :                                    "response data not available");
     833                 :            :                         return;
     834                 :            :                 }
     835                 :            :         } else
     836                 :            : #endif /* CONFIG_EAP_PROXY */
     837                 :            : 
     838                 :       1005 :         resp = eap_get_eapRespData(sm->eap);
     839         [ -  + ]:       1005 :         if (resp == NULL) {
     840                 :          0 :                 wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
     841                 :            :                            "not available");
     842                 :       1005 :                 return;
     843                 :            :         }
     844                 :            : 
     845                 :            :         /* Send EAP-Packet from the EAP layer to the Authenticator */
     846                 :       2010 :         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
     847                 :       1005 :                             IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
     848                 :            :                             wpabuf_len(resp));
     849                 :            : 
     850                 :            :         /* eapRespData is not used anymore, so free it here */
     851                 :       1005 :         wpabuf_free(resp);
     852                 :            : 
     853         [ +  + ]:       1005 :         if (sm->initial_req)
     854                 :        183 :                 sm->dot1xSuppEapolReqIdFramesRx++;
     855                 :            :         else
     856                 :        822 :                 sm->dot1xSuppEapolReqFramesRx++;
     857                 :       1005 :         sm->dot1xSuppEapolRespFramesTx++;
     858                 :       1005 :         sm->dot1xSuppEapolFramesTx++;
     859                 :            : }
     860                 :            : 
     861                 :            : 
     862                 :       6507 : static void eapol_sm_abortSupp(struct eapol_sm *sm)
     863                 :            : {
     864                 :            :         /* release system resources that may have been allocated for the
     865                 :            :          * authentication session */
     866                 :       6507 :         os_free(sm->last_rx_key);
     867                 :       6507 :         sm->last_rx_key = NULL;
     868                 :       6507 :         wpabuf_free(sm->eapReqData);
     869                 :       6507 :         sm->eapReqData = NULL;
     870                 :       6507 :         eap_sm_abort(sm->eap);
     871                 :       6507 : }
     872                 :            : 
     873                 :            : 
     874                 :          0 : static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
     875                 :            : {
     876                 :          0 :         eapol_sm_step(timeout_ctx);
     877                 :          0 : }
     878                 :            : 
     879                 :            : 
     880                 :        364 : static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
     881                 :            : {
     882         [ +  - ]:        364 :         if (sm->ctx->port_cb)
     883                 :        364 :                 sm->ctx->port_cb(sm->ctx->ctx, 1);
     884                 :        364 : }
     885                 :            : 
     886                 :            : 
     887                 :       6608 : static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
     888                 :            : {
     889         [ +  - ]:       6608 :         if (sm->ctx->port_cb)
     890                 :       6608 :                 sm->ctx->port_cb(sm->ctx->ctx, 0);
     891                 :       6608 : }
     892                 :            : 
     893                 :            : 
     894                 :            : /**
     895                 :            :  * eapol_sm_step - EAPOL state machine step function
     896                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
     897                 :            :  *
     898                 :            :  * This function is called to notify the state machine about changed external
     899                 :            :  * variables. It will step through the EAPOL state machines in loop to process
     900                 :            :  * all triggered state changes.
     901                 :            :  */
     902                 :       9144 : void eapol_sm_step(struct eapol_sm *sm)
     903                 :            : {
     904                 :            :         int i;
     905                 :            : 
     906                 :            :         /* In theory, it should be ok to run this in loop until !changed.
     907                 :            :          * However, it is better to use a limit on number of iterations to
     908                 :            :          * allow events (e.g., SIGTERM) to stop the program cleanly if the
     909                 :            :          * state machine were to generate a busy loop. */
     910         [ +  - ]:      14606 :         for (i = 0; i < 100; i++) {
     911                 :      14606 :                 sm->changed = FALSE;
     912                 :      14606 :                 SM_STEP_RUN(SUPP_PAE);
     913                 :      14606 :                 SM_STEP_RUN(KEY_RX);
     914                 :      14606 :                 SM_STEP_RUN(SUPP_BE);
     915                 :            : #ifdef CONFIG_EAP_PROXY
     916                 :            :                 if (sm->use_eap_proxy) {
     917                 :            :                         /* Drive the EAP proxy state machine */
     918                 :            :                         if (eap_proxy_sm_step(sm->eap_proxy, sm->eap))
     919                 :            :                                 sm->changed = TRUE;
     920                 :            :                 } else
     921                 :            : #endif /* CONFIG_EAP_PROXY */
     922         [ +  + ]:      14606 :                 if (eap_peer_sm_step(sm->eap))
     923                 :       1938 :                         sm->changed = TRUE;
     924         [ +  + ]:      14606 :                 if (!sm->changed)
     925                 :       9144 :                         break;
     926                 :            :         }
     927                 :            : 
     928         [ -  + ]:       9144 :         if (sm->changed) {
     929                 :            :                 /* restart EAPOL state machine step from timeout call in order
     930                 :            :                  * to allow other events to be processed. */
     931                 :          0 :                 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
     932                 :          0 :                 eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
     933                 :            :         }
     934                 :            : 
     935 [ +  - ][ +  + ]:       9144 :         if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
     936                 :        369 :                 int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
     937                 :        369 :                 sm->cb_status = EAPOL_CB_IN_PROGRESS;
     938                 :        369 :                 sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
     939                 :            :         }
     940                 :       9144 : }
     941                 :            : 
     942                 :            : 
     943                 :            : #ifdef CONFIG_CTRL_IFACE
     944                 :         60 : static const char *eapol_supp_pae_state(int state)
     945                 :            : {
     946   [ -  -  -  -  :         60 :         switch (state) {
             -  +  -  - ]
     947                 :            :         case SUPP_PAE_LOGOFF:
     948                 :          0 :                 return "LOGOFF";
     949                 :            :         case SUPP_PAE_DISCONNECTED:
     950                 :          0 :                 return "DISCONNECTED";
     951                 :            :         case SUPP_PAE_CONNECTING:
     952                 :          0 :                 return "CONNECTING";
     953                 :            :         case SUPP_PAE_AUTHENTICATING:
     954                 :          0 :                 return "AUTHENTICATING";
     955                 :            :         case SUPP_PAE_HELD:
     956                 :          0 :                 return "HELD";
     957                 :            :         case SUPP_PAE_AUTHENTICATED:
     958                 :         60 :                 return "AUTHENTICATED";
     959                 :            :         case SUPP_PAE_RESTART:
     960                 :          0 :                 return "RESTART";
     961                 :            :         default:
     962                 :         60 :                 return "UNKNOWN";
     963                 :            :         }
     964                 :            : }
     965                 :            : 
     966                 :            : 
     967                 :          0 : static const char *eapol_supp_be_state(int state)
     968                 :            : {
     969   [ #  #  #  #  :          0 :         switch (state) {
             #  #  #  #  
                      # ]
     970                 :            :         case SUPP_BE_REQUEST:
     971                 :          0 :                 return "REQUEST";
     972                 :            :         case SUPP_BE_RESPONSE:
     973                 :          0 :                 return "RESPONSE";
     974                 :            :         case SUPP_BE_SUCCESS:
     975                 :          0 :                 return "SUCCESS";
     976                 :            :         case SUPP_BE_FAIL:
     977                 :          0 :                 return "FAIL";
     978                 :            :         case SUPP_BE_TIMEOUT:
     979                 :          0 :                 return "TIMEOUT";
     980                 :            :         case SUPP_BE_IDLE:
     981                 :          0 :                 return "IDLE";
     982                 :            :         case SUPP_BE_INITIALIZE:
     983                 :          0 :                 return "INITIALIZE";
     984                 :            :         case SUPP_BE_RECEIVE:
     985                 :          0 :                 return "RECEIVE";
     986                 :            :         default:
     987                 :          0 :                 return "UNKNOWN";
     988                 :            :         }
     989                 :            : }
     990                 :            : 
     991                 :            : 
     992                 :         60 : static const char * eapol_port_status(PortStatus status)
     993                 :            : {
     994         [ +  - ]:         60 :         if (status == Authorized)
     995                 :         60 :                 return "Authorized";
     996                 :            :         else
     997                 :         60 :                 return "Unauthorized";
     998                 :            : }
     999                 :            : #endif /* CONFIG_CTRL_IFACE */
    1000                 :            : 
    1001                 :            : 
    1002                 :            : #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
    1003                 :        460 : static const char * eapol_port_control(PortControl ctrl)
    1004                 :            : {
    1005   [ +  -  +  - ]:        460 :         switch (ctrl) {
    1006                 :            :         case Auto:
    1007                 :        371 :                 return "Auto";
    1008                 :            :         case ForceUnauthorized:
    1009                 :          0 :                 return "ForceUnauthorized";
    1010                 :            :         case ForceAuthorized:
    1011                 :         89 :                 return "ForceAuthorized";
    1012                 :            :         default:
    1013                 :        460 :                 return "Unknown";
    1014                 :            :         }
    1015                 :            : }
    1016                 :            : #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
    1017                 :            : 
    1018                 :            : 
    1019                 :            : /**
    1020                 :            :  * eapol_sm_configure - Set EAPOL variables
    1021                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1022                 :            :  * @heldPeriod: dot1xSuppHeldPeriod
    1023                 :            :  * @authPeriod: dot1xSuppAuthPeriod
    1024                 :            :  * @startPeriod: dot1xSuppStartPeriod
    1025                 :            :  * @maxStart: dot1xSuppMaxStart
    1026                 :            :  *
    1027                 :            :  * Set configurable EAPOL state machine variables. Each variable can be set to
    1028                 :            :  * the given value or ignored if set to -1 (to set only some of the variables).
    1029                 :            :  */
    1030                 :          0 : void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
    1031                 :            :                         int startPeriod, int maxStart)
    1032                 :            : {
    1033         [ #  # ]:          0 :         if (sm == NULL)
    1034                 :          0 :                 return;
    1035         [ #  # ]:          0 :         if (heldPeriod >= 0)
    1036                 :          0 :                 sm->heldPeriod = heldPeriod;
    1037         [ #  # ]:          0 :         if (authPeriod >= 0)
    1038                 :          0 :                 sm->authPeriod = authPeriod;
    1039         [ #  # ]:          0 :         if (startPeriod >= 0)
    1040                 :          0 :                 sm->startPeriod = startPeriod;
    1041         [ #  # ]:          0 :         if (maxStart >= 0)
    1042                 :          0 :                 sm->maxStart = maxStart;
    1043                 :            : }
    1044                 :            : 
    1045                 :            : 
    1046                 :            : /**
    1047                 :            :  * eapol_sm_get_method_name - Get EAPOL method name
    1048                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1049                 :            :  * Returns: Static string containing name of current eap method or NULL
    1050                 :            :  */
    1051                 :          0 : const char * eapol_sm_get_method_name(struct eapol_sm *sm)
    1052                 :            : {
    1053 [ #  # ][ #  # ]:          0 :         if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED ||
    1054                 :          0 :             sm->suppPortStatus != Authorized)
    1055                 :          0 :                 return NULL;
    1056                 :            : 
    1057                 :          0 :         return eap_sm_get_method_name(sm->eap);
    1058                 :            : }
    1059                 :            : 
    1060                 :            : 
    1061                 :            : #ifdef CONFIG_CTRL_IFACE
    1062                 :            : /**
    1063                 :            :  * eapol_sm_get_status - Get EAPOL state machine status
    1064                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1065                 :            :  * @buf: Buffer for status information
    1066                 :            :  * @buflen: Maximum buffer length
    1067                 :            :  * @verbose: Whether to include verbose status information
    1068                 :            :  * Returns: Number of bytes written to buf.
    1069                 :            :  *
    1070                 :            :  * Query EAPOL state machine for status information. This function fills in a
    1071                 :            :  * text area with current status information from the EAPOL state machine. If
    1072                 :            :  * the buffer (buf) is not large enough, status information will be truncated
    1073                 :            :  * to fit the buffer.
    1074                 :            :  */
    1075                 :         60 : int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
    1076                 :            :                         int verbose)
    1077                 :            : {
    1078                 :            :         int len, ret;
    1079         [ -  + ]:         60 :         if (sm == NULL)
    1080                 :          0 :                 return 0;
    1081                 :            : 
    1082                 :         60 :         len = os_snprintf(buf, buflen,
    1083                 :            :                           "Supplicant PAE state=%s\n"
    1084                 :            :                           "suppPortStatus=%s\n",
    1085                 :         60 :                           eapol_supp_pae_state(sm->SUPP_PAE_state),
    1086                 :            :                           eapol_port_status(sm->suppPortStatus));
    1087 [ +  - ][ -  + ]:         60 :         if (len < 0 || (size_t) len >= buflen)
    1088                 :          0 :                 return 0;
    1089                 :            : 
    1090         [ -  + ]:         60 :         if (verbose) {
    1091                 :          0 :                 ret = os_snprintf(buf + len, buflen - len,
    1092                 :            :                                   "heldPeriod=%u\n"
    1093                 :            :                                   "authPeriod=%u\n"
    1094                 :            :                                   "startPeriod=%u\n"
    1095                 :            :                                   "maxStart=%u\n"
    1096                 :            :                                   "portControl=%s\n"
    1097                 :            :                                   "Supplicant Backend state=%s\n",
    1098                 :            :                                   sm->heldPeriod,
    1099                 :            :                                   sm->authPeriod,
    1100                 :            :                                   sm->startPeriod,
    1101                 :            :                                   sm->maxStart,
    1102                 :            :                                   eapol_port_control(sm->portControl),
    1103                 :          0 :                                   eapol_supp_be_state(sm->SUPP_BE_state));
    1104 [ #  # ][ #  # ]:          0 :                 if (ret < 0 || (size_t) ret >= buflen - len)
    1105                 :          0 :                         return len;
    1106                 :          0 :                 len += ret;
    1107                 :            :         }
    1108                 :            : 
    1109                 :            : #ifdef CONFIG_EAP_PROXY
    1110                 :            :         if (sm->use_eap_proxy)
    1111                 :            :                 len += eap_proxy_sm_get_status(sm->eap_proxy,
    1112                 :            :                                                buf + len, buflen - len,
    1113                 :            :                                                verbose);
    1114                 :            :         else
    1115                 :            : #endif /* CONFIG_EAP_PROXY */
    1116                 :         60 :         len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
    1117                 :            : 
    1118                 :         60 :         return len;
    1119                 :            : }
    1120                 :            : 
    1121                 :            : 
    1122                 :            : /**
    1123                 :            :  * eapol_sm_get_mib - Get EAPOL state machine MIBs
    1124                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1125                 :            :  * @buf: Buffer for MIB information
    1126                 :            :  * @buflen: Maximum buffer length
    1127                 :            :  * Returns: Number of bytes written to buf.
    1128                 :            :  *
    1129                 :            :  * Query EAPOL state machine for MIB information. This function fills in a
    1130                 :            :  * text area with current MIB information from the EAPOL state machine. If
    1131                 :            :  * the buffer (buf) is not large enough, MIB information will be truncated to
    1132                 :            :  * fit the buffer.
    1133                 :            :  */
    1134                 :          0 : int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
    1135                 :            : {
    1136                 :            :         size_t len;
    1137                 :            :         int ret;
    1138                 :            : 
    1139         [ #  # ]:          0 :         if (sm == NULL)
    1140                 :          0 :                 return 0;
    1141         [ #  # ]:          0 :         ret = os_snprintf(buf, buflen,
    1142                 :            :                           "dot1xSuppPaeState=%d\n"
    1143                 :            :                           "dot1xSuppHeldPeriod=%u\n"
    1144                 :            :                           "dot1xSuppAuthPeriod=%u\n"
    1145                 :            :                           "dot1xSuppStartPeriod=%u\n"
    1146                 :            :                           "dot1xSuppMaxStart=%u\n"
    1147                 :            :                           "dot1xSuppSuppControlledPortStatus=%s\n"
    1148                 :            :                           "dot1xSuppBackendPaeState=%d\n",
    1149                 :          0 :                           sm->SUPP_PAE_state,
    1150                 :            :                           sm->heldPeriod,
    1151                 :            :                           sm->authPeriod,
    1152                 :            :                           sm->startPeriod,
    1153                 :            :                           sm->maxStart,
    1154                 :          0 :                           sm->suppPortStatus == Authorized ?
    1155                 :            :                           "Authorized" : "Unauthorized",
    1156                 :          0 :                           sm->SUPP_BE_state);
    1157                 :            : 
    1158 [ #  # ][ #  # ]:          0 :         if (ret < 0 || (size_t) ret >= buflen)
    1159                 :          0 :                 return 0;
    1160                 :          0 :         len = ret;
    1161                 :            : 
    1162                 :          0 :         ret = os_snprintf(buf + len, buflen - len,
    1163                 :            :                           "dot1xSuppEapolFramesRx=%u\n"
    1164                 :            :                           "dot1xSuppEapolFramesTx=%u\n"
    1165                 :            :                           "dot1xSuppEapolStartFramesTx=%u\n"
    1166                 :            :                           "dot1xSuppEapolLogoffFramesTx=%u\n"
    1167                 :            :                           "dot1xSuppEapolRespFramesTx=%u\n"
    1168                 :            :                           "dot1xSuppEapolReqIdFramesRx=%u\n"
    1169                 :            :                           "dot1xSuppEapolReqFramesRx=%u\n"
    1170                 :            :                           "dot1xSuppInvalidEapolFramesRx=%u\n"
    1171                 :            :                           "dot1xSuppEapLengthErrorFramesRx=%u\n"
    1172                 :            :                           "dot1xSuppLastEapolFrameVersion=%u\n"
    1173                 :            :                           "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
    1174                 :            :                           sm->dot1xSuppEapolFramesRx,
    1175                 :            :                           sm->dot1xSuppEapolFramesTx,
    1176                 :            :                           sm->dot1xSuppEapolStartFramesTx,
    1177                 :            :                           sm->dot1xSuppEapolLogoffFramesTx,
    1178                 :            :                           sm->dot1xSuppEapolRespFramesTx,
    1179                 :            :                           sm->dot1xSuppEapolReqIdFramesRx,
    1180                 :            :                           sm->dot1xSuppEapolReqFramesRx,
    1181                 :            :                           sm->dot1xSuppInvalidEapolFramesRx,
    1182                 :            :                           sm->dot1xSuppEapLengthErrorFramesRx,
    1183                 :            :                           sm->dot1xSuppLastEapolFrameVersion,
    1184                 :          0 :                           MAC2STR(sm->dot1xSuppLastEapolFrameSource));
    1185                 :            : 
    1186 [ #  # ][ #  # ]:          0 :         if (ret < 0 || (size_t) ret >= buflen - len)
    1187                 :          0 :                 return len;
    1188                 :          0 :         len += ret;
    1189                 :            : 
    1190                 :          0 :         return len;
    1191                 :            : }
    1192                 :            : #endif /* CONFIG_CTRL_IFACE */
    1193                 :            : 
    1194                 :            : 
    1195                 :            : /**
    1196                 :            :  * eapol_sm_rx_eapol - Process received EAPOL frames
    1197                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1198                 :            :  * @src: Source MAC address of the EAPOL packet
    1199                 :            :  * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
    1200                 :            :  * @len: Length of the EAPOL frame
    1201                 :            :  * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
    1202                 :            :  * -1 failure
    1203                 :            :  */
    1204                 :       1513 : int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
    1205                 :            :                       size_t len)
    1206                 :            : {
    1207                 :            :         const struct ieee802_1x_hdr *hdr;
    1208                 :            :         const struct ieee802_1x_eapol_key *key;
    1209                 :            :         int data_len;
    1210                 :       1513 :         int res = 1;
    1211                 :            :         size_t plen;
    1212                 :            : 
    1213         [ -  + ]:       1513 :         if (sm == NULL)
    1214                 :          0 :                 return 0;
    1215                 :       1513 :         sm->dot1xSuppEapolFramesRx++;
    1216         [ -  + ]:       1513 :         if (len < sizeof(*hdr)) {
    1217                 :          0 :                 sm->dot1xSuppInvalidEapolFramesRx++;
    1218                 :          0 :                 return 0;
    1219                 :            :         }
    1220                 :       1513 :         hdr = (const struct ieee802_1x_hdr *) buf;
    1221                 :       1513 :         sm->dot1xSuppLastEapolFrameVersion = hdr->version;
    1222                 :       1513 :         os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
    1223                 :       1513 :         if (hdr->version < EAPOL_VERSION) {
    1224                 :            :                 /* TODO: backwards compatibility */
    1225                 :            :         }
    1226                 :       1513 :         plen = be_to_host16(hdr->length);
    1227         [ -  + ]:       1513 :         if (plen > len - sizeof(*hdr)) {
    1228                 :          0 :                 sm->dot1xSuppEapLengthErrorFramesRx++;
    1229                 :          0 :                 return 0;
    1230                 :            :         }
    1231                 :            : #ifdef CONFIG_WPS
    1232 [ +  - ][ -  + ]:       1513 :         if (sm->conf.workaround &&
    1233         [ #  # ]:          0 :             plen < len - sizeof(*hdr) &&
    1234         [ #  # ]:          0 :             hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
    1235                 :          0 :             len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
    1236                 :          0 :                 const struct eap_hdr *ehdr =
    1237                 :            :                         (const struct eap_hdr *) (hdr + 1);
    1238                 :            :                 u16 elen;
    1239                 :            : 
    1240                 :          0 :                 elen = be_to_host16(ehdr->length);
    1241 [ #  # ][ #  # ]:          0 :                 if (elen > plen && elen <= len - sizeof(*hdr)) {
    1242                 :            :                         /*
    1243                 :            :                          * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
    1244                 :            :                          * packets with too short EAPOL header length field
    1245                 :            :                          * (14 octets). This is fixed in firmware Ver.1.49.
    1246                 :            :                          * As a workaround, fix the EAPOL header based on the
    1247                 :            :                          * correct length in the EAP packet.
    1248                 :            :                          */
    1249                 :          0 :                         wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
    1250                 :            :                                    "payload length based on EAP header: "
    1251                 :            :                                    "%d -> %d", (int) plen, elen);
    1252                 :          0 :                         plen = elen;
    1253                 :            :                 }
    1254                 :            :         }
    1255                 :            : #endif /* CONFIG_WPS */
    1256                 :       1513 :         data_len = plen + sizeof(*hdr);
    1257                 :            : 
    1258      [ +  +  - ]:       1513 :         switch (hdr->type) {
    1259                 :            :         case IEEE802_1X_TYPE_EAP_PACKET:
    1260         [ +  - ]:       1187 :                 if (sm->conf.workaround) {
    1261                 :            :                         /*
    1262                 :            :                          * An AP has been reported to send out EAP message with
    1263                 :            :                          * undocumented code 10 at some point near the
    1264                 :            :                          * completion of EAP authentication. This can result in
    1265                 :            :                          * issues with the unexpected EAP message triggering
    1266                 :            :                          * restart of EAPOL authentication. Avoid this by
    1267                 :            :                          * skipping the message without advancing the state
    1268                 :            :                          * machine.
    1269                 :            :                          */
    1270                 :       1187 :                         const struct eap_hdr *ehdr =
    1271                 :            :                                 (const struct eap_hdr *) (hdr + 1);
    1272 [ +  - ][ -  + ]:       1187 :                         if (plen >= sizeof(*ehdr) && ehdr->code == 10) {
    1273                 :          0 :                                 wpa_printf(MSG_DEBUG, "EAPOL: Ignore EAP packet with unknown code 10");
    1274                 :          0 :                                 break;
    1275                 :            :                         }
    1276                 :            :                 }
    1277                 :            : 
    1278         [ +  + ]:       1187 :                 if (sm->cached_pmk) {
    1279                 :            :                         /* Trying to use PMKSA caching, but Authenticator did
    1280                 :            :                          * not seem to have a matching entry. Need to restart
    1281                 :            :                          * EAPOL state machines.
    1282                 :            :                          */
    1283                 :          5 :                         eapol_sm_abort_cached(sm);
    1284                 :            :                 }
    1285                 :       1187 :                 wpabuf_free(sm->eapReqData);
    1286                 :       1187 :                 sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
    1287         [ +  - ]:       1187 :                 if (sm->eapReqData) {
    1288                 :       1187 :                         wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
    1289                 :            :                                    "frame");
    1290                 :       1187 :                         sm->eapolEap = TRUE;
    1291                 :            : #ifdef CONFIG_EAP_PROXY
    1292                 :            :                         if (sm->use_eap_proxy) {
    1293                 :            :                                 eap_proxy_packet_update(
    1294                 :            :                                         sm->eap_proxy,
    1295                 :            :                                         wpabuf_mhead_u8(sm->eapReqData),
    1296                 :            :                                         wpabuf_len(sm->eapReqData));
    1297                 :            :                                 wpa_printf(MSG_DEBUG, "EAPOL: eap_proxy "
    1298                 :            :                                            "EAP Req updated");
    1299                 :            :                         }
    1300                 :            : #endif /* CONFIG_EAP_PROXY */
    1301                 :       1187 :                         eapol_sm_step(sm);
    1302                 :            :                 }
    1303                 :       1187 :                 break;
    1304                 :            :         case IEEE802_1X_TYPE_EAPOL_KEY:
    1305         [ -  + ]:        326 :                 if (plen < sizeof(*key)) {
    1306                 :          0 :                         wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
    1307                 :            :                                    "frame received");
    1308                 :          0 :                         break;
    1309                 :            :                 }
    1310                 :        326 :                 key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
    1311 [ +  + ][ +  + ]:        326 :                 if (key->type == EAPOL_KEY_TYPE_WPA ||
    1312                 :        320 :                     key->type == EAPOL_KEY_TYPE_RSN) {
    1313                 :            :                         /* WPA Supplicant takes care of this frame. */
    1314                 :        322 :                         wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
    1315                 :            :                                    "frame in EAPOL state machines");
    1316                 :        322 :                         res = 0;
    1317                 :        322 :                         break;
    1318                 :            :                 }
    1319         [ -  + ]:          4 :                 if (key->type != EAPOL_KEY_TYPE_RC4) {
    1320                 :          0 :                         wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
    1321                 :          0 :                                    "EAPOL-Key type %d", key->type);
    1322                 :          0 :                         break;
    1323                 :            :                 }
    1324                 :          4 :                 os_free(sm->last_rx_key);
    1325                 :          4 :                 sm->last_rx_key = os_malloc(data_len);
    1326         [ +  - ]:          4 :                 if (sm->last_rx_key) {
    1327                 :          4 :                         wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
    1328                 :            :                                    "frame");
    1329                 :          4 :                         os_memcpy(sm->last_rx_key, buf, data_len);
    1330                 :          4 :                         sm->last_rx_key_len = data_len;
    1331                 :          4 :                         sm->rxKey = TRUE;
    1332                 :          4 :                         eapol_sm_step(sm);
    1333                 :            :                 }
    1334                 :          4 :                 break;
    1335                 :            :         default:
    1336                 :          0 :                 wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
    1337                 :          0 :                            hdr->type);
    1338                 :          0 :                 sm->dot1xSuppInvalidEapolFramesRx++;
    1339                 :          0 :                 break;
    1340                 :            :         }
    1341                 :            : 
    1342                 :       1513 :         return res;
    1343                 :            : }
    1344                 :            : 
    1345                 :            : 
    1346                 :            : /**
    1347                 :            :  * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
    1348                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1349                 :            :  *
    1350                 :            :  * Notify EAPOL state machine about transmitted EAPOL packet from an external
    1351                 :            :  * component, e.g., WPA. This will update the statistics.
    1352                 :            :  */
    1353                 :        559 : void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
    1354                 :            : {
    1355         [ +  + ]:        559 :         if (sm)
    1356                 :        547 :                 sm->dot1xSuppEapolFramesTx++;
    1357                 :        559 : }
    1358                 :            : 
    1359                 :            : 
    1360                 :            : /**
    1361                 :            :  * eapol_sm_notify_portEnabled - Notification about portEnabled change
    1362                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1363                 :            :  * @enabled: New portEnabled value
    1364                 :            :  *
    1365                 :            :  * Notify EAPOL state machine about new portEnabled value.
    1366                 :            :  */
    1367                 :       2194 : void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
    1368                 :            : {
    1369         [ +  + ]:       2194 :         if (sm == NULL)
    1370                 :       2194 :                 return;
    1371                 :       2163 :         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
    1372                 :            :                    "portEnabled=%d", enabled);
    1373                 :       2163 :         sm->portEnabled = enabled;
    1374                 :       2163 :         eapol_sm_step(sm);
    1375                 :            : }
    1376                 :            : 
    1377                 :            : 
    1378                 :            : /**
    1379                 :            :  * eapol_sm_notify_portValid - Notification about portValid change
    1380                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1381                 :            :  * @valid: New portValid value
    1382                 :            :  *
    1383                 :            :  * Notify EAPOL state machine about new portValid value.
    1384                 :            :  */
    1385                 :       2309 : void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
    1386                 :            : {
    1387         [ +  + ]:       2309 :         if (sm == NULL)
    1388                 :       2309 :                 return;
    1389                 :       2266 :         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
    1390                 :            :                    "portValid=%d", valid);
    1391                 :       2266 :         sm->portValid = valid;
    1392                 :       2266 :         eapol_sm_step(sm);
    1393                 :            : }
    1394                 :            : 
    1395                 :            : 
    1396                 :            : /**
    1397                 :            :  * eapol_sm_notify_eap_success - Notification of external EAP success trigger
    1398                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1399                 :            :  * @success: %TRUE = set success, %FALSE = clear success
    1400                 :            :  *
    1401                 :            :  * Notify the EAPOL state machine that external event has forced EAP state to
    1402                 :            :  * success (success = %TRUE). This can be cleared by setting success = %FALSE.
    1403                 :            :  *
    1404                 :            :  * This function is called to update EAP state when WPA-PSK key handshake has
    1405                 :            :  * been completed successfully since WPA-PSK does not use EAP state machine.
    1406                 :            :  */
    1407                 :        970 : void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
    1408                 :            : {
    1409         [ +  + ]:        970 :         if (sm == NULL)
    1410                 :        970 :                 return;
    1411                 :        964 :         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
    1412                 :            :                    "EAP success=%d", success);
    1413                 :        964 :         sm->eapSuccess = success;
    1414                 :        964 :         sm->altAccept = success;
    1415         [ +  + ]:        964 :         if (success)
    1416                 :        199 :                 eap_notify_success(sm->eap);
    1417                 :        964 :         eapol_sm_step(sm);
    1418                 :            : }
    1419                 :            : 
    1420                 :            : 
    1421                 :            : /**
    1422                 :            :  * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
    1423                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1424                 :            :  * @fail: %TRUE = set failure, %FALSE = clear failure
    1425                 :            :  *
    1426                 :            :  * Notify EAPOL state machine that external event has forced EAP state to
    1427                 :            :  * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
    1428                 :            :  */
    1429                 :        460 : void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
    1430                 :            : {
    1431         [ -  + ]:        460 :         if (sm == NULL)
    1432                 :        460 :                 return;
    1433                 :        460 :         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
    1434                 :            :                    "EAP fail=%d", fail);
    1435                 :        460 :         sm->eapFail = fail;
    1436                 :        460 :         sm->altReject = fail;
    1437                 :        460 :         eapol_sm_step(sm);
    1438                 :            : }
    1439                 :            : 
    1440                 :            : 
    1441                 :            : /**
    1442                 :            :  * eapol_sm_notify_config - Notification of EAPOL configuration change
    1443                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1444                 :            :  * @config: Pointer to current network EAP configuration
    1445                 :            :  * @conf: Pointer to EAPOL configuration data
    1446                 :            :  *
    1447                 :            :  * Notify EAPOL state machine that configuration has changed. config will be
    1448                 :            :  * stored as a backpointer to network configuration. This can be %NULL to clear
    1449                 :            :  * the stored pointed. conf will be copied to local EAPOL/EAP configuration
    1450                 :            :  * data. If conf is %NULL, this part of the configuration change will be
    1451                 :            :  * skipped.
    1452                 :            :  */
    1453                 :       2737 : void eapol_sm_notify_config(struct eapol_sm *sm,
    1454                 :            :                             struct eap_peer_config *config,
    1455                 :            :                             const struct eapol_config *conf)
    1456                 :            : {
    1457         [ -  + ]:       2737 :         if (sm == NULL)
    1458                 :          0 :                 return;
    1459                 :            : 
    1460                 :       2737 :         sm->config = config;
    1461                 :            : #ifdef CONFIG_EAP_PROXY
    1462                 :            :         sm->use_eap_proxy = eap_proxy_notify_config(sm->eap_proxy, config) > 0;
    1463                 :            : #endif /* CONFIG_EAP_PROXY */
    1464                 :            : 
    1465         [ +  + ]:       2737 :         if (conf == NULL)
    1466                 :       2280 :                 return;
    1467                 :            : 
    1468                 :        457 :         sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
    1469                 :        457 :         sm->conf.required_keys = conf->required_keys;
    1470                 :        457 :         sm->conf.fast_reauth = conf->fast_reauth;
    1471                 :        457 :         sm->conf.workaround = conf->workaround;
    1472                 :            : #ifdef CONFIG_EAP_PROXY
    1473                 :            :         if (sm->use_eap_proxy) {
    1474                 :            :                 /* Using EAP Proxy, so skip EAP state machine update */
    1475                 :            :                 return;
    1476                 :            :         }
    1477                 :            : #endif /* CONFIG_EAP_PROXY */
    1478         [ +  - ]:        457 :         if (sm->eap) {
    1479                 :        457 :                 eap_set_fast_reauth(sm->eap, conf->fast_reauth);
    1480                 :        457 :                 eap_set_workaround(sm->eap, conf->workaround);
    1481                 :        457 :                 eap_set_force_disabled(sm->eap, conf->eap_disabled);
    1482                 :       2737 :                 eap_set_external_sim(sm->eap, conf->external_sim);
    1483                 :            :         }
    1484                 :            : }
    1485                 :            : 
    1486                 :            : 
    1487                 :            : /**
    1488                 :            :  * eapol_sm_get_key - Get master session key (MSK) from EAP
    1489                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1490                 :            :  * @key: Pointer for key buffer
    1491                 :            :  * @len: Number of bytes to copy to key
    1492                 :            :  * Returns: 0 on success (len of key available), maximum available key len
    1493                 :            :  * (>0) if key is available but it is shorter than len, or -1 on failure.
    1494                 :            :  *
    1495                 :            :  * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
    1496                 :            :  * is available only after a successful authentication.
    1497                 :            :  */
    1498                 :        170 : int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
    1499                 :            : {
    1500                 :            :         const u8 *eap_key;
    1501                 :            :         size_t eap_len;
    1502                 :            : 
    1503                 :            : #ifdef CONFIG_EAP_PROXY
    1504                 :            :         if (sm->use_eap_proxy) {
    1505                 :            :                 /* Get key from EAP proxy */
    1506                 :            :                 if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) {
    1507                 :            :                         wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
    1508                 :            :                         return -1;
    1509                 :            :                 }
    1510                 :            :                 eap_key = eap_proxy_get_eapKeyData(sm->eap_proxy, &eap_len);
    1511                 :            :                 if (eap_key == NULL) {
    1512                 :            :                         wpa_printf(MSG_DEBUG, "EAPOL: Failed to get "
    1513                 :            :                                    "eapKeyData");
    1514                 :            :                         return -1;
    1515                 :            :                 }
    1516                 :            :                 goto key_fetched;
    1517                 :            :         }
    1518                 :            : #endif /* CONFIG_EAP_PROXY */
    1519 [ +  - ][ -  + ]:        170 :         if (sm == NULL || !eap_key_available(sm->eap)) {
    1520                 :          0 :                 wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
    1521                 :          0 :                 return -1;
    1522                 :            :         }
    1523                 :        170 :         eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
    1524         [ -  + ]:        170 :         if (eap_key == NULL) {
    1525                 :          0 :                 wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
    1526                 :          0 :                 return -1;
    1527                 :            :         }
    1528                 :            : #ifdef CONFIG_EAP_PROXY
    1529                 :            : key_fetched:
    1530                 :            : #endif /* CONFIG_EAP_PROXY */
    1531         [ -  + ]:        170 :         if (len > eap_len) {
    1532                 :          0 :                 wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
    1533                 :            :                            "available (len=%lu)",
    1534                 :            :                            (unsigned long) len, (unsigned long) eap_len);
    1535                 :          0 :                 return eap_len;
    1536                 :            :         }
    1537                 :        170 :         os_memcpy(key, eap_key, len);
    1538                 :        170 :         wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
    1539                 :            :                    (unsigned long) len);
    1540                 :        170 :         return 0;
    1541                 :            : }
    1542                 :            : 
    1543                 :            : 
    1544                 :            : /**
    1545                 :            :  * eapol_sm_notify_logoff - Notification of logon/logoff commands
    1546                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1547                 :            :  * @logoff: Whether command was logoff
    1548                 :            :  *
    1549                 :            :  * Notify EAPOL state machines that user requested logon/logoff.
    1550                 :            :  */
    1551                 :        726 : void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
    1552                 :            : {
    1553         [ +  - ]:        726 :         if (sm) {
    1554                 :        726 :                 sm->userLogoff = logoff;
    1555         [ +  + ]:        726 :                 if (!logoff) {
    1556                 :            :                         /* If there is a delayed txStart queued, start now. */
    1557                 :        725 :                         sm->startWhen = 0;
    1558                 :            :                 }
    1559                 :        726 :                 eapol_sm_step(sm);
    1560                 :            :         }
    1561                 :        726 : }
    1562                 :            : 
    1563                 :            : 
    1564                 :            : /**
    1565                 :            :  * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
    1566                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1567                 :            :  *
    1568                 :            :  * Notify EAPOL state machines that PMKSA caching was successful. This is used
    1569                 :            :  * to move EAPOL and EAP state machines into authenticated/successful state.
    1570                 :            :  */
    1571                 :          5 : void eapol_sm_notify_cached(struct eapol_sm *sm)
    1572                 :            : {
    1573         [ -  + ]:          5 :         if (sm == NULL)
    1574                 :          5 :                 return;
    1575                 :          5 :         wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
    1576                 :          5 :         sm->eapSuccess = TRUE;
    1577                 :          5 :         eap_notify_success(sm->eap);
    1578                 :          5 :         eapol_sm_step(sm);
    1579                 :            : }
    1580                 :            : 
    1581                 :            : 
    1582                 :            : /**
    1583                 :            :  * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
    1584                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1585                 :            :  * @attempt: Whether PMKSA caching is tried
    1586                 :            :  *
    1587                 :            :  * Notify EAPOL state machines whether PMKSA caching is used.
    1588                 :            :  */
    1589                 :          6 : void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
    1590                 :            : {
    1591         [ -  + ]:          6 :         if (sm == NULL)
    1592                 :          6 :                 return;
    1593         [ +  - ]:          6 :         if (attempt) {
    1594                 :          6 :                 wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
    1595                 :          6 :                 sm->cached_pmk = TRUE;
    1596                 :            :         } else {
    1597                 :          0 :                 wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
    1598                 :          0 :                 sm->cached_pmk = FALSE;
    1599                 :            :         }
    1600                 :            : }
    1601                 :            : 
    1602                 :            : 
    1603                 :          5 : static void eapol_sm_abort_cached(struct eapol_sm *sm)
    1604                 :            : {
    1605                 :          5 :         wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
    1606                 :            :                    "doing full EAP authentication");
    1607         [ -  + ]:          5 :         if (sm == NULL)
    1608                 :          5 :                 return;
    1609                 :          5 :         sm->cached_pmk = FALSE;
    1610                 :          5 :         sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
    1611                 :          5 :         sm->suppPortStatus = Unauthorized;
    1612                 :          5 :         eapol_sm_set_port_unauthorized(sm);
    1613                 :            : 
    1614                 :            :         /* Make sure we do not start sending EAPOL-Start frames first, but
    1615                 :            :          * instead move to RESTART state to start EAPOL authentication. */
    1616                 :          5 :         sm->startWhen = 3;
    1617                 :          5 :         eapol_enable_timer_tick(sm);
    1618                 :            : 
    1619         [ +  - ]:          5 :         if (sm->ctx->aborted_cached)
    1620                 :          5 :                 sm->ctx->aborted_cached(sm->ctx->ctx);
    1621                 :            : }
    1622                 :            : 
    1623                 :            : 
    1624                 :            : /**
    1625                 :            :  * eapol_sm_register_scard_ctx - Notification of smart card context
    1626                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1627                 :            :  * @ctx: Context data for smart card operations
    1628                 :            :  *
    1629                 :            :  * Notify EAPOL state machines of context data for smart card operations. This
    1630                 :            :  * context data will be used as a parameter for scard_*() functions.
    1631                 :            :  */
    1632                 :         31 : void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
    1633                 :            : {
    1634         [ +  - ]:         31 :         if (sm) {
    1635                 :         31 :                 sm->ctx->scard_ctx = ctx;
    1636                 :         31 :                 eap_register_scard_ctx(sm->eap, ctx);
    1637                 :            :         }
    1638                 :         31 : }
    1639                 :            : 
    1640                 :            : 
    1641                 :            : /**
    1642                 :            :  * eapol_sm_notify_portControl - Notification of portControl changes
    1643                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1644                 :            :  * @portControl: New value for portControl variable
    1645                 :            :  *
    1646                 :            :  * Notify EAPOL state machines that portControl variable has changed.
    1647                 :            :  */
    1648                 :        460 : void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
    1649                 :            : {
    1650         [ -  + ]:        460 :         if (sm == NULL)
    1651                 :        460 :                 return;
    1652                 :        460 :         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
    1653                 :            :                    "portControl=%s", eapol_port_control(portControl));
    1654                 :        460 :         sm->portControl = portControl;
    1655                 :        460 :         eapol_sm_step(sm);
    1656                 :            : }
    1657                 :            : 
    1658                 :            : 
    1659                 :            : /**
    1660                 :            :  * eapol_sm_notify_ctrl_attached - Notification of attached monitor
    1661                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1662                 :            :  *
    1663                 :            :  * Notify EAPOL state machines that a monitor was attached to the control
    1664                 :            :  * interface to trigger re-sending of pending requests for user input.
    1665                 :            :  */
    1666                 :         17 : void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
    1667                 :            : {
    1668         [ -  + ]:         17 :         if (sm == NULL)
    1669                 :         17 :                 return;
    1670                 :         17 :         eap_sm_notify_ctrl_attached(sm->eap);
    1671                 :            : }
    1672                 :            : 
    1673                 :            : 
    1674                 :            : /**
    1675                 :            :  * eapol_sm_notify_ctrl_response - Notification of received user input
    1676                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1677                 :            :  *
    1678                 :            :  * Notify EAPOL state machines that a control response, i.e., user
    1679                 :            :  * input, was received in order to trigger retrying of a pending EAP request.
    1680                 :            :  */
    1681                 :          2 : void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
    1682                 :            : {
    1683         [ -  + ]:          2 :         if (sm == NULL)
    1684                 :          2 :                 return;
    1685 [ +  - ][ +  - ]:          2 :         if (sm->eapReqData && !sm->eapReq) {
    1686                 :          2 :                 wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
    1687                 :            :                            "input) notification - retrying pending EAP "
    1688                 :            :                            "Request");
    1689                 :          2 :                 sm->eapolEap = TRUE;
    1690                 :          2 :                 sm->eapReq = TRUE;
    1691                 :          2 :                 eapol_sm_step(sm);
    1692                 :            :         }
    1693                 :            : }
    1694                 :            : 
    1695                 :            : 
    1696                 :            : /**
    1697                 :            :  * eapol_sm_request_reauth - Request reauthentication
    1698                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1699                 :            :  *
    1700                 :            :  * This function can be used to request EAPOL reauthentication, e.g., when the
    1701                 :            :  * current PMKSA entry is nearing expiration.
    1702                 :            :  */
    1703                 :         22 : void eapol_sm_request_reauth(struct eapol_sm *sm)
    1704                 :            : {
    1705 [ +  - ][ -  + ]:         22 :         if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
    1706                 :         22 :                 return;
    1707                 :         22 :         eapol_sm_txStart(sm);
    1708                 :            : }
    1709                 :            : 
    1710                 :            : 
    1711                 :            : /**
    1712                 :            :  * eapol_sm_notify_lower_layer_success - Notification of lower layer success
    1713                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1714                 :            :  * @in_eapol_sm: Whether the caller is already running inside EAPOL state
    1715                 :            :  * machine loop (eapol_sm_step())
    1716                 :            :  *
    1717                 :            :  * Notify EAPOL (and EAP) state machines that a lower layer has detected a
    1718                 :            :  * successful authentication. This is used to recover from dropped EAP-Success
    1719                 :            :  * messages.
    1720                 :            :  */
    1721                 :        564 : void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
    1722                 :            : {
    1723         [ +  + ]:        564 :         if (sm == NULL)
    1724                 :        564 :                 return;
    1725                 :        552 :         eap_notify_lower_layer_success(sm->eap);
    1726         [ +  + ]:        552 :         if (!in_eapol_sm)
    1727                 :        548 :                 eapol_sm_step(sm);
    1728                 :            : }
    1729                 :            : 
    1730                 :            : 
    1731                 :            : /**
    1732                 :            :  * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
    1733                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1734                 :            :  */
    1735                 :       1796 : void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
    1736                 :            : {
    1737         [ +  - ]:       1796 :         if (sm)
    1738                 :       1796 :                 eap_invalidate_cached_session(sm->eap);
    1739                 :       1796 : }
    1740                 :            : 
    1741                 :            : 
    1742                 :       1515 : static struct eap_peer_config * eapol_sm_get_config(void *ctx)
    1743                 :            : {
    1744                 :       1515 :         struct eapol_sm *sm = ctx;
    1745         [ +  - ]:       1515 :         return sm ? sm->config : NULL;
    1746                 :            : }
    1747                 :            : 
    1748                 :            : 
    1749                 :       2182 : static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
    1750                 :            : {
    1751                 :       2182 :         struct eapol_sm *sm = ctx;
    1752 [ +  - ][ -  + ]:       2182 :         if (sm == NULL || sm->eapReqData == NULL)
    1753                 :          0 :                 return NULL;
    1754                 :            : 
    1755                 :       2182 :         return sm->eapReqData;
    1756                 :            : }
    1757                 :            : 
    1758                 :            : 
    1759                 :      60828 : static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
    1760                 :            : {
    1761                 :      60828 :         struct eapol_sm *sm = ctx;
    1762         [ -  + ]:      60828 :         if (sm == NULL)
    1763                 :          0 :                 return FALSE;
    1764   [ +  +  -  -  :      60828 :         switch (variable) {
          -  +  +  +  +  
                      - ]
    1765                 :            :         case EAPOL_eapSuccess:
    1766                 :        552 :                 return sm->eapSuccess;
    1767                 :            :         case EAPOL_eapRestart:
    1768                 :      20281 :                 return sm->eapRestart;
    1769                 :            :         case EAPOL_eapFail:
    1770                 :          0 :                 return sm->eapFail;
    1771                 :            :         case EAPOL_eapResp:
    1772                 :          0 :                 return sm->eapResp;
    1773                 :            :         case EAPOL_eapNoResp:
    1774                 :          0 :                 return sm->eapNoResp;
    1775                 :            :         case EAPOL_eapReq:
    1776                 :       5778 :                 return sm->eapReq;
    1777                 :            :         case EAPOL_portEnabled:
    1778                 :      20450 :                 return sm->portEnabled;
    1779                 :            :         case EAPOL_altAccept:
    1780                 :       9178 :                 return sm->altAccept;
    1781                 :            :         case EAPOL_altReject:
    1782                 :       4589 :                 return sm->altReject;
    1783                 :            :         }
    1784                 :      60828 :         return FALSE;
    1785                 :            : }
    1786                 :            : 
    1787                 :            : 
    1788                 :      10926 : static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
    1789                 :            :                               Boolean value)
    1790                 :            : {
    1791                 :      10926 :         struct eapol_sm *sm = ctx;
    1792         [ -  + ]:      10926 :         if (sm == NULL)
    1793                 :      10926 :                 return;
    1794   [ +  +  +  +  :      10926 :         switch (variable) {
          +  +  -  -  -  
                      - ]
    1795                 :            :         case EAPOL_eapSuccess:
    1796                 :       7047 :                 sm->eapSuccess = value;
    1797                 :       7047 :                 break;
    1798                 :            :         case EAPOL_eapRestart:
    1799                 :        352 :                 sm->eapRestart = value;
    1800                 :        352 :                 break;
    1801                 :            :         case EAPOL_eapFail:
    1802                 :        447 :                 sm->eapFail = value;
    1803                 :        447 :                 break;
    1804                 :            :         case EAPOL_eapResp:
    1805                 :       1357 :                 sm->eapResp = value;
    1806                 :       1357 :                 break;
    1807                 :            :         case EAPOL_eapNoResp:
    1808                 :        534 :                 sm->eapNoResp = value;
    1809                 :        534 :                 break;
    1810                 :            :         case EAPOL_eapReq:
    1811                 :       1189 :                 sm->eapReq = value;
    1812                 :       1189 :                 break;
    1813                 :            :         case EAPOL_portEnabled:
    1814                 :          0 :                 sm->portEnabled = value;
    1815                 :          0 :                 break;
    1816                 :            :         case EAPOL_altAccept:
    1817                 :          0 :                 sm->altAccept = value;
    1818                 :          0 :                 break;
    1819                 :            :         case EAPOL_altReject:
    1820                 :          0 :                 sm->altReject = value;
    1821                 :          0 :                 break;
    1822                 :            :         }
    1823                 :            : }
    1824                 :            : 
    1825                 :            : 
    1826                 :       9178 : static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
    1827                 :            : {
    1828                 :       9178 :         struct eapol_sm *sm = ctx;
    1829         [ -  + ]:       9178 :         if (sm == NULL)
    1830                 :          0 :                 return 0;
    1831         [ +  - ]:       9178 :         switch (variable) {
    1832                 :            :         case EAPOL_idleWhile:
    1833                 :       9178 :                 return sm->idleWhile;
    1834                 :            :         }
    1835                 :       9178 :         return 0;
    1836                 :            : }
    1837                 :            : 
    1838                 :            : 
    1839                 :      10360 : static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
    1840                 :            :                              unsigned int value)
    1841                 :            : {
    1842                 :      10360 :         struct eapol_sm *sm = ctx;
    1843         [ -  + ]:      10360 :         if (sm == NULL)
    1844                 :      10360 :                 return;
    1845         [ +  - ]:      10360 :         switch (variable) {
    1846                 :            :         case EAPOL_idleWhile:
    1847                 :      10360 :                 sm->idleWhile = value;
    1848         [ +  + ]:      10360 :                 if (sm->idleWhile > 0)
    1849                 :       1359 :                         eapol_enable_timer_tick(sm);
    1850                 :      10360 :                 break;
    1851                 :            :         }
    1852                 :            : }
    1853                 :            : 
    1854                 :            : 
    1855                 :          1 : static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
    1856                 :            : {
    1857                 :            : #ifndef CONFIG_NO_CONFIG_BLOBS
    1858                 :          1 :         struct eapol_sm *sm = ctx;
    1859 [ +  - ][ +  - ]:          1 :         if (sm && sm->ctx && sm->ctx->set_config_blob)
                 [ +  - ]
    1860                 :          1 :                 sm->ctx->set_config_blob(sm->ctx->ctx, blob);
    1861                 :            : #endif /* CONFIG_NO_CONFIG_BLOBS */
    1862                 :          1 : }
    1863                 :            : 
    1864                 :            : 
    1865                 :            : static const struct wpa_config_blob *
    1866                 :          2 : eapol_sm_get_config_blob(void *ctx, const char *name)
    1867                 :            : {
    1868                 :            : #ifndef CONFIG_NO_CONFIG_BLOBS
    1869                 :          2 :         struct eapol_sm *sm = ctx;
    1870 [ +  - ][ +  - ]:          2 :         if (sm && sm->ctx && sm->ctx->get_config_blob)
                 [ +  - ]
    1871                 :          2 :                 return sm->ctx->get_config_blob(sm->ctx->ctx, name);
    1872                 :            :         else
    1873                 :          2 :                 return NULL;
    1874                 :            : #else /* CONFIG_NO_CONFIG_BLOBS */
    1875                 :            :         return NULL;
    1876                 :            : #endif /* CONFIG_NO_CONFIG_BLOBS */
    1877                 :            : }
    1878                 :            : 
    1879                 :            : 
    1880                 :          0 : static void eapol_sm_notify_pending(void *ctx)
    1881                 :            : {
    1882                 :          0 :         struct eapol_sm *sm = ctx;
    1883         [ #  # ]:          0 :         if (sm == NULL)
    1884                 :          0 :                 return;
    1885 [ #  # ][ #  # ]:          0 :         if (sm->eapReqData && !sm->eapReq) {
    1886                 :          0 :                 wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
    1887                 :            :                            "state machine - retrying pending EAP Request");
    1888                 :          0 :                 sm->eapolEap = TRUE;
    1889                 :          0 :                 sm->eapReq = TRUE;
    1890                 :          0 :                 eapol_sm_step(sm);
    1891                 :            :         }
    1892                 :            : }
    1893                 :            : 
    1894                 :            : 
    1895                 :            : #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
    1896                 :          2 : static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
    1897                 :            :                                       const char *txt)
    1898                 :            : {
    1899                 :          2 :         struct eapol_sm *sm = ctx;
    1900                 :          2 :         wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
    1901         [ +  - ]:          2 :         if (sm->ctx->eap_param_needed)
    1902                 :          2 :                 sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
    1903                 :          2 : }
    1904                 :            : #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
    1905                 :            : #define eapol_sm_eap_param_needed NULL
    1906                 :            : #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
    1907                 :            : 
    1908                 :        109 : static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
    1909                 :            :                                  const char *cert_hash,
    1910                 :            :                                  const struct wpabuf *cert)
    1911                 :            : {
    1912                 :        109 :         struct eapol_sm *sm = ctx;
    1913         [ +  - ]:        109 :         if (sm->ctx->cert_cb)
    1914                 :        109 :                 sm->ctx->cert_cb(sm->ctx->ctx, depth, subject,
    1915                 :            :                                  cert_hash, cert);
    1916                 :        109 : }
    1917                 :            : 
    1918                 :            : 
    1919                 :        674 : static void eapol_sm_notify_status(void *ctx, const char *status,
    1920                 :            :                                    const char *parameter)
    1921                 :            : {
    1922                 :        674 :         struct eapol_sm *sm = ctx;
    1923                 :            : 
    1924         [ +  - ]:        674 :         if (sm->ctx->status_cb)
    1925                 :        674 :                 sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
    1926                 :        674 : }
    1927                 :            : 
    1928                 :            : 
    1929                 :          8 : static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
    1930                 :            : {
    1931                 :          8 :         struct eapol_sm *sm = ctx;
    1932                 :            : 
    1933         [ +  - ]:          8 :         if (sm->ctx->set_anon_id)
    1934                 :          8 :                 sm->ctx->set_anon_id(sm->ctx->ctx, id, len);
    1935                 :          8 : }
    1936                 :            : 
    1937                 :            : 
    1938                 :            : static struct eapol_callbacks eapol_cb =
    1939                 :            : {
    1940                 :            :         eapol_sm_get_config,
    1941                 :            :         eapol_sm_get_bool,
    1942                 :            :         eapol_sm_set_bool,
    1943                 :            :         eapol_sm_get_int,
    1944                 :            :         eapol_sm_set_int,
    1945                 :            :         eapol_sm_get_eapReqData,
    1946                 :            :         eapol_sm_set_config_blob,
    1947                 :            :         eapol_sm_get_config_blob,
    1948                 :            :         eapol_sm_notify_pending,
    1949                 :            :         eapol_sm_eap_param_needed,
    1950                 :            :         eapol_sm_notify_cert,
    1951                 :            :         eapol_sm_notify_status,
    1952                 :            :         eapol_sm_set_anon_id
    1953                 :            : };
    1954                 :            : 
    1955                 :            : 
    1956                 :            : /**
    1957                 :            :  * eapol_sm_init - Initialize EAPOL state machine
    1958                 :            :  * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
    1959                 :            :  * and EAPOL state machine will free it in eapol_sm_deinit()
    1960                 :            :  * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
    1961                 :            :  *
    1962                 :            :  * Allocate and initialize an EAPOL state machine.
    1963                 :            :  */
    1964                 :         31 : struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
    1965                 :            : {
    1966                 :            :         struct eapol_sm *sm;
    1967                 :            :         struct eap_config conf;
    1968                 :         31 :         sm = os_zalloc(sizeof(*sm));
    1969         [ -  + ]:         31 :         if (sm == NULL)
    1970                 :          0 :                 return NULL;
    1971                 :         31 :         sm->ctx = ctx;
    1972                 :            : 
    1973                 :         31 :         sm->portControl = Auto;
    1974                 :            : 
    1975                 :            :         /* Supplicant PAE state machine */
    1976                 :         31 :         sm->heldPeriod = 60;
    1977                 :         31 :         sm->startPeriod = 30;
    1978                 :         31 :         sm->maxStart = 3;
    1979                 :            : 
    1980                 :            :         /* Supplicant Backend state machine */
    1981                 :         31 :         sm->authPeriod = 30;
    1982                 :            : 
    1983                 :         31 :         os_memset(&conf, 0, sizeof(conf));
    1984                 :         31 :         conf.opensc_engine_path = ctx->opensc_engine_path;
    1985                 :         31 :         conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
    1986                 :         31 :         conf.pkcs11_module_path = ctx->pkcs11_module_path;
    1987                 :         31 :         conf.wps = ctx->wps;
    1988                 :         31 :         conf.cert_in_cb = ctx->cert_in_cb;
    1989                 :            : 
    1990                 :         31 :         sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
    1991         [ -  + ]:         31 :         if (sm->eap == NULL) {
    1992                 :          0 :                 os_free(sm);
    1993                 :          0 :                 return NULL;
    1994                 :            :         }
    1995                 :            : 
    1996                 :            : #ifdef CONFIG_EAP_PROXY
    1997                 :            :         sm->use_eap_proxy = FALSE;
    1998                 :            :         sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx);
    1999                 :            :         if (sm->eap_proxy == NULL) {
    2000                 :            :                 wpa_printf(MSG_ERROR, "Unable to initialize EAP Proxy");
    2001                 :            :         }
    2002                 :            : #endif /* CONFIG_EAP_PROXY */
    2003                 :            : 
    2004                 :            :         /* Initialize EAPOL state machines */
    2005                 :         31 :         sm->initialize = TRUE;
    2006                 :         31 :         eapol_sm_step(sm);
    2007                 :         31 :         sm->initialize = FALSE;
    2008                 :         31 :         eapol_sm_step(sm);
    2009                 :            : 
    2010                 :         31 :         sm->timer_tick_enabled = 1;
    2011                 :         31 :         eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
    2012                 :            : 
    2013                 :         31 :         return sm;
    2014                 :            : }
    2015                 :            : 
    2016                 :            : 
    2017                 :            : /**
    2018                 :            :  * eapol_sm_deinit - Deinitialize EAPOL state machine
    2019                 :            :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    2020                 :            :  *
    2021                 :            :  * Deinitialize and free EAPOL state machine.
    2022                 :            :  */
    2023                 :         31 : void eapol_sm_deinit(struct eapol_sm *sm)
    2024                 :            : {
    2025         [ -  + ]:         31 :         if (sm == NULL)
    2026                 :         31 :                 return;
    2027                 :         31 :         eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
    2028                 :         31 :         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
    2029                 :         31 :         eap_peer_sm_deinit(sm->eap);
    2030                 :            : #ifdef CONFIG_EAP_PROXY
    2031                 :            :         eap_proxy_deinit(sm->eap_proxy);
    2032                 :            : #endif /* CONFIG_EAP_PROXY */
    2033                 :         31 :         os_free(sm->last_rx_key);
    2034                 :         31 :         wpabuf_free(sm->eapReqData);
    2035                 :         31 :         os_free(sm->ctx);
    2036                 :         31 :         os_free(sm);
    2037                 :            : }
    2038                 :            : 
    2039                 :            : 
    2040                 :         31 : void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
    2041                 :            :                              struct ext_password_data *ext)
    2042                 :            : {
    2043 [ +  - ][ +  - ]:         31 :         if (sm && sm->eap)
    2044                 :         31 :                 eap_sm_set_ext_pw_ctx(sm->eap, ext);
    2045                 :         31 : }
    2046                 :            : 
    2047                 :            : 
    2048                 :         64 : int eapol_sm_failed(struct eapol_sm *sm)
    2049                 :            : {
    2050         [ -  + ]:         64 :         if (sm == NULL)
    2051                 :          0 :                 return 0;
    2052 [ +  + ][ -  + ]:         64 :         return !sm->eapSuccess && sm->eapFail;
    2053                 :            : }
    2054                 :            : 
    2055                 :            : 
    2056                 :          0 : int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len)
    2057                 :            : {
    2058                 :            : #ifdef CONFIG_EAP_PROXY
    2059                 :            :         if (sm->eap_proxy == NULL)
    2060                 :            :                 return -1;
    2061                 :            :         return eap_proxy_get_imsi(sm->eap_proxy, imsi, len);
    2062                 :            : #else /* CONFIG_EAP_PROXY */
    2063                 :          0 :         return -1;
    2064                 :            : #endif /* CONFIG_EAP_PROXY */
    2065                 :            : }

Generated by: LCOV version 1.9